VietCat commited on
Commit
f6866df
·
1 Parent(s): 56edd5b

add history to analyze

Browse files
Files changed (3) hide show
  1. app/constants.py +1 -1
  2. app/llm.py +10 -8
  3. 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 = 123456789
 
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 vụ: Với mỗi câu hỏi, trích xuất thông tin ra một đối tượng JSON duy nhất. Kết quả phải ngắn gọn, chính xác chỉ sử dụng thuật ngữ trong các văn bản pháp luật.
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
- 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".
424
- phuong_tien: Tên phương tiện nếu có, ngược lại để chuỗi rỗng "".
425
- hanh_vi: Nêu tên gọi pháp lý của hành vi của câu hỏi một cách súc tích trực tiếp nhất. Tuyệt đối không diễn giải dài dòng hoặc dùng thuật ngữ đời thường
426
- cau_hoi: Diễn đạt lại thành một câu hỏi ngắn gọn trực tiếp về mục đích đã xác định, sử dụng đúng thuật ngữ pháp lý.
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
- BÂY GIỜ, ÁP DỤNG VỚI CÂU HỎI SAU:
 
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 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
- MAX_CONTEXT_CHARS = 20_000
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 = []