mikaelJ46 commited on
Commit
b607765
Β·
verified Β·
1 Parent(s): ac8ba85

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +65 -55
app.py CHANGED
@@ -15,19 +15,19 @@ import time
15
  try:
16
  import google.generativeai as genai
17
  genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
18
- gemini_model = genai.GenerativeModel('gemini-2.5 pro')
19
- print(" Gemini AI initialized successfully (PRIMARY)")
20
  except Exception as e:
21
- print(f" Error initializing Gemini: {e}")
22
  gemini_model = None
23
 
24
  # Cohere (Secondary)
25
  try:
26
  import cohere
27
  cohere_client = cohere.Client(os.getenv("COHERE_API_KEY"))
28
- print(" Cohere initialized successfully (SECONDARY)")
29
  except Exception as e:
30
- print(f" Error initializing Cohere: {e}")
31
  cohere_client = None
32
 
33
  # Z.ai (Tertiary)
@@ -37,9 +37,9 @@ try:
37
  provider="novita",
38
  api_key=os.environ.get("HF_TOKEN"),
39
  )
40
- print(" Z.ai GLM-4.6 initialized successfully (TERTIARY)")
41
  except Exception as e:
42
- print(f" Error initializing Z.ai: {e}")
43
  zai_client = None
44
 
45
  # MiniMax (Final Fallback)
@@ -48,9 +48,9 @@ try:
48
  provider="novita",
49
  api_key=os.environ.get("HF_TOKEN"),
50
  )
51
- print(" MiniMax AI initialized successfully (FINAL FALLBACK)")
52
  except Exception as e:
53
- print(f" Error initializing MiniMax: {e}")
54
  minimax_client = None
55
 
56
  # ---------- 2. Unified AI Function with Smart Fallback ----------
@@ -74,7 +74,7 @@ def ask_ai(prompt, temperature=0.7, max_retries=2):
74
  return response.text, "gemini"
75
  except Exception as e:
76
  last_error = e
77
- print(f" Gemini attempt {attempt+1} failed: {str(e)}")
78
  if attempt < max_retries - 1:
79
  time.sleep(1)
80
 
@@ -90,7 +90,7 @@ def ask_ai(prompt, temperature=0.7, max_retries=2):
90
  return response.text, "cohere"
91
  except Exception as e:
92
  last_error = e
93
- print(f" Cohere attempt {attempt+1} failed: {str(e)}")
94
  if attempt < max_retries - 1:
95
  time.sleep(1)
96
 
@@ -106,7 +106,7 @@ def ask_ai(prompt, temperature=0.7, max_retries=2):
106
  return completion.choices[0].message.content, "zai"
107
  except Exception as e:
108
  last_error = e
109
- print(f" Z.ai attempt {attempt+1} failed: {str(e)}")
110
  if attempt < max_retries - 1:
111
  time.sleep(1)
112
 
@@ -121,10 +121,10 @@ def ask_ai(prompt, temperature=0.7, max_retries=2):
121
  return completion.choices[0].message.content, "minimax"
122
  except Exception as e:
123
  last_error = e
124
- print(f" MiniMax 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 ----------
@@ -166,7 +166,7 @@ def extract_text_from_pdf(pdf_file):
166
  except Exception as e:
167
  return f"Error extracting PDF: {e}"
168
 
169
- # ---------- 6. AI Tutor with Multi-Model Support ----------
170
  def ai_tutor_chat(message, history, subject, topic, level):
171
  if not message.strip():
172
  return history
@@ -183,8 +183,8 @@ Use a friendly, supportive tone to help students learn effectively."""
183
  if user_msg:
184
  conversation += f"Student: {user_msg}\n"
185
  if bot_msg:
186
- # Remove source indicators from history
187
- clean_msg = bot_msg.replace("[Cohere] ", "").replace("[Z.ai] ", "").replace("[MiniMax] ", "")
188
  conversation += f"Tutor: {clean_msg}\n"
189
 
190
  conversation += f"Student: {message}\nTutor:"
@@ -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""" 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", "zai", "minimax"]:
@@ -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), " 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
 
@@ -350,13 +350,13 @@ 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 " Paper uploaded!", get_papers_list()
354
 
355
  def get_papers_list():
356
  if not papers_storage:
357
  return "No papers yet."
