Telegram bot exception for sending messages by chat id
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Ekaropolus 2025-05-20 04:00:13 -06:00
parent 4092be0121
commit 206c4db278

View File

@ -1,11 +1,10 @@
import json import json
import logging import logging
from django.http import JsonResponse from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from asgiref.sync import sync_to_async
from telegram import Update, Bot from telegram import Update, Bot
from django.utils import timezone from django.utils import timezone
from django.conf import settings
from .models import TelegramBot, TelegramConversation, TelegramMessage from .models import TelegramBot, TelegramConversation, TelegramMessage
from pxy_langchain.services import LangchainAIService from pxy_langchain.services import LangchainAIService
@ -14,102 +13,107 @@ from .handlers import dream_city_command, start, help_command, handle_location
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@csrf_exempt @csrf_exempt
async def telegram_webhook(request, bot_name): def telegram_webhook(request, bot_name):
""" """
Telegram webhook handler that logs inbound/outbound messages and Webhook view for Telegram that logs inbound/outbound messages,
responds with AI or commands, resilient to Neo4j or send failures. handles commands and AI fallback, and always returns 200 OK.
Always returns 200 OK to prevent Telegram retries.
""" """
try: try:
logger.info(f"Webhook called for bot: {bot_name}") # 1) Sólo POST
# 1) Load bot configuration
try:
bot_instance = await sync_to_async(TelegramBot.objects.get)(
name=bot_name, is_active=True
)
except TelegramBot.DoesNotExist:
logger.error(f"Bot '{bot_name}' not found or inactive.")
return JsonResponse({"status": "ok", "error": f"Bot '{bot_name}' not found."}, status=200)
# 2) Ensure POST
if request.method != "POST": if request.method != "POST":
logger.warning("Received non-POST request to Telegram webhook.") logger.warning("Received non-POST request to Telegram webhook.")
return JsonResponse({"status": "ok"}, status=200) return JsonResponse({"status": "ok"})
# 3) Parse the update JSON # 2) Cargar configuración del bot
try:
bot_instance = TelegramBot.objects.get(name=bot_name, is_active=True)
except TelegramBot.DoesNotExist:
msg = f"Bot '{bot_name}' not found or inactive."
logger.error(msg)
return JsonResponse({"status": "ok", "error": msg})
# 3) Parsear el update
try: try:
payload = json.loads(request.body.decode("utf-8")) payload = json.loads(request.body.decode("utf-8"))
update = Update.de_json(payload, Bot(token=bot_instance.token)) update = Update.de_json(payload, Bot(token=bot_instance.token))
logger.info(f"Parsed update: {update}")
except Exception as e: except Exception as e:
logger.error(f"Failed to parse update JSON: {e}") logger.error(f"Failed to parse update JSON: {e}")
return JsonResponse({"status": "ok", "error": "Invalid JSON payload"}, status=200) return JsonResponse({"status": "ok", "error": "Invalid JSON payload"})
# 4) Log inbound message # 4) Loggear mensaje entrante
user_id = str(update.effective_user.id) if update.message and update.effective_user:
conv, _ = await sync_to_async(TelegramConversation.objects.get_or_create)( user_id = str(update.effective_user.id)
bot=bot_instance, conv, _ = TelegramConversation.objects.get_or_create(
user_id=user_id, bot=bot_instance,
defaults={'started_at': timezone.now()} user_id=user_id,
) defaults={"started_at": timezone.now()}
incoming_text = update.message.text or ""
try:
await sync_to_async(TelegramMessage.objects.create)(
conversation=conv,
direction=TelegramMessage.IN,
content=incoming_text
) )
except Exception as log_in_err: incoming_text = update.message.text or ""
logger.error(f"Error logging inbound message: {log_in_err}")
# 5) Handle commands or AI response
if update.message:
try: try:
text = update.message.text or "" TelegramMessage.objects.create(
conversation=conv,
direction=TelegramMessage.IN,
content=incoming_text
)
except Exception as log_in_err:
logger.error(f"Error logging inbound message: {log_in_err}")
else:
logger.warning("Update has no message or user info.")
# 5) Manejar comandos y fallback AI
reply = None
response_time = 0
if update.message:
text = update.message.text or ""
try:
# Comandos predefinidos
if text == "/start": if text == "/start":
await start(update) start(update)
elif text == "/help": elif text == "/help":
await help_command(update) help_command(update)
elif text == "/dream_city": elif text == "/dream_city":
await dream_city_command(update) dream_city_command(update)
elif update.message.location: elif update.message.location:
await handle_location(update) handle_location(update)
else: else:
# AI fallback with resilience # Fallback AI
try: try:
assistant = await sync_to_async(LangchainAIService)(bot_instance.assistant) assistant = LangchainAIService(bot_instance.assistant)
start_time = timezone.now() start_ts = timezone.now()
bot_response = await sync_to_async(assistant.generate_response)(text) reply = assistant.generate_response(text)
response_time = int((timezone.now() - start_time).total_seconds() * 1000) response_time = int((timezone.now() - start_ts).total_seconds() * 1000)
except Exception as ai_err: except Exception as ai_err:
logger.error(f"AI service error: {ai_err}") logger.error(f"AI service error: {ai_err}")
bot_response = "Lo siento, el servicio de IA no está disponible." reply = "Lo siento, el servicio de IA no está disponible."
response_time = 0 response_time = 0
# Send reply (skipped in DEBUG) # Enviar respuesta
if not settings.DEBUG: chat_id = update.message.chat.id
try:
await update.message.reply_text(bot_response)
except Exception as send_err:
logger.error(f"Error sending message to Telegram: {send_err}")
# Log outbound message
try: try:
await sync_to_async(TelegramMessage.objects.create)( Bot(token=bot_instance.token).send_message(
chat_id=chat_id,
text=reply
)
except Exception as send_err:
logger.error(f"Error sending message to Telegram (chat {chat_id}): {send_err}")
# Loggear mensaje saliente
try:
TelegramMessage.objects.create(
conversation=conv, conversation=conv,
direction=TelegramMessage.OUT, direction=TelegramMessage.OUT,
content=bot_response, content=reply,
response_time_ms=response_time response_time_ms=response_time
) )
except Exception as log_out_err: except Exception as log_out_err:
logger.error(f"Error logging outbound message: {log_out_err}") logger.error(f"Error logging outbound message: {log_out_err}")
except Exception as cmd_err: except Exception as cmd_err:
logger.error(f"Error processing Telegram commands: {cmd_err}") logger.error(f"Error processing Telegram commands: {cmd_err}")
# 6) Always return 200 OK # 6) Devolver siempre 200 OK
return JsonResponse({"status": "ok"}, status=200) return JsonResponse({"status": "ok"})
except Exception as e: except Exception as e:
logger.error(f"Unexpected error in telegram_webhook: {e}") logger.error(f"Unexpected error in telegram_webhook: {e}")
return JsonResponse({"status": "ok", "error": str(e)}, status=200) return JsonResponse({"status": "ok", "error": str(e)})