Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,96 +1,56 @@
|
|
| 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 |
-
from reportlab.lib.units import cm
|
| 8 |
|
| 9 |
# Configure Gemini API
|
| 10 |
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
|
| 11 |
|
| 12 |
# ---------- PROMPTS ----------
|
| 13 |
-
TRANSCRIPTION_PROMPT = """
|
| 14 |
-
|
| 15 |
-
You are an expert transcriptionist specializing in scientific and mathematical documents.
|
| 16 |
-
Your primary goal is to convert handwritten mathematical work into a perfectly formatted,
|
| 17 |
-
machine-readable Markdown document using LaTeX for all mathematical notation.
|
| 18 |
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
"""
|
| 27 |
-
|
| 28 |
-
GRADING_PROMPT = """
|
| 29 |
-
You are an official examiner. Grade the student transcription using the question paper
|
| 30 |
-
and the official marking scheme.
|
| 31 |
-
|
| 32 |
-
Rules:
|
| 33 |
-
1. Apply marks exactly as per the markscheme (M1, A1, etc.).
|
| 34 |
-
2. M marks must be earned before A marks.
|
| 35 |
-
3. Justify each awarded or withheld mark with clear reasoning.
|
| 36 |
-
4. Classify all errors as Conceptual Error, Silly Mistake, or None.
|
| 37 |
-
5. Follow dependency between M and A strictly.
|
| 38 |
-
6. Do not give marks outside the markscheme.
|
| 39 |
-
Output must be a structured grading report with reasoning.
|
| 40 |
-
"""
|
| 41 |
|
| 42 |
# ---------- STEP 1: TRANSCRIPTION ----------
|
| 43 |
def transcribe(ans_file):
|
| 44 |
-
yield "β³ Processing transcription..."
|
| 45 |
try:
|
| 46 |
ans_uploaded = genai.upload_file(path=ans_file.name, display_name="Answer Sheet")
|
| 47 |
model = genai.GenerativeModel("gemini-2.5-pro", generation_config={"temperature": 0})
|
|
|
|
| 48 |
resp = model.generate_content([TRANSCRIPTION_PROMPT, ans_uploaded])
|
|
|
|
| 49 |
transcription = getattr(resp, "text", None) or resp.candidates[0].content.parts[0].text
|
| 50 |
-
|
|
|
|
| 51 |
except Exception as e:
|
| 52 |
-
|
| 53 |
|
| 54 |
# ---------- STEP 2: GRADING ----------
|
| 55 |
def grade(qp_file, ms_file, transcription):
|
| 56 |
-
yield "β³ Grading in progress..."
|
| 57 |
try:
|
| 58 |
qp_uploaded = genai.upload_file(path=qp_file.name, display_name="Question Paper")
|
| 59 |
ms_uploaded = genai.upload_file(path=ms_file.name, display_name="Marking Scheme")
|
| 60 |
-
|
| 61 |
model = genai.GenerativeModel("gemini-2.5-pro", generation_config={"temperature": 0})
|
| 62 |
-
resp = model.generate_content([GRADING_PROMPT, qp_uploaded, ms_uploaded, transcription])
|
| 63 |
-
grading = getattr(resp, "text", None) or resp.candidates[0].content.parts[0].text
|
| 64 |
-
|
| 65 |
-
# Save grading report as PDF
|
| 66 |
-
pdf_path = "/tmp/grading_report.pdf"
|
| 67 |
-
doc = SimpleDocTemplate(pdf_path, pagesize=A4)
|
| 68 |
-
styles = getSampleStyleSheet()
|
| 69 |
-
elements = []
|
| 70 |
|
| 71 |
-
|
| 72 |
-
elements.append(Spacer(1, 0.5*cm))
|
| 73 |
-
for para in grading.split("\n"):
|
| 74 |
-
if para.strip():
|
| 75 |
-
elements.append(Paragraph(para, styles["Normal"]))
|
| 76 |
-
elements.append(Spacer(1, 0.2*cm))
|
| 77 |
-
|
| 78 |
-
doc.build(elements)
|
| 79 |
|
| 80 |
-
|
|
|
|
|
|
|
| 81 |
except Exception as e:
|
| 82 |
-
|
| 83 |
|
| 84 |
# ---------- GRADIO APP ----------
|
| 85 |
with gr.Blocks(title="π AI Teacher Assistant") as demo:
|
| 86 |
-
# Inject MathJax for LaTeX rendering
|
| 87 |
-
gr.HTML("""
|
| 88 |
-
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
|
| 89 |
-
<script id="MathJax-script" async
|
| 90 |
-
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
|
| 91 |
-
</script>
|
| 92 |
-
""")
|
| 93 |
-
|
| 94 |
gr.Markdown("## π AI Teacher Assistant\nUpload exam documents to transcribe and grade student answers step by step.")
|
| 95 |
|
| 96 |
with gr.Row():
|
|
@@ -100,16 +60,29 @@ with gr.Blocks(title="π AI Teacher Assistant") as demo:
|
|
| 100 |
|
| 101 |
# Step 1: Transcription
|
| 102 |
transcribe_btn = gr.Button("Step 1: Transcribe Answer Sheet")
|
| 103 |
-
|
|
|
|
|
|
|
| 104 |
|
| 105 |
# Step 2: Grading
|
| 106 |
grade_btn = gr.Button("Step 2: Grade the Student")
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
|
| 114 |
if __name__ == "__main__":
|
| 115 |
demo.launch()
|
|
|
|
| 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 |
# Configure Gemini API
|
| 9 |
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
|
| 10 |
|
| 11 |
# ---------- PROMPTS ----------
|
| 12 |
+
TRANSCRIPTION_PROMPT = """ ... """ # unchanged
|
| 13 |
+
GRADING_PROMPT = """ ... """ # unchanged
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
+
# ---------- HELPER: Save to PDF ----------
|
| 16 |
+
def save_as_pdf(text, filename="output.pdf"):
|
| 17 |
+
styles = getSampleStyleSheet()
|
| 18 |
+
doc = SimpleDocTemplate(filename, pagesize=A4)
|
| 19 |
+
story = [Paragraph(p, styles["Normal"]) for p in text.split("\n")]
|
| 20 |
+
doc.build(story)
|
| 21 |
+
return filename
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
# ---------- STEP 1: TRANSCRIPTION ----------
|
| 24 |
def transcribe(ans_file):
|
|
|
|
| 25 |
try:
|
| 26 |
ans_uploaded = genai.upload_file(path=ans_file.name, display_name="Answer Sheet")
|
| 27 |
model = genai.GenerativeModel("gemini-2.5-pro", generation_config={"temperature": 0})
|
| 28 |
+
|
| 29 |
resp = model.generate_content([TRANSCRIPTION_PROMPT, ans_uploaded])
|
| 30 |
+
|
| 31 |
transcription = getattr(resp, "text", None) or resp.candidates[0].content.parts[0].text
|
| 32 |
+
pdf_path = save_as_pdf(transcription, "transcription.pdf")
|
| 33 |
+
return transcription, pdf_path
|
| 34 |
except Exception as e:
|
| 35 |
+
return f"β Error during transcription: {e}", None
|
| 36 |
|
| 37 |
# ---------- STEP 2: GRADING ----------
|
| 38 |
def grade(qp_file, ms_file, transcription):
|
|
|
|
| 39 |
try:
|
| 40 |
qp_uploaded = genai.upload_file(path=qp_file.name, display_name="Question Paper")
|
| 41 |
ms_uploaded = genai.upload_file(path=ms_file.name, display_name="Marking Scheme")
|
|
|
|
| 42 |
model = genai.GenerativeModel("gemini-2.5-pro", generation_config={"temperature": 0})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
|
| 44 |
+
resp = model.generate_content([GRADING_PROMPT, qp_uploaded, ms_uploaded, transcription])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
|
| 46 |
+
grading = getattr(resp, "text", None) or resp.candidates[0].content.parts[0].text
|
| 47 |
+
pdf_path = save_as_pdf(grading, "grading.pdf")
|
| 48 |
+
return grading, pdf_path
|
| 49 |
except Exception as e:
|
| 50 |
+
return f"β Error during grading: {e}", None
|
| 51 |
|
| 52 |
# ---------- GRADIO APP ----------
|
| 53 |
with gr.Blocks(title="π AI Teacher Assistant") as demo:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
gr.Markdown("## π AI Teacher Assistant\nUpload exam documents to transcribe and grade student answers step by step.")
|
| 55 |
|
| 56 |
with gr.Row():
|
|
|
|
| 60 |
|
| 61 |
# Step 1: Transcription
|
| 62 |
transcribe_btn = gr.Button("Step 1: Transcribe Answer Sheet")
|
| 63 |
+
with gr.Row():
|
| 64 |
+
transcription_out = gr.Markdown(label="π Student Transcription")
|
| 65 |
+
transcription_pdf = gr.File(label="β¬οΈ Download Transcription (PDF)")
|
| 66 |
|
| 67 |
# Step 2: Grading
|
| 68 |
grade_btn = gr.Button("Step 2: Grade the Student")
|
| 69 |
+
with gr.Row():
|
| 70 |
+
grading_out = gr.Textbox(label="β
Grading Report (Step-by-Step)", lines=20)
|
| 71 |
+
grading_pdf = gr.File(label="β¬οΈ Download Grading (PDF)")
|
| 72 |
+
|
| 73 |
+
# Button Logic with loading indicators
|
| 74 |
+
transcribe_btn.click(
|
| 75 |
+
fn=transcribe,
|
| 76 |
+
inputs=[ans_file],
|
| 77 |
+
outputs=[transcription_out, transcription_pdf],
|
| 78 |
+
show_progress=True
|
| 79 |
+
)
|
| 80 |
+
grade_btn.click(
|
| 81 |
+
fn=grade,
|
| 82 |
+
inputs=[qp_file, ms_file, transcription_out],
|
| 83 |
+
outputs=[grading_out, grading_pdf],
|
| 84 |
+
show_progress=True
|
| 85 |
+
)
|
| 86 |
|
| 87 |
if __name__ == "__main__":
|
| 88 |
demo.launch()
|