358
  return "\n".join(
359
- f"**{p['title']}** ({p['subject'].upper()} - {p['level']}) {' PDF' if p.get('has_pdf') else ''}\n {p['uploaded_at']}\n{p['content'][:120]}...\n{'─'*60}"
360
  for p in papers_storage
361
  )
362
 
@@ -364,25 +364,26 @@ 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" 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
- Justice AI Tutor | Translator | Dictionary | Past Papers
378
  _Powered by Gemini AI with intelligent fallback system_
379
  """)
380
 
381
  with gr.Tabs():
382
- # ───── STUDENT ─────
383
- with gr.Tab(" Student Portal"):
384
  with gr.Tabs():
385
- with gr.Tab("Justice AI Tutor"):
 
386
  gr.Markdown("### Chat with Your AI Tutor\n*Powered by Gemini 2.5 with automatic fallback*")
387
  with gr.Row():
388
  subj = gr.Radio(["French", "EFL"], label="Subject", value="French")
@@ -396,26 +397,29 @@ 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 ", variant="primary")
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(" Translator"):
 
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 ", variant="primary").click(translate_text, [inp, dir_], out)
411
 
412
- with gr.Tab(" Dictionary"):
 
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 ", variant="primary").click(dictionary_lookup, w, o)
417
 
418
- with gr.Tab(" Practice"):
 
419
  gr.Markdown("### Generate & Practice Exam Questions")
420
  with gr.Row():
421
  ps = gr.Radio(["French", "EFL"], label="Subject", value="French")
@@ -423,34 +427,35 @@ 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=" Question", lines=5, interactive=False)
427
  exp = gr.Textbox(label="Expected", lines=2, visible=False)
428
- mark = gr.Textbox(label=" Mark Scheme", lines=3, interactive=False)
429
- ans = gr.Textbox(lines=8, label=" Your Answer", placeholder="Type your answer...")
430
- fb = gr.Textbox(lines=12, label=" Feedback", interactive=False)
431
 
432
  with gr.Row():
433
- gr.Button(" Generate", variant="primary").click(generate_question, [ps, pt, pl], [q, exp, mark])
434
- gr.Button(" Check", variant="secondary").click(check_answer, [q, exp, ans, ps, pl], fb)
435
 
436
- with gr.Tab(" Past Papers"):
 
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(" Show", variant="primary").click(view_papers_student, [psb, plb], pd)
443
 
444
- # ───── ADMIN ─────
445
- with gr.Tab(" Admin Panel"):
446
  with gr.Column() as login_section:
447
- gr.Markdown("### Admin Login")
448
  pwd = gr.Textbox(label="Password", type="password", placeholder="Enter password")
449
- login_btn = gr.Button(" Login", variant="primary")
450
  login_status = gr.Textbox(label="Status", interactive=False)
451
 
452
  with gr.Column(visible=False) as admin_section:
453
- gr.Markdown("### Upload Past Papers")
454
  with gr.Row():
455
  with gr.Column():
456
  t = gr.Textbox(label="Title", placeholder="e.g., Paper 1 - June 2023")
@@ -458,8 +463,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=" PDF (optional)", file_types=[".pdf"])
462
- up = gr.Button(" Upload", variant="primary")
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,4 +472,9 @@ 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
  app.launch()
 
15
  try:
16
  import google.generativeai as genai
17
  genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
18
+ gemini_model = genai.GenerativeModel('gemini-2.5-pro')
19
+ print("βœ… Gemini AI initialized successfully (PRIMARY)")
20
  except Exception as e:
21
+ print(f"❌ Error initializing Gemini: {e}")
22
  gemini_model = None
23
 
24
  # Cohere (Secondary)
25
  try:
26
  import cohere
27
  cohere_client = cohere.Client(os.getenv("COHERE_API_KEY"))
28
+ print("βœ… Cohere initialized successfully (SECONDARY)")
29
  except Exception as e:
30
+ print(f"❌ Error initializing Cohere: {e}")
31
  cohere_client = None
32
 
33
  # Z.ai (Tertiary)
 
37
  provider="novita",
38
  api_key=os.environ.get("HF_TOKEN"),
39
  )
40
+ print("βœ… Z.ai GLM-4.6 initialized successfully (TERTIARY)")
41
  except Exception as e:
42
+ print(f"❌ Error initializing Z.ai: {e}")
43
  zai_client = None
44
 
45
  # MiniMax (Final Fallback)
 
48
  provider="novita",
49
  api_key=os.environ.get("HF_TOKEN"),
50
  )
51
+ print("βœ… MiniMax AI initialized successfully (FINAL FALLBACK)")
52
  except Exception as e:
53
+ print(f"❌ Error initializing MiniMax: {e}")
54
  minimax_client = None
55
 
56
  # ---------- 2. Unified AI Function with Smart Fallback ----------
 
74
  return response.text, "gemini"
75
  except Exception as e:
76
  last_error = e
77
+ print(f"⚠ Gemini attempt {attempt+1} failed: {str(e)}")
78
  if attempt < max_retries - 1:
79
  time.sleep(1)
80
 
 
90
  return response.text, "cohere"
91
  except Exception as e:
92
  last_error = e
93
+ print(f"⚠ Cohere attempt {attempt+1} failed: {str(e)}")
94
  if attempt < max_retries - 1:
95
  time.sleep(1)
96
 
 
106
  return completion.choices[0].message.content, "zai"
107
  except Exception as e:
108
  last_error = e
109
+ print(f"⚠ Z.ai attempt {attempt+1} failed: {str(e)}")
110
  if attempt < max_retries - 1:
111
  time.sleep(1)
112
 
 
121
  return completion.choices[0].message.content, "minimax"
122
  except Exception as e:
123
  last_error = e
124
+ print(f"⚠ MiniMax 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 ----------
 
166
  except Exception as e:
167
  return f"Error extracting PDF: {e}"
168
 
169
+ # ---------- 6. AI Tutor with Multi-Model Support (FIXED) ----------
170
  def ai_tutor_chat(message, history, subject, topic, level):
171
  if not message.strip():
172
  return history
 
183
  if user_msg:
184
  conversation += f"Student: {user_msg}\n"
185
  if bot_msg:
186
+ # FIXED: Remove emoji indicators that match what we're actually adding
187
+ clean_msg = bot_msg.replace("πŸ”΅ ", "").replace("🟒 ", "").replace("🟣 ", "")
188
  conversation += f"Tutor: {clean_msg}\n"
189
 
190
  conversation += f"Student: {message}\nTutor:"
 
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", "zai", "minimax"]:
 
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
 
 
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:
357
  return "No papers yet."
358
  return "\n".join(
359
+ f"**{p['title']}** ({p['subject'].upper()} - {p['level']}) {'πŸ“„ PDF' if p.get('has_pdf') else ''}\n⏰ {p['uploaded_at']}\n{p['content'][:120]}...\n{'─'*60}"
360
  for p in papers_storage
361
  )
362
 
 
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
  _Powered by Gemini AI with intelligent fallback system_
379
  """)
