dzezzefezfz commited on
Commit
ebc3bd9
·
verified ·
1 Parent(s): d66cd82

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +240 -50
app.py CHANGED
@@ -4,35 +4,185 @@ import gradio as gr
4
 
5
  BASE_URL = "https://router.huggingface.co/v1"
6
 
 
 
 
7
  CSS = """
8
- :root{--bg:#0b0f19;--panel:rgba(255,255,255,.06);--panel2:rgba(255,255,255,.09);--text:rgba(255,255,255,.92);--muted:rgba(255,255,255,.65);--border:rgba(255,255,255,.12);--accent:#7c3aed;}
9
- body.light{--bg:#f6f7fb;--panel:rgba(0,0,0,.04);--panel2:rgba(0,0,0,.06);--text:rgba(0,0,0,.88);--muted:rgba(0,0,0,.60);--border:rgba(0,0,0,.10);--accent:#2563eb;}
10
- .gradio-container{background:var(--bg)!important;color:var(--text)!important;}
11
- .card{background:var(--panel);border:1px solid var(--border);border-radius:18px;padding:16px;}
12
- button.primary{background:var(--accent)!important;border:none!important;color:white!important;}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  """
14
 
15
  TOGGLE = """
16
  <div style="display:flex;align-items:center;gap:10px;user-select:none;">
17
- <span style="color:var(--muted);font-size:13px;">Theme</span>
18
  <label style="display:flex;align-items:center;gap:10px;">
19
- <span style="color:var(--muted);font-size:13px;">Light</span>
20
- <input id="themeToggle" type="checkbox"/>
21
- <span style="color:var(--muted);font-size:13px;">Dark</span>
22
  </label>
23
  </div>
 
24
  <script>
25
  const saved = localStorage.getItem("theme") || "dark";
26
  if(saved==="light") document.body.classList.add("light");
27
- const t=document.getElementById("themeToggle");
28
- t.checked=(saved!=="light");
29
- t.addEventListener("change",()=>{
30
- if(t.checked){document.body.classList.remove("light");localStorage.setItem("theme","dark");}
31
- else{document.body.classList.add("light");localStorage.setItem("theme","light");}
 
 
 
 
 
 
 
32
  });
33
  </script>
34
  """
35
 
 
 
 
36
  def get_headers():
37
  key = os.environ.get("HF_API_KEY")
38
  if not key:
@@ -49,75 +199,115 @@ def list_models(headers):
49
  return None, "No models available for this account"
50
  return models, None
51
 
52
- def chat_call(headers, model, messages):
53
  r = requests.post(
54
  f"{BASE_URL}/chat/completions",
55
  headers=headers,
56
- json={"model": model, "messages": messages, "temperature": 0.7, "max_tokens": 220},
 
 
 
 
 
57
  timeout=60,
58
  )
59
  if r.status_code != 200:
60
  return f"HTTP {r.status_code}: {r.text}"
61
- return r.json()["choices"][0]["message"]["content"]
62
 
63
- with gr.Blocks(title="My AI Chatbot") as demo:
64
- with gr.Column(elem_classes=["card"]):
65
- gr.Markdown("## My AI Chatbot")
66
- gr.HTML(TOGGLE)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
- status = gr.Markdown("Starting…")
69
- model_dd = gr.Dropdown(label="Model", choices=[], value=None, interactive=True)
 
70
 
71
- # Gradio 6.x Chatbot expects messages format by default:
72
- # history = [{"role":"user","content":"..."}, {"role":"assistant","content":"..."} ...]
73
- chatbot = gr.Chatbot(height=520)
74
 
 
 
 
 
75
 
76
- msg = gr.Textbox(placeholder="Type a message…", show_label=False)
77
- with gr.Row():
78
- send = gr.Button("Send", elem_classes=["primary"])
79
- clear = gr.Button("Clear")
 
 
 
 
 
 
 
 
 
80
 
81
  def init():
82
  headers, err = get_headers()
83
  if err:
84
  return f"❌ {err}", gr.update(choices=[], value=None)
 
85
  models, err = list_models(headers)
86
  if err:
87
  return f"❌ {err}", gr.update(choices=[], value=None)
 
88
  default_model = models[0]
89
  return f"✅ Ready. Using model: `{default_model}`", gr.update(choices=models, value=default_model)
90
 
91
- def respond(user_msg, history, model):
92
  history = history or []
 
 
 
93
 
94
  headers, err = get_headers()
95
  if err:
96
- history += [{"role": "user", "content": user_msg},
97
- {"role": "assistant", "content": f"Setup error: {err}"}]
 
 
98
  return "", history
99
 
100
  if not model:
101
- models, m_err = list_models(headers)
102
- if m_err:
103
- history += [{"role": "user", "content": user_msg},
104
- {"role": "assistant", "content": f"Model error: {m_err}"}]
105
- return "", history
106
- model = models[0]
107
-
108
- messages = [{"role": "system", "content": "You are a helpful assistant."}] + history + [
109
- {"role": "user", "content": user_msg}
110
- ]
111
- bot = chat_call(headers, model, messages)
112
 
