Download src/services/evaluation_service.py from False45/math-api: direct link, hf CLI and curl.
- Browser
- Download file 3.49 kB
-
https://huggingface.co/spaces/False45/math-api/resolve/main/src/services/evaluation_service.py
- Command line
-
hf download hf://spaces/False45/math-api/src/services/evaluation_service.py
-
curl -L -o evaluation_service.py https://huggingface.co/spaces/False45/math-api/resolve/main/src/services/evaluation_service.py
3.49 kB
| """ | |
| Evaluation Service — Offline LLM-as-judge pipeline for answering quality. | |
| """ | |
| import logging | |
| from typing import Dict, List, Any | |
| from backend.src.config import settings | |
| logger = logging.getLogger("math_assistant.eval") | |
| class EvaluationService: | |
| """Uses LLM-as-judge to evaluate generated math answers against reference solutions.""" | |
| def __init__(self, judge_model: str = "gemini-2.5-flash"): | |
| self.judge_model = judge_model | |
| def evaluate_answer(self, question: str, generated_answer: str, reference_answer: str) -> Dict[str, Any]: | |
| """Ask the judge model to score the generated answer from 1 to 5.""" | |
| from google import genai | |
| from google.genai import types | |
| api_key = settings.gemini_api_key | |
| if not api_key: | |
| return {"score": 0, "reasoning": "Missing API Key for evaluation"} | |
| client = genai.Client(api_key=api_key) | |
| prompt = f"""You are an expert mathematics teacher grading a student's answer. | |
| Question: {question} | |
| Reference/Correct Answer: | |
| {reference_answer} | |
| Student's Answer to evaluate: | |
| {generated_answer} | |
| Grade the student's answer from 1 to 5 based on: | |
| 1. Accuracy: Is the final answer correct? | |
| 2. Steps: Are the steps logical and mathematically sound? | |
| Format your response EXACTLY as follows: | |
| SCORE: [1-5] | |
| REASONING: [1-2 sentences explaining why] | |
| """ | |
| config = types.GenerateContentConfig( | |
| temperature=0.1, | |
| max_output_tokens=150, | |
| ) | |
| try: | |
| response = client.models.generate_content( | |
| model=self.judge_model, | |
| contents=prompt, | |
| config=config | |
| ) | |
| text = response.text.strip() | |
| score = 0 | |
| reasoning = text | |
| for line in text.split('\n'): | |
| if line.startswith("SCORE:"): | |
| try: | |
| score = int(line.replace("SCORE:", "").strip()) | |
| except: | |
| pass | |
| elif line.startswith("REASONING:"): | |
| reasoning = line.replace("REASONING:", "").strip() | |
| return {"score": score, "reasoning": reasoning} | |
| except Exception as e: | |
| logger.error(f"Evaluation failed: {e}") | |
| return {"score": 0, "reasoning": f"Evaluation error: {e}"} | |
| def run_eval_pipeline(self, test_cases: List[Dict[str, str]]) -> Dict[str, Any]: | |
| """Run evaluation on a batch of test cases.""" | |
| results = [] | |
| total_score = 0 | |
| for case in test_cases: | |
| res = self.evaluate_answer( | |
| question=case['question'], | |
| generated_answer=case['generated_answer'], | |
| reference_answer=case['reference_answer'] | |
| ) | |
| total_score += res['score'] | |
| results.append({ | |
| "question": case['question'], | |
| "score": res['score'], | |
| "reasoning": res['reasoning'] | |
| }) | |
| avg_score = total_score / len(test_cases) if test_cases else 0 | |
| return { | |
| "average_score": avg_score, | |
| "total_evaluated": len(test_cases), | |
| "results": results | |
| } | |