380
 
381
  with gr.Tabs():
382
+ # ───── STUDENT PORTAL ─────
383
+ with gr.Tab("πŸ‘¨β€πŸŽ“ Student Portal"):
384
  with gr.Tabs():
385
+ # AI TUTOR
386
+ with gr.Tab("πŸ€– AI Tutor"):
387
  gr.Markdown("### Chat with Your AI Tutor\n*Powered by Gemini 2.5 with automatic fallback*")
388
  with gr.Row():
389
  subj = gr.Radio(["French", "EFL"], label="Subject", value="French")
 
397
  chat = gr.Chatbot(height=450, show_label=False)
398
  txt = gr.Textbox(placeholder="Ask anything... e.g., 'Explain the passΓ© composΓ©'", label="Message")
399
  with gr.Row():
400
+ send = gr.Button("Send πŸ“€", variant="primary")
401
+ clr = gr.Button("Clear πŸ—‘")
402
  send.click(ai_tutor_chat, [txt, chat, subj, topc, lvl], chat)
403
  txt.submit(ai_tutor_chat, [txt, chat, subj, topc, lvl], chat)
404
  clr.click(clear_chat, outputs=chat)
405
 
406
+ # TRANSLATOR
407
+ with gr.Tab("🌐 Translator"):
408
  gr.Markdown("### English ⟷ French Translation")
409
  dir_ = gr.Radio(["English β†’ French", "French β†’ English"], label="Direction", value="English β†’ French")
