Benny-Tang commited on
Commit
bd2bcf3
·
verified ·
1 Parent(s): 2ea57ed

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -150
app.py CHANGED
@@ -1,156 +1,98 @@
1
- import gradio as gr
 
2
  import random
 
 
3
 
4
- # -------------------------------
5
- # Demo Exam Data
6
- # -------------------------------
7
- QUESTIONS = {
8
- "Bahasa Melayu Paper 1": [
9
- {"text": "Tulis sebuah karangan tentang kepentingan membaca.", "answer": None},
10
- {"text": "Huraikan peranan teknologi dalam kehidupan seharian.", "answer": None},
11
- ],
12
- "Bahasa Melayu Paper 2": [
13
- {"text": "Apakah kata dasar bagi perkataan 'berjalan'?",
14
- "choices": ["A. Ber", "B. Jalan", "C. An", "D. Jal"], "answer": "B"},
15
- {"text": "Peribahasa 'harapkan pegar, pegar makan padi' bermaksud?",
16
- "choices": ["A. Orang rajin", "B. Pengkhianatan oleh penjaga", "C. Hidup susah", "D. Orang baik hati"], "answer": "B"},
17
- ],
18
- "English Paper 1": [
19
- {"text": "Write an essay about the importance of sports.", "answer": None},
20
- {"text": "Describe a memorable day at school.", "answer": None},
21
- ],
22
- "English Paper 2": [
23
- {"text": "Choose the correct synonym for 'happy'.",
24
- "choices": ["A. Sad", "B. Joyful", "C. Angry", "D. Tired"], "answer": "B"},
25
- {"text": "What is the plural of 'child'?",
26
- "choices": ["A. Childs", "B. Childes", "C. Children", "D. Childer"], "answer": "C"},
27
- ],
28
- }
29
-
30
- # -------------------------------
31
- # Load Exam Function
32
- # -------------------------------
33
- def load_exam(subject):
34
- questions = QUESTIONS.get(subject, [])
35
- outputs = []
36
-
37
- for i, q in enumerate(questions, 1):
38
- # Display question text
39
- outputs.append(f"**Q{i}:** {q['text']}")
40
-
41
- # Subjective Paper → Textbox
42
- if "choices" not in q:
43
- outputs.append("") # empty string = textbox placeholder
44
-
45
- # Objective Paper Radio buttons
46
- else:
47
- outputs.append({"choices": q["choices"], "value": None})
48
-
49
- return outputs, questions
50
-
51
-
52
- # -------------------------------
53
- # Submit Exam Function
54
- # -------------------------------
55
- def submit_exam(answers, questions):
56
- score = 0
57
- results = []
58
-
59
- for ans, q in zip(answers, questions):
60
- if "choices" in q: # objective paper
61
- correct = q["answer"]
62
- if ans == correct:
63
- score += 1
64
- results.append(f"✅ {q['text']} → Your answer: {ans} (Correct)")
65
- else:
66
- results.append(f"❌ {q['text']} → Your answer: {ans}, Correct answer: {correct}")
67
- else: # subjective paper
68
- results.append(f"📝 {q['text']} → Your response recorded.")
69
-
70
- return f"Your Score: {score} / {len(questions)}", "\n\n".join(results)
71
-
72
-
73
- # -------------------------------
74
- # Build Gradio UI
75
- # -------------------------------
76
  with gr.Blocks() as demo:
