atz21 commited on
Commit
02d8496
·
verified ·
1 Parent(s): 4350cad
Files changed (1) hide show
  1. app.py +53 -31
app.py CHANGED
@@ -1,34 +1,39 @@
1
  import os
2
  import gradio as gr
3
  import google.generativeai as genai
4
- from reportlab.platypus import SimpleDocTemplate, Paragraph
5
- from reportlab.lib.styles import getSampleStyleSheet
6
- from reportlab.lib.pagesizes import A4
7
 
8
  # -------------------- CONFIG --------------------
9
  genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
10
 
11
  # ---------- PROMPTS ----------
12
- TRANSCRIPTION_PROMPT = """ Your Role: You are an expert technical transcriber specializing in mathematical and scientific documents. Your mission is to convert handwritten solutions from a provided image or PDF into a clean, accurate, and logically structured Markdown format.
13
  Primary Objective: Preserve the author's intended solution path while filtering out all mistakes, corrections, and extraneous marks. The final output must be perfectly formatted and easy to follow.
 
14
  Core Instructions:
15
  Hierarchical Structure:
16
- Identify all questions and subquestions based on their numbering (e.g., 1. a), ### i)).
17
- Use ## for main questions (e.g., ## Question 1).
18
- Use ### for subquestions (e.g., ### a), ### i)).
19
- If a question number appears out of its logical sequence, transcribe it with the label provided in the source.
 
20
  What to Exclude (Content Filtration):
21
- Mistakes: Completely ignore and do not transcribe any number, variable, or expression that has been struck through, scribbled over, or crossed out. Transcribe only the corrected, final version.
22
- Extraneous Marks: Do not include any doodles, underlines (unless part of a fraction), or stray marks not relevant to the solution.
 
23
  Crucial Distinction: Cancellations vs. Step Cuts:
24
- Term Cancellation: This is a valid mathematical step where terms cancel each other out (e.g., +2x and -2x, or a term divided by itself).
25
- Action: Transcribe the step where the cancellation occurs. Immediately after that line, add a concise, bracketed note explaining what was cancelled.
26
- Step Cut: This is when the author skips intermediate algebraic or arithmetic steps (e.g., jumping from 2b = 2 directly to b = 1).
27
- Action: Transcribe the steps exactly as they appear. Do not invent or add the missing steps. The logical jump in the transcribed output serves to represent the step cut.
 
28
  Formatting and Special Cases:
29
- Equations: Enclose all mathematical equations and multi-line calculations in Markdown code blocks for clarity and proper rendering.
30
- Illegibility: If a specific word or number is impossible to read, use the placeholder [illegible].
31
- Graphs: Do not attempt to recreate graphs. Instead, describe them textually. Note the type of curve (e.g., parabola, polynomial) and list any labeled key points like intercepts, vertices, or asymptotes."""
 
 
 
32
  GRADING_PROMPT = """Instructions to Examiners
33
 
34
  Abbreviations:
@@ -108,16 +113,13 @@ Implied marks appear in brackets, e.g. (M1), and can only be awarded if correct
108
  - More than one solution: mark only the first response unless candidate specifies otherwise.
109
  """
110
 
111
-
112
- # ---------- HELPER: Save to PDF ----------
113
  def save_as_pdf(text, filename="output.pdf"):
114
- styles = getSampleStyleSheet()
115
- doc = SimpleDocTemplate(filename, pagesize=A4)
116
- story = [Paragraph(p, styles["Normal"]) for p in text.split("\n")]
117
- doc.build(story)
118
  return filename
119
 
120
-
121
  # ---------- STEP 1: TRANSCRIPTION ----------
122
  def transcribe(ans_file):
123
  try:
@@ -135,7 +137,6 @@ def transcribe(ans_file):
135
  except Exception as e:
136
  return f"❌ Error during transcription: {e}", None
137
 
138
-
139
  # ---------- STEP 2: GRADING ----------
140
  def grade(qp_file, ms_file, transcription):
141
  try:
@@ -143,18 +144,39 @@ def grade(qp_file, ms_file, transcription):
143
  ms_uploaded = genai.upload_file(path=ms_file, display_name="Marking Scheme")
144
  model = genai.GenerativeModel("gemini-2.5-pro", generation_config={"temperature": 0})
145
 
146
- resp = model.generate_content([GRADING_PROMPT, qp_uploaded, ms_uploaded, transcription])
147
-
148
- grading = getattr(resp, "text", None)
149
- if not grading and resp.candidates:
150
- grading = resp.candidates[0].content.parts[0].text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
  pdf_path = save_as_pdf(grading, "grading.pdf")
153
  return grading, pdf_path
154
  except Exception as e:
155
  return f"❌ Error during grading: {e}", None
156
 
157
-
158
  # ---------- GRADIO APP ----------
159
  with gr.Blocks(title="LeadIB AI Grading") as demo:
160
  gr.Markdown("## LeadIB AI Grading\nUpload exam documents to transcribe and grade student answers step by step.")
 
1
  import os
2
  import gradio as gr
3
  import google.generativeai as genai
4
+ from markdown_pdf import MarkdownPdf, Section
 
 
5
 
6
  # -------------------- CONFIG --------------------
7
  genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
8
 
9
  # ---------- PROMPTS ----------
