Wfafa commited on
Commit
627902e
ยท
verified ยท
1 Parent(s): c120258

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +366 -58
app.py CHANGED
@@ -1,70 +1,378 @@
 
1
  import gradio as gr
2
- from huggingface_hub import InferenceClient
 
 
3
 
 
 
 
 
 
 
4
 
5
- def respond(
6
- message,
7
- history: list[dict[str, str]],
8
- system_message,
9
- max_tokens,
10
- temperature,
11
- top_p,
12
- hf_token: gr.OAuthToken,
13
- ):
14
- """
15
- For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
16
- """
17
- client = InferenceClient(token=hf_token.token, model="openai/gpt-oss-20b")
 
 
 
18
 
19
- messages = [{"role": "system", "content": system_message}]
 
20
 
21
- messages.extend(history)
 
 
 
 
22
 
23
- messages.append({"role": "user", "content": message})
 
 
24
 
25
- response = ""
26
 
27
- for message in client.chat_completion(
28
- messages,
29
- max_tokens=max_tokens,
30
- stream=True,
31
- temperature=temperature,
32
- top_p=top_p,
33
- ):
34
- choices = message.choices
35
- token = ""
36
- if len(choices) and choices[0].delta.content:
37
- token = choices[0].delta.content
38
 
39
- response += token
40
- yield response
 
 
 
 
 
41
 
 
 
 
 
 
 
 
 
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  """
44
- For information on how to customize the ChatInterface, peruse the gradio docs: https://www.gradio.app/docs/chatinterface
45
- """
46
- chatbot = gr.ChatInterface(
47
- respond,
48
- type="messages",
49
- additional_inputs=[
50
- gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
51
- gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
52
- gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
53
- gr.Slider(
54
- minimum=0.1,
55
- maximum=1.0,
56
- value=0.95,
57
- step=0.05,
58
- label="Top-p (nucleus sampling)",
59
- ),
60
- ],
61
- )
62
-
63
- with gr.Blocks() as demo:
64
- with gr.Sidebar():
65
- gr.LoginButton()
66
- chatbot.render()
67
-
68
-
69
- if __name__ == "__main__":
70
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
  import gradio as gr
3
+ import requests
4
+ import json
5
+ import time
6
 
7
+ # Test HF_TOKEN
8
+ HF_TOKEN = os.getenv("HF_TOKEN")
9
+ if not HF_TOKEN:
10
+ print("Error: HF_TOKEN not set. Please set your Hugging Face API token.")
11
+ else:
12
+ print("HF_TOKEN loaded successfully.")
13
 
14
+ # ๐ŸŒ Web search function (unchanged)
15
+ def search_web(query):
16
+ try:
17
+ url = "https://api.duckduckgo.com/"
18
+ params = {"q": query, "format": "json", "no_html": 1, "skip_disambig": 1}
19
+ response = requests.get(url, params=params)
20
+ data = response.json()
21
+ if data.get("AbstractText"):
22
+ return data["AbstractText"]
23
+ elif data.get("RelatedTopics"):
24
+ topics = [t.get("Text", "") for t in data["RelatedTopics"] if "Text" in t]
25
+ return " ".join(topics[:3])
26
+ else:
27
+ return "No useful information found."
28
+ except Exception as e:
29
+ return f"Search error: {e}"
30
 
31
+ # ๐Ÿง  Memory setup (unchanged)
32
+ MEMORY_FILE = "memory.json"
33
 
34
+ def load_memory():
35
+ if os.path.exists(MEMORY_FILE):
36
+ with open(MEMORY_FILE, "r") as f:
37
+ return json.load(f)
38
+ return []
39
 
40
+ def save_memory(memory):
41
+ with open(MEMORY_FILE, "w") as f:
42
+ json.dump(memory, f)
43
 
44
+ memory = load_memory()
45
 
46
+ # ๐Ÿ’ฌ Chat function (removed file_input handling)
47
+ def chat_with_model(message, history, context):
48
+ if not isinstance(history, list):
49
+ history = []
 
 
 
 
 
 
 
50
 
51
+ if message.lower().startswith("search "):
52
+ query = message[7:]
53
+ search_result = search_web(query)
54
+ timestamp = time.strftime("%H:%M")
55
+ history.append((f"{message} <span class='timestamp'>{timestamp}</span>", f"๐Ÿ”Ž Here's what I found online:\n\n{search_result} <span class='timestamp'>{timestamp}</span>"))
56
+ save_memory(history)
57
+ return history, history
58
 