77
- gr.Markdown("## 📘 SPM Exam Simulator")
78
-
79
- subject = gr.Dropdown(list(QUESTIONS.keys()), label="Select Subject")
80
- load_btn = gr.Button("Load Exam")
81
-
82
- question_boxes = []
83
- answer_inputs = []
84
-
85
- # Preallocate 10 slots (max 10 questions per subject for demo)
86
- for i in range(10):
87
- qtext = gr.Markdown(visible=False)
88
- atext = gr.Textbox(visible=False, label="Your Answer")
89
- aradio = gr.Radio(visible=False, label="Select Answer")
90
- question_boxes.append((qtext, atext, aradio))
91
- answer_inputs.append((atext, aradio))
92
-
93
- submit_btn = gr.Button("Submit", visible=False)
94
- score_output = gr.Markdown()
95
- detail_output = gr.Markdown()
96
- state_questions = gr.State()
97
-
98
- def on_load(subject):
99
- outputs, questions = load_exam(subject)
100
-
101
- # Reset UI
102
- updates = []
103
- answers_state = []
104
-
105
- for i, (qtext, atext, aradio) in enumerate(question_boxes):
106
- if i < len(questions):
107
- q = questions[i]
108
- qtext.update(value=f"**Q{i+1}:** {q['text']}", visible=True)
109
-
110
- if "choices" in q: # objective
111
- atext.update(visible=False)
112
- aradio.update(choices=q["choices"], value=None, visible=True)
113
- answers_state.append(None)
114
- else: # subjective
115
- aradio.update(visible=False)
116
- atext.update(value="", visible=True)
117
- answers_state.append("")
118
- else:
119
- qtext.update(visible=False)
120
- atext.update(visible=False)
121
- aradio.update(visible=False)
122
-
123
- updates.extend([qtext, atext, aradio])
124
-
125
- return updates + [gr.Button.update(visible=True), questions]
126
-
127
- def on_submit(*all_inputs):
128
- # all_inputs includes answers + state_questions
129
- *answers, questions = all_inputs
130
-
131
- # Extract answers: pick from textbox or radio
132
- processed = []
133
- for (txt, rad), ans in zip(answer_inputs, answers):
134
- if isinstance(ans, str):
135
- processed.append(ans)
136
- elif isinstance(ans, dict) and "value" in ans:
137
- processed.append(ans["value"])
138
- else:
139
- processed.append(None)
140
-
141
- return submit_exam(processed, questions)
142
-
143
- load_btn.click(
144
- fn=on_load,
145
- inputs=[subject],
146
- outputs=[comp for triple in question_boxes for comp in triple] + [submit_btn, state_questions],
147
- )
148
-
149
- submit_btn.click(
150
- fn=on_submit,
151
- inputs=[comp for pair in answer_inputs for comp in pair] + [state_questions],
152
- outputs=[score_output, detail_output],
153
- )
154
 
155
  demo.launch(server_name="0.0.0.0", server_port=7860)
156
 
@@ -174,5 +116,6 @@ demo.launch(server_name="0.0.0.0", server_port=7860)
174
 
175
 
176
 
 
177
 
178
 
 
1
+ import os
2
+ import json
3
  import random
4
+ import subprocess
5
+ import gradio as gr
6
 
