import json import logging from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from telegram import Update, Bot from django.utils import timezone from .models import TelegramBot, TelegramConversation, TelegramMessage from pxy_langchain.services import LangchainAIService from .handlers import dream_city_command, start, help_command, handle_location logger = logging.getLogger(__name__) @csrf_exempt def telegram_webhook(request, bot_name): """ Webhook view for Telegram that logs inbound/outbound messages, handles commands and AI fallback, and always returns 200 OK. """ try: # 1) Sólo POST if request.method != "POST": logger.warning("Received non-POST request to Telegram webhook.") return JsonResponse({"status": "ok"}) # 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: payload = json.loads(request.body.decode("utf-8")) update = Update.de_json(payload, Bot(token=bot_instance.token)) except Exception as e: logger.error(f"Failed to parse update JSON: {e}") return JsonResponse({"status": "ok", "error": "Invalid JSON payload"}) # 4) Loggear mensaje entrante if update.message and update.effective_user: user_id = str(update.effective_user.id) conv, _ = TelegramConversation.objects.get_or_create( bot=bot_instance, user_id=user_id, defaults={"started_at": timezone.now()} ) incoming_text = update.message.text or "" try: 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": start(update) elif text == "/help": help_command(update) elif text == "/dream_city": dream_city_command(update) elif update.message.location: handle_location(update) else: # Fallback AI try: assistant = LangchainAIService(bot_instance.assistant) start_ts = timezone.now() reply = assistant.generate_response(text) response_time = int((timezone.now() - start_ts).total_seconds() * 1000) except Exception as ai_err: logger.error(f"AI service error: {ai_err}") reply = "Lo siento, el servicio de IA no está disponible." response_time = 0 # Enviar respuesta chat_id = update.message.chat.id try: 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, direction=TelegramMessage.OUT, content=reply, response_time_ms=response_time ) except Exception as log_out_err: logger.error(f"Error logging outbound message: {log_out_err}") except Exception as cmd_err: logger.error(f"Error processing Telegram commands: {cmd_err}") # 6) Devolver siempre 200 OK return JsonResponse({"status": "ok"}) except Exception as e: logger.error(f"Unexpected error in telegram_webhook: {e}") return JsonResponse({"status": "ok", "error": str(e)})