File size: 5,255 Bytes
f381be8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
115
116
117
118
119
120
121
122
123
124
125
126
"""
api.schemas
===========
Pydantic models for request / response validation.
"""

from __future__ import annotations

from pydantic import BaseModel, Field
from typing import Optional


# ── Prediction ───────────────────────────────────────────────────────────────
class PredictRequest(BaseModel):
    """Request body for single-cycle prediction."""
    battery_id: str = Field(..., description="Battery identifier, e.g. 'B0005'")
    cycle_number: int = Field(..., ge=1, description="Current cycle number")
    ambient_temperature: float = Field(default=24.0, description="Ambient temperature (Β°C)")
    peak_voltage: float = Field(default=4.19, description="Peak charge voltage (V)")
    min_voltage: float = Field(default=2.61, description="Discharge cutoff voltage (V)")
    avg_current: float = Field(default=1.82, description="Average discharge current (A)")
    avg_temp: float = Field(default=32.6, description="Average cell temperature (Β°C) β€” typically higher than ambient")
    temp_rise: float = Field(default=14.7, description="Temperature rise during cycle (Β°C) β€” NASA dataset mean β‰ˆ 15Β°C")
    cycle_duration: float = Field(default=3690.0, description="Cycle duration (seconds)")
    Re: float = Field(default=0.045, description="Electrolyte resistance (Ξ©) β€” training range 0.027–0.156")
    Rct: float = Field(default=0.069, description="Charge transfer resistance (Ξ©) β€” training range 0.04–0.27")
    delta_capacity: float = Field(default=-0.005, description="Capacity change from last cycle (Ah)")


class PredictResponse(BaseModel):
    """Response body for a prediction."""
    battery_id: str
    cycle_number: int
    soh_pct: float = Field(..., description="Predicted State of Health (%)")
    rul_cycles: Optional[float] = Field(None, description="Predicted Remaining Useful Life (cycles)")
    degradation_state: str = Field(..., description="Degradation state label")
    confidence_lower: Optional[float] = None
    confidence_upper: Optional[float] = None
    model_used: str = Field(..., description="Name of the model that produced the prediction")
    model_version: Optional[str] = Field(None, description="Semantic version of the model used")


# ── Batch Prediction ─────────────────────────────────────────────────────────
class BatchPredictRequest(BaseModel):
    """Batch prediction for multiple cycles of one battery."""
    battery_id: str
    cycles: list[dict] = Field(..., description="List of cycle feature dicts")


class BatchPredictResponse(BaseModel):
    """Batch prediction response."""
    battery_id: str
    predictions: list[PredictResponse]


# ── Recommendation ───────────────────────────────────────────────────────────
class RecommendationRequest(BaseModel):
    """Request for operational recommendations."""
    battery_id: str
    current_cycle: int = Field(..., ge=1)
    current_soh: float = Field(..., ge=0, le=100)
    ambient_temperature: float = Field(default=24.0)
    top_k: int = Field(default=5, ge=1, le=20)


class SingleRecommendation(BaseModel):
    """One recommendation entry."""
    rank: int
    ambient_temperature: float
    discharge_current: float
    cutoff_voltage: float
    predicted_rul: float
    rul_improvement: float
    rul_improvement_pct: float
    explanation: str


class RecommendationResponse(BaseModel):
    """Response with ranked recommendations."""
    battery_id: str
    current_soh: float
    recommendations: list[SingleRecommendation]


# ── Model info ───────────────────────────────────────────────────────────────
class ModelInfo(BaseModel):
    """Info about a registered model."""
    name: str
    version: Optional[str] = None
    display_name: Optional[str] = None
    family: str
    algorithm: Optional[str] = None
    target: str
    r2: Optional[float] = None
    metrics: dict[str, float]
    is_default: bool = False
    loaded: bool = True
    load_error: Optional[str] = None


class HealthResponse(BaseModel):
    """Health check response."""
    status: str = "ok"
    version: str
    models_loaded: int
    device: str


# ── Visualization ────────────────────────────────────────────────────────────
class BatteryVizData(BaseModel):
    """Data for 3D battery visualization."""
    battery_id: str
    soh_pct: float
    temperature: float
    cycle_number: int
    degradation_state: str
    color_hex: str = Field(..., description="Color hex code for SOH heatmap")


class DashboardData(BaseModel):
    """Full dashboard payload."""
    batteries: list[BatteryVizData]
    capacity_fade: dict[str, list[float]]
    model_metrics: dict[str, dict[str, float]]
    best_model: str