| | import os |
| | from groq import Groq |
| | import gradio as gr |
| | import pytesseract |
| | from sentence_transformers import SentenceTransformer, util |
| | from PIL import Image |
| | from typing import List |
| | import torch |
| | from transformers import BertTokenizer, BertModel, T5ForConditionalGeneration, T5Tokenizer |
| | import torch.nn.functional as F |
| |
|
| | |
| | tokenizer = BertTokenizer.from_pretrained('bert-base-uncased') |
| | bert_model = BertModel.from_pretrained('bert-base-uncased') |
| | sentence_model = SentenceTransformer('paraphrase-MiniLM-L6-v2') |
| |
|
| | |
| | grammar_model = T5ForConditionalGeneration.from_pretrained('t5-base') |
| | grammar_tokenizer = T5Tokenizer.from_pretrained('t5-base') |
| |
|
| | |
| | client = Groq(api_key=os.environ.get("GROQ_API_KEY")) |
| |
|
| | |
| | system_prompt = { |
| | "role": "system", |
| | "content": "You are a useful assistant. You reply with efficient answers." |
| | } |
| |
|
| | async def chat_groq(message, history): |
| | messages = [system_prompt] |
| | for msg in history: |
| | messages.append({"role": "user", "content": str(msg[0])}) |
| | messages.append({"role": "assistant", "content": str(msg[1])}) |
| | messages.append({"role": "user", "content": str(message)}) |
| |
|
| | response_content = '' |
| | |
| | stream = client.chat.completions.create( |
| | model="llama3-70b-8192", |
| | messages=messages, |
| | max_tokens=1024, |
| | temperature=1.3, |
| | stream=True |
| | ) |
| |
|
| | for chunk in stream: |
| | content = chunk.choices[0].delta.content |
| | if content: |
| | response_content += chunk.choices[0].delta.content |
| | yield response_content |
| |
|
| | def extract_text_from_image(filepath: str, languages: List[str]): |
| | image = Image.open(filepath) |
| | lang_str = '+'.join(languages) |
| | return pytesseract.image_to_string(image=image, lang=lang_str) |
| |
|
| | def assign_badge(grade): |
| | if grade == 5: |
| | return "Gold Badge 🌟" |
| | elif grade == 4: |
| | return "Silver Badge 🥈" |
| | elif grade == 3: |
| | return "Bronze Badge 🥉" |
| | else: |
| | return "Keep Improving Badge 💪" |
| |
|
| | def detailed_feedback(similarity_score): |
| | if similarity_score >= 0.9: |
| | return {"Clarity": "Excellent", "Completeness": "Complete", "Accuracy": "Accurate"} |
| | elif similarity_score >= 0.8: |
| | return {"Clarity": "Good", "Completeness": "Almost Complete", "Accuracy": "Mostly Accurate"} |
| | elif similarity_score >= 0.7: |
| | return {"Clarity": "Fair", "Completeness": "Partial", "Accuracy": "Some Errors"} |
| | else: |
| | return {"Clarity": "Needs Improvement", "Completeness": "Incomplete", "Accuracy": "Inaccurate"} |
| |
|
| | def get_grade(similarity_score): |
| | if similarity_score >= 0.9: |
| | return 5 |
| | elif similarity_score >= 0.8: |
| | return 4 |
| | elif similarity_score >= 0.7: |
| | return 3 |
| | elif similarity_score >= 0.6: |
| | return 2 |
| | else: |
| | return 1 |
| |
|
| | def get_bert_embedding(text): |
| | inputs = tokenizer(text, return_tensors='pt', truncation=True, padding=True) |
| | with torch.no_grad(): |
| | outputs = bert_model(**inputs) |
| | embeddings = outputs.last_hidden_state.mean(dim=1) |
| | return embeddings |
| |
|
| | def calculate_cosine_similarity(embedding1, embedding2): |
| | similarity = F.cosine_similarity(embedding1, embedding2) |
| | return similarity.item() |
| |
|
| | def calculate_sentence_similarity(text1, text2): |
| | embedding1 = sentence_model.encode(text1, convert_to_tensor=True) |
| | embedding2 = sentence_model.encode(text2, convert_to_tensor=True) |
| | return util.pytorch_cos_sim(embedding1, embedding2).item() |
| |
|
| | |
| | def detect_grammar_errors(text): |
| | input_text = f"grammar: {text}" |
| | inputs = grammar_tokenizer.encode(input_text, return_tensors='pt', max_length=512, truncation=True) |
| | outputs = grammar_model.generate(inputs, max_length=512, num_beams=4, early_stopping=True) |
| | grammar_analysis = grammar_tokenizer.decode(outputs[0], skip_special_tokens=True) |
| | |
| | |
| | corrected_sentence = grammar_analysis |
| | |
| | |
| | |
| | original_words = text.split() |
| | corrected_words = corrected_sentence.split() |
| | |
| | |
| | error_count = abs(len(original_words) - len(corrected_words)) |
| | |
| | return error_count, corrected_sentence |
| |
|
| |
|
| | def penalize_for_grammar(student_answer): |
| | grammar_errors, _ = detect_grammar_errors(student_answer) |
| | print(f"errors given by grammer:{grammar_errors}") |
| | |
| | penalty = max(0, 1 - 0.25 * grammar_errors) |
| | return penalty |
| |
|
| |
|
| | def compare_answers(student_answer, teacher_answer): |
| | bert_similarity = calculate_cosine_similarity(get_bert_embedding(student_answer), get_bert_embedding(teacher_answer)) |
| | print(f"BERT similarity: {bert_similarity}") |
| | |
| | sentence_similarity = calculate_sentence_similarity(student_answer, teacher_answer) |
| | print(f"Sentence similarity: {sentence_similarity}") |
| | |
| | |
| | semantic_similarity = (0.50 * bert_similarity + 0.50 * sentence_similarity) |
| | print(f"Semantic similarity: {semantic_similarity}") |
| | |
| | |
| | grammar_penalty = penalize_for_grammar(student_answer) |
| | final_similarity = semantic_similarity - grammar_penalty |
| | print(f"grammar penalty: {grammar_penalty}") |
| | print(f"Final similarity (after grammar penalty): {final_similarity}") |
| | |
| | return final_similarity |
| |
|
| | def extract_keywords(text): |
| | return set(text.lower().split()) |
| |
|
| | def check_keywords(student_answer, model_answer): |
| | student_keywords = extract_keywords(student_answer) |
| | teacher_keywords = extract_keywords(model_answer) |
| | keyword_overlap = len(student_keywords.intersection(teacher_keywords)) |
| | keyword_similarity = keyword_overlap / (len(teacher_keywords) if len(teacher_keywords) > 0 else 1) |
| | print(f"Keyword similarity: {keyword_similarity}") |
| | return keyword_similarity |
| |
|
| | def evaluate_answer(image, languages, model_answer): |
| | student_answer = extract_text_from_image(image, languages) |
| | print(f"Extracted student answer: {student_answer}") |
| | |
| | |
| | semantic_similarity = compare_answers(student_answer, model_answer) |
| | |
| | |
| | keyword_similarity = check_keywords(student_answer, model_answer) |
| | |
| | |
| | combined_similarity = (0.9 * semantic_similarity + 0.1 * keyword_similarity) |
| | print(f"Combined similarity score: {combined_similarity}") |
| | |
| | grade = get_grade(combined_similarity) |
| | feedback = f"Student's answer: {student_answer}\nTeacher's answer: {model_answer}" |
| | badge = assign_badge(grade) |
| | detailed_feedback_msg = detailed_feedback(combined_similarity) |
| | |
| | prompt = f"The student got grade: {grade} when the student's answer is: {student_answer} and the teacher's answer is: {model_answer}. Justify the grade given to the student." |
| | |
| | return grade, combined_similarity * 100, feedback, badge, detailed_feedback_msg, prompt |
| |
|
| | async def gradio_interface(image, languages: List[str], model_answer="The process of photosynthesis helps plants produce glucose using sunlight.", prompt="", history=[]): |
| | grade, similarity_score, feedback, badge, detailed_feedback_msg, prompt = evaluate_answer(image, languages, model_answer) |
| | response = "" |
| | async for result in chat_groq(prompt, history): |
| | response = result |
| | return grade, similarity_score, feedback, badge, detailed_feedback_msg, response |
| |
|
| | language_choices = pytesseract.get_languages() |
| |
|
| | interface = gr.Interface( |
| | fn=gradio_interface, |
| | inputs=[ |
| | gr.Image(type="filepath", label="Input"), |
| | gr.CheckboxGroup(language_choices, type="value", value=['eng'], label='Language'), |
| | gr.Textbox(lines=2, placeholder="Enter your model answer here", label="Model Answer"), |
| | gr.Textbox(lines=2, placeholder="Enter your prompt here", label="Prompt") |
| | ], |
| | outputs=[ |
| | gr.Text(label="Grade"), |
| | gr.Number(label="Similarity Score (%)"), |
| | gr.Text(label="Feedback"), |
| | gr.Text(label="Badge"), |
| | gr.JSON(label="Detailed Feedback"), |
| | gr.Text(label="Generated Response") |
| | ], |
| | title="Enhanced Automated Grading System", |
| | description="Upload an image of your answer sheet to get a grade from 1 to 5, similarity score, visual feedback, badge, and detailed feedback based on the model answer.", |
| | live=True |
| | ) |
| |
|
| | if __name__ == "__main__": |
| | interface.queue() |
| | interface.launch() |
| |
|