DeepRat commited on
Commit
f8a4504
·
verified ·
1 Parent(s): c0d1a99

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +70 -133
main.py CHANGED
@@ -24,10 +24,15 @@ logger = logging.getLogger(__name__)
24
  FLOW_API_URL = os.getenv("FLOW_API_URL")
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
  # -------------------------------
@@ -55,51 +60,25 @@ async def serve_index():
55
  # -------------------------------
56
  @app.get("/static/te.png")
57
  async def serve_logo():
58
- """Sirve el logo te.png si existe, o un SVG placeholder si no"""
59
  logo_path = "static/te.png"
60
-
61
  if os.path.exists(logo_path):
62
- # Si existe el logo, servirlo normalmente
63
  return FileResponse(logo_path)
64
- else:
65
- # Si no existe, devolver un SVG placeholder
66
- svg_content = '''<svg width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
67
- <!-- Fondo circular -->
68
  <circle cx="20" cy="20" r="18" fill="#f6ae2d"/>
69
-
70
- <!-- Ojo estilizado -->
71
- <g transform="translate(20, 20)">
72
- <!-- Forma del ojo -->
73
- <path d="M -12 0 Q -6 -6 0 -6 Q 6 -6 12 0 Q 6 6 0 6 Q -6 6 -12 0"
74
- fill="#420909"
75
- stroke="none"/>
76
-
77
- <!-- Iris -->
78
  <circle cx="0" cy="0" r="5" fill="#f6ae2d"/>
79
-
80
- <!-- Pupila -->
81
  <circle cx="0" cy="0" r="3" fill="#420909"/>
82
-
83
- <!-- Brillo -->
84
  <circle cx="-1" cy="-1" r="1" fill="white" opacity="0.8"/>
85
  </g>
86
-
87
- <!-- Texto TE -->
88
- <text x="20" y="35" font-family="Arial, sans-serif" font-size="8" font-weight="bold"
89
  text-anchor="middle" fill="#420909">TE</text>
90
  </svg>'''
91
-
92
- return Response(
93
- content=svg_content,
94
- media_type="image/svg+xml",
95
- headers={
96
- "Cache-Control": "public, max-age=3600",
97
- "Content-Type": "image/svg+xml"
98
- }
99
- )
100
 
101
  # -------------------------------
102
- # MODELO DE ENTRADA
103
  # -------------------------------
104
  class AnalyzeRequest(BaseModel):
105
  url: str
@@ -115,139 +94,98 @@ class AnalyzeResponse(BaseModel):
115
  @app.post("/analyze", response_model=AnalyzeResponse)
116
  async def analyze(request: AnalyzeRequest):
117
  logger.info(f"📥 Recibida solicitud de análisis para URL: {request.url}")
118
-
 
 
 
 
 
 
 
 
 
 
119
  try:
120
- # IMPORTANTE: El flow espera un mensaje de chat que contenga la URL,
121
- # no la URL directamente. El ChatInput procesará el mensaje y
122
- # el URLComponent extraerá la URL del texto.
123
- payload = {
124
- "input_value": request.url, # El ChatInput recibirá esto como mensaje
125
- "output_type": "chat",
126
- "input_type": "chat",
127
- "tweaks": {} # Agregar tweaks vacío por si acaso
128
- }
129
-
130
- headers = {
131
- "Content-Type": "application/json",
132
- "User-Agent": "TrueEye-HuggingFace-Space/1.0"
133
- }
134
-
135
- logger.info(f"📤 Enviando petición a Langflow...")
136
- logger.debug(f"Payload: {payload}")
137
-
138
- # Hacer la petición con timeout de 300 segundos (5 minutos)
139
- # dado que el flow tiene múltiples llamadas a modelos LLM
140
  response = requests.post(
141
- FLOW_API_URL,
142
- json=payload,
143
  headers=headers,
144
- timeout=300 # 5 minutos de timeout
145
  )
146
-
147
  logger.info(f"📨 Respuesta recibida. Status: {response.status_code}")
148
-
149
- # Verificar el status de la respuesta
150
  response.raise_for_status()
151
-
152
- # Parsear la respuesta
153
  data = response.json()
154
- logger.debug(f"Respuesta JSON: {data}")
155
-
156
- # El formato de respuesta de Langflow puede variar
157
- # Intentar extraer el resultado de diferentes formas
158
  result_text = None
159
-
160
- # Opción 1: Respuesta directa en 'result'
161
  if isinstance(data, dict) and "result" in data:
162
  result_text = data["result"]
163
-
164
- # Opción 2: Respuesta en formato de outputs
165
  elif isinstance(data, dict) and "outputs" in data:
166
  outputs = data["outputs"]
167
- if isinstance(outputs, list) and len(outputs) > 0:
168
- output = outputs[0]
169
- if "outputs" in output:
170
- # Buscar el ChatOutput
171
- for node_output in output["outputs"]:
172
- if "message" in node_output:
173
- if isinstance(node_output["message"], dict):
174
- result_text = node_output["message"].get("text", "")
175
- else:
176
- result_text = str(node_output["message"])
177
- break
178
-
179
- # Opción 3: Intentar extraer de cualquier estructura
180
- if not result_text and isinstance(data, dict):
181
- # Buscar recursivamente cualquier campo 'text' o 'message'
182
- result_text = _extract_text_from_response(data)
183
-
184
  if not result_text:
