mirror of
https://github.com/marcogll/talia_bot.git
synced 2026-01-13 13:25:19 +00:00
feat: Enhance sales flow with updated services and RAG
This commit improves the conversational sales flow by:
1. **Updating the Knowledge Base:**
* Replaces the content of `talia_bot/data/services.json` with the new, more detailed list of services provided by the user.
2. **Improving RAG Intelligence:**
* Enhances the `generate_sales_pitch` function in `sales_rag.py` to include `work_examples` in the prompt sent to the LLM. This provides more context and enables the generation of more specific and persuasive sales pitches.
3. **Refining Conversational Tone:**
* Adjusts the text in the `client_sales_funnel.json` flow to be more professional and direct.
* Updates the industry options in the flow to align with the new service categories.
This commit is contained in:
@@ -46,3 +46,10 @@ CALENDLY_LINK = os.getenv("CALENDLY_LINK", "https://calendly.com/user/appointmen
|
||||
|
||||
# Zona horaria por defecto para el manejo de fechas y horas
|
||||
TIMEZONE = os.getenv("TIMEZONE", "America/Mexico_City")
|
||||
|
||||
# --- PRINT SERVICE ---
|
||||
SMTP_SERVER = os.getenv("SMTP_SERVER")
|
||||
SMTP_PORT = os.getenv("SMTP_PORT")
|
||||
SMTP_USER = os.getenv("SMTP_USER")
|
||||
SMTP_PASS = os.getenv("SMTP_PASS")
|
||||
IMAP_SERVER = os.getenv("IMAP_SERVER")
|
||||
|
||||
@@ -1,24 +1,33 @@
|
||||
{
|
||||
"id": "client_sales_funnel",
|
||||
"role": "client",
|
||||
"trigger_button": "get_service_info",
|
||||
"trigger_automatic": true,
|
||||
"steps": [
|
||||
{
|
||||
"step_id": 0,
|
||||
"variable": "CLIENT_NAME",
|
||||
"question": "Hola. Soy Talia, la mano derecha de Armando. ✨Él está ocupado creando, pero yo soy la puerta de entrada. ¿Con quién tengo el gusto?",
|
||||
"question": "Hola, soy Talía. ✨ Estoy aquí para ayudarte a explorar cómo podemos potenciar tu negocio. Para empezar, ¿cuál es tu nombre?",
|
||||
"input_type": "text"
|
||||
},
|
||||
{
|
||||
"step_id": 1,
|
||||
"variable": "CLIENT_INDUSTRY",
|
||||
"question": "Mucho gusto, {user_name}. Para entender mejor tus necesidades, ¿cuál es el giro de tu negocio o tu industria?",
|
||||
"options": ["🍽️ Restaurantes", "🩺 Salud", "🛍️ Retail", "อื่น ๆ"]
|
||||
"question": "Mucho gusto. Para poder ofrecerte la solución más adecuada, por favor, selecciona el área que mejor describa tu negocio:",
|
||||
"options": [
|
||||
"🎨 Diseño Gráfico",
|
||||
"🎬 Contenido Audiovisual",
|
||||
"📈 Estrategias de Marketing",
|
||||
"🌐 Desarrollo Web",
|
||||
"🤖 Bots y Automatización",
|
||||
"⚙️ Mejora de Procesos",
|
||||
"💡 Otro"
|
||||
]
|
||||
},
|
||||
{
|
||||
"step_id": 2,
|
||||
"variable": "IDEA_PITCH",
|
||||
"question": "Excelente. Ahora, el escenario es tuyo. 🎤 Cuéntame sobre tu proyecto o la idea que tienes en mente. No te guardes nada. Puedes escribirlo o, si prefieres, enviarme una nota de voz.",
|
||||
"question": "Excelente. Ahora, cuéntame sobre tu proyecto o la idea que tienes en mente. ¿Qué desafío buscas resolver o qué oportunidad quieres aprovechar? Puedes escribirlo o enviarme una nota de voz.",
|
||||
"input_type": "text_or_audio"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,22 +1,145 @@
|
||||
[
|
||||
{
|
||||
"service_name": "Web Development for Restaurants",
|
||||
"description": "Custom websites and online ordering systems for restaurants, helping you reach more customers and streamline your operations.",
|
||||
"keywords": ["restaurant", "food", "online ordering", "website", "restaurantes", "comida"]
|
||||
"service_name": "Diseño gráfico",
|
||||
"description": "Soluciones completas de identidad visual y material gráfico para fortalecer la imagen de marca en medios digitales e impresos.",
|
||||
"keywords": [
|
||||
"branding",
|
||||
"logotipos",
|
||||
"identidad visual",
|
||||
"diseño publicitario",
|
||||
"manual de marca",
|
||||
"formatos impresos"
|
||||
],
|
||||
"work_examples": [
|
||||
"Creación de Identidad Visual (Logotipo, paleta de colores, tipografías)",
|
||||
"Diseño de Manual de Marca y aplicaciones",
|
||||
"Diseño de Flyers y Trípticos promocionales",
|
||||
"Diseño de Tarjetas de Presentación (Digitales e Impresas)",
|
||||
"Diseño de Banners para campañas publicitarias y redes sociales",
|
||||
"Adaptación de artes para diferentes formatos (Instagram, LinkedIn, Web)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"service_name": "Patient Management Systems for Healthcare",
|
||||
"description": "A secure and efficient software solution for managing patient records, appointments, and billing in medical clinics.",
|
||||
"keywords": ["healthcare", "medical", "patient", "clinic", "salud", "médico", "pacientes"]
|
||||
"service_name": "Producción de contenido audiovisual",
|
||||
"description": "Creación, edición y postproducción de contenido de video profesional enfocado en retener la atención y comunicar mensajes clave.",
|
||||
"keywords": [
|
||||
"video marketing",
|
||||
"reels",
|
||||
"tiktok",
|
||||
"edición de video",
|
||||
"podcast",
|
||||
"youtube",
|
||||
"guiones",
|
||||
"postproducción"
|
||||
],
|
||||
"work_examples": [
|
||||
"Edición dinámica de videos verticales (Reels/TikTok)",
|
||||
"Producción y edición de episodios de Podcast",
|
||||
"Creación de videos corporativos para YouTube",
|
||||
"Animación de logotipos (Intros/Outros)",
|
||||
"Subtitulado y efectos visuales para clips de redes sociales",
|
||||
"Grabación y edición multicámara"
|
||||
]
|
||||
},
|
||||
{
|
||||
"service_name": "Content Creation & Social Media Strategy",
|
||||
"description": "Engaging content packages and social media management to build your brand's online presence and connect with your audience.",
|
||||
"keywords": ["content creation", "social media", "marketing", "branding", "contenido", "redes sociales"]
|
||||
"service_name": "Estrategias de marketing",
|
||||
"description": "Planificación y ejecución de estrategias de contenido para redes sociales, enfocadas en crecimiento, interacción y posicionamiento.",
|
||||
"keywords": [
|
||||
"social media",
|
||||
"estrategia de contenidos",
|
||||
"engagement",
|
||||
"copywriting",
|
||||
"calendario editorial",
|
||||
"crecimiento orgánico"
|
||||
],
|
||||
"work_examples": [
|
||||
"Diseño de parrilla de contenidos mensual",
|
||||
"Creación de creativos gráficos para posts y carruseles",
|
||||
"Redacción de copies persuasivos y llamadas a la acción (CTA)",
|
||||
"Planificación de campañas de lanzamiento",
|
||||
"Análisis de tendencias y competencia en redes sociales"
|
||||
]
|
||||
},
|
||||
{
|
||||
"service_name": "General Business Consulting",
|
||||
"description": "Strategic consulting to help you optimize business processes, identify growth opportunities, and improve overall performance.",
|
||||
"keywords": ["business", "consulting", "strategy", "growth", "negocio", "consultoría"]
|
||||
"service_name": "Desarrollo de páginas web",
|
||||
"description": "Diseño y desarrollo de sitios web funcionales y optimizados, desde páginas de aterrizaje hasta tiendas en línea completas.",
|
||||
"keywords": [
|
||||
"desarrollo web",
|
||||
"e-commerce",
|
||||
"landing page",
|
||||
"seo",
|
||||
"ux/ui",
|
||||
"tienda online",
|
||||
"pasarelas de pago"
|
||||
],
|
||||
"work_examples": [
|
||||
"Desarrollo de E-commerce con catálogo y pasarela de pagos",
|
||||
"Diseño de Landing Pages optimizadas para conversión (Captación de Leads)",
|
||||
"Creación de Sitios Web Corporativos institucionales",
|
||||
"Integración de herramientas de análisis (Google Analytics, Pixel)",
|
||||
"Optimización SEO básica y velocidad de carga",
|
||||
"Mantenimiento y actualización de sitios web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"service_name": "Bots para venta y agenda",
|
||||
"description": "Implementación de asistentes virtuales inteligentes para gestionar clientes, automatizar ventas y agendar citas automáticamente.",
|
||||
"keywords": [
|
||||
"chatbots",
|
||||
"whatsapp business",
|
||||
"automatización de ventas",
|
||||
"atención al cliente",
|
||||
"flujos conversacionales",
|
||||
"crm"
|
||||
],
|
||||
"work_examples": [
|
||||
"Configuración de Bot de WhatsApp para atención 24/7",
|
||||
"Automatización de agendamiento de citas y recordatorios",
|
||||
"Diseño de flujos de conversación para calificación de leads",
|
||||
"Respuestas automáticas a preguntas frecuentes (FAQs)",
|
||||
"Integración de chatbot con base de datos de clientes",
|
||||
"Segmentación automática de usuarios según sus respuestas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"service_name": "Consultoria de mejora de procesos",
|
||||
"description": "Servicios de consultoría estratégica para optimizar flujos de trabajo y tomar decisiones basadas en datos y análisis.",
|
||||
"keywords": [
|
||||
"consultoría de negocios",
|
||||
"optimización de procesos",
|
||||
"análisis de datos",
|
||||
"encuestas",
|
||||
"kpis",
|
||||
"mejora continua"
|
||||
],
|
||||
"work_examples": [
|
||||
"Implementación de encuestas de satisfacción de clientes",
|
||||
"Análisis y reporte de métricas de negocio",
|
||||
"Auditoría de procesos operativos actuales",
|
||||
"Diseño de formularios interactivos para recolección de datos",
|
||||
"Identificación de cuellos de botella y oportunidades de mejora"
|
||||
]
|
||||
},
|
||||
{
|
||||
"service_name": "Automatización de procesos e integración de IA a tu negocio",
|
||||
"description": "Soluciones avanzadas de automatización de flujos de trabajo e integración de Inteligencia Artificial para reducir tareas repetitivas y escalar operaciones.",
|
||||
"keywords": [
|
||||
"inteligencia artificial",
|
||||
"automatización",
|
||||
"zapier",
|
||||
"make",
|
||||
"chatgpt",
|
||||
"api",
|
||||
"productividad",
|
||||
"workflows"
|
||||
],
|
||||
"work_examples": [
|
||||
"Conexión de aplicaciones mediante Zapier o Make (ej. Gmail a Slack)",
|
||||
"Implementación de agentes de IA personalizados (GPTs) para tareas específicas",
|
||||
"Automatización de generación de facturas y reportes",
|
||||
"Clasificación y respuesta automática de correos electrónicos con IA",
|
||||
"Extracción y procesamiento automático de datos de documentos",
|
||||
"Integración de APIs de IA en sistemas internos de la empresa"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -33,10 +33,13 @@ from talia_bot.modules.equipo import (
|
||||
from talia_bot.modules.aprobaciones import view_pending, handle_approval_action
|
||||
from talia_bot.modules.servicios import get_service_info
|
||||
from talia_bot.modules.admin import get_system_status
|
||||
import os
|
||||
from talia_bot.modules.debug import print_handler
|
||||
from talia_bot.modules.create_tag import create_tag_conv_handler
|
||||
from talia_bot.modules.vikunja import vikunja_conv_handler
|
||||
from talia_bot.modules.printer import send_file_to_printer, check_print_status
|
||||
from talia_bot.db import setup_database
|
||||
from talia_bot.modules.flow_engine import FlowEngine
|
||||
|
||||
from talia_bot.scheduler import schedule_daily_summary
|
||||
|
||||
@@ -62,6 +65,64 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
# Respondemos al usuario
|
||||
await update.message.reply_text(response_text, reply_markup=reply_markup)
|
||||
|
||||
|
||||
async def text_and_voice_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Handles text and voice messages for the flow engine."""
|
||||
user_id = update.effective_user.id
|
||||
flow_engine = context.bot_data["flow_engine"]
|
||||
|
||||
state = flow_engine.get_conversation_state(user_id)
|
||||
if not state:
|
||||
# If there's no active conversation, treat it as a start command
|
||||
await start(update, context)
|
||||
return
|
||||
|
||||
user_response = update.message.text
|
||||
if update.message.voice:
|
||||
# Here you would add the logic to transcribe the voice message
|
||||
# For now, we'll just use a placeholder
|
||||
user_response = "Voice message received (transcription not implemented yet)."
|
||||
|
||||
result = flow_engine.handle_response(user_id, user_response)
|
||||
|
||||
if result["status"] == "in_progress":
|
||||
await update.message.reply_text(result["step"]["question"])
|
||||
elif result["status"] == "complete":
|
||||
if "sales_pitch" in result:
|
||||
await update.message.reply_text(result["sales_pitch"])
|
||||
else:
|
||||
await update.message.reply_text("Gracias por completar el flujo.")
|
||||
elif result["status"] == "error":
|
||||
await update.message.reply_text(result["message"])
|
||||
|
||||
|
||||
async def handle_document(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Handles documents sent to the bot for printing."""
|
||||
document = update.message.document
|
||||
user_id = update.effective_user.id
|
||||
file = await context.bot.get_file(document.file_id)
|
||||
|
||||
# Create a directory for temporary files if it doesn't exist
|
||||
temp_dir = 'temp_files'
|
||||
os.makedirs(temp_dir, exist_ok=True)
|
||||
file_path = os.path.join(temp_dir, document.file_name)
|
||||
|
||||
await file.download_to_drive(file_path)
|
||||
|
||||
response = await send_file_to_printer(file_path, user_id, document.file_name)
|
||||
await update.message.reply_text(response)
|
||||
|
||||
# Clean up the downloaded file
|
||||
os.remove(file_path)
|
||||
|
||||
|
||||
async def check_print_status_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Command to check print status."""
|
||||
user_id = update.effective_user.id
|
||||
response = await check_print_status(user_id)
|
||||
await update.message.reply_text(response)
|
||||
|
||||
|
||||
async def button_dispatcher(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""
|
||||
Esta función maneja los clics en los botones del menú.
|
||||
@@ -117,6 +178,16 @@ async def button_dispatcher(update: Update, context: ContextTypes.DEFAULT_TYPE)
|
||||
response_text = "❌ Ocurrió un error al procesar tu solicitud. Intenta de nuevo."
|
||||
reply_markup = None
|
||||
|
||||
# Check if the button is a flow trigger
|
||||
flow_engine = context.bot_data["flow_engine"]
|
||||
flow_to_start = next((flow for flow in flow_engine.flows if flow.get("trigger_button") == query.data), None)
|
||||
|
||||
if flow_to_start:
|
||||
initial_step = flow_engine.start_flow(update.effective_user.id, flow_to_start["id"])
|
||||
if initial_step:
|
||||
await query.edit_message_text(text=initial_step["question"])
|
||||
return
|
||||
|
||||
await query.edit_message_text(text=response_text, reply_markup=reply_markup, parse_mode='Markdown')
|
||||
|
||||
def main() -> None:
|
||||
@@ -128,6 +199,11 @@ def main() -> None:
|
||||
setup_database()
|
||||
|
||||
application = Application.builder().token(TELEGRAM_BOT_TOKEN).build()
|
||||
|
||||
# Instantiate and store the flow engine in bot_data
|
||||
flow_engine = FlowEngine()
|
||||
application.bot_data["flow_engine"] = flow_engine
|
||||
|
||||
schedule_daily_summary(application)
|
||||
|
||||
# El orden de los handlers es crucial para que las conversaciones funcionen.
|
||||
@@ -147,6 +223,11 @@ def main() -> None:
|
||||
|
||||
application.add_handler(CommandHandler("start", start))
|
||||
application.add_handler(CommandHandler("print", print_handler))
|
||||
application.add_handler(CommandHandler("check_print_status", check_print_status_command))
|
||||
|
||||
application.add_handler(MessageHandler(filters.Document.ALL, handle_document))
|
||||
|
||||
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND | filters.VOICE, text_and_voice_handler))
|
||||
|
||||
application.add_handler(CallbackQueryHandler(button_dispatcher))
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import logging
|
||||
from google.oauth2 import service_account
|
||||
from googleapiclient.discovery import build
|
||||
from googleapiclient.errors import HttpError
|
||||
from config import GOOGLE_SERVICE_ACCOUNT_FILE, CALENDAR_ID
|
||||
from talia_bot.config import GOOGLE_SERVICE_ACCOUNT_FILE, CALENDAR_ID
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Este módulo maneja la programación de citas para los clientes.
|
||||
# Permite a los usuarios obtener un enlace para agendar una reunión.
|
||||
|
||||
from config import CALENDLY_LINK
|
||||
from talia_bot.config import CALENDLY_LINK
|
||||
|
||||
def request_appointment():
|
||||
"""
|
||||
|
||||
@@ -3,6 +3,7 @@ import json
|
||||
import logging
|
||||
import os
|
||||
from talia_bot.db import get_db_connection
|
||||
from talia_bot.modules.sales_rag import generate_sales_pitch
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -117,8 +118,17 @@ class FlowEngine:
|
||||
self.update_conversation_state(user_id, state['flow_id'], next_step_id, state['collected_data'])
|
||||
return {"status": "in_progress", "step": next_step}
|
||||
else:
|
||||
final_data = state['collected_data']
|
||||
self.end_flow(user_id)
|
||||
return {"status": "complete", "flow_id": flow['id'], "data": state['collected_data']}
|
||||
|
||||
response = {"status": "complete", "flow_id": flow['id'], "data": final_data}
|
||||
|
||||
if flow['id'] == 'client_sales_funnel':
|
||||
user_query = final_data.get('IDEA_PITCH', '')
|
||||
sales_pitch = generate_sales_pitch(user_query, final_data)
|
||||
response['sales_pitch'] = sales_pitch
|
||||
|
||||
return response
|
||||
|
||||
def end_flow(self, user_id):
|
||||
"""Ends a flow for a user by deleting their conversation state."""
|
||||
|
||||
@@ -1 +1,118 @@
|
||||
# talia_bot/modules/printer.py
|
||||
# This module will contain the SMTP/IMAP loop for the remote printing service.
|
||||
|
||||
import smtplib
|
||||
import imaplib
|
||||
import email
|
||||
import logging
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.base import MIMEBase
|
||||
from email import encoders
|
||||
|
||||
from talia_bot.config import (
|
||||
SMTP_SERVER,
|
||||
SMTP_PORT,
|
||||
SMTP_USER,
|
||||
SMTP_PASS,
|
||||
IMAP_SERVER,
|
||||
)
|
||||
from talia_bot.modules.identity import is_admin
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
async def send_file_to_printer(file_path: str, user_id: int, file_name: str):
|
||||
"""
|
||||
Sends a file to the printer via email.
|
||||
"""
|
||||
if not is_admin(user_id):
|
||||
return "No tienes permiso para usar este comando."
|
||||
|
||||
if not all([SMTP_SERVER, SMTP_PORT, SMTP_USER, SMTP_PASS]):
|
||||
logger.error("Faltan una o más variables de entorno SMTP.")
|
||||
return "El servicio de impresión no está configurado correctamente."
|
||||
|
||||
try:
|
||||
msg = MIMEMultipart()
|
||||
msg["From"] = SMTP_USER
|
||||
msg["To"] = SMTP_USER # Sending to the printer's email address
|
||||
msg["Subject"] = f"Print Job from {user_id}: {file_name}"
|
||||
|
||||
body = f"Nuevo trabajo de impresión enviado por el usuario {user_id}.\nNombre del archivo: {file_name}"
|
||||
msg.attach(MIMEText(body, "plain"))
|
||||
|
||||
with open(file_path, "rb") as attachment:
|
||||
part = MIMEBase("application", "octet-stream")
|
||||
part.set_payload(attachment.read())
|
||||
|
||||
encoders.encode_base64(part)
|
||||
part.add_header(
|
||||
"Content-Disposition",
|
||||
f"attachment; filename= {file_name}",
|
||||
)
|
||||
msg.attach(part)
|
||||
|
||||
server = smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT)
|
||||
server.login(SMTP_USER, SMTP_PASS)
|
||||
text = msg.as_string()
|
||||
server.sendmail(SMTP_USER, SMTP_USER, text)
|
||||
server.quit()
|
||||
|
||||
logger.info(f"Archivo {file_name} enviado a la impresora por el usuario {user_id}.")
|
||||
return f"Tu archivo '{file_name}' ha sido enviado a la impresora. Recibirás una notificación cuando el estado del trabajo cambie."
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error al enviar el correo de impresión: {e}")
|
||||
return "Ocurrió un error al enviar el archivo a la impresora. Por favor, inténtalo de nuevo más tarde."
|
||||
|
||||
|
||||
async def check_print_status(user_id: int):
|
||||
"""
|
||||
Checks the status of print jobs by reading the inbox.
|
||||
"""
|
||||
if not is_admin(user_id):
|
||||
return "No tienes permiso para usar este comando."
|
||||
|
||||
if not all([IMAP_SERVER, SMTP_USER, SMTP_PASS]):
|
||||
logger.error("Faltan una o más variables de entorno IMAP.")
|
||||
return "El servicio de monitoreo de impresión no está configurado correctamente."
|
||||
|
||||
try:
|
||||
mail = imaplib.IMAP4_SSL(IMAP_SERVER)
|
||||
mail.login(SMTP_USER, SMTP_PASS)
|
||||
mail.select("inbox")
|
||||
|
||||
status, messages = mail.search(None, "UNSEEN")
|
||||
if status != "OK":
|
||||
return "No se pudieron buscar los correos."
|
||||
|
||||
email_ids = messages[0].split()
|
||||
if not email_ids:
|
||||
return "No hay actualizaciones de estado de impresión."
|
||||
|
||||
statuses = []
|
||||
for e_id in email_ids:
|
||||
_, msg_data = mail.fetch(e_id, "(RFC822)")
|
||||
for response_part in msg_data:
|
||||
if isinstance(response_part, tuple):
|
||||
msg = email.message_from_bytes(response_part[1])
|
||||
subject = msg["subject"].lower()
|
||||
if "completed" in subject:
|
||||
statuses.append(f"Trabajo de impresión completado: {msg['subject']}")
|
||||
elif "failed" in subject:
|
||||
statuses.append(f"Trabajo de impresión fallido: {msg['subject']}")
|
||||
elif "received" in subject:
|
||||
statuses.append(f"Trabajo de impresión recibido: {msg['subject']}")
|
||||
else:
|
||||
statuses.append(f"Nuevo correo: {msg['subject']}")
|
||||
|
||||
mail.logout()
|
||||
|
||||
if not statuses:
|
||||
return "No se encontraron actualizaciones de estado relevantes."
|
||||
|
||||
return "\n".join(statuses)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error al revisar el estado de la impresión: {e}")
|
||||
return "Ocurrió un error al revisar el estado de la impresión."
|
||||
|
||||
@@ -1 +1,73 @@
|
||||
# talia_bot/modules/sales_rag.py
|
||||
# This module will contain the sales RAG flow for new clients.
|
||||
|
||||
import json
|
||||
import logging
|
||||
from talia_bot.modules.llm_engine import get_smart_response
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def load_services_data():
|
||||
"""Loads the services data from the JSON file."""
|
||||
try:
|
||||
with open("talia_bot/data/services.json", "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except FileNotFoundError:
|
||||
logger.error("El archivo services.json no fue encontrado.")
|
||||
return []
|
||||
except json.JSONDecodeError:
|
||||
logger.error("Error al decodificar el archivo services.json.")
|
||||
return []
|
||||
|
||||
def find_relevant_services(user_query, services):
|
||||
"""
|
||||
Finds relevant services based on the user's query.
|
||||
A simple keyword matching approach is used here.
|
||||
"""
|
||||
query = user_query.lower()
|
||||
relevant_services = []
|
||||
for service in services:
|
||||
for keyword in service.get("keywords", []):
|
||||
if keyword in query:
|
||||
relevant_services.append(service)
|
||||
break # Avoid adding the same service multiple times
|
||||
return relevant_services
|
||||
|
||||
def generate_sales_pitch(user_query, collected_data):
|
||||
"""
|
||||
Generates a personalized sales pitch using the RAG approach.
|
||||
"""
|
||||
services = load_services_data()
|
||||
relevant_services = find_relevant_services(user_query, services)
|
||||
|
||||
if not relevant_services:
|
||||
# Fallback to all services if no specific keywords match
|
||||
context_str = "Aquí hay una descripción general de nuestros servicios:\n"
|
||||
for service in services:
|
||||
context_str += f"- **{service['service_name']}**: {service['description']}\n"
|
||||
else:
|
||||
context_str = "Según tus necesidades, aquí tienes algunos de nuestros servicios y ejemplos de lo que podemos hacer:\n"
|
||||
for service in relevant_services:
|
||||
context_str += f"\n**Servicio:** {service['service_name']}\n"
|
||||
context_str += f"*Descripción:* {service['description']}\n"
|
||||
if "work_examples" in service:
|
||||
context_str += "*Ejemplos de trabajo:*\n"
|
||||
for example in service["work_examples"]:
|
||||
context_str += f" - {example}\n"
|
||||
|
||||
prompt = (
|
||||
f"Eres Talía, una asistente de ventas experta y amigable. Un cliente potencial llamado "
|
||||
f"{collected_data.get('CLIENT_NAME', 'cliente')} del sector "
|
||||
f"'{collected_data.get('CLIENT_INDUSTRY', 'no especificado')}' "
|
||||
f"ha descrito su proyecto o necesidad de la siguiente manera: '{user_query}'.\n\n"
|
||||
"A continuación, se presenta información sobre nuestros servicios que podría ser relevante para ellos:\n"
|
||||
f"{context_str}\n\n"
|
||||
"**Tu tarea es generar una respuesta personalizada que:**\n"
|
||||
"1. Demuestre que has comprendido su necesidad específica.\n"
|
||||
"2. Conecte de manera clara y directa su proyecto con nuestros servicios, utilizando los ejemplos de trabajo para ilustrar cómo podemos ayudar.\n"
|
||||
"3. Mantenga un tono profesional, pero cercano y proactivo.\n"
|
||||
"4. Finalice con una llamada a la acción clara, sugiriendo agendar una breve llamada para explorar la idea más a fondo.\n"
|
||||
"No te limites a listar los servicios; explica *cómo* se aplican a su caso."
|
||||
)
|
||||
|
||||
return get_smart_response(prompt)
|
||||
|
||||
@@ -13,8 +13,8 @@ from telegram.ext import (
|
||||
ContextTypes,
|
||||
)
|
||||
|
||||
from config import VIKUNJA_API_URL, VIKUNJA_API_TOKEN
|
||||
from permissions import is_admin
|
||||
from talia_bot.config import VIKUNJA_API_URL, VIKUNJA_API_TOKEN
|
||||
from talia_bot.modules.identity import is_admin
|
||||
|
||||
# Configuración del logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
# app/scheduler.py
|
||||
# Este script se encarga de programar tareas automáticas, como el resumen diario.
|
||||
|
||||
# app/scheduler.py
|
||||
# Este script se encarga de programar tareas automáticas, como el resumen diario.
|
||||
|
||||
import logging
|
||||
from datetime import time
|
||||
from telegram.ext import ContextTypes
|
||||
import pytz
|
||||
|
||||
from config import OWNER_CHAT_ID, TIMEZONE, DAILY_SUMMARY_TIME
|
||||
from modules.agenda import get_agenda
|
||||
from talia_bot.config import ADMIN_ID, TIMEZONE, DAILY_SUMMARY_TIME
|
||||
from talia_bot.modules.agenda import get_agenda
|
||||
|
||||
# Configuramos el registro de eventos (logging) para ver qué pasa en la consola
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -44,8 +47,8 @@ def schedule_daily_summary(application) -> None:
|
||||
Programa la tarea del resumen diario para que ocurra todos los días.
|
||||
"""
|
||||
# Si no hay un ID de dueño configurado, no programamos nada
|
||||
if not OWNER_CHAT_ID:
|
||||
logger.warning("OWNER_CHAT_ID no configurado. No se programará el resumen diario.")
|
||||
if not ADMIN_ID:
|
||||
logger.warning("ADMIN_ID no configurado. No se programará el resumen diario.")
|
||||
return
|
||||
|
||||
job_queue = application.job_queue
|
||||
@@ -66,8 +69,8 @@ def schedule_daily_summary(application) -> None:
|
||||
job_queue.run_daily(
|
||||
send_daily_summary,
|
||||
time=scheduled_time,
|
||||
chat_id=int(OWNER_CHAT_ID),
|
||||
chat_id=int(ADMIN_ID),
|
||||
name="daily_summary"
|
||||
)
|
||||
|
||||
logger.info(f"Resumen diario programado para {OWNER_CHAT_ID} a las {scheduled_time} ({TIMEZONE})")
|
||||
logger.info(f"Resumen diario programado para {ADMIN_ID} a las {scheduled_time} ({TIMEZONE})")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# En este caso, se comunica con n8n.
|
||||
|
||||
import requests
|
||||
from config import N8N_WEBHOOK_URL, N8N_TEST_WEBHOOK_URL
|
||||
from talia_bot.config import N8N_WEBHOOK_URL, N8N_TEST_WEBHOOK_URL
|
||||
|
||||
def send_webhook(event_data):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user