Spaces:
Sleeping
Sleeping
Commit ·
1552b5a
1
Parent(s): 4229df6
feat: HF model repo at v1/v2 root; version selector UI with download submenu; artifacts/ out of git
Browse files- .gitignore +3 -18
- Dockerfile +1 -2
- api/main.py +64 -1
- artifacts/v1/results/classical_rul_results.csv +0 -4
- artifacts/v1/results/classical_soh_results.csv +0 -11
- artifacts/v1/results/dg_itransformer_results.json +0 -9
- artifacts/v1/results/ensemble_results.csv +0 -9
- artifacts/v1/results/final_rankings.csv +0 -23
- artifacts/v1/results/lstm_soh_results.csv +0 -5
- artifacts/v1/results/transformer_soh_results.csv +0 -5
- artifacts/v1/results/unified_results.csv +0 -23
- artifacts/v1/results/vae_lstm_results.json +0 -8
- artifacts/v2/results/battery_features.csv +0 -0
- artifacts/v2/results/classical_rul_results.csv +0 -4
- artifacts/v2/results/classical_soh_results.csv +0 -11
- artifacts/v2/results/dg_itransformer_results.json +0 -9
- artifacts/v2/results/ensemble_results.csv +0 -9
- artifacts/v2/results/final_rankings.csv +0 -23
- artifacts/v2/results/lstm_soh_results.csv +0 -5
- artifacts/v2/results/transformer_soh_results.csv +0 -5
- artifacts/v2/results/unified_results.csv +0 -23
- artifacts/v2/results/v2_classical_results.csv +0 -9
- artifacts/v2/results/v2_intra_battery.json +0 -9
- artifacts/v2/results/v2_model_validation.csv +0 -17
- artifacts/v2/results/v2_training_summary.json +0 -14
- artifacts/v2/results/v2_validation_report.html +0 -0
- artifacts/v2/results/v2_validation_summary.json +0 -11
- artifacts/v2/results/vae_lstm_results.json +0 -8
- frontend/src/App.tsx +6 -18
- frontend/src/api.ts +15 -0
- frontend/src/components/VersionSelector.tsx +220 -0
- scripts/download_models.py +91 -50
- scripts/upload_models_to_hub.py +21 -7
.gitignore
CHANGED
|
@@ -1,23 +1,8 @@
|
|
| 1 |
# ─────────────────────────────────────────────────────────────────────────────
|
| 2 |
-
#
|
|
|
|
| 3 |
# ─────────────────────────────────────────────────────────────────────────────
|
| 4 |
-
artifacts/
|
| 5 |
-
artifacts/v2/figures/
|
| 6 |
-
artifacts/v2/reports/
|
| 7 |
-
artifacts/v2/results/*.npz
|
| 8 |
-
artifacts/v2/results/*.png
|
| 9 |
-
notebooks/
|
| 10 |
-
# ─────────────────────────────────────────────────────────────────────────────
|
| 11 |
-
# Model artifacts — stored on HF Hub, NOT in git
|
| 12 |
-
# Download via: python scripts/download_models.py
|
| 13 |
-
# or automatically on Docker startup
|
| 14 |
-
# ─────────────────────────────────────────────────────────────────────────────
|
| 15 |
-
artifacts/v1/models/
|
| 16 |
-
artifacts/v2/models/
|
| 17 |
-
artifacts/v1/scalers/
|
| 18 |
-
artifacts/v2/scalers/
|
| 19 |
-
# Sentinel written by download_models.py
|
| 20 |
-
artifacts/.hf_downloaded
|
| 21 |
|
| 22 |
# Python
|
| 23 |
__pycache__/
|
|
|
|
| 1 |
# ─────────────────────────────────────────────────────────────────────────────
|
| 2 |
+
# Entire artifacts/ lives on HF Hub model repo (NeerajCodz/aiBatteryLifeCycle)
|
| 3 |
+
# Downloaded at Docker startup via scripts/download_models.py
|
| 4 |
# ─────────────────────────────────────────────────────────────────────────────
|
| 5 |
+
artifacts/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
# Python
|
| 8 |
__pycache__/
|
Dockerfile
CHANGED
|
@@ -43,12 +43,11 @@ RUN mkdir -p artifacts/v1/models/classical artifacts/v1/models/deep \
|
|
| 43 |
artifacts/v2/scalers artifacts/v2/results artifacts/v2/reports \
|
| 44 |
artifacts/logs
|
| 45 |
|
| 46 |
-
# Copy project source
|
| 47 |
COPY src/ src/
|
| 48 |
COPY api/ api/
|
| 49 |
COPY scripts/ scripts/
|
| 50 |
COPY cleaned_dataset/ cleaned_dataset/
|
| 51 |
-
COPY artifacts/ artifacts/
|
| 52 |
|
| 53 |
# Copy built frontend
|
| 54 |
COPY --from=frontend-build /app/frontend/dist frontend/dist
|
|
|
|
| 43 |
artifacts/v2/scalers artifacts/v2/results artifacts/v2/reports \
|
| 44 |
artifacts/logs
|
| 45 |
|
| 46 |
+
# Copy project source (artifacts/ is NOT in git — downloaded at runtime)
|
| 47 |
COPY src/ src/
|
| 48 |
COPY api/ api/
|
| 49 |
COPY scripts/ scripts/
|
| 50 |
COPY cleaned_dataset/ cleaned_dataset/
|
|
|
|
| 51 |
|
| 52 |
# Copy built frontend
|
| 53 |
COPY --from=frontend-build /app/frontend/dist frontend/dist
|
api/main.py
CHANGED
|
@@ -42,10 +42,11 @@ Docker
|
|
| 42 |
|
| 43 |
from __future__ import annotations
|
| 44 |
|
|
|
|
| 45 |
from contextlib import asynccontextmanager
|
| 46 |
from pathlib import Path
|
| 47 |
|
| 48 |
-
from fastapi import FastAPI
|
| 49 |
from fastapi.middleware.cors import CORSMiddleware
|
| 50 |
from fastapi.staticfiles import StaticFiles
|
| 51 |
from fastapi.responses import FileResponse
|
|
@@ -110,6 +111,68 @@ async def health():
|
|
| 110 |
)
|
| 111 |
|
| 112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
# ── Include routers ──────────────────────────────────────────────────────────
|
| 114 |
from api.routers.predict import router as predict_router, v1_router
|
| 115 |
from api.routers.predict_v2 import router as predict_v2_router
|
|
|
|
| 42 |
|
| 43 |
from __future__ import annotations
|
| 44 |
|
| 45 |
+
import asyncio
|
| 46 |
from contextlib import asynccontextmanager
|
| 47 |
from pathlib import Path
|
| 48 |
|
| 49 |
+
from fastapi import BackgroundTasks, FastAPI, HTTPException
|
| 50 |
from fastapi.middleware.cors import CORSMiddleware
|
| 51 |
from fastapi.staticfiles import StaticFiles
|
| 52 |
from fastapi.responses import FileResponse
|
|
|
|
| 111 |
)
|
| 112 |
|
| 113 |
|
| 114 |
+
# ── Version management ───────────────────────────────────────────────────────
|
| 115 |
+
_REGISTRIES = {"v1": registry_v1, "v2": registry_v2}
|
| 116 |
+
_version_status: dict[str, str] = {} # "downloading" | "ready" | "error"
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
def _artifacts_dir() -> Path:
|
| 120 |
+
return Path(__file__).resolve().parent.parent / "artifacts"
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def _version_loaded(version: str) -> bool:
|
| 124 |
+
base = _artifacts_dir() / version / "models" / "classical"
|
| 125 |
+
return any(base.glob("*.joblib")) if base.exists() else False
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
@app.get("/api/versions", tags=["meta"])
|
| 129 |
+
async def list_versions():
|
| 130 |
+
"""Return all known versions with loaded / downloading status."""
|
| 131 |
+
return [
|
| 132 |
+
{
|
| 133 |
+
"id": v,
|
| 134 |
+
"display": f"Version {v[1]}",
|
| 135 |
+
"loaded": _version_loaded(v),
|
| 136 |
+
"model_count": _REGISTRIES[v].model_count,
|
| 137 |
+
"status": _version_status.get(v, "ready" if _version_loaded(v) else "not_downloaded"),
|
| 138 |
+
}
|
| 139 |
+
for v in ["v2", "v1"]
|
| 140 |
+
]
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
async def _bg_load_version(version: str) -> None:
|
| 144 |
+
import subprocess, sys as _sys
|
| 145 |
+
try:
|
| 146 |
+
proc = await asyncio.create_subprocess_exec(
|
| 147 |
+
_sys.executable, "scripts/download_models.py", "--version", version,
|
| 148 |
+
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT,
|
| 149 |
+
)
|
| 150 |
+
await proc.wait()
|
| 151 |
+
if proc.returncode == 0:
|
| 152 |
+
_REGISTRIES[version].load_all()
|
| 153 |
+
_version_status[version] = "ready"
|
| 154 |
+
log.info("Version %s loaded on demand — %d models", version,
|
| 155 |
+
_REGISTRIES[version].model_count)
|
| 156 |
+
else:
|
| 157 |
+
_version_status[version] = "error"
|
| 158 |
+
log.error("download_models.py failed for version %s", version)
|
| 159 |
+
except Exception as exc:
|
| 160 |
+
_version_status[version] = "error"
|
| 161 |
+
log.error("Failed to load version %s: %s", version, exc)
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
@app.post("/api/versions/{version}/load", tags=["meta"])
|
| 165 |
+
async def load_version(version: str, background_tasks: BackgroundTasks):
|
| 166 |
+
"""Download + activate a model version from HF Hub (runs in background)."""
|
| 167 |
+
if version not in _REGISTRIES:
|
| 168 |
+
raise HTTPException(status_code=400, detail=f"Unknown version '{version}'")
|
| 169 |
+
if _version_status.get(version) == "downloading":
|
| 170 |
+
return {"status": "downloading", "version": version}
|
| 171 |
+
_version_status[version] = "downloading"
|
| 172 |
+
background_tasks.add_task(_bg_load_version, version)
|
| 173 |
+
return {"status": "downloading", "version": version}
|
| 174 |
+
|
| 175 |
+
|
| 176 |
# ── Include routers ──────────────────────────────────────────────────────────
|
| 177 |
from api.routers.predict import router as predict_router, v1_router
|
| 178 |
from api.routers.predict_v2 import router as predict_v2_router
|
artifacts/v1/results/classical_rul_results.csv
DELETED
|
@@ -1,4 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tolerance_acc_5cyc
|
| 2 |
-
RandomForest,8.942333980582523,137.23446964660195,11.714711675777682,-0.15748641443851108,120.88277153106779,0.4058252427184466
|
| 3 |
-
XGBoost,6.7578043937683105,74.80780029296875,8.649150264214905,0.3690432906150818,90.60895087232073,0.429126213592233
|
| 4 |
-
LightGBM,9.174716686966466,125.80377799208308,11.216228331845027,-0.06107572161612751,112.25501529299473,0.35145631067961164
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v1/results/classical_soh_results.csv
DELETED
|
@@ -1,11 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tolerance_acc_2pct
|
| 2 |
-
RandomForest,4.78051739475878,41.771168089034525,6.463061819991708,0.956679157080545,28.807727531282236,0.29514563106796116
|
| 3 |
-
LightGBM,6.909989455704782,89.23030742727897,9.446179514876846,0.9074593240133356,56.94413475231037,0.24854368932038834
|
| 4 |
-
XGBoost,8.506303251021016,136.22476526016746,11.67153654238239,0.8587214117403497,72.81562821369698,0.22330097087378642
|
| 5 |
-
SVR,7.562130215902278,187.88576938734298,13.707143006014892,0.805143828272144,97.82839183781172,0.32233009708737864
|
| 6 |
-
KNN-10,11.665738368704334,265.7682207905257,16.302399234177948,0.7243720041223407,89.92209971367193,0.26019417475728157
|
| 7 |
-
KNN-5,11.751580021863887,270.3768092061512,16.44313866651228,0.7195924409938166,88.41470284019084,0.2757281553398058
|
| 8 |
-
KNN-20,12.035078655061884,272.741740151536,16.514894494108525,0.71713977312056,101.98653839713165,0.2407766990291262
|
| 9 |
-
ElasticNet,15.796038594619795,460.3763913475375,21.45638346384445,0.5225440358554927,144.4728811908027,0.06407766990291262
|
| 10 |
-
Lasso,15.830927911593506,462.77574982037044,21.512223265398916,0.5200556632227833,145.46522399976544,0.05242718446601942
|
| 11 |
-
Ridge,15.860549029501184,464.1921925903698,21.545119925179574,0.5185866716299998,145.65718178268125,0.05048543689320388
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v1/results/dg_itransformer_results.json
DELETED
|
@@ -1,9 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"MAE": 12.886456320718098,
|
| 3 |
-
"MSE": 323.38418900793243,
|
| 4 |
-
"RMSE": 17.982886003306934,
|
| 5 |
-
"R2": 0.12310012848141882,
|
| 6 |
-
"MAPE": 69.98234771512423,
|
| 7 |
-
"tol_2pct": 0.04827586206896552,
|
| 8 |
-
"tol_5pct": 0.2896551724137931
|
| 9 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v1/results/ensemble_results.csv
DELETED
|
@@ -1,9 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tol_2pct
|
| 2 |
-
Weighted Avg Ensemble,3.737822790616429,37.739016006374186,6.1432089339671805,0.8976655649469139,5.478476687258817,0.3482758620689655
|
| 3 |
-
tft,4.732738753085752,46.68825874782447,6.832880706394959,0.8733984854887593,7.499287950788588,0.21379310344827587
|
| 4 |
-
Stacking Ensemble,5.76908337148985,60.03540223313905,7.7482515597481125,0.8372059046352616,10.924057540803656,0.12413793103448276
|
| 5 |
-
vae_lstm,8.494939970437716,100.78674732190278,10.039260297546965,0.7267031327397879,14.250142040133243,0.09310344827586207
|
| 6 |
-
batterygpt,8.020673063309337,129.06954589210812,11.360877866261397,0.6500105074494692,12.874349389916773,0.28620689655172415
|
| 7 |
-
vanilla_lstm,10.561354979478219,155.95773910638056,12.488304092485118,0.5770995427937917,14.375050332959946,0.15862068965517243
|
| 8 |
-
bidirectional_lstm,11.134867385317946,167.3343794115467,12.935779041540046,0.5462502472468515,17.124593156141298,0.10689655172413794
|
| 9 |
-
attention_lstm,14.181327172488002,288.23989200564256,16.977629163273726,0.21839863277892768,24.827876450140888,0.15862068965517243
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v1/results/final_rankings.csv
DELETED
|
@@ -1,23 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tolerance_acc_2pct,tol_2pct,tol_5pct
|
| 2 |
-
RandomForest,4.78051739475878,41.771168089034525,6.463061819991708,0.956679157080545,28.80772753128224,0.2951456310679611,,
|
| 3 |
-
LightGBM,6.909989455704782,89.23030742727897,9.446179514876846,0.9074593240133356,56.94413475231037,0.2485436893203883,,
|
| 4 |
-
Weighted Avg Ensemble,3.737822790616429,37.739016006374186,6.1432089339671805,0.8976655649469139,5.478476687258817,,0.3482758620689655,
|
| 5 |
-
TFT,4.732738753085752,46.68825874782447,6.832880706394959,0.8733984854887593,7.499287950788588,,0.2137931034482758,
|
| 6 |
-
XGBoost,8.506303251021016,136.22476526016746,11.67153654238239,0.8587214117403497,72.81562821369698,0.2233009708737864,,
|
| 7 |
-
Stacking Ensemble,5.76908337148985,60.03540223313905,7.748251559748112,0.8372059046352616,10.924057540803656,,0.1241379310344827,
|
| 8 |
-
SVR,7.562130215902278,187.88576938734295,13.707143006014892,0.805143828272144,97.82839183781172,0.3223300970873786,,
|
| 9 |
-
VAE-LSTM,8.494939970437716,100.78674732190278,10.039260297546965,0.7267031327397879,14.250142040133243,,0.09310344827586207,
|
| 10 |
-
KNN-10,11.665738368704334,265.7682207905257,16.302399234177948,0.7243720041223407,89.92209971367193,0.2601941747572815,,
|
| 11 |
-
KNN-5,11.751580021863887,270.3768092061512,16.44313866651228,0.7195924409938166,88.41470284019084,0.2757281553398058,,
|
| 12 |
-
KNN-20,12.035078655061884,272.741740151536,16.514894494108525,0.71713977312056,101.98653839713164,0.2407766990291262,,
|
| 13 |
-
BatteryGPT,8.020673063309337,129.06954589210812,11.360877866261395,0.6500105074494692,12.874349389916771,,0.2862068965517241,
|
| 14 |
-
GRU,9.275809104339835,134.65458890701777,11.604076391812397,0.6348659095727935,15.248492181524448,0.193103448275862,,
|
| 15 |
-
Vanilla LSTM,10.56135497947822,155.95773910638056,12.488304092485118,0.5770995427937917,14.375050332959946,0.1586206896551724,,
|
| 16 |
-
Bidirectional LSTM,11.134867385317946,167.3343794115467,12.935779041540046,0.5462502472468515,17.124593156141298,0.1068965517241379,,
|
| 17 |
-
ElasticNet,15.796038594619796,460.3763913475375,21.45638346384445,0.5225440358554927,144.4728811908027,0.0640776699029126,,
|
| 18 |
-
Lasso,15.830927911593506,462.7757498203704,21.51222326539892,0.5200556632227833,145.46522399976544,0.0524271844660194,,
|
| 19 |
-
Ridge,15.860549029501184,464.1921925903698,21.545119925179574,0.5185866716299998,145.65718178268125,0.0504854368932038,,
|
| 20 |
-
iTransformer,14.544141949115827,275.09890344946007,16.58610573490535,0.2540321967199925,73.33406651321724,,0.0172413793103448,
|
| 21 |
-
Attention LSTM,14.181327172488002,288.23989200564256,16.977629163273726,0.2183986327789276,24.827876450140888,0.1586206896551724,,
|
| 22 |
-
DG-iTransformer,14.183794754173379,313.5635374005159,17.707725359303375,0.1497301506825386,94.26231665878274,,0.1103448275862069,0.2
|
| 23 |
-
Physics iTransformer,16.41156271618159,379.65023683665015,19.48461538847124,-0.0294728537142276,97.60205959509742,,0.0,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v1/results/lstm_soh_results.csv
DELETED
|
@@ -1,5 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tolerance_acc_2pct
|
| 2 |
-
GRU,9.275809104339837,134.65458890701777,11.604076391812395,0.6348659095727935,15.248492181524448,0.19310344827586207
|
| 3 |
-
Vanilla LSTM,10.561354979478219,155.95773910638056,12.488304092485118,0.5770995427937917,14.375050332959946,0.15862068965517243
|
| 4 |
-
Bidirectional LSTM,11.134867385317946,167.3343794115467,12.935779041540046,0.5462502472468515,17.124593156141298,0.10689655172413794
|
| 5 |
-
Attention LSTM,14.181327172488002,288.23989200564256,16.977629163273726,0.21839863277892768,24.827876450140888,0.15862068965517243
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v1/results/transformer_soh_results.csv
DELETED
|
@@ -1,5 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tol_2pct
|
| 2 |
-
TFT,9.538144323660262,127.31655440584875,11.283463759229644,0.6547639804432781,18.98017853690174,0.05517241379310345
|
| 3 |
-
BatteryGPT,9.614953606189902,135.34729964687295,11.633885836076997,0.6329875309153767,15.44417472623618,0.1793103448275862
|
| 4 |
-
iTransformer,9.356759048993766,150.35062176683638,12.261754432659153,0.5923039981808029,14.4907916127095,0.1310344827586207
|
| 5 |
-
Physics iTransformer,12.1375468649355,214.65431642999653,14.651085844741901,0.4179358518552816,24.985288391381786,0.07931034482758621
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v1/results/unified_results.csv
DELETED
|
@@ -1,23 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tolerance_acc_2pct,tol_2pct,tol_5pct
|
| 2 |
-
RandomForest,4.78051739475878,41.771168089034525,6.463061819991708,0.956679157080545,28.80772753128224,0.2951456310679611,,
|
| 3 |
-
LightGBM,6.909989455704782,89.23030742727897,9.446179514876846,0.9074593240133356,56.94413475231037,0.2485436893203883,,
|
| 4 |
-
Weighted Avg Ensemble,3.737822790616429,37.739016006374186,6.1432089339671805,0.8976655649469139,5.478476687258817,,0.3482758620689655,
|
| 5 |
-
TFT,4.732738753085752,46.68825874782447,6.832880706394959,0.8733984854887593,7.499287950788588,,0.2137931034482758,
|
| 6 |
-
XGBoost,8.506303251021016,136.22476526016746,11.67153654238239,0.8587214117403497,72.81562821369698,0.2233009708737864,,
|
| 7 |
-
Stacking Ensemble,5.76908337148985,60.03540223313905,7.748251559748112,0.8372059046352616,10.924057540803656,,0.1241379310344827,
|
| 8 |
-
SVR,7.562130215902278,187.88576938734295,13.707143006014892,0.805143828272144,97.82839183781172,0.3223300970873786,,
|
| 9 |
-
VAE-LSTM,8.494939970437716,100.78674732190278,10.039260297546965,0.7267031327397879,14.250142040133243,,0.09310344827586207,
|
| 10 |
-
KNN-10,11.665738368704334,265.7682207905257,16.302399234177948,0.7243720041223407,89.92209971367193,0.2601941747572815,,
|
| 11 |
-
KNN-5,11.751580021863887,270.3768092061512,16.44313866651228,0.7195924409938166,88.41470284019084,0.2757281553398058,,
|
| 12 |
-
KNN-20,12.035078655061884,272.741740151536,16.514894494108525,0.71713977312056,101.98653839713164,0.2407766990291262,,
|
| 13 |
-
BatteryGPT,8.020673063309337,129.06954589210812,11.360877866261395,0.6500105074494692,12.874349389916771,,0.2862068965517241,
|
| 14 |
-
GRU,9.275809104339835,134.65458890701777,11.604076391812397,0.6348659095727935,15.248492181524448,0.193103448275862,,
|
| 15 |
-
Vanilla LSTM,10.56135497947822,155.95773910638056,12.488304092485118,0.5770995427937917,14.375050332959946,0.1586206896551724,,
|
| 16 |
-
Bidirectional LSTM,11.134867385317946,167.3343794115467,12.935779041540046,0.5462502472468515,17.124593156141298,0.1068965517241379,,
|
| 17 |
-
ElasticNet,15.796038594619796,460.3763913475375,21.45638346384445,0.5225440358554927,144.4728811908027,0.0640776699029126,,
|
| 18 |
-
Lasso,15.830927911593506,462.7757498203704,21.51222326539892,0.5200556632227833,145.46522399976544,0.0524271844660194,,
|
| 19 |
-
Ridge,15.860549029501184,464.1921925903698,21.545119925179574,0.5185866716299998,145.65718178268125,0.0504854368932038,,
|
| 20 |
-
iTransformer,14.544141949115827,275.09890344946007,16.58610573490535,0.2540321967199925,73.33406651321724,,0.0172413793103448,
|
| 21 |
-
Attention LSTM,14.181327172488002,288.23989200564256,16.977629163273726,0.2183986327789276,24.827876450140888,0.1586206896551724,,
|
| 22 |
-
DG-iTransformer,14.183794754173379,313.5635374005159,17.707725359303375,0.1497301506825386,94.26231665878274,,0.1103448275862069,0.2
|
| 23 |
-
Physics iTransformer,16.41156271618159,379.65023683665015,19.48461538847124,-0.0294728537142276,97.60205959509742,,0.0,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v1/results/vae_lstm_results.json
DELETED
|
@@ -1,8 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"MAE": 8.494939970437716,
|
| 3 |
-
"MSE": 100.78674732190278,
|
| 4 |
-
"RMSE": 10.039260297546965,
|
| 5 |
-
"R2": 0.7267031327397879,
|
| 6 |
-
"MAPE": 14.250142040133243,
|
| 7 |
-
"tol_2pct": 0.09310344827586207
|
| 8 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/battery_features.csv
DELETED
|
The diff for this file is too large to render.
See raw diff
|
|
|
artifacts/v2/results/classical_rul_results.csv
DELETED
|
@@ -1,4 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tolerance_acc_5cyc
|
| 2 |
-
RandomForest,8.942333980582523,137.23446964660195,11.714711675777682,-0.15748641443851108,120.88277153106779,0.4058252427184466
|
| 3 |
-
XGBoost,6.7578043937683105,74.80780029296875,8.649150264214905,0.3690432906150818,90.60895087232073,0.429126213592233
|
| 4 |
-
LightGBM,9.174716686966466,125.80377799208308,11.216228331845027,-0.06107572161612751,112.25501529299473,0.35145631067961164
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/classical_soh_results.csv
DELETED
|
@@ -1,11 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tolerance_acc_2pct
|
| 2 |
-
RandomForest,4.78051739475878,41.771168089034525,6.463061819991708,0.956679157080545,28.807727531282236,0.29514563106796116
|
| 3 |
-
LightGBM,6.909989455704782,89.23030742727897,9.446179514876846,0.9074593240133356,56.94413475231037,0.24854368932038834
|
| 4 |
-
XGBoost,8.506303251021016,136.22476526016746,11.67153654238239,0.8587214117403497,72.81562821369698,0.22330097087378642
|
| 5 |
-
SVR,7.562130215902278,187.88576938734298,13.707143006014892,0.805143828272144,97.82839183781172,0.32233009708737864
|
| 6 |
-
KNN-10,11.665738368704334,265.7682207905257,16.302399234177948,0.7243720041223407,89.92209971367193,0.26019417475728157
|
| 7 |
-
KNN-5,11.751580021863887,270.3768092061512,16.44313866651228,0.7195924409938166,88.41470284019084,0.2757281553398058
|
| 8 |
-
KNN-20,12.035078655061884,272.741740151536,16.514894494108525,0.71713977312056,101.98653839713165,0.2407766990291262
|
| 9 |
-
ElasticNet,15.796038594619795,460.3763913475375,21.45638346384445,0.5225440358554927,144.4728811908027,0.06407766990291262
|
| 10 |
-
Lasso,15.830927911593506,462.77574982037044,21.512223265398916,0.5200556632227833,145.46522399976544,0.05242718446601942
|
| 11 |
-
Ridge,15.860549029501184,464.1921925903698,21.545119925179574,0.5185866716299998,145.65718178268125,0.05048543689320388
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/dg_itransformer_results.json
DELETED
|
@@ -1,9 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"MAE": 12.886456320718098,
|
| 3 |
-
"MSE": 323.38418900793243,
|
| 4 |
-
"RMSE": 17.982886003306934,
|
| 5 |
-
"R2": 0.12310012848141882,
|
| 6 |
-
"MAPE": 69.98234771512423,
|
| 7 |
-
"tol_2pct": 0.04827586206896552,
|
| 8 |
-
"tol_5pct": 0.2896551724137931
|
| 9 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/ensemble_results.csv
DELETED
|
@@ -1,9 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tol_2pct
|
| 2 |
-
Weighted Avg Ensemble,3.737822790616429,37.739016006374186,6.1432089339671805,0.8976655649469139,5.478476687258817,0.3482758620689655
|
| 3 |
-
tft,4.732738753085752,46.68825874782447,6.832880706394959,0.8733984854887593,7.499287950788588,0.21379310344827587
|
| 4 |
-
Stacking Ensemble,5.76908337148985,60.03540223313905,7.7482515597481125,0.8372059046352616,10.924057540803656,0.12413793103448276
|
| 5 |
-
vae_lstm,8.494939970437716,100.78674732190278,10.039260297546965,0.7267031327397879,14.250142040133243,0.09310344827586207
|
| 6 |
-
batterygpt,8.020673063309337,129.06954589210812,11.360877866261397,0.6500105074494692,12.874349389916773,0.28620689655172415
|
| 7 |
-
vanilla_lstm,10.561354979478219,155.95773910638056,12.488304092485118,0.5770995427937917,14.375050332959946,0.15862068965517243
|
| 8 |
-
bidirectional_lstm,11.134867385317946,167.3343794115467,12.935779041540046,0.5462502472468515,17.124593156141298,0.10689655172413794
|
| 9 |
-
attention_lstm,14.181327172488002,288.23989200564256,16.977629163273726,0.21839863277892768,24.827876450140888,0.15862068965517243
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/final_rankings.csv
DELETED
|
@@ -1,23 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tolerance_acc_2pct,tol_2pct,tol_5pct
|
| 2 |
-
RandomForest,4.78051739475878,41.771168089034525,6.463061819991708,0.956679157080545,28.80772753128224,0.2951456310679611,,
|
| 3 |
-
LightGBM,6.909989455704782,89.23030742727897,9.446179514876846,0.9074593240133356,56.94413475231037,0.2485436893203883,,
|
| 4 |
-
Weighted Avg Ensemble,3.737822790616429,37.739016006374186,6.1432089339671805,0.8976655649469139,5.478476687258817,,0.3482758620689655,
|
| 5 |
-
TFT,4.732738753085752,46.68825874782447,6.832880706394959,0.8733984854887593,7.499287950788588,,0.2137931034482758,
|
| 6 |
-
XGBoost,8.506303251021016,136.22476526016746,11.67153654238239,0.8587214117403497,72.81562821369698,0.2233009708737864,,
|
| 7 |
-
Stacking Ensemble,5.76908337148985,60.03540223313905,7.748251559748112,0.8372059046352616,10.924057540803656,,0.1241379310344827,
|
| 8 |
-
SVR,7.562130215902278,187.88576938734295,13.707143006014892,0.805143828272144,97.82839183781172,0.3223300970873786,,
|
| 9 |
-
VAE-LSTM,8.494939970437716,100.78674732190278,10.039260297546965,0.7267031327397879,14.250142040133243,,0.09310344827586207,
|
| 10 |
-
KNN-10,11.665738368704334,265.7682207905257,16.302399234177948,0.7243720041223407,89.92209971367193,0.2601941747572815,,
|
| 11 |
-
KNN-5,11.751580021863887,270.3768092061512,16.44313866651228,0.7195924409938166,88.41470284019084,0.2757281553398058,,
|
| 12 |
-
KNN-20,12.035078655061884,272.741740151536,16.514894494108525,0.71713977312056,101.98653839713164,0.2407766990291262,,
|
| 13 |
-
BatteryGPT,8.020673063309337,129.06954589210812,11.360877866261395,0.6500105074494692,12.874349389916771,,0.2862068965517241,
|
| 14 |
-
GRU,9.275809104339835,134.65458890701777,11.604076391812397,0.6348659095727935,15.248492181524448,0.193103448275862,,
|
| 15 |
-
Vanilla LSTM,10.56135497947822,155.95773910638056,12.488304092485118,0.5770995427937917,14.375050332959946,0.1586206896551724,,
|
| 16 |
-
Bidirectional LSTM,11.134867385317946,167.3343794115467,12.935779041540046,0.5462502472468515,17.124593156141298,0.1068965517241379,,
|
| 17 |
-
ElasticNet,15.796038594619796,460.3763913475375,21.45638346384445,0.5225440358554927,144.4728811908027,0.0640776699029126,,
|
| 18 |
-
Lasso,15.830927911593506,462.7757498203704,21.51222326539892,0.5200556632227833,145.46522399976544,0.0524271844660194,,
|
| 19 |
-
Ridge,15.860549029501184,464.1921925903698,21.545119925179574,0.5185866716299998,145.65718178268125,0.0504854368932038,,
|
| 20 |
-
iTransformer,14.544141949115827,275.09890344946007,16.58610573490535,0.2540321967199925,73.33406651321724,,0.0172413793103448,
|
| 21 |
-
Attention LSTM,14.181327172488002,288.23989200564256,16.977629163273726,0.2183986327789276,24.827876450140888,0.1586206896551724,,
|
| 22 |
-
DG-iTransformer,14.183794754173379,313.5635374005159,17.707725359303375,0.1497301506825386,94.26231665878274,,0.1103448275862069,0.2
|
| 23 |
-
Physics iTransformer,16.41156271618159,379.65023683665015,19.48461538847124,-0.0294728537142276,97.60205959509742,,0.0,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/lstm_soh_results.csv
DELETED
|
@@ -1,5 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tolerance_acc_2pct
|
| 2 |
-
GRU,9.275809104339837,134.65458890701777,11.604076391812395,0.6348659095727935,15.248492181524448,0.19310344827586207
|
| 3 |
-
Vanilla LSTM,10.561354979478219,155.95773910638056,12.488304092485118,0.5770995427937917,14.375050332959946,0.15862068965517243
|
| 4 |
-
Bidirectional LSTM,11.134867385317946,167.3343794115467,12.935779041540046,0.5462502472468515,17.124593156141298,0.10689655172413794
|
| 5 |
-
Attention LSTM,14.181327172488002,288.23989200564256,16.977629163273726,0.21839863277892768,24.827876450140888,0.15862068965517243
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/transformer_soh_results.csv
DELETED
|
@@ -1,5 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tol_2pct
|
| 2 |
-
TFT,9.538144323660262,127.31655440584875,11.283463759229644,0.6547639804432781,18.98017853690174,0.05517241379310345
|
| 3 |
-
BatteryGPT,9.614953606189902,135.34729964687295,11.633885836076997,0.6329875309153767,15.44417472623618,0.1793103448275862
|
| 4 |
-
iTransformer,9.356759048993766,150.35062176683638,12.261754432659153,0.5923039981808029,14.4907916127095,0.1310344827586207
|
| 5 |
-
Physics iTransformer,12.1375468649355,214.65431642999653,14.651085844741901,0.4179358518552816,24.985288391381786,0.07931034482758621
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/unified_results.csv
DELETED
|
@@ -1,23 +0,0 @@
|
|
| 1 |
-
model,MAE,MSE,RMSE,R2,MAPE,tolerance_acc_2pct,tol_2pct,tol_5pct
|
| 2 |
-
RandomForest,4.78051739475878,41.771168089034525,6.463061819991708,0.956679157080545,28.80772753128224,0.2951456310679611,,
|
| 3 |
-
LightGBM,6.909989455704782,89.23030742727897,9.446179514876846,0.9074593240133356,56.94413475231037,0.2485436893203883,,
|
| 4 |
-
Weighted Avg Ensemble,3.737822790616429,37.739016006374186,6.1432089339671805,0.8976655649469139,5.478476687258817,,0.3482758620689655,
|
| 5 |
-
TFT,4.732738753085752,46.68825874782447,6.832880706394959,0.8733984854887593,7.499287950788588,,0.2137931034482758,
|
| 6 |
-
XGBoost,8.506303251021016,136.22476526016746,11.67153654238239,0.8587214117403497,72.81562821369698,0.2233009708737864,,
|
| 7 |
-
Stacking Ensemble,5.76908337148985,60.03540223313905,7.748251559748112,0.8372059046352616,10.924057540803656,,0.1241379310344827,
|
| 8 |
-
SVR,7.562130215902278,187.88576938734295,13.707143006014892,0.805143828272144,97.82839183781172,0.3223300970873786,,
|
| 9 |
-
VAE-LSTM,8.494939970437716,100.78674732190278,10.039260297546965,0.7267031327397879,14.250142040133243,,0.09310344827586207,
|
| 10 |
-
KNN-10,11.665738368704334,265.7682207905257,16.302399234177948,0.7243720041223407,89.92209971367193,0.2601941747572815,,
|
| 11 |
-
KNN-5,11.751580021863887,270.3768092061512,16.44313866651228,0.7195924409938166,88.41470284019084,0.2757281553398058,,
|
| 12 |
-
KNN-20,12.035078655061884,272.741740151536,16.514894494108525,0.71713977312056,101.98653839713164,0.2407766990291262,,
|
| 13 |
-
BatteryGPT,8.020673063309337,129.06954589210812,11.360877866261395,0.6500105074494692,12.874349389916771,,0.2862068965517241,
|
| 14 |
-
GRU,9.275809104339835,134.65458890701777,11.604076391812397,0.6348659095727935,15.248492181524448,0.193103448275862,,
|
| 15 |
-
Vanilla LSTM,10.56135497947822,155.95773910638056,12.488304092485118,0.5770995427937917,14.375050332959946,0.1586206896551724,,
|
| 16 |
-
Bidirectional LSTM,11.134867385317946,167.3343794115467,12.935779041540046,0.5462502472468515,17.124593156141298,0.1068965517241379,,
|
| 17 |
-
ElasticNet,15.796038594619796,460.3763913475375,21.45638346384445,0.5225440358554927,144.4728811908027,0.0640776699029126,,
|
| 18 |
-
Lasso,15.830927911593506,462.7757498203704,21.51222326539892,0.5200556632227833,145.46522399976544,0.0524271844660194,,
|
| 19 |
-
Ridge,15.860549029501184,464.1921925903698,21.545119925179574,0.5185866716299998,145.65718178268125,0.0504854368932038,,
|
| 20 |
-
iTransformer,14.544141949115827,275.09890344946007,16.58610573490535,0.2540321967199925,73.33406651321724,,0.0172413793103448,
|
| 21 |
-
Attention LSTM,14.181327172488002,288.23989200564256,16.977629163273726,0.2183986327789276,24.827876450140888,0.1586206896551724,,
|
| 22 |
-
DG-iTransformer,14.183794754173379,313.5635374005159,17.707725359303375,0.1497301506825386,94.26231665878274,,0.1103448275862069,0.2
|
| 23 |
-
Physics iTransformer,16.41156271618159,379.65023683665015,19.48461538847124,-0.0294728537142276,97.60205959509742,,0.0,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/v2_classical_results.csv
DELETED
|
@@ -1,9 +0,0 @@
|
|
| 1 |
-
model,r2,mae,within_5pct
|
| 2 |
-
extra_trees,0.9545111863206289,1.325439106747622,99.27007299270073
|
| 3 |
-
svr,0.9749418151896808,0.8447528977381709,99.27007299270073
|
| 4 |
-
ridge,0.96260007301777,1.238689808585007,99.27007299270073
|
| 5 |
-
xgboost,0.9701536078007467,1.276102318230126,98.72262773722628
|
| 6 |
-
gradient_boosting,0.9427669688063848,1.4114545626753392,98.54014598540147
|
| 7 |
-
knn_k5,0.9303819293635062,1.7036079148305412,97.62773722627736
|
| 8 |
-
random_forest,0.9518568236961867,1.6867479514298702,96.71532846715328
|
| 9 |
-
lightgbm,0.9560384659829149,1.5661312778770975,95.98540145985402
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/v2_intra_battery.json
DELETED
|
@@ -1,9 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"target": "within_5pct >= 95",
|
| 3 |
-
"passed_models": 8,
|
| 4 |
-
"total_models": 8,
|
| 5 |
-
"best_model": "extra_trees",
|
| 6 |
-
"best_within_5pct": 99.27007299270073,
|
| 7 |
-
"best_r2": 0.9545111863206289,
|
| 8 |
-
"notes": "XGBoost\u2192LGB+GB Ensemble, Ridge\u2192ExtraTrees-Scaled, KNN\u2192SVR Ensemble"
|
| 9 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/v2_model_validation.csv
DELETED
|
@@ -1,17 +0,0 @@
|
|
| 1 |
-
model,mae,rmse,r2,within_2pct,within_5pct,passed_95
|
| 2 |
-
random_forest,0.9087291273437881,1.969167860523798,0.9768094711831841,83.75912408759125,95.07299270072993,True
|
| 3 |
-
svr,1.6349861755580366,3.4846680412456976,0.9273780344781068,82.48175182481752,88.86861313868614,False
|
| 4 |
-
xgboost,1.0395094776911078,2.3264169017858896,0.9676316722415876,82.2992700729927,88.86861313868614,False
|
| 5 |
-
lightgbm,1.5073643559068495,2.9029505644051135,0.9496007058102836,81.02189781021897,88.13868613138686,False
|
| 6 |
-
knn_k20,2.486675866923982,6.500672824933502,0.7472670935266853,84.12408759124088,85.21897810218978,False
|
| 7 |
-
knn_k10,2.537245189395581,6.643166546082999,0.7360659298020076,84.48905109489051,84.67153284671532,False
|
| 8 |
-
knn_k5,2.5366661790854557,6.661080117527008,0.734640592527769,84.48905109489051,84.67153284671532,False
|
| 9 |
-
lasso,6.338197702892737,7.855862262540625,0.63090947633286,13.321167883211679,49.63503649635037,False
|
| 10 |
-
ridge,6.354219600702956,7.877916808246509,0.6288341980649439,13.138686131386862,49.63503649635037,False
|
| 11 |
-
elasticnet,6.359292593403684,7.8720819252103045,0.6293838121478381,13.503649635036496,49.27007299270073,False
|
| 12 |
-
physics_itransformer,11.942222882334457,19.560215899810355,-1.288191997636034,15.875912408759124,44.70802919708029,False
|
| 13 |
-
itransformer,18.775672188288702,24.807532802455988,-2.680546617377897,10.948905109489052,25.18248175182482,False
|
| 14 |
-
dynamic_graph_itransformer,14.5743662824896,18.019296255058386,-0.9418730093540923,6.204379562043796,17.335766423357665,False
|
| 15 |
-
extra_trees,21.583514681220528,25.105434141924782,-2.769473079864784,5.839416058394161,9.48905109489051,False
|
| 16 |
-
gradient_boosting,29.48091148539111,32.124687008446905,-5.1719583162447185,0.0,0.18248175182481752,False
|
| 17 |
-
best_rul_model,61.6389790255578,62.979116792145476,-22.721290167829615,0.0,0.0,False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/v2_training_summary.json
DELETED
|
@@ -1,14 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"version": "v2.0",
|
| 3 |
-
"timestamp": "2026-02-25T18:16:44.705048",
|
| 4 |
-
"total_models": 12,
|
| 5 |
-
"passed_models": 5,
|
| 6 |
-
"pass_rate_pct": 41.66666666666667,
|
| 7 |
-
"best_model": "extra_trees",
|
| 8 |
-
"best_within_5pct": 99.27007299270073,
|
| 9 |
-
"best_r2": 0.9545111863206289,
|
| 10 |
-
"mean_within_5pct": 77.38746958637469,
|
| 11 |
-
"train_samples": 2130,
|
| 12 |
-
"test_samples": 548,
|
| 13 |
-
"batteries": 30
|
| 14 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/v2_validation_report.html
DELETED
|
File without changes
|
artifacts/v2/results/v2_validation_summary.json
DELETED
|
@@ -1,11 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"timestamp": "2026-02-25T16:31:44.904601",
|
| 3 |
-
"test_samples": 548,
|
| 4 |
-
"test_batteries": 30,
|
| 5 |
-
"total_models_tested": 16,
|
| 6 |
-
"models_passed_95pct": 1,
|
| 7 |
-
"overall_pass_rate_pct": 6.25,
|
| 8 |
-
"best_model": "random_forest",
|
| 9 |
-
"best_within_5pct": 95.07299270072993,
|
| 10 |
-
"mean_within_5pct": 53.809306569343065
|
| 11 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
artifacts/v2/results/vae_lstm_results.json
DELETED
|
@@ -1,8 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"MAE": 8.494939970437716,
|
| 3 |
-
"MSE": 100.78674732190278,
|
| 4 |
-
"RMSE": 10.039260297546965,
|
| 5 |
-
"R2": 0.7267031327397879,
|
| 6 |
-
"MAPE": 14.250142040133243,
|
| 7 |
-
"tol_2pct": 0.09310344827586207
|
| 8 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/App.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import GraphPanel from "./components/GraphPanel";
|
|
| 5 |
import RecommendationPanel from "./components/RecommendationPanel";
|
| 6 |
import MetricsPanel from "./components/MetricsPanel";
|
| 7 |
import ResearchPaper from "./components/ResearchPaper";
|
|
|
|
| 8 |
import { ToastProvider } from "./components/Toast";
|
| 9 |
import { getApiVersion, setApiVersion } from "./api";
|
| 10 |
import { BatteryCharging } from "lucide-react";
|
|
@@ -42,24 +43,11 @@ export default function App() {
|
|
| 42 |
<h1 className="text-lg font-bold">AI Battery Lifecycle Predictor</h1>
|
| 43 |
</div>
|
| 44 |
<div className="flex items-center gap-4">
|
| 45 |
-
{/* Version
|
| 46 |
-
<
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
onClick={() => handleVersionChange(v)}
|
| 51 |
-
className={`px-3 py-1 rounded text-xs font-bold transition-colors ${
|
| 52 |
-
apiVersion === v
|
| 53 |
-
? v === "v2"
|
| 54 |
-
? "bg-green-600 text-white"
|
| 55 |
-
: "bg-blue-600 text-white"
|
| 56 |
-
: "text-gray-400 hover:text-white"
|
| 57 |
-
}`}
|
| 58 |
-
>
|
| 59 |
-
{v.toUpperCase()}
|
| 60 |
-
</button>
|
| 61 |
-
))}
|
| 62 |
-
</div>
|
| 63 |
<nav className="flex gap-1">
|
| 64 |
{tabs.map((t) => (
|
| 65 |
<button
|
|
|
|
| 5 |
import RecommendationPanel from "./components/RecommendationPanel";
|
| 6 |
import MetricsPanel from "./components/MetricsPanel";
|
| 7 |
import ResearchPaper from "./components/ResearchPaper";
|
| 8 |
+
import VersionSelector from "./components/VersionSelector";
|
| 9 |
import { ToastProvider } from "./components/Toast";
|
| 10 |
import { getApiVersion, setApiVersion } from "./api";
|
| 11 |
import { BatteryCharging } from "lucide-react";
|
|
|
|
| 43 |
<h1 className="text-lg font-bold">AI Battery Lifecycle Predictor</h1>
|
| 44 |
</div>
|
| 45 |
<div className="flex items-center gap-4">
|
| 46 |
+
{/* Version selector with submenu */}
|
| 47 |
+
<VersionSelector
|
| 48 |
+
activeVersion={apiVersion}
|
| 49 |
+
onSwitch={handleVersionChange}
|
| 50 |
+
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
<nav className="flex gap-1">
|
| 52 |
{tabs.map((t) => (
|
| 53 |
<button
|
frontend/src/api.ts
CHANGED
|
@@ -66,6 +66,21 @@ export interface ModelVersionGroups {
|
|
| 66 |
default_model: string | null;
|
| 67 |
}
|
| 68 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
export interface BatteryVizData {
|
| 70 |
battery_id: string;
|
| 71 |
soh_pct: number;
|
|
|
|
| 66 |
default_model: string | null;
|
| 67 |
}
|
| 68 |
|
| 69 |
+
// ── Version management ───────────────────────────────────────────────────────
|
| 70 |
+
export interface VersionInfo {
|
| 71 |
+
id: string; // "v1" | "v2"
|
| 72 |
+
display: string; // "Version 1" | "Version 2"
|
| 73 |
+
loaded: boolean;
|
| 74 |
+
model_count: number;
|
| 75 |
+
status: "ready" | "not_downloaded" | "downloading" | "error";
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
export const fetchVersions = () =>
|
| 79 |
+
baseApi.get<VersionInfo[]>("/versions").then((r) => r.data);
|
| 80 |
+
|
| 81 |
+
export const loadVersion = (version: string) =>
|
| 82 |
+
baseApi.post<{ status: string; version: string }>(`/versions/${version}/load`).then((r) => r.data);
|
| 83 |
+
|
| 84 |
export interface BatteryVizData {
|
| 85 |
battery_id: string;
|
| 86 |
soh_pct: number;
|
frontend/src/components/VersionSelector.tsx
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* VersionSelector
|
| 3 |
+
*
|
| 4 |
+
* Shows the active API version badge ("Version 2") with a chevron icon.
|
| 5 |
+
* Clicking opens a submenu listing all available versions:
|
| 6 |
+
* - Active version: shown with a check mark
|
| 7 |
+
* - Downloaded but inactive: "Switch" button
|
| 8 |
+
* - Not yet downloaded: Download icon button → triggers server-side download
|
| 9 |
+
* then auto-switches when ready
|
| 10 |
+
*/
|
| 11 |
+
|
| 12 |
+
import { useCallback, useEffect, useRef, useState } from "react";
|
| 13 |
+
import {
|
| 14 |
+
ChevronRight, Download, Check, RefreshCw, AlertCircle, Layers,
|
| 15 |
+
} from "lucide-react";
|
| 16 |
+
import { fetchVersions, loadVersion, VersionInfo } from "../api";
|
| 17 |
+
|
| 18 |
+
interface Props {
|
| 19 |
+
activeVersion: "v1" | "v2";
|
| 20 |
+
onSwitch: (v: "v1" | "v2") => void;
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
export default function VersionSelector({ activeVersion, onSwitch }: Props) {
|
| 24 |
+
const [open, setOpen] = useState(false);
|
| 25 |
+
const [versions, setVersions] = useState<VersionInfo[]>([]);
|
| 26 |
+
const [busy, setBusy] = useState<string | null>(null); // version being downloaded
|
| 27 |
+
const menuRef = useRef<HTMLDivElement>(null);
|
| 28 |
+
const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
| 29 |
+
|
| 30 |
+
// ── Load version list ────────────────────────────────────────────────────
|
| 31 |
+
const refresh = useCallback(() => {
|
| 32 |
+
fetchVersions()
|
| 33 |
+
.then(setVersions)
|
| 34 |
+
.catch(() => {});
|
| 35 |
+
}, []);
|
| 36 |
+
|
| 37 |
+
useEffect(() => {
|
| 38 |
+
refresh();
|
| 39 |
+
}, [refresh]);
|
| 40 |
+
|
| 41 |
+
// ── Poll while a download is in progress ────────────────────────────────
|
| 42 |
+
useEffect(() => {
|
| 43 |
+
const hasDownloading = versions.some((v) => v.status === "downloading");
|
| 44 |
+
if (hasDownloading && !pollRef.current) {
|
| 45 |
+
pollRef.current = setInterval(refresh, 2500);
|
| 46 |
+
}
|
| 47 |
+
if (!hasDownloading && pollRef.current) {
|
| 48 |
+
clearInterval(pollRef.current);
|
| 49 |
+
pollRef.current = null;
|
| 50 |
+
setBusy(null);
|
| 51 |
+
}
|
| 52 |
+
return () => {
|
| 53 |
+
if (pollRef.current) clearInterval(pollRef.current);
|
| 54 |
+
};
|
| 55 |
+
}, [versions, refresh]);
|
| 56 |
+
|
| 57 |
+
// ── Close on outside click ───────────────────────────────────────────────
|
| 58 |
+
useEffect(() => {
|
| 59 |
+
if (!open) return;
|
| 60 |
+
const handler = (e: MouseEvent) => {
|
| 61 |
+
if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
|
| 62 |
+
setOpen(false);
|
| 63 |
+
}
|
| 64 |
+
};
|
| 65 |
+
document.addEventListener("mousedown", handler);
|
| 66 |
+
return () => document.removeEventListener("mousedown", handler);
|
| 67 |
+
}, [open]);
|
| 68 |
+
|
| 69 |
+
// ── Actions ──────────────────────────────────────────────────────────────
|
| 70 |
+
const handleDownload = async (version: string) => {
|
| 71 |
+
setBusy(version);
|
| 72 |
+
try {
|
| 73 |
+
await loadVersion(version);
|
| 74 |
+
refresh(); // poll will take over
|
| 75 |
+
} catch {
|
| 76 |
+
setBusy(null);
|
| 77 |
+
}
|
| 78 |
+
};
|
| 79 |
+
|
| 80 |
+
const handleSwitch = (version: string) => {
|
| 81 |
+
onSwitch(version as "v1" | "v2");
|
| 82 |
+
setOpen(false);
|
| 83 |
+
};
|
| 84 |
+
|
| 85 |
+
const activeDisplay = versions.find((v) => v.id === activeVersion)?.display
|
| 86 |
+
?? `Version ${activeVersion[1]}`;
|
| 87 |
+
|
| 88 |
+
// Versions that are NOT the active one
|
| 89 |
+
const others = versions.filter((v) => v.id !== activeVersion);
|
| 90 |
+
|
| 91 |
+
return (
|
| 92 |
+
<div className="relative" ref={menuRef}>
|
| 93 |
+
{/* Badge button */}
|
| 94 |
+
<button
|
| 95 |
+
onClick={() => setOpen((o) => !o)}
|
| 96 |
+
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-bold
|
| 97 |
+
transition-colors select-none
|
| 98 |
+
${activeVersion === "v2"
|
| 99 |
+
? "bg-green-600 text-white hover:bg-green-500"
|
| 100 |
+
: "bg-blue-600 text-white hover:bg-blue-500"}`}
|
| 101 |
+
title="Switch model version"
|
| 102 |
+
>
|
| 103 |
+
<Layers className="w-3.5 h-3.5 opacity-80" />
|
| 104 |
+
{activeDisplay}
|
| 105 |
+
<ChevronRight
|
| 106 |
+
className={`w-3.5 h-3.5 transition-transform duration-200
|
| 107 |
+
${open ? "rotate-90" : ""}`}
|
| 108 |
+
/>
|
| 109 |
+
</button>
|
| 110 |
+
|
| 111 |
+
{/* Dropdown */}
|
| 112 |
+
{open && (
|
| 113 |
+
<div
|
| 114 |
+
className="absolute right-0 top-full mt-2 w-56
|
| 115 |
+
bg-gray-900 border border-gray-700 rounded-xl shadow-2xl z-50
|
| 116 |
+
overflow-hidden"
|
| 117 |
+
>
|
| 118 |
+
{/* Header */}
|
| 119 |
+
<div className="px-3 py-2 border-b border-gray-700 text-xs text-gray-400 font-medium">
|
| 120 |
+
Model Versions
|
| 121 |
+
</div>
|
| 122 |
+
|
| 123 |
+
{/* Active version row */}
|
| 124 |
+
<div className="flex items-center justify-between px-3 py-2.5 bg-gray-800/50">
|
| 125 |
+
<div>
|
| 126 |
+
<span className="text-sm font-semibold text-white">{activeDisplay}</span>
|
| 127 |
+
<span className="ml-2 text-xs text-green-400">active</span>
|
| 128 |
+
</div>
|
| 129 |
+
<Check className="w-4 h-4 text-green-400 shrink-0" />
|
| 130 |
+
</div>
|
| 131 |
+
|
| 132 |
+
{/* Other versions */}
|
| 133 |
+
{others.length === 0 && (
|
| 134 |
+
<div className="px-3 py-3 text-xs text-gray-500 text-center">
|
| 135 |
+
No other versions available
|
| 136 |
+
</div>
|
| 137 |
+
)}
|
| 138 |
+
{others.map((v) => {
|
| 139 |
+
const isDownloading = v.status === "downloading" || busy === v.id;
|
| 140 |
+
const isError = v.status === "error";
|
| 141 |
+
const canSwitch = v.loaded && !isDownloading;
|
| 142 |
+
|
| 143 |
+
return (
|
| 144 |
+
<div
|
| 145 |
+
key={v.id}
|
| 146 |
+
className="flex items-center justify-between px-3 py-2.5
|
| 147 |
+
hover:bg-gray-800/60 transition-colors"
|
| 148 |
+
>
|
| 149 |
+
<div>
|
| 150 |
+
<span className="text-sm font-medium text-gray-200">{v.display}</span>
|
| 151 |
+
{v.loaded && v.model_count > 0 && (
|
| 152 |
+
<span className="ml-2 text-xs text-gray-500">
|
| 153 |
+
{v.model_count} models
|
| 154 |
+
</span>
|
| 155 |
+
)}
|
| 156 |
+
{isError && (
|
| 157 |
+
<span className="ml-2 text-xs text-red-400">error</span>
|
| 158 |
+
)}
|
| 159 |
+
{isDownloading && (
|
| 160 |
+
<span className="ml-2 text-xs text-yellow-400 animate-pulse">
|
| 161 |
+
downloading…
|
| 162 |
+
</span>
|
| 163 |
+
)}
|
| 164 |
+
</div>
|
| 165 |
+
|
| 166 |
+
<div className="flex items-center gap-1 shrink-0">
|
| 167 |
+
{/* Switch button — visible when loaded */}
|
| 168 |
+
{canSwitch && (
|
| 169 |
+
<button
|
| 170 |
+
onClick={() => handleSwitch(v.id)}
|
| 171 |
+
className="px-2 py-0.5 rounded text-xs font-medium
|
| 172 |
+
bg-blue-700 hover:bg-blue-600 text-white transition-colors"
|
| 173 |
+
title={`Switch to ${v.display}`}
|
| 174 |
+
>
|
| 175 |
+
Load
|
| 176 |
+
</button>
|
| 177 |
+
)}
|
| 178 |
+
|
| 179 |
+
{/* Download button — visible when NOT loaded and NOT downloading */}
|
| 180 |
+
{!v.loaded && !isDownloading && !isError && (
|
| 181 |
+
<button
|
| 182 |
+
onClick={() => handleDownload(v.id)}
|
| 183 |
+
className="p-1.5 rounded-lg bg-gray-700 hover:bg-gray-600
|
| 184 |
+
text-gray-300 hover:text-white transition-colors"
|
| 185 |
+
title={`Download ${v.display} from HF Hub`}
|
| 186 |
+
>
|
| 187 |
+
<Download className="w-3.5 h-3.5" />
|
| 188 |
+
</button>
|
| 189 |
+
)}
|
| 190 |
+
|
| 191 |
+
{/* Spinner while downloading */}
|
| 192 |
+
{isDownloading && (
|
| 193 |
+
<RefreshCw className="w-3.5 h-3.5 text-yellow-400 animate-spin" />
|
| 194 |
+
)}
|
| 195 |
+
|
| 196 |
+
{/* Error retry */}
|
| 197 |
+
{isError && !isDownloading && (
|
| 198 |
+
<button
|
| 199 |
+
onClick={() => handleDownload(v.id)}
|
| 200 |
+
className="p-1.5 rounded-lg bg-gray-700 hover:bg-red-700
|
| 201 |
+
text-red-400 hover:text-white transition-colors"
|
| 202 |
+
title="Retry download"
|
| 203 |
+
>
|
| 204 |
+
<AlertCircle className="w-3.5 h-3.5" />
|
| 205 |
+
</button>
|
| 206 |
+
)}
|
| 207 |
+
</div>
|
| 208 |
+
</div>
|
| 209 |
+
);
|
| 210 |
+
})}
|
| 211 |
+
|
| 212 |
+
{/* Footer hint */}
|
| 213 |
+
<div className="px-3 py-2 border-t border-gray-700 text-xs text-gray-600 text-center">
|
| 214 |
+
Models hosted on Hugging Face Hub
|
| 215 |
+
</div>
|
| 216 |
+
</div>
|
| 217 |
+
)}
|
| 218 |
+
</div>
|
| 219 |
+
);
|
| 220 |
+
}
|
scripts/download_models.py
CHANGED
|
@@ -2,7 +2,20 @@
|
|
| 2 |
Download model artifacts from Hugging Face Hub at container startup.
|
| 3 |
|
| 4 |
Called automatically by the Docker entrypoint before uvicorn starts.
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
"""
|
| 7 |
|
| 8 |
import os
|
|
@@ -14,83 +27,111 @@ from pathlib import Path
|
|
| 14 |
# ──────────────────────────────────────────────────────────────────────────────
|
| 15 |
REPO_ID = "NeerajCodz/aiBatteryLifeCycle"
|
| 16 |
REPO_TYPE = "model"
|
| 17 |
-
# Token read from the HF_TOKEN Space Secret (set in Space Settings
|
| 18 |
# For local use: set HF_TOKEN in your shell or .env before running
|
| 19 |
HF_TOKEN = os.getenv("HF_TOKEN", "")
|
| 20 |
|
| 21 |
-
#
|
| 22 |
-
#
|
| 23 |
-
|
| 24 |
-
# pointed local_dir at the artifacts/ subfolder directly).
|
| 25 |
-
PROJECT_ROOT = Path(__file__).resolve().parent.parent # /app (or repo root locally)
|
| 26 |
-
ARTIFACTS_DIR = PROJECT_ROOT / "artifacts"
|
| 27 |
|
| 28 |
-
# Sentinel file — written after a successful download
|
| 29 |
SENTINEL = ARTIFACTS_DIR / ".hf_downloaded"
|
| 30 |
|
| 31 |
# ──────────────────────────────────────────────────────────────────────────────
|
| 32 |
|
| 33 |
|
| 34 |
-
def
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
"""
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
if missing:
|
| 47 |
if SENTINEL.exists():
|
| 48 |
-
SENTINEL.unlink()
|
| 49 |
-
print(f"[download_models] Sentinel
|
| 50 |
return False
|
| 51 |
return True
|
| 52 |
|
| 53 |
|
| 54 |
-
def
|
| 55 |
try:
|
| 56 |
-
from huggingface_hub import snapshot_download
|
| 57 |
except ImportError:
|
| 58 |
-
print("[download_models] huggingface_hub not installed — installing now…")
|
| 59 |
import subprocess
|
| 60 |
-
subprocess.check_call([sys.executable, "-m", "pip", "install",
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
ARTIFACTS_DIR.mkdir(parents=True, exist_ok=True)
|
| 64 |
|
| 65 |
-
print(f"[download_models] Downloading from {REPO_ID} → {ARTIFACTS_DIR}")
|
| 66 |
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
)
|
| 78 |
-
|
| 79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
|
| 81 |
-
snapshot_download(**kwargs)
|
| 82 |
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
|
|
|
|
|
|
|
|
|
| 86 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
|
| 88 |
-
|
| 89 |
-
if already_downloaded():
|
| 90 |
print("[download_models] Artifacts already present — skipping download")
|
| 91 |
return
|
| 92 |
|
| 93 |
-
|
| 94 |
|
| 95 |
|
| 96 |
if __name__ == "__main__":
|
|
|
|
| 2 |
Download model artifacts from Hugging Face Hub at container startup.
|
| 3 |
|
| 4 |
Called automatically by the Docker entrypoint before uvicorn starts.
|
| 5 |
+
Can also download a specific version on-demand (e.g. from the API).
|
| 6 |
+
|
| 7 |
+
HF model repo layout (v1/ and v2/ at repo root):
|
| 8 |
+
v1/models/classical/*.joblib
|
| 9 |
+
v1/models/deep/*.pt *.keras
|
| 10 |
+
v1/scalers/*.joblib
|
| 11 |
+
v2/models/classical/*.joblib
|
| 12 |
+
v2/models/deep/*.pt *.keras
|
| 13 |
+
v2/scalers/*.joblib
|
| 14 |
+
v2/results/*.json
|
| 15 |
+
|
| 16 |
+
Local layout after download (local_dir = ARTIFACTS_DIR):
|
| 17 |
+
artifacts/v1/...
|
| 18 |
+
artifacts/v2/...
|
| 19 |
"""
|
| 20 |
|
| 21 |
import os
|
|
|
|
| 27 |
# ──────────────────────────────────────────────────────────────────────────────
|
| 28 |
REPO_ID = "NeerajCodz/aiBatteryLifeCycle"
|
| 29 |
REPO_TYPE = "model"
|
| 30 |
+
# Token read from the HF_TOKEN Space Secret (set in Space Settings -> Secrets)
|
| 31 |
# For local use: set HF_TOKEN in your shell or .env before running
|
| 32 |
HF_TOKEN = os.getenv("HF_TOKEN", "")
|
| 33 |
|
| 34 |
+
# HF repo stores v1/ and v2/ at root → local_dir=ARTIFACTS_DIR maps them to
|
| 35 |
+
# artifacts/v1/... and artifacts/v2/...
|
| 36 |
+
ARTIFACTS_DIR = Path(__file__).resolve().parent.parent / "artifacts"
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
+
# Sentinel file — written after a successful full download
|
| 39 |
SENTINEL = ARTIFACTS_DIR / ".hf_downloaded"
|
| 40 |
|
| 41 |
# ──────────────────────────────────────────────────────────────────────────────
|
| 42 |
|
| 43 |
|
| 44 |
+
def _hf_kwargs(allow_patterns: list | None = None,
|
| 45 |
+
ignore_patterns: list | None = None) -> dict:
|
| 46 |
+
"""Build kwargs for snapshot_download; inject token only when non-empty."""
|
| 47 |
+
kwargs: dict = dict(
|
| 48 |
+
repo_id=REPO_ID,
|
| 49 |
+
repo_type=REPO_TYPE,
|
| 50 |
+
local_dir=str(ARTIFACTS_DIR),
|
| 51 |
+
)
|
| 52 |
+
if allow_patterns:
|
| 53 |
+
kwargs["allow_patterns"] = allow_patterns
|
| 54 |
+
if ignore_patterns:
|
| 55 |
+
kwargs["ignore_patterns"] = ignore_patterns
|
| 56 |
+
if HF_TOKEN:
|
| 57 |
+
kwargs["token"] = HF_TOKEN
|
| 58 |
+
return kwargs
|
| 59 |
|
| 60 |
+
|
| 61 |
+
def _key_models(version: str = "v2") -> list:
|
| 62 |
+
base = ARTIFACTS_DIR / version / "models" / "classical"
|
| 63 |
+
return [base / f"{m}.joblib" for m in ("random_forest", "xgboost", "lightgbm")]
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def version_loaded(version: str) -> bool:
|
| 67 |
+
"""Return True when the given version's key models exist on disk."""
|
| 68 |
+
return all(p.exists() for p in _key_models(version))
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def already_downloaded(version: str = "v2") -> bool:
|
| 72 |
+
"""Return True only when all three BestEnsemble component models are present."""
|
| 73 |
+
missing = [p for p in _key_models(version) if not p.exists()]
|
| 74 |
if missing:
|
| 75 |
if SENTINEL.exists():
|
| 76 |
+
SENTINEL.unlink()
|
| 77 |
+
print(f"[download_models] Sentinel stale ({len(missing)} key models missing) — will re-download")
|
| 78 |
return False
|
| 79 |
return True
|
| 80 |
|
| 81 |
|
| 82 |
+
def _ensure_hub():
|
| 83 |
try:
|
| 84 |
+
from huggingface_hub import snapshot_download # noqa: F401
|
| 85 |
except ImportError:
|
|
|
|
| 86 |
import subprocess
|
| 87 |
+
subprocess.check_call([sys.executable, "-m", "pip", "install",
|
| 88 |
+
"huggingface_hub>=0.23", "-q"])
|
|
|
|
|
|
|
| 89 |
|
|
|
|
| 90 |
|
| 91 |
+
def download_version(version: str) -> None:
|
| 92 |
+
"""Download a single version (e.g. 'v1' or 'v2') from HF Hub into artifacts/."""
|
| 93 |
+
_ensure_hub()
|
| 94 |
+
from huggingface_hub import snapshot_download
|
| 95 |
+
ARTIFACTS_DIR.mkdir(parents=True, exist_ok=True)
|
| 96 |
+
print(f"[download_models] Downloading {version}/ from {REPO_ID} -> {ARTIFACTS_DIR}")
|
| 97 |
+
snapshot_download(**_hf_kwargs(
|
| 98 |
+
allow_patterns=[f"{version}/**"],
|
| 99 |
+
ignore_patterns=["*.log"],
|
| 100 |
+
))
|
| 101 |
+
print(f"[download_models] {version}/ ready")
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
def download_all() -> None:
|
| 105 |
+
"""Download all versions (v1 + v2) from HF Hub."""
|
| 106 |
+
_ensure_hub()
|
| 107 |
+
from huggingface_hub import snapshot_download
|
| 108 |
+
ARTIFACTS_DIR.mkdir(parents=True, exist_ok=True)
|
| 109 |
+
print(f"[download_models] Downloading all versions from {REPO_ID} -> {ARTIFACTS_DIR}")
|
| 110 |
+
snapshot_download(**_hf_kwargs(ignore_patterns=["*.log"]))
|
| 111 |
+
SENTINEL.write_text("downloaded\n")
|
| 112 |
+
print("[download_models] Artifacts ready")
|
| 113 |
|
|
|
|
| 114 |
|
| 115 |
+
def main() -> None:
|
| 116 |
+
import argparse
|
| 117 |
+
parser = argparse.ArgumentParser()
|
| 118 |
+
parser.add_argument("--version", default=None,
|
| 119 |
+
help="Download only this version, e.g. v1 or v2")
|
| 120 |
+
args = parser.parse_args()
|
| 121 |
|
| 122 |
+
if args.version:
|
| 123 |
+
if version_loaded(args.version):
|
| 124 |
+
print(f"[download_models] {args.version} already present — skipping")
|
| 125 |
+
else:
|
| 126 |
+
download_version(args.version)
|
| 127 |
+
return
|
| 128 |
|
| 129 |
+
# Default: ensure v2 (latest) is present
|
| 130 |
+
if already_downloaded("v2"):
|
| 131 |
print("[download_models] Artifacts already present — skipping download")
|
| 132 |
return
|
| 133 |
|
| 134 |
+
download_all()
|
| 135 |
|
| 136 |
|
| 137 |
if __name__ == "__main__":
|
scripts/upload_models_to_hub.py
CHANGED
|
@@ -151,28 +151,42 @@ def main():
|
|
| 151 |
commit_message="chore: update model card",
|
| 152 |
)
|
| 153 |
|
| 154 |
-
# 3. Upload
|
| 155 |
-
#
|
|
|
|
| 156 |
for version in ["v1", "v2"]:
|
| 157 |
version_path = ARTIFACTS / version
|
| 158 |
if not version_path.exists():
|
| 159 |
print(f" [skip] {version_path} does not exist")
|
| 160 |
continue
|
| 161 |
|
| 162 |
-
print(f"\nUploading
|
| 163 |
upload_folder(
|
| 164 |
folder_path=str(version_path),
|
| 165 |
-
path_in_repo=
|
| 166 |
repo_id=REPO_ID,
|
| 167 |
repo_type=REPO_TYPE,
|
| 168 |
token=HF_TOKEN,
|
| 169 |
ignore_patterns=["logs/**", "*.log"],
|
| 170 |
-
commit_message=f"feat: upload {version}
|
| 171 |
run_as_future=False,
|
| 172 |
)
|
| 173 |
-
print(f" [OK]
|
| 174 |
|
| 175 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
|
| 177 |
|
| 178 |
if __name__ == "__main__":
|
|
|
|
| 151 |
commit_message="chore: update model card",
|
| 152 |
)
|
| 153 |
|
| 154 |
+
# 3. Upload each version directly at repo root: v1/ and v2/ (NOT under artifacts/)
|
| 155 |
+
# This keeps the HF model repo clean — download_models.py maps them back into
|
| 156 |
+
# the local artifacts/ folder via local_dir=ARTIFACTS_DIR.
|
| 157 |
for version in ["v1", "v2"]:
|
| 158 |
version_path = ARTIFACTS / version
|
| 159 |
if not version_path.exists():
|
| 160 |
print(f" [skip] {version_path} does not exist")
|
| 161 |
continue
|
| 162 |
|
| 163 |
+
print(f"\nUploading {version}/ at repo root …")
|
| 164 |
upload_folder(
|
| 165 |
folder_path=str(version_path),
|
| 166 |
+
path_in_repo=version, # v1/ or v2/ at repo root
|
| 167 |
repo_id=REPO_ID,
|
| 168 |
repo_type=REPO_TYPE,
|
| 169 |
token=HF_TOKEN,
|
| 170 |
ignore_patterns=["logs/**", "*.log"],
|
| 171 |
+
commit_message=f"feat: upload {version} artifacts at repo root",
|
| 172 |
run_as_future=False,
|
| 173 |
)
|
| 174 |
+
print(f" [OK] {version}/ uploaded")
|
| 175 |
|
| 176 |
+
# 4. Remove old artifacts/ tree that may exist from previous uploads
|
| 177 |
+
print("\nCleaning up legacy artifacts/ folder in HF repo (if any) …")
|
| 178 |
+
try:
|
| 179 |
+
api.delete_folder(
|
| 180 |
+
path_in_repo="artifacts",
|
| 181 |
+
repo_id=REPO_ID,
|
| 182 |
+
repo_type=REPO_TYPE,
|
| 183 |
+
commit_message="chore: remove legacy artifacts/ folder (moved to repo root)",
|
| 184 |
+
)
|
| 185 |
+
print(" [OK] artifacts/ removed")
|
| 186 |
+
except Exception as e:
|
| 187 |
+
print(f" [skip] No legacy artifacts/ to remove ({e})")
|
| 188 |
+
|
| 189 |
+
print("\n[OK] All artifacts uploaded to", f"https://huggingface.co/{REPO_ID}")
|
| 190 |
|
| 191 |
|
| 192 |
if __name__ == "__main__":
|