mirror of
https://github.com/marcogll/talia_bot.git
synced 2026-01-13 21:35:19 +00:00
Merge pull request #22 from marcogll/feature/flow-engine-implementation-15654864159042246464
feat: implement JSON-driven conversational flow engine (final)
This commit is contained in:
58
.env.example
58
.env.example
@@ -1,18 +1,58 @@
|
|||||||
|
# .env.example
|
||||||
|
# Rellena estas variables y renombra este archivo a .env
|
||||||
|
|
||||||
# --- TELEGRAM & SECURITY ---
|
# --- TELEGRAM & SECURITY ---
|
||||||
|
# Token de tu bot de Telegram, obtenido de @BotFather.
|
||||||
TELEGRAM_BOT_TOKEN=
|
TELEGRAM_BOT_TOKEN=
|
||||||
|
# Tu Telegram User ID. Usado para notificaciones críticas y funciones de administrador.
|
||||||
ADMIN_ID=
|
ADMIN_ID=
|
||||||
|
# (Opcional) Lista separada por comas de IDs de Telegram para los miembros del equipo.
|
||||||
|
CREW_CHAT_IDS=
|
||||||
|
|
||||||
# --- AI CORE ---
|
# --- AI CORE ---
|
||||||
|
# Tu clave de API de OpenAI.
|
||||||
OPENAI_API_KEY=
|
OPENAI_API_KEY=
|
||||||
|
# El modelo de OpenAI que quieres usar (ej. gpt-4, gpt-3.5-turbo).
|
||||||
|
OPENAI_MODEL=gpt-3.5-turbo
|
||||||
|
|
||||||
# --- INTEGRATIONS ---
|
# --- INTEGRACIONES ---
|
||||||
VIKUNJA_API_URL=https://tuservidor.com/api/v1
|
# URL base de tu instancia de Vikunja (ej. https://vikunja.tu-dominio.com/api/v1).
|
||||||
|
VIKUNJA_BASE_URL=
|
||||||
|
# Token de API generado en Vikunja.
|
||||||
VIKUNJA_TOKEN=
|
VIKUNJA_TOKEN=
|
||||||
GOOGLE_CREDENTIALS_PATH=./data/credentials.json
|
# ID del proyecto en Vikunja que se usará como "bandeja de entrada" para nuevas tareas.
|
||||||
|
VIKUNJA_INBOX_PROJECT_ID=
|
||||||
|
|
||||||
# --- PRINT SERVICE ---
|
# Ruta al archivo JSON de credenciales de tu cuenta de servicio de Google.
|
||||||
SMTP_SERVER=smtp.hostinger.com
|
GOOGLE_SERVICE_ACCOUNT_FILE=google_key.json
|
||||||
SMTP_PORT=465
|
# ID del calendario de Google que el bot gestionará.
|
||||||
SMTP_USER=print.service@vanityexperience.mx
|
CALENDAR_ID=
|
||||||
SMTP_PASS=
|
|
||||||
IMAP_SERVER=imap.hostinger.com
|
# --- PRINT SERVICE (SMTP/IMAP) ---
|
||||||
|
# Servidor SMTP para enviar correos.
|
||||||
|
SMTP_SERVER=
|
||||||
|
# Puerto del servidor SMTP (ej. 465 para SSL, 587 para STARTTLS).
|
||||||
|
SMTP_PORT=
|
||||||
|
# Usuario para la autenticación SMTP.
|
||||||
|
SMTP_USER=
|
||||||
|
# Contraseña para la autenticación SMTP.
|
||||||
|
SMTP_PASSWORD=
|
||||||
|
|
||||||
|
# Servidor IMAP para leer correos.
|
||||||
|
IMAP_SERVER=
|
||||||
|
# Usuario para la autenticación IMAP.
|
||||||
|
IMAP_USER=
|
||||||
|
# Contraseña para la autenticación IMAP.
|
||||||
|
IMAP_PASSWORD=
|
||||||
|
# Dirección de correo de la impresora (a donde se envían los trabajos de impresión).
|
||||||
|
PRINTER_EMAIL=
|
||||||
|
|
||||||
|
# --- OTROS ---
|
||||||
|
# (Opcional) URL de un webhook de n8n para integraciones personalizadas.
|
||||||
|
N8N_WEBHOOK_URL=
|
||||||
|
# Hora para enviar el resumen diario (formato HH:MM).
|
||||||
|
DAILY_SUMMARY_TIME=08:00
|
||||||
|
# Tu enlace de Calendly para agendar citas.
|
||||||
|
CALENDLY_LINK=
|
||||||
|
# Zona horaria para el bot (ej. America/Mexico_City, Europe/Madrid).
|
||||||
|
TIMEZONE=America/Monterrey
|
||||||
|
|||||||
22
README.md
22
README.md
@@ -40,6 +40,7 @@ El sistema sigue un flujo modular:
|
|||||||
* **`vikunja.py`**: API asíncrona para leer/escribir tareas y proyectos.
|
* **`vikunja.py`**: API asíncrona para leer/escribir tareas y proyectos.
|
||||||
* **`calendar.py`**: API para crear eventos en Google Calendar.
|
* **`calendar.py`**: API para crear eventos en Google Calendar.
|
||||||
* **`mailer.py`**: Envío de correos (SMTP) para el flujo de impresión.
|
* **`mailer.py`**: Envío de correos (SMTP) para el flujo de impresión.
|
||||||
|
* **`imap_listener.py`**: Escucha de confirmaciones de impresión (IMAP).
|
||||||
* **`llm_engine.py`**: Análisis RAG para el embudo de ventas.
|
* **`llm_engine.py`**: Análisis RAG para el embudo de ventas.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -70,6 +71,7 @@ Crea un archivo `.env` en la raíz del proyecto a partir de `.env.example` y rel
|
|||||||
# --- TELEGRAM & SECURITY ---
|
# --- TELEGRAM & SECURITY ---
|
||||||
TELEGRAM_BOT_TOKEN=tu_token_telegram
|
TELEGRAM_BOT_TOKEN=tu_token_telegram
|
||||||
ADMIN_ID=tu_telegram_id
|
ADMIN_ID=tu_telegram_id
|
||||||
|
CREW_CHAT_IDS=id1,id2,id3
|
||||||
|
|
||||||
# --- AI CORE ---
|
# --- AI CORE ---
|
||||||
OPENAI_API_KEY=sk-...
|
OPENAI_API_KEY=sk-...
|
||||||
@@ -82,15 +84,15 @@ VIKUNJA_INBOX_PROJECT_ID=el_id_de_tu_proyecto_bandeja_de_entrada
|
|||||||
GOOGLE_SERVICE_ACCOUNT_FILE=google_key.json
|
GOOGLE_SERVICE_ACCOUNT_FILE=google_key.json
|
||||||
CALENDAR_ID=tu_id_de_google_calendar
|
CALENDAR_ID=tu_id_de_google_calendar
|
||||||
|
|
||||||
# --- PRINT SERVICE ---
|
# --- PRINT SERVICE (SMTP/IMAP) ---
|
||||||
SMTP_SERVER=smtp.tuservidor.com
|
SMTP_SERVER=smtp.hostinger.com
|
||||||
SMTP_PORT=587
|
SMTP_PORT=465
|
||||||
SMTP_USER=tu_usuario_smtp
|
SMTP_USER=print.service@vanityexperience.mx
|
||||||
SMTP_PASSWORD=tu_password_smtp
|
SMTP_PASSWORD=tu_password_smtp
|
||||||
IMAP_SERVER=imap.tuservidor.com
|
IMAP_SERVER=imap.hostinger.com
|
||||||
IMAP_USER=tu_usuario_imap
|
IMAP_USER=print.service@vanityexperience.mx
|
||||||
IMAP_PASSWORD=tu_password_imap
|
IMAP_PASSWORD=tu_password_imap
|
||||||
PRINTER_EMAIL=el_email_de_la_impresora
|
PRINTER_EMAIL=vanityprinter@print.epsonconnect.com
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Ejecutar con Docker
|
### 3. Ejecutar con Docker
|
||||||
@@ -118,7 +120,7 @@ talia_bot_mg/
|
|||||||
│ │ ├── llm_engine.py # Cliente OpenAI (Whisper y GPT)
|
│ │ ├── llm_engine.py # Cliente OpenAI (Whisper y GPT)
|
||||||
│ │ ├── transcription.py # Lógica de transcripción de audio
|
│ │ ├── transcription.py # Lógica de transcripción de audio
|
||||||
│ │ ├── mailer.py # Módulo para envío de correos (SMTP)
|
│ │ ├── mailer.py # Módulo para envío de correos (SMTP)
|
||||||
│ │ └── ... # Otros módulos de soporte
|
│ │ └── imap_listener.py # Módulo para leer correos (IMAP)
|
||||||
│ └── data/
|
│ └── data/
|
||||||
│ ├── flows.json # ¡IMPORTANTE! Define todas las conversaciones
|
│ ├── flows.json # ¡IMPORTANTE! Define todas las conversaciones
|
||||||
│ ├── services.json # Base de conocimiento para ventas
|
│ ├── services.json # Base de conocimiento para ventas
|
||||||
@@ -136,11 +138,11 @@ talia_bot_mg/
|
|||||||
|
|
||||||
- [x] **Implementado el Motor de Flujos Conversacionales.**
|
- [x] **Implementado el Motor de Flujos Conversacionales.**
|
||||||
- [x] **Integración completa de Vikunja, OpenAI y Google Calendar.**
|
- [x] **Integración completa de Vikunja, OpenAI y Google Calendar.**
|
||||||
- [ ] Implementar el loop de confirmación de impresión (IMAP Listener).
|
- [x] **Implementado el Loop de Confirmación de Impresión (IMAP).**
|
||||||
- [ ] Mejorar el parsing de fechas y horas con lenguaje natural más avanzado.
|
- [ ] Mejorar el parsing de fechas y horas con lenguaje natural más avanzado.
|
||||||
- [ ] Migrar de OpenAI a Google Gemini 1.5 Pro.
|
- [ ] Migrar de OpenAI a Google Gemini 1.5 Pro.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Desarrollado por: Marco G.
|
Desarrollado por: Marco G.
|
||||||
Asistente Personalizado v2.0 (Arquitectura de Flujos)
|
Asistente Personalizado v2.1 (Ciclo de Impresión Completo)
|
||||||
|
|||||||
@@ -10,40 +10,44 @@ from pathlib import Path
|
|||||||
env_path = Path(__file__).parent.parent / '.env'
|
env_path = Path(__file__).parent.parent / '.env'
|
||||||
load_dotenv(dotenv_path=env_path)
|
load_dotenv(dotenv_path=env_path)
|
||||||
|
|
||||||
# Token del bot de Telegram (obtenido de @BotFather)
|
# --- TELEGRAM & SECURITY ---
|
||||||
TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
|
TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
|
||||||
|
# Prioriza ADMIN_ID, pero usa OWNER_CHAT_ID como fallback para compatibilidad
|
||||||
|
ADMIN_ID = os.getenv("ADMIN_ID") or os.getenv("OWNER_CHAT_ID")
|
||||||
|
CREW_CHAT_IDS = os.getenv("CREW_CHAT_IDS", "").split(',')
|
||||||
|
|
||||||
# ID de chat del dueño del bot (para recibir notificaciones importantes)
|
# --- AI CORE ---
|
||||||
ADMIN_ID = os.getenv("ADMIN_ID")
|
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
||||||
|
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-3.5-turbo")
|
||||||
|
|
||||||
# Ruta al archivo de credenciales de la cuenta de servicio de Google
|
# --- INTEGRACIONES ---
|
||||||
|
# Google
|
||||||
GOOGLE_SERVICE_ACCOUNT_FILE = os.getenv("GOOGLE_SERVICE_ACCOUNT_FILE")
|
GOOGLE_SERVICE_ACCOUNT_FILE = os.getenv("GOOGLE_SERVICE_ACCOUNT_FILE")
|
||||||
if GOOGLE_SERVICE_ACCOUNT_FILE and not os.path.isabs(GOOGLE_SERVICE_ACCOUNT_FILE):
|
if GOOGLE_SERVICE_ACCOUNT_FILE and not os.path.isabs(GOOGLE_SERVICE_ACCOUNT_FILE):
|
||||||
GOOGLE_SERVICE_ACCOUNT_FILE = str(Path(__file__).parent.parent / GOOGLE_SERVICE_ACCOUNT_FILE)
|
GOOGLE_SERVICE_ACCOUNT_FILE = str(Path(__file__).parent.parent / GOOGLE_SERVICE_ACCOUNT_FILE)
|
||||||
|
|
||||||
# ID del calendario de Google que usará el bot
|
|
||||||
CALENDAR_ID = os.getenv("CALENDAR_ID")
|
CALENDAR_ID = os.getenv("CALENDAR_ID")
|
||||||
|
|
||||||
# URL del webhook de n8n para enviar datos a otros servicios
|
# Vikunja
|
||||||
N8N_WEBHOOK_URL = os.getenv("N8N_WEBHOOK_URL")
|
|
||||||
N8N_TEST_WEBHOOK_URL = os.getenv("N8N_TEST_WEBHOOK_URL")
|
|
||||||
|
|
||||||
# Configuración de Vikunja
|
|
||||||
VIKUNJA_API_URL = os.getenv("VIKUNJA_BASE_URL")
|
VIKUNJA_API_URL = os.getenv("VIKUNJA_BASE_URL")
|
||||||
VIKUNJA_API_TOKEN = os.getenv("VIKUNJA_TOKEN")
|
VIKUNJA_API_TOKEN = os.getenv("VIKUNJA_TOKEN")
|
||||||
VIKUNJA_INBOX_PROJECT_ID = os.getenv("VIKUNJA_INBOX_PROJECT_ID")
|
VIKUNJA_INBOX_PROJECT_ID = os.getenv("VIKUNJA_INBOX_PROJECT_ID")
|
||||||
|
|
||||||
# Llave de la API de OpenAI para usar modelos de lenguaje (como GPT)
|
# n8n
|
||||||
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
N8N_WEBHOOK_URL = os.getenv("N8N_WEBHOOK_URL")
|
||||||
|
N8N_TEST_WEBHOOK_URL = os.getenv("N8N_WEBHOOK-TEST_URL")
|
||||||
|
|
||||||
# Modelo de OpenAI a utilizar (ej. gpt-3.5-turbo, gpt-4)
|
# --- PRINT SERVICE (SMTP/IMAP) ---
|
||||||
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-3.5-turbo")
|
SMTP_SERVER = os.getenv("SMTP_SERVER")
|
||||||
|
SMTP_PORT = int(os.getenv("SMTP_PORT", 587))
|
||||||
|
SMTP_USER = os.getenv("SMTP_USER")
|
||||||
|
SMTP_PASSWORD = os.getenv("SMTP_PASSWORD")
|
||||||
|
|
||||||
# Hora del resumen diario (formato HH:MM)
|
IMAP_SERVER = os.getenv("IMAP_SERVER")
|
||||||
|
IMAP_USER = os.getenv("IMAP_USER")
|
||||||
|
IMAP_PASSWORD = os.getenv("IMAP_PASSWORD")
|
||||||
|
PRINTER_EMAIL = os.getenv("PRINTER_EMAIL")
|
||||||
|
|
||||||
|
# --- OTROS ---
|
||||||
DAILY_SUMMARY_TIME = os.getenv("DAILY_SUMMARY_TIME", "07:00")
|
DAILY_SUMMARY_TIME = os.getenv("DAILY_SUMMARY_TIME", "07:00")
|
||||||
|
|
||||||
# Enlace de Calendly para agendar citas
|
|
||||||
CALENDLY_LINK = os.getenv("CALENDLY_LINK", "https://calendly.com/user/appointment-link")
|
CALENDLY_LINK = os.getenv("CALENDLY_LINK", "https://calendly.com/user/appointment-link")
|
||||||
|
|
||||||
# Zona horaria por defecto para el manejo de fechas y horas
|
|
||||||
TIMEZONE = os.getenv("TIMEZONE", "America/Mexico_City")
|
TIMEZONE = os.getenv("TIMEZONE", "America/Mexico_City")
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ logger = logging.getLogger(__name__)
|
|||||||
async def send_email_with_attachment(file_content: bytes, filename: str, subject: str):
|
async def send_email_with_attachment(file_content: bytes, filename: str, subject: str):
|
||||||
"""
|
"""
|
||||||
Sends an email with an attachment using SMTP.
|
Sends an email with an attachment using SMTP.
|
||||||
|
Adapts connection method based on SMTP_PORT.
|
||||||
"""
|
"""
|
||||||
if not all([SMTP_SERVER, SMTP_PORT, SMTP_USER, SMTP_PASSWORD, PRINTER_EMAIL]):
|
if not all([SMTP_SERVER, SMTP_PORT, SMTP_USER, SMTP_PASSWORD, PRINTER_EMAIL]):
|
||||||
logger.error("SMTP settings are not fully configured.")
|
logger.error("SMTP settings are not fully configured.")
|
||||||
@@ -40,12 +41,19 @@ async def send_email_with_attachment(file_content: bytes, filename: str, subject
|
|||||||
try:
|
try:
|
||||||
context = ssl.create_default_context()
|
context = ssl.create_default_context()
|
||||||
|
|
||||||
# Usamos asyncio.to_thread para correr el código síncrono de smtplib
|
|
||||||
def _send_mail():
|
def _send_mail():
|
||||||
|
if SMTP_PORT == 465:
|
||||||
|
# Use SMTP_SSL for port 465
|
||||||
|
with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT, context=context) as server:
|
||||||
|
server.login(SMTP_USER, SMTP_PASSWORD)
|
||||||
|
server.sendmail(IMAP_USER, PRINTER_EMAIL, text)
|
||||||
|
else:
|
||||||
|
# Use STARTTLS for other ports like 587
|
||||||
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
|
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
|
||||||
server.starttls(context=context)
|
server.starttls(context=context)
|
||||||
server.login(SMTP_USER, SMTP_PASSWORD)
|
server.login(SMTP_USER, SMTP_PASSWORD)
|
||||||
server.sendmail(IMAP_USER, PRINTER_EMAIL, text)
|
server.sendmail(IMAP_USER, PRINTER_EMAIL, text)
|
||||||
|
|
||||||
logger.info(f"Email sent to {PRINTER_EMAIL} for printing.")
|
logger.info(f"Email sent to {PRINTER_EMAIL} for printing.")
|
||||||
|
|
||||||
await asyncio.to_thread(_send_mail)
|
await asyncio.to_thread(_send_mail)
|
||||||
|
|||||||
Reference in New Issue
Block a user