atz21 commited on
Commit
c09fe54
·
verified ·
1 Parent(s): 1f0729a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -237
app.py CHANGED
@@ -1,252 +1,78 @@
1
- import gradio as gr
2
  import os
3
- import io
4
- from google import generativeai as genai
5
-
6
- def process_exam_papers(question_paper, marking_scheme, answer_sheet, api_key, progress=gr.Progress()):
7
- """
8
- Process uploaded exam papers and return transcription and grading
9
- """
10
- if not api_key:
11
- return "Please provide a valid Gemini API key.", "", "Ready"
12
-
13
- if not all([question_paper, marking_scheme, answer_sheet]):
14
- return "Please upload all three files.", "", "Ready"
15
-
16
- try:
17
- # Configure Gemini API
18
- genai.configure(api_key=api_key)
19
-
20
- progress(0.1, desc="Uploading files to Gemini...")
21
-
22
- # Upload files to Gemini
23
- qp_file = genai.upload_file(path=question_paper.name, display_name="Question Paper")
24
- ms_file = genai.upload_file(path=marking_scheme.name, display_name="Marking Scheme")
25
- ans_file = genai.upload_file(path=answer_sheet.name, display_name="Answer Sheet")
26
-
27
- progress(0.3, desc="Files uploaded. Starting transcription...")
28
-
29
- # Transcription instructions
30
- transcription_instructions = """
31
- Persona:
32
- You are an expert transcriptionist specializing in scientific and mathematical documents. Your primary goal is to convert handwritten mathematical work into a perfectly formatted, machine-readable Markdown document using LaTeX for all mathematical notation.
33
-
34
- Core Task:
35
- Your task is to transcribe the provided handwritten student solutions into a single, clean Markdown string.
36
-
37
- Key Directives & Rules:
38
- Absolute Fidelity: Transcribe exactly what is written. Do NOT correct mathematical errors, logical fallacies, or spelling mistakes. Your role is purely that of a scribe, not a grader or editor.
39
 
40
- LaTeX for All Math: All mathematical content—including single variables, numbers in equations, fractions, exponents, roots, and symbols—must be enclosed in LaTeX delimiters. Use inline $ ... $ for math within text and block $$ ... $$ for standalone equations.
 
41
 
42
- Handle Strikethroughs: Completely ignore and omit any text, numbers, or expressions that have been struck through by the student. Do not include them in the final output.
 
 
 
 
 
43
 
44
- Preserve Structure:
45
- Use Markdown bolding (e.g., **1.**, **2a.**) to clearly separate each question or sub-part.
46
- Maintain the vertical, step-by-step flow of the student's derivations. For multi-line aligned equations, use the \\begin{align*} ... \\end{align*} environment within a $$ ... $$ block.
 
 
 
 
 
47
 
48
- Handle Ambiguity: If a character or symbol is genuinely illegible or ambiguous, make your best interpretation and enclose it in square brackets. For example, if a variable could be u or v, write [u?].
 
 
49
 
50
- Output Format:
51
- The final output must be a single Markdown string.
52
- Ensure all LaTeX renders correctly and the structure is clean and readable.
 
 
 
 
 
 
53
 
54
- Comprehensive Example:
55
- If the student's handwritten work for a question looks like this:
56
- 7. Find the value of y.
57
- y = (x² + 3) / 2
58
- for x = 3
59
- y = ( + 3) / 2
60
- y = (6+3) / 2
61
- y = (9 + 3) / 2
62
- y = 12 / 2
63
- y = 6
64
 
65
- Your expected output should be:
66
- **7.**
 
 
67
 
68
- Find the value of y.
69
- $$
70
- y = \\frac{x^2 + 3}{2}
71
- $$
72
- for $x = 3$
73
- $$
74
- \\begin{align*}
75
- y &= \\frac{3^2 + 3}{2} \\\\
76
- y &= \\frac{9 + 3}{2} \\\\
77
- y &= \\frac{12}{2} \\\\
78
- y &= 6
79
- \\end{align*}
80
- $$
81
- """
82
-
83
- # Initialize Gemini model for transcription
84
- model = genai.GenerativeModel(
85
- "gemini-2.5-pro",
86
- generation_config={"temperature": 0}
87
- )
88
-
89
- progress(0.4, desc="Transcribing handwritten answers...")
90
-
91
- # Generate transcription
92
- response = model.generate_content([
93
- transcription_instructions,
94
- ans_file
95
- ])
96
-
97
- # Extract transcription safely
98
- student_transcription = getattr(response, "text", None)
99
- if not student_transcription:
100
- student_transcription = response.candidates[0].content.parts[0].text
101
-
102
- progress(0.7, desc="Transcription complete. Starting grading process...")
103
-
104
- # Return transcription first, then continue with grading
105
- yield student_transcription, "⏳ Grading in progress...", "Grading"
106
-
107
- # Grading system instructions
108
- grading_system = """
109
- Instructions to Examiners:
110
- Abbreviations:
111
- - M: Marks for correct Method.
112
- - A: Marks for Answer or Accuracy (often depends on preceding M mark).
113
- - R: Marks for clear Reasoning.
114
- - AG: Answer given in the question; no marks awarded.
115
- - FT: Follow Through; award marks for correct method/answer using incorrect earlier results.
116
 
117
- Marking Rules:
118
- 1. Always follow the markscheme annotations (M1, A2, etc.).
119
- 2. M marks must be earned before dependent A marks are awarded (no M0 followed by A1 unless explicitly allowed).
120
- 3. If M and A marks are on the same line (e.g., M1A1), M is for the method attempt, A is for correct values.
121
- 4. Multiple A marks on the same line are awarded independently unless otherwise noted.
122
- 5. Do not split M2, A3, etc. unless instructed.
123
- 6. "Show that" responses do not need to restate the AG line unless noted.
124
- 7. Once a correct answer is seen, ignore further incorrect working unless it affects a later part (then apply FT as appropriate).
125
- 8. Do not award the final A mark if an incorrect approximation is used in the same part.
126
 
127
- Error Avoidance:
128
- - **No incorrect mark allocation:** Do not award marks unless they are explicitly justified by the markscheme.
129
- - **No misclassification of errors:** Distinguish correctly between "Conceptual Errors" and "Silly Mistakes."
130
- - **Follow markscheme logic exactly:** Especially regarding when to withhold accuracy marks if method marks are not earned.
131
- """
132
-
133
- # Now start grading using the transcribed text
134
- # Generate grading
135
- grading_response = model.generate_content([
136
- f"You are an official examiner. Use the following grading system and rules to assess the answers:\n\n{grading_system}\n\n"
137
- "Your output must:\n"
138
- "1. Apply marks exactly as per the markscheme.\n"
139
- "2. Justify each awarded or withheld mark with reference to the grading rules.\n"
140
- "3. Identify and classify all errors accurately (Conceptual Error, Silly Mistake, or None).\n"
141
- "4. Follow the dependency between M and A marks strictly.\n"
142
- "5. Avoid giving marks that the markscheme does not allow.\n"
143
- "6. Provide a step-by-step reasoning for each mark awarded or withheld, explaining your thought process clearly.\n",
144
- qp_file,
145
- ms_file,
146
- student_transcription # Use the transcribed text, not the original PDF
147
- ])
148
-
149
- progress(0.9, desc="Finalizing grading results...")
150
-
151
- # Extract grading safely
152
- grading_text = getattr(grading_response, "text", None)
153
- if not grading_text and grading_response.candidates:
154
- grading_text = grading_response.candidates[0].content.parts[0].text
155
- elif not grading_text:
156
- grading_text = "No Response"
157
-
158
- progress(1.0, desc="Complete!")
159
-
160
- # Return final results
161
- yield student_transcription, grading_text, "Complete"
162
-
163
  except Exception as e:
