dzezzefezfz commited on
Commit
311bf98
·
verified ·
1 Parent(s): 311a85a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -215
app.py CHANGED
@@ -2,191 +2,26 @@ import os
2
  import requests
3
  import gradio as gr
4
 
5
- # -----------------------------
6
- # Hugging Face Router (OpenAI-compatible)
7
- # -----------------------------
8
- HF_API_KEY = os.environ.get("HF_API_KEY")
9
- if not HF_API_KEY:
10
- raise RuntimeError("HF_API_KEY is not set in Space variables")
11
-
12
  BASE_URL = "https://router.huggingface.co/v1"
13
- HEADERS = {
14
- "Authorization": f"Bearer {HF_API_KEY}",
15
- "Content-Type": "application/json",
16
- }
17
-
18
- def get_first_model():
19
- r = requests.get(f"{BASE_URL}/models", headers=HEADERS, timeout=30)
20
- if r.status_code != 200:
21
- raise RuntimeError(f"Cannot list models. HTTP {r.status_code}: {r.text}")
22
- data = r.json()
23
- models = data.get("data", [])
24
- if not models:
25
- raise RuntimeError("No models returned for your account. Enable an Inference Provider in HF settings.")
26
- return models[0]["id"]
27
-
28
- MODEL = get_first_model()
29
-
30
- def call_model(messages):
31
- payload = {
32
- "model": MODEL,
33
- "messages": messages,
34
- "temperature": 0.7,
35
- "max_tokens": 250,
36
- }
37
- r = requests.post(f"{BASE_URL}/chat/completions", headers=HEADERS, json=payload, timeout=60)
38
- if r.status_code != 200:
39
- return f"HTTP {r.status_code}: {r.text}"
40
- data = r.json()
41
- return data["choices"][0]["message"]["content"]
42
-
43
-
44
- # -----------------------------
45
- # UI + Chat logic
46
- # -----------------------------
47
- def respond(user_msg, history):
48
- history = history or []
49
- # Convert Gradio history (list of [user, bot]) -> OpenAI-style messages
50
- messages = [{"role": "system", "content": "You are a helpful assistant. Keep answers concise unless asked otherwise."}]
51
- for u, b in history:
52
- messages.append({"role": "user", "content": u})
53
- messages.append({"role": "assistant", "content": b})
54
-
55
- messages.append({"role": "user", "content": user_msg})
56
- bot_msg = call_model(messages)
57
-
58
- history.append([user_msg, bot_msg])
59
- return "", history
60
-
61
 
