SPB Git forge

spb/uqo-chat

Public
14commits 1branches 0releases
1.4 MBsize
maindefault branch
17 days agolast push
Python 64.6% TypeScript 33.7% CSS 0.8%
2.8 KB · 71 lines python
Raw Blame History
1from __future__ import annotations23from typing import Any45from fastapi import APIRouter, Depends, HTTPException, status6from pydantic import BaseModel78from app.core.security import AuthUser, get_current_user, hash_user_id9from app.db import SessionLocal10from app.models import Quiz, QuizAttempt11from app.services import analytics1213router = APIRouter(tags=["quiz"])141516class AnswersReq(BaseModel):17    answers: dict[str, Any]181920def _grade(q: dict[str, Any], given: Any) -> bool:21    t = q["type"]22    try:23        if t == "mcq":24            return int(given) == int(q["answer"])25        if t == "true_false":26            g = given if isinstance(given, bool) else str(given).lower() in {"true", "vrai", "1"}27            return g == bool(q["answer"])28        if t == "numeric":29            val = float(str(given).replace(" ", "").replace(",", ".").replace("$", "").replace("%", ""))30            ans = float(q["answer"])31            tol = float(q.get("tolerance", 0.02))32            return abs(val - ans) <= max(abs(ans) * tol, 1e-9)33    except (TypeError, ValueError):34        return False35    return False363738@router.get("/quiz/{quiz_id}")39async def get_quiz(quiz_id: str, auth: AuthUser = Depends(get_current_user)) -> dict:40    async with SessionLocal() as session:41        quiz = await session.get(Quiz, quiz_id)42    if not quiz or quiz.user_id != auth.id:43        raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Quiz introuvable.")44    payload = dict(quiz.payload)45    payload["questions"] = [{k: v for k, v in q.items() if k not in {"answer", "explanation"}}46                            for q in payload.get("questions", [])]47    return payload484950@router.post("/quiz/{quiz_id}/answers")51async def submit(quiz_id: str, req: AnswersReq, auth: AuthUser = Depends(get_current_user)) -> dict:52    async with SessionLocal() as session:53        quiz = await session.get(Quiz, quiz_id)54        if not quiz or quiz.user_id != auth.id:55            raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Quiz introuvable.")56        questions = quiz.payload.get("questions", [])57        results = []58        correct = 059        for q in questions:60            given = req.answers.get(q["id"])61            ok = _grade(q, given) if given is not None else False62            correct += int(ok)63            results.append({"id": q["id"], "correct": ok, "given": given,64                            "answer": q["answer"], "explanation": q.get("explanation", ""),65                            "unit": q.get("unit", "")})66        score = correct / len(questions) if questions else 0.067        session.add(QuizAttempt(quiz_id=quiz_id, answers=req.answers, score=score))68        await session.commit()69    await analytics.record_event(hash_user_id(auth.id), quiz.course_code, "quiz", quiz.topic)70    return {"score": score, "correct": correct, "total": len(questions), "results": results}71