164
- yield f"Error processing files: {str(e)}", "", "Error"
 
165
 
166
- # Create Gradio interface
167
- with gr.Blocks(title="Exam Paper Grading System", theme=gr.themes.Soft()) as demo:
168
- gr.Markdown("""
169
- # 📚 Automated Exam Paper Grading System
170
-
171
- Upload your question paper, marking scheme, and answer sheet to get automated transcription and grading using Google's Gemini AI.
172
- """)
173
-
174
- with gr.Row():
175
- with gr.Column():
176
- gr.Markdown("### 📋 Upload Files")
177
- api_key = gr.Textbox(
178
- label="Gemini API Key",
179
- placeholder="Enter your Google Gemini API key",
180
- type="password"
181
- )
182
- question_paper = gr.File(
183
- label="Question Paper (PDF)",
184
- file_types=[".pdf"]
185
- )
186
- marking_scheme = gr.File(
187
- label="Marking Scheme (PDF)",
188
- file_types=[".pdf"]
189
- )
190
- answer_sheet = gr.File(
191
- label="Answer Sheet (PDF)",
192
- file_types=[".pdf"]
193
- )
194
-
195
- process_btn = gr.Button(
196
- "🚀 Process Papers",
197
- variant="primary",
198
- size="lg"
199
- )
200
-
201
- with gr.Row():
202
- with gr.Column():
203
- gr.Markdown("### 📝 Student Answer Transcription")
204
- transcription_output = gr.Textbox(
205
- label="Transcribed Answers",
206
- lines=15,
207
- max_lines=25,
208
- show_copy_button=True,
209
- placeholder="Transcribed answers will appear here first..."
210
- )
211
-
212
- with gr.Column():
213
- gr.Markdown("### ✅ Grading Results")
214
- grading_output = gr.Textbox(
215
- label="Detailed Grading",
216
- lines=15,
217
- max_lines=25,
218
- show_copy_button=True,
219
- placeholder="Grading results will appear here after transcription is complete..."
220
- )
221
-
222
- # Add status indicator
223
- with gr.Row():
224
- status_display = gr.Textbox(
225
- label="Status",
226
- value="Ready",
227
- interactive=False,
228
- show_label=True
229
- )
230
-
231
- # Set up the processing function
232
- process_btn.click(
233
- fn=process_exam_papers,
234
- inputs=[question_paper, marking_scheme, answer_sheet, api_key],
235
- outputs=[transcription_output, grading_output, status_display]
236
- )
237
-
238
- gr.Markdown("""
239
- ### 📖 How to Use:
240
- 1. **Get a Gemini API Key**: Visit [Google AI Studio](https://makersuite.google.com/app/apikey) to get your free API key
241
- 2. **Upload PDFs**: Upload your question paper, marking scheme, and student answer sheet
242
- 3. **Process**: Click the "Process Papers" button to get transcription and grading
243
- 4. **Review**: Check the transcribed answers and detailed grading results
244
-
245
- ### ⚠️ Notes:
246
- - All uploaded files are processed securely and not stored permanently
247
- - The system transcribes exactly what's written (including errors) for accurate grading
248
- - LaTeX mathematical notation is automatically formatted for clarity
249
- """)
250
 
