Proyecto de chatbot en Python construido con Genkit (plugin OpenAI compatible) y FastAPI, expuesto como API HTTP y con memoria persistente por sesión en archivos JSON.
Está pensado para ser simple, auditable y extensible, incorporando:
- memoria híbrida (contexto reciente + resumen + memoria estructurada)
- seguridad básica por API Key (sin usuarios aún)
- batería de tests con
pytest - checks básicos de seguridad (pip-audit, bandit, semgrep)
- API REST con FastAPI
- Integración con Genkit (Python beta) + plugin OpenAI compatible
- Memoria persistente por sesión en JSON (carpeta
data/) - Memoria híbrida:
- ventana de contexto reciente (últimos N mensajes)
- resumen acumulativo (long-term memory)
- memoria estructurada (profile / preferences / facts / todos, etc.)
- Endpoints para ver / editar / resetear memoria (resumen y estructurada)
- API Key obligatoria para casi todos los endpoints
- Tests con
pytest(sin llamadas reales a OpenAI) - Compatible con Genkit Developer UI (
genkit start ...)
- Windows 11 (probado)
- Python 3.11.x (recomendado 3.11.9)
- Node.js 20 LTS (recomendado) — solo para
genkit-cliy Dev UI - VS Code + extensión Python (Microsoft)
En tu repo lo normal es que el código viva en
src/y los tests entests/.
src/api.py→ FastAPI (endpoints + seguridad + validaciones)src/flows.py→ Flow de Genkit (chat_flow)src/memory_json.py→ Persistencia de memoria por sesión (JSON)src/run_api.py→ Arranque de Uvicorntests/→ tests unitarios e integración (TestClient)data/→ archivos JSON de memoria persistente (se crea automáticamente).env/.env.example→ variables de entornorequirements.txt→ dependenciasREADME.md,REQUIREMENTS.md,AGENTS.md,.gitignore
Crea un .env (o exporta variables) con:
OPENAI_API_KEY→ clave real de OpenAI (solo necesaria si llamas al modelo de verdad)API_KEY→ API Key interna para proteger endpoints (cabeceraX-API-Key)- (opcional)
DATA_DIR→ carpeta donde guardar JSON de memoria (por defectodata)
Ejemplo .env:
OPENAI_API_KEY="sk-..."
API_KEY="change-me"
DATA_DIR="data"python -m venv .venv
.\.venv\Scripts\activate
pip install -r requirements.txtpython src/run_api.py
# Uvicorn: http://127.0.0.1:8000Con Node 20 LTS instalado y genkit-cli disponible:
genkit start -- python src/run_api.py
# Dev UI: http://localhost:4000 (puede variar el puerto)En algunos entornos, Genkit puede intentar escribir archivos de runtime con timestamps tipo ISO que incluyen :.
En Windows esto puede provocar OSError: [Errno 22] Invalid argument porque : no es válido en nombres de archivo.
La solución típica es sanear el nombre del archivo runtime reemplazando : por - (o similar) en el código que lo genera (o en la capa que lo envuelve), tal como hiciste al parchear el _server.py.
- La API exige la cabecera:
X-API-Key: <API_KEY> - Se suele permitir sin key un endpoint “público” de health (por ejemplo
/health) para monitorización.
La memoria se guarda por sesión en JSON dentro de data/ (o DATA_DIR):
- Cada sesión tiene un
session_id. - En el JSON se suelen mantener:
messages: historial (o últimos N mensajes para contexto)summary: resumen acumulativostructured: memoria estructurada (diccionario)
Flujo típico:
- El cliente crea una sesión (
/sessions/new) o envía unsession_id. - En
/chat, se carga memoria desdedata/<session_id>.json. - Se envía al flow el contexto reciente +
summary+structured. - Tras responder, se persiste:
- mensajes recientes
- actualización del resumen (si aplica)
- cambios en memoria estructurada
Los nombres exactos pueden variar según tu
src/api.py, pero la idea es esta.
GET /health→ healthcheck (público)POST /sessions/new→ crea sesiónGET /sessions/{session_id}→ recupera estado/metadata de sesiónPOST /sessions/{session_id}/reset→ resetea la sesiónDELETE /sessions/{session_id}→ borra la sesiónPOST /chat→ chat (usa memoria persistente)
GET /sessions/{session_id}/summaryPUT /sessions/{session_id}/summaryPOST /sessions/{session_id}/summary/reset
GET /sessions/{session_id}/memoryPUT /sessions/{session_id}/memory(set completo)PATCH /sessions/{session_id}/memory(merge/update parcial)POST /sessions/{session_id}/memory/reset
En Windows puedes usar curl (o PowerShell
Invoke-RestMethod). Aquí van ejemplos con curl.
Define:
API_KEY="change-me"BASE="http://127.0.0.1:8000"
curl -s -X POST "$BASE/sessions/new" \
-H "X-API-Key: $API_KEY"curl -s -X POST "$BASE/chat" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{"session_id":"<SESSION_ID>","prompt":"Hola, me llamo Antonio"}'curl -s -X GET "$BASE/sessions/<SESSION_ID>/summary" \
-H "X-API-Key: $API_KEY"curl -s -X PUT "$BASE/sessions/<SESSION_ID>/summary" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{"summary":"El usuario se llama Antonio. Le interesa Genkit y FastAPI."}'curl -s -X GET "$BASE/sessions/<SESSION_ID>/memory" \
-H "X-API-Key: $API_KEY"curl -s -X PATCH "$BASE/sessions/<SESSION_ID>/memory" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{"profile":{"name":"Antonio"}, "preferences":{"lang":"es"}}'$env:API_KEY="test-key"
pytestEn Windows (PowerShell) recomendamos fijar PYTHONPATH=src para que los imports funcionen igual que en ejecución:
$env:PYTHONPATH="src"
$env:API_KEY="test-key"
pytest -qTip: si usas un comando tipo
test-all, asegúrate de que exporta tambiénPYTHONPATH=src.
pip-auditbandit -r src -ll$env:PYTHONIOENCODING="utf-8"
chcp 65001
semgrep --config=p/security-audit srcSi lo publicas en GitHub y quieres máxima adopción, lo más común es:
- MIT (muy permisiva)
- Apache-2.0 (permisiva + explícita en patentes)
Si no tienes una preferencia clara, MIT suele ser la opción más sencilla para proyectos demo/plantilla.
- Autenticación por usuarios (JWT/OAuth)
- Rate limiting por IP/usuario
- Observabilidad (OpenTelemetry + backend de trazas/logs)
- Persistencia en DB (SQLite/Postgres) en lugar de JSON si crece
- RAG (vector store) y políticas de acceso por rol