File size: 3,090 Bytes
2532605
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46c1c8b
 
 
2532605
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46c1c8b
2532605
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46c1c8b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
"""
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  # Circuit name


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")