185
- logger.warning("⚠️ No se pudo extraer texto de la respuesta")
186
- result_text = "⚠️ Se procesó la solicitud pero no se pudo extraer el resultado. Respuesta recibida: " + str(data)[:200]
187
-
188
  logger.info("✅ Análisis completado exitosamente")
189
  return AnalyzeResponse(result=result_text)
190
-
191
  except requests.exceptions.Timeout:
192
  logger.error("⏱️ Timeout en la petición a Langflow")
193
  return AnalyzeResponse(
194
- result="❌ Error: La solicitud tardó demasiado tiempo. El análisis puede ser muy complejo o el servicio está sobrecargado.",
195
- success=False,
196
- error="timeout"
197
  )
198
  except requests.exceptions.ConnectionError as e:
199
  logger.error(f"🔌 Error de conexión: {e}")
200
  return AnalyzeResponse(
201
- result="❌ Error: No se pudo conectar con el servicio de análisis. Verifica que el FLOW_API_URL esté correctamente configurado.",
202
- success=False,
203
- error="connection"
204
  )
205
  except requests.exceptions.HTTPError as e:
206
- logger.error(f"🚫 Error HTTP: {e}")
207
- logger.error(f"Respuesta del servidor: {e.response.text if e.response else 'No hay respuesta'}")
208
  return AnalyzeResponse(
209
- result=f"❌ Error del servidor: {e}. Verifica que el flow esté activo y funcionando.",
210
- success=False,
211
- error=f"http_{e.response.status_code if e.response else 'unknown'}"
212
  )
213
  except Exception as e:
214
  logger.exception(f"💥 Error inesperado: {e}")
215
  return AnalyzeResponse(
216
- result=f"❌ Error inesperado: {str(e)}",
217
- success=False,
218
- error="unknown"
219
  )
220
 
221
  def _extract_text_from_response(data):
222
- """Función auxiliar para extraer texto de una respuesta compleja"""
223
  if isinstance(data, str):
224
  return data
225
-
226
  if isinstance(data, dict):
227
- # Buscar campos comunes
228
- for key in ['text', 'message', 'result', 'output', 'content']:
229
- if key in data:
230
- value = data[key]
231
- if isinstance(value, str):
232
- return value
233
- elif isinstance(value, dict) or isinstance(value, list):
234
- result = _extract_text_from_response(value)
235
- if result:
236
- return result
237
-
238
- # Si no encontramos campos conocidos, buscar en todos los valores
239
- for value in data.values():
240
- if isinstance(value, (dict, list)):
241
- result = _extract_text_from_response(value)
242
- if result:
243
- return result
244
-
245
- elif isinstance(data, list):
246
  for item in data:
247
- result = _extract_text_from_response(item)
248
- if result:
249
- return result
250
-
251
  return None
252
 
253
  # -------------------------------
@@ -255,7 +193,6 @@ def _extract_text_from_response(data):
255
  # -------------------------------
256
  @app.get("/health")
257
  async def health_check():
