dzezzefezfz commited on
Commit
74ac7b1
·
verified ·
1 Parent(s): 0eeea8c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -101
app.py CHANGED
@@ -14,12 +14,8 @@ CSS = """
14
  --panel2:rgba(255,255,255,.08);
15
  --text:rgba(255,255,255,.92);
16
  --muted:rgba(255,255,255,.65);
17
- --border:rgba(255,255,255,.12);
18
- --accent:#7c3aed;
19
-
20
- --bubble-user:rgba(124,58,237,.18);
21
- --bubble-assistant:rgba(255,255,255,.06);
22
- --input-bg:rgba(255,255,255,.06);
23
  }
24
 
25
  body.light{
@@ -27,93 +23,72 @@ body.light{
27
  --panel:rgba(0,0,0,.04);
28
  --panel2:rgba(0,0,0,.06);
29
  --text:rgba(0,0,0,.88);
30
- --muted:rgba(0,0,0,.60);
31
  --border:rgba(0,0,0,.10);
32
- --accent:#2563eb;
33
-
34
- --bubble-user:rgba(37,99,235,.12);
35
- --bubble-assistant:rgba(0,0,0,.04);
36
- --input-bg:rgba(0,0,0,.04);
37
  }
38
 
39
  .gradio-container{
40
- background:var(--bg)!important;
41
- color:var(--text)!important;
 
 
42
  }
43
 
44
  #wrap{
45
  max-width: 980px;
46
- margin: 0 auto;
47
- padding: 18px 14px;
48
  }
49
 
50
  .header{
51
  display:flex;
52
- align-items:center;
53
  justify-content:space-between;
54
- gap:12px;
55
- padding:12px 14px;
56
- border:1px solid var(--border);
57
- border-radius:16px;
58
- background:var(--panel);
 
59
  }
60
 
61
- .header h2{ margin:0; font-size:18px; font-weight:650; }
62
- .subtle{ color:var(--muted); font-size:12px; }
63
-
64
  .block{
65
- margin-top:10px;
66
- border:1px solid var(--border);
67
- border-radius:16px;
68
- background:var(--panel);
69
- padding:12px;
 
70
  }
71
 
72
- .chat_shell{
73
- margin-top:10px;
74
- border:1px solid var(--border);
75
- border-radius:16px;
76
- background:var(--panel);
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;
84
- padding:12px 12px !important;
85
- margin:8px 10px !important;
86
- box-shadow:none !important;
87
  }
88
- .chat_shell .message.user{ background:var(--bubble-user) !important; }
89
- .chat_shell .message.bot{ background:var(--bubble-assistant) !important; }
90
 
91
  .composer{
92
- margin-top:10px;
93
- border:1px solid var(--border);
94
- border-radius:16px;
95
- background:var(--panel);
96
- padding:10px;
97
  }
98
 
99
- .composer textarea, .composer input{
100
- background:var(--input-bg)!important;
101
- border:1px solid var(--border)!important;
102
- color:var(--text)!important;
103
- border-radius:14px!important;
104
  }
105
 
106
- button.primary{
107
- background:var(--accent)!important;
108
- border:none!important;
109
- color:white!important;
110
- border-radius:14px!important;
111
  }
112
- button.secondary{
113
- background:transparent!important;
114
- border:1px solid var(--border)!important;
115
- color:var(--text)!important;
116
- border-radius:14px!important;
117
  }
118
 
119
  footer{ display:none !important; }
@@ -146,7 +121,7 @@ TOGGLE = """
146
  """
147
 
148
  # ----------------------------
149
- # API helpers
150
  # ----------------------------
151
  def get_headers():
152
  key = os.environ.get("HF_API_KEY")
@@ -154,6 +129,7 @@ def get_headers():
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)
159
  if r.status_code != 200:
@@ -164,6 +140,7 @@ def list_models(headers):
164
  return None, "No models returned"
165
  return models, None
166
 
 
167
  def chat_call(headers, model, messages, temperature, max_tokens):
168
  payload = {
169
  "model": model,
@@ -186,30 +163,11 @@ def chat_call(headers, model, messages, temperature, max_tokens):
186
  except Exception:
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)."""
@@ -218,12 +176,27 @@ def trimmed_messages(msgs):
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
  # ----------------------------