251
  if __name__ == "__main__":
252
- demo.launch()
 
 
1
  import os
2
+ import gradio as gr
3
+ import google.generativeai as genai
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
+ # Configure Gemini with Hugging Face Secret
6
+ genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
7
 
8
+ # ---------- PROMPTS ----------
9
+ TRANSCRIPTION_PROMPT = """
10
+ Persona:
11
+ You are an expert transcriptionist specializing in scientific and mathematical documents.
12
+ Your primary goal is to convert handwritten mathematical work into a perfectly formatted,
13
+ machine-readable Markdown document using LaTeX for all mathematical notation.
14
 
15
+ Rules:
16
+ - Transcribe exactly what is written, do not correct errors.
17
+ - Use $...$ for inline math, $$...$$ for block math.
18
+ - Ignore struck-through text.
19
+ - Preserve structure: bold for Q numbers (**1.**), step-by-step math with \\begin{align*}.
20
+ - If a symbol is ambiguous, mark as [x?].
21
+ Output must be a clean Markdown string.
22
+ """
23
 
24
+ GRADING_PROMPT = """
25
+ You are an official examiner. Grade the student transcription using the question paper
26
+ and the official marking scheme.
27
 
28
+ Rules:
29
+ 1. Apply marks exactly as per the markscheme (M1, A1, etc.).
30
+ 2. M marks must be earned before A marks.
31
+ 3. Justify each awarded or withheld mark with clear reasoning.
32
+ 4. Classify all errors as Conceptual Error, Silly Mistake, or None.
33
+ 5. Follow dependency between M and A strictly.
34
+ 6. Do not give marks outside the markscheme.
35
+ Output must be a structured grading report with reasoning.
36
+ """
37
 
38
+ # ---------- CORE FUNCTION ----------
39
+ def grade_student(qp_file, ms_file, ans_file):
40
+ try:
41
+ # Upload files to Gemini
42
+ qp_uploaded = genai.upload_file(path=qp_file.name, display_name="Question Paper")
43
+ ms_uploaded = genai.upload_file(path=ms_file.name, display_name="Marking Scheme")
44
+ ans_uploaded = genai.upload_file(path=ans_file.name, display_name="Answer Sheet")
 
 
 
45
 
46
+ # Step 1: Transcription
47
+ model = genai.GenerativeModel("gemini-2.5-pro", generation_config={"temperature": 0})
48
+ transcription_resp = model.generate_content([TRANSCRIPTION_PROMPT, ans_uploaded])
49
+ transcription = getattr(transcription_resp, "text", None) or transcription_resp.candidates[0].content.parts[0].text
50
 
51
+ # Step 2: Grading
52
+ grading_resp = model.generate_content([GRADING_PROMPT, qp_uploaded, ms_uploaded, transcription])
53
+ grading = getattr(grading_resp, "text", None) or grading_resp.candidates[0].content.parts[0].text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
+ return transcription, grading
 
 
 
 
 
 
 
 
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  except Exception as e:
58
+ return "Error during processing: " + str(e), ""
59
+
60
 
61
+ # ---------- GRADIO UI ----------
62
+ demo = gr.Interface(
63
+ fn=grade_student,
64
+ inputs=[
65
+ gr.File(label="Upload Question Paper (PDF)", type="file"),
66
+ gr.File(label="Upload Mark Scheme (PDF)", type="file"),
67
+ gr.File(label="Upload Student Answer Sheet (PDF)", type="file")
68
+ ],
69
+ outputs=[
70
+ gr.Markdown(label="Student Transcription"),
71
+ gr.Textbox(label="Grading Report")
72
+ ],
73
+ title="📘 AI Teacher Assistant",
74
+ description="Upload a Question Paper, Mark Scheme, and Student Answer Sheet. The app transcribes handwritten answers into Markdown/LaTeX and grades them using the official scheme."
75
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
  if __name__ == "__main__":
78
+ demo.launch()