7
+ from agents import AnalyzerAgent, CoachAgent, PredictiveAgent
8
+ from ocr_agent import OcrAgent
9
+
10
+ # Paths
11
+ DATA_DIR = "data"
12
+ QUESTIONS_FILE = "questions.json"
13
+ os.makedirs(DATA_DIR, exist_ok=True)
14
+
15
+ # Load merged question bank
16
+ def load_question_bank():
17
+ if not os.path.exists(QUESTIONS_FILE) or os.path.getsize(QUESTIONS_FILE) == 0:
18
+ return []
19
+ try:
20
+ with open(QUESTIONS_FILE, "r", encoding="utf-8") as f:
21
+ return json.load(f)
22
+ except:
23
+ return []
24
+
25
+ QUESTION_BANK = load_question_bank()
26
+
27
+ # Initialize agents
28
+ analyzer = AnalyzerAgent()
29
+ coach = CoachAgent()
30
+ predictor = PredictiveAgent()
31
+ ocr_agent = OcrAgent()
32
+
33
+ # Functions
34
+ def upload_pdf(pdf_file, subject, year, paper):
35
+ if pdf_file is None:
36
+ return "⚠️ No file uploaded."
37
+ questions = ocr_agent.extract_questions(pdf_file, subject, year, paper)
38
+ subprocess.run(["python", "merge_questions.py"])
39
+ return f"✅ Extracted {len(questions)} questions from {subject.upper()} Paper {paper} ({year})"
40
+
41
+ def run_exam(subject, num_questions, include_predicted):
42
+ pool = [q for q in QUESTION_BANK if subject.lower() in q["source"]]
43
+ if include_predicted:
44
+ predicted = predictor.predict(subject)
45
+ pool.append({"id": 9999, "text": predicted, "choices": [], "topics": [], "source": "predicted"})
46
+ if not pool:
47
+ return "⚠️ No questions available.", [], []
48
+ selected = random.sample(pool, min(num_questions, len(pool)))
49
+ q_texts = [q["text"] for q in selected]
50
+ q_ids = [q["id"] for q in selected]
51
+ return "\n\n".join(q_texts), q_ids, [q.get("choices", []) for q in selected]
52
+
53
+ def submit_answers(q_ids, answers):
54
+ correct_answers = ["A"] * len(q_ids) # Placeholder until scheme data ready
55
+ score, analysis = analyzer.analyze(answers, correct_answers)
56
+ return f"Score: {score}/{len(q_ids)}", "\n".join(analysis)
57
+
58
+ def essay_feedback(essay_text):
59
+ return coach.coach(essay_text)
60
+
61
+ # Gradio UI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  with gr.Blocks() as demo:
63
+ gr.Markdown("## 📝 SPM Exam Simulator (Form 5)")
64
+
65
+ with gr.Tab("Upload Past Papers"):
66
+ pdf_file = gr.File(label="Upload PDF", type="filepath")
67
+ subject = gr.Dropdown(["BM", "English", "Math", "History", "Science", "MoralStudies"], label="Subject")
68
+ year = gr.Number(label="Year", value=2018, precision=0)
69
+ paper = gr.Dropdown([1, 2], label="Paper")
70
+ upload_btn = gr.Button("Process PDF")
71
+ upload_out = gr.Textbox(label="Upload Status")
72
+ upload_btn.click(fn=upload_pdf, inputs=[pdf_file, subject, year, paper], outputs=upload_out)
73
+
74
+ with gr.Tab("Paper 2 Simulator"):
75
+ subject_sim = gr.Dropdown(["BM", "English", "Math", "History", "Science", "MoralStudies"], label="Subject")
76
+ num_q = gr.Slider(1, 50, step=1, value=10, label="Number of Questions")
77
+ include_pred = gr.Checkbox(label="Include AI-Predicted")
78
+ run_btn = gr.Button("Start Simulation")
79
+ q_out = gr.Textbox(label="Questions")
80
+ ids_out = gr.State()
81
+ choices_out = gr.State()
82
+ run_btn.click(fn=run_exam, inputs=[subject_sim, num_q, include_pred], outputs=[q_out, ids_out, choices_out])
83
+
84
+ ans_in = gr.Textbox(label="Your Answers (comma-separated, e.g. A,B,C)")
85
+ submit_btn = gr.Button("Submit")
86
+ score_out = gr.Textbox(label="Score")
87
+ analysis_out = gr.Textbox(label="Analysis")
88
+ submit_btn.click(fn=lambda ids, ans: submit_answers(ids, ans.split(",")),
89
+ inputs=[ids_out, ans_in], outputs=[score_out, analysis_out])
90
+
91
+ with gr.Tab("Paper 1 (Essay Practice)"):
92
+ essay_in = gr.Textbox(label="Write your essay here", lines=10)
93
+ essay_btn = gr.Button("Get Feedback")
94
+ essay_out = gr.Textbox(label="Feedback")
95
+ essay_btn.click(fn=essay_feedback, inputs=essay_in, outputs=essay_out)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
  demo.launch(server_name="0.0.0.0", server_port=7860)
98
 
 
116
 
117
 
118
 
119
+
120
 
121