Files changed (1) hide show
  1. app.py +62 -62
app.py CHANGED
@@ -11,42 +11,42 @@ from typing import Dict, List, Any
11
  os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
12
  os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
13
 
14
- print("🚀 Iniciando Eco Finder API...")
15
 
16
- # Configuración
17
  try:
18
  import tensorflow as tf
19
  print(f"✅ TensorFlow version: {tf.__version__}")
20
  from tensorflow.keras.models import load_model
21
  TENSORFLOW_AVAILABLE = True
22
  except ImportError as e:
23
- print(f"❌ TensorFlow no disponible: {e}")
24
  TENSORFLOW_AVAILABLE = False
25
 
26
- # Cargar recursos
27
  def load_resources():
28
  try:
29
  with open("feature_stats.json", "r") as f:
30
  feature_stats = json.load(f)
31
- print("✅ Feature stats cargado")
32
 
33
  with open("scaler.pkl", "rb") as f:
34
  scaler = pickle.load(f)
35
- print("✅ Scaler cargado")
36
 
37
  with open("label_encoder.pkl", "rb") as f:
38
  label_encoder = pickle.load(f)
39
- print("✅ Label encoder cargado")
40
 
41
  model = None
42
  if TENSORFLOW_AVAILABLE:
43
  model = load_model("modulo_tabular.h5")
44
- print("✅ Modelo cargado")
45
 
46
  return model, scaler, label_encoder, feature_stats
47
 
48
  except Exception as e:
