Pranil Bankar
Deploy Application
4d67ec7
Raw History Blame Contribute Delete
4.68 kB
"""
schemas.py — Pydantic models for FastAPI request/response validation
Defines the complete API contract for the NEET Biology Q&A system.
"""
from pydantic import BaseModel, Field
from typing import Optional
# ==============================
# REQUEST MODELS
# ==============================
class QuestionRequest(BaseModel):
"""Request body for the /qa endpoint."""
question: str = Field(
...,
min_length=5,
max_length=500,
description="The NEET Biology question to answer.",
examples=["What is the role of cofactors in enzyme activity?"],
)
chapter_filter: Optional[str] = Field(
default=None,
description="Optional: manually specify a chapter to filter retrieval. "
"If omitted, BERT classifier auto-detects the chapter.",
examples=["Biomolecules"],
)
top_k: int = Field(
default=5,
ge=1,
le=20,
description="Number of NCERT chunks to retrieve for context.",
)
use_classifier: bool = Field(
default=True,
description="Whether to use the BERT classifier for auto chapter detection.",
)
# ==============================
# RESPONSE MODELS
# ==============================
class TopicInfo(BaseModel):
"""A predicted topic/subtopic from the NCERT syllabus."""
section_code: str = Field(..., description="Section code (e.g., '9.8')")
section_title: str = Field(..., description="Section title (e.g., 'Enzymes')")
similarity: float = Field(..., description="Cosine similarity score (0-1)")
class ClassificationResult(BaseModel):
"""BERT classification output for the question."""
chapter: str = Field(..., description="Predicted NCERT chapter name")
chapter_id: int = Field(..., description="Chapter ID (0-30)")
chapter_confidence: float = Field(..., description="BERT confidence score (0-1)")
topics: list[TopicInfo] = Field(
default=[],
description="Top 1-3 relevant topics/subtopics within the chapter",
)
rejected: bool = Field(default=False, description="True if rejected by OOD gating")
rejection_reason: str = Field(default="", description="Reason for rejection")
entropy: float = Field(default=0.0, description="Normalized entropy of prediction")
margin: float = Field(default=0.0, description="Confidence margin between top-1 and top-2")
class IsNeetBioRequest(BaseModel):
"""Request body for the /is-neet-bio validation endpoint."""
question: str = Field(
...,
min_length=3,
max_length=500,
description="The question to validate."
)
class IsNeetBioResponse(BaseModel):
"""Response indicating whether the query is valid NEET biology."""
is_valid: bool
rejected: bool
reason: str
class SourceChunk(BaseModel):
"""A retrieved NCERT text chunk used as context."""
chapter: Optional[str] = None
section: Optional[str] = None
section_title: Optional[str] = None
text_content: Optional[str] = None
similarity: float = 0.0
class QAResponse(BaseModel):
"""Full response from the Q&A pipeline."""
question: str = Field(..., description="The original question")
classification: Optional[ClassificationResult] = Field(
default=None,
description="BERT classification result (chapter + topics)",
)
answer: str = Field(..., description="Generated answer from NCERT context")
justification: list[str] = Field(
default=[],
description="Step-by-step justification of the answer",
)
sources: list[SourceChunk] = Field(
default=[],
description="Retrieved NCERT chunks used as evidence",
)
confidence: float = Field(
...,
ge=0.0,
le=1.0,
description="Overall confidence score (0-1)",
)
verified: bool = Field(..., description="Whether the answer passed verification")
verifier_note: str = Field(
default="",
description="Explanation from the verifier",
)
class ClassifyOnlyRequest(BaseModel):
"""Request body for the /classify endpoint (no RAG, just classification)."""
question: str = Field(
...,
min_length=5,
max_length=500,
description="The NEET Biology question to classify.",
examples=["What is the role of mitochondria in ATP synthesis?"],
)
class ClassifyOnlyResponse(BaseModel):
"""Response from the /classify endpoint."""
question: str
classification: ClassificationResult
class HealthResponse(BaseModel):
"""Health check response."""
status: str = "ok"
version: str = "1.0.0"
components: dict = {}