| """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"] |
|
|