Murali Chandran commited on
Commit
bdfea42
·
1 Parent(s): 91ba198
Files changed (1) hide show
  1. app.py +65 -42
app.py CHANGED
@@ -1,11 +1,11 @@
1
  # app.py — Mobile-safe Gradio Space (prevents truncation on phones)
2
- # - Uses Chatbot(type="messages") for modern rendering
3
- # - Fixed-height, scrollable chat area on mobile & desktop
4
- # - CSS forces wrapping (no cut-off), preserves newlines
5
- # - SSR disabled (some mobile browsers misbehave with SSR streaming)
6
- # - Works with any sync or streaming generate() function
 
7
 
8
- import os
9
  import gradio as gr
10
 
11
  APP_TITLE = "MiniGPT – Mobile Friendly"
@@ -24,9 +24,15 @@ def predict(message: str, history: list[dict]):
24
  history is a list of {"role": "user"|"assistant", "content": str}.
25
  """
26
  # EXAMPLE: simple echo with a long multi-line block to stress-wrap on mobile
27
- long_demo = "\n".join([f"step {i+1}: example line that is intentionally long to test wrapping on mobile browsers. "
28
- f"It should never be truncated; it should wrap and the container should scroll." for i in range(8)])
29
- reply = f"Here is your message back:\n\n{message}\n\n{long_demo}\n\nfinal answer: this text should fully render on mobile."
 
 
 
 
 
 
30
 
31
  # If you want streaming, yield chunks instead of returning a full string:
32
  # for chunk in reply.split(" "):
@@ -38,7 +44,9 @@ def predict(message: str, history: list[dict]):
38
  # -------------------------------
39
  # Build UI
40
  # -------------------------------
41
- with gr.Blocks(fill_height=True, css="""
 
 
42
  /* ====== MOBILE-SAFE CHAT STYLES ====== */
43
  html, body, .gradio-container { height: 100%; }
44
  #chatbox { height: 70vh; overflow: auto; }
@@ -46,7 +54,8 @@ html, body, .gradio-container { height: 100%; }
46
  #chatbox * { overflow-wrap: anywhere; word-break: break-word; }
47
  #chatbox pre, #chatbox code, #chatbox .prose pre { white-space: pre-wrap; }
