Spaces:
Paused
Paused
File size: 5,565 Bytes
29384ce d290510 e5c3ef3 29384ce 6d68582 29384ce d290510 e5c3ef3 29384ce d290510 29384ce d290510 e5c3ef3 3066400 d290510 f8a4504 29384ce e5c3ef3 29384ce 6d68582 d290510 6d68582 29384ce d290510 29384ce e5c3ef3 29384ce d290510 29384ce e5c3ef3 29384ce e5c3ef3 d290510 29384ce 3066400 d290510 e5c3ef3 d290510 f8a4504 e5c3ef3 f8a4504 e5c3ef3 d290510 3066400 e5c3ef3 d290510 e5c3ef3 d290510 3066400 d290510 e5c3ef3 3066400 29384ce d290510 e5c3ef3 d290510 e5c3ef3 d290510 e5c3ef3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# main.py
import os
import uuid
import logging
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, Response
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
import requests
from typing import Optional, Any, Dict
# -------------------------------
# CONFIGURACIÓN DE LOGGING
# -------------------------------
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# -------------------------------
# CARGA DE SECRETS
# -------------------------------
FLOW_API_URL = os.getenv("FLOW_API_URL")
API_KEY = os.getenv("LANGFLOW_API_KEY")
if not FLOW_API_URL:
raise RuntimeError("❌ FLOW_API_URL no está definido. Agrégalo en los Secrets de Hugging Face.")
if not API_KEY:
raise RuntimeError("❌ LANGFLOW_API_KEY no está definido. Agrégalo en los Secrets de Hugging Face.")
logger.info(f"✅ FLOW_API_URL configurado: {FLOW_API_URL[:30]}...")
logger.info(f"✅ LANGFLOW_API_KEY cargada (longitud {len(API_KEY)})")
# -------------------------------
# INICIALIZACIÓN DE LA APP
# -------------------------------
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/")
async def serve_index():
return FileResponse("static/index.html")
@app.get("/static/te.png")
async def serve_logo():
logo_path = "static/te.png"
if os.path.exists(logo_path):
return FileResponse(logo_path)
svg = '''<svg width="40" height="40" ...>...</svg>''' # placeholder SVG
return Response(svg, media_type="image/svg+xml", headers={"Cache-Control":"public, max-age=3600"})
# -------------------------------
# MODELOS DE Pydantic
# -------------------------------
class AnalyzeRequest(BaseModel):
url: str
class AnalyzeResponse(BaseModel):
result: str
success: bool = True
error: Optional[str] = None
# -------------------------------
# HELPER DE EXTRACCIÓN
# -------------------------------
def _extract_text_from_response(data: Any) -> Optional[str]:
if isinstance(data, str):
return data
if isinstance(data, dict):
for key in ("outputs","result","message","text","content"):
val = data.get(key)
if isinstance(val, str):
return val
elif val is not None:
txt = _extract_text_from_response(val)
if txt:
return txt
for val in data.values():
txt = _extract_text_from_response(val)
if txt:
return txt
if isinstance(data, list):
for item in data:
txt = _extract_text_from_response(item)
if txt:
return txt
return None
# -------------------------------
# ENDPOINT /analyze
# -------------------------------
@app.post("/analyze", response_model=AnalyzeResponse)
async def analyze(request: AnalyzeRequest):
logger.info(f"📥 Recibida solicitud de análisis para URL: {request.url}")
session_id = str(uuid.uuid4())
payload = {
"input_value": request.url,
"input_type": "chat",
"output_type": "chat",
"session_id": session_id,
"output_component": "",
"tweaks": None
}
headers = {
"Content-Type": "application/json",
"User-Agent": "TrueEye-HuggingFace-Space/1.0",
"x-api-key": API_KEY
}
try:
logger.info("📤 Enviando petición a Langflow...")
logger.debug(f"Payload: {payload}")
resp = requests.post(FLOW_API_URL, json=payload, headers=headers, timeout=300)
logger.info(f"📨 Respuesta recibida. Status: {resp.status_code}")
resp.raise_for_status()
data = resp.json()
logger.debug(f"Respuesta JSON completa: {data}")
# Extraer texto final
result_text = _extract_text_from_response(data)
if not result_text:
logger.warning("⚠️ No se pudo extraer texto de la respuesta")
result_text = "⚠️ Se procesó la solicitud pero no se pudo extraer el resultado."
logger.info("✅ Análisis completado exitosamente")
return AnalyzeResponse(result=result_text)
except requests.exceptions.Timeout:
logger.error("⏱️ Timeout en la petición a Langflow")
return AnalyzeResponse(result="❌ Error: Timeout (el análisis tardó demasiado)", success=False, error="timeout")
except requests.exceptions.HTTPError as e:
body = e.response.text if e.response is not None else "<no body>"
logger.error(f"🚫 Error HTTP {e.response.status_code if e.response else ''}: {body}")
return AnalyzeResponse(
result=f"❌ Error HTTP al llamar al Flow: {body}",
success=False,
error=f"http_{e.response.status_code if e.response else 'unknown'}"
)
except Exception as e:
logger.exception("💥 Error inesperado en /analyze")
return AnalyzeResponse(result=f"❌ Error inesperado: {e}", success=False, error="unknown")
# -------------------------------
# HEALTHCHECK
# -------------------------------
@app.get("/health")
async def health_check():
return {
"status": "healthy",
"flow_url": bool(FLOW_API_URL),
"service": "TrueEye Reports"
} |