113
- history += [{"role": "user", "content": user_msg},
114
- {"role": "assistant", "content": bot}]
 
 
 
 
 
115
  return "", history
116
 
117
  demo.load(init, outputs=[status, model_dd])
118
- send.click(respond, inputs=[msg, chatbot, model_dd], outputs=[msg, chatbot])
119
- msg.submit(respond, inputs=[msg, chatbot, model_dd], outputs=[msg, chatbot])
120
  clear.click(lambda: [], outputs=chatbot)
121
 
122
- # Gradio 6.x: pass css here, not in Blocks()
123
- demo.launch(css=CSS)
 
4
 
5
  BASE_URL = "https://router.huggingface.co/v1"
6
 
7
+ # ----------------------------
8
+ # ChatGPT-like CSS + theme vars
9
+ # ----------------------------
10
  CSS = """
11
+ :root{
12
+ --bg: #0b0f19;
13
+ --panel: rgba(255,255,255,.06);
14
+ --panel2: rgba(255,255,255,.09);
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{
26
+ --bg: #f6f7fb;
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
+ /* Center the app like ChatGPT */
45
+ #app_wrap{
46
+ max-width: 980px;
47
+ margin: 0 auto;
48
+ padding: 18px 14px 0 14px;
49
+ }
50
+
51
+ .header{
52
+ display:flex;
53
+ align-items:center;
54
+ justify-content:space-between;
55
+ gap: 12px;
56
+ padding: 10px 12px;
57
+ border: 1px solid var(--border);
58
+ border-radius: 16px;
59
+ background: var(--panel);
60
+ }
61
+
62
+ .header h2{
63
+ margin: 0;
64
+ font-size: 18px;
65
+ font-weight: 650;
66
+ }
67
+
68
+ .subtle{
69
+ color: var(--muted);
70
+ font-size: 12px;
71
+ }
72
+
73
+ /* Settings area */
74
+ .settings{
75
+ margin-top: 10px;
76
+ border: 1px solid var(--border);
77
+ border-radius: 16px;
78
+ background: var(--panel);
79
+ padding: 12px;
80
+ }
81
+
82
+ /* Chat area wrapper */
83
+ .chat_shell{
84
+ margin-top: 10px;
85
+ border: 1px solid var(--border);
86
+ border-radius: 16px;
87
+ background: var(--panel);
88
+ overflow: hidden;
89
+ }
90
+
91
+ /* Make Chatbot look like bubbles */
92
+ .chat_shell .wrap{
93
+ padding: 6px 6px 0 6px;
94
+ }
95
+
96
+ .chat_shell .message{
97
+ border-radius: 16px !important;
98
+ border: 1px solid var(--border) !important;
99
+ padding: 12px 12px !important;
100
+ margin: 8px 6px !important;
101
+ box-shadow: none !important;
102
+ }
103
+
104
+ /* assistant bubble */
105
+ .chat_shell .message.bot{
106
+ background: var(--bubble-assistant) !important;
107
+ }
108
+
109
+ /* user bubble */
110
+ .chat_shell .message.user{
111
+ background: var(--bubble-user) !important;
112
+ }
113
+
114
+ /* Composer like ChatGPT (sticky-ish) */
115
+ .composer{
116
+ margin-top: 10px;
117
+ border: 1px solid var(--border);
118
+ border-radius: 16px;
119
+ background: var(--panel);
120
+ padding: 10px;
121
+ }
122
+
123
+ .composer textarea, .composer input{
124
+ background: var(--input-bg) !important;
125
+ border: 1px solid var(--border) !important;
126
+ color: var(--text) !important;
127
+ border-radius: 14px !important;
128
+ }
129
+
130
+ /* Buttons */
131
+ button.primary{
132
+ background: var(--accent) !important;
133
+ border: none !important;
134
+ color: white !important;
135
+ border-radius: 14px !important;
136
+ }
137
+
138
+ button.secondary{
139
+ background: transparent !important;
140
+ border: 1px solid var(--border) !important;
141
+ color: var(--text) !important;
142
+ border-radius: 14px !important;
143
+ }
144
+
145
+ /* Reduce Gradio default paddings */
146
+ .gradio-container .prose{
147
+ max-width: 100% !important;
148
+ }
149
+
150
+ /* Hide the default footer */
151
+ footer{ display:none !important; }
152
  """
153
 
154
  TOGGLE = """
155
  <div style="display:flex;align-items:center;gap:10px;user-select:none;">
156
+ <span class="subtle">Theme</span>
157
  <label style="display:flex;align-items:center;gap:10px;">
158
+ <span class="subtle">Light</span>
159
+ <input id="themeToggle" type="checkbox" style="transform:scale(1.1);"/>
160
+ <span class="subtle">Dark</span>
161
  </label>
162
  </div>
163
+
164
  <script>
165
  const saved = localStorage.getItem("theme") || "dark";
166
  if(saved==="light") document.body.classList.add("light");
167
+
168
+ const t = document.getElementById("themeToggle");
169
+ t.checked = (saved !== "light");
170
+
171
+ t.addEventListener("change", ()=>{
172
+ if(t.checked){
173
+ document.body.classList.remove("light");
174
+ localStorage.setItem("theme","dark");
175
+ }else{
176
+ document.body.classList.add("light");
177
+ localStorage.setItem("theme","light");
178
+ }
179
  });
180
  </script>
181
  """