62
- # -----------------------------
63
- # Modern CSS + theme toggle (light/dark)
64
- # -----------------------------
65
  CSS = """
66
- :root{
67
- --bg: #0b0f19;
68
- --panel: rgba(255,255,255,0.06);
69
- --panel-2: rgba(255,255,255,0.08);
70
- --text: rgba(255,255,255,0.92);
71
- --muted: rgba(255,255,255,0.68);
72
- --border: rgba(255,255,255,0.12);
73
- --accent: #7c3aed; /* purple */
74
- --shadow: 0 10px 30px rgba(0,0,0,0.35);
75
- }
76
-
77
- body.light{
78
- --bg: #f6f7fb;
79
- --panel: rgba(0,0,0,0.04);
80
- --panel-2: rgba(0,0,0,0.06);
81
- --text: rgba(0,0,0,0.88);
82
- --muted: rgba(0,0,0,0.60);
83
- --border: rgba(0,0,0,0.10);
84
- --accent: #2563eb; /* blue */
85
- --shadow: 0 10px 30px rgba(0,0,0,0.10);
86
- }
87
-
88
- .gradio-container{
89
- background: var(--bg) !important;
90
- color: var(--text) !important;
91
- }
92
-
93
- #app_wrap{
94
- max-width: 980px;
95
- margin: 0 auto;
96
- }
97
-
98
- .card{
99
- background: var(--panel);
100
- border: 1px solid var(--border);
101
- border-radius: 18px;
102
- box-shadow: var(--shadow);
103
- }
104
-
105
- .header{
106
- display: flex;
107
- align-items: center;
108
- justify-content: space-between;
109
- gap: 12px;
110
- padding: 18px 18px 10px 18px;
111
- }
112
-
113
- .title{
114
- font-size: 22px;
115
- font-weight: 700;
116
- letter-spacing: 0.2px;
117
- }
118
-
119
- .subtitle{
120
- font-size: 13px;
121
- color: var(--muted);
122
- margin-top: 4px;
123
- }
124
-
125
- .badge{
126
- padding: 6px 10px;
127
- border-radius: 999px;
128
- background: var(--panel-2);
129
- border: 1px solid var(--border);
130
- color: var(--muted);
131
- font-size: 12px;
132
- white-space: nowrap;
133
- }
134
-
135
- /* Chat area */
136
- #chat{
137
- border-top: 1px solid var(--border);
138
- padding: 14px 14px 0 14px;
139
- }
140
-
141
- #chat .wrap{
142
- border-radius: 16px;
143
- }
144
-
145
- /* Input row */
146
- #input_row{
147
- display: flex;
148
- gap: 10px;
149
- padding: 14px;
150
- border-top: 1px solid var(--border);
151
- }
152
-
153
- #input_row textarea, #input_row input{
154
- background: var(--panel-2) !important;
155
- border: 1px solid var(--border) !important;
156
- color: var(--text) !important;
157
- border-radius: 14px !important;
158
- }
159
-
160
- button.primary{
161
- background: var(--accent) !important;
162
- border: none !important;
163
- color: white !important;
164
- border-radius: 14px !important;
165
- }
166
-
167
- button.secondary{
168
- background: var(--panel-2) !important;
169
- border: 1px solid var(--border) !important;
170
- color: var(--text) !important;
171
- border-radius: 14px !important;
172
- }
173
-
174
- /* Toggle */
175
- .toggle{
176
- display:flex;
177
- align-items:center;
178
- gap:10px;
179
- user-select:none;
180
- }
181
-
182
- .toggle input{
183
- width: 44px;
184
- height: 24px;
185
- }
186
  """
187
 
188
  THEME_TOGGLE_HTML = """
189
- <div class="toggle">
190
  <span style="color:var(--muted); font-size:13px;">Theme</span>
191
  <label style="display:flex; align-items:center; gap:10px;">
192
  <span style="color:var(--muted); font-size:13px;">Light</span>
@@ -194,58 +29,96 @@ THEME_TOGGLE_HTML = """
194
  <span style="color:var(--muted); font-size:13px;">Dark</span>
195
  </label>
196
  </div>
197
-
198
  <script>
199
- // default to dark unless user saved preference
200
  const saved = localStorage.getItem("theme") || "dark";
201
  if (saved === "light") document.body.classList.add("light");
202
- const toggle = document.getElementById("themeToggle");
203
- // checked = dark
204
- toggle.checked = (saved !== "light");
205
-
206
- toggle.addEventListener("change", () => {
207
- if (toggle.checked) {
208
- document.body.classList.remove("light");
209
- localStorage.setItem("theme", "dark");
210
- } else {
211
- document.body.classList.add("light");
212
- localStorage.setItem("theme", "light");
213
- }
214
  });
215
  </script>
