mirror of
https://github.com/marcogll/telegram_new_socias.git
synced 2026-01-13 13:15:16 +00:00
Merge pull request #3 from marcogll/feat/docker-mysql-logging-13516104967243096474
Feat/docker mysql logging 13516104967243096474
This commit is contained in:
6
.env
6
.env
@@ -3,8 +3,4 @@ TELEGRAM_TOKEN=TU_TOKEN_NUEVO_AQUI
|
|||||||
|
|
||||||
# Webhooks de n8n (puedes agregar más aquí en el futuro)
|
# Webhooks de n8n (puedes agregar más aquí en el futuro)
|
||||||
WEBHOOK_CONTRATO=https://flows.soul23.cloud/webhook/DuXh9Oi7SCAMf9
|
WEBHOOK_CONTRATO=https://flows.soul23.cloud/webhook/DuXh9Oi7SCAMf9
|
||||||
WEBHOOK_PRINT=
|
# WEBHOOK_VACACIONES=https://... (futuro)
|
||||||
WEBHOOK_VACACIONES=
|
|
||||||
|
|
||||||
# --- DATABASE ---
|
|
||||||
DATABASE_URL=mysql+mysqlconnector://user:password@db:3306/vanessa_logs
|
|
||||||
22
.env.example
Normal file
22
.env.example
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Configuración de Telegram
|
||||||
|
TELEGRAM_TOKEN=TU_TOKEN_NUEVO_AQUI
|
||||||
|
|
||||||
|
# Webhooks de n8n (puedes agregar más aquí en el futuro)
|
||||||
|
WEBHOOK_CONTRATO=
|
||||||
|
WEBHOOK_PRINT=
|
||||||
|
WEBHOOK_VACACIONES=
|
||||||
|
|
||||||
|
# --- DATABASE ---
|
||||||
|
# Usado por el servicio de la base de datos en docker-compose.yml
|
||||||
|
MYSQL_DATABASE=vanessa_logs
|
||||||
|
MYSQL_USER=user
|
||||||
|
MYSQL_PASSWORD=password
|
||||||
|
MYSQL_ROOT_PASSWORD=rootpassword
|
||||||
|
|
||||||
|
# --- SMTP ---
|
||||||
|
# Usado por el módulo de impresión para enviar correos
|
||||||
|
SMTP_SERVER=smtp.hostinger.com
|
||||||
|
SMTP_PORT=465
|
||||||
|
SMTP_USER=your_email@example.com
|
||||||
|
SMTP_PASSWORD=your_password
|
||||||
|
SMTP_RECIPIENT=your_email@example.com
|
||||||
112
Readme.md
112
Readme.md
@@ -1,6 +1,6 @@
|
|||||||
# 🤖 Vanessa Bot – Asistente de RH para Vanity
|
# 🤖 Vanessa Bot – Asistente de RH para Vanity
|
||||||
|
|
||||||
Vanessa es un bot de Telegram escrito en Python que automatiza procesos internos de Recursos Humanos en Vanity. Su objetivo es eliminar fricción operativa: onboarding, solicitudes de RH e impresión de documentos, todo orquestado desde Telegram y conectado a flujos de n8n.
|
Vanessa es un bot de Telegram escrito en Python que automatiza procesos internos de Recursos Humanos en Vanity. Su objetivo es eliminar fricción operativa: onboarding, solicitudes de RH e impresión de documentos, todo orquestado desde Telegram y conectado a flujos de n8n o servicios de correo.
|
||||||
|
|
||||||
Este repositorio está pensado como **proyecto Python profesional**, modular y listo para correr 24/7 en producción.
|
Este repositorio está pensado como **proyecto Python profesional**, modular y listo para correr 24/7 en producción.
|
||||||
|
|
||||||
@@ -10,12 +10,12 @@ Este repositorio está pensado como **proyecto Python profesional**, modular y l
|
|||||||
|
|
||||||
Vanessa no es un chatbot genérico: es una interfaz conversacional para procesos reales de negocio.
|
Vanessa no es un chatbot genérico: es una interfaz conversacional para procesos reales de negocio.
|
||||||
|
|
||||||
- Onboarding completo de nuevas socias (/welcome)
|
- Onboarding completo de nuevas socias (`/welcome`)
|
||||||
- Envío de archivos a impresión (/print)
|
- Envío de archivos a impresión por correo electrónico (`/print`)
|
||||||
- Solicitud de vacaciones (/vacaciones)
|
- Solicitud de vacaciones (`/vacaciones`)
|
||||||
- Solicitud de permisos por horas (/permiso)
|
- Solicitud de permisos por horas (`/permiso`)
|
||||||
|
|
||||||
Cada flujo es un módulo independiente y todos los datos se envían a **webhooks de n8n** para su procesamiento posterior.
|
Cada flujo es un módulo independiente, y los datos se envían a **webhooks de n8n** o se procesan directamente, como en el caso de la impresión.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -24,7 +24,8 @@ Cada flujo es un módulo independiente y todos los datos se envían a **webhooks
|
|||||||
```
|
```
|
||||||
vanity_bot/
|
vanity_bot/
|
||||||
│
|
│
|
||||||
├── .env # Variables sensibles (tokens, URLs)
|
├── .env # Variables sensibles (tokens, URLs, credenciales)
|
||||||
|
├── .env.example # Archivo de ejemplo para variables de entorno
|
||||||
├── main.py # Cerebro principal del bot
|
├── main.py # Cerebro principal del bot
|
||||||
├── requirements.txt # Dependencias
|
├── requirements.txt # Dependencias
|
||||||
├── Dockerfile # Definición del contenedor del bot
|
├── Dockerfile # Definición del contenedor del bot
|
||||||
@@ -35,7 +36,7 @@ vanity_bot/
|
|||||||
├── __init__.py
|
├── __init__.py
|
||||||
├── database.py # Módulo de conexión a la base de datos
|
├── database.py # Módulo de conexión a la base de datos
|
||||||
├── onboarding.py # Flujo /welcome (onboarding RH)
|
├── onboarding.py # Flujo /welcome (onboarding RH)
|
||||||
├── printer.py # Flujo /print (impresión)
|
├── printer.py # Flujo /print (impresión por email)
|
||||||
└── rh_requests.py # /vacaciones y /permiso
|
└── rh_requests.py # /vacaciones y /permiso
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -43,23 +44,32 @@ vanity_bot/
|
|||||||
|
|
||||||
## 🔐 Configuración (.env)
|
## 🔐 Configuración (.env)
|
||||||
|
|
||||||
Crea un archivo `.env` en la raíz del proyecto con el siguiente contenido:
|
Copia el archivo `.env.example` a `.env` y rellena los valores correspondientes. Este archivo es ignorado por Git para proteger tus credenciales.
|
||||||
|
|
||||||
```
|
```
|
||||||
# --- TELEGRAM ---
|
# --- TELEGRAM ---
|
||||||
TELEGRAM_TOKEN=TU_TOKEN_AQUI
|
TELEGRAM_TOKEN=TU_TOKEN_AQUI
|
||||||
|
|
||||||
# --- WEBHOOKS N8N ---
|
# --- WEBHOOKS N8N ---
|
||||||
WEBHOOK_ONBOARDING=https://flows.soul23.cloud/webhook/contrato
|
WEBHOOK_ONBOARDING=https://...
|
||||||
WEBHOOK_PRINT=https://flows.soul23.cloud/webhook/impresion
|
WEBHOOK_PRINT=https://...
|
||||||
WEBHOOK_VACACIONES=https://flows.soul23.cloud/webhook/vacaciones
|
WEBHOOK_VACACIONES=https://...
|
||||||
|
|
||||||
# --- DATABASE ---
|
# --- DATABASE ---
|
||||||
# Esta URL es para la conexión interna de Docker, no la modifiques si usas Docker Compose.
|
# Usado por el servicio de la base de datos en docker-compose.yml
|
||||||
DATABASE_URL=mysql+mysqlconnector://user:password@db:3306/vanessa_logs
|
MYSQL_DATABASE=vanessa_logs
|
||||||
```
|
MYSQL_USER=user
|
||||||
|
MYSQL_PASSWORD=password
|
||||||
|
MYSQL_ROOT_PASSWORD=rootpassword
|
||||||
|
|
||||||
Nunca subas este archivo al repositorio.
|
# --- SMTP PARA IMPRESIÓN ---
|
||||||
|
# Usado por el módulo de impresión para enviar correos
|
||||||
|
SMTP_SERVER=smtp.hostinger.com
|
||||||
|
SMTP_PORT=465
|
||||||
|
SMTP_USER=tu_email@dominio.com
|
||||||
|
SMTP_PASSWORD=tu_password_de_email
|
||||||
|
SMTP_RECIPIENT=email_destino@dominio.com
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -76,7 +86,7 @@ Con el archivo `.env` ya configurado, simplemente ejecuta:
|
|||||||
```bash
|
```bash
|
||||||
docker-compose up --build
|
docker-compose up --build
|
||||||
```
|
```
|
||||||
Este comando construirá la imagen del bot, descargará la imagen de MySQL, creará los volúmenes y redes, y lanzará ambos servicios. El bot se conectará automáticamente a la base de datos para registrar los logs.
|
Este comando construirá la imagen del bot, descargará la imagen de MySQL, y lanzará ambos servicios. `docker-compose` leerá las variables del archivo `.env` para configurar los contenedores.
|
||||||
|
|
||||||
### 3. Detener los servicios
|
### 3. Detener los servicios
|
||||||
Para detener los contenedores, presiona `Ctrl+C` en la terminal donde se están ejecutando, o ejecuta desde otro terminal:
|
Para detener los contenedores, presiona `Ctrl+C` en la terminal donde se están ejecutando, o ejecuta desde otro terminal:
|
||||||
@@ -86,40 +96,13 @@ docker-compose down
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📦 Instalación Manual
|
|
||||||
|
|
||||||
Se recomienda usar un entorno virtual.
|
|
||||||
|
|
||||||
```
|
|
||||||
python -m venv venv
|
|
||||||
source venv/bin/activate
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ▶️ Ejecución Manual
|
|
||||||
|
|
||||||
```
|
|
||||||
python main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
Si el token es válido, verás:
|
|
||||||
|
|
||||||
```
|
|
||||||
🧠 Vanessa Brain iniciada y escuchando...
|
|
||||||
```
|
|
||||||
**Nota**: Para que la ejecución manual funcione, necesitarás tener una base de datos MySQL corriendo localmente y accesible en la URL especificada en `DATABASE_URL` dentro de tu archivo `.env`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧩 Arquitectura Interna
|
## 🧩 Arquitectura Interna
|
||||||
|
|
||||||
### main.py (El Cerebro)
|
### main.py (El Cerebro)
|
||||||
- Inicializa el bot de Telegram
|
- Inicializa el bot de Telegram
|
||||||
- Carga variables de entorno
|
- Carga variables de entorno
|
||||||
- Registra los handlers de cada módulo
|
- Registra los handlers de cada módulo
|
||||||
- Define el menú principal (/start, /help)
|
- Define el menú principal (`/start`, `/help`)
|
||||||
|
|
||||||
### modules/database.py
|
### modules/database.py
|
||||||
- Gestiona la conexión a la base de datos MySQL con SQLAlchemy.
|
- Gestiona la conexión a la base de datos MySQL con SQLAlchemy.
|
||||||
@@ -127,43 +110,26 @@ Si el token es válido, verás:
|
|||||||
- Provee la función `log_request` para registrar interacciones.
|
- Provee la función `log_request` para registrar interacciones.
|
||||||
|
|
||||||
### modules/onboarding.py
|
### modules/onboarding.py
|
||||||
Flujo conversacional complejo basado en `ConversationHandler`.
|
Flujo conversacional complejo que recolecta datos de nuevas empleadas y los envía a un webhook de n8n.
|
||||||
- Recolecta información personal, laboral y de emergencia
|
|
||||||
- Normaliza datos (RFC, CURP, fechas)
|
|
||||||
- Usa teclados guiados para reducir errores
|
|
||||||
- Envía un payload estructurado a n8n
|
|
||||||
|
|
||||||
### modules/printer.py
|
### modules/printer.py
|
||||||
- Recibe documentos o imágenes desde Telegram
|
- Recibe documentos o imágenes desde Telegram.
|
||||||
- Obtiene el enlace temporal de Telegram
|
- Descarga el archivo de forma segura desde los servidores de Telegram.
|
||||||
- Envía el archivo a una cola de impresión vía webhook
|
- Se conecta a un servidor SMTP para enviar el archivo como un adjunto por correo electrónico a una dirección predefinida.
|
||||||
|
|
||||||
### modules/rh_requests.py
|
### modules/rh_requests.py
|
||||||
- Maneja solicitudes simples de RH: Vacaciones y Permisos por horas.
|
- Maneja solicitudes simples de RH (Vacaciones y Permisos) y las envía a un webhook de n8n.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🧠 Filosofía del Proyecto
|
## 🧠 Filosofía del Proyecto
|
||||||
|
|
||||||
- Telegram como UI
|
- **Telegram como UI**: Interfaz conversacional accesible para todos.
|
||||||
- Python como cerebro
|
- **Python como cerebro**: Lógica de negocio y orquestación.
|
||||||
- n8n como sistema nervioso
|
- **Docker para despliegue**: Entornos consistentes y portátiles.
|
||||||
- Docker para despliegue
|
- **MySQL para persistencia**: Registro auditable de todas las interacciones.
|
||||||
- MySQL para persistencia de logs
|
- **SMTP para acciones directas**: Integración con sistemas estándar como el correo.
|
||||||
- Datos estructurados, no mensajes sueltos
|
- **Modularidad total**: Cada habilidad es un componente independiente.
|
||||||
- Modularidad total: cada habilidad se enchufa o se quita
|
|
||||||
|
|
||||||
Vanessa no reemplaza RH: elimina fricción humana innecesaria.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Extensiones Futuras
|
|
||||||
|
|
||||||
- Firma digital de contratos
|
|
||||||
- Finder de documentos
|
|
||||||
- Reportes automáticos
|
|
||||||
- Roles y permisos
|
|
||||||
- Modo administrador
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ services:
|
|||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
- DATABASE_URL=mysql+mysqlconnector://user:password@db:3306/vanessa_logs
|
- DATABASE_URL=mysql+mysqlconnector://${MYSQL_USER}:${MYSQL_PASSWORD}@db:3306/${MYSQL_DATABASE}
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
volumes:
|
volumes:
|
||||||
@@ -19,14 +19,12 @@ services:
|
|||||||
container_name: vanessa_db
|
container_name: vanessa_db
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
MYSQL_DATABASE: vanessa_logs
|
MYSQL_DATABASE: ${MYSQL_DATABASE}
|
||||||
MYSQL_USER: user
|
MYSQL_USER: ${MYSQL_USER}
|
||||||
MYSQL_PASSWORD: password
|
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||||
MYSQL_ROOT_PASSWORD: rootpassword
|
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||||
volumes:
|
volumes:
|
||||||
- mysql_data:/var/lib/mysql
|
- mysql_data:/var/lib/mysql
|
||||||
ports:
|
|
||||||
- "3306:3306"
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
mysql_data:
|
mysql_data:
|
||||||
|
|||||||
@@ -1,9 +1,21 @@
|
|||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
|
import smtplib
|
||||||
|
import ssl
|
||||||
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
from email.mime.application import MIMEApplication
|
||||||
from telegram import Update
|
from telegram import Update
|
||||||
from telegram.ext import ContextTypes, ConversationHandler, CommandHandler, MessageHandler, filters
|
from telegram.ext import ContextTypes, ConversationHandler, CommandHandler, MessageHandler, filters
|
||||||
from modules.database import log_request
|
from modules.database import log_request
|
||||||
|
|
||||||
|
# --- SMTP Configuration ---
|
||||||
|
SMTP_SERVER = os.getenv("SMTP_SERVER")
|
||||||
|
SMTP_PORT = int(os.getenv("SMTP_PORT", 465))
|
||||||
|
SMTP_USER = os.getenv("SMTP_USER")
|
||||||
|
SMTP_PASSWORD = os.getenv("SMTP_PASSWORD")
|
||||||
|
SMTP_RECIPIENT = os.getenv("SMTP_RECIPIENT")
|
||||||
|
|
||||||
# Estado
|
# Estado
|
||||||
ESPERANDO_ARCHIVO = 1
|
ESPERANDO_ARCHIVO = 1
|
||||||
|
|
||||||
@@ -20,25 +32,48 @@ async def recibir_archivo(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
|||||||
file_id = archivo.file_id
|
file_id = archivo.file_id
|
||||||
file_name = getattr(archivo, 'file_name', f"foto_{file_id}.jpg")
|
file_name = getattr(archivo, 'file_name', f"foto_{file_id}.jpg")
|
||||||
|
|
||||||
# Obtenemos el link de descarga directo de Telegram
|
await update.message.reply_text(f"Procesando *{file_name}*... un momento por favor.")
|
||||||
file_info = await context.bot.get_file(file_id)
|
|
||||||
file_url = file_info.file_path
|
|
||||||
|
|
||||||
# Enviamos a n8n
|
|
||||||
webhook = os.getenv("WEBHOOK_PRINT")
|
|
||||||
payload = {
|
|
||||||
"user": user.full_name,
|
|
||||||
"email_user": f"{user.username}@telegram.org", # O pedir el mail antes
|
|
||||||
"file_url": file_url,
|
|
||||||
"file_name": file_name,
|
|
||||||
"tipo": "impresion"
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
requests.post(webhook, json=payload)
|
# 1. Descargar el archivo de Telegram
|
||||||
await update.message.reply_text(f"✅ Archivo *{file_name}* enviado a cola de impresión.")
|
file_info = await context.bot.get_file(file_id)
|
||||||
except:
|
file_url = file_info.file_path
|
||||||
await update.message.reply_text("❌ Error al conectar con el servidor de impresión.")
|
file_content = requests.get(file_url).content
|
||||||
|
|
||||||
|
# 2. Construir el correo
|
||||||
|
msg = MIMEMultipart()
|
||||||
|
msg['From'] = SMTP_USER
|
||||||
|
msg['To'] = SMTP_RECIPIENT
|
||||||
|
msg['Subject'] = f"Nuevo archivo para imprimir de {user.full_name}"
|
||||||
|
|
||||||
|
# Cuerpo del correo
|
||||||
|
body = f"""
|
||||||
|
Hola,
|
||||||
|
|
||||||
|
El usuario {user.full_name} (Username: @{user.username}, ID: {user.id}) ha enviado un archivo para imprimir.
|
||||||
|
|
||||||
|
Nombre del archivo: {file_name}
|
||||||
|
|
||||||
|
Este correo ha sido generado automáticamente por Vanessa Bot.
|
||||||
|
"""
|
||||||
|
msg.attach(MIMEText(body, 'plain'))
|
||||||
|
|
||||||
|
# Adjuntar el archivo
|
||||||
|
attachment = MIMEApplication(file_content, Name=file_name)
|
||||||
|
attachment['Content-Disposition'] = f'attachment; filename="{file_name}"'
|
||||||
|
msg.attach(attachment)
|
||||||
|
|
||||||
|
# 3. Enviar el correo
|
||||||
|
context = ssl.create_default_context()
|
||||||
|
with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT, context=context) as server:
|
||||||
|
server.login(SMTP_USER, SMTP_PASSWORD)
|
||||||
|
server.sendmail(SMTP_USER, SMTP_RECIPIENT, msg.as_string())
|
||||||
|
|
||||||
|
await update.message.reply_text(f"✅ Archivo *{file_name}* enviado a la impresora correctamente.")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al enviar correo: {e}") # Log para el admin
|
||||||
|
await update.message.reply_text("❌ Hubo un error al procesar tu archivo. Por favor, contacta a un administrador.")
|
||||||
|
|
||||||
return ConversationHandler.END
|
return ConversationHandler.END
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user