Update core/conversational_agent.py
Browse files- core/conversational_agent.py +106 -63
core/conversational_agent.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
| 1 |
import time
|
| 2 |
import traceback
|
| 3 |
-
from typing import List, Dict, Any, Tuple
|
| 4 |
-
from sentence_transformers import SentenceTransformer
|
| 5 |
from models.schemas import RAGSearchResult
|
| 6 |
from core.multilingual_manager import MultilingualManager
|
| 7 |
from core.enhanced_rag import EnhancedRAGSystem
|
|
@@ -18,11 +17,11 @@ class ConversationalAgent:
|
|
| 18 |
def process_query(self, query: str, chat_history: List[Tuple[str, str]] = None) -> Tuple[str, List[Dict]]:
|
| 19 |
"""Xử lý truy vấn hội thoại với grounding từ RAG"""
|
| 20 |
try:
|
| 21 |
-
print(f"🤖 Xử lý truy vấn: {query}")
|
| 22 |
|
| 23 |
# Phát hiện ngôn ngữ
|
| 24 |
language = self.multilingual_manager.detect_language(query)
|
| 25 |
-
print(f"🌐 Ngôn ngữ phát hiện: {language}")
|
| 26 |
|
| 27 |
# Tìm kiếm ngữ nghĩa trong RAG
|
| 28 |
search_results = self.rag_system.semantic_search(query, top_k=3)
|
|
@@ -36,18 +35,28 @@ class ConversationalAgent:
|
|
| 36 |
# Tạo prompt với context
|
| 37 |
prompt = self._create_grounded_prompt(query, context, language, chat_history)
|
| 38 |
|
| 39 |
-
# Tạo phản hồi (
|
| 40 |
-
response = self._generate_response(prompt, language)
|
| 41 |
|
| 42 |
# Cập nhật lịch sử
|
| 43 |
self._update_conversation_history("assistant", response)
|
| 44 |
|
| 45 |
-
#
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
except Exception as e:
|
| 49 |
error_msg = f"Xin lỗi, đã có lỗi xảy ra: {str(e)}"
|
| 50 |
-
print(f"❌ Lỗi
|
| 51 |
return error_msg, []
|
| 52 |
|
| 53 |
def _build_context_from_results(self, results: List[RAGSearchResult], query: str, language: str) -> str:
|
|
@@ -59,17 +68,20 @@ class ConversationalAgent:
|
|
| 59 |
return "No relevant information found in the knowledge base."
|
| 60 |
|
| 61 |
if language == 'vi':
|
| 62 |
-
context_parts = [f"
|
| 63 |
else:
|
| 64 |
-
context_parts = [f"
|
| 65 |
|
| 66 |
for i, result in enumerate(results[:3]): # Lấy 3 kết quả đầu
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
|
|
|
|
|
|
|
|
|
| 73 |
|
| 74 |
return "\n".join(context_parts)
|
| 75 |
|
|
@@ -81,84 +93,117 @@ class ConversationalAgent:
|
|
| 81 |
history_text = ""
|
| 82 |
if chat_history and len(chat_history) > 0:
|
| 83 |
if language == 'vi':
|
| 84 |
-
history_parts = ["Lịch sử hội thoại
|
| 85 |
-
for user_msg, assistant_msg in chat_history[-
|
| 86 |
-
history_parts.append(f"
|
| 87 |
history_parts.append(f"Trợ lý: {assistant_msg}")
|
| 88 |
else:
|
| 89 |
-
history_parts = ["
|
| 90 |
-
for user_msg, assistant_msg in chat_history[-
|
| 91 |
-
history_parts.append(f"
|
| 92 |
history_parts.append(f"Assistant: {assistant_msg}")
|
| 93 |
history_text = "\n".join(history_parts) + "\n\n"
|
| 94 |
|
| 95 |
# Tạo prompt dựa trên ngôn ngữ
|
| 96 |
if language == 'vi':
|
| 97 |
-
prompt = f"""{history_text}
|
| 98 |
{context}
|
| 99 |
|
| 100 |
CÂU HỎI HIỆN TẠI: {query}
|
| 101 |
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
|
| 109 |
TRẢ LỜI:"""
|
| 110 |
else:
|
| 111 |
-
prompt = f"""{history_text}
|
| 112 |
{context}
|
| 113 |
|
| 114 |
CURRENT QUESTION: {query}
|
| 115 |
|
| 116 |
INSTRUCTIONS:
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
|
| 123 |
ANSWER:"""
|
| 124 |
|
| 125 |
return prompt
|
| 126 |
|
| 127 |
-
def _generate_response(self, prompt: str, language: str) -> str:
|
| 128 |
-
"""Tạo phản hồi từ prompt (
|
| 129 |
# Đây là mô phỏng - trong thực tế sẽ gọi API LLM
|
| 130 |
-
time.sleep(0.
|
| 131 |
-
|
| 132 |
-
# Phân tích prompt để tạo phản hồi phù hợp
|
| 133 |
-
no_info_vi = "Không có thông tin liên quan trong cơ sở tri thức"
|
| 134 |
-
no_info_en = "No relevant information found in the knowledge base"
|
| 135 |
|
| 136 |
-
if
|
| 137 |
if language == 'vi':
|
| 138 |
-
return "Xin lỗi, tôi không tìm thấy thông tin cụ thể về
|
| 139 |
else:
|
| 140 |
-
return "Sorry, I couldn't find specific information about this
|
|
|
|
|
|
|
|
|
|
| 141 |
|
| 142 |
# Tạo phản hồi dựa trên ngôn ngữ
|
| 143 |
if language == 'vi':
|
| 144 |
responses = [
|
| 145 |
-
"Dựa trên thông tin
|
| 146 |
-
"Theo
|
| 147 |
-
"
|
| 148 |
]
|
| 149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
else:
|
| 151 |
responses = [
|
| 152 |
-
"Based on
|
| 153 |
-
"According to
|
| 154 |
-
"Based on the
|
| 155 |
]
|
| 156 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
|
| 158 |
import random
|
| 159 |
base_response = random.choice(responses)
|
| 160 |
|
| 161 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 162 |
|
| 163 |
def _update_conversation_history(self, role: str, message: str):
|
| 164 |
"""Cập nhật lịch sử hội thoại"""
|
|
@@ -175,7 +220,7 @@ ANSWER:"""
|
|
| 175 |
def clear_conversation_history(self):
|
| 176 |
"""Xóa lịch sử hội thoại"""
|
| 177 |
self.conversation_history = []
|
| 178 |
-
print("🧹 Đã xóa lịch sử hội thoại")
|
| 179 |
|
| 180 |
def get_conversation_stats(self) -> Dict:
|
| 181 |
"""Lấy thống kê hội thoại"""
|
|
@@ -186,10 +231,8 @@ ANSWER:"""
|
|
| 186 |
"total_messages": len(self.conversation_history),
|
| 187 |
"user_messages": len(user_msgs),
|
| 188 |
"assistant_messages": len(assistant_msgs),
|
| 189 |
-
"
|
| 190 |
-
"
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
"""Lấy lịch sử hội thoại gần đây"""
|
| 195 |
-
return self.conversation_history[-limit:] if self.conversation_history else []
|
|
|
|
| 1 |
import time
|
| 2 |
import traceback
|
| 3 |
+
from typing import List, Dict, Any, Tuple, Optional
|
|
|
|
| 4 |
from models.schemas import RAGSearchResult
|
| 5 |
from core.multilingual_manager import MultilingualManager
|
| 6 |
from core.enhanced_rag import EnhancedRAGSystem
|
|
|
|
| 17 |
def process_query(self, query: str, chat_history: List[Tuple[str, str]] = None) -> Tuple[str, List[Dict]]:
|
| 18 |
"""Xử lý truy vấn hội thoại với grounding từ RAG"""
|
| 19 |
try:
|
| 20 |
+
print(f"🤖 CAG: Xử lý truy vấn: {query}")
|
| 21 |
|
| 22 |
# Phát hiện ngôn ngữ
|
| 23 |
language = self.multilingual_manager.detect_language(query)
|
| 24 |
+
print(f"🌐 CAG: Ngôn ngữ phát hiện: {language}")
|
| 25 |
|
| 26 |
# Tìm kiếm ngữ nghĩa trong RAG
|
| 27 |
search_results = self.rag_system.semantic_search(query, top_k=3)
|
|
|
|
| 35 |
# Tạo prompt với context
|
| 36 |
prompt = self._create_grounded_prompt(query, context, language, chat_history)
|
| 37 |
|
| 38 |
+
# Tạo phản hồi (mô phỏng - có thể tích hợp LLM thực)
|
| 39 |
+
response = self._generate_response(prompt, language, search_results)
|
| 40 |
|
| 41 |
# Cập nhật lịch sử
|
| 42 |
self._update_conversation_history("assistant", response)
|
| 43 |
|
| 44 |
+
# Convert results to dict
|
| 45 |
+
results_dict = []
|
| 46 |
+
for result in search_results:
|
| 47 |
+
results_dict.append({
|
| 48 |
+
"id": result.id,
|
| 49 |
+
"text": result.text[:150] + "..." if len(result.text) > 150 else result.text,
|
| 50 |
+
"similarity": round(result.similarity, 3),
|
| 51 |
+
"metadata": result.metadata
|
| 52 |
+
})
|
| 53 |
+
|
| 54 |
+
print(f"✅ CAG: Đã xử lý, tìm thấy {len(results_dict)} kết quả")
|
| 55 |
+
return response, results_dict
|
| 56 |
|
| 57 |
except Exception as e:
|
| 58 |
error_msg = f"Xin lỗi, đã có lỗi xảy ra: {str(e)}"
|
| 59 |
+
print(f"❌ CAG Lỗi: {traceback.format_exc()}")
|
| 60 |
return error_msg, []
|
| 61 |
|
| 62 |
def _build_context_from_results(self, results: List[RAGSearchResult], query: str, language: str) -> str:
|
|
|
|
| 68 |
return "No relevant information found in the knowledge base."
|
| 69 |
|
| 70 |
if language == 'vi':
|
| 71 |
+
context_parts = [f"Thông tin liên quan đến '{query}':"]
|
| 72 |
else:
|
| 73 |
+
context_parts = [f"Relevant information about '{query}':"]
|
| 74 |
|
| 75 |
for i, result in enumerate(results[:3]): # Lấy 3 kết quả đầu
|
| 76 |
+
source = result.metadata.get('source', 'unknown')
|
| 77 |
+
lang = result.metadata.get('language', 'unknown')
|
| 78 |
+
|
| 79 |
+
if language == 'vi':
|
| 80 |
+
context_parts.append(f"\n{i+1}. {result.text}")
|
| 81 |
+
context_parts.append(f" (Nguồn: {source}, Ngôn ngữ: {lang})")
|
| 82 |
+
else:
|
| 83 |
+
context_parts.append(f"\n{i+1}. {result.text}")
|
| 84 |
+
context_parts.append(f" (Source: {source}, Language: {lang})")
|
| 85 |
|
| 86 |
return "\n".join(context_parts)
|
| 87 |
|
|
|
|
| 93 |
history_text = ""
|
| 94 |
if chat_history and len(chat_history) > 0:
|
| 95 |
if language == 'vi':
|
| 96 |
+
history_parts = ["Lịch sử hội thoại trước:"]
|
| 97 |
+
for user_msg, assistant_msg in chat_history[-2:]: # Lấy 2 cặp gần nhất
|
| 98 |
+
history_parts.append(f"Bạn: {user_msg}")
|
| 99 |
history_parts.append(f"Trợ lý: {assistant_msg}")
|
| 100 |
else:
|
| 101 |
+
history_parts = ["Previous conversation:"]
|
| 102 |
+
for user_msg, assistant_msg in chat_history[-2:]:
|
| 103 |
+
history_parts.append(f"You: {user_msg}")
|
| 104 |
history_parts.append(f"Assistant: {assistant_msg}")
|
| 105 |
history_text = "\n".join(history_parts) + "\n\n"
|
| 106 |
|
| 107 |
# Tạo prompt dựa trên ngôn ngữ
|
| 108 |
if language == 'vi':
|
| 109 |
+
prompt = f"""{history_text}THÔNG TIN TỪ CƠ SỞ DỮ LIỆU:
|
| 110 |
{context}
|
| 111 |
|
| 112 |
CÂU HỎI HIỆN TẠI: {query}
|
| 113 |
|
| 114 |
+
YÊU CẦU:
|
| 115 |
+
- Trả lời dựa trên thông tin được cung cấp
|
| 116 |
+
- Nếu thiếu thông tin, hãy nói rõ
|
| 117 |
+
- Trả lời bằng tiếng Việt
|
| 118 |
+
- Ngắn gọn, chính xác
|
| 119 |
+
- Có thể thêm thông tin bổ sung nếu cần
|
| 120 |
|
| 121 |
TRẢ LỜI:"""
|
| 122 |
else:
|
| 123 |
+
prompt = f"""{history_text}INFORMATION FROM DATABASE:
|
| 124 |
{context}
|
| 125 |
|
| 126 |
CURRENT QUESTION: {query}
|
| 127 |
|
| 128 |
INSTRUCTIONS:
|
| 129 |
+
- Answer based on provided information
|
| 130 |
+
- If information is insufficient, clearly state that
|
| 131 |
+
- Respond in {language}
|
| 132 |
+
- Be concise and accurate
|
| 133 |
+
- You may add supplementary information if needed
|
| 134 |
|
| 135 |
ANSWER:"""
|
| 136 |
|
| 137 |
return prompt
|
| 138 |
|
| 139 |
+
def _generate_response(self, prompt: str, language: str, search_results: List[RAGSearchResult]) -> str:
|
| 140 |
+
"""Tạo phản hồi từ prompt (mô phỏng)"""
|
| 141 |
# Đây là mô phỏng - trong thực tế sẽ gọi API LLM
|
| 142 |
+
time.sleep(0.3) # Giả lập thời gian xử lý
|
|
|
|
|
|
|
|
|
|
|
|
|
| 143 |
|
| 144 |
+
if not search_results:
|
| 145 |
if language == 'vi':
|
| 146 |
+
return "Xin lỗi, tôi không tìm thấy thông tin cụ thể về chủ đề này trong cơ sở dữ liệu hiện tại. Bạn có thể thử diễn đạt khác hoặc thêm thông tin mới."
|
| 147 |
else:
|
| 148 |
+
return "Sorry, I couldn't find specific information about this topic in the current database. You might try rephrasing or adding new information."
|
| 149 |
+
|
| 150 |
+
# Đếm số kết quả
|
| 151 |
+
result_count = len(search_results)
|
| 152 |
|
| 153 |
# Tạo phản hồi dựa trên ngôn ngữ
|
| 154 |
if language == 'vi':
|
| 155 |
responses = [
|
| 156 |
+
f"Dựa trên {result_count} thông tin liên quan tôi tìm thấy:",
|
| 157 |
+
f"Theo {result_count} nguồn thông tin từ cơ sở dữ liệu:",
|
| 158 |
+
f"Căn cứ vào {result_count} kết quả tìm kiếm:"
|
| 159 |
]
|
| 160 |
+
|
| 161 |
+
# Lấy các chủ đề chính
|
| 162 |
+
sources = []
|
| 163 |
+
for result in search_results[:2]:
|
| 164 |
+
source = result.metadata.get('source', '')
|
| 165 |
+
if source and source not in sources:
|
| 166 |
+
sources.append(source)
|
| 167 |
+
|
| 168 |
+
if sources:
|
| 169 |
+
source_text = f" (từ {', '.join(sources)})"
|
| 170 |
+
else:
|
| 171 |
+
source_text = ""
|
| 172 |
+
|
| 173 |
+
follow_up = f"\n\nĐây là thông tin hữu ích tôi tìm được{source_text}. Bạn có thể xem chi tiết các nguồn thông tin bên phải."
|
| 174 |
+
|
| 175 |
else:
|
| 176 |
responses = [
|
| 177 |
+
f"Based on {result_count} relevant information sources:",
|
| 178 |
+
f"According to {result_count} data sources from the database:",
|
| 179 |
+
f"Based on the search results ({result_count} found):"
|
| 180 |
]
|
| 181 |
+
|
| 182 |
+
# Get main sources
|
| 183 |
+
sources = []
|
| 184 |
+
for result in search_results[:2]:
|
| 185 |
+
source = result.metadata.get('source', '')
|
| 186 |
+
if source and source not in sources:
|
| 187 |
+
sources.append(source)
|
| 188 |
+
|
| 189 |
+
if sources:
|
| 190 |
+
source_text = f" (from {', '.join(sources)})"
|
| 191 |
+
else:
|
| 192 |
+
source_text = ""
|
| 193 |
+
|
| 194 |
+
follow_up = f"\n\nThis is useful information I found{source_text}. You can view the detailed sources on the right."
|
| 195 |
|
| 196 |
import random
|
| 197 |
base_response = random.choice(responses)
|
| 198 |
|
| 199 |
+
# Thêm nội dung cụ thể từ kết quả đầu tiên
|
| 200 |
+
if search_results and len(search_results[0].text) > 50:
|
| 201 |
+
main_info = search_results[0].text[:200] + "..." if len(search_results[0].text) > 200 else search_results[0].text
|
| 202 |
+
response = f"{base_response}\n\n{main_info}{follow_up}"
|
| 203 |
+
else:
|
| 204 |
+
response = f"{base_response}{follow_up}"
|
| 205 |
+
|
| 206 |
+
return response
|
| 207 |
|
| 208 |
def _update_conversation_history(self, role: str, message: str):
|
| 209 |
"""Cập nhật lịch sử hội thoại"""
|
|
|
|
| 220 |
def clear_conversation_history(self):
|
| 221 |
"""Xóa lịch sử hội thoại"""
|
| 222 |
self.conversation_history = []
|
| 223 |
+
print("🧹 CAG: Đã xóa lịch sử hội thoại")
|
| 224 |
|
| 225 |
def get_conversation_stats(self) -> Dict:
|
| 226 |
"""Lấy thống kê hội thoại"""
|
|
|
|
| 231 |
"total_messages": len(self.conversation_history),
|
| 232 |
"user_messages": len(user_msgs),
|
| 233 |
"assistant_messages": len(assistant_msgs),
|
| 234 |
+
"current_session": len(self.conversation_history),
|
| 235 |
+
"last_interaction": time.strftime('%H:%M:%S', time.localtime(
|
| 236 |
+
self.conversation_history[-1]["timestamp"] if self.conversation_history else time.time()
|
| 237 |
+
))
|
| 238 |
+
}
|
|
|
|
|
|