add history to analyze
Browse files- app/constants.py +1 -1
- app/llm.py +10 -8
- app/message_processor.py +39 -36
app/constants.py
CHANGED
|
@@ -192,4 +192,4 @@ FOUND_REGULATIONS_MESSAGES = [
|
|
| 192 |
]
|
| 193 |
|
| 194 |
SHEET_RANGE = 'chat!A2:N'
|
| 195 |
-
VERSION_NUMBER =
|
|
|
|
| 192 |
]
|
| 193 |
|
| 194 |
SHEET_RANGE = 'chat!A2:N'
|
| 195 |
+
VERSION_NUMBER = 123456790
|
app/llm.py
CHANGED
|
@@ -393,7 +393,8 @@ class LLMClient:
|
|
| 393 |
@timing_decorator_async
|
| 394 |
async def analyze(
|
| 395 |
self,
|
| 396 |
-
text: str,
|
|
|
|
| 397 |
**kwargs
|
| 398 |
) -> List[Dict[str, Any]]:
|
| 399 |
"""
|
|
@@ -408,7 +409,7 @@ class LLMClient:
|
|
| 408 |
"""
|
| 409 |
|
| 410 |
prompt = f"""
|
| 411 |
-
Nhiệm
|
| 412 |
Định dạng JSON bắt buộc:
|
| 413 |
|
| 414 |
{{
|
|
@@ -420,10 +421,10 @@ class LLMClient:
|
|
| 420 |
|
| 421 |
Hướng dẫn chi tiết cho từng trường:
|
| 422 |
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
|
| 428 |
VÍ DỤ MẪU:
|
| 429 |
|
|
@@ -436,8 +437,9 @@ class LLMClient:
|
|
| 436 |
"cau_hoi": "Mức xử phạt cho hành vi ô tô không chấp hành hiệu lệnh của đèn tín hiệu giao thông là bao nhiêu?"
|
| 437 |
}}
|
| 438 |
|
| 439 |
-
|
| 440 |
-
|
|
|
|
| 441 |
|
| 442 |
Câu hỏi:
|
| 443 |
\"{text}\"
|
|
|
|
| 393 |
@timing_decorator_async
|
| 394 |
async def analyze(
|
| 395 |
self,
|
| 396 |
+
text: str,
|
| 397 |
+
conversation_context: str,
|
| 398 |
**kwargs
|
| 399 |
) -> List[Dict[str, Any]]:
|
| 400 |
"""
|
|
|
|
| 409 |
"""
|
| 410 |
|
| 411 |
prompt = f"""
|
| 412 |
+
Bạn là một chuyên gia phân tích ngôn ngữ tự nhiên (NLP) chuyên xử lý các câu hỏi về luật giao thông Việt Nam. Nhiệm vụ của bạn là đọc kỹ **lịch sử trò chuyện** và **câu hỏi mới nhất** của người dùng để trích xuất thông tin vào một cấu trúc JSON duy nhất. Chỉ trả về đối tượng JSON, không thêm bất kỳ giải thích nào.
|
| 413 |
Định dạng JSON bắt buộc:
|
| 414 |
|
| 415 |
{{
|
|
|
|
| 421 |
|
| 422 |
Hướng dẫn chi tiết cho từng trường:
|
| 423 |
|
| 424 |
+
**muc_dich**: Phải là một trong các giá trị sau: "hỏi về mức phạt", "hỏi về quy tắc giao thông", "hỏi về báo hiệu đường bộ", "hỏi về quy trình xử lý vi phạm giao thông", "thông tin cá nhân của AI", "khác". **Phải dựa vào câu hỏi mới nhất để xác định.**
|
| 425 |
+
**phuong_tien**: Tên phương tiện được đề cập trong câu hỏi mới hoặc trong lịch sử gần nhất. Nếu không có, để chuỗi rỗng "".
|
| 426 |
+
**hanh_vi**: Tên gọi pháp lý của hành vi. **Sử dụng lịch sử trò chuyện để xác định hành vi nếu câu hỏi mới không đề cập đến.** Nếu không có hành vi cụ thể, để chuỗi rỗng "".
|
| 427 |
+
**cau_hoi**: Diễn đạt lại câu hỏi mới nhất của người dùng thành một câu hỏi hoàn chỉnh, kết hợp ngữ cảnh từ lịch sử nếu cần, sử dụng đúng thuật ngữ pháp lý.
|
| 428 |
|
| 429 |
VÍ DỤ MẪU:
|
| 430 |
|
|
|
|
| 437 |
"cau_hoi": "Mức xử phạt cho hành vi ô tô không chấp hành hiệu lệnh của đèn tín hiệu giao thông là bao nhiêu?"
|
| 438 |
}}
|
| 439 |
|
| 440 |
+
Bây giờ, hãy phân tích lịch sử và câu hỏi sau và chỉ trả về đối tượng JSON.
|
| 441 |
+
Lịch sử trò chuyện:
|
| 442 |
+
\"{conversation_context}\"
|
| 443 |
|
| 444 |
Câu hỏi:
|
| 445 |
\"{text}\"
|
app/message_processor.py
CHANGED
|
@@ -112,7 +112,7 @@ class MessageProcessor:
|
|
| 112 |
from app.constants import VEHICLE_KEYWORDS
|
| 113 |
command, remaining_text = extract_command(message_text)
|
| 114 |
|
| 115 |
-
llm_analysis = await self.channel.llm.analyze(message_text)
|
| 116 |
logger.info(f"[LLM][RAW] Kết quả trả về từ analyze: {llm_analysis}")
|
| 117 |
|
| 118 |
muc_dich = None
|
|
@@ -148,41 +148,7 @@ class MessageProcessor:
|
|
| 148 |
muc_dich_to_use = muc_dich or conv.get('originalpurpose')
|
| 149 |
logger.info(f"[DEBUG] Định hướng mục đích xử lý: {muc_dich_to_use}")
|
| 150 |
|
| 151 |
-
|
| 152 |
-
conversation_context = []
|
| 153 |
-
total_chars = 0
|
| 154 |
-
|
| 155 |
-
def get_latest_timestamp(ts_value):
|
| 156 |
-
if isinstance(ts_value, (int, float)): return int(ts_value)
|
| 157 |
-
if isinstance(ts_value, str):
|
| 158 |
-
try: return int(json.loads(ts_value))
|
| 159 |
-
except:
|
| 160 |
-
try: return int(ts_value)
|
| 161 |
-
except: return 0
|
| 162 |
-
if isinstance(ts_value, list):
|
| 163 |
-
if not ts_value: return 0
|
| 164 |
-
return max([get_latest_timestamp(item) for item in ts_value]) if ts_value else 0
|
| 165 |
-
return 0
|
| 166 |
-
|
| 167 |
-
sorted_history = sorted(history, key=lambda row: get_latest_timestamp(row.get('timestamp', 0)))
|
| 168 |
-
|
| 169 |
-
for row in reversed(sorted_history):
|
| 170 |
-
temp_blocks = []
|
| 171 |
-
|
| 172 |
-
# --- SỬA LỖI THỨ TỰ LỊCH SỬ TẠI ĐÂY ---
|
| 173 |
-
# Đảm bảo lượt nói của user luôn được thêm vào trước.
|
| 174 |
-
if row.get('originaltext'):
|
| 175 |
-
temp_blocks.append({"role": "user", "content": row['originaltext']})
|
| 176 |
-
# Lượt nói của trợ lý ảo được thêm vào sau.
|
| 177 |
-
if row.get('systemresponse'):
|
| 178 |
-
temp_blocks.append({"role": "assistant", "content": row['systemresponse']})
|
| 179 |
-
|
| 180 |
-
temp_total = sum(len(block['content']) for block in temp_blocks)
|
| 181 |
-
if total_chars + temp_total > MAX_CONTEXT_CHARS: continue
|
| 182 |
-
|
| 183 |
-
# Thêm cặp hỏi-đáp vào đầu danh sách context, duy trì thứ tự thời gian
|
| 184 |
-
conversation_context = temp_blocks + conversation_context
|
| 185 |
-
total_chars += temp_total
|
| 186 |
|
| 187 |
response = None
|
| 188 |
if not command:
|
|
@@ -217,6 +183,43 @@ class MessageProcessor:
|
|
| 217 |
logger.info(f"Chuẩn bị ghi/cập nhật dữ liệu cuối cùng vào sheet: {conv}")
|
| 218 |
await loop.run_in_executor(None, lambda: sheets_client.log_conversation(**conv))
|
| 219 |
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
|
| 221 |
def flatten_timestamp(self, ts):
|
| 222 |
flat = []
|
|
|
|
| 112 |
from app.constants import VEHICLE_KEYWORDS
|
| 113 |
command, remaining_text = extract_command(message_text)
|
| 114 |
|
| 115 |
+
llm_analysis = await self.channel.llm.analyze(message_text, self.get_llm_history(history))
|
| 116 |
logger.info(f"[LLM][RAW] Kết quả trả về từ analyze: {llm_analysis}")
|
| 117 |
|
| 118 |
muc_dich = None
|
|
|
|
| 148 |
muc_dich_to_use = muc_dich or conv.get('originalpurpose')
|
| 149 |
logger.info(f"[DEBUG] Định hướng mục đích xử lý: {muc_dich_to_use}")
|
| 150 |
|
| 151 |
+
conversation_context = self.get_llm_history(history)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
|
| 153 |
response = None
|
| 154 |
if not command:
|
|
|
|
| 183 |
logger.info(f"Chuẩn bị ghi/cập nhật dữ liệu cuối cùng vào sheet: {conv}")
|
| 184 |
await loop.run_in_executor(None, lambda: sheets_client.log_conversation(**conv))
|
| 185 |
return
|
| 186 |
+
|
| 187 |
+
def get_latest_timestamp(self,ts_value):
|
| 188 |
+
if isinstance(ts_value, (int, float)): return int(ts_value)
|
| 189 |
+
if isinstance(ts_value, str):
|
| 190 |
+
try: return int(json.loads(ts_value))
|
| 191 |
+
except:
|
| 192 |
+
try: return int(ts_value)
|
| 193 |
+
except: return 0
|
| 194 |
+
if isinstance(ts_value, list):
|
| 195 |
+
if not ts_value: return 0
|
| 196 |
+
return max([self.get_latest_timestamp(item) for item in ts_value]) if ts_value else 0
|
| 197 |
+
return 0
|
| 198 |
+
|
| 199 |
+
def get_llm_history(self, history: List):
|
| 200 |
+
sorted_history = sorted(history, key=lambda row: self.get_latest_timestamp(row.get('timestamp', 0)))
|
| 201 |
+
|
| 202 |
+
total_chars = 0
|
| 203 |
+
MAX_CONTEXT_CHARS = 20_000
|
| 204 |
+
conversation_context = []
|
| 205 |
+
for row in reversed(sorted_history):
|
| 206 |
+
temp_blocks = []
|
| 207 |
+
|
| 208 |
+
# --- SỬA LỖI THỨ TỰ LỊCH SỬ TẠI ĐÂY ---
|
| 209 |
+
# Đảm bảo lượt nói của user luôn được thêm vào trước.
|
| 210 |
+
if row.get('originaltext'):
|
| 211 |
+
temp_blocks.append({"role": "user", "content": row['originaltext']})
|
| 212 |
+
# Lượt nói của trợ lý ảo được thêm vào sau.
|
| 213 |
+
if row.get('systemresponse'):
|
| 214 |
+
temp_blocks.append({"role": "assistant", "content": row['systemresponse']})
|
| 215 |
+
|
| 216 |
+
temp_total = sum(len(block['content']) for block in temp_blocks)
|
| 217 |
+
if total_chars + temp_total > MAX_CONTEXT_CHARS: continue
|
| 218 |
+
|
| 219 |
+
# Thêm cặp hỏi-đáp vào đầu danh sách context, duy trì thứ tự thời gian
|
| 220 |
+
conversation_context = temp_blocks + conversation_context
|
| 221 |
+
total_chars += temp_total
|
| 222 |
+
return conversation_context
|
| 223 |
|
| 224 |
def flatten_timestamp(self, ts):
|
| 225 |
flat = []
|