Spaces:
Sleeping
Sleeping
| import os | |
| import gradio as gr | |
| import base64 | |
| from typing import List | |
| from io import BytesIO | |
| from PIL import Image | |
| import zipfile | |
| from openai import OpenAI | |
| def encode_image(image_path): | |
| """Encodes an image file to base64.""" | |
| with open(image_path, "rb") as image_file: | |
| return base64.b64encode(image_file.read()).decode('utf-8') | |
| def generate_prompt(question, marking_scheme, student_response): | |
| """Generates the grading prompt for the OpenAI API.""" | |
| prompt = f""" | |
| Question: {question} | |
| Marking Scheme: {marking_scheme} | |
| Student Response: {student_response} | |
| 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. | |
| """ | |
| return prompt | |
| def read_file_content(file): | |
| """Reads the content of a file.""" | |
| with open(file.name, 'r') as f: | |
| return f.read() | |
| def grade_student_answers(client, marking_scheme, student_answers): | |
| """Grades student answers using the OpenAI API.""" | |
| prompt = f""" | |
| Marking Scheme: | |
| {marking_scheme} | |
| Student Answers: | |
| {student_answers} | |
| Grade the student answers based on the marking scheme. Use appropriate Checkmark (✓) and (X). Provide a detailed feedback and score as a percentage. | |
| The output should resemble that of a Professor! | |
| """ | |
| response = client.chat.completions.create( | |
| model="gpt-4", | |
| messages=[ | |
| {"role": "system", "content": "You are an expert Quiz grader."}, | |
| {"role": "user", "content": prompt} | |
| ], | |
| max_tokens=1048 | |
| ) | |
| return response.choices[0].message.content.strip() | |
| def grade_explanatory_test_text(api_key, question_file, marking_scheme_file, student_responses): | |
| """Grades explanatory test text files.""" | |
| client = OpenAI(api_key=api_key) | |
| output_files = [] | |
| try: | |
| question = read_file_content(question_file) | |
| marking_scheme = read_file_content(marking_scheme_file) | |
| for student_file in student_responses: | |
| student_name = os.path.splitext(os.path.basename(student_file.name))[0] | |
| student_response = read_file_content(student_file) | |
| prompt = generate_prompt(question, marking_scheme, student_response) | |
| response = client.chat.completions.create( | |
| model="gpt-4", | |
| messages=[ | |
| {"role": "system", "content": "You are a helpful assistant"}, | |
| {"role": "user", "content": prompt} | |
| ], | |
| max_tokens=3500, | |
| temperature=0.0 | |
| ) | |
| grade = response.choices[0].message.content.strip() | |
| output_filename = f"{student_name}_grade.txt" | |
| with open(output_filename, 'w') as out_f: | |
| out_f.write(grade) | |
| output_files.append(output_filename) | |
| zip_filename = "graded_results.zip" | |
| with zipfile.ZipFile(zip_filename, 'w') as zip_file: | |
| for file in output_files: | |
| zip_file.write(file) | |
| return zip_filename | |
| except Exception as e: | |
| return f"An error occurred: {e}" | |
| def extract_text_from_image(api_key, image_file): | |
| """Extracts text from an image using the OpenAI API.""" | |
| try: | |
| client = OpenAI(api_key=api_key) | |
| with Image.open(image_file) as img: | |
| img = img.convert("RGB") | |
| img.thumbnail((1280, 1280)) | |
| buffer = BytesIO() | |
| img.save(buffer, format="JPEG") | |
| base64_image = base64.b64encode(buffer.getvalue()).decode('utf-8') | |
| response = client.chat.completions.create( | |
| model="gpt-4", | |
| messages=[ | |
| {"role": "system", "content": "You are a helpful assistant"}, | |
| {"role": "user", "content": [ | |
| {"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."}, | |
| {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}} | |
| ]} | |
| ], | |
| max_tokens=1048 | |
| ) | |
| return response.choices[0].message.content.strip() | |
| except Exception as e: | |
| return f"An error occurred while extracting text from the image: {e}" | |
| def grade_explanatory_test_image(api_key, question_file, marking_scheme_file, student_responses): | |
| """Grades explanatory test image files.""" | |
| client = OpenAI(api_key=api_key) | |
| output_files = [] | |
| try: | |
| question = read_file_content(question_file) | |
| marking_scheme = read_file_content(marking_scheme_file) | |
| for image_file in student_responses: | |
| student_name = os.path.splitext(os.path.basename(image_file.name))[0] | |
| student_response = extract_text_from_image(api_key, image_file) | |
| if "An error occurred" in student_response: | |
| return student_response | |
| prompt = generate_prompt(question, marking_scheme, student_response) | |
| response = client.chat.completions.create( | |
| model="gpt-4", | |
| messages=[ | |
| {"role": "system", "content": "You are a helpful assistant"}, | |
| {"role": "user", "content": prompt} | |
| ], | |
| max_tokens=3500, | |
| temperature=0.0 | |
| ) | |
| grade = response.choices[0].message.content.strip() | |
| output_filename = f"{student_name}_grade.txt" | |
| with open(output_filename, 'w') as out_f: | |
| out_f.write(grade) | |
| output_files.append(output_filename) | |
| zip_filename = "graded_results.zip" | |
| with zipfile.ZipFile(zip_filename, 'w') as zip_file: | |
| for file in output_files: | |
| zip_file.write(file) | |
| return zip_filename | |
| except Exception as e: | |
| return f"An error occurred: {e}" | |
| def grade_multiple_choice_test(api_key, marking_scheme_file, images): | |
| """Grades multiple choice test image files.""" | |
| client = OpenAI(api_key=api_key) | |
| output_files = [] | |
| try: | |
| marking_scheme = read_file_content(marking_scheme_file) | |
| for image_file in images: | |
| student_name = os.path.splitext(os.path.basename(image_file.name))[0] | |
| student_answers = extract_text_from_image(api_key, image_file) | |
| if "An error occurred" in student_answers: | |
| return student_answers | |
| grade = grade_student_answers(client, marking_scheme, student_answers) | |
| output_filename = f"{student_name}_grade.txt" | |
| with open(output_filename, 'w') as out_f: | |
| out_f.write(grade) | |
| output_files.append(output_filename) | |
| zip_filename = "graded_results.zip" | |
| with zipfile.ZipFile(zip_filename, 'w') as zip_file: | |
| for file in output_files: | |
| zip_file.write(file) | |
| return zip_filename | |
| except Exception as e: | |
| return f"An error occurred: {e}" | |
| def handle_choice(choice): | |
| """Handles the user choice for test type and updates the UI accordingly.""" | |
| if choice == "Explanatory Test": | |
| return [ | |
| gr.update(visible=True), # question_file | |
| gr.update(visible=True), # marking_scheme_explanatory_file | |
| gr.update(visible=True), # explanatory_type | |
| gr.update(visible=False), # marking_scheme_mcq_file | |
| gr.update(visible=False), # image_input_mcq | |
| gr.update(visible=False), # student_responses_text | |
| gr.update(visible=False) # student_responses_image | |
| ] | |
| else: | |
| return [ | |
| gr.update(visible=False), # question_file | |
| gr.update(visible=False), # marking_scheme_explanatory_file | |
| gr.update(visible=False), # explanatory_type | |
| gr.update(visible=True), # marking_scheme_mcq_file | |
| gr.update(visible=True), # image_input_mcq | |
| gr.update(visible=False), # student_responses_text | |
| gr.update(visible=False) # student_responses_image | |
| ] | |
| def handle_explanatory_type(explanatory_type): | |
| """Handles the explanatory test type and updates the UI accordingly.""" | |
| if explanatory_type == "Text Files": | |
| return [ | |
| gr.update(visible=True), # student_responses_text | |
| gr.update(visible=False) # student_responses_image | |
| ] | |
| else: | |
| return [ | |
| gr.update(visible=False), # student_responses_text | |
| gr.update(visible=True) # student_responses_image | |
| ] | |
| def clear_inputs(): | |
| """Clears all input fields.""" | |
| return [ | |
| "", # API key | |
| None, # choice | |
| gr.update(value=None, visible=False), # explanatory_type | |
| gr.update(visible=False), # question_file | |
| gr.update(visible=False), # marking_scheme_explanatory_file | |
| gr.update(visible=False), # student_responses_text | |
| gr.update(visible=False), # student_responses_image | |
| gr.update(visible=False), # marking_scheme_mcq_file | |
| gr.update(visible=False), # image_input_mcq | |
| None # output_file | |
| ] | |
| # Gradio Interface | |
| with gr.Blocks() as demo: | |
| api_key = gr.Textbox(label="OpenAI API Key", type="password") | |
| choice = gr.Radio(["Explanatory Test", "Multiple Choice Test"], label="Choose the type of test to grade") | |
| explanatory_type = gr.Radio(["Text Files", "Image Files"], label="Choose the type of explanatory test", visible=False) | |
| # Explanatory test inputs | |
| question_file = gr.File(label="Upload Question File", visible=False) | |
| marking_scheme_explanatory_file = gr.File(label="Upload Marking Scheme File", visible=False) | |
| student_responses_text = gr.File(label="Upload Student Response Text Files", file_count='multiple', visible=False) | |
| student_responses_image = gr.File(label="Upload Student Response Image Files", file_count='multiple', visible=False) | |
| # Multiple choice test inputs | |
| marking_scheme_mcq_file = gr.File(label="Upload Marking Scheme File", visible=False) | |
| image_input_mcq = gr.File(label="Upload Student Answer Images", file_count='multiple', visible=False) | |
| output_file = gr.File(label="Download Graded Results") | |
| # Handle choice to show/hide appropriate inputs | |
| choice.change(fn=handle_choice, inputs=choice, outputs=[question_file, marking_scheme_explanatory_file, explanatory_type, marking_scheme_mcq_file, image_input_mcq]) | |
| explanatory_type.change(fn=handle_explanatory_type, inputs=explanatory_type, outputs=[student_responses_text, student_responses_image]) | |
| # Submit and Clear buttons | |
| submit_btn = gr.Button("Submit") | |
| clear_btn = gr.Button("Clear") | |
| submit_btn.click( | |
| 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: | |
| grade_explanatory_test_text(api_key, question_file, marking_scheme_explanatory_file, student_responses_text) if explanatory_type == "Text Files" else | |
| grade_explanatory_test_image(api_key, question_file, marking_scheme_explanatory_file, student_responses_image) if choice == "Explanatory Test" else | |
| grade_multiple_choice_test(api_key, marking_scheme_mcq_file, image_input_mcq), | |
| 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], | |
| outputs=output_file | |
| ) | |
| clear_btn.click( | |
| fn=clear_inputs, | |
| inputs=[], | |
| outputs=[api_key, choice, explanatory_type, question_file, marking_scheme_explanatory_file, | |
| student_responses_text, student_responses_image, marking_scheme_mcq_file, | |
| image_input_mcq, output_file] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |