eda-express / eda /insights.py
aitziberluis's picture
Upload 9 files
d7f258e verified
Raw
History Blame Contribute Delete
2.38 kB
"""Conclusiones narrativas generadas por LLM (opcional).
Decisión de privacidad importante: al LLM se le envía SOLO el resumen
estadístico agregado (medias, porcentajes, alertas) — jamás filas del
dataset. Un dataset puede contener datos personales; sus estadísticas
agregadas, normalmente no.
"""
from __future__ import annotations
import json
import os
import requests
GROQ_URL = "https://api.groq.com/openai/v1/chat/completions"
GROQ_MODEL = "llama-3.3-70b-versatile"
SYSTEM_PROMPT = """Eres un analista de datos senior. Te paso el resumen estadístico \
agregado de un dataset (no tienes acceso a las filas) y escribes conclusiones útiles \
en español, en Markdown, con esta estructura:
## Lectura general
(2-3 frases: qué pinta tiene el dataset, tamaño, calidad global.)
## Lo más relevante
(4-6 viñetas con los hallazgos que un analista destacaría: variables problemáticas, \
correlaciones interesantes, rarezas. Cita números concretos del resumen.)
## Próximos pasos sugeridos
(3-5 viñetas accionables y ordenadas: qué limpiar primero, qué explorar después, \
qué precauciones tomar si se va a modelar.)
Reglas: no inventes nada que no esté en el resumen; si algo no se puede saber sin \
ver los datos, dilo. Sé concreto y directo, sin relleno."""
def llm_available() -> bool:
return bool(os.environ.get("GROQ_API_KEY"))
def generate_insights(summary: dict) -> str:
"""Genera conclusiones a partir del resumen compacto. Lanza RuntimeError si falla."""
if not llm_available():
raise RuntimeError(
"No hay GROQ_API_KEY configurada. Las conclusiones narrativas son "
"opcionales: el resto del análisis no la necesita."
)
payload = json.dumps(summary, ensure_ascii=False, default=str)
response = requests.post(
GROQ_URL,
headers={"Authorization": f"Bearer {os.environ['GROQ_API_KEY']}"},
json={
"model": GROQ_MODEL,
"temperature": 0.3,
"messages": [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": payload[:20000]},
],
},
timeout=90,
)
if response.status_code != 200:
raise RuntimeError(f"Groq devolvió {response.status_code}: {response.text[:200]}")
return response.json()["choices"][0]["message"]["content"]