"""Pydantic schemas for knowledge graph endpoints.""" from pydantic import BaseModel, ConfigDict, Field class LONode(BaseModel): """A learning outcome node in the knowledge graph.""" lo_id: str = Field(..., description="Learning outcome ID") title: str = Field(..., description="Learning outcome title") grade: int = Field(..., ge=6, le=8, description="Grade level") subject: str = Field(..., description="Subject name") chapter: str = Field(..., description="Chapter name") difficulty: str = Field(..., description="Difficulty level") bloom_level: str = Field(..., description="Bloom taxonomy level") class LORelationship(BaseModel): """A relationship between learning outcomes.""" from_lo_id: str = Field(..., description="Source learning outcome ID") to_lo_id: str = Field(..., description="Target learning outcome ID") relationship_type: str = Field(..., description="Type of relationship") strength: float = Field(..., ge=0.0, le=1.0, description="Relationship strength") class KnowledgeGraphResponse(BaseModel): """Response for knowledge graph queries.""" model_config = ConfigDict(extra="forbid") lo_id: str = Field(..., description="Queried learning outcome ID") source: str = Field(default="knowledge_graph", description="Data source") timestamp: str = Field(..., description="Response timestamp") # Core LO information lo_info: LONode = Field(..., description="Learning outcome details") # Graph relationships prerequisites: list[LONode] = Field(default_factory=list, description="Prerequisite learning outcomes") successors: list[LONode] = Field(default_factory=list, description="Dependent learning outcomes") # Metadata prerequisite_count: int = Field(..., ge=0, description="Number of prerequisites") successor_count: int = Field(..., ge=0, description="Number of successors") depth_from_root: int = Field(..., ge=0, description="Depth in dependency chain") class KnowledgeGraphRequest(BaseModel): """Request for knowledge graph queries.""" model_config = ConfigDict(extra="forbid") lo_id: str = Field(..., description="Learning outcome ID to query") include_prerequisites: bool = Field(default=True, description="Include prerequisite LOs") include_successors: bool = Field(default=True, description="Include successor LOs") max_depth: int = Field(default=2, ge=1, le=5, description="Maximum depth to traverse")