59
+ conversation = [
60
+ {"role": "system", "content": (
61
+ "You are EduAI, a multilingual educational AI assistant created by a Sri Lankan student named Wafa Fazly. "
62
+ "When solving math, explain step-by-step like a professional tutor. "
63
+ "Use Markdown and LaTeX formatting for equations (use \\[ and \\]). "
64
+ "Keep answers neat, structured, and student-friendly."
65
+ )}
66
+ ]
67
 
68
+ for past_user, past_bot in history[-5:]:
69
+ conversation.append({"role": "user", "content": past_user.split(' <span')[0]}) # Strip timestamp for API
70
+ conversation.append({"role": "assistant", "content": past_bot.split(' <span')[0]})
71
+
72
+ conversation.append({"role": "user", "content": message})
73
+
74
+ try:
75
+ response = requests.post(
76
+ "https://router.huggingface.co/v1/chat/completions",
77
+ headers={
78
+ "Authorization": f"Bearer {HF_TOKEN}",
79
+ "Content-Type": "application/json"
80
+ },
81
+ json={
82
+ "model": "deepseek-ai/DeepSeek-V3.2-Exp:novita",
83
+ "messages": conversation
84
+ }
85
+ )
86
+ if response.status_code != 200:
87
+ raise Exception(f"API Error: {response.status_code} - {response.text}")
88
+
89
+ data = response.json()
90
+ reply = data["choices"][0]["message"]["content"]
91
+
92
+ reply = reply.replace("Step", "\n\n**Step").replace(":", ":**").replace("\\[", "\n\n\\[").replace("\\]", "\\]\n\n")
93
+
94
+ timestamp = time.strftime("%H:%M")
95
+ history.append((f"{message} <span class='timestamp'>{timestamp}</span>", f"{reply} <span class='timestamp'>{timestamp}</span>"))
96
+ save_memory(history)
97
+ return history, history
98
+
99
+ except Exception as e:
100
+ print("Backend Error:", e)
101
+ timestamp = time.strftime("%H:%M")
102
+ error_msg = f"๐Ÿ˜… EduAI is having trouble connecting right now. Check your HF_TOKEN or try again later! <span class='timestamp'>{timestamp}</span>"
103
+ history.append((f"{message} <span class='timestamp'>{timestamp}</span>", error_msg))
104
+ return history, history
105
+
106
+ # ๐Ÿ“˜ Sidebar context update (unchanged)
107
+ def update_context(choice):
108
+ if not choice:
109
+ return "๐Ÿ“˜ **You are in General Mode.** Ask EduAI anything about your studies!"
110
+ return f"๐Ÿ“˜ **You selected {choice} mode.** Ask anything related to this topic!"
111
+
112
+ # ๐Ÿงน Clear chat memory (unchanged)
113
+ def clear_memory():
114
+ if os.path.exists(MEMORY_FILE):
115
+ os.remove(MEMORY_FILE)
116
+ return [], "๐Ÿงน Chat memory cleared! Start fresh."
117
+
118
+ # ๐Ÿ–Œ Custom CSS (unchanged, but input-row simplified)
119
+ custom_css = """
120
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
121
+
122
+ body {
123
+ font-family: 'Inter', sans-serif;
124
+ margin: 0;
125
+ padding: 0;
126
+ background: #0f0f0f;
127
+ color: #e0e0e0;
128
+ min-height: 100vh;
129
+ }
130
+ .gradio-container {
131
+ background: transparent;
132
+ box-shadow: none;
133
+ }
134
+ .header-title {
135
+ font-size: 28px;
136
+ text-align: center;
137
+ margin-bottom: 20px;
138
+ font-weight: 600;
139
+ color: #007BFF;
140
+ text-shadow: 0 0 10px rgba(0, 123, 255, 0.5);
141
+ }
142
+ .sidebar {
143
+ background: #1a1a1a;
144
+ padding: 20px;
145
+ border-radius: 12px;
146
+ box-shadow: 0 4px 12px rgba(0,0,0,0.5);
147
+ border: 1px solid #333;
148
+ width: 280px;
149
+ }
150
+ .menu-title {
151
+ font-size: 18px;
152
+ font-weight: 500;
153
+ margin-bottom: 15px;
154
+ color: #007BFF;
155
+ }
156
+ .accordion {
157
+ border-radius: 10px;
158
+ margin-bottom: 10px;
159
+ box-shadow: 0 2px 6px rgba(0,0,0,0.3);
160
+ }
161
+ .accordion-header {
162
+ background: #2a2a2a;
163
+ color: #e0e0e0;
164
+ border-radius: 10px;
165
+ padding: 12px;
166
+ font-weight: 500;
167
+ cursor: pointer;
168
+ transition: background 0.3s;
169
+ }
170
+ .accordion-header:hover {
171
+ background: #007BFF;
172
+ color: #0f0f0f;
173
+ }
174
+ .main-chat {
175
+ padding: 20px;
176
+ background: #0f0f0f;
177
+ display: flex;
178
+ flex-direction: column;
179
+ height: calc(100vh - 100px);
180
+ }
181
+ .context-box {
182
+ background: #1a1a1a;
183
+ padding: 15px;
184
+ border-radius: 10px;
185
+ box-shadow: 0 2px 6px rgba(0,0,0,0.3);
186
+ margin-bottom: 15px;
187
+ border: 1px solid #333;
188
+ color: #e0e0e0;
189
+ font-size: 14px;
190
+ }
191
+ .chatbox {
192
+ flex: 1;
193
+ border-radius: 10px;
194
+ box-shadow: 0 2px 6px rgba(0,0,0,0.3);
195
+ background: #1a1a1a;
196
+ border: 1px solid #333;
197
+ padding: 15px;
198
+ overflow-y: auto;
199
+ }
200
+ .message {
201
+ display: flex;
202
+ margin: 15px 0;
203
+ animation: fadeIn 0.5s ease-in;
204
+ }
205
+ @keyframes fadeIn {
206
+ from { opacity: 0; transform: translateY(10px); }
207
+ to { opacity: 1; transform: translateY(0); }
208
+ }
209
+ .message.user {
210
+ justify-content: flex-end;
211
+ }
212
+ .message.ai {
213
+ justify-content: flex-start;
214
+ }
215
+ .message .avatar {
216
+ width: 40px;
217
+ height: 40px;
218
+ border-radius: 50%;
219
+ margin: 0 10px;
220
+ background: #007BFF;
221
+ display: flex;
222
+ align-items: center;
223
+ justify-content: center;
224
+ color: white;
225
+ font-weight: 600;
226
+ font-size: 16px;
227
+ }
228
+ .message.ai .avatar {
229
+ background: #333;
230
+ }
231
+ .message .bubble {
232
+ max-width: 70%;
233
+ padding: 12px 16px;
234
+ border-radius: 18px;
235
+ position: relative;
236
+ }
237
+ .message.user .bubble {
238
+ background: #007BFF;
239
+ color: white;
240
+ }
241
+ .message.ai .bubble {
242
+ background: #2a2a2a;
243
+ color: #e0e0e0;
244
+ border: 1px solid #333;
245
+ }
246
+ .timestamp {
247
+ font-size: 10px;
248
+ opacity: 0.7;
249
+ margin-top: 5px;
250
+ display: block;
251
+ }
252
+ .typing {
253
+ display: none;
254
+ font-style: italic;
255
+ color: #aaa;
256
+ padding: 10px;
257
+ animation: pulse 1.5s infinite;
258
+ }
259
+ @keyframes pulse {
260
+ 0%, 100% { opacity: 0.5; }
261
+ 50% { opacity: 1; }
262
+ }
263
+ .input-row {
264
+ margin-top: 15px;
265
+ }
266
+ .chat-input {
267
+ width: 100%;
268
+ border-radius: 20px;
269
+ padding: 12px 16px;
270
+ border: 1px solid #555;
271
+ background: #1a1a1a;
272
+ color: #e0e0e0;
273
+ transition: border-color 0.3s;
274
+ font-size: 14px;
275
+ }
276
+ .chat-input:focus {
277
+ border-color: #007BFF;
278
+ outline: none;
279
+ }
280
+ .btn-clear {
281
+ background: #f44336;
282
+ color: white;
283
+ border-radius: 10px;
284
+ padding: 10px 15px;
285
+ border: none;
286
+ font-weight: 500;
287
+ cursor: pointer;
288
+ transition: background 0.3s;
289
+ }
290
+ .btn-clear:hover {
291
+ background: #d32f2f;
292
+ }
293
+ .about-text {
294
+ font-size: 14px;
295
+ color: #aaa;
296
+ line-height: 1.5;
297
+ }
298
+ .radio {
299
+ margin: 10px 0;
300
+ }
301
+ .radio label {
302
+ color: #e0e0e0;
303
+ }
304
  """