258
- """Endpoint para verificar que el servicio está funcionando"""
259
  return {
260
  "status": "healthy",
261
  "flow_configured": bool(FLOW_API_URL),
 
24
  FLOW_API_URL = os.getenv("FLOW_API_URL")
25
  if FLOW_API_URL is None:
26
  raise RuntimeError("❌ FLOW_API_URL no está definido. Agregalo en los Secrets de Hugging Face.")
 
 
27
  logger.info(f"✅ FLOW_API_URL configurado: {FLOW_API_URL[:30]}...")
28
 
29
+ # -------------------------------
30
+ # CARGA DEL LANGFLOW_API_KEY DESDE SECRETS
31
+ # -------------------------------
32
+ LANGFLOW_API_KEY = os.getenv("LANGFLOW_API_KEY")
33
+ if LANGFLOW_API_KEY is None:
34
+ raise RuntimeError("❌ LANGFLOW_API_KEY no está definido. Agregalo en los Secrets de Hugging Face.")
35
+
36
  # -------------------------------
37
  # INICIALIZACIÓN DE LA APP
38
  # -------------------------------
 
60
  # -------------------------------
61
  @app.get("/static/te.png")
62
  async def serve_logo():
 
63
  logo_path = "static/te.png"
 
64
  if os.path.exists(logo_path):
 
65
  return FileResponse(logo_path)
66
+ svg_content = '''<svg width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
 
 
 
67
  <circle cx="20" cy="20" r="18" fill="#f6ae2d"/>
68
+ <g transform="translate(20,20)">
69
+ <path d="M -12 0 Q -6 -6 0 -6 Q 6 -6 12 0 Q 6 6 0 6 Q -6 6 -12 0" fill="#420909" stroke="none"/>
 
 
 
 
 
 
 
70
  <circle cx="0" cy="0" r="5" fill="#f6ae2d"/>
 
 
71
  <circle cx="0" cy="0" r="3" fill="#420909"/>
 
 
72
  <circle cx="-1" cy="-1" r="1" fill="white" opacity="0.8"/>
73
  </g>
74
+ <text x="20" y="35" font-family="Arial, sans-serif" font-size="8" font-weight="bold"
 
 
75
  text-anchor="middle" fill="#420909">TE</text>
76
  </svg>'''
77
+ return Response(content=svg_content, media_type="image/svg+xml",
78
+ headers={"Cache-Control": "public, max-age=3600"})
 
 
 
 
 
 
 
79
 
80
  # -------------------------------
81
+ # MODELO DE ENTRADA/SALIDA
82
  # -------------------------------
83
  class AnalyzeRequest(BaseModel):
84
  url: str
 
94
  @app.post("/analyze", response_model=AnalyzeResponse)
95
  async def analyze(request: AnalyzeRequest):
96
  logger.info(f"📥 Recibida solicitud de análisis para URL: {request.url}")
97
+ payload = {
98
+ "input_value": request.url,
99
+ "output_type": "chat",
100
+ "input_type": "chat",
101
+ "tweaks": {}
102
+ }
103
+ headers = {
104
+ "Content-Type": "application/json",
105
+ "User-Agent": "TrueEye-HuggingFace-Space/1.0",
106
+ "x-api-key": LANGFLOW_API_KEY
107
+ }
108
  try:
109
+ logger.info("📤 Enviando petición a Langflow…")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  response = requests.post(
111
+ FLOW_API_URL,
112
+ json=payload,
113
  headers=headers,
114
+ timeout=300
115
  )
 
116
  logger.info(f"📨 Respuesta recibida. Status: {response.status_code}")
 
 
117
  response.raise_for_status()
 
 
118
  data = response.json()
119
+
120
+ # Extraer texto de la respuesta
 
 
121
  result_text = None
 
 
122
  if isinstance(data, dict) and "result" in data:
123
  result_text = data["result"]
 
 
124
  elif isinstance(data, dict) and "outputs" in data:
125
  outputs = data["outputs"]
126
+ if outputs and isinstance(outputs, list):
127
+ for node in outputs[0].get("outputs", []):
128
+ msg = node.get("message")
129
+ if isinstance(msg, dict):
130
+ result_text = msg.get("text", "")
131
+ else:
132
+ result_text = str(msg)
133
+ if result_text:
134
+ break
 
 
 
 
 
 
 
 
135
  if not result_text:
136
+ result_text = _extract_text_from_response(data) or \
137
+ "⚠️ No se pudo extraer el resultado. Respuesta: " + str(data)[:200]
138
+
139
  logger.info("✅ Análisis completado exitosamente")
140
  return AnalyzeResponse(result=result_text)
141
+
142
  except requests.exceptions.Timeout:
143
  logger.error("⏱️ Timeout en la petición a Langflow")
144
  return AnalyzeResponse(
145
+ result="❌ Error: Timeout en el análisis.",
146
+ success=False, error="timeout"
 
147
  )
148
  except requests.exceptions.ConnectionError as e:
149
  logger.error(f"🔌 Error de conexión: {e}")
150
  return AnalyzeResponse(
151
+ result="❌ Error: No se pudo conectar al servicio de análisis.",
152
+ success=False, error="connection"
 
153
  )
154
  except requests.exceptions.HTTPError as e:
155
+ logger.error(f"🚫 Error HTTP: {e}; {e.response.text if e.response else ''}")
 
156
  return AnalyzeResponse(
157
+ result=f"❌ Error del servidor: {e}",
158
+ success=False, error=f"http_{e.response.status_code if e.response else 'unknown'}"
 
159
  )
160
  except Exception as e:
161
  logger.exception(f"💥 Error inesperado: {e}")
162
  return AnalyzeResponse(
163
+ result=f"❌ Error inesperado: {e}",
164
+ success=False, error="unknown"
 
165
  )
166
 
167
  def _extract_text_from_response(data):
 
168
  if isinstance(data, str):
169
  return data
 
170
  if isinstance(data, dict):
171
+ for key in ['text','message','result','output','content']:
172
+ v = data.get(key)
173
+ if isinstance(v, str):
174
+ return v
175
+ elif isinstance(v, (dict, list)):
176
+ r = _extract_text_from_response(v)
177
+ if r:
178
+ return r
179
+ for v in data.values():
180
+ if isinstance(v, (dict, list)):
181
+ r = _extract_text_from_response(v)
182
+ if r:
183
+ return r
184
+ if isinstance(data, list):
 
 
 
 
 
185
  for item in data:
186
+ r = _extract_text_from_response(item)
187
+ if r:
188
+ return r
 
189
  return None
190
 
191
  # -------------------------------
 
193
  # -------------------------------
194
  @app.get("/health")
195
  async def health_check():
 
196
  return {
197
  "status": "healthy",
198
  "flow_configured": bool(FLOW_API_URL),