Sistema de análisis automático de feedback: clasifica por sentimiento, categorías y urgencia, detecta patrones, resume mensajes y muestra insights en un panel Streamlit. Fuentes: WhatsApp, formularios web y encuestas (n8n) + carga manual.
Documentación: docs/ · Estado: implementación · Demo: checklist E2E · Propuesta expansión: más fuentes
cp .env.example .env
# Completar SOLO en .env local (nunca commitear — ver docs/guides/seguridad-y-secretos.md)
pip install -r requirements.txtVariables en .env (plantilla en .env.example):
| Variable | Uso |
|---|---|
DB_DSN |
FastAPI + worker (Session pooler Supabase) |
GEMINI_API_KEY |
Clasificador, patrones, Copilot |
COHERE_API_KEY |
Embeddings RAG |
API_KEY |
Header X-API-Key — generar con openssl rand -hex 32 |
GROQ_API_KEY |
Fallback LLM (opcional, recomendado) |
SUPABASE_URL / SUPABASE_KEY |
Dashboard |
FASTAPI_INGEST_URL |
n8n Docker → http://host.docker.internal:8000/ingest |
FASTAPI_URL |
Dashboard/Copilot → http://localhost:8000 |
WEBHOOK_URL |
Base HTTPS pública para Meta/WhatsApp (ngrok en local) |
| Variable | Default | Descripción |
|---|---|---|
CONFIDENCE_REVIEW_THRESHOLD |
0.7 | Marca mensajes para revisión humana |
CLASSIFY_LLM_BATCH_SIZE |
8 | Mensajes por llamada (1 = 1-a-1) |
CLASSIFY_MAX_TEXT_CHARS |
300 | Textos largos van solos |
GEMINI_CONCURRENCY |
3 | Chunks en paralelo |
GEMINI_CACHE_ENABLED |
true | Caché explícito Gemini (Fase B) |
GEMINI_CACHE_VERSION |
v3-taxonomia1 | Cambiar al editar prompts cacheados |
RECURRING_TOPICS_INTERVAL_DAYS |
1 | Job temas recurrentes (0 = off) |
RECURRING_TOPICS_PERIOD_DAYS |
7 | Ventana histórica de análisis |
Detalle: docs/plans/optimizacion-llm.md
Aplicar schema en Supabase SQL Editor:
docs/database/supabase_schema.sql(schema completo)- Si ya tenías tablas creadas, aplicar migraciones en orden: 006 → 007 → 008 → 009 → 010 → 011
cd backend
../.venv/bin/uvicorn src.api.main:app --reload --host 0.0.0.0 --port 8000cd backend
../.venv/bin/python worker.py.venv/bin/streamlit run dashboard/main.pydocker compose up -d --no-deps n8nAbrir http://localhost:5679 → importar n8n/Feedback-Ingest-3-fuentes-a-FastAPI.json → activar workflow (toggle ON) → reasignar credenciales Google/WhatsApp si hace falta.
Recrear n8n tras cambiar .env:
docker compose up -d n8n --no-deps --force-recreateEl worker indexa embeddings automáticamente tras cada tick. Para backfill manual:
cd backend && ../.venv/bin/python scripts/backfill_embeddings.py
# o
cd backend && ../.venv/bin/python embed_job.py| Servicio | URL |
|---|---|
| FastAPI health | http://localhost:8000/health |
| FastAPI docs | http://localhost:8000/docs |
| Dashboard | http://localhost:8501 |
| n8n | http://localhost:5679 |
| Grupo | Vistas |
|---|---|
| Operación | Vista General, Clasificaciones (Mensajes + Revisar) |
| Prioridades | Urgencia y señales |
| Análisis | Tendencias (Temas + Patrones, con filtro de período) |
| Datos | Exportar, Carga |
Vista General incluye Entradas recientes (últimas 10 de feedback_raw) para confirmar si n8n/carga llegó a Supabase, con auto-refresh cada 30 s. Copilot en sidebar (modal; el cierre persiste al cambiar de pestaña).
Extensiones: plan-clasificador-automejora.md
| Archivo | Uso |
|---|---|
n8n/Feedback-Ingest-3-fuentes-a-FastAPI.json |
Producción: WhatsApp Trigger, Tally webhook, Google Sheets (Forms) |
n8n/feedback-ingest-simple.json |
Prueba con un solo webhook |
Tras importar y activar el workflow:
| Fuente | Cómo llega a n8n |
|---|---|
Nodo WhatsApp Trigger — callback Meta = {WEBHOOK_URL}/webhook/{webhookId}/webhook (Production URL del nodo) |
|
| Tally | Webhook POST → http://localhost:5679/webhook/tally (o URL pública ngrok) |
| Google Forms | Google Sheets Trigger (~1 min) — formulario vinculado a Sheet; OAuth Google en n8n |
Tally: docs/guides/n8n-tally-webhook.md
Google Forms (alternativa sin OAuth): docs/guides/n8n-google-forms-apps-script.md
Nodo POST a FastAPI (compartido por las 3 fuentes):
- URL:
http://host.docker.internal:8000/ingest(o={{ $env.FASTAPI_INGEST_URL }}) - Header:
X-API-Key: ={{ $env.API_KEY }}(desde.env; preview rojo de$enven n8n es normal al editar)
WhatsApp requiere credencial WhatsApp OAuth; Google Sheets requiere Google OAuth en n8n.
Checklist completo: docs/guides/n8n-e2e-checklist.md
# 1. Ingest directo a FastAPI
curl -X POST http://localhost:8000/ingest \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{"external_id":"test-001","fuente":"manual","texto":"La app falla al pagar","timestamp":"2026-06-17T12:00:00Z","metadata":{}}'
# 2. Webhook Tally (workflow n8n activo)
curl -X POST http://localhost:5679/webhook/tally \
-H "Content-Type: application/json" \
-d '{"eventType":"FORM_RESPONSE","data":{"responseId":"tally-001","fields":[{"label":"Comentario","value":"Soporte muy lento"}]}}'Verificar en Supabase y en el dashboard (Mensajes Clasificados):
SELECT external_id, fuente, estado FROM feedback_raw ORDER BY created_at DESC;docker compose up -d --buildServicios: api, worker, dashboard, n8n. Para desarrollo local con FastAPI en el host, usar solo docker compose up -d --no-deps n8n.
Plantilla producción: .env.production.example
Documentación completa en docs/. Punto de entrada según tu rol:
| Rol | Empezar por |
|---|---|
| Evaluador / revisor | Estado de implementación → ADRs |
| Desarrollador | README (instalación) → Schema DB |
| Operador (n8n) | Checklist E2E |
El diseño del sistema está documentado en Architecture Decision Records:
- LLM y clasificación (Gemini + Groq)
- Pipeline LangGraph (6 nodos)
- Ingestión n8n (WhatsApp, Tally, Google Forms)
- Supabase + RAG Copilot
- Dashboard Streamlit v3 + automejora acotada (ADR-009, ADR-010)
- Guías operativas — n8n, Tally, Forms, BI
- Seguridad y secretos — qué no subir a Git
- Base de datos — schema y migraciones
- Optimización LLM — fases A–D implementadas
texto,fuente,external_id
"La app se cierra sola",csv,csv-001
"Muy buen servicio",csv,| Columna | Obligatorio | Alias aceptados |
|---|---|---|
texto |
Sí | content, message, comentario, text |
fuente |
No (default csv) |
source |
external_id |
No (UUID auto) | — |
También soporta JSON y Excel (.xlsx/.xls). En Excel se usa la primera hoja con datos que tenga columna texto o content (ignora hojas tipo LÉEME/readme).
Datasets de prueba locales: carpeta Data/ (no versionada — ver .gitignore). Plantilla versionada: samples/plantilla_feedback.csv.
Si mensajes quedan en estado error (p. ej. rate limit 429 de Gemini/Groq):
cd backend && python scripts/requeue_errors.pySi quedan atascados en procesando (worker crasheado):
cd backend && python scripts/recover_stuck_processing.pyRevisa los logs del worker tras reencolar. El dashboard muestra el conteo en la barra de estado y el banner de salud.
¿Seguís en local? No necesitás nada de esta sección — ver docs/guides/entornos-dev-y-prod.md.
Plantilla: .env.production.example · Plan: docs/plans/plan-produccion-single-tenant.md
docker compose -f docker-compose.prod.yml --env-file /path/to/.env up -d- Migraciones 007, 008, 009, 010 y 011 aplicadas en Supabase prod
API_KEYrotada (openssl rand -hex 32) yENV=production- Dashboard con rol
dashboard_readonly+DASHBOARD_READONLY=true - Proxy TLS + Basic Auth delante del dashboard (guía)
- CI verde en
main(ruff + pytest + gitleaks) - Worker +
recover_stuck_processing.pyprobados con lote de 50 mensajes - n8n activo con
WEBHOOK_URLHTTPS de producción - Backup Supabase verificado
- Equipo conoce runbook
- No commitear
.envni datasets locales (Data/). - Plantillas:
.env.example,.env.production.example(sin valores reales). - Guía completa: docs/guides/seguridad-y-secretos.md
PYTHONPATH=backend:. .venv/bin/pytest tests/ -vbackend/src/ # FastAPI, LangGraph, RAG
dashboard/ # Streamlit
shared/ # Constantes compartidas (ingesta CSV)
samples/ # Plantillas de ejemplo (sin datos reales)
n8n/ # Workflows exportados (sin API keys embebidas)
prompts/ # Prompts LLM (system, few-shot, patrones)
docs/ # Índice en docs/README.md
tests/ # Suite pytest (79+ tests)
.github/ # CI: ruff + pytest + gitleaks
docker-compose.prod.yml # Despliegue producción