10
+ TRANSCRIPTION_PROMPT = """Your Role: You are an expert technical transcriber specializing in mathematical and scientific documents. Your mission is to convert handwritten solutions from a provided image or PDF into a clean, accurate, and logically structured Markdown format.
11
  Primary Objective: Preserve the author's intended solution path while filtering out all mistakes, corrections, and extraneous marks. The final output must be perfectly formatted and easy to follow.
12
+
13
  Core Instructions:
14
  Hierarchical Structure:
15
+ - Identify all questions and subquestions based on their numbering (e.g., 1. a), i)).
16
+ - Use ## for main questions (e.g., ## Question 1).
17
+ - Use ### for subquestions (e.g., ### a), ### i)).
18
+ - If a question number appears out of its logical sequence, transcribe it with the label provided in the source.
19
+
20
  What to Exclude (Content Filtration):
21
+ - Mistakes: Completely ignore and do not transcribe any number, variable, or expression that has been struck through, scribbled over, or crossed out. Transcribe only the corrected, final version.
22
+ - Extraneous Marks: Do not include any doodles, underlines (unless part of a fraction), or stray marks not relevant to the solution.
23
+
24
  Crucial Distinction: Cancellations vs. Step Cuts:
25
+ - Term Cancellation: This is a valid mathematical step where terms cancel each other out (e.g., +2x and -2x, or a term divided by itself).
26
+ Action: Transcribe the step where the cancellation occurs. Immediately after that line, add a concise, bracketed note explaining what was cancelled.
27
+ - Step Cut: This is when the author skips intermediate algebraic or arithmetic steps (e.g., jumping from 2b = 2 directly to b = 1).
28
+ Action: Transcribe the steps exactly as they appear. Do not invent or add the missing steps. The logical jump in the transcribed output serves to represent the step cut.
29
+
30
  Formatting and Special Cases:
31
+ - Equations: Enclose all mathematical equations and multi-line calculations in Markdown code blocks for clarity and proper rendering.
32
+ - Illegibility: If a specific word or number is impossible to read, use the placeholder [illegible].
33
+ - Graphs: Do not attempt to recreate graphs. Instead, describe them textually. Note the type of curve (e.g., parabola, polynomial) and list any labeled key points like intercepts, vertices, or asymptotes.
34
+ """
35
+
36
+ # Full 9-rule grading prompt (point 9 is Presentation; "Calculators" section removed)
37
  GRADING_PROMPT = """Instructions to Examiners
38
 
39
  Abbreviations:
 
113
  - More than one solution: mark only the first response unless candidate specifies otherwise.
114
  """
115
 
116
+ # ---------- HELPER: Save to PDF using markdown-pdf ----------
 
117
  def save_as_pdf(text, filename="output.pdf"):
118
+ pdf = MarkdownPdf()
119
+ pdf.add_section(Section(text, toc=False))
120
+ pdf.save(filename)
 
121
  return filename
122
 
 
123
  # ---------- STEP 1: TRANSCRIPTION ----------
124
  def transcribe(ans_file):
125
  try:
 
137
  except Exception as e:
138
  return f"❌ Error during transcription: {e}", None
139
 
 
140
  # ---------- STEP 2: GRADING ----------
141
  def grade(qp_file, ms_file, transcription):
142
  try:
 
144
  ms_uploaded = genai.upload_file(path=ms_file, display_name="Marking Scheme")
145
  model = genai.GenerativeModel("gemini-2.5-pro", generation_config={"temperature": 0})
146
 
147
+ # Prompt that embeds the full 9 rules and enforces a structured grading table
148
+ structured_instructions = (
149
+ "You are an official examiner. Use the following grading rules strictly:\n\n"
150
+ f"{GRADING_PROMPT}\n\n"
151
+ "OUTPUT FORMAT (use GitHub-flavored Markdown table):\n\n"
152
+ "| Student wrote | Marks Awarded | Reason (reference the rules; specify error type: A : All Good , B : Silly Mistake , C : Conceptual Error , D : Hard question , E : Not Applicable) |\n"
153
+ "|---|---|---|\n"
154
+ "Then, after the table, provide a short 'Summary & Final Mark' section with totals and any FT usage noted.\n\n"
155
+ "Guidelines:\n"
156
+ "1) Apply marks exactly as per the markscheme.\n"
157
+ "2) Justify each awarded or withheld mark with explicit references to the numbered rules.\n"
158
+ "3) Classify all errors (Conceptual Error, Silly Mistake, Misread, or None).\n"
159
+ "4) Enforce dependency between M and A marks (no A awarded if M not earned) and indicate FT when applied.\n"
160
+ "5) Do not invent marks that are not present in the markscheme.\n"
161
+ "6) Provide step-by-step reasoning for each mark awarded or withheld.\n"
162
+ )
163
+
164
+ response = model.generate_content([
165
+ structured_instructions,
166
+ qp_uploaded, # uploaded question paper
167
+ ms_uploaded, # uploaded marking scheme
168
+ transcription # student's transcription
169
+ ])
170
+
171
+ grading = getattr(response, "text", None)
172
+ if not grading and response.candidates:
173
+ grading = response.candidates[0].content.parts[0].text
174
 
175
  pdf_path = save_as_pdf(grading, "grading.pdf")
176
  return grading, pdf_path
177
  except Exception as e:
178
  return f"❌ Error during grading: {e}", None
179
 
 
180
  # ---------- GRADIO APP ----------
181
  with gr.Blocks(title="LeadIB AI Grading") as demo:
182
  gr.Markdown("## LeadIB AI Grading\nUpload exam documents to transcribe and grade student answers step by step.")