Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -18,18 +18,18 @@ try:
|
|
| 18 |
provider="novita",
|
| 19 |
api_key=os.environ.get("HF_TOKEN"),
|
| 20 |
)
|
| 21 |
-
print("
|
| 22 |
except Exception as e:
|
| 23 |
-
print(f"
|
| 24 |
zai_client = None
|
| 25 |
|
| 26 |
# Cohere (Secondary)
|
| 27 |
try:
|
| 28 |
import cohere
|
| 29 |
cohere_client = cohere.Client(os.getenv("COHERE_API_KEY"))
|
| 30 |
-
print("
|
| 31 |
except Exception as e:
|
| 32 |
-
print(f"
|
| 33 |
cohere_client = None
|
| 34 |
|
| 35 |
# MiniMax (Tertiary)
|
|
@@ -38,9 +38,9 @@ try:
|
|
| 38 |
provider="novita",
|
| 39 |
api_key=os.environ.get("HF_TOKEN"),
|
| 40 |
)
|
| 41 |
-
print("
|
| 42 |
except Exception as e:
|
| 43 |
-
print(f"
|
| 44 |
minimax_client = None
|
| 45 |
|
| 46 |
# Gemini (Final Fallback)
|
|
@@ -48,9 +48,9 @@ try:
|
|
| 48 |
import google.generativeai as genai
|
| 49 |
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
|
| 50 |
gemini_model = genai.GenerativeModel('gemini-pro')
|
| 51 |
-
print("
|
| 52 |
except Exception as e:
|
| 53 |
-
print(f"
|
| 54 |
gemini_model = None
|
| 55 |
|
| 56 |
# ---------- 2. Unified AI Function with Smart Fallback ----------
|
|
@@ -73,7 +73,7 @@ def ask_ai(prompt, temperature=0.7, max_retries=2):
|
|
| 73 |
return completion.choices[0].message.content, "zai"
|
| 74 |
except Exception as e:
|
| 75 |
last_error = e
|
| 76 |
-
print(f"
|
| 77 |
if attempt < max_retries - 1:
|
| 78 |
time.sleep(1)
|
| 79 |
|
|
@@ -89,7 +89,7 @@ def ask_ai(prompt, temperature=0.7, max_retries=2):
|
|
| 89 |
return response.text, "cohere"
|
| 90 |
except Exception as e:
|
| 91 |
last_error = e
|
| 92 |
-
print(f"
|
| 93 |
if attempt < max_retries - 1:
|
| 94 |
time.sleep(1)
|
| 95 |
|
|
@@ -105,7 +105,7 @@ def ask_ai(prompt, temperature=0.7, max_retries=2):
|
|
| 105 |
return completion.choices[0].message.content, "minimax"
|
| 106 |
except Exception as e:
|
| 107 |
last_error = e
|
| 108 |
-
print(f"
|
| 109 |
if attempt < max_retries - 1:
|
| 110 |
time.sleep(1)
|
| 111 |
|
|
@@ -121,10 +121,10 @@ def ask_ai(prompt, temperature=0.7, max_retries=2):
|
|
| 121 |
return response.text, "gemini"
|
| 122 |
except Exception as e:
|
| 123 |
last_error = e
|
| 124 |
-
print(f"
|
| 125 |
|
| 126 |
# All failed
|
| 127 |
-
error_msg = f"
|
| 128 |
return error_msg, "error"
|
| 129 |
|
| 130 |
# ---------- 3. Global storage ----------
|
|
@@ -194,11 +194,11 @@ Use a friendly, supportive tone to help students learn effectively."""
|
|
| 194 |
|
| 195 |
# Add source indicator if not from Z.ai
|
| 196 |
if source == "cohere":
|
| 197 |
-
bot_response = f"
|
| 198 |
elif source == "minimax":
|
| 199 |
-
bot_response = f"
|
| 200 |
elif source == "gemini":
|
| 201 |
-
bot_response = f"
|
| 202 |
elif source == "error":
|
| 203 |
pass # Error already formatted
|
| 204 |
|
|
@@ -304,15 +304,15 @@ Return JSON (no markdown):
|
|
| 304 |
try:
|
| 305 |
clean_txt = response.replace("```json", "").replace("```", "").strip()
|
| 306 |
fb = json.loads(clean_txt)
|
| 307 |
-
result = f"""
|
| 308 |
|
| 309 |
-
|
| 310 |
{fb['feedback']}
|
| 311 |
|
| 312 |
-
|
| 313 |
{fb.get('strengths', 'Good effort!')}
|
| 314 |
|
| 315 |
-
|
| 316 |
{fb['improvements']}"""
|
| 317 |
|
| 318 |
if source in ["cohere", "minimax", "gemini"]:
|
|
@@ -325,12 +325,12 @@ Return JSON (no markdown):
|
|
| 325 |
# ---------- 10. Admin β Past Papers ----------
|
| 326 |
def verify_admin_password(password):
|
| 327 |
if password == ADMIN_PASSWORD:
|
| 328 |
-
return gr.update(visible=True), gr.update(visible=False), "
|
| 329 |
-
return gr.update(visible=False), gr.update(visible=True), "
|
| 330 |
|
| 331 |
def upload_paper(title, subject, level, content, pdf_file):
|
| 332 |
if not all([title, subject, level, content]):
|
| 333 |
-
return "
|
| 334 |
|
| 335 |
paper_id = len(papers_storage) + 1
|
| 336 |
|
|
@@ -339,7 +339,7 @@ def upload_paper(title, subject, level, content, pdf_file):
|
|
| 339 |
pdf_text = extract_text_from_pdf(pdf_file)
|
| 340 |
if pdf_text and not pdf_text.startswith("Error"):
|
| 341 |
pdf_content_storage[paper_id] = pdf_text
|
| 342 |
-
content += f"\n\n[
|
| 343 |
|
| 344 |
papers_storage.append({
|
| 345 |
"id": paper_id,
|
|
@@ -350,7 +350,7 @@ def upload_paper(title, subject, level, content, pdf_file):
|
|
| 350 |
"has_pdf": bool(pdf_text and not pdf_text.startswith("Error")),
|
| 351 |
"uploaded_at": datetime.now().strftime("%Y-%m-%d %H:%M")
|
| 352 |
})
|
| 353 |
-
return "
|
| 354 |
|
| 355 |
def get_papers_list():
|
| 356 |
if not papers_storage:
|
|
@@ -364,25 +364,24 @@ def view_papers_student(subject, level):
|
|
| 364 |
filtered = [p for p in papers_storage
|
| 365 |
if p["subject"] == subject.lower() and p["level"] == level]
|
| 366 |
if not filtered:
|
| 367 |
-
return f"
|
| 368 |
return "\n".join(
|
| 369 |
-
f"**{p['title']}** {'
|
| 370 |
for p in filtered
|
| 371 |
)
|
| 372 |
|
| 373 |
# ---------- 11. Gradio UI ----------
|
| 374 |
with gr.Blocks(theme=gr.themes.Soft(), title="IGCSE/GCSE Platform") as app:
|
| 375 |
gr.Markdown("""
|
| 376 |
-
#
|
| 377 |
-
|
| 378 |
-
π AI Tutor | π Translator | π Dictionary | π Past Papers
|
| 379 |
""")
|
| 380 |
|
| 381 |
with gr.Tabs():
|
| 382 |
# βββββ STUDENT βββββ
|
| 383 |
-
with gr.Tab("
|
| 384 |
with gr.Tabs():
|
| 385 |
-
with gr.Tab("
|
| 386 |
gr.Markdown("### Chat with Your AI Tutor\n*Powered by Z.ai with automatic fallback*")
|
| 387 |
with gr.Row():
|
| 388 |
subj = gr.Radio(["French", "EFL"], label="Subject", value="French")
|
|
@@ -396,26 +395,26 @@ with gr.Blocks(theme=gr.themes.Soft(), title="IGCSE/GCSE Platform") as app:
|
|
| 396 |
chat = gr.Chatbot(height=450, show_label=False)
|
| 397 |
txt = gr.Textbox(placeholder="Ask anything... e.g., 'Explain the passΓ© composΓ©'", label="Message")
|
| 398 |
with gr.Row():
|
| 399 |
-
send = gr.Button("Send
|
| 400 |
-
clr = gr.Button("Clear
|
| 401 |
send.click(ai_tutor_chat, [txt, chat, subj, topc, lvl], chat)
|
| 402 |
txt.submit(ai_tutor_chat, [txt, chat, subj, topc, lvl], chat)
|
| 403 |
clr.click(clear_chat, outputs=chat)
|
| 404 |
|
| 405 |
-
with gr.Tab("
|
| 406 |
gr.Markdown("### English β· French Translation")
|
| 407 |
dir_ = gr.Radio(["English β French", "French β English"], label="Direction", value="English β French")
|
| 408 |
inp = gr.Textbox(lines=6, label="Input Text", placeholder="Enter text...")
|
| 409 |
out = gr.Textbox(lines=6, label="Translation")
|
| 410 |
-
gr.Button("Translate
|
| 411 |
|
| 412 |
-
with gr.Tab("
|
| 413 |
gr.Markdown("### French Dictionary")
|
| 414 |
w = gr.Textbox(placeholder="Enter French word...", label="Word")
|
| 415 |
o = gr.Textbox(lines=16, label="Definition")
|
| 416 |
-
gr.Button("Look Up
|
| 417 |
|
| 418 |
-
with gr.Tab("
|
| 419 |
gr.Markdown("### Generate & Practice Exam Questions")
|
| 420 |
with gr.Row():
|
| 421 |
ps = gr.Radio(["French", "EFL"], label="Subject", value="French")
|
|
@@ -423,34 +422,34 @@ with gr.Blocks(theme=gr.themes.Soft(), title="IGCSE/GCSE Platform") as app:
|
|
| 423 |
pt = gr.Dropdown(french_topics, label="Topic")
|
| 424 |
ps.change(upd_topics, ps, pt)
|
| 425 |
|
| 426 |
-
q = gr.Textbox(label="
|
| 427 |
exp = gr.Textbox(label="Expected", lines=2, visible=False)
|
| 428 |
-
mark = gr.Textbox(label="
|
| 429 |
-
ans = gr.Textbox(lines=8, label="
|
| 430 |
-
fb = gr.Textbox(lines=12, label="
|
| 431 |
|
| 432 |
with gr.Row():
|
| 433 |
-
gr.Button("
|
| 434 |
-
gr.Button("
|
| 435 |
|
| 436 |
-
with gr.Tab("
|
| 437 |
gr.Markdown("### Browse Past Papers")
|
| 438 |
with gr.Row():
|
| 439 |
psb = gr.Radio(["French", "EFL"], label="Subject", value="French")
|
| 440 |
plb = gr.Radio(["IGCSE", "GCSE"], label="Level", value="IGCSE")
|
| 441 |
pd = gr.Textbox(lines=22, label="Papers", interactive=False)
|
| 442 |
-
gr.Button("
|
| 443 |
|
| 444 |
# βββββ ADMIN βββββ
|
| 445 |
-
with gr.Tab("
|
| 446 |
with gr.Column() as login_section:
|
| 447 |
-
gr.Markdown("###
|
| 448 |
pwd = gr.Textbox(label="Password", type="password", placeholder="Enter password")
|
| 449 |
-
login_btn = gr.Button("
|
| 450 |
login_status = gr.Textbox(label="Status", interactive=False)
|
| 451 |
|
| 452 |
with gr.Column(visible=False) as admin_section:
|
| 453 |
-
gr.Markdown("###
|
| 454 |
with gr.Row():
|
| 455 |
with gr.Column():
|
| 456 |
t = gr.Textbox(label="Title", placeholder="e.g., Paper 1 - June 2023")
|
|
@@ -458,8 +457,8 @@ with gr.Blocks(theme=gr.themes.Soft(), title="IGCSE/GCSE Platform") as app:
|
|
| 458 |
s = gr.Radio(["French", "EFL"], label="Subject", value="French")
|
| 459 |
lv = gr.Radio(["IGCSE", "GCSE"], label="Level", value="IGCSE")
|
| 460 |
c = gr.Textbox(lines=6, label="Description")
|
| 461 |
-
pdf = gr.File(label="
|
| 462 |
-
up = gr.Button("
|
| 463 |
st = gr.Textbox(label="Status")
|
| 464 |
with gr.Column():
|
| 465 |
lst = gr.Textbox(lines=24, label="All Papers", value=get_papers_list(), interactive=False)
|
|
@@ -467,33 +466,4 @@ with gr.Blocks(theme=gr.themes.Soft(), title="IGCSE/GCSE Platform") as app:
|
|
| 467 |
|
| 468 |
login_btn.click(verify_admin_password, [pwd], [admin_section, login_section, login_status])
|
| 469 |
|
| 470 |
-
gr.Markdown("""
|
| 471 |
-
---
|
| 472 |
-
### π Multi-AI System Setup:
|
| 473 |
-
|
| 474 |
-
**Required API Keys (add in Secrets):**
|
| 475 |
-
1. `HF_TOKEN` - Hugging Face token (for Z.ai & MiniMax)
|
| 476 |
-
2. `COHERE_API_KEY` - Cohere API key
|
| 477 |
-
3. `GEMINI_API_KEY` - Google Gemini API key
|
| 478 |
-
|
| 479 |
-
**How It Works:**
|
| 480 |
-
- π΅ **Z.ai GLM-4.6** tries first (best for education)
|
| 481 |
-
- π **Cohere** kicks in if Z.ai fails
|
| 482 |
-
- π£ **MiniMax** as third option
|
| 483 |
-
- π’ **Gemini** as final fallback
|
| 484 |
-
|
| 485 |
-
**Requirements:**
|
| 486 |
-
```
|
| 487 |
-
gradio>=4.0.0
|
| 488 |
-
PyPDF2>=3.0.0
|
| 489 |
-
huggingface_hub>=0.19.0
|
| 490 |
-
cohere>=4.0.0
|
| 491 |
-
google-generativeai>=0.3.0
|
| 492 |
-
```
|
| 493 |
-
|
| 494 |
-
**Admin Password:** `@mikaelJ46`
|
| 495 |
-
|
| 496 |
-
*Reliable, multi-model AI system ensures 99.9% uptime!* π
|
| 497 |
-
""")
|
| 498 |
-
|
| 499 |
app.launch()
|
|
|
|
| 18 |
provider="novita",
|
| 19 |
api_key=os.environ.get("HF_TOKEN"),
|
| 20 |
)
|
| 21 |
+
print(" Z.ai GLM-4.6 initialized successfully")
|
| 22 |
except Exception as e:
|
| 23 |
+
print(f" Error initializing Z.ai: {e}")
|
| 24 |
zai_client = None
|
| 25 |
|
| 26 |
# Cohere (Secondary)
|
| 27 |
try:
|
| 28 |
import cohere
|
| 29 |
cohere_client = cohere.Client(os.getenv("COHERE_API_KEY"))
|
| 30 |
+
print(" Cohere initialized successfully")
|
| 31 |
except Exception as e:
|
| 32 |
+
print(f" Error initializing Cohere: {e}")
|
| 33 |
cohere_client = None
|
| 34 |
|
| 35 |
# MiniMax (Tertiary)
|
|
|
|
| 38 |
provider="novita",
|
| 39 |
api_key=os.environ.get("HF_TOKEN"),
|
| 40 |
)
|
| 41 |
+
print(" MiniMax AI initialized successfully")
|
| 42 |
except Exception as e:
|
| 43 |
+
print(f" Error initializing MiniMax: {e}")
|
| 44 |
minimax_client = None
|
| 45 |
|
| 46 |
# Gemini (Final Fallback)
|
|
|
|
| 48 |
import google.generativeai as genai
|
| 49 |
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
|
| 50 |
gemini_model = genai.GenerativeModel('gemini-pro')
|
| 51 |
+
print(" Gemini AI initialized successfully")
|
| 52 |
except Exception as e:
|
| 53 |
+
print(f" Error initializing Gemini: {e}")
|
| 54 |
gemini_model = None
|
| 55 |
|
| 56 |
# ---------- 2. Unified AI Function with Smart Fallback ----------
|
|
|
|
| 73 |
return completion.choices[0].message.content, "zai"
|
| 74 |
except Exception as e:
|
| 75 |
last_error = e
|
| 76 |
+
print(f" Z.ai attempt {attempt+1} failed: {str(e)}")
|
| 77 |
if attempt < max_retries - 1:
|
| 78 |
time.sleep(1)
|
| 79 |
|
|
|
|
| 89 |
return response.text, "cohere"
|
| 90 |
except Exception as e:
|
| 91 |
last_error = e
|
| 92 |
+
print(f" Cohere attempt {attempt+1} failed: {str(e)}")
|
| 93 |
if attempt < max_retries - 1:
|
| 94 |
time.sleep(1)
|
| 95 |
|
|
|
|
| 105 |
return completion.choices[0].message.content, "minimax"
|
| 106 |
except Exception as e:
|
| 107 |
last_error = e
|
| 108 |
+
print(f" MiniMax attempt {attempt+1} failed: {str(e)}")
|
| 109 |
if attempt < max_retries - 1:
|
| 110 |
time.sleep(1)
|
| 111 |
|
|
|
|
| 121 |
return response.text, "gemini"
|
| 122 |
except Exception as e:
|
| 123 |
last_error = e
|
| 124 |
+
print(f" Gemini fallback failed: {str(e)}")
|
| 125 |
|
| 126 |
# All failed
|
| 127 |
+
error_msg = f" Error: All AI services failed. Last error: {str(last_error)}"
|
| 128 |
return error_msg, "error"
|
| 129 |
|
| 130 |
# ---------- 3. Global storage ----------
|
|
|
|
| 194 |
|
| 195 |
# Add source indicator if not from Z.ai
|
| 196 |
if source == "cohere":
|
| 197 |
+
bot_response = f" {bot_response}"
|
| 198 |
elif source == "minimax":
|
| 199 |
+
bot_response = f" {bot_response}"
|
| 200 |
elif source == "gemini":
|
| 201 |
+
bot_response = f" {bot_response}"
|
| 202 |
elif source == "error":
|
| 203 |
pass # Error already formatted
|
| 204 |
|
|
|
|
| 304 |
try:
|
| 305 |
clean_txt = response.replace("```json", "").replace("```", "").strip()
|
| 306 |
fb = json.loads(clean_txt)
|
| 307 |
+
result = f""" Score: {fb['score']}%
|
| 308 |
|
| 309 |
+
Detailed Feedback:
|
| 310 |
{fb['feedback']}
|
| 311 |
|
| 312 |
+
Your Strengths:
|
| 313 |
{fb.get('strengths', 'Good effort!')}
|
| 314 |
|
| 315 |
+
How to Improve:
|
| 316 |
{fb['improvements']}"""
|
| 317 |
|
| 318 |
if source in ["cohere", "minimax", "gemini"]:
|
|
|
|
| 325 |
# ---------- 10. Admin β Past Papers ----------
|
| 326 |
def verify_admin_password(password):
|
| 327 |
if password == ADMIN_PASSWORD:
|
| 328 |
+
return gr.update(visible=True), gr.update(visible=False), " Access granted!"
|
| 329 |
+
return gr.update(visible=False), gr.update(visible=True), " Incorrect password!"
|
| 330 |
|
| 331 |
def upload_paper(title, subject, level, content, pdf_file):
|
| 332 |
if not all([title, subject, level, content]):
|
| 333 |
+
return " Please fill all required fields!", get_papers_list()
|
| 334 |
|
| 335 |
paper_id = len(papers_storage) + 1
|
| 336 |
|
|
|
|
| 339 |
pdf_text = extract_text_from_pdf(pdf_file)
|
| 340 |
if pdf_text and not pdf_text.startswith("Error"):
|
| 341 |
pdf_content_storage[paper_id] = pdf_text
|
| 342 |
+
content += f"\n\n[ PDF extracted: {len(pdf_text)} characters]"
|
| 343 |
|
| 344 |
papers_storage.append({
|
| 345 |
"id": paper_id,
|
|
|
|
| 350 |
"has_pdf": bool(pdf_text and not pdf_text.startswith("Error")),
|
| 351 |
"uploaded_at": datetime.now().strftime("%Y-%m-%d %H:%M")
|
| 352 |
})
|
| 353 |
+
return " Paper uploaded!", get_papers_list()
|
| 354 |
|
| 355 |
def get_papers_list():
|
| 356 |
if not papers_storage:
|
|
|
|
| 364 |
filtered = [p for p in papers_storage
|
| 365 |
if p["subject"] == subject.lower() and p["level"] == level]
|
| 366 |
if not filtered:
|
| 367 |
+
return f" No {subject} {level} papers available."
|
| 368 |
return "\n".join(
|
| 369 |
+
f"**{p['title']}** {' PDF' if p.get('has_pdf') else ''}\n {p['uploaded_at']}\n\n{p['content']}\n\n{'β'*60}"
|
| 370 |
for p in filtered
|
| 371 |
)
|
| 372 |
|
| 373 |
# ---------- 11. Gradio UI ----------
|
| 374 |
with gr.Blocks(theme=gr.themes.Soft(), title="IGCSE/GCSE Platform") as app:
|
| 375 |
gr.Markdown("""
|
| 376 |
+
# IGCSE/GCSE Language Learning Platform
|
| 377 |
+
AI Tutor | Translator | Dictionary | Past Papers
|
|
|
|
| 378 |
""")
|
| 379 |
|
| 380 |
with gr.Tabs():
|
| 381 |
# βββββ STUDENT βββββ
|
| 382 |
+
with gr.Tab(" Student Portal"):
|
| 383 |
with gr.Tabs():
|
| 384 |
+
with gr.Tab(" AI Tutor"):
|
| 385 |
gr.Markdown("### Chat with Your AI Tutor\n*Powered by Z.ai with automatic fallback*")
|
| 386 |
with gr.Row():
|
| 387 |
subj = gr.Radio(["French", "EFL"], label="Subject", value="French")
|
|
|
|
| 395 |
chat = gr.Chatbot(height=450, show_label=False)
|
| 396 |
txt = gr.Textbox(placeholder="Ask anything... e.g., 'Explain the passΓ© composΓ©'", label="Message")
|
| 397 |
with gr.Row():
|
| 398 |
+
send = gr.Button("Send ", variant="primary")
|
| 399 |
+
clr = gr.Button("Clear ")
|
| 400 |
send.click(ai_tutor_chat, [txt, chat, subj, topc, lvl], chat)
|
| 401 |
txt.submit(ai_tutor_chat, [txt, chat, subj, topc, lvl], chat)
|
| 402 |
clr.click(clear_chat, outputs=chat)
|
| 403 |
|
| 404 |
+
with gr.Tab(" Translator"):
|
| 405 |
gr.Markdown("### English β· French Translation")
|
| 406 |
dir_ = gr.Radio(["English β French", "French β English"], label="Direction", value="English β French")
|
| 407 |
inp = gr.Textbox(lines=6, label="Input Text", placeholder="Enter text...")
|
| 408 |
out = gr.Textbox(lines=6, label="Translation")
|
| 409 |
+
gr.Button("Translate ", variant="primary").click(translate_text, [inp, dir_], out)
|
| 410 |
|
| 411 |
+
with gr.Tab(" Dictionary"):
|
| 412 |
gr.Markdown("### French Dictionary")
|
| 413 |
w = gr.Textbox(placeholder="Enter French word...", label="Word")
|
| 414 |
o = gr.Textbox(lines=16, label="Definition")
|
| 415 |
+
gr.Button("Look Up ", variant="primary").click(dictionary_lookup, w, o)
|
| 416 |
|
| 417 |
+
with gr.Tab(" Practice"):
|
| 418 |
gr.Markdown("### Generate & Practice Exam Questions")
|
| 419 |
with gr.Row():
|
| 420 |
ps = gr.Radio(["French", "EFL"], label="Subject", value="French")
|
|
|
|
| 422 |
pt = gr.Dropdown(french_topics, label="Topic")
|
| 423 |
ps.change(upd_topics, ps, pt)
|
| 424 |
|
| 425 |
+
q = gr.Textbox(label=" Question", lines=5, interactive=False)
|
| 426 |
exp = gr.Textbox(label="Expected", lines=2, visible=False)
|
| 427 |
+
mark = gr.Textbox(label=" Mark Scheme", lines=3, interactive=False)
|
| 428 |
+
ans = gr.Textbox(lines=8, label=" Your Answer", placeholder="Type your answer...")
|
| 429 |
+
fb = gr.Textbox(lines=12, label=" Feedback", interactive=False)
|
| 430 |
|
| 431 |
with gr.Row():
|
| 432 |
+
gr.Button(" Generate", variant="primary").click(generate_question, [ps, pt, pl], [q, exp, mark])
|
| 433 |
+
gr.Button(" Check", variant="secondary").click(check_answer, [q, exp, ans, ps, pl], fb)
|
| 434 |
|
| 435 |
+
with gr.Tab(" Past Papers"):
|
| 436 |
gr.Markdown("### Browse Past Papers")
|
| 437 |
with gr.Row():
|
| 438 |
psb = gr.Radio(["French", "EFL"], label="Subject", value="French")
|
| 439 |
plb = gr.Radio(["IGCSE", "GCSE"], label="Level", value="IGCSE")
|
| 440 |
pd = gr.Textbox(lines=22, label="Papers", interactive=False)
|
| 441 |
+
gr.Button(" Show", variant="primary").click(view_papers_student, [psb, plb], pd)
|
| 442 |
|
| 443 |
# βββββ ADMIN βββββ
|
| 444 |
+
with gr.Tab(" Admin Panel"):
|
| 445 |
with gr.Column() as login_section:
|
| 446 |
+
gr.Markdown("### Admin Login")
|
| 447 |
pwd = gr.Textbox(label="Password", type="password", placeholder="Enter password")
|
| 448 |
+
login_btn = gr.Button(" Login", variant="primary")
|
| 449 |
login_status = gr.Textbox(label="Status", interactive=False)
|
| 450 |
|
| 451 |
with gr.Column(visible=False) as admin_section:
|
| 452 |
+
gr.Markdown("### Upload Past Papers")
|
| 453 |
with gr.Row():
|
| 454 |
with gr.Column():
|
| 455 |
t = gr.Textbox(label="Title", placeholder="e.g., Paper 1 - June 2023")
|
|
|
|
| 457 |
s = gr.Radio(["French", "EFL"], label="Subject", value="French")
|
| 458 |
lv = gr.Radio(["IGCSE", "GCSE"], label="Level", value="IGCSE")
|
| 459 |
c = gr.Textbox(lines=6, label="Description")
|
| 460 |
+
pdf = gr.File(label=" PDF (optional)", file_types=[".pdf"])
|
| 461 |
+
up = gr.Button(" Upload", variant="primary")
|
| 462 |
st = gr.Textbox(label="Status")
|
| 463 |
with gr.Column():
|
| 464 |
lst = gr.Textbox(lines=24, label="All Papers", value=get_papers_list(), interactive=False)
|
|
|
|
| 466 |
|
| 467 |
login_btn.click(verify_admin_password, [pwd], [admin_section, login_section, login_status])
|
| 468 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 469 |
app.launch()
|