msmaje commited on
Commit
40b8198
·
verified ·
1 Parent(s): 8cb0881

app.py created

Browse files

a brand new app.py

Files changed (1) hide show
  1. app.py +280 -0
app.py ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import base64
4
+ from typing import List
5
+ from io import BytesIO
6
+ from PIL import Image
7
+ import zipfile
8
+ from openai import OpenAI
9
+
10
+ def encode_image(image_path):
11
+ """Encodes an image file to base64."""
12
+ with open(image_path, "rb") as image_file:
13
+ return base64.b64encode(image_file.read()).decode('utf-8')
14
+
15
+ def generate_prompt(question, marking_scheme, student_response):
16
+ """Generates the grading prompt for the OpenAI API."""
17
+ prompt = f"""
18
+ Question: {question}
19
+
20
+ Marking Scheme: {marking_scheme}
21
+
22
+ Student Response: {student_response}
23
+
24
+ As an expert in this field, please grade the student's response based on the marking scheme provided. Provide detailed scores and feedback, and a well-tabulated breakdown of scores.
25
+ """
26
+ return prompt
27
+
28
+ def read_file_content(file):
29
+ """Reads the content of a file."""
30
+ with open(file.name, 'r') as f:
31
+ return f.read()
32
+
33
+ def grade_student_answers(client, marking_scheme, student_answers):
34
+ """Grades student answers using the OpenAI API."""
35
+ prompt = f"""
36
+ Marking Scheme:
37
+ {marking_scheme}
38
+
39
+ Student Answers:
40
+ {student_answers}
41
+
42
+ Grade the student answers based on the marking scheme. Use appropriate Checkmark (✓) and (X). Provide a detailed feedback and score as a percentage.
43
+
44
+ The output should resemble that of a Professor!
45
+ """
46
+ response = client.chat.completions.create(
47
+ model="gpt-4",
48
+ messages=[
49
+ {"role": "system", "content": "You are an expert Quiz grader."},
50
+ {"role": "user", "content": prompt}
51
+ ],
52
+ max_tokens=1048
53
+ )
54
+ return response.choices[0].message.content.strip()
55
+
56
+ def grade_explanatory_test_text(api_key, question_file, marking_scheme_file, student_responses):
57
+ """Grades explanatory test text files."""
58
+ client = OpenAI(api_key=api_key)
59
+ output_files = []
60
+ try:
61
+ question = read_file_content(question_file)
62
+ marking_scheme = read_file_content(marking_scheme_file)
63
+ for student_file in student_responses:
64
+ student_name = os.path.splitext(os.path.basename(student_file.name))[0]
65
+ student_response = read_file_content(student_file)
66
+ prompt = generate_prompt(question, marking_scheme, student_response)
67
+ response = client.chat.completions.create(
68
+ model="gpt-4",
69
+ messages=[
70
+ {"role": "system", "content": "You are a helpful assistant"},
71
+ {"role": "user", "content": prompt}
72
+ ],
73
+ max_tokens=3500,
74
+ temperature=0.0
75
+ )
76
+ grade = response.choices[0].message.content.strip()
77
+ output_filename = f"{student_name}_grade.txt"
78
+ with open(output_filename, 'w') as out_f:
79
+ out_f.write(grade)
80
+ output_files.append(output_filename)
81
+
82
+ zip_filename = "graded_results.zip"
83
+ with zipfile.ZipFile(zip_filename, 'w') as zip_file:
84
+ for file in output_files:
85
+ zip_file.write(file)
86
+
87
+ return zip_filename
88
+ except Exception as e:
89
+ return f"An error occurred: {e}"
90
+
91
+ def extract_text_from_image(api_key, image_file):
92
+ """Extracts text from an image using the OpenAI API."""
93
+ try:
94
+ client = OpenAI(api_key=api_key)
95
+
96
+ with Image.open(image_file) as img:
97
+ img = img.convert("RGB")
98
+ img.thumbnail((1280, 1280))
99
+ buffer = BytesIO()
100
+ img.save(buffer, format="JPEG")
101
+ base64_image = base64.b64encode(buffer.getvalue()).decode('utf-8')
102
+
103
+ response = client.chat.completions.create(
104
+ model="gpt-4",
105
+ messages=[
106
+ {"role": "system", "content": "You are a helpful assistant"},
107
+ {"role": "user", "content": [
108
+ {"type":"text", "text": "Extract the text from this image. It is a student exam script, where the student is answering multiple choice questions. Write out the text in the image. Don't include any other text in your output."},
109
+ {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}}
110
+ ]}
111
+ ],
112
+ max_tokens=1048
113
+ )
114
+
115
+ return response.choices[0].message.content.strip()
116
+ except Exception as e:
117
+ return f"An error occurred while extracting text from the image: {e}"
118
+
119
+ def grade_explanatory_test_image(api_key, question_file, marking_scheme_file, student_responses):
120
+ """Grades explanatory test image files."""
121
+ client = OpenAI(api_key=api_key)
122
+ output_files = []
123
+ try:
124
+ question = read_file_content(question_file)
125
+ marking_scheme = read_file_content(marking_scheme_file)
126
+ for image_file in student_responses:
127
+ student_name = os.path.splitext(os.path.basename(image_file.name))[0]
128
+ student_response = extract_text_from_image(api_key, image_file)
129
+ if "An error occurred" in student_response:
130
+ return student_response
131
+ prompt = generate_prompt(question, marking_scheme, student_response)
132
+ response = client.chat.completions.create(
133
+ model="gpt-4",
134
+ messages=[
135
+ {"role": "system", "content": "You are a helpful assistant"},
136
+ {"role": "user", "content": prompt}
137
+ ],
138
+ max_tokens=3500,
139
+ temperature=0.0
140
+ )
141
+ grade = response.choices[0].message.content.strip()
142
+ output_filename = f"{student_name}_grade.txt"
143
+ with open(output_filename, 'w') as out_f:
144
+ out_f.write(grade)
145
+ output_files.append(output_filename)
146
+
147
+ zip_filename = "graded_results.zip"
148
+ with zipfile.ZipFile(zip_filename, 'w') as zip_file:
149
+ for file in output_files:
150
+ zip_file.write(file)
151
+
152
+ return zip_filename
153
+ except Exception as e:
154
+ return f"An error occurred: {e}"
155
+
156
+ def grade_multiple_choice_test(api_key, marking_scheme_file, images):
157
+ """Grades multiple choice test image files."""
158
+ client = OpenAI(api_key=api_key)
159
+ output_files = []
160
+ try:
161
+ marking_scheme = read_file_content(marking_scheme_file)
162
+ for image_file in images:
163
+ student_name = os.path.splitext(os.path.basename(image_file.name))[0]
164
+ student_answers = extract_text_from_image(api_key, image_file)
165
+ if "An error occurred" in student_answers:
166
+ return student_answers
167
+
168
+ grade = grade_student_answers(client, marking_scheme, student_answers)
169
+
170
+ output_filename = f"{student_name}_grade.txt"
171
+ with open(output_filename, 'w') as out_f:
172
+ out_f.write(grade)
173
+ output_files.append(output_filename)
174
+
175
+ zip_filename = "graded_results.zip"
176
+ with zipfile.ZipFile(zip_filename, 'w') as zip_file:
177
+ for file in output_files:
178
+ zip_file.write(file)
179
+
180
+ return zip_filename
181
+ except Exception as e:
182
+ return f"An error occurred: {e}"
183
+
184
+ def handle_choice(choice):
185
+ """Handles the user choice for test type and updates the UI accordingly."""
186
+ if choice == "Explanatory Test":
187
+ return [
188
+ gr.update(visible=True), # question_file
189
+ gr.update(visible=True), # marking_scheme_explanatory_file
190
+ gr.update(visible=True), # explanatory_type
191
+ gr.update(visible=False), # marking_scheme_mcq_file
192
+ gr.update(visible=False), # image_input_mcq
193
+ gr.update(visible=False), # student_responses_text
194
+ gr.update(visible=False) # student_responses_image
195
+ ]
196
+ else:
197
+ return [
198
+ gr.update(visible=False), # question_file
199
+ gr.update(visible=False), # marking_scheme_explanatory_file
200
+ gr.update(visible=False), # explanatory_type
201
+ gr.update(visible=True), # marking_scheme_mcq_file
202
+ gr.update(visible=True), # image_input_mcq
203
+ gr.update(visible=False), # student_responses_text
204
+ gr.update(visible=False) # student_responses_image
205
+ ]
206
+
207
+ def handle_explanatory_type(explanatory_type):
208
+ """Handles the explanatory test type and updates the UI accordingly."""
209
+ if explanatory_type == "Text Files":
210
+ return [
211
+ gr.update(visible=True), # student_responses_text
212
+ gr.update(visible=False) # student_responses_image
213
+ ]
214
+ else:
215
+ return [
216
+ gr.update(visible=False), # student_responses_text
217
+ gr.update(visible=True) # student_responses_image
218
+ ]
219
+
220
+ def clear_inputs():
221
+ """Clears all input fields."""
222
+ return [
223
+ "", # API key
224
+ None, # choice
225
+ gr.update(value=None, visible=False), # explanatory_type
226
+ gr.update(visible=False), # question_file
227
+ gr.update(visible=False), # marking_scheme_explanatory_file
228
+ gr.update(visible=False), # student_responses_text
229
+ gr.update(visible=False), # student_responses_image
230
+ gr.update(visible=False), # marking_scheme_mcq_file
231
+ gr.update(visible=False), # image_input_mcq
232
+ None # output_file
233
+ ]
234
+
235
+ # Gradio Interface
236
+ with gr.Blocks() as demo:
237
+ api_key = gr.Textbox(label="OpenAI API Key", type="password")
238
+
239
+ choice = gr.Radio(["Explanatory Test", "Multiple Choice Test"], label="Choose the type of test to grade")
240
+ explanatory_type = gr.Radio(["Text Files", "Image Files"], label="Choose the type of explanatory test", visible=False)
241
+
242
+ # Explanatory test inputs
243
+ question_file = gr.File(label="Upload Question File", visible=False)
244
+ marking_scheme_explanatory_file = gr.File(label="Upload Marking Scheme File", visible=False)
245
+ student_responses_text = gr.File(label="Upload Student Response Text Files", file_count='multiple', visible=False)
246
+ student_responses_image = gr.File(label="Upload Student Response Image Files", file_count='multiple', visible=False)
247
+
248
+ # Multiple choice test inputs
249
+ marking_scheme_mcq_file = gr.File(label="Upload Marking Scheme File", visible=False)
250
+ image_input_mcq = gr.File(label="Upload Student Answer Images", file_count='multiple', visible=False)
251
+
252
+ output_file = gr.File(label="Download Graded Results")
253
+
254
+ # Handle choice to show/hide appropriate inputs
255
+ choice.change(fn=handle_choice, inputs=choice, outputs=[question_file, marking_scheme_explanatory_file, explanatory_type, marking_scheme_mcq_file, image_input_mcq])
256
+ explanatory_type.change(fn=handle_explanatory_type, inputs=explanatory_type, outputs=[student_responses_text, student_responses_image])
257
+
258
+ # Submit and Clear buttons
259
+ submit_btn = gr.Button("Submit")
260
+ clear_btn = gr.Button("Clear")
261
+
262
+ submit_btn.click(
263
+ fn=lambda api_key, choice, explanatory_type, question_file, marking_scheme_explanatory_file, student_responses_text, student_responses_image, marking_scheme_mcq_file, image_input_mcq:
264
+ grade_explanatory_test_text(api_key, question_file, marking_scheme_explanatory_file, student_responses_text) if explanatory_type == "Text Files" else
265
+ grade_explanatory_test_image(api_key, question_file, marking_scheme_explanatory_file, student_responses_image) if choice == "Explanatory Test" else
266
+ grade_multiple_choice_test(api_key, marking_scheme_mcq_file, image_input_mcq),
267
+ inputs=[api_key, choice, explanatory_type, question_file, marking_scheme_explanatory_file, student_responses_text, student_responses_image, marking_scheme_mcq_file, image_input_mcq],
268
+ outputs=output_file
269
+ )
270
+
271
+ clear_btn.click(
272
+ fn=clear_inputs,
273
+ inputs=[],
274
+ outputs=[api_key, choice, explanatory_type, question_file, marking_scheme_explanatory_file,
275
+ student_responses_text, student_responses_image, marking_scheme_mcq_file,
276
+ image_input_mcq, output_file]
277
+ )
278
+
279
+ if __name__ == "__main__":
280
+ demo.launch()