mvm2-math-verification / utils /explanation_generator.py
Varshith dharmaj
Upload utils/explanation_generator.py with huggingface_hub
ca95ab5 verified
"""
Explanation Generation
Generates natural language explanations for errors found
Provides educational context and learning suggestions
"""
from typing import Dict, Any
def generate_explanation(error: Dict[str, Any]) -> str:
"""
Generate human-readable explanation for an error.
Args:
error: Error dictionary with type, found, correct, step_number, etc.
Returns:
Natural language explanation string (2-3 sentences)
"""
error_type = error.get("type", "unknown")
found = error.get("found", "")
correct = error.get("correct", "")
operation = error.get("operation", "")
step_number = error.get("step_number", 0)
# Extract numbers from found and correct
import re
found_nums = re.findall(r'\d+\.?\d*', found)
correct_nums = re.findall(r'\d+\.?\d*', correct)
# Generate explanation based on error type
if error_type == "calculation_error":
explanation = _explain_arithmetic_error(found, correct, operation, found_nums, correct_nums)
elif error_type == "logical_error":
explanation = _explain_logical_error(error, step_number)
elif error_type == "operation_mismatch":
explanation = _explain_operation_mismatch(error, found, correct)
elif error_type == "semantic_error":
explanation = _explain_semantic_error(error, found, correct)
else:
explanation = _explain_generic_error(found, correct)
# Add learning context
learning_tip = _get_learning_tip(error_type, operation)
if learning_tip:
explanation += f" {learning_tip}"
return explanation
def _explain_arithmetic_error(found: str, correct: str, operation: str, found_nums: list, correct_nums: list) -> str:
"""Explain arithmetic calculation errors."""
if not found_nums or not correct_nums:
return f"You wrote '{found}', but the correct answer is '{correct}'."
try:
found_result = float(found_nums[-1]) if found_nums else 0
correct_result = float(correct_nums[-1]) if correct_nums else 0
if len(found_nums) >= 2:
operand1 = float(found_nums[0])
operand2 = float(found_nums[1])
op_names = {
'+': 'add',
'-': 'subtract',
'*': 'multiply',
'/': 'divide'
}
op_name = op_names.get(operation, 'calculate')
explanation = f"You wrote {found_result}, but {operand1} {operation} {operand2} actually equals {correct_result}. "
if operation == '+':
explanation += f"When you add {operand2} to {operand1}, you get {correct_result}, not {found_result}."
elif operation == '-':
explanation += f"When you subtract {operand2} from {operand1}, you count down: {operand1}, {correct_result}. So {operand1} - {operand2} = {correct_result}, not {found_result}."
elif operation == '*':
explanation += f"When you multiply {operand1} by {operand2}, you get {correct_result}, not {found_result}."
elif operation == '/':
explanation += f"When you divide {operand1} by {operand2}, you get {correct_result}, not {found_result}."
else:
explanation += f"The correct calculation gives {correct_result}, not {found_result}."
return explanation
except:
pass
return f"You wrote '{found}', but the correct answer is '{correct}'."
def _explain_logical_error(error: Dict[str, Any], step_number: int) -> str:
"""Explain logical consistency errors."""
description = error.get("description", "There is a logical inconsistency in your reasoning.")
explanation = f"In step {step_number}, {description.lower()} "
explanation += "This contradicts your earlier statements or creates circular reasoning."
return explanation
def _explain_operation_mismatch(error: Dict[str, Any], found: str, correct: str) -> str:
"""Explain operation mismatch errors."""
description = error.get("description", "The operation doesn't match what you described.")
explanation = f"{description} "
explanation += "Make sure the mathematical operation matches what you're trying to do in the problem."
return explanation
def _explain_semantic_error(error: Dict[str, Any], found: str, correct: str) -> str:
"""Explain semantic inconsistency errors."""
description = error.get("description", "The meaning doesn't match the mathematical expression.")
explanation = f"{description} "
explanation += "Review the step to ensure it follows logically from the previous steps."
return explanation
def _explain_generic_error(found: str, correct: str) -> str:
"""Generic error explanation."""
return f"You wrote '{found}', but the correct answer should be '{correct}'. Please review your calculation."
def _get_learning_tip(error_type: str, operation: str) -> str:
"""Get learning tip based on error type."""
tips = {
"calculation_error": "Try double-checking your arithmetic by working through the problem step by step.",
"logical_error": "Make sure each step follows logically from the previous one and doesn't contradict earlier statements.",
"operation_mismatch": "Before writing the math, think about which operation matches what you're trying to do.",
"semantic_error": "Review how this step connects to the overall problem and previous steps."
}
return tips.get(error_type, "Practice similar problems to improve your understanding.")