diff --git a/.env.example b/.env.example index 3cb8950..9244e83 100644 --- a/.env.example +++ b/.env.example @@ -1,18 +1,58 @@ +# .env.example +# Rellena estas variables y renombra este archivo a .env + # --- TELEGRAM & SECURITY --- +# Token de tu bot de Telegram, obtenido de @BotFather. TELEGRAM_BOT_TOKEN= +# Tu Telegram User ID. Usado para notificaciones críticas y funciones de administrador. ADMIN_ID= +# (Opcional) Lista separada por comas de IDs de Telegram para los miembros del equipo. +CREW_CHAT_IDS= # --- AI CORE --- +# Tu clave de API de OpenAI. OPENAI_API_KEY= +# El modelo de OpenAI que quieres usar (ej. gpt-4, gpt-3.5-turbo). +OPENAI_MODEL=gpt-3.5-turbo -# --- INTEGRATIONS --- -VIKUNJA_API_URL=https://tuservidor.com/api/v1 +# --- INTEGRACIONES --- +# 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= -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 --- -SMTP_SERVER=smtp.hostinger.com -SMTP_PORT=465 -SMTP_USER=print.service@vanityexperience.mx -SMTP_PASS= -IMAP_SERVER=imap.hostinger.com +# Ruta al archivo JSON de credenciales de tu cuenta de servicio de Google. +GOOGLE_SERVICE_ACCOUNT_FILE=google_key.json +# ID del calendario de Google que el bot gestionará. +CALENDAR_ID= + +# --- 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 diff --git a/README.md b/README.md index ea947d7..4a61ad1 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ El sistema sigue un flujo modular: * **`vikunja.py`**: API asíncrona para leer/escribir tareas y proyectos. * **`calendar.py`**: API para crear eventos en Google Calendar. * **`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. --- @@ -70,6 +71,7 @@ Crea un archivo `.env` en la raíz del proyecto a partir de `.env.example` y rel # --- TELEGRAM & SECURITY --- TELEGRAM_BOT_TOKEN=tu_token_telegram ADMIN_ID=tu_telegram_id +CREW_CHAT_IDS=id1,id2,id3 # --- AI CORE --- 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 CALENDAR_ID=tu_id_de_google_calendar -# --- PRINT SERVICE --- -SMTP_SERVER=smtp.tuservidor.com -SMTP_PORT=587 -SMTP_USER=tu_usuario_smtp +# --- PRINT SERVICE (SMTP/IMAP) --- +SMTP_SERVER=smtp.hostinger.com +SMTP_PORT=465 +SMTP_USER=print.service@vanityexperience.mx SMTP_PASSWORD=tu_password_smtp -IMAP_SERVER=imap.tuservidor.com -IMAP_USER=tu_usuario_imap +IMAP_SERVER=imap.hostinger.com +IMAP_USER=print.service@vanityexperience.mx IMAP_PASSWORD=tu_password_imap -PRINTER_EMAIL=el_email_de_la_impresora +PRINTER_EMAIL=vanityprinter@print.epsonconnect.com ``` ### 3. Ejecutar con Docker @@ -118,7 +120,7 @@ talia_bot_mg/ │ │ ├── llm_engine.py # Cliente OpenAI (Whisper y GPT) │ │ ├── transcription.py # Lógica de transcripción de audio │ │ ├── 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/ │ ├── flows.json # ¡IMPORTANTE! Define todas las conversaciones │ ├── services.json # Base de conocimiento para ventas @@ -136,11 +138,11 @@ talia_bot_mg/ - [x] **Implementado el Motor de Flujos Conversacionales.** - [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. - [ ] Migrar de OpenAI a Google Gemini 1.5 Pro. --- Desarrollado por: Marco G. -Asistente Personalizado v2.0 (Arquitectura de Flujos) +Asistente Personalizado v2.1 (Ciclo de Impresión Completo) diff --git a/talia_bot/config.py b/talia_bot/config.py index 5b2a18d..95d498a 100644 --- a/talia_bot/config.py +++ b/talia_bot/config.py @@ -10,40 +10,44 @@ from pathlib import Path env_path = Path(__file__).parent.parent / '.env' load_dotenv(dotenv_path=env_path) -# Token del bot de Telegram (obtenido de @BotFather) +# --- TELEGRAM & SECURITY --- 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) -ADMIN_ID = os.getenv("ADMIN_ID") +# --- AI CORE --- +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") 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) - -# ID del calendario de Google que usará el bot CALENDAR_ID = os.getenv("CALENDAR_ID") -# URL del webhook de n8n para enviar datos a otros servicios -N8N_WEBHOOK_URL = os.getenv("N8N_WEBHOOK_URL") -N8N_TEST_WEBHOOK_URL = os.getenv("N8N_TEST_WEBHOOK_URL") - -# Configuración de Vikunja +# Vikunja VIKUNJA_API_URL = os.getenv("VIKUNJA_BASE_URL") VIKUNJA_API_TOKEN = os.getenv("VIKUNJA_TOKEN") VIKUNJA_INBOX_PROJECT_ID = os.getenv("VIKUNJA_INBOX_PROJECT_ID") -# Llave de la API de OpenAI para usar modelos de lenguaje (como GPT) -OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") +# n8n +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) -OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-3.5-turbo") +# --- PRINT SERVICE (SMTP/IMAP) --- +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") - -# Enlace de Calendly para agendar citas 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") diff --git a/talia_bot/modules/mailer.py b/talia_bot/modules/mailer.py index f7e388d..418d195 100644 --- a/talia_bot/modules/mailer.py +++ b/talia_bot/modules/mailer.py @@ -17,6 +17,7 @@ logger = logging.getLogger(__name__) async def send_email_with_attachment(file_content: bytes, filename: str, subject: str): """ 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]): logger.error("SMTP settings are not fully configured.") @@ -40,13 +41,20 @@ async def send_email_with_attachment(file_content: bytes, filename: str, subject try: context = ssl.create_default_context() - # Usamos asyncio.to_thread para correr el código síncrono de smtplib def _send_mail(): - with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server: - server.starttls(context=context) - server.login(SMTP_USER, SMTP_PASSWORD) - server.sendmail(IMAP_USER, PRINTER_EMAIL, text) - logger.info(f"Email sent to {PRINTER_EMAIL} for printing.") + 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: + server.starttls(context=context) + server.login(SMTP_USER, SMTP_PASSWORD) + server.sendmail(IMAP_USER, PRINTER_EMAIL, text) + + logger.info(f"Email sent to {PRINTER_EMAIL} for printing.") await asyncio.to_thread(_send_mail) return True