Pingul commited on
Commit
bd3500d
·
verified ·
1 Parent(s): 71b75c8

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -0
app.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from datetime import datetime
4
+ from contextlib import asynccontextmanager
5
+ import os
6
+ from ExoMACModel import ExoMACModel
7
+ from models.requests import PredictRequest
8
+ from models.responses import PredictResponse
9
+ from typing import Optional
10
+ from fastapi import HTTPException
11
+ import pandas as pd
12
+
13
+ @asynccontextmanager
14
+ async def lifespan(app: FastAPI):
15
+ model = ExoMACModel(
16
+ repo_id=os.getenv("EXOMAC_REPO", "ZapatoProgramming/ExoMAC-KKT"),
17
+ local_dir=os.getenv("EXOMAC_LOCAL_DIR", "ExoMACModel/ExoMAC-KKT"),
18
+ prefer_snapshot=True,
19
+ always_download=False,
20
+ verbose=True,
21
+ )
22
+ app.state.model = model
23
+ yield
24
+
25
+ app = FastAPI(
26
+ title="NASA SpaceApp API",
27
+ description="API para el proyecto NASA SpaceApp 2025",
28
+ version="1.0.0",
29
+ lifespan=lifespan
30
+ )
31
+
32
+ # Configurar CORS
33
+ app.add_middleware(
34
+ CORSMiddleware,
35
+ allow_origins=["*"],
36
+ allow_credentials=True,
37
+ allow_methods=["*"],
38
+ allow_headers=["*"],
39
+ )
40
+
41
+ @app.get("/")
42
+ async def root():
43
+ """Endpoint raíz de la API"""
44
+ return {
45
+ "message": "Bienvenido a NASA SpaceApp API",
46
+ "version": "1.0.0",
47
+ "docs": "/docs"
48
+ }
49
+
50
+ @app.get("/health")
51
+ async def health():
52
+ """Endpoint de health check"""
53
+ return {
54
+ "status": "healthy",
55
+ "timestamp": datetime.now().isoformat(),
56
+ "service": "NASA SpaceApp API"
57
+ }
58
+
59
+
60
+ @app.get("/test/predict")
61
+ async def test_predict():
62
+ """Endpoint de prueba para la predicción"""
63
+ return {
64
+ "status": 200,
65
+ "message": "SOY EL CHESTNUT",
66
+ }
67
+
68
+ @app.post("/predict", response_model=PredictResponse)
69
+ def predict(
70
+ req: PredictRequest,
71
+ ):
72
+ m: Optional[ExoMACModel] = getattr(app.state, "model", None)
73
+ if m is None:
74
+ raise HTTPException(503, "Model not loaded")
75
+
76
+ data = dict(req.features)
77
+
78
+ try:
79
+ label, probabilities = m.predict(
80
+ data,
81
+ return_proba=True,
82
+ compute_engineered_if_missing=True,
83
+ )
84
+ except Exception as e:
85
+ raise HTTPException(500, f"Prediction error")
86
+
87
+ cols = m.feature_columns
88
+ recognized = [c for c in cols if c in data]
89
+ unknown = [k for k in data.keys() if k not in cols]
90
+
91
+ used = m._ensure_engineered_features(dict(data))
92
+ X = pd.DataFrame([used], dtype=float).reindex(columns=cols)
93
+ missing = X.columns[X.iloc[0].isna()].tolist()
94
+
95
+ # Engineered features: those added beyond the original input keys
96
+ engineered_only = {k: used.get(k) for k in used.keys() if k not in data}
97
+ # JSON-safe (convert NaN to None and numpy floats to float)
98
+ engineered_json = {
99
+ k: (None if pd.isna(v) else float(v)) if isinstance(v, (int, float)) or hasattr(v, "__float__") else None
100
+ for k, v in engineered_only.items()
101
+ }
102
+
103
+ return PredictResponse(
104
+ label=label,
105
+ probabilities=probabilities,
106
+ recognized=recognized,
107
+ unknown=unknown,
108
+ missing=missing,
109
+ feature_order=cols,
110
+ engineered=engineered_json,
111
+ )