@@ -237,7 +210,12 @@ with gr.Blocks(title="Chat") as demo:
237
 
238
  with gr.Column(elem_classes=["block"]):
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(
@@ -251,8 +229,7 @@ with gr.Blocks(title="Chat") as demo:
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([])
@@ -267,19 +244,24 @@ with gr.Blocks(title="Chat") as demo:
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:
@@ -287,7 +269,7 @@ with gr.Blocks(title="Chat") as demo:
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:
@@ -295,9 +277,8 @@ with gr.Blocks(title="Chat") as demo:
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
 
@@ -305,8 +286,7 @@ with gr.Blocks(title="Chat") as demo:
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 [], []
@@ -326,5 +306,5 @@ with gr.Blocks(title="Chat") as demo:
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)
 
14
  --panel2:rgba(255,255,255,.08);
15
  --text:rgba(255,255,255,.92);
16
  --muted:rgba(255,255,255,.65);
17
+ --border:rgba(255,255,255,.10);
18
+ --shadow: 0 20px 60px rgba(0,0,0,.45);
 
 
 
 
19
  }
20
 
21
  body.light{
 
23
  --panel:rgba(0,0,0,.04);
24
  --panel2:rgba(0,0,0,.06);
25
  --text:rgba(0,0,0,.88);
26
+ --muted:rgba(0,0,0,.55);
27
  --border:rgba(0,0,0,.10);
28
+ --shadow: 0 20px 60px rgba(0,0,0,.12);
 
 
 
 
29
  }
30
 
31
  .gradio-container{
32
+ background: radial-gradient(1200px 700px at 20% 10%, rgba(98, 123, 255, .22), transparent 60%),
33
+ radial-gradient(1000px 700px at 80% 30%, rgba(255, 90, 150, .18), transparent 60%),
34
+ var(--bg) !important;
35
+ color: var(--text) !important;
36
  }
37
 
38
  #wrap{
39
  max-width: 980px;
40
+ margin: 22px auto;
41
+ padding: 0 14px;
42
  }
43
 
44
  .header{
45
  display:flex;
 
46
  justify-content:space-between;
47
+ align-items:center;
48
+ padding: 18px 14px;
49
+ border: 1px solid var(--border);
50
+ border-radius: 18px;
51
+ background: var(--panel);
52
+ box-shadow: var(--shadow);
53
  }
54
 
 
 
 
55
  .block{
56
+ border: 1px solid var(--border);
57
+ border-radius: 18px;
58
+ background: var(--panel);
59
+ box-shadow: var(--shadow);
60
+ padding: 14px;
61
+ margin-top: 14px;
62
  }
63
 
64
+ .subtle{ color: var(--muted); }
 
 
 
 
 
 
65
 
66
+ .chat_shell{
67
+ border: 1px solid var(--border);
68
+ border-radius: 18px;
69
+ background: var(--panel);
70
+ box-shadow: var(--shadow);
71
+ padding: 10px;
72
+ margin-top: 14px;
73
  }
 
 
74
 
75
  .composer{
76
+ margin-top: 10px;
 
 
 
 
77
  }
78
 
79
+ .primary button, .secondary button{
80
+ border-radius: 14px !important;
81
+ border: 1px solid var(--border) !important;
 
 
82
  }
83
 
84
+ .primary button{
85
+ background: rgba(98, 123, 255, .85) !important;
86
+ color: white !important;
 
 
87
  }
88
+
89
+ .secondary button{
90
+ background: var(--panel2) !important;
91
+ color: var(--text) !important;
 
92
  }
93
 
94
  footer{ display:none !important; }
 
