dzezzefezfz commited on
Commit
0eeea8c
·
verified ·
1 Parent(s): 5ab3e51

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -50
app.py CHANGED
@@ -77,7 +77,7 @@ body.light{
77
  overflow:hidden;
78
  }
79
 
80
- /* Bubble styling (best-effort: Gradio DOM can vary by version) */
81
  .chat_shell .message{
82
  border-radius:16px !important;
83
  border:1px solid var(--border) !important;
@@ -152,10 +152,7 @@ def get_headers():
152
  key = os.environ.get("HF_API_KEY")
153
  if not key:
154
  return None, "HF_API_KEY missing (Space Settings → Variables)"
155
- return {
156
- "Authorization": f"Bearer {key}",
157
- "Content-Type": "application/json",
158
- }, None
159
 
160
  def list_models(headers):
161
  r = requests.get(f"{BASE_URL}/models", headers=headers, timeout=20)
@@ -163,7 +160,9 @@ def list_models(headers):
163
  return None, f"HTTP {r.status_code}: {r.text}"
164
  data = r.json()
165
  models = [m.get("id") for m in data.get("data", []) if m.get("id")]
166
- return models, None if models else (None, "No models returned")
 
 
167
 
168
  def chat_call(headers, model, messages, temperature, max_tokens):
169
  payload = {
@@ -188,30 +187,47 @@ def chat_call(headers, model, messages, temperature, max_tokens):
188
  return f"Unexpected response shape: {data}"
189
 
190
  # ----------------------------
191
- # Conversation management
192
  # ----------------------------
193
- MAX_TURNS = 14 # number of (user+assistant) pairs to send each request
194
-
195
- def trim_history(history):
196
- """
197
- history is Gradio Chatbot type='messages':
198
- [{"role":"user","content":"..."}, {"role":"assistant","content":"..."}, ...]
199
- """
200
- if not history:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  return []
202
- return history[-MAX_TURNS * 2 :]
203
 
204
- def build_messages(system_prompt, history, user_msg):
205
  return (
206
  [{"role": "system", "content": system_prompt}]
207
- + trim_history(history)
208
  + [{"role": "user", "content": user_msg}]
209
  )
210
 
211
  # ----------------------------
212
  # Gradio app
213
  # ----------------------------
214
- with gr.Blocks(title="Chat", css=CSS) as demo:
215
  with gr.Column(elem_id="wrap"):
216
  with gr.Row(elem_classes=["header"]):
217
  gr.Markdown("## My AI Chatbot")
@@ -223,21 +239,23 @@ with gr.Blocks(title="Chat", css=CSS) as demo:
223
  with gr.Row():
224
  model_dd = gr.Dropdown(label="Model (from /v1/models)", choices=[], value=None, interactive=True)
225
  refresh_btn = gr.Button("Refresh models", elem_classes=["secondary"])
 
226
  model_override = gr.Textbox(
227
  label="Model override (optional)",
228
- placeholder="If dropdown models fail, paste a chat-capable model id here (takes precedence).",
229
- )
230
- system_prompt = gr.Textbox(
231
- label="System prompt",
232
- value="You are a helpful assistant.",
233
  )
 
 
234
  with gr.Row():
235
  temperature = gr.Slider(0.0, 1.5, value=0.7, step=0.05, label="Temperature")
236
  max_tokens = gr.Slider(64, 2048, value=800, step=32, label="Max tokens")
237
 
238
  with gr.Column(elem_classes=["chat_shell"]):
239
- # CRITICAL: type="messages" ensures history is OpenAI-style dicts
240
- chatbot = gr.Chatbot(type="messages", height=560)
 
 
 
241
 
242
  with gr.Column(elem_classes=["composer"]):
243
  msg = gr.Textbox(placeholder="Message…", show_label=False, lines=1)
@@ -249,62 +267,64 @@ with gr.Blocks(title="Chat", css=CSS) as demo:
249
  headers, err = get_headers()
250
  if err:
251
  return f"❌ {err}", gr.update(choices=[], value=None)
252
-
253
  models, err = list_models(headers)
254
- if err or not models:
255
- return f"❌ {err or 'No models found'}", gr.update(choices=[], value=None)
256
-
257
- # do NOT assume first model is chat-capable; just pick first as a convenience
258
  return f"✅ Models loaded ({len(models)}).", gr.update(choices=models, value=models[0])
259
 
260
  def init():
261
  return do_refresh_models()
262
 
263
- def respond(user_msg, history, model_dd_value, model_text, sys_prompt, temp, mx):
264
- history = history or []
265
  user_msg = (user_msg or "").strip()
266
  if not user_msg:
267
- return "", history
268
 
269
  headers, err = get_headers()
270
  if err:
271
- history = history + [
272
  {"role": "user", "content": user_msg},
273
  {"role": "assistant", "content": f"Setup error: {err}"},
274
  ]
275
- return "", history
276
 
277
- # Prefer override, otherwise dropdown
278
  model = (model_text or "").strip() or (model_dd_value or "").strip()
279
  if not model:
280
- history = history + [
281
  {"role": "user", "content": user_msg},
282
- {"role": "assistant", "content": "No model selected. Choose one from the dropdown or set Model override."},
283
  ]
284
- return "", history
285
 
286
- messages = build_messages(sys_prompt or "You are a helpful assistant.", history, user_msg)
287
- bot = chat_call(headers, model, messages, temp, mx)
 
288
 
289
- history = history + [
290
  {"role": "user", "content": user_msg},
291
  {"role": "assistant", "content": bot},
292
  ]
293
- return "", history
 
 
 
 
294
 
295
  demo.load(init, outputs=[status, model_dd])
296
  refresh_btn.click(do_refresh_models, outputs=[status, model_dd])
297
 
298
  send.click(
299
  respond,
300
- inputs=[msg, chatbot, model_dd, model_override, system_prompt, temperature, max_tokens],
301
- outputs=[msg, chatbot],
302
  )
303
  msg.submit(
304
  respond,
305
- inputs=[msg, chatbot, model_dd, model_override, system_prompt, temperature, max_tokens],
306
- outputs=[msg, chatbot],
307
  )
308
- clear.click(lambda: [], outputs=chatbot)
309
 
310
- demo.launch()
 
 
77
  overflow:hidden;
78
  }
79
 
80
+ /* Best-effort bubble styling (DOM varies by Gradio version) */
81
  .chat_shell .message{
82
  border-radius:16px !important;
83
  border:1px solid var(--border) !important;
 
152
  key = os.environ.get("HF_API_KEY")
153
  if not key:
154
  return None, "HF_API_KEY missing (Space Settings → Variables)"
155
+ return {"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, None
 
 
 
156
 
157
  def list_models(headers):
158
  r = requests.get(f"{BASE_URL}/models", headers=headers, timeout=20)
 
160
  return None, f"HTTP {r.status_code}: {r.text}"
161
  data = r.json()
162
  models = [m.get("id") for m in data.get("data", []) if m.get("id")]
163
+ if not models:
164
+ return None, "No models returned"
165
+ return models, None
166
 
167
  def chat_call(headers, model, messages, temperature, max_tokens):
168
  payload = {
 
187
  return f"Unexpected response shape: {data}"
188
 
189
  # ----------------------------
190
+ # History conversion utilities
191
  # ----------------------------
192
+ MAX_TURNS = 14 # keep last N user+assistant pairs
193
+
194
+ def ui_pairs_from_messages(msgs):
195
+ """Convert OpenAI messages -> Chatbot tuple list [(user, assistant), ...]"""
196
+ pairs = []
197
+ pending_user = None
198
+ for m in msgs or []:
199
+ role = m.get("role")
200
+ content = m.get("content", "")
201
+ if role == "user":
202
+ pending_user = content
203
+ elif role == "assistant":
204
+ if pending_user is None:
205
+ # assistant without user, show it anyway
206
+ pairs.append(("", content))
207
+ else:
208
+ pairs.append((pending_user, content))
209
+ pending_user = None
210
+ if pending_user is not None:
211
+ pairs.append((pending_user, "")) # user message without assistant yet
212
+ return pairs
213
+
214
+ def trimmed_messages(msgs):
215
+ """Trim to last MAX_TURNS pairs (2 messages each)."""
216
+ if not msgs:
217
  return []
218
+ return msgs[-MAX_TURNS * 2 :]
219
 
220
+ def build_messages(system_prompt, msgs, user_msg):
221
  return (
222
  [{"role": "system", "content": system_prompt}]
223
+ + trimmed_messages(msgs)
224
  + [{"role": "user", "content": user_msg}]
225
  )
226
 
227
  # ----------------------------
228
  # Gradio app
229
  # ----------------------------
230
+ with gr.Blocks(title="Chat") as demo:
231
  with gr.Column(elem_id="wrap"):
232
  with gr.Row(elem_classes=["header"]):
233
  gr.Markdown("## My AI Chatbot")
 
239
  with gr.Row():
240
  model_dd = gr.Dropdown(label="Model (from /v1/models)", choices=[], value=None, interactive=True)
241
  refresh_btn = gr.Button("Refresh models", elem_classes=["secondary"])
242
+
243
  model_override = gr.Textbox(
244
  label="Model override (optional)",
245
+ placeholder="Paste a chat-capable model id here (takes precedence over dropdown).",
 
 
 
 
246
  )
247
+
248
+ system_prompt = gr.Textbox(label="System prompt", value="You are a helpful assistant.")
249
  with gr.Row():
250
  temperature = gr.Slider(0.0, 1.5, value=0.7, step=0.05, label="Temperature")
251
  max_tokens = gr.Slider(64, 2048, value=800, step=32, label="Max tokens")
252
 
253
  with gr.Column(elem_classes=["chat_shell"]):
254
+ # IMPORTANT: no `type=` here (your Gradio doesn't support it)
255
+ chatbot = gr.Chatbot(height=560)
256
+
257
+ # Internal message state (OpenAI-style dict list)
258
+ msg_state = gr.State([])
259
 
260
  with gr.Column(elem_classes=["composer"]):
261
  msg = gr.Textbox(placeholder="Message…", show_label=False, lines=1)
 
267
  headers, err = get_headers()
268
  if err:
269
  return f"❌ {err}", gr.update(choices=[], value=None)
 
270
  models, err = list_models(headers)
271
+ if err:
272
+ return f"❌ {err}", gr.update(choices=[], value=None)
 
 
273
  return f"✅ Models loaded ({len(models)}).", gr.update(choices=models, value=models[0])
274
 
275
  def init():
276
  return do_refresh_models()
277
 
278
+ def respond(user_msg, msgs, model_dd_value, model_text, sys_prompt, temp, mx):
279
+ msgs = msgs or []
280
  user_msg = (user_msg or "").strip()
281
  if not user_msg:
282
+ return "", ui_pairs_from_messages(msgs), msgs
283
 
284
  headers, err = get_headers()
285
  if err:
286
+ msgs = msgs + [
287
  {"role": "user", "content": user_msg},
288
  {"role": "assistant", "content": f"Setup error: {err}"},
289
  ]
290
+ return "", ui_pairs_from_messages(msgs), msgs
291
 
 
292
  model = (model_text or "").strip() or (model_dd_value or "").strip()
293
  if not model:
294
+ msgs = msgs + [
295
  {"role": "user", "content": user_msg},
296
+ {"role": "assistant", "content": "No model selected. Choose one or set Model override."},
297
  ]
298
+ return "", ui_pairs_from_messages(msgs), msgs
299
 
300
+ # Build request messages safely
301
+ req_messages = build_messages(sys_prompt or "You are a helpful assistant.", msgs, user_msg)
302
+ bot = chat_call(headers, model, req_messages, temp, mx)
303
 
304
+ msgs = msgs + [
305
  {"role": "user", "content": user_msg},
306
  {"role": "assistant", "content": bot},
307
  ]
308
+
309
+ return "", ui_pairs_from_messages(msgs), msgs
310
+
311
+ def do_clear():
312
+ return [], []
313
 
314
  demo.load(init, outputs=[status, model_dd])
315
  refresh_btn.click(do_refresh_models, outputs=[status, model_dd])
316
 
317
  send.click(
318
  respond,
319
+ inputs=[msg, msg_state, model_dd, model_override, system_prompt, temperature, max_tokens],
320
+ outputs=[msg, chatbot, msg_state],
321
  )
322
  msg.submit(
323
  respond,
324
+ inputs=[msg, msg_state, model_dd, model_override, system_prompt, temperature, max_tokens],
325
+ outputs=[msg, chatbot, msg_state],
326
  )
327
+ clear.click(do_clear, outputs=[chatbot, msg_state])
328
 
329
+ # Gradio 6.x: pass css to launch(), not Blocks()
330
+ demo.launch(css=CSS)