EduBridgeee / app.py
Wfafa's picture
Update app.py
3247af6 verified
raw
history blame
9.97 kB
Perfect, Cherry! ๐Ÿ˜„ Hereโ€™s a **complete, ready-to-run Gradio AI agent** with:
* โœ… `type="messages"` properly implemented (no more incompatible data errors)
* โœ… Modern **dark theme** UI with rounded chat bubbles
* โœ… **Sidebar** with subjects, planner, languages, settings, and About section
* โœ… **Floating send button + file upload**
* โœ… **Context box** showing current mode
---
```python
import os
import gradio as gr
import requests
import json
# =======================
# Hugging Face Token
# =======================
HF_TOKEN = os.getenv("HF_TOKEN")
if not HF_TOKEN:
print("Error: HF_TOKEN not set.")
else:
print("HF_TOKEN loaded successfully.")
# =======================
# Memory
# =======================
MEMORY_FILE = "memory.json"
def load_memory():
if os.path.exists(MEMORY_FILE):
with open(MEMORY_FILE, "r") as f:
return json.load(f)
return []
def save_memory(memory):
with open(MEMORY_FILE, "w") as f:
json.dump(memory, f)
# =======================
# Web search function
# =======================
def search_web(query):
try:
url = "https://api.duckduckgo.com/"
params = {"q": query, "format": "json", "no_html": 1, "skip_disambig": 1}
response = requests.get(url, params=params)
data = response.json()
if data.get("AbstractText"):
return data["AbstractText"]
elif data.get("RelatedTopics"):
topics = [t.get("Text", "") for t in data.get("RelatedTopics", []) if "Text" in t]
return " ".join(topics[:3])
else:
return "No useful information found."
except Exception as e:
return f"Search error: {e}"
# =======================
# Chat function
# =======================
def chat_with_model(message, history, context, file_input=None):
if history is None:
history = []
if message.lower().startswith("search "):
query = message[7:]
search_result = search_web(query)
history.append({"role": "user", "content": message})
history.append({"role": "assistant", "content": f"๐Ÿ”Ž Here's what I found online:\n\n{search_result}"})
save_memory(history)
return history, history
if file_input:
message += f"\n\n๐Ÿ“Ž (User uploaded a file named '{file_input.name}')"
# Add user message
history.append({"role": "user", "content": message})
# Build conversation for API
conversation = [{"role": m["role"], "content": m["content"]} for m in history]
try:
response = requests.post(
"https://router.huggingface.co/v1/chat/completions",
headers={
"Authorization": f"Bearer {HF_TOKEN}",
"Content-Type": "application/json"
},
json={
"model": "deepseek-ai/DeepSeek-V3.2-Exp:novita",
"messages": conversation
}
)
if response.status_code != 200:
raise Exception(f"API Error: {response.status_code} - {response.text}")
reply = response.json()["choices"][0]["message"]["content"]
# Format math nicely
reply = reply.replace("Step", "\n\n**Step").replace(":", ":**").replace("\\[", "\n\n\\[").replace("\\]", "\\]\n\n")
# Add assistant reply
history.append({"role": "assistant", "content": reply})
save_memory(history)
return history, history
except Exception as e:
print("Backend Error:", e)
error_msg = "๐Ÿ˜… EduAI is having trouble connecting. Check HF_TOKEN or try again later!"
history.append({"role": "assistant", "content": error_msg})
return history, history
# =======================
# Sidebar context update
# =======================
def update_context(choice):
if choice is None:
return "๐Ÿ“˜ **You are in General Mode.** Ask EduAI anything about your studies!"
return f"๐Ÿ“˜ **You selected {choice} mode.** Ask anything related to this topic!"
# =======================
# Clear memory
# =======================
def clear_memory():
if os.path.exists(MEMORY_FILE):
os.remove(MEMORY_FILE)
return [], "๐Ÿงน Chat memory cleared! Start fresh."
# =======================
# Custom CSS
# =======================
custom_css = """
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap');
body { font-family:'Roboto', sans-serif; background:#1e1e1e; color:#e0e0e0; min-height:100vh; }
.header-title { font-size:36px; text-align:center; margin-bottom:20px; color:#007BFF; font-weight:700; text-shadow:0 0 10px rgba(0,123,255,0.5); }
.sidebar { background:#2a2a2a; padding:20px; border-radius:12px; box-shadow:0 4px 12px rgba(0,0,0,0.5); border:1px solid #333; }
.menu-title { font-size:20px; font-weight:500; margin-bottom:15px; color:#007BFF; }
.accordion { background:#2a2a2a; border-radius:12px; padding:10px; margin-bottom:10px; box-shadow:0 3px 8px rgba(0,0,0,0.5); }
.accordion-header { background:#333; color:#e0e0e0; border-radius:10px; padding:12px; font-weight:500; cursor:pointer; transition:0.3s; }
.accordion-header:hover { background:#007BFF; color:#1e1e1e; }
.main-chat { padding:20px; background:#1e1e1e; }
.context-box { background:#2a2a2a; padding:15px; border-radius:10px; box-shadow:0 2px 6px rgba(0,0,0,0.3); margin-bottom:15px; border:1px solid #333; color:#e0e0e0; }
.chatbox .message.user { background:#007BFF; color:#fff; border-radius:20px; padding:12px 18px; margin:8px 0; }
.chatbox .message.bot { background:#333; color:#e0e0e0; border-radius:20px; padding:12px 18px; margin:8px 0; }
.input-row { display:flex; gap:10px; margin-top:10px; }
.chat-input { flex:1; border-radius:12px; padding:12px; border:1px solid #555; background:#2a2a2a; color:#e0e0e0; }
.chat-input:focus { border-color:#007BFF; outline:none; }
.btn-send { background:#7c3aed; color:#fff; border-radius:12px; padding:12px 18px; border:none; cursor:pointer; transition:0.3s; }
.btn-send:hover { background:#5b21b6; }
.file-upload { width:50px; height:50px; border:1px solid #555; border-radius:12px; background:#2a2a2a; display:flex; align-items:center; justify-content:center; cursor:pointer; font-size:20px; color:#e0e0e0; transition:0.3s; }
.file-upload:hover { background:#007BFF; color:#1e1e1e; }
.btn-clear { background:#f44336; color:white; border-radius:12px; padding:10px 15px; border:none; cursor:pointer; transition:0.3s; }
.btn-clear:hover { background:#d32f2f; }
.about-text { font-size:14px; color:#aaa; line-height:1.5; }
.radio label { color:#e0e0e0; margin:8px 0; }
"""
# =======================
# Gradio UI
# =======================
with gr.Blocks(theme=gr.themes.Base(), css=custom_css) as iface:
gr.Markdown("# ๐ŸŽ“ **EduAI โ€” Professional Study Companion**", elem_classes="header-title")
with gr.Row():
# Sidebar
with gr.Column(scale=1, min_width=250, elem_classes="sidebar"):
gr.Markdown("### ๐Ÿงญ **Main Menu**", elem_classes="menu-title")
with gr.Accordion("๐Ÿ“š Subject Tutor", open=False):
subj = gr.Radio(
["Science ๐Ÿงช", "ICT ๐Ÿ’ป", "English ๐Ÿ“˜", "Mathematics โž—"],
label="Choose a subject", type="index"
)
with gr.Accordion("๐Ÿ—“ Study Planner", open=False):
planner = gr.Radio(
["View Plan ๐Ÿ“…", "Add Task โœ๏ธ", "Study Tips ๐Ÿ’ก"],
label="Planner Options", type="index"
)
with gr.Accordion("๐ŸŒ Languages", open=False):
lang = gr.Radio(
["Learn Sinhala ๐Ÿ‡ฑ๐Ÿ‡ฐ","Learn Tamil ๐Ÿ‡ฎ๐Ÿ‡ณ","Learn English ๐Ÿ‡ฌ๐Ÿ‡ง","Learn Spanish ๐Ÿ‡ช๐Ÿ‡ธ"],
label="Language Options", type="index"
)
with gr.Accordion("โš™๏ธ Settings", open=False):
clear_btn = gr.Button("๐Ÿงน Clear Memory", elem_classes="btn-clear")
with gr.Accordion("๐Ÿ‘ฉโ€๐ŸŽ“ About", open=False):
gr.Markdown(
"EduAI โ€“ developed by **Wafa Fazly** using a pre-trained AI model. Helps learners understand **Science, ICT, English, and more**.",
elem_classes="about-text"
)
# Main Chat Area
with gr.Column(scale=4, elem_classes="main-chat"):
context_display = gr.Markdown(
"๐Ÿ“˜ **You are in General Mode.** Ask EduAI anything about your studies!",
elem_classes="context-box"
)
chatbot = gr.Chatbot(
label="EduAI Chat",
height=500,
render_markdown=True,
type="messages",
latex_delimiters=[{"left": "$$", "right": "$$", "display": True},
{"left": "\\[", "right": "\\]", "display": True}]
)
# Input row
with gr.Row(elem_classes="input-row"):
msg = gr.Textbox(label="Ask EduAI:", placeholder="Type your question here...", elem_classes="chat-input", show_label=False)
file_input = gr.File(label="๐Ÿ“Ž", file_types=[".pdf", ".docx", ".png", ".jpg"], elem_classes="file-upload", show_label=False)
send_btn = gr.Button("โœˆ๏ธ", elem_classes="btn-send")
# =======================
# Event handlers
# =======================
subj.change(update_context, inputs=subj, outputs=context_display)
planner.change(update_context, inputs=planner, outputs=context_display)
lang.change(update_context, inputs=lang, outputs=context_display)
send_btn.click(chat_with_model, inputs=[msg, chatbot, context_display, file_input], outputs=[chatbot, chatbot])
msg.submit(chat_with_model, inputs=[msg, chatbot, context_display, file_input], outputs=[chatbot, chatbot])
clear_btn.click(clear_memory, outputs=[chatbot, context_display])
# Launch the app
iface.launch()
```