48
  @media (max-width: 480px) { #chatbox { font-size: 0.95rem; } }
49
- """) as demo:
 
50
  gr.Markdown(f"# {APP_TITLE}")
51
  gr.Markdown(APP_DESC)
52
 
@@ -63,33 +72,39 @@ html, body, .gradio-container { height: 100%; }
63
 
64
  # ---------- Components ----------
65
  if MESSAGES_MODE:
66
- chat = gr.Chatbot(type="messages", height=540, show_copy_button=True, layout="bubble", elem_id="chatbox")
 
 
 
 
 
67
  history_state = gr.State([]) # list[dict]
68
  else:
69
- chat = gr.Chatbot(height=540, show_copy_button=True, layout="bubble", elem_id="chatbox")
70
- history_state = gr.State([]) # list[tuple[str,str]]
 
 
 
 
71
 
72
  msg = gr.Textbox(placeholder="Ask me something…", autofocus=True)
73
  send = gr.Button("Send")
74
  clear = gr.Button("Clear")
75
 
76
  # ---------- Event handlers ----------
77
- def on_clear():
78
- return ([], []) if MESSAGES_MODE else ([], [])
79
-
80
  def on_user_submit(user_message, hist):
81
  if MESSAGES_MODE:
82
  # hist: list[dict]
83
  new_hist = hist + [{"role": "user", "content": user_message}]
84
- # Show pending assistant message slot (optional)
85
  return gr.update(value=new_hist), new_hist, ""
86
  else:
87
- # hist: list[tuple]
88
- new_hist = hist + [(user_message, "")]
89
  return gr.update(value=new_hist), new_hist, ""
90
 
91
  def on_bot_respond(hist):
92
- # Derive the latest user message from history (works in both modes)
93
  if MESSAGES_MODE:
94
  user_message = ""
95
  for m in reversed(hist or []):
@@ -99,7 +114,6 @@ html, body, .gradio-container { height: 100%; }
99
  model_hist = hist
100
  else:
101
  user_message = hist[-1][0] if hist else ""
102
- # Convert tuple hist -> messages for model
103
  model_hist = []
104
  for u, a in hist:
105
  model_hist.append({"role": "user", "content": u})
@@ -108,7 +122,7 @@ html, body, .gradio-container { height: 100%; }
108
 
109
  out = predict(user_message, model_hist)
110
 
111
- # Streaming generator
112
  if hasattr(out, "__iter__") and not isinstance(out, (str, bytes)):
113
  acc = ""
114
  for chunk in out:
@@ -117,48 +131,57 @@ html, body, .gradio-container { height: 100%; }
117
  temp = hist + [{"role": "assistant", "content": acc}]
118
  yield gr.update(value=temp), temp
119
  else:
120
- # Replace last pair's assistant text as it streams
121
  if hist:
122
- temp = hist[:-1] + [(hist[-1][0], acc)]
123
  else:
124
- temp = [(user_message, acc)]
125
  yield gr.update(value=temp), temp
126
  return
127
 
128
- # Single string
129
  reply = str(out)
130
  if MESSAGES_MODE:
131
  new_hist = hist + [{"role": "assistant", "content": reply}]
132
  return gr.update(value=new_hist), new_hist
133
  else:
134
- new_hist = hist[:-1] + [(hist[-1][0], reply)] if hist else [(user_message, reply)]
135
  return gr.update(value=new_hist), new_hist
136
 
137
- # Wire events
138
- user_submit = msg.submit(on_user_submit, inputs=[msg, history_state], outputs=[chat, history_state, msg])
139
- btn_submit = send.click(on_user_submit, inputs=[msg, history_state], outputs=[chat, history_state, msg])
140
-
141
- # After we append the user message, trigger the bot to respond
 
 
 
 
 
 
 
 
142
  user_submit.then(on_bot_respond, inputs=[history_state], outputs=[chat, history_state])
143
- btn_submit.then(on_bot_respond, inputs=[msg, history_state], outputs=[chat, history_state])
144
 
145
  clear.click(lambda: ([], []), None, [chat, history_state])
146
 
147
- gr.Markdown("""
 
148
  **Notes**
149
  - This build avoids `ChatInterface` to prevent DuplicateBlockError on older Gradio.
150
- - On Gradio < 4.37, it uses tuple chat format; on newer, it uses `type="messages"`.
151
  - CSS ensures full wrapping + scroll on mobile; `ssr_mode=False` below improves stability.
152
- """)
 
153
 
154
- # Queue for stability
155
- # Version-safe queue setup
156
  try:
157
- # Gradio ≥ 4.33 typically supports default_concurrency_limit
158
  demo.queue(default_concurrency_limit=2, max_size=32, status_update_rate=0.5)
159
  except TypeError:
160
- # Fallback for older signatures
161
- demo.queue()
 
 
162
 
163
  if __name__ == "__main__":
164
  demo.launch(ssl_verify=False, ssr_mode=False)
 
1
  # app.py — Mobile-safe Gradio Space (prevents truncation on phones)
2
+ # - Compatible with Gradio 4.31.0 and newer
3
+ # - Uses Chatbot(type="messages") automatically on >= 4.37, legacy tuples on older
4
+ # - Fixed-height, scrollable chat, forced wrapping to avoid truncation on phones
5
+ # - No ChatInterface (avoids DuplicateBlockError on older Gradio)
6
+ # - Version-safe queue() call
7
+ # - Works with sync or streaming predict()
8
 
 
9
  import gradio as gr
10
 
11
  APP_TITLE = "MiniGPT – Mobile Friendly"
 
24
  history is a list of {"role": "user"|"assistant", "content": str}.
25
  """
26
  # EXAMPLE: simple echo with a long multi-line block to stress-wrap on mobile
27
+ long_demo = " ".join([
28
+ f"step {i+1}: example line that is intentionally long to test wrapping on mobile browsers. "
29
+ f"It should never be truncated; it should wrap and the container should scroll."
30
+ for i in range(8)
31
+ ])
32
+ reply = (
33
+ f"Here is your message back:{message} {long_demo}"
34
+ f"final answer: this text should fully render on mobile."
35
+ )
36
 
37
  # If you want streaming, yield chunks instead of returning a full string:
38
  # for chunk in reply.split(" "):
 
44
  # -------------------------------
45
  # Build UI
46
  # -------------------------------
47
+ with gr.Blocks(
48
+ fill_height=True,
49
+ css="""
50
  /* ====== MOBILE-SAFE CHAT STYLES ====== */
51
  html, body, .gradio-container { height: 100%; }
52
  #chatbox { height: 70vh; overflow: auto; }
 
54
  #chatbox * { overflow-wrap: anywhere; word-break: break-word; }
55
  #chatbox pre, #chatbox code, #chatbox .prose pre { white-space: pre-wrap; }
56
  @media (max-width: 480px) { #chatbox { font-size: 0.95rem; } }
57
+ """,
58
+ ) as demo:
59
  gr.Markdown(f"# {APP_TITLE}")
60
  gr.Markdown(APP_DESC)
61
 
 
72
 
73
  # ---------- Components ----------
74
  if MESSAGES_MODE:
75
+ chat = gr.Chatbot(
76
+ type="messages",
77
+ height=540,
78
+ show_copy_button=True,
79
+ elem_id="chatbox",
80
+ )
81
  history_state = gr.State([]) # list[dict]
82
  else:
83
+ chat = gr.Chatbot(
84
+ height=540,
85
+ show_copy_button=True,
86
+ elem_id="chatbox",
87
+ )
88
+ history_state = gr.State([]) # list[list[str, str]]
89
 
90
  msg = gr.Textbox(placeholder="Ask me something…", autofocus=True)
91
  send = gr.Button("Send")
92
  clear = gr.Button("Clear")
93
 
94
  # ---------- Event handlers ----------
 
 
 
95
  def on_user_submit(user_message, hist):
96
  if MESSAGES_MODE:
97
  # hist: list[dict]
98
  new_hist = hist + [{"role": "user", "content": user_message}]
99
+ # Show user message in chat immediately; clear textbox
100
  return gr.update(value=new_hist), new_hist, ""
101
  else:
102
+ # hist: list[[user, bot]]
103
+ new_hist = hist + [[user_message, ""]]
104
  return gr.update(value=new_hist), new_hist, ""
105
 
106
  def on_bot_respond(hist):
107
+ # Derive the latest user message; build model history in messages format
108
  if MESSAGES_MODE:
109
  user_message = ""
110
  for m in reversed(hist or []):
 
114
  model_hist = hist
115
  else:
116
  user_message = hist[-1][0] if hist else ""
 
117
  model_hist = []
118
  for u, a in hist:
119
  model_hist.append({"role": "user", "content": u})
 
122
 
123
  out = predict(user_message, model_hist)
124
 
125
+ # Streaming generator support
126
  if hasattr(out, "__iter__") and not isinstance(out, (str, bytes)):
127
  acc = ""
128
  for chunk in out:
 
131
  temp = hist + [{"role": "assistant", "content": acc}]
132
  yield gr.update(value=temp), temp
133
  else:
 
134
  if hist:
135
+ temp = hist[:-1] + [[hist[-1][0], acc]]
136
  else:
137
+ temp = [[user_message, acc]]
138
  yield gr.update(value=temp), temp
139
  return
140
 
141
+ # Single string reply
142
  reply = str(out)
143
  if MESSAGES_MODE:
144
  new_hist = hist + [{"role": "assistant", "content": reply}]
145
  return gr.update(value=new_hist), new_hist
146
  else:
147
+ new_hist = hist[:-1] + [[hist[-1][0], reply]] if hist else [[user_message, reply]]
148
  return gr.update(value=new_hist), new_hist
149
 
150
+ # ---------- Wire events (inside Blocks) ----------
151
+ user_submit = msg.submit(
152
+ on_user_submit,
153
+ inputs=[msg, history_state],
154
+ outputs=[chat, history_state, msg],
155
+ )
156
+ btn_submit = send.click(
157
+ on_user_submit,
158
+ inputs=[msg, history_state],
159
+ outputs=[chat, history_state, msg],
160
+ )
161
+
162
+ # After appending the user message, trigger the bot to respond
163
  user_submit.then(on_bot_respond, inputs=[history_state], outputs=[chat, history_state])
164
+ btn_submit.then(on_bot_respond, inputs=[history_state], outputs=[chat, history_state])
165
 
166
  clear.click(lambda: ([], []), None, [chat, history_state])
167
 
168
+ gr.Markdown(
169
+ """
170
  **Notes**
171
  - This build avoids `ChatInterface` to prevent DuplicateBlockError on older Gradio.
172
+ - On Gradio < 4.37, it uses legacy tuple chat format; on newer, it uses `type="messages"`.
173
  - CSS ensures full wrapping + scroll on mobile; `ssr_mode=False` below improves stability.
174
+ """
175
+ )
176
 
177
+ # Queue for stability (version-safe args)
 
178
  try:
 
179
  demo.queue(default_concurrency_limit=2, max_size=32, status_update_rate=0.5)
180
  except TypeError:
181
+ try:
182
+ demo.queue(concurrency_count=2)
183
+ except TypeError:
184
+ demo.queue()
185
 
186
  if __name__ == "__main__":
187
  demo.launch(ssl_verify=False, ssr_mode=False)