Spaces:
Sleeping
Sleeping
| from flask import Blueprint, request, jsonify | |
| import logging | |
| from core.rag_pipeline import RAGPipeline | |
| from core.embedding_model import get_embedding_model | |
| from models.conversation_model import Conversation | |
| from flask_jwt_extended import jwt_required, get_jwt_identity | |
| import datetime | |
| # Cấu hình logging | |
| logger = logging.getLogger(__name__) | |
| # Tạo blueprint | |
| chat_routes = Blueprint('chat', __name__) | |
| # Khởi tạo RAG Pipeline một lần duy nhất khi module được load | |
| rag_pipeline = None | |
| def get_rag_pipeline(): | |
| """Singleton pattern để tránh khởi tạo lại RAG Pipeline""" | |
| global rag_pipeline | |
| if rag_pipeline is None: | |
| logger.info("Khởi tạo RAG Pipeline lần đầu") | |
| rag_pipeline = RAGPipeline() | |
| return rag_pipeline | |
| # Hàm tạo tiêu đề từ tin nhắn | |
| def create_title_from_message(message, max_length=50): | |
| """Tạo tiêu đề cuộc trò chuyện từ tin nhắn đầu tiên của người dùng""" | |
| message = message.strip().replace('\n', ' ') | |
| if len(message) <= max_length: | |
| return message | |
| return message[:max_length-3] + "..." | |
| def chat(): | |
| """API endpoint để xử lý tin nhắn chat""" | |
| try: | |
| data = request.json | |
| message = data.get('message') | |
| age = data.get('age', 1) | |
| conversation_id = data.get('conversation_id') | |
| user_id = get_jwt_identity() | |
| if not message: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Vui lòng nhập tin nhắn" | |
| }), 400 | |
| logger.info(f"Nhận tin nhắn từ user {user_id}: {message[:50]}...") | |
| # Xử lý conversation | |
| if conversation_id: | |
| conversation = Conversation.find_by_id(conversation_id) | |
| if not conversation or str(conversation.user_id) != user_id: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Không tìm thấy cuộc trò chuyện" | |
| }), 404 | |
| if len(conversation.messages) == 0: | |
| final_title = create_title_from_message(message, 50) | |
| conversation.title = final_title | |
| logger.info(f"Cập nhật title cho conversation {conversation_id}: '{final_title}'") | |
| else: | |
| final_title = create_title_from_message(message, 50) | |
| conversation = Conversation.create( | |
| user_id=user_id, | |
| title=final_title, | |
| age_context=age | |
| ) | |
| logger.info(f"Tạo conversation mới với title: '{final_title}'") | |
| # Thêm tin nhắn của user | |
| conversation.add_message("user", message) | |
| # Sử dụng RAG Pipeline để generate response | |
| pipeline = get_rag_pipeline() | |
| # Generate response sử dụng RAG | |
| logger.info("Bắt đầu generate response với RAG Pipeline") | |
| response_data = pipeline.generate_response(message, age) | |
| if response_data.get("success"): | |
| bot_response = response_data.get("response", "Xin lỗi, tôi không thể trả lời câu hỏi này.") | |
| sources = response_data.get("sources", []) | |
| # Thêm tin nhắn bot vào conversation | |
| conversation.add_message("bot", bot_response, sources=sources) | |
| logger.info(f"Đã generate response thành công cho conversation {conversation.conversation_id}") | |
| return jsonify({ | |
| "success": True, | |
| "response": bot_response, | |
| "sources": sources, | |
| "conversation_id": str(conversation.conversation_id) | |
| }) | |
| else: | |
| error_msg = response_data.get("error", "Không thể tạo phản hồi") | |
| logger.error(f"Lỗi generate response: {error_msg}") | |
| return jsonify({ | |
| "success": False, | |
| "error": error_msg | |
| }), 500 | |
| except Exception as e: | |
| logger.error(f"Lỗi xử lý chat: {str(e)}") | |
| return jsonify({ | |
| "success": False, | |
| "error": f"Lỗi máy chủ: {str(e)}" | |
| }), 500 | |
| def edit_message(message_id): | |
| """API endpoint để chỉnh sửa tin nhắn""" | |
| try: | |
| data = request.json | |
| new_content = data.get('content') | |
| conversation_id = data.get('conversation_id') | |
| age = data.get('age', 1) | |
| user_id = get_jwt_identity() | |
| if not new_content or not conversation_id: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Thiếu thông tin cần thiết" | |
| }), 400 | |
| logger.info(f"Edit message {message_id} in conversation {conversation_id}: {new_content[:50]}...") | |
| # Tìm conversation | |
| conversation = Conversation.find_by_id(conversation_id) | |
| if not conversation or str(conversation.user_id) != user_id: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Không tìm thấy cuộc trò chuyện" | |
| }), 404 | |
| # Tìm message và kiểm tra quyền | |
| message_found = False | |
| for msg in conversation.messages: | |
| if str(msg.get('_id', msg.get('id'))) == message_id: | |
| if msg['role'] != 'user': | |
| return jsonify({ | |
| "success": False, | |
| "error": "Chỉ có thể chỉnh sửa tin nhắn của người dùng" | |
| }), 400 | |
| message_found = True | |
| break | |
| if not message_found: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Không tìm thấy tin nhắn" | |
| }), 404 | |
| # Cập nhật tin nhắn và xóa tất cả tin nhắn sau nó | |
| success, result_message = conversation.edit_message(message_id, new_content) | |
| if not success: | |
| return jsonify({ | |
| "success": False, | |
| "error": result_message | |
| }), 400 | |
| # Tạo phản hồi mới với RAG Pipeline | |
| pipeline = get_rag_pipeline() | |
| response_data = pipeline.generate_response(new_content, age) | |
| if response_data.get("success"): | |
| bot_response = response_data.get("response", "Xin lỗi, tôi không thể trả lời câu hỏi này.") | |
| sources = response_data.get("sources", []) | |
| # Thêm phản hồi bot mới | |
| success, bot_message = conversation.regenerate_bot_response_after_edit(message_id, bot_response, sources) | |
| if success: | |
| # Trả về conversation đã cập nhật | |
| updated_conversation = Conversation.find_by_id(conversation_id) | |
| logger.info(f"Successfully edited message and generated new response") | |
| return jsonify({ | |
| "success": True, | |
| "message": "Đã chỉnh sửa tin nhắn và tạo phản hồi mới", | |
| "conversation": updated_conversation.to_dict() | |
| }) | |
| else: | |
| return jsonify({ | |
| "success": False, | |
| "error": bot_message | |
| }), 500 | |
| else: | |
| return jsonify({ | |
| "success": False, | |
| "error": response_data.get("error", "Không thể tạo phản hồi mới") | |
| }), 500 | |
| except Exception as e: | |
| logger.error(f"Lỗi chỉnh sửa tin nhắn: {str(e)}") | |
| return jsonify({ | |
| "success": False, | |
| "error": f"Lỗi máy chủ: {str(e)}" | |
| }), 500 | |
| def regenerate_response(message_id): | |
| """API endpoint để tạo lại phản hồi""" | |
| try: | |
| data = request.json | |
| conversation_id = data.get('conversation_id') | |
| age = data.get('age', 1) | |
| user_id = get_jwt_identity() | |
| if not conversation_id: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Thiếu conversation_id" | |
| }), 400 | |
| logger.info(f"Regenerate response for message {message_id} in conversation {conversation_id}") | |
| # Tìm conversation | |
| conversation = Conversation.find_by_id(conversation_id) | |
| if not conversation or str(conversation.user_id) != user_id: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Không tìm thấy cuộc trò chuyện" | |
| }), 404 | |
| # Tìm tin nhắn và tin nhắn user trước đó | |
| user_message = None | |
| for i, msg in enumerate(conversation.messages): | |
| if str(msg.get('_id', msg.get('id'))) == message_id: | |
| if msg['role'] != 'bot': | |
| return jsonify({ | |
| "success": False, | |
| "error": "Chỉ có thể regenerate phản hồi của bot" | |
| }), 400 | |
| # Tìm tin nhắn user trước đó | |
| if i > 0 and conversation.messages[i-1]['role'] == 'user': | |
| user_message = conversation.messages[i-1]['content'] | |
| break | |
| if not user_message: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Không tìm thấy tin nhắn người dùng tương ứng" | |
| }), 404 | |
| # Sử dụng RAG Pipeline để generate response mới | |
| pipeline = get_rag_pipeline() | |
| response_data = pipeline.generate_response(user_message, age) | |
| if response_data.get("success"): | |
| bot_response = response_data.get("response", "Xin lỗi, tôi không thể trả lời câu hỏi này.") | |
| sources = response_data.get("sources", []) | |
| success, result_message = conversation.regenerate_response(message_id, bot_response, sources) | |
| if success: | |
| # Trả về conversation đã cập nhật | |
| updated_conversation = Conversation.find_by_id(conversation_id) | |
| logger.info(f"Successfully regenerated response") | |
| return jsonify({ | |
| "success": True, | |
| "conversation": updated_conversation.to_dict() | |
| }) | |
| else: | |
| return jsonify({ | |
| "success": False, | |
| "error": result_message | |
| }), 400 | |
| else: | |
| return jsonify({ | |
| "success": False, | |
| "error": response_data.get("error", "Không thể tạo phản hồi mới") | |
| }), 500 | |
| except Exception as e: | |
| logger.error(f"Lỗi regenerate response: {str(e)}") | |
| return jsonify({ | |
| "success": False, | |
| "error": f"Lỗi máy chủ: {str(e)}" | |
| }), 500 | |
| def switch_message_version(message_id, version): | |
| """API endpoint để chuyển đổi version của tin nhắn""" | |
| try: | |
| data = request.json | |
| conversation_id = data.get('conversation_id') | |
| user_id = get_jwt_identity() | |
| if not conversation_id: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Thiếu conversation_id" | |
| }), 400 | |
| logger.info(f"Switching message {message_id} to version {version} in conversation {conversation_id}") | |
| # Tìm conversation | |
| conversation = Conversation.find_by_id(conversation_id) | |
| if not conversation or str(conversation.user_id) != user_id: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Không tìm thấy cuộc trò chuyện" | |
| }), 404 | |
| # Debug: Log current conversation state before switch | |
| logger.info(f"Before switch - Conversation has {len(conversation.messages)} messages") | |
| for i, msg in enumerate(conversation.messages): | |
| logger.info(f" Message {i}: {msg['role']} - {msg['content'][:30]}... (current_version: {msg.get('current_version', 1)})") | |
| # Chuyển đổi version | |
| success = conversation.switch_message_version(message_id, version) | |
| if success: | |
| # Reload conversation để đảm bảo có dữ liệu mới nhất | |
| updated_conversation = Conversation.find_by_id(conversation_id) | |
| # Debug: Log conversation state after switch | |
| logger.info(f"After switch - Conversation has {len(updated_conversation.messages)} messages") | |
| for i, msg in enumerate(updated_conversation.messages): | |
| logger.info(f" Message {i}: {msg['role']} - {msg['content'][:30]}... (current_version: {msg.get('current_version', 1)})") | |
| logger.info(f"Successfully switched message {message_id} to version {version}") | |
| return jsonify({ | |
| "success": True, | |
| "conversation": updated_conversation.to_dict() | |
| }) | |
| else: | |
| logger.error(f"Failed to switch message {message_id} to version {version}") | |
| return jsonify({ | |
| "success": False, | |
| "error": "Không thể chuyển đổi version" | |
| }), 400 | |
| except Exception as e: | |
| logger.error(f"Lỗi chuyển đổi version: {str(e)}") | |
| return jsonify({ | |
| "success": False, | |
| "error": f"Lỗi máy chủ: {str(e)}" | |
| }), 500 | |
| def delete_message_and_following(message_id): | |
| """API endpoint để xóa tin nhắn và tất cả tin nhắn sau nó""" | |
| try: | |
| data = request.json | |
| conversation_id = data.get('conversation_id') | |
| user_id = get_jwt_identity() | |
| if not conversation_id: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Thiếu conversation_id" | |
| }), 400 | |
| # Tìm conversation | |
| conversation = Conversation.find_by_id(conversation_id) | |
| if not conversation or str(conversation.user_id) != user_id: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Không tìm thấy cuộc trò chuyện" | |
| }), 404 | |
| # Xóa tin nhắn và các tin nhắn theo sau | |
| success = conversation.delete_message_and_following(message_id) | |
| if success: | |
| updated_conversation = Conversation.find_by_id(conversation_id) | |
| return jsonify({ | |
| "success": True, | |
| "conversation": updated_conversation.to_dict() | |
| }) | |
| else: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Không thể xóa tin nhắn" | |
| }), 400 | |
| except Exception as e: | |
| logger.error(f"Lỗi xóa tin nhắn: {str(e)}") | |
| return jsonify({ | |
| "success": False, | |
| "error": f"Lỗi máy chủ: {str(e)}" | |
| }), 500 |