305
+
306
+ # ๐ŸŽจ Gradio Interface without file uploader
307
+ with gr.Blocks(theme=gr.themes.Base(), css=custom_css) as iface:
308
+ gr.Markdown("# ๐Ÿค– **EduAI**", elem_classes="header-title")
309
+
310
+ with gr.Row():
311
+ with gr.Column(scale=1, elem_classes="sidebar"):
312
+ gr.Markdown("### ๐Ÿงญ **Menu**", elem_classes="menu-title")
313
+
314
+ with gr.Accordion("๐Ÿ“š Subject Tutor", open=False):
315
+ subj = gr.Radio(
316
+ ["Science ๐Ÿงช", "ICT ๐Ÿ’ป", "English ๐Ÿ“˜", "Mathematics โž—"],
317
+ label="Choose a subject",
318
+ type="index"
319
+ )
320
+
321
+ with gr.Accordion("๐Ÿ—“ Study Planner", open=False):
322
+ planner = gr.Radio(
323
+ ["View Plan ๐Ÿ“…", "Add Task โœ๏ธ", "Study Tips ๐Ÿ’ก"],
324
+ label="Planner Options",
325
+ type="index"
326
+ )
327
+
328
+ with gr.Accordion("๐ŸŒ Languages", open=False):
329
+ lang = gr.Radio(
330
+ ["Learn Sinhala ๐Ÿ‡ฑ๐Ÿ‡ฐ", "Learn Tamil ๐Ÿ‡ฎ๐Ÿ‡ณ", "Learn English ๐Ÿ‡ฌ๐Ÿ‡ง", "Learn Spanish ๐Ÿ‡ช๐Ÿ‡ธ"],
331
+ label="Language Options",
332
+ type="index"
333
+ )
334
+
335
+ with gr.Accordion("โš™๏ธ Settings", open=False):
336
+ clear_btn = gr.Button("๐Ÿงน Clear Memory", elem_classes="btn-clear")
337
+
338
+ with gr.Accordion("๐Ÿ‘ฉโ€๐ŸŽ“ About", open=False):
339
+ gr.Markdown("""
340
+ EduAI โ€“ developed by **Wafa Fazly** using a pre-trained AI model.
341
+ Helps learners understand **Science, ICT, English, and more** in a simple, friendly way! ๐Ÿ’ฌ
342
+ """, elem_classes="about-text")
343
+
344
+ with gr.Column(scale=4, elem_classes="main-chat"):
345
+ context_display = gr.Markdown(
346
+ "๐Ÿ“˜ **You are in General Mode.** Ask EduAI anything about your studies!",
347
+ elem_classes="context-box"
348
+ )
349
+
350
+ chatbot = gr.Chatbot(
351
+ label="",
352
+ height=500,
353
+ render_markdown=True,
354
+ type="messages",
355
+ latex_delimiters=[{"left": "$$", "right": "$$", "display": True}, {"left": "\\[", "right": "\\]", "display": True}]
356
+ )
357
+
358
+ typing_indicator = gr.Markdown("", elem_classes="typing")
359
+
360
+ with gr.Row(elem_classes="input-row"):
361
+ msg = gr.Textbox(placeholder="Message EduAI...", elem_classes="chat-input", show_label=False)
362
+
363
+ # Event Handlers with typing indicator
364
+ def start_typing():
365
+ return "EduAI is typing..."
366
+
367
+ def stop_typing():
368
+ return ""
369
+
370
+ subj.change(update_context, inputs=subj, outputs=context_display)
371
+ planner.change(update_context, inputs=planner, outputs=context_display)
372
+ lang.change(update_context, inputs=lang, outputs=context_display)
373
+ msg.submit(start_typing, outputs=typing_indicator).then(
374
+ chat_with_model, inputs=[msg, chatbot, context_display], outputs=[chatbot, chatbot]
375
+ ).then(stop_typing, outputs=typing_indicator)
376
+ clear_btn.click(clear_memory, outputs=[chatbot, context_display])
377
+
378
+ iface.launch()