DeepRat commited on
Commit
e5c3ef3
·
verified ·
1 Parent(s): 85d983d

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +162 -12
main.py CHANGED
@@ -1,11 +1,22 @@
1
  # main.py
2
  import os
3
- from fastapi import FastAPI
 
4
  from fastapi.middleware.cors import CORSMiddleware
5
  from fastapi.responses import FileResponse
6
  from fastapi.staticfiles import StaticFiles
7
  from pydantic import BaseModel
8
  import requests
 
 
 
 
 
 
 
 
 
 
9
 
10
  # -------------------------------
11
  # CARGA DEL FLOW_API_URL DESDE SECRETS
@@ -14,6 +25,9 @@ FLOW_API_URL = os.getenv("FLOW_API_URL")
14
  if FLOW_API_URL is None:
15
  raise RuntimeError("❌ FLOW_API_URL no está definido. Agregalo en los Secrets de Hugging Face.")
16
 
 
 
 
17
  # -------------------------------
18
  # INICIALIZACIÓN DE LA APP
19
  # -------------------------------
@@ -22,7 +36,7 @@ app = FastAPI()
22
  # Middleware CORS
23
  app.add_middleware(
24
  CORSMiddleware,
25
- allow_origins=["*"], # Podés restringir esto si querés
26
  allow_credentials=True,
27
  allow_methods=["*"],
28
  allow_headers=["*"],
@@ -42,24 +56,160 @@ async def serve_index():
42
  class AnalyzeRequest(BaseModel):
43
  url: str
44
 
 
 
 
 
 
45
  # -------------------------------
46
  # ENDPOINT DE ANÁLISIS
47
  # -------------------------------
48
- @app.post("/analyze")
49
  async def analyze(request: AnalyzeRequest):
 
 
50
  try:
 
 
 
51
  payload = {
52
- "input_value": request.url,
53
  "output_type": "chat",
54
- "input_type": "chat"
 
55
  }
56
- headers = {"Content-Type": "application/json"}
57
- response = requests.post(FLOW_API_URL, json=payload, headers=headers)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  response.raise_for_status()
 
 
59
  data = response.json()
60
- result_text = data.get("result", "⚠️ No se encontró respuesta en el output.")
61
- return {"result": result_text}
62
- except requests.exceptions.RequestException as e:
63
- return {"result": f"❌ Error al conectarse al Flow: {e}"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  except Exception as e:
65
- return {"result": f" Error inesperado: {e}"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  # main.py
2
  import os
3
+ import logging
4
+ from fastapi import FastAPI, HTTPException
5
  from fastapi.middleware.cors import CORSMiddleware
6
  from fastapi.responses import FileResponse
7
  from fastapi.staticfiles import StaticFiles
8
  from pydantic import BaseModel
9
  import requests
10
+ from typing import Optional
11
+
12
+ # -------------------------------
13
+ # CONFIGURACIÓN DE LOGGING
14
+ # -------------------------------
15
+ logging.basicConfig(
16
+ level=logging.INFO,
17
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
18
+ )
19
+ logger = logging.getLogger(__name__)
20
 
21
  # -------------------------------
22
  # CARGA DEL FLOW_API_URL DESDE SECRETS
 
25
  if FLOW_API_URL is None:
26
  raise RuntimeError("❌ FLOW_API_URL no está definido. Agregalo en los Secrets de Hugging Face.")
27
 
28
+ # Log para verificar la URL (sin mostrar la URL completa por seguridad)
29
+ logger.info(f"✅ FLOW_API_URL configurado: {FLOW_API_URL[:30]}...")
30
+
31
  # -------------------------------
32
  # INICIALIZACIÓN DE LA APP
33
  # -------------------------------
 
36
  # Middleware CORS
37
  app.add_middleware(
38
  CORSMiddleware,
39
+ allow_origins=["*"],
40
  allow_credentials=True,
41
  allow_methods=["*"],
42
  allow_headers=["*"],
 
56
  class AnalyzeRequest(BaseModel):
57
  url: str
58
 
59
+ class AnalyzeResponse(BaseModel):
60
+ result: str
61
+ success: bool = True
62
+ error: Optional[str] = None
63
+
64
  # -------------------------------
65
  # ENDPOINT DE ANÁLISIS
66
  # -------------------------------
67
+ @app.post("/analyze", response_model=AnalyzeResponse)
68
  async def analyze(request: AnalyzeRequest):
69
+ logger.info(f"📥 Recibida solicitud de análisis para URL: {request.url}")
70
+
71
  try:
72
+ # IMPORTANTE: El flow espera un mensaje de chat que contenga la URL,
73
+ # no la URL directamente. El ChatInput procesará el mensaje y
74
+ # el URLComponent extraerá la URL del texto.
75
  payload = {
76
+ "input_value": request.url, # El ChatInput recibirá esto como mensaje
77
  "output_type": "chat",
78
+ "input_type": "chat",
79
+ "tweaks": {} # Agregar tweaks vacío por si acaso
80
  }
81
+
82
+ headers = {
83
+ "Content-Type": "application/json",
84
+ "User-Agent": "TrueEye-HuggingFace-Space/1.0"
85
+ }
86
+
87
+ logger.info(f"📤 Enviando petición a Langflow...")
88
+ logger.debug(f"Payload: {payload}")
89
+
90
+ # Hacer la petición con timeout de 300 segundos (5 minutos)
91
+ # dado que el flow tiene múltiples llamadas a modelos LLM
92
+ response = requests.post(
93
+ FLOW_API_URL,
94
+ json=payload,
95
+ headers=headers,
96
+ timeout=300 # 5 minutos de timeout
97
+ )
98
+
99
+ logger.info(f"📨 Respuesta recibida. Status: {response.status_code}")
100
+
101
+ # Verificar el status de la respuesta
102
  response.raise_for_status()
103
+
104
+ # Parsear la respuesta
105
  data = response.json()
106
+ logger.debug(f"Respuesta JSON: {data}")
107
+
108
+ # El formato de respuesta de Langflow puede variar
109
+ # Intentar extraer el resultado de diferentes formas
110
+ result_text = None
111
+
112
+ # Opción 1: Respuesta directa en 'result'
113
+ if isinstance(data, dict) and "result" in data:
114
+ result_text = data["result"]
115
+
116
+ # Opción 2: Respuesta en formato de outputs
117
+ elif isinstance(data, dict) and "outputs" in data:
118
+ outputs = data["outputs"]
119
+ if isinstance(outputs, list) and len(outputs) > 0:
120
+ output = outputs[0]
121
+ if "outputs" in output:
122
+ # Buscar el ChatOutput
123
+ for node_output in output["outputs"]:
124
+ if "message" in node_output:
125
+ if isinstance(node_output["message"], dict):
126
+ result_text = node_output["message"].get("text", "")
127
+ else:
128
+ result_text = str(node_output["message"])
129
+ break
130
+
131
+ # Opción 3: Intentar extraer de cualquier estructura
132
+ if not result_text and isinstance(data, dict):
133
+ # Buscar recursivamente cualquier campo 'text' o 'message'
134
+ result_text = _extract_text_from_response(data)
135
+
136
+ if not result_text:
137
+ logger.warning("⚠️ No se pudo extraer texto de la respuesta")
138
+ result_text = "⚠️ Se procesó la solicitud pero no se pudo extraer el resultado. Respuesta recibida: " + str(data)[:200]
139
+
140
+ logger.info("✅ Análisis completado exitosamente")
141
+ return AnalyzeResponse(result=result_text)
142
+
143
+ except requests.exceptions.Timeout:
144
+ logger.error("⏱️ Timeout en la petición a Langflow")
145
+ return AnalyzeResponse(
146
+ result="❌ Error: La solicitud tardó demasiado tiempo. El análisis puede ser muy complejo o el servicio está sobrecargado.",
147
+ success=False,
148
+ error="timeout"
149
+ )
150
+ except requests.exceptions.ConnectionError as e:
151
+ logger.error(f"🔌 Error de conexión: {e}")
152
+ return AnalyzeResponse(
153
+ result="❌ Error: No se pudo conectar con el servicio de análisis. Verifica que el FLOW_API_URL esté correctamente configurado.",
154
+ success=False,
155
+ error="connection"
156
+ )
157
+ except requests.exceptions.HTTPError as e:
158
+ logger.error(f"🚫 Error HTTP: {e}")
159
+ logger.error(f"Respuesta del servidor: {e.response.text if e.response else 'No hay respuesta'}")
160
+ return AnalyzeResponse(
161
+ result=f"❌ Error del servidor: {e}. Verifica que el flow esté activo y funcionando.",
162
+ success=False,
163
+ error=f"http_{e.response.status_code if e.response else 'unknown'}"
164
+ )
165
  except Exception as e:
166
+ logger.exception(f"💥 Error inesperado: {e}")
167
+ return AnalyzeResponse(
168
+ result=f"❌ Error inesperado: {str(e)}",
169
+ success=False,
170
+ error="unknown"
171
+ )
172
+
173
+ def _extract_text_from_response(data):
174
+ """Función auxiliar para extraer texto de una respuesta compleja"""
175
+ if isinstance(data, str):
176
+ return data
177
+
178
+ if isinstance(data, dict):
179
+ # Buscar campos comunes
180
+ for key in ['text', 'message', 'result', 'output', 'content']:
181
+ if key in data:
182
+ value = data[key]
183
+ if isinstance(value, str):
184
+ return value
185
+ elif isinstance(value, dict) or isinstance(value, list):
186
+ result = _extract_text_from_response(value)
187
+ if result:
188
+ return result
189
+
190
+ # Si no encontramos campos conocidos, buscar en todos los valores
191
+ for value in data.values():
192
+ if isinstance(value, (dict, list)):
193
+ result = _extract_text_from_response(value)
194
+ if result:
195
+ return result
196
+
197
+ elif isinstance(data, list):
198
+ for item in data:
199
+ result = _extract_text_from_response(item)
200
+ if result:
201
+ return result
202
+
203
+ return None
204
+
205
+ # -------------------------------
206
+ # ENDPOINT DE SALUD
207
+ # -------------------------------
208
+ @app.get("/health")
209
+ async def health_check():
210
+ """Endpoint para verificar que el servicio está funcionando"""
211
+ return {
212
+ "status": "healthy",
213
+ "flow_configured": bool(FLOW_API_URL),
214
+ "service": "TrueEye Reports"
215
+ }