216
  """
217
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  with gr.Blocks(css=CSS, title="My AI Chatbot") as demo:
219
- with gr.Column(elem_id="app_wrap"):
220
  with gr.Group(elem_classes=["card"]):
221
  with gr.Row(elem_classes=["header"]):
222
  with gr.Column(scale=3):
223
- gr.Markdown(f"""
224
- <div class="title">My AI Chatbot</div>
225
- <div class="subtitle">Modern UI • Light/Dark mode toggle • Running model: <span class="badge">{MODEL}</span></div>
226
- """)
227
  gr.HTML(THEME_TOGGLE_HTML)
228
 
229
- chatbot = gr.Chatbot(
230
- elem_id="chat",
231
- height=520,
232
- show_copy_button=True,
233
- bubble_full_width=False,
234
- )
235
-
236
- with gr.Row(elem_id="input_row"):
237
- msg = gr.Textbox(
238
- placeholder="Type a message…",
239
- show_label=False,
240
- container=False,
241
- scale=8,
242
- )
243
  send = gr.Button("Send", variant="primary", elem_classes=["primary"], scale=2)
244
  clear = gr.Button("Clear", variant="secondary", elem_classes=["secondary"], scale=2)
245
 
246
- # Wire events
247
- send.click(respond, inputs=[msg, chatbot], outputs=[msg, chatbot])
248
- msg.submit(respond, inputs=[msg, chatbot], outputs=[msg, chatbot])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  clear.click(lambda: [], outputs=chatbot)
250
 
251
  demo.launch()
 
2
  import requests
3
  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,0.06);--panel2:rgba(255,255,255,0.08);--text:rgba(255,255,255,0.92);--muted:rgba(255,255,255,0.68);--border:rgba(255,255,255,0.12);--accent:#7c3aed;}
9
+ body.light{--bg:#f6f7fb;--panel:rgba(0,0,0,0.04);--panel2:rgba(0,0,0,0.06);--text:rgba(0,0,0,0.88);--muted:rgba(0,0,0,0.60);--border:rgba(0,0,0,0.10);--accent:#2563eb;}
10
+ .gradio-container{background:var(--bg)!important;color:var(--text)!important;}
11
+ #wrap{max-width:980px;margin:0 auto;}
12
+ .card{background:var(--panel);border:1px solid var(--border);border-radius:18px;}
13
+ .header{display:flex;justify-content:space-between;align-items:center;padding:18px 18px 10px;}
14
+ .title{font-size:22px;font-weight:700;}
15
+ .subtitle{font-size:13px;color:var(--muted);margin-top:4px;}
16
+ .badge{padding:6px 10px;border-radius:999px;background:var(--panel2);border:1px solid var(--border);color:var(--muted);font-size:12px;white-space:nowrap;}
17
+ #inputrow{display:flex;gap:10px;padding:14px;border-top:1px solid var(--border);}
18
+ #inputrow textarea{background:var(--panel2)!important;border:1px solid var(--border)!important;color:var(--text)!important;border-radius:14px!important;}
19
+ button.primary{background:var(--accent)!important;border:none!important;color:white!important;border-radius:14px!important;}
20
+ button.secondary{background:var(--panel2)!important;border:1px solid var(--border)!important;color:var(--text)!important;border-radius:14px!important;}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  """
22
 
23
  THEME_TOGGLE_HTML = """
24
+ <div style="display:flex;align-items:center;gap:10px;user-select:none;">
25
  <span style="color:var(--muted); font-size:13px;">Theme</span>
26
  <label style="display:flex; align-items:center; gap:10px;">
27
  <span style="color:var(--muted); font-size:13px;">Light</span>
 
29
  <span style="color:var(--muted); font-size:13px;">Dark</span>
30
  </label>
31
  </div>
 
32
  <script>
 
33
  const saved = localStorage.getItem("theme") || "dark";
34
  if (saved === "light") document.body.classList.add("light");
35
+ const t = document.getElementById("themeToggle");
36
+ t.checked = (saved !== "light");
37
+ t.addEventListener("change", () => {
38
+ if (t.checked) { document.body.classList.remove("light"); localStorage.setItem("theme","dark"); }
39
+ else { document.body.classList.add("light"); localStorage.setItem("theme","light"); }
 
 
 
 
 
 
 
40
  });
41
  </script>
42
  """
43
 
