bloggy commited on
Commit
c500600
·
verified ·
1 Parent(s): 5511244

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +119 -0
app.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import pytesseract
4
+ from PIL import Image
5
+ from rapidfuzz import fuzz, utils
6
+ import io
7
+
8
+ # --- CONFIGURATION ---
9
+ st.set_page_config(page_title="AI Student Grader", layout="wide")
10
+ st.title("📝 AI Student Answer Grader")
11
+ st.markdown("Upload answer sheets and an answer key to automatically calculate marks.")
12
+
13
+ # --- SIDEBAR SETTINGS ---
14
+ st.sidebar.header("Grading Settings")
15
+ accuracy_threshold = st.sidebar.slider("Minimum Accuracy Threshold (%)", 0, 100, 70)
16
+ marks_per_question = st.sidebar.number_input("Marks per correct answer", value=1.0)
17
+
18
+ # --- HELPER FUNCTIONS ---
19
+ def perform_ocr(image):
20
+ """Extracts text from an uploaded image."""
21
+ img = Image.open(image)
22
+ # Optional: Add image preprocessing here (grayscale, thresholding)
23
+ text = pytesseract.image_to_string(img)
24
+ return text.strip()
25
+
26
+ def compare_answers(student_text, answer_key, threshold):
27
+ """
28
+ Compares student text with answer key using Fuzzy Matching.
29
+ DeepSeek-R1 style logic: We look for the presence of key concepts.
30
+ """
31
+ # Simple line-by-line comparison (assuming 1 question per line or similar structure)
32
+ # For complex papers, you'd split by question numbers
33
+ score = 0
34
+ key_lines = [line.strip() for line in answer_key.split('\n') if line.strip()]
35
+ student_lines = [line.strip() for line in student_text.split('\n') if line.strip()]
36
+
37
+ details = []
38
+
39
+ for i, correct_ans in enumerate(key_lines):
40
+ match_found = False
41
+ highest_match = 0
42
+
43
+ # Compare against each line in student text to find the best match for this answer
44
+ for s_line in student_lines:
45
+ similarity = fuzz.token_set_ratio(correct_ans, s_line)
46
+ if similarity > highest_match:
47
+ highest_match = similarity
48
+
49
+ if highest_match >= threshold:
50
+ score += marks_per_question
51
+ match_found = True
52
+
53
+ details.append({
54
+ "Question": i + 1,
55
+ "Match %": round(highest_match, 2),
56
+ "Status": "Correct" if match_found else "Incorrect"
57
+ })
58
+
59
+ return score, details
60
+
61
+ # --- UI LAYOUT ---
62
+ col1, col2 = st.columns(2)
63
+
64
+ with col1:
65
+ st.subheader("1. Reference Answer Key")
66
+ key_input_type = st.radio("Key Format", ["Text Input", "Upload Image"])
67
+
68
+ if key_input_type == "Text Input":
69
+ answer_key_text = st.text_area("Paste the correct answers (one per line):")
70
+ else:
71
+ key_img = st.file_uploader("Upload Answer Key Image", type=['png', 'jpg', 'jpeg'])
72
+ if key_img:
73
+ answer_key_text = perform_ocr(key_img)
74
+ st.text_area("Extracted Key (Edit if needed):", value=answer_key_text)
75
+
76
+ with col2:
77
+ st.subheader("2. Student Answer Sheets")
78
+ student_images = st.file_uploader("Upload Student Images (Max 5)", type=['png', 'jpg', 'jpeg'], accept_multiple_files=True)
79
+
80
+ # --- PROCESSING ---
81
+ if st.button("Calculate Marks"):
82
+ if not answer_key_text or not student_images:
83
+ st.error("Please provide both the answer key and student images.")
84
+ else:
85
+ results = []
86
+
87
+ progress_bar = st.progress(0)
88
+ for idx, img_file in enumerate(student_images):
89
+ # 1. OCR
90
+ extracted_text = perform_ocr(img_file)
91
+
92
+ # 2. Compare
93
+ score, details = compare_answers(extracted_text, answer_key_text, accuracy_threshold)
94
+
95
+ # 3. Store Results
96
+ results.append({
97
+ "Student Name": img_file.name.split('.')[0], # Uses filename as name
98
+ "Raw Score": score,
99
+ "Final Marks": f"{score}/{len(answer_key_text.splitlines()) * marks_per_question}",
100
+ "Match Percentage": f"{accuracy_threshold}%"
101
+ })
102
+ progress_bar.progress((idx + 1) / len(student_images))
103
+
104
+ # --- DISPLAY RESULTS ---
105
+ df = pd.DataFrame(results)
106
+ st.subheader("📊 Results Overview")
107
+ st.table(df)
108
+
109
+ # --- EXCEL EXPORT ---
110
+ output = io.BytesIO()
111
+ with pd.ExcelWriter(output, engine='openpyxl') as writer:
112
+ df.to_excel(writer, index=False, sheet_name='Grades')
113
+
114
+ st.download_button(
115
+ label="📥 Download Excel Sheet",
116
+ data=output.getvalue(),
117
+ file_name="student_grades.xlsx",
118
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
119
+ )