From 326578763f8583ce9d20d387cb2ec4ce0608010e Mon Sep 17 00:00:00 2001 From: Ekaropolus Date: Sun, 6 Jul 2025 00:48:23 -0600 Subject: [PATCH] New bots for Green Economy with handlers, webhooks and so on --- pxy_bots/handlers/__init__.py | 14 +++++ pxy_bots/handlers/handlers_citizen.py | 30 ++++++++++ pxy_bots/handlers/handlers_city.py | 13 ++++ pxy_bots/handlers/handlers_private.py | 16 +++++ pxy_bots/views.py | 85 ++++++++++++++++++++------- 5 files changed, 137 insertions(+), 21 deletions(-) create mode 100644 pxy_bots/handlers/__init__.py create mode 100644 pxy_bots/handlers/handlers_citizen.py create mode 100644 pxy_bots/handlers/handlers_city.py create mode 100644 pxy_bots/handlers/handlers_private.py diff --git a/pxy_bots/handlers/__init__.py b/pxy_bots/handlers/__init__.py new file mode 100644 index 0000000..bccb148 --- /dev/null +++ b/pxy_bots/handlers/__init__.py @@ -0,0 +1,14 @@ +# Importa los handlers comunes +from ..handlers import start, help_command, handle_location, respond + +# Importa los específicos por bot +from .handlers_citizen import next_truck, report_trash, private_pickup, green_balance +from .handlers_city import next_route, complete_stop, missed_stop, my_eco_score as city_eco_score +from .handlers_private import available_jobs, accept_job, next_pickup, complete_pickup, my_eco_score as private_eco_score + +__all__ = [ + "start", "help_command", "handle_location", "respond", + "next_truck", "report_trash", "private_pickup", "green_balance", + "next_route", "complete_stop", "missed_stop", "city_eco_score", + "available_jobs", "accept_job", "next_pickup", "complete_pickup", "private_eco_score" +] diff --git a/pxy_bots/handlers/handlers_citizen.py b/pxy_bots/handlers/handlers_citizen.py new file mode 100644 index 0000000..48a9291 --- /dev/null +++ b/pxy_bots/handlers/handlers_citizen.py @@ -0,0 +1,30 @@ +from telegram import Update, KeyboardButton, ReplyKeyboardMarkup + +async def next_truck(update: Update): + if update.message.location: + lat, lon = update.message.location.latitude, update.message.location.longitude + await update.message.reply_text( + f"🚛 El camión pasa por tu zona ({lat}, {lon}) mañana a las 8:00 AM.") + else: + keyboard = [[KeyboardButton("📍 Enviar ubicación", request_location=True)]] + markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True, one_time_keyboard=True) + await update.message.reply_text( + "Mándame tu ubicación para decirte cuándo pasa el camión.", + reply_markup=markup) + +async def report_trash(update: Update): + user_text = update.message.text + await update.message.reply_text(f"🌱 Calculé tu CO₂ por '{user_text}' y te di 5 Monedas Verdes. ¡Chido!") + +async def private_pickup(update: Update): + if update.message.location: + await update.message.reply_text("🛵 ¡Pepe de la motito va en camino! Llega en 10 min.") + else: + keyboard = [[KeyboardButton("📍 Enviar ubicación", request_location=True)]] + markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True, one_time_keyboard=True) + await update.message.reply_text( + "Mándame tu ubicación para buscar un reco privado.", + reply_markup=markup) + +async def green_balance(update: Update): + await update.message.reply_text("💰 Llevas 23 Monedas Verdes acumuladas y evitaste 15 kg CO₂.") diff --git a/pxy_bots/handlers/handlers_city.py b/pxy_bots/handlers/handlers_city.py new file mode 100644 index 0000000..1f22db3 --- /dev/null +++ b/pxy_bots/handlers/handlers_city.py @@ -0,0 +1,13 @@ +from telegram import Update + +async def next_route(update: Update): + await update.message.reply_text("🚛 Hoy te toca: Calle Reforma, Av. Juárez y Callejón Verde.") + +async def complete_stop(update: Update): + await update.message.reply_text("✅ Parada marcada como recolectada. ¡Buen trabajo!") + +async def missed_stop(update: Update): + await update.message.reply_text("🚧 Parada marcada como NO recolectada.") + +async def my_eco_score(update: Update): + await update.message.reply_text("🌿 Llevas 120 Monedas Verdes este mes por tu eficiencia.") diff --git a/pxy_bots/handlers/handlers_private.py b/pxy_bots/handlers/handlers_private.py new file mode 100644 index 0000000..78875de --- /dev/null +++ b/pxy_bots/handlers/handlers_private.py @@ -0,0 +1,16 @@ +from telegram import Update + +async def available_jobs(update: Update): + await update.message.reply_text("📝 Hay 2 chambas cerca: Calle Pino y Calle Limón.") + +async def accept_job(update: Update): + await update.message.reply_text("👌 Chamba aceptada. Ve a Calle Pino 123.") + +async def next_pickup(update: Update): + await update.message.reply_text("➡️ Tu siguiente recolección es en Calle Limón 45.") + +async def complete_pickup(update: Update): + await update.message.reply_text("✅ ¡Recolección completada! Te ganaste 3 Monedas Verdes.") + +async def my_eco_score(update: Update): + await update.message.reply_text("🏆 Tienes 45 Monedas Verdes acumuladas este mes.") diff --git a/pxy_bots/views.py b/pxy_bots/views.py index 17186da..b47ee0b 100644 --- a/pxy_bots/views.py +++ b/pxy_bots/views.py @@ -1,24 +1,31 @@ import json +import logging from telegram import Update, Bot from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from asgiref.sync import sync_to_async from .models import TelegramBot from pxy_langchain.services import LangchainAIService -from .handlers import dream_city_command, start, help_command, handle_location -import logging +from .handlers import ( + start, help_command, handle_location, + next_truck, report_trash, private_pickup, green_balance, + next_route, complete_stop, missed_stop, my_eco_score as city_eco_score, + available_jobs, accept_job, next_pickup, complete_pickup, my_eco_score as private_eco_score +) logger = logging.getLogger(__name__) @csrf_exempt async def telegram_webhook(request, bot_name): """ - Webhook view that handles Telegram updates asynchronously and only uses LangChain. + Webhook view that routes each bot to its own set of handlers based on bot_name. + - 'pepebasurita': bot para ciudadanos + - 'pepecamioncito': bot para recolectores municipales + - 'pepemotito': bot para recolectores privados """ try: logger.info(f"Webhook called for bot: {bot_name}") - # Step 1: Fetch the bot instance asynchronously try: bot_instance = await sync_to_async(TelegramBot.objects.get)(name=bot_name, is_active=True) logger.info(f"Loaded bot configuration: {bot_instance}") @@ -26,12 +33,10 @@ async def telegram_webhook(request, bot_name): logger.error(f"Bot '{bot_name}' not found or inactive.") return JsonResponse({"error": f"Bot '{bot_name}' not found."}, status=400) - # Step 2: Ensure the bot has a LangChain assistant if not bot_instance.assistant: logger.error(f"No assistant configured for bot '{bot_name}'.") return JsonResponse({"error": "Assistant not configured."}, status=400) - # Step 3: Process POST request from Telegram if request.method == "POST": try: request_body = json.loads(request.body.decode("utf-8")) @@ -41,23 +46,61 @@ async def telegram_webhook(request, bot_name): logger.error(f"Failed to decode JSON: {e}") return JsonResponse({"error": "Invalid JSON payload"}, status=400) - # Step 4: Route commands to the appropriate handlers if update.message: - if update.message.text == "/start": - await start(update) - elif update.message.text == "/help": - await help_command(update) - elif update.message.text == "/dream_city": - await dream_city_command(update) - elif update.message.location: - await handle_location(update) - else: - # Step 5: Process AI-generated response using LangChain - assistant_instance = await sync_to_async(LangchainAIService)(bot_instance.assistant) - bot_response = await sync_to_async(assistant_instance.generate_response)(update.message.text) + text = update.message.text or "" - # Step 6: Send the response back to Telegram - await update.message.reply_text(bot_response) + # 🚀 Citizen bot + if bot_name == "pepebasurita": + if text == "/start": + await start(update) + elif text == "/help": + await help_command(update) + elif text == "/next_truck": + await next_truck(update) + elif text == "/report_trash": + await report_trash(update) + elif text == "/private_pickup": + await private_pickup(update) + elif text == "/green_balance": + await green_balance(update) + elif update.message.location: + await handle_location(update) + else: + assistant_instance = await sync_to_async(LangchainAIService)(bot_instance.assistant) + bot_response = await sync_to_async(assistant_instance.generate_response)(text) + await update.message.reply_text(bot_response) + + # 🚚 City collector bot + elif bot_name == "pepecamioncito": + if text == "/start": + await start(update) + elif text == "/help": + await help_command(update) + elif text == "/next_route": + await next_route(update) + elif text == "/complete_stop": + await complete_stop(update) + elif text == "/missed_stop": + await missed_stop(update) + elif text == "/my_eco_score": + await city_eco_score(update) + + # 🚛 Private collector bot + elif bot_name == "pepemotito": + if text == "/start": + await start(update) + elif text == "/help": + await help_command(update) + elif text == "/available_jobs": + await available_jobs(update) + elif text.startswith("/accept_job"): + await accept_job(update) + elif text == "/next_pickup": + await next_pickup(update) + elif text == "/complete_pickup": + await complete_pickup(update) + elif text == "/my_eco_score": + await private_eco_score(update) return JsonResponse({"status": "ok"})