49
- print(f"❌ Error cargando recursos: {str(e)}")
50
  feature_stats = {
51
  "feature_columns": [
52
  "koi_period", "koi_duration", "koi_depth", "koi_prad",
@@ -62,28 +62,28 @@ def load_resources():
62
  }
63
  return None, None, None, feature_stats
64
 
65
- # Cargar recursos
66
  model, scaler, label_encoder, feature_stats = load_resources()
67
  feature_columns = feature_stats.get("feature_columns", [])
68
  train_medians = feature_stats.get("train_medians", {})
69
 
70
  BASE = "https://exoplanetarchive.ipac.caltech.edu/cgi-bin/nstedAPI/nph-nstedAPI"
71
 
72
- # ==================== FUNCIONES PARA GRADIO ====================
73
 
74
  def predict_single(features: Dict) -> Dict:
75
- """Función para predecir un solo objeto - USADA POR GRADIO"""
76
  try:
77
  if model is None or scaler is None or label_encoder is None:
78
- return {"error": "Modelo no disponible"}
79
 
80
- # Crear array de características
81
  input_features = []
82
  for feature in feature_columns:
83
  value = features.get(feature, train_medians.get(feature, 0))
84
  input_features.append(float(value))
85
 
86
- # Predecir
87
  input_array = np.array([input_features])
88
  X_input = scaler.transform(input_array)
89
 
@@ -114,7 +114,7 @@ def predict_from_dict(
114
  koi_steff: float, koi_slogg: float, koi_smet: float,
115
  koi_kepmag: float, koi_model_snr: float, koi_num_transits: float
116
  ) -> Dict:
117
- """Wrapper que toma parámetros individuales y los convierte a dict"""
118
  features = {
119
  "koi_period": koi_period,
120
  "koi_duration": koi_duration,
@@ -131,29 +131,29 @@ def predict_from_dict(
131
  }
132
  return predict_single(features)
133
 
134
- def predict_toi_realtime():
135
- """Función para TOI en tiempo real"""
136
  try:
137
  if model is None or scaler is None or label_encoder is None:
138
- return "❌ Modelo no disponible"
139
 
140
- # Consultar API de exoplanetas
141
  where = ("(tfopwg_disp like 'PC' or tfopwg_disp like 'APC') "
142
  "and (pl_orbper is not null or tce_period is not null)")
143
 
144
- params = {"table": "toi", "where": where, "format": "csv"}
145
  resp = requests.get(BASE, params=params, timeout=60)
146
  resp.raise_for_status()
147
- toi_df = pd.read_csv(io.StringIO(resp.text))
148
 
149
- if toi_df.empty:
150
- return "❌ No se encontraron objetos TOI"
151
 
152
- # Tomar muestra
153
- toi_sample = toi_df.sample(min(3, len(toi_df)), random_state=7)
154
- toi_sample.columns = [c.strip().lower() for c in toi_sample.columns]
155
 
156
- # Mapeo de sinónimos
157
  candidates_map = {
158
  "koi_period": ["pl_orbper", "tce_period", "orbper", "period"],
159
  "koi_duration": ["pl_trandurh", "tce_duration", "tran_dur", "trandur", "duration", "dur"],
@@ -179,11 +179,11 @@ def predict_toi_realtime():
179
  return found[0]
180
  return None
181
 
182
- cols_set = set(toi_sample.columns)
183
  results = []
184
 
185
- for idx, row in toi_sample.iterrows():
186
- # Preparar características
187
  features = {}
188
  for feat in feature_columns:
189
  src = first_present(candidates_map.get(feat, []), cols_set)
@@ -192,24 +192,24 @@ def predict_toi_realtime():
192
  else:
193
  features[feat] = train_medians.get(feat, 0)
194
 
195
- # Predecir
196
  result = predict_single(features)
197
 
198
  if "error" not in result:
199
  results.append({
200
- "TOI": row.get('toi', f"TOI-{idx}"),
201
- "Disposición": row.get('tfopwg_disp', 'Unknown'),
202
- "Predicción": result['prediction'],
203
- "P(Confirmado)": f"{result['probabilities']['CONFIRMED']:.3f}",
204
- "P(Candidato)": f"{result['probabilities']['CANDIDATE']:.3f}",
205
- "P(Falso Positivo)": f"{result['probabilities']['FALSE_POSITIVE']:.3f}"
206
  })
207
 
208
  if not results:
209
- return "❌ No se pudieron generar predicciones"
210
 
211
  result_df = pd.DataFrame(results)
212
- return f"**Predicciones TOI:**\n\n{result_df.to_markdown(index=False)}"
213
 
214
  except Exception as e:
215
  return f"❌ Error: {str(e)}"
@@ -217,7 +217,7 @@ def predict_toi_realtime():
217
  def predict_manual(
218
  period, duration, depth, prad, srad, teq, steff, slogg, smet, kepmag, snr, num_transits
219
  ):
220
- """Función para predicción manual en Gradio"""
221
  try:
222
  result = predict_from_dict(
223
  period, duration, depth, prad, srad, teq, steff, slogg, smet, kepmag, snr, num_transits
@@ -226,7 +226,7 @@ def predict_manual(
226
  if "error" in result:
227
  return f"❌ {result['error']}"
228
 
229
- output = f"**Predicción:** {result['prediction']}\n\n**Probabilidades:**\n"
230
  for clase, prob in result['probabilities'].items():
231
  output += f"- {clase}: {prob:.3f}\n"
232
 
@@ -235,21 +235,21 @@ def predict_manual(
235
  except Exception as e:
236
  return f"❌ Error: {str(e)}"
237
 
238
- # ==================== INTERFAZ GRADIO ====================
239
 
240
  with gr.Blocks(theme=gr.themes.Soft(), title="Eco Finder API") as demo:
241
  gr.Markdown("# 🌌 Eco Finder API")
242
- gr.Markdown("Clasificador de exoplanetas")
243
 
244
- with gr.Tab("🎯 Predicción API"):
245
- gr.Markdown("### Endpoint para consumo desde frontend")
246
  gr.Markdown("""
247
  **URL:** `https://jarpalucas-echo-finder-api.hf.space/api/predict`
248
 
249
- **Método:** POST
250
  **Content-Type:** application/json
251
 
252
- **Ejemplo de uso con curl:**
253
  ```bash
254
  curl -X POST "https://jarpalucas-echo-finder-api.hf.space/api/predict" \\
255
  -H "Content-Type: application/json" \\
@@ -270,7 +270,7 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Eco Finder API") as demo:
270
  ```
271
  """)
272
 
273
- # Inputs para probar la API localmente
274
  with gr.Row():
275
  with gr.Column():
276
  period = gr.Number(label="koi_period", value=10.0)
@@ -288,7 +288,7 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Eco Finder API") as demo:
288
  snr = gr.Number(label="koi_model_snr", value=10.0)
289
  num_transits = gr.Number(label="koi_num_transits", value=3.0)
290
 
291
- api_btn = gr.Button("🚀 Probar Predicción")
292
  api_output = gr.JSON()
293
 
294
  api_btn.click(
@@ -297,15 +297,15 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Eco Finder API") as demo:
297
  outputs=api_output
298
  )
299
 
300
- with gr.Tab("🔭 TOI Tiempo Real"):
301
- gr.Markdown("Predicciones de objetos TOI en tiempo real")
302
- toi_btn = gr.Button("🔍 Analizar TOI")
303
- toi_output = gr.Markdown()
304
- toi_btn.click(predict_toi_realtime, outputs=toi_output)
305
 
306
- with gr.Tab("📊 Interfaz Manual"):
307
- gr.Markdown("Interfaz manual para predicciones")
308
- manual_btn = gr.Button("🎯 Predecir")
309
  manual_output = gr.Markdown()
310
  manual_btn.click(
311
  fn=predict_manual,
@@ -313,9 +313,9 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Eco Finder API") as demo:
313
  outputs=manual_output
314
  )
315
 
316
- print("🎉 Aplicación iniciada correctamente!")
317
- print("🌐 Interfaz disponible en: /")
318
- print("🔗 Endpoint API disponible en: /api/predict")
319
 
320
  if __name__ == "__main__":
321
- demo.launch(server_name="0.0.0.0", server_port=7860, share=False)
 
11
  os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
12
  os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
13
 
14
+ print("🚀 Starting Eco Finder API...")
15
 
16
+ # Configuration
17
  try:
18
  import tensorflow as tf
19
  print(f"✅ TensorFlow version: {tf.__version__}")
20
  from tensorflow.keras.models import load_model
21
  TENSORFLOW_AVAILABLE = True
22
  except ImportError as e:
23
+ print(f"❌ TensorFlow not available: {e}")
24
  TENSORFLOW_AVAILABLE = False
25
 
26
+ # Load resources
27
  def load_resources():
28
  try:
29
  with open("feature_stats.json", "r") as f:
30
  feature_stats = json.load(f)
31
+ print("✅ Feature stats loaded")
32
 
33
  with open("scaler.pkl", "rb") as f:
34
  scaler = pickle.load(f)
35
+ print("✅ Scaler loaded")
36
 
37
  with open("label_encoder.pkl", "rb") as f:
38
  label_encoder = pickle.load(f)
39
+ print("✅ Label encoder loaded")
40
 
41
  model = None
42
  if TENSORFLOW_AVAILABLE:
43
  model = load_model("modulo_tabular.h5")
44
+ print("✅ Model loaded")
45
 
46
  return model, scaler, label_encoder, feature_stats
47
 
48
  except Exception as e:
49
+ print(f"❌ Error loading resources: {str(e)}")
50
  feature_stats = {
51
  "feature_columns": [
52
  "koi_period", "koi_duration", "koi_depth", "koi_prad",
 
62
  }
63
  return None, None, None, feature_stats
64
 
65
+ # Load resources
66
  model, scaler, label_encoder, feature_stats = load_resources()
67
  feature_columns = feature_stats.get("feature_columns", [])
68
  train_medians = feature_stats.get("train_medians", {})
69
 
70
  BASE = "https://exoplanetarchive.ipac.caltech.edu/cgi-bin/nstedAPI/nph-nstedAPI"
71
 
72
+ # ==================== FUNCTIONS FOR GRADIO ====================
73
 
74
  def predict_single(features: Dict) -> Dict:
75
+ """Function to predict a single object - USED BY GRADIO"""
76
  try:
77
  if model is None or scaler is None or label_encoder is None:
78
+ return {"error": "Model not available"}
79
 
80
+ # Create feature array
81
  input_features = []
82
  for feature in feature_columns:
83
  value = features.get(feature, train_medians.get(feature, 0))
84
  input_features.append(float(value))
85
 
86
+ # Predict
87
  input_array = np.array([input_features])
88
  X_input = scaler.transform(input_array)
89
 
 
114
  koi_steff: float, koi_slogg: float, koi_smet: float,
115
  koi_kepmag: float, koi_model_snr: float, koi_num_transits: float
116
  ) -> Dict:
117
+ """Wrapper that takes individual parameters and converts them to dict"""
118
  features = {
119
  "koi_period": koi_period,
120
  "koi_duration": koi_duration,
 
131
  }
132
  return predict_single(features)
133
 
134
+ def predict_koi_realtime():
135
+ """Function for real-time KOI"""
136
  try:
137
  if model is None or scaler is None or label_encoder is None:
138
+ return "❌ Model not available"
139
 
140
+ # Query exoplanet API
141
  where = ("(tfopwg_disp like 'PC' or tfopwg_disp like 'APC') "
142
  "and (pl_orbper is not null or tce_period is not null)")
143
 
144
+ params = {"table": "koi", "where": where, "format": "csv"}
145
  resp = requests.get(BASE, params=params, timeout=60)
146
  resp.raise_for_status()
147
+ koi_df = pd.read_csv(io.StringIO(resp.text))
148
 
149
+ if koi_df.empty:
150
+ return "❌ No KOI objects found"
151
 
152
+ # Take sample
153
+ koi_sample = koi_df.sample(min(3, len(koi_df)), random_state=7)
154
+ koi_sample.columns = [c.strip().lower() for c in koi_sample.columns]
155
 
156
+ # Synonym mapping
157
  candidates_map = {
158
  "koi_period": ["pl_orbper", "tce_period", "orbper", "period"],
159
  "koi_duration": ["pl_trandurh", "tce_duration", "tran_dur", "trandur", "duration", "dur"],
 
179
  return found[0]
180
  return None
181
 
182
+ cols_set = set(koi_sample.columns)
183
  results = []
184
 
185
+ for idx, row in koi_sample.iterrows():
186
+ # Prepare features
187
  features = {}
188
  for feat in feature_columns:
189
  src = first_present(candidates_map.get(feat, []), cols_set)
 
192
  else:
193
  features[feat] = train_medians.get(feat, 0)
194
 
195
+ # Predict
196
  result = predict_single(features)
197
 
198
  if "error" not in result:
199
  results.append({
200
+ "KOI": row.get('koi', f"KOI-{idx}"),
201
+ "Disposition": row.get('tfopwg_disp', 'Unknown'),
202
+ "Prediction": result['prediction'],
203
+ "P(Confirmed)": f"{result['probabilities']['CONFIRMED']:.3f}",
204
+ "P(Candidate)": f"{result['probabilities']['CANDIDATE']:.3f}",
205
+ "P(False Positive)": f"{result['probabilities']['FALSE_POSITIVE']:.3f}"
206
  })
207
 
208
  if not results:
209
+ return "❌ Could not generate predictions"
210
 
211
  result_df = pd.DataFrame(results)
212
+ return f"**KOI Predictions:**\n\n{result_df.to_markdown(index=False)}"
213
 
214
  except Exception as e:
215
  return f"❌ Error: {str(e)}"
 
217
  def predict_manual(
218
  period, duration, depth, prad, srad, teq, steff, slogg, smet, kepmag, snr, num_transits
219
  ):
220
+ """Function for manual prediction in Gradio"""
221
  try:
222
  result = predict_from_dict(
223
  period, duration, depth, prad, srad, teq, steff, slogg, smet, kepmag, snr, num_transits
 
226
  if "error" in result:
227
  return f"❌ {result['error']}"
228
 
229
+ output = f"**Prediction:** {result['prediction']}\n\n**Probabilities:**\n"
230
  for clase, prob in result['probabilities'].items():
231
  output += f"- {clase}: {prob:.3f}\n"
232
 
 
235
  except Exception as e:
236
  return f"❌ Error: {str(e)}"
237
 
238
+ # ==================== GRADIO INTERFACE ====================
239
 
240
  with gr.Blocks(theme=gr.themes.Soft(), title="Eco Finder API") as demo:
241
  gr.Markdown("# 🌌 Eco Finder API")
242
+ gr.Markdown("Exoplanet classifier")
243
 
244
+ with gr.Tab("🎯 API Prediction"):
245
+ gr.Markdown("### Endpoint for frontend consumption")
246
  gr.Markdown("""
247
  **URL:** `https://jarpalucas-echo-finder-api.hf.space/api/predict`
248
 
249
+ **Method:** POST
250
  **Content-Type:** application/json
251
 
252
+ **Usage example with curl:**
253
  ```bash
254
  curl -X POST "https://jarpalucas-echo-finder-api.hf.space/api/predict" \\
255
  -H "Content-Type: application/json" \\
 
270
  ```
271
  """)
272
 
273
+ # Inputs to test the API locally
274
  with gr.Row():
275
  with gr.Column():
276
  period = gr.Number(label="koi_period", value=10.0)
 
288
  snr = gr.Number(label="koi_model_snr", value=10.0)
289
  num_transits = gr.Number(label="koi_num_transits", value=3.0)
290
 
291
+ api_btn = gr.Button("🚀 Test Prediction")
292
  api_output = gr.JSON()
293
 
294
  api_btn.click(
 
297
  outputs=api_output
298
  )
299
 
300
+ with gr.Tab("🔭 Real-time KOI"):
301
+ gr.Markdown("Real-time KOI object predictions")
302
+ koi_btn = gr.Button("🔍 Analyze KOI")
303
+ koi_output = gr.Markdown()
304
+ koi_btn.click(predict_koi_realtime, outputs=koi_output)
305
 
306
+ with gr.Tab("📊 Manual Interface"):
307
+ gr.Markdown("Manual interface for predictions")
308
+ manual_btn = gr.Button("🎯 Predict")
309
  manual_output = gr.Markdown()
310
  manual_btn.click(
311
  fn=predict_manual,
 
313
  outputs=manual_output
314
  )
315
 
316
+ print("🎉 Application started successfully!")
317
+ print("🌐 Interface available at: /")
318
+ print("🔗 API endpoint available at: /api/predict")
319
 
320
  if __name__ == "__main__":
321
+ demo.launch(server_name="0.0.0.0", server_port=7860, share=False)