182
 
183
+ # ----------------------------
184
+ # API helpers
185
+ # ----------------------------
186
  def get_headers():
187
  key = os.environ.get("HF_API_KEY")
188
  if not key:
 
199
  return None, "No models available for this account"
200
  return models, None
201
 
202
+ def chat_call(headers, model, messages, temperature=0.7, max_tokens=800):
203
  r = requests.post(
204
  f"{BASE_URL}/chat/completions",
205
  headers=headers,
206
+ json={
207
+ "model": model,
208
+ "messages": messages,
209
+ "temperature": temperature,
210
+ "max_tokens": max_tokens,
211
+ },
212
  timeout=60,
213
  )
214
  if r.status_code != 200:
215
  return f"HTTP {r.status_code}: {r.text}"
 
216
 
217
+ data = r.json()
218
+ try:
219
+ return data["choices"][0]["message"]["content"]
220
+ except Exception:
221
+ return f"Unexpected response: {data}"
222
+
223
+ # ----------------------------
224
+ # Conversation management
225
+ # ----------------------------
226
+ MAX_TURNS = 14 # number of user+assistant pairs to keep
227
+
228
+ def build_messages(history, user_msg):
229
+ # history is already in [{"role": "...", "content": "..."}] format
230
+ trimmed = (history or [])[-MAX_TURNS * 2 :]
231
+ return [{"role": "system", "content": "You are a helpful assistant."}] + trimmed + [
232
+ {"role": "user", "content": user_msg}
233
+ ]
234
+
235
+ # ----------------------------
236
+ # Gradio UI
237
+ # ----------------------------
238
+ with gr.Blocks(title="ChatGPT-style Gradio Chat", css=CSS) as demo:
239
+ with gr.Column(elem_id="app_wrap"):
240
 
241
+ with gr.Row(elem_classes=["header"]):
242
+ gr.Markdown("## My AI Chatbot", elem_classes=[])
243
+ gr.HTML(TOGGLE)
244
 
245
+ status = gr.Markdown("Starting…", elem_classes=["subtle"])
 
 
246
 
247
+ with gr.Column(elem_classes=["settings"]):
248
+ model_dd = gr.Dropdown(label="Model", choices=[], value=None, interactive=True)
249
+ temperature = gr.Slider(0.0, 1.5, value=0.7, step=0.05, label="Temperature")
250
+ max_tokens = gr.Slider(64, 2048, value=800, step=32, label="Max tokens")
251
 
252
+ with gr.Column(elem_classes=["chat_shell"]):
253
+ # Gradio 6.x supports "messages" style history for Chatbot
254
+ chatbot = gr.Chatbot(height=560)
255
+
256
+ with gr.Column(elem_classes=["composer"]):
257
+ msg = gr.Textbox(
258
+ placeholder="Message…",
259
+ show_label=False,
260
+ lines=1,
261
+ )
262
+ with gr.Row():
263
+ send = gr.Button("Send", elem_classes=["primary"])
264
+ clear = gr.Button("Clear", elem_classes=["secondary"])
265
 
266
  def init():
267
  headers, err = get_headers()
268
  if err:
269
  return f"❌ {err}", gr.update(choices=[], value=None)
270
+
271
  models, err = list_models(headers)
272
  if err:
273
  return f"❌ {err}", gr.update(choices=[], value=None)
274
+
275
  default_model = models[0]
276
  return f"✅ Ready. Using model: `{default_model}`", gr.update(choices=models, value=default_model)
277
 
278
+ def respond(user_msg, history, model, temp, mx):
279
  history = history or []
280
+ user_msg = (user_msg or "").strip()
281
+ if not user_msg:
282
+ return "", history
283
 
284
  headers, err = get_headers()
285
  if err:
286
+ history += [
287
+ {"role": "user", "content": user_msg},
288
+ {"role": "assistant", "content": f"Setup error: {err}"},
289
+ ]
290
  return "", history
291
 
292
  if not model:
293
+ history += [
294
+ {"role": "user", "content": user_msg},
295
+ {"role": "assistant", "content": "Please select a model first."},
296
+ ]
297
+ return "", history
 
 
 
 
 
 
298
 
299
+ messages = build_messages(history, user_msg)
300
+ bot = chat_call(headers, model, messages, temperature=float(temp), max_tokens=int(mx))
301
+
302
+ history += [
303
+ {"role": "user", "content": user_msg},
304
+ {"role": "assistant", "content": bot},
305
+ ]
306
  return "", history
307
 
308
  demo.load(init, outputs=[status, model_dd])
309
+ send.click(respond, inputs=[msg, chatbot, model_dd, temperature, max_tokens], outputs=[msg, chatbot])
310
+ msg.submit(respond, inputs=[msg, chatbot, model_dd, temperature, max_tokens], outputs=[msg, chatbot])
311
  clear.click(lambda: [], outputs=chatbot)
312
 
313
+ demo.launch()