Spaces:
Sleeping
Sleeping
| """ | |
| Chatbot API views for handling conversational queries. | |
| """ | |
| import json | |
| import logging | |
| import uuid | |
| from typing import Any, Dict | |
| from django.http import HttpRequest, JsonResponse | |
| from django.views.decorators.csrf import csrf_exempt | |
| from rest_framework import status | |
| from rest_framework.decorators import api_view | |
| from rest_framework.request import Request | |
| from rest_framework.response import Response | |
| from .chatbot import get_chatbot | |
| from hue_portal.chatbot.context_manager import ConversationContext | |
| logger = logging.getLogger(__name__) | |
| def chat_simple(request: HttpRequest) -> JsonResponse: | |
| """ | |
| Lightweight POST-only endpoint to help Spaces hit the chatbot without DRF. | |
| """ | |
| if request.method != "POST": | |
| return JsonResponse({"error": "Method not allowed"}, status=405) | |
| try: | |
| payload: Dict[str, Any] = json.loads(request.body.decode("utf-8")) | |
| except json.JSONDecodeError as exc: | |
| return JsonResponse( | |
| {"error": "Invalid JSON body", "details": str(exc)}, | |
| status=400, | |
| ) | |
| message: str = str(payload.get("message", "")).strip() | |
| session_id_raw = payload.get("session_id") or "" | |
| session_id: str = str(session_id_raw).strip() if session_id_raw else "" | |
| reset_session: bool = bool(payload.get("reset_session", False)) | |
| if not message: | |
| return JsonResponse({"error": "message is required"}, status=400) | |
| if reset_session: | |
| session_id = "" | |
| if not session_id: | |
| session_id = str(uuid.uuid4()) | |
| else: | |
| try: | |
| uuid.UUID(session_id) | |
| except ValueError: | |
| session_id = str(uuid.uuid4()) | |
| try: | |
| chatbot = get_chatbot() | |
| response = chatbot.generate_response(message, session_id=session_id) | |
| except Exception as exc: | |
| return JsonResponse( | |
| { | |
| "message": "Xin lỗi, có lỗi xảy ra. Vui lòng thử lại.", | |
| "intent": "error", | |
| "error": str(exc), | |
| "results": [], | |
| "count": 0, | |
| "session_id": session_id, | |
| }, | |
| status=500, | |
| ) | |
| if "session_id" not in response: | |
| response["session_id"] = session_id | |
| return JsonResponse(response, status=200) | |
| def chat(request: Request) -> Response: | |
| """ | |
| Chatbot endpoint for natural language queries with session support. | |
| Request body: | |
| { | |
| "message": "Mức phạt vượt đèn đỏ là bao nhiêu?", | |
| "session_id": "optional-uuid-string", | |
| "reset_session": false | |
| } | |
| Response: | |
| { | |
| "message": "Tôi tìm thấy 1 mức phạt liên quan đến '...':", | |
| "intent": "search_fine", | |
| "confidence": 0.95, | |
| "results": [...], | |
| "count": 1, | |
| "session_id": "uuid-string" | |
| } | |
| """ | |
| # Log raw request data for debugging | |
| raw_data = dict(request.data) if hasattr(request.data, 'get') else {} | |
| logger.info(f"[CHAT] 📥 Raw request data keys: {list(raw_data.keys())}, Content-Type: {request.content_type}") | |
| print(f"[CHAT] 📥 Raw request data keys: {list(raw_data.keys())}, Content-Type: {request.content_type}", flush=True) | |
| message = request.data.get("message", "").strip() | |
| session_id = request.data.get("session_id") or "" | |
| if session_id: | |
| session_id = str(session_id).strip() | |
| else: | |
| session_id = "" | |
| reset_session = request.data.get("reset_session", False) | |
| # Log received message for debugging | |
| message_preview = message[:100] + "..." if len(message) > 100 else message | |
| logger.info(f"[CHAT] 📨 Received POST request - Message: '{message_preview}' (length: {len(message)}), Session: {session_id[:8] if session_id else 'new'}") | |
| print(f"[CHAT] 📨 Received POST request - Message: '{message_preview}' (length: {len(message)}), Session: {session_id[:8] if session_id else 'new'}", flush=True) | |
| if not message: | |
| return Response( | |
| {"error": "message is required"}, | |
| status=status.HTTP_400_BAD_REQUEST | |
| ) | |
| # Handle session reset | |
| if reset_session: | |
| session_id = None | |
| # Generate new session_id if not provided | |
| if not session_id: | |
| session_id = str(uuid.uuid4()) | |
| else: | |
| # Validate session_id format | |
| try: | |
| uuid.UUID(session_id) | |
| except ValueError: | |
| # Invalid UUID format, generate new one | |
| session_id = str(uuid.uuid4()) | |
| try: | |
| logger.info(f"[CHAT] ⏳ Starting response generation for message (length: {len(message)})") | |
| print(f"[CHAT] ⏳ Starting response generation for message (length: {len(message)})", flush=True) | |
| chatbot = get_chatbot() | |
| response = chatbot.generate_response(message, session_id=session_id) | |
| # Ensure session_id is in response | |
| if "session_id" not in response: | |
| response["session_id"] = session_id | |
| response_preview = response.get("message", "")[:100] + "..." if len(response.get("message", "")) > 100 else response.get("message", "") | |
| logger.info(f"[CHAT] ✅ Response generated successfully - Intent: {response.get('intent', 'unknown')}, Response length: {len(response.get('message', ''))}") | |
| print(f"[CHAT] ✅ Response generated successfully - Intent: {response.get('intent', 'unknown')}, Response preview: '{response_preview}'", flush=True) | |
| return Response(response, status=status.HTTP_200_OK) | |
| except Exception as e: | |
| return Response( | |
| { | |
| "message": "Xin lỗi, có lỗi xảy ra. Vui lòng thử lại.", | |
| "intent": "error", | |
| "error": str(e), | |
| "results": [], | |
| "count": 0, | |
| "session_id": session_id | |
| }, | |
| status=status.HTTP_500_INTERNAL_SERVER_ERROR | |
| ) | |
| def health(request): | |
| """ | |
| Health check endpoint for chatbot service. | |
| """ | |
| try: | |
| chatbot = get_chatbot() | |
| return Response({ | |
| "status": "healthy", | |
| "service": "chatbot", | |
| "classifier_loaded": chatbot.intent_classifier is not None | |
| }) | |
| except Exception as e: | |
| return Response( | |
| {"status": "unhealthy", "error": str(e)}, | |
| status=status.HTTP_500_INTERNAL_SERVER_ERROR | |
| ) | |
| def test_init(request: Request) -> Response: | |
| """ | |
| Force chatbot initialization to validate startup on Hugging Face Spaces. | |
| """ | |
| try: | |
| chatbot = get_chatbot() | |
| return Response( | |
| { | |
| "status": "initialized", | |
| "classifier_loaded": chatbot.intent_classifier is not None, | |
| }, | |
| status=status.HTTP_200_OK, | |
| ) | |
| except Exception as exc: | |
| return Response( | |
| {"status": "error", "message": str(exc)}, | |
| status=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| ) | |
| def test_generate(request: Request) -> Response: | |
| """ | |
| Generate a quick response for smoke-testing LLM connectivity. | |
| """ | |
| message = request.data.get("message", "").strip() | |
| if not message: | |
| return Response( | |
| {"error": "message is required"}, | |
| status=status.HTTP_400_BAD_REQUEST, | |
| ) | |
| session_id = str(request.data.get("session_id") or uuid.uuid4()) | |
| try: | |
| chatbot = get_chatbot() | |
| response = chatbot.generate_response(message, session_id=session_id) | |
| response.setdefault("session_id", session_id) | |
| return Response(response, status=status.HTTP_200_OK) | |
| except Exception as exc: | |
| return Response( | |
| { | |
| "message": "Xin lỗi, có lỗi xảy ra. Vui lòng thử lại.", | |
| "intent": "error", | |
| "error": str(exc), | |
| "results": [], | |
| "count": 0, | |
| "session_id": session_id, | |
| }, | |
| status=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| ) | |
| def model_status(request: Request) -> Response: | |
| """ | |
| Provide lightweight diagnostics about the current chatbot instance. | |
| """ | |
| try: | |
| chatbot = get_chatbot() | |
| status_payload = { | |
| "intent_classifier_loaded": chatbot.intent_classifier is not None, | |
| "knowledge_base_ready": getattr(chatbot, "knowledge_base", None) is not None, | |
| "llm_provider": getattr(chatbot, "llm_provider", "unknown"), | |
| } | |
| return Response(status_payload, status=status.HTTP_200_OK) | |
| except Exception as exc: | |
| return Response( | |
| {"status": "error", "message": str(exc)}, | |
| status=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| ) | |