121
  """
122
 
123
  # ----------------------------
124
+ # HF Router helpers
125
  # ----------------------------
126
  def get_headers():
127
  key = os.environ.get("HF_API_KEY")
 
129
  return None, "HF_API_KEY missing (Space Settings → Variables)"
130
  return {"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, None
131
 
132
+
133
  def list_models(headers):
134
  r = requests.get(f"{BASE_URL}/models", headers=headers, timeout=20)
135
  if r.status_code != 200:
 
140
  return None, "No models returned"
141
  return models, None
142
 
143
+
144
  def chat_call(headers, model, messages, temperature, max_tokens):
145
  payload = {
146
  "model": model,
 
163
  except Exception:
164
  return f"Unexpected response shape: {data}"
165
 
166
+
167
  # ----------------------------
168
+ # Message utilities
169
  # ----------------------------
170
+ MAX_TURNS = 14 # keep last N user+assistant pairs in history
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
 
172
  def trimmed_messages(msgs):
173
  """Trim to last MAX_TURNS pairs (2 messages each)."""
 
176
  return msgs[-MAX_TURNS * 2 :]
177
 
178
  def build_messages(system_prompt, msgs, user_msg):
179
+ """Build request payload messages (system + recent turns + new user)."""
180
  return (
181
  [{"role": "system", "content": system_prompt}]
182
  + trimmed_messages(msgs)
183
  + [{"role": "user", "content": user_msg}]
184
  )
185
 
186
+ def ui_messages_from_state(msgs):
187
+ """
188
+ Chatbot(type="messages") expects:
189
+ [{"role":"user"/"assistant", "content":"..."}, ...]
190
+ We hide "system" from the UI.
191
+ """
192
+ out = []
193
+ for m in msgs or []:
194
+ role = m.get("role")
195
+ if role in ("user", "assistant"):
196
+ out.append({"role": role, "content": m.get("content", "")})
197
+ return out
198
+
199
+
200
  # ----------------------------
201
  # Gradio app
202
  # ----------------------------
 
210
 
211
  with gr.Column(elem_classes=["block"]):
212
  with gr.Row():
213
+ model_dd = gr.Dropdown(
214
+ label="Model (from /v1/models)",
215
+ choices=[],
216
+ value=None,
217
+ interactive=True,
218
+ )
219
  refresh_btn = gr.Button("Refresh models", elem_classes=["secondary"])
220
 
221
  model_override = gr.Textbox(
 
229
  max_tokens = gr.Slider(64, 2048, value=800, step=32, label="Max tokens")
230
 
231
  with gr.Column(elem_classes=["chat_shell"]):
232
+ chatbot = gr.Chatbot(height=560, type="messages")
 
233
 
234
  # Internal message state (OpenAI-style dict list)
235
  msg_state = gr.State([])
 
244
  headers, err = get_headers()
245
  if err:
246
  return f"❌ {err}", gr.update(choices=[], value=None)
247
+
248
  models, err = list_models(headers)
249
  if err:
250
  return f"❌ {err}", gr.update(choices=[], value=None)
251
+
252
+ # Choose a default if available
253
+ default = models[0] if models else None
254
+ return f"✅ Models loaded ({len(models)}).", gr.update(choices=models, value=default)
255
 
256
  def init():
257
  return do_refresh_models()
258
 
259
  def respond(user_msg, msgs, model_dd_value, model_text, sys_prompt, temp, mx):
 
260
  user_msg = (user_msg or "").strip()
261
+ msgs = msgs or []
262
  if not user_msg:
263
+ # No-op; keep UI/state unchanged
264
+ return "", ui_messages_from_state(msgs), msgs
265
 
266
  headers, err = get_headers()
267
  if err:
 
269
  {"role": "user", "content": user_msg},
270
  {"role": "assistant", "content": f"Setup error: {err}"},
271
  ]
272
+ return "", ui_messages_from_state(msgs), msgs
273
 
274
  model = (model_text or "").strip() or (model_dd_value or "").strip()
275
  if not model:
 
277
  {"role": "user", "content": user_msg},
278
  {"role": "assistant", "content": "No model selected. Choose one or set Model override."},
279
  ]
280
+ return "", ui_messages_from_state(msgs), msgs
281
 
 
282
  req_messages = build_messages(sys_prompt or "You are a helpful assistant.", msgs, user_msg)
283
  bot = chat_call(headers, model, req_messages, temp, mx)
284
 
 
286
  {"role": "user", "content": user_msg},
287
  {"role": "assistant", "content": bot},
288
  ]
289
+ return "", ui_messages_from_state(msgs), msgs
 
290
 
291
  def do_clear():
292
  return [], []
 
306
  )
307
  clear.click(do_clear, outputs=[chatbot, msg_state])
308
 
309
+ # Gradio 6.x: css can be passed to launch()
310
  demo.launch(css=CSS)