Abhilater
fix: fix missing return GradeResponse and indentation in main.py
32085f9
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
from env.environment import SchoolInterventionEnv
from env.models import (
StepRequest, StepResponse, ResetResponse,
Observation, GradeResponse, GradeRequest, TaskListResponse, EnvInfo,
)
from env.tasks import list_tasks
from env.graders import grade
env = SchoolInterventionEnv()
@asynccontextmanager
async def lifespan(app: FastAPI):
env.reset()
yield
app = FastAPI(
title="School AI Intervention Environment",
description="OpenEnv-compliant RL environment for student intervention.",
version="2.2.2",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
@app.post("/reset", response_model=ResetResponse)
def reset():
obs = env.reset()
return ResetResponse(observation=Observation(**obs))
@app.post("/step", response_model=StepResponse)
def step(request: StepRequest):
try:
obs, reward, done, info = env.step(request.action.value)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
return StepResponse(
observation=Observation(**obs),
reward=reward,
done=done,
info=info,
)
@app.get("/state", response_model=Observation)
def state():
return Observation(**env.state())
@app.get("/tasks", response_model=TaskListResponse)
def get_tasks():
return TaskListResponse(tasks=list(list_tasks().values()))
@app.post("/grade/{task_name}", response_model=GradeResponse)
def grade_state(task_name: str, request: GradeRequest = None):
if task_name not in ["easy", "medium", "hard"]:
raise HTTPException(status_code=400, detail=f"Unknown task '{task_name}'")
# Use provided state if given, otherwise use current env state
if request and any(getattr(request, field) is not None for field in ['attendance', 'performance', 'stress_level', 'risk_score']):
state_to_grade = {
"student_id": request.student_id if request.student_id is not None else 0,
"attendance": float(request.attendance) if request.attendance is not None else env.state()["attendance"],
"performance": float(request.performance) if request.performance is not None else env.state()["performance"],
"stress_level": float(request.stress_level) if request.stress_level is not None else env.state()["stress_level"],
"risk_score": float(request.risk_score) if request.risk_score is not None else env.state()["risk_score"],
"week": request.week if request.week is not None else env.state()["week"],
}
else:
state_to_grade = env.state()
result = grade(task_name, state_to_grade)
# Use exact range as allowed by Pydantic (ge=0.0, le=1.0)
safe_score = round(min(1.0, max(0.0, float(result["score"]))), 4)
return GradeResponse(
task=result["task"],
score=safe_score,
passed=result["passed"],
breakdown=result["breakdown"],
)
@app.get("/info", response_model=EnvInfo)
def env_info():
return EnvInfo(
name="school-intervention-env",
version="2.2.2",
description="Simulate student intervention decisions.",
action_space=SchoolInterventionEnv.ACTIONS,
observation_keys=["student_id", "attendance", "performance", "stress_level", "risk_score", "week"],
max_steps=SchoolInterventionEnv.MAX_STEPS,
tasks=["easy", "medium", "hard"],
)
@app.get("/health")
def health():
return {"status": "ok", "environment": "school-intervention-env"}
@app.get("/logs-container")
def logs_container():
return {"logs": "Application running normally"}