Benny-Tang commited on
Commit
3241dd2
·
verified ·
1 Parent(s): bf49bb2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -49
app.py CHANGED
@@ -1,8 +1,12 @@
1
  import json
2
  import random
3
  import os
 
4
  import gradio as gr
 
 
5
  from agents import AnalyzerAgent, CoachAgent, PredictiveAgent
 
6
 
7
  QUESTIONS_FILE = "questions.json"
8
 
@@ -10,23 +14,27 @@ if not os.path.exists(QUESTIONS_FILE):
10
  with open(QUESTIONS_FILE, "w", encoding="utf-8") as f:
11
  json.dump([], f, indent=2)
12
 
13
- with open(QUESTIONS_FILE, "r", encoding="utf-8") as f:
14
- QUESTION_BANK = json.load(f)
 
 
 
 
 
15
 
16
  analyzer = AnalyzerAgent()
17
  coach_agent = CoachAgent()
18
  predictor = PredictiveAgent()
 
19
 
 
20
  def start_exam(level, subject, num_questions=10, include_predicted=True):
21
- # Filter only real past paper questions
22
  pool = [q for q in QUESTION_BANK if q.get("subject") == f"{level}_{subject}"]
23
 
24
- # Optionally add predictions in memory (not saved)
25
  predicted_questions = []
26
  if include_predicted:
27
  predicted_questions = predictor.generate_predictions(level, subject, n=8)
28
 
29
- # Combine both pools
30
  combined_pool = pool + predicted_questions
31
  if not combined_pool:
32
  return [], gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), []
@@ -65,7 +73,6 @@ def submit_exam(answers, exam_data, level, subject):
65
 
66
  analysis = analyzer.analyze(per_question)
67
  coach = coach_agent.coach(analysis, level, subject)
68
-
69
  predictions_summary = predictor.summary(level, subject)
70
 
71
  return (
@@ -77,52 +84,96 @@ def submit_exam(answers, exam_data, level, subject):
77
  gr.update(visible=True)
78
  )
79
 
80
- # Gradio UI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  with gr.Blocks() as demo:
82
- gr.Markdown("## 📘 SPM Exam Simulator (2018–2024) with AI Predictions")
83
-
84
- with gr.Row():
85
- level = gr.Dropdown(["Form5"], value="Form5", label="Level (SPM=Form5)")
86
- subject = gr.Dropdown(
87
- ["BM", "English", "Math", "History", "Science", "MoralStudies",
88
- "Accounting", "Economics", "Business"],
89
- value="Math",
90
- label="Subject"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  )
92
- num_q = gr.Slider(5, 50, step=5, value=10, label="Number of Questions")
93
- include_pred = gr.Checkbox(True, label="Include AI-predicted")
94
- start_btn = gr.Button("Start Exam")
95
-
96
- exam_output = gr.State()
97
-
98
- exam_area = gr.Column(visible=False)
99
- with exam_area:
100
- gr.Markdown("### Questions")
101
- exam_display = gr.JSON(label="Exam")
102
- answers_box = gr.JSON(label="Your Answers")
103
- submit_btn = gr.Button("Submit Exam")
104
-
105
- results_area = gr.Column(visible=False)
106
- with results_area:
107
- score_text = gr.Textbox(label="Score", interactive=False)
108
- with gr.Tab("Weakness Analysis"):
109
- analysis_json = gr.JSON()
110
- with gr.Tab("Study Coach"):
111
- coach_json = gr.JSON()
112
- with gr.Tab("Predictions (Admin)"):
113
- predictions_json = gr.JSON()
114
-
115
- start_btn.click(
116
- start_exam,
117
- inputs=[level, subject, num_q, include_pred],
118
- outputs=[exam_display, exam_area, results_area, score_text, exam_output]
119
- )
120
 
121
- submit_btn.click(
122
- submit_exam,
123
- inputs=[answers_box, exam_output, level, subject],
124
- outputs=[score_text, analysis_json, coach_json, predictions_json, exam_area, results_area]
125
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
  if __name__ == "__main__":
128
  demo.launch()
@@ -132,3 +183,4 @@ if __name__ == "__main__":
132
 
133
 
134
 
 
 
1
  import json
2
  import random
3
  import os
4
+ import re
5
  import gradio as gr
6
+ import subprocess
7
+
8
  from agents import AnalyzerAgent, CoachAgent, PredictiveAgent
9
+ from ocr_agent import OcrAgent
10
 
11
  QUESTIONS_FILE = "questions.json"
12
 
 
14
  with open(QUESTIONS_FILE, "w", encoding="utf-8") as f:
15
  json.dump([], f, indent=2)
16
 
17
+ def load_question_bank():
18
+ if os.path.exists(QUESTIONS_FILE):
19
+ with open(QUESTIONS_FILE, "r", encoding="utf-8") as f:
20
+ return json.load(f)
21
+ return []
22
+
23
+ QUESTION_BANK = load_question_bank()
24
 
25
  analyzer = AnalyzerAgent()
26
  coach_agent = CoachAgent()
27
  predictor = PredictiveAgent()
28
+ ocr_agent = OcrAgent()
29
 
30
+ # ----------------- Exam Functions -----------------
31
  def start_exam(level, subject, num_questions=10, include_predicted=True):
 
32
  pool = [q for q in QUESTION_BANK if q.get("subject") == f"{level}_{subject}"]
33
 
 
34
  predicted_questions = []
35
  if include_predicted:
36
  predicted_questions = predictor.generate_predictions(level, subject, n=8)
37
 
 
38
  combined_pool = pool + predicted_questions
39
  if not combined_pool:
40
  return [], gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), []
 
