Natarajan-Networks/grading-env
0
1import os2import requests3from openai import OpenAI4 5API_BASE_URL = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1")6MODEL_NAME = os.getenv("MODEL_NAME", "Qwen/Qwen2.5-72B-Instruct")7HF_TOKEN = os.getenv("HF_TOKEN")8 9if HF_TOKEN is None:10 raise ValueError("HF_TOKEN environment variable is required")11 12client = OpenAI(13 base_url=API_BASE_URL,14 api_key=HF_TOKEN15)16 17ENV_BASE_URL = os.getenv("ENV_BASE_URL", os.getenv("SPACE_URL", "https://natarajan-networks-grading-env.hf.space"))18 19def llm_grade(question, student_answer, answer_key, semantic_similarity, concept_coverage):20 prompt = f"""You are an expert educational grader. Grade the following student answer.21 22Question: {question}23Reference Answer: {answer_key}24Student Answer: {student_answer}25Semantic Similarity Score: {semantic_similarity:.2f}26Concept Coverage Score: {concept_coverage:.2f}27 28Instructions:29- Award marks between 0.1 and 0.9 only30- 0.9 = excellent answer covering all key concepts31- 0.5 = partial answer with some correct concepts32- 0.1 = completely wrong or irrelevant answer33- Consider the semantic similarity and concept coverage scores as hints34- Be fair and consistent35 36Respond with ONLY a single decimal number between 0.1 and 0.9. Nothing else."""37 38 try:39 response = client.chat.completions.create(40 model=MODEL_NAME,41 messages=[{"role": "user", "content": prompt}],42 max_tokens=10,43 temperature=0.144 )45 text = response.choices[0].message.content.strip()46 mark = float(text)47 return round(max(0.1, min(0.9, mark)), 2)48 except Exception:49 return round(max(0.1, min(0.9, (semantic_similarity + concept_coverage) / 2 + 0.1)), 2)50 51def run_task(task_id):52 base = ENV_BASE_URL.rstrip("/")53 rewards = []54 step_num = 055 success = False56 score = 0.557 58 task_names = {1: "grading-easy", 2: "grading-medium", 3: "grading-hard"}59 task_name = task_names.get(task_id, f"grading-task-{task_id}")60 61 print(f"[START] task={task_name} env=edueval model={MODEL_NAME}", flush=True)62 63 try:64 reset_resp = requests.post(65 f"{base}/reset",66 params={"task_id": task_id},67 timeout=3068 )69 obs = reset_resp.json()70 done = obs.get("done", False)71 72 while not done:73 step_num += 174 75 question = obs.get("question_text", "")76 student_answer = obs.get("student_answer", "")77 answer_key = obs.get("answer_key", "")78 semantic_similarity = obs.get("semantic_similarity", 0.0)79 concept_coverage = obs.get("concept_coverage", 0.0)80 81 marks = llm_grade(82 question,83 student_answer,84 answer_key,85 semantic_similarity,86 concept_coverage87 )88 89 step_resp = requests.post(90 f"{base}/step",91 params={"task_id": task_id},92 json={"marks_awarded": marks},93 timeout=3094 )95 result = step_resp.json()96 reward = result.get("reward", 0.0)97 done = result.get("done", False)98 obs = result.get("observation", {})99 rewards.append(reward)100 101 print(f"[STEP] step={step_num} action={marks} reward={reward:.2f} done={str(done).lower()} error=null", flush=True)102 103 score = round(sum(rewards) / max(len(rewards), 1), 2)104 score = max(0.05, min(0.95, score))105 success = score >= 0.5106 107 except Exception as e:108 if not rewards:109 rewards.append(0.05)110 print(f"[STEP] step={step_num+1} action=error reward=0.05 done=true error={str(e)}", flush=True)111 112 finally:113 rewards_str = ",".join(f"{r:.2f}" for r in rewards) if rewards else "0.05"114 score_clamped = round(max(0.01, min(0.99, score)), 2)115 print(f"[END] success={str(success).lower()} steps={step_num} score={score_clamped} rewards={rewards_str}", flush=True)116 117 return score118 119if __name__ == "__main__":120 for task_id in [1, 2, 3]:121 run_task(task_id)