TrueEye_Reports / main.py
DeepRat's picture
Update main.py
d290510 verified
# 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"
}