GiusMagi commited on
Commit
9f3d804
Β·
verified Β·
1 Parent(s): 7f6e43f

Update server.py

Browse files
Files changed (1) hide show
  1. server.py +149 -100
server.py CHANGED
@@ -8,20 +8,19 @@ from pydantic import BaseModel
8
  import traceback
9
  import logging
10
  import sys
 
 
 
11
 
12
- # Setup logging piΓΉ dettagliato
13
  logging.basicConfig(
14
- level=logging.INFO,
15
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
16
  handlers=[logging.StreamHandler(sys.stdout)]
17
  )
18
  logger = logging.getLogger(__name__)
19
 
20
- app = FastAPI(
21
- title="Incassi API - Debug Mode",
22
- description="API per debug del modello incassi",
23
- version="debug-1.0"
24
- )
25
 
26
  app.add_middleware(
27
  CORSMiddleware,
@@ -31,53 +30,35 @@ app.add_middleware(
31
  allow_headers=["*"],
32
  )
33
 
34
- # Variabile globale per il modello
35
  mdl = None
36
 
37
- # ===== CARICAMENTO MODELLO CON STEP-BY-STEP DEBUG =====
 
 
 
 
38
  def load_model():
39
  global mdl
40
  try:
41
- logger.info("πŸ”§ STEP 1: Inizio caricamento modello...")
42
 
43
- # Verifica esistenza file
44
  import os
45
  if not os.path.exists("incassi_model.pkl"):
46
- raise FileNotFoundError("File incassi_model.pkl non trovato")
47
-
48
- file_size = os.path.getsize("incassi_model.pkl")
49
- logger.info(f"πŸ“ File trovato - Dimensione: {file_size} bytes")
50
 
51
- # Carica il modello
52
- logger.info("πŸ”§ STEP 2: Caricamento pickle...")
53
  with open("incassi_model.pkl", "rb") as f:
54
  mdl = cp.load(f)
55
 
56
- logger.info("πŸ”§ STEP 3: Modello caricato in memoria")
57
- logger.info(f"πŸ“‹ Tipo modello: {type(mdl)}")
58
- logger.info(f"πŸ“‹ Versione: {getattr(mdl, 'model_version', 'N/A')}")
59
 
60
- # Test attributi base (SENZA chiamare predict)
61
- logger.info("πŸ”§ STEP 4: Verifica attributi modello...")
62
- logger.info(f"πŸ“‹ p100_thr: {getattr(mdl, 'p100_thr', 'N/A')}")
63
- logger.info(f"πŸ“‹ feat_cols_full length: {len(getattr(mdl, 'feat_cols_full', []))}")
64
- logger.info(f"πŸ“‹ stage1 type: {type(getattr(mdl, 'stage1', None))}")
65
- logger.info(f"πŸ“‹ stage2 type: {type(getattr(mdl, 'stage2', None))}")
66
-
67
- logger.info("βœ… STEP 5: Modello caricato con successo (SENZA test predict)")
68
  return True
69
-
70
  except Exception as e:
71
- logger.error(f"❌ ERRORE nel caricamento modello: {e}")
72
- logger.error(f"❌ Traceback completo:\n{traceback.format_exc()}")
73
  return False
74
 
75
- # Carica modello all'import
76
  model_loaded = load_model()
77
- if not model_loaded:
78
- logger.error("❌ FATALE: Impossibile caricare il modello")
79
 
80
- # ===== PYDANTIC MODELS SEMPLIFICATI =====
81
  class PredictIn(BaseModel):
82
  Debitore_cluster: str | None = None
83
  Stato_Giudizio: str | None = None
@@ -95,9 +76,9 @@ class PredictIn(BaseModel):
95
  giorni_da_cessione: int | None = None
96
  Zona: str | None = None
97
 
98
- def _to_model_format(d: dict) -> pd.DataFrame:
99
- """Conversione input -> formato modello"""
100
- logger.info("πŸ”„ Conversione input in corso...")
101
 
102
  row = {
103
  "Debitore_cluster": d.get("Debitore_cluster"),
@@ -118,111 +99,179 @@ def _to_model_format(d: dict) -> pd.DataFrame:
118
  }
119
 
120
  df = pd.DataFrame([row])
121
- logger.info(f"βœ… DataFrame creato - Shape: {df.shape}")
122
  return df
123
 
124
- # ===== ENDPOINTS =====
125
  @app.get("/")
126
  def root():
127
  return {
128
  "ok": True,
129
- "service": "incassi-api-debug",
130
  "model_loaded": model_loaded,
131
- "model_version": getattr(mdl, "model_version", "N/A") if mdl else "N/A"
132
  }
133
 
134
  @app.get("/status")
135
  def status():
136
- """Status dettagliato del sistema"""
137
  if not mdl:
138
  return {"error": "Modello non caricato"}
139
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  try:
 
 
 
 
 
 
 
 
 
141
  return {
142
- "model_loaded": True,
143
- "model_type": str(type(mdl)),
144
- "model_version": getattr(mdl, "model_version", "N/A"),
145
- "p100_threshold": getattr(mdl, "p100_thr", "N/A"),
146
- "features_count": len(getattr(mdl, "feat_cols_full", [])),
147
- "stage1_loaded": hasattr(mdl, "stage1") and mdl.stage1 is not None,
148
- "stage2_loaded": hasattr(mdl, "stage2") and mdl.stage2 is not None,
149
  }
 
150
  except Exception as e:
151
- return {"error": f"Errore status: {e}"}
 
 
152
 
153
- @app.post("/test_simple")
154
- def test_simple(inp: PredictIn):
155
- """Test semplificato - solo conversione dati"""
156
  try:
157
- logger.info("πŸ§ͺ Test semplice avviato...")
158
 
159
  if not mdl:
160
  raise HTTPException(status_code=503, detail="Modello non caricato")
161
 
162
- # Solo conversione, SENZA predict
163
- df = _to_model_format(inp.dict())
164
- logger.info(f"βœ… Conversione riuscita: {df.shape}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
- # Test solo _ensure_raw_cols (metodo piΓΉ semplice)
167
- logger.info("πŸ”§ Test _ensure_raw_cols...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  df_ensured = mdl._ensure_raw_cols(df)
169
- logger.info(f"βœ… _ensure_raw_cols riuscito: {df_ensured.shape}")
170
 
171
- return {
172
- "status": "success",
173
- "input_shape": df.shape,
174
- "ensured_shape": df_ensured.shape,
175
- "columns": list(df.columns),
176
- }
177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  except Exception as e:
179
- logger.error(f"❌ Errore test_simple: {e}")
180
  logger.error(f"❌ Traceback:\n{traceback.format_exc()}")
181
- raise HTTPException(status_code=500, detail=str(e))
182
 
183
- @app.post("/predict")
184
  def predict(inp: PredictIn):
185
- """Predizione completa con debug step-by-step"""
186
  try:
187
- logger.info("πŸš€ PREDICT chiamato...")
188
 
189
  if not mdl:
190
  raise HTTPException(status_code=503, detail="Modello non caricato")
191
 
192
- # Step 1: Conversione
193
- logger.info("πŸ”§ Step 1: Conversione input...")
194
- df = _to_model_format(inp.dict())
195
 
196
- # Step 2: Predict con cattura errore specifica
197
- logger.info("πŸ”§ Step 2: Chiamata mdl.predict...")
198
- try:
199
  result = mdl.predict(df)
200
- logger.info("βœ… mdl.predict completato")
201
- except Exception as predict_error:
202
- logger.error(f"❌ ERRORE SPECIFICO in mdl.predict: {predict_error}")
203
- logger.error(f"❌ Tipo errore: {type(predict_error)}")
204
- logger.error(f"❌ Traceback predict:\n{traceback.format_exc()}")
205
- raise HTTPException(status_code=500, detail=f"Errore in predict: {predict_error}")
206
-
207
- # Step 3: Formattazione output
208
- logger.info("πŸ”§ Step 3: Formattazione output...")
209
- p100, prob_ord, yhat, final_class, _ = result
210
-
211
- response = {
212
- "p100": float(p100),
213
- "prob_ord": np.asarray(prob_ord, dtype=float).tolist(),
214
- "yhat": float(yhat),
215
- "final_class": str(final_class),
216
- }
217
 
218
- logger.info(f"βœ… Predizione completata: yhat={response['yhat']:.2f}")
219
- return response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
  except HTTPException:
222
  raise
223
  except Exception as e:
224
- logger.error(f"❌ ERRORE GENERALE in predict: {e}")
225
  logger.error(f"❌ Traceback:\n{traceback.format_exc()}")
226
- raise HTTPException(status_code=500, detail=str(e))
227
 
228
- logger.info("πŸš€ Server inizializzato - Modello caricato senza test predict")
 
8
  import traceback
9
  import logging
10
  import sys
11
+ import signal
12
+ import threading
13
+ import time
14
 
15
+ # Setup logging ultra-dettagliato
16
  logging.basicConfig(
17
+ level=logging.DEBUG,
18
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
19
  handlers=[logging.StreamHandler(sys.stdout)]
20
  )
21
  logger = logging.getLogger(__name__)
22
 
23
+ app = FastAPI(title="Incassi API - Super Debug", version="debug-2.0")
 
 
 
 
24
 
25
  app.add_middleware(
26
  CORSMiddleware,
 
30
  allow_headers=["*"],
31
  )
32
 
 
33
  mdl = None
34
 
35
+ # Funzione di timeout per debug
36
+ def timeout_handler(signum, frame):
37
+ logger.error("⏰ TIMEOUT! Operazione bloccata")
38
+ raise TimeoutError("Operazione bloccata oltre il timeout")
39
+
40
  def load_model():
41
  global mdl
42
  try:
43
+ logger.info("πŸ”§ Caricamento modello...")
44
 
 
45
  import os
46
  if not os.path.exists("incassi_model.pkl"):
47
+ raise FileNotFoundError("File non trovato")
 
 
 
48
 
 
 
49
  with open("incassi_model.pkl", "rb") as f:
50
  mdl = cp.load(f)
51
 
52
+ logger.info(f"βœ… Modello caricato: {type(mdl)}")
53
+ logger.info(f"πŸ“‹ Attributi: {dir(mdl)[:10]}...") # primi 10 attributi
 
54
 
 
 
 
 
 
 
 
 
55
  return True
 
56
  except Exception as e:
57
+ logger.error(f"❌ Errore caricamento: {e}")
 
58
  return False
59
 
 
60
  model_loaded = load_model()
 
 
61
 
 
62
  class PredictIn(BaseModel):
63
  Debitore_cluster: str | None = None
64
  Stato_Giudizio: str | None = None
 
76
  giorni_da_cessione: int | None = None
77
  Zona: str | None = None
78
 
79
+ def safe_to_model_format(d: dict) -> pd.DataFrame:
80
+ """Conversione sicura con timeout"""
81
+ logger.info("πŸ”„ Conversione input...")
82
 
83
  row = {
84
  "Debitore_cluster": d.get("Debitore_cluster"),
 
99
  }
100
 
101
  df = pd.DataFrame([row])
102
+ logger.info(f"βœ… DataFrame: {df.shape}, cols: {list(df.columns)[:5]}...")
103
  return df
104
 
 
105
  @app.get("/")
106
  def root():
107
  return {
108
  "ok": True,
109
+ "service": "incassi-super-debug",
110
  "model_loaded": model_loaded,
 
111
  }
112
 
113
  @app.get("/status")
114
  def status():
 
115
  if not mdl:
116
  return {"error": "Modello non caricato"}
117
 
118
+ return {
119
+ "model_loaded": True,
120
+ "model_type": str(type(mdl)),
121
+ "has_predict": hasattr(mdl, "predict"),
122
+ "has_stage1": hasattr(mdl, "stage1"),
123
+ "has_stage2": hasattr(mdl, "stage2"),
124
+ "methods": [m for m in dir(mdl) if not m.startswith('_')][:10]
125
+ }
126
+
127
+ @app.post("/test_conversion")
128
+ def test_conversion(inp: PredictIn):
129
+ """Test solo conversione dati"""
130
  try:
131
+ logger.info("πŸ§ͺ Test conversione...")
132
+
133
+ if not mdl:
134
+ raise HTTPException(status_code=503, detail="Modello non caricato")
135
+
136
+ # Solo conversione
137
+ df = safe_to_model_format(inp.dict())
138
+ logger.info("βœ… Conversione OK")
139
+
140
  return {
141
+ "status": "conversion_ok",
142
+ "shape": df.shape,
143
+ "columns_sample": list(df.columns)[:10],
144
+ "first_row_sample": {k: str(v)[:50] for k, v in df.iloc[0].to_dict().items() if k in list(df.columns)[:5]}
 
 
 
145
  }
146
+
147
  except Exception as e:
148
+ logger.error(f"❌ Errore conversione: {e}")
149
+ logger.error(f"❌ Traceback:\n{traceback.format_exc()}")
150
+ raise HTTPException(status_code=500, detail=f"Errore conversione: {str(e)}")
151
 
152
+ @app.post("/test_ensure_cols")
153
+ def test_ensure_cols(inp: PredictIn):
154
+ """Test solo _ensure_raw_cols"""
155
  try:
156
+ logger.info("πŸ§ͺ Test ensure_raw_cols...")
157
 
158
  if not mdl:
159
  raise HTTPException(status_code=503, detail="Modello non caricato")
160
 
161
+ df = safe_to_model_format(inp.dict())
162
+ logger.info("πŸ”§ Chiamata _ensure_raw_cols...")
163
+
164
+ # Test con timeout di 10 secondi
165
+ def run_ensure():
166
+ return mdl._ensure_raw_cols(df)
167
+
168
+ # Esegui in thread separato per timeout
169
+ import concurrent.futures
170
+ with concurrent.futures.ThreadPoolExecutor() as executor:
171
+ future = executor.submit(run_ensure)
172
+ try:
173
+ df_ensured = future.result(timeout=10)
174
+ logger.info("βœ… _ensure_raw_cols OK")
175
+ return {
176
+ "status": "ensure_cols_ok",
177
+ "original_shape": df.shape,
178
+ "ensured_shape": df_ensured.shape
179
+ }
180
+ except concurrent.futures.TimeoutError:
181
+ logger.error("⏰ _ensure_raw_cols TIMEOUT")
182
+ raise HTTPException(status_code=408, detail="_ensure_raw_cols timeout")
183
 
184
+ except HTTPException:
185
+ raise
186
+ except Exception as e:
187
+ logger.error(f"❌ Errore ensure_cols: {e}")
188
+ logger.error(f"❌ Traceback:\n{traceback.format_exc()}")
189
+ raise HTTPException(status_code=500, detail=f"Errore ensure_cols: {str(e)}")
190
+
191
+ @app.post("/test_preprocess")
192
+ def test_preprocess(inp: PredictIn):
193
+ """Test solo _preprocess_apply"""
194
+ try:
195
+ logger.info("πŸ§ͺ Test preprocess...")
196
+
197
+ if not mdl:
198
+ raise HTTPException(status_code=503, detail="Modello non caricato")
199
+
200
+ df = safe_to_model_format(inp.dict())
201
  df_ensured = mdl._ensure_raw_cols(df)
 
202
 
203
+ logger.info("πŸ”§ Chiamata _preprocess_apply...")
204
+
205
+ # Test con timeout
206
+ def run_preprocess():
207
+ return mdl._preprocess_apply(df_ensured)
 
208
 
209
+ import concurrent.futures
210
+ with concurrent.futures.ThreadPoolExecutor() as executor:
211
+ future = executor.submit(run_preprocess)
212
+ try:
213
+ df_processed = future.result(timeout=15)
214
+ logger.info("βœ… _preprocess_apply OK")
215
+ return {
216
+ "status": "preprocess_ok",
217
+ "processed_shape": df_processed.shape,
218
+ "processed_columns_count": len(df_processed.columns)
219
+ }
220
+ except concurrent.futures.TimeoutError:
221
+ logger.error("⏰ _preprocess_apply TIMEOUT")
222
+ raise HTTPException(status_code=408, detail="_preprocess_apply timeout")
223
+
224
+ except HTTPException:
225
+ raise
226
  except Exception as e:
227
+ logger.error(f"❌ Errore preprocess: {e}")
228
  logger.error(f"❌ Traceback:\n{traceback.format_exc()}")
229
+ raise HTTPException(status_code=500, detail=f"Errore preprocess: {str(e)}")
230
 
231
+ @app.post("/predict")
232
  def predict(inp: PredictIn):
233
+ """Predizione completa con timeout estremo"""
234
  try:
235
+ logger.info("πŸš€ PREDICT con timeout...")
236
 
237
  if not mdl:
238
  raise HTTPException(status_code=503, detail="Modello non caricato")
239
 
240
+ df = safe_to_model_format(inp.dict())
 
 
241
 
242
+ # Predict con timeout di 30 secondi
243
+ def run_predict():
244
+ logger.info("πŸ”§ Esecuzione mdl.predict()...")
245
  result = mdl.predict(df)
246
+ logger.info("βœ… mdl.predict() completato")
247
+ return result
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
 
249
+ import concurrent.futures
250
+ with concurrent.futures.ThreadPoolExecutor() as executor:
251
+ future = executor.submit(run_predict)
252
+ try:
253
+ result = future.result(timeout=30)
254
+
255
+ p100, prob_ord, yhat, final_class, _ = result
256
+ response = {
257
+ "p100": float(p100),
258
+ "prob_ord": np.asarray(prob_ord, dtype=float).tolist(),
259
+ "yhat": float(yhat),
260
+ "final_class": str(final_class),
261
+ }
262
+
263
+ logger.info(f"βœ… Predizione completata: {response['yhat']:.2f}")
264
+ return response
265
+
266
+ except concurrent.futures.TimeoutError:
267
+ logger.error("⏰ PREDICT TIMEOUT dopo 30 secondi")
268
+ raise HTTPException(status_code=408, detail="Predizione timeout - modello bloccato")
269
 
270
  except HTTPException:
271
  raise
272
  except Exception as e:
273
+ logger.error(f"❌ ERRORE PREDICT: {e}")
274
  logger.error(f"❌ Traceback:\n{traceback.format_exc()}")
275
+ raise HTTPException(status_code=500, detail=f"Errore predict: {str(e)}")
276
 
277
+ logger.info("πŸš€ Super Debug Server inizializzato")