410
  inp = gr.Textbox(lines=6, label="Input Text", placeholder="Enter text...")
411
  out = gr.Textbox(lines=6, label="Translation")
412
+ gr.Button("Translate πŸ”„", variant="primary").click(translate_text, [inp, dir_], out)
413
 
414
+ # DICTIONARY
415
+ with gr.Tab("πŸ“– Dictionary"):
416
  gr.Markdown("### French Dictionary")
417
  w = gr.Textbox(placeholder="Enter French word...", label="Word")
418
  o = gr.Textbox(lines=16, label="Definition")
419
+ gr.Button("Look Up πŸ”", variant="primary").click(dictionary_lookup, w, o)
420
 
421
+ # PRACTICE QUESTIONS
422
+ with gr.Tab("✍ Practice"):
423
  gr.Markdown("### Generate & Practice Exam Questions")
424
  with gr.Row():
425
  ps = gr.Radio(["French", "EFL"], label="Subject", value="French")
 
427
  pt = gr.Dropdown(french_topics, label="Topic")
428
  ps.change(upd_topics, ps, pt)
429
 
430
+ q = gr.Textbox(label="πŸ“ Question", lines=5, interactive=False)
431
  exp = gr.Textbox(label="Expected", lines=2, visible=False)
432
+ mark = gr.Textbox(label="πŸ“Š Mark Scheme", lines=3, interactive=False)
433
+ ans = gr.Textbox(lines=8, label="✏ Your Answer", placeholder="Type your answer...")
434
+ fb = gr.Textbox(lines=12, label="πŸ“‹ Feedback", interactive=False)
435
 
436
  with gr.Row():
437
+ gr.Button("🎲 Generate", variant="primary").click(generate_question, [ps, pt, pl], [q, exp, mark])
438
+ gr.Button("βœ… Check", variant="secondary").click(check_answer, [q, exp, ans, ps, pl], fb)
439
 
440
+ # PAST PAPERS
441
+ with gr.Tab("πŸ“š Past Papers"):
442
  gr.Markdown("### Browse Past Papers")
443
  with gr.Row():
444
  psb = gr.Radio(["French", "EFL"], label="Subject", value="French")
445
  plb = gr.Radio(["IGCSE", "GCSE"], label="Level", value="IGCSE")
446
  pd = gr.Textbox(lines=22, label="Papers", interactive=False)
447
+ gr.Button("πŸ“– Show", variant="primary").click(view_papers_student, [psb, plb], pd)
448
 
449
+ # ───── ADMIN PANEL ─────
450
+ with gr.Tab("πŸ” Admin Panel"):
451
  with gr.Column() as login_section:
452
+ gr.Markdown("### πŸ” Admin Login")
453
  pwd = gr.Textbox(label="Password", type="password", placeholder="Enter password")
454
+ login_btn = gr.Button("πŸ”“ Login", variant="primary")
455
  login_status = gr.Textbox(label="Status", interactive=False)
456
 
457
  with gr.Column(visible=False) as admin_section:
458
+ gr.Markdown("### πŸ“€ Upload Past Papers")
459
  with gr.Row():
460
  with gr.Column():
461
  t = gr.Textbox(label="Title", placeholder="e.g., Paper 1 - June 2023")
 
463
  s = gr.Radio(["French", "EFL"], label="Subject", value="French")
464
  lv = gr.Radio(["IGCSE", "GCSE"], label="Level", value="IGCSE")
465
  c = gr.Textbox(lines=6, label="Description")
466
+ pdf = gr.File(label="πŸ“„ PDF (optional)", file_types=[".pdf"])
467
+ up = gr.Button("⬆ Upload", variant="primary")
468
  st = gr.Textbox(label="Status")
469
  with gr.Column():
470
  lst = gr.Textbox(lines=24, label="All Papers", value=get_papers_list(), interactive=False)
 
472
 
473
  login_btn.click(verify_admin_password, [pwd], [admin_section, login_section, login_status])
474
 
475
+ gr.Markdown("""
476
+ ---
477
+ **System Status:** 🟒 Gemini AI (Primary) | πŸ”΅ Cohere (Secondary) | 🟒 Z.ai (Tertiary) | 🟣 MiniMax (Fallback)
478
+ """)
479
+
480
  app.launch()