73
 
74
  analysis = analyzer.analyze(per_question)
75
  coach = coach_agent.coach(analysis, level, subject)
 
76
  predictions_summary = predictor.summary(level, subject)
77
 
78
  return (
 
84
  gr.update(visible=True)
85
  )
86
 
87
+ # ----------------- OCR Upload & Auto Merge -----------------
88
+ def auto_detect(file_path):
89
+ """Try to detect year + subject from filename like spm_2018_Math.pdf"""
90
+ fname = os.path.basename(file_path)
91
+ m = re.match(r"spm_(\d{4})_(\w+)\.pdf", fname, re.IGNORECASE)
92
+ if m:
93
+ year, subject = m.groups()
94
+ return year, subject.capitalize()
95
+ return None, None
96
+
97
+ def process_pdf(file, subject, year):
98
+ raw = ocr_agent.extract_from_pdf(file.name)
99
+ cleaned = ocr_agent.clean_text(raw)
100
+ saved_file = ocr_agent.text_to_json(cleaned, subject=subject, year=year, output_dir="data")
101
+
102
+ try:
103
+ subprocess.run(["python", "merge_questions.py"], check=True)
104
+ global QUESTION_BANK
105
+ QUESTION_BANK = load_question_bank()
106
+ return f"✅ OCR complete. Saved: {saved_file}. Dataset merged into {QUESTIONS_FILE}."
107
+ except subprocess.CalledProcessError as e:
108
+ return f"⚠️ OCR extracted {saved_file}, but merge failed: {str(e)}"
109
+
110
+ def prefill_subject_year(file):
111
+ """Return auto-detected subject/year for UI prefill"""
112
+ if not file:
113
+ return "BM", "2018"
114
+ year, subject = auto_detect(file.name)
115
+ return subject if subject else "BM", year if year else "2018"
116
+
117
+ # ----------------- Gradio UI -----------------
118
  with gr.Blocks() as demo:
119
+ gr.Markdown("## 📘 SPM Exam Simulator (2018–2024) with AI Predictions + OCR Upload")
120
+
121
+ with gr.Tab("📝 Exam Simulator"):
122
+ with gr.Row():
123
+ level = gr.Dropdown(["Form5"], value="Form5", label="Level (SPM=Form5)")
124
+ subject = gr.Dropdown(
125
+ ["BM", "English", "Math", "History", "Science", "MoralStudies",
126
+ "Accounting", "Economics", "Business"],
127
+ value="Math",
128
+ label="Subject"
129
+ )
130
+ num_q = gr.Slider(5, 50, step=5, value=10, label="Number of Questions")
131
+ include_pred = gr.Checkbox(True, label="Include AI-predicted")
132
+ start_btn = gr.Button("Start Exam")
133
+
134
+ exam_output = gr.State()
135
+
136
+ exam_area = gr.Column(visible=False)
137
+ with exam_area:
138
+ gr.Markdown("### Questions")
139
+ exam_display = gr.JSON(label="Exam")
140
+ answers_box = gr.JSON(label="Your Answers")
141
+ submit_btn = gr.Button("Submit Exam")
142
+
143
+ results_area = gr.Column(visible=False)
144
+ with results_area:
145
+ score_text = gr.Textbox(label="Score", interactive=False)
146
+ with gr.Tab("Weakness Analysis"):
147
+ analysis_json = gr.JSON()
148
+ with gr.Tab("Study Coach"):
149
+ coach_json = gr.JSON()
150
+ with gr.Tab("Predictions (Admin)"):
151
+ predictions_json = gr.JSON()
152
+
153
+ start_btn.click(
154
+ start_exam,
155
+ inputs=[level, subject, num_q, include_pred],
156
+ outputs=[exam_display, exam_area, results_area, score_text, exam_output]
157
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
+ submit_btn.click(
160
+ submit_exam,
161
+ inputs=[answers_box, exam_output, level, subject],
162
+ outputs=[score_text, analysis_json, coach_json, predictions_json, exam_area, results_area]
163
+ )
164
+
165
+ with gr.Tab("📂 Upload Exam PDF"):
166
+ pdf_file = gr.File(label="Upload SPM PDF", type="file")
167
+
168
+ subject_input = gr.Dropdown(["BM", "English", "Math", "History", "Science", "MoralStudies"],
169
+ value="BM", label="Subject")
170
+ year_input = gr.Dropdown([str(y) for y in range(2018, 2025)], value="2018", label="Year")
171
+ process_btn = gr.Button("Process PDF → JSON + Merge")
172
+ ocr_status = gr.Textbox(label="OCR Status", interactive=False)
173
+
174
+ # Prefill subject/year when PDF is uploaded
175
+ pdf_file.change(prefill_subject_year, inputs=[pdf_file], outputs=[subject_input, year_input])
176
+ process_btn.click(process_pdf, inputs=[pdf_file, subject_input, year_input], outputs=ocr_status)
177
 
178
  if __name__ == "__main__":
179
  demo.launch()
 
183
 
184
 
185
 
186
+