| """ |
| KRONECTOR API — Pydantic schemas for request/response validation. |
| """ |
|
|
| from typing import Any, Optional |
|
|
| from pydantic import BaseModel, Field |
|
|
|
|
| class PredictionRequest(BaseModel): |
| """Natural language query for F1 prediction.""" |
|
|
| query: str = Field( |
| ..., |
| min_length=3, |
| max_length=500, |
| examples=["What's Max's win probability at Monaco 2023?"], |
| ) |
| crashed_in_quali: bool = Field( |
| False, description="Manually flag if the driver crashed in qualifying" |
| ) |
|
|
|
|
| class PredictionMetadata(BaseModel): |
| """Metadata about the predicted race/driver.""" |
|
|
| season: int |
| round: int |
| driver_id: str |
| driver_name: str |
| team: str |
| grid_position: float |
|
|
|
|
| class PredictionResponse(BaseModel): |
| """Win probability prediction with SHAP explanations.""" |
|
|
| win_probability: float = Field( |
| ..., ge=0, le=100, description="Win probability as a percentage (0-100)" |
| ) |
| metadata: PredictionMetadata |
| shap_values: Optional[dict[str, float]] = Field( |
| None, description="SHAP feature importance dict" |
| ) |
| llm_explanation: Optional[str] = Field( |
| None, description="Natural language explanation from Llama3" |
| ) |
| confidence_rating: Optional[str] = Field( |
| None, description="CritiqueAgent's confidence evaluation" |
| ) |
|
|
|
|
| class DriverInfo(BaseModel): |
| """Driver summary info.""" |
|
|
| driver_id: str |
| driver_name: str |
| team: Optional[str] = None |
|
|
|
|
| class RaceInfo(BaseModel): |
| """Race summary info.""" |
|
|
| season: int |
| round: int |
| name: str |
|
|
|
|
| class HealthResponse(BaseModel): |
| """System health status.""" |
|
|
| status: str = Field(..., examples=["healthy"]) |
| model_loaded: bool |
| data_available: bool |
| version: str = "1.0.0" |
|
|
|
|
| class ErrorResponse(BaseModel): |
| """Standard error response.""" |
|
|
| detail: str |
| error_code: str = Field(..., examples=["INVALID_QUERY", "MODEL_NOT_LOADED"]) |
|
|
|
|
| class CompareRequest(BaseModel): |
| """Request for Head-to-Head Driver Comparison.""" |
|
|
| driver1: str = Field( |
| ..., |
| examples=["Max Verstappen", "VER"], |
| description="First driver to compare (name or 3-letter code)" |
| ) |
| driver2: str = Field( |
| ..., |
| examples=["Kimi Antonelli", "ANT"], |
| description="Second driver to compare (name or 3-letter code)" |
| ) |
| season: Optional[int] = Field(None, description="Optional year (defaults to latest available)") |
| round: Optional[int] = Field(None, description="Optional round number (defaults to latest available)") |
|
|
|
|
| class CompareResponse(BaseModel): |
| """Head-to-Head Comparison Response.""" |
|
|
| driver1: PredictionMetadata |
| driver2: PredictionMetadata |
| driver1_win_probability: float |
| driver2_win_probability: float |
| shap_deltas: dict[str, float] = Field( |
| ..., |
| description="Mathematical difference between driver 1 and driver 2 SHAP values (positive means driver 1 has the edge, negative means driver 2 has the edge)" |
| ) |
| llm_analysis: str = Field(..., description="Groq's Head-to-Head tale of the tape") |
|
|