44
+ def get_headers():
45
+ key = os.environ.get("HF_API_KEY")
46
+ if not key:
47
+ return None, "HF_API_KEY is missing. Go to Space Settings → Variables and add HF_API_KEY, then restart/build."
48
+ return {
49
+ "Authorization": f"Bearer {key}",
50
+ "Content-Type": "application/json",
51
+ }, None
52
+
53
+ def list_models(headers):
54
+ r = requests.get(f"{BASE_URL}/models", headers=headers, timeout=30)
55
+ if r.status_code != 200:
56
+ return None, f"Cannot list models. HTTP {r.status_code}: {r.text}"
57
+ data = r.json()
58
+ models = data.get("data", [])
59
+ if not models:
60
+ return None, "No models returned for your account. You likely need to enable an Inference Provider in HF settings."
61
+ return [m["id"] for m in models if "id" in m], None
62
+
63
+ def chat_call(headers, model, history, user_msg):
64
+ messages = [{"role": "system", "content": "You are a helpful assistant. Keep answers concise unless asked otherwise."}]
65
+ for u, b in history:
66
+ messages.append({"role": "user", "content": u})
67
+ messages.append({"role": "assistant", "content": b})
68
+ messages.append({"role": "user", "content": user_msg})
69
+
70
+ payload = {"model": model, "messages": messages, "temperature": 0.7, "max_tokens": 250}
71
+ r = requests.post(f"{BASE_URL}/chat/completions", headers=headers, json=payload, timeout=60)
72
+ if r.status_code != 200:
73
+ return f"HTTP {r.status_code}: {r.text}"
74
+ data = r.json()
75
+ return data["choices"][0]["message"]["content"]
76
+
77
  with gr.Blocks(css=CSS, title="My AI Chatbot") as demo:
78
+ with gr.Column(elem_id="wrap"):
79
  with gr.Group(elem_classes=["card"]):
80
  with gr.Row(elem_classes=["header"]):
81
  with gr.Column(scale=3):
82
+ title = gr.Markdown("<div class='title'>My AI Chatbot</div><div class='subtitle'>Modern UI • Light/Dark mode toggle</div>")
 
 
 
83
  gr.HTML(THEME_TOGGLE_HTML)
84
 
85
+ status = gr.Markdown("") # shows key/model errors without crashing
86
+ model_dd = gr.Dropdown(label="Model", choices=[], value=None, interactive=True)
87
+
88
+ chatbot = gr.Chatbot(height=520, show_copy_button=True, bubble_full_width=False)
89
+
90
+ with gr.Row(elem_id="inputrow"):
91
+ msg = gr.Textbox(placeholder="Type a message…", show_label=False, container=False, scale=8)
 
 
 
 
 
 
 
92
  send = gr.Button("Send", variant="primary", elem_classes=["primary"], scale=2)
93
  clear = gr.Button("Clear", variant="secondary", elem_classes=["secondary"], scale=2)
94
 
95
+ def init():
96
+ headers, err = get_headers()
97
+ if err:
98
+ return gr.update(value=f"**Setup error:** {err}"), gr.update(choices=[], value=None)
99
+
100
+ models, err = list_models(headers)
101
+ if err:
102
+ return gr.update(value=f"**Provider error:** {err}"), gr.update(choices=[], value=None)
103
+
104
+ default_model = models[0]
105
+ return gr.update(value=f"**Ready.** Using model: `{default_model}`"), gr.update(choices=models, value=default_model)
106
+
107
+ def respond(user_msg, history, model):
108
+ headers, err = get_headers()
109
+ if err:
110
+ history = history or []
111
+ history.append([user_msg, f"Setup error: {err}"])
112
+ return "", history
113
+
114
+ history = history or []
115
+ bot = chat_call(headers, model, history, user_msg)
116
+ history.append([user_msg, bot])
117
+ return "", history
118
+
119
+ demo.load(init, inputs=None, outputs=[status, model_dd])
120
+ send.click(respond, inputs=[msg, chatbot, model_dd], outputs=[msg, chatbot])
121
+ msg.submit(respond, inputs=[msg, chatbot, model_dd], outputs=[msg, chatbot])
122
  clear.click(lambda: [], outputs=chatbot)
123
 
124
  demo.launch()