dammmmmmmmm commited on
Commit
f15b6d4
·
verified ·
1 Parent(s): b0dd369

Upload strategy_competitor.py

Browse files
backend/ai/strategy/strategy_competitor.py CHANGED
@@ -1,80 +1,92 @@
1
- import time
2
-
3
- class CompetitorStrategy:
4
- def __init__(self, llm_client, data_engine):
5
- self.llm_client = llm_client
6
- self.data_engine = data_engine
7
-
8
- # --- KỊCH BẢN CHUẨN (SOURCE OF TRUTH) ---
9
- # Đây là nội dung an toàn tuyệt đối mà bạn đã duyệt.
10
- # AI sẽ sử dụng nội dung này làm xương sống, không được tự bịa thêm.
11
- CORE_MESSAGE = (
12
- "Thực sự thì việc mình cân nhắc tìm phương án tiết kiệm hơn là điều rất dễ hiểu và hợp lý thôi ạ.\n\n"
13
- "Tuy nhiên, em cũng xin phép chia sẻ thêm một chút là mỗi nhà mạng sẽ có thế mạnh riêng về vùng phủ sóng "
14
- "hay độ ổn định, nên trải nghiệm thực tế đôi khi sẽ khác nhau. "
15
- "Bởi nhiều khi, việc giữ được đường truyền ổn định để mình làm việc, giải trí "
16
- "lại quan trọng hơn là một chút chênh lệch nhỏ về giá cả.\n\n"
17
- "Do đó, trước khi mình đưa ra quyết định cuối cùng, mình cứ để em kiểm tra lại xem hiện tại "
18
- " chương trình ưu đãi nào tốt hơn để 'tối ưu chi phí' cho mình không nhé?\n\n"
19
- "Còn nếu sau khi cân nhắc mình vẫn muốn ngưng sử dụng, thì chắc chắn bên em sẽ hỗ trợ mình "
20
- "theo đúng quy trình, nhanh chóng minh bạch ."
21
- )
22
-
23
- def execute(self, customer_id, complaint_text):
24
- # 1. TRÍCH XUẤT DỮ LIỆU
25
- ctx = self.data_engine.get_full_context(customer_id)
26
- if not ctx: return "Lỗi: Không tìm thấy khách hàng."
27
-
28
- # Log kiểm tra
29
- cust = ctx.get('customer', {})
30
- print(f" ⚡ [Strategy Competitor] ID {customer_id}: Xử lý khiếu nại giá/đối thủ. Input: '{complaint_text}'")
31
-
32
- # 2. XÂY DỰNG PROMPT (GROUNDED GENERATION)
33
- # Kỹ thuật: In-Context Learning với Ràng buộc âm (Negative Constraints)
34
-
35
- prompt = f"""
36
- VAI TRÒ: Bạn là người bạn đồng hành tin cậy của khách hàng (CSKH).
37
-
38
- DỮ LIỆU ĐẦU VÀO:
39
- - Lời khách hàng: "{complaint_text}"
40
- - Nội dung chính (CORE MESSAGE):
41
- '''
42
- {self.CORE_MESSAGE}
43
- '''
44
-
45
- NHIỆM VỤ:
46
- Hãy tạo ra câu trả lời hoàn chỉnh.
47
-
48
- BƯỚC 1: MỞ ĐẦU (Đồng cảm & Thân thiện)
49
- - Viết một câu mở đầu thể hiện sự thấu hiểu.
50
- - BẮT BUỘC dùng từ: "hợp lý" (thay cho chính đáng), "chia sẻ với mình".
51
- - dụ: "Dạ, em hoàn toàn chia sẻ với mình về vấn đề chi phí ạ. Em hiểu việc mình cân nhắc phương án tiết kiệm hơn là điều rất hợp lý."
52
-
53
- BƯỚC 2: THÂN BÀI (Giải pháp)
54
- - Nối tiếp bằng nội dung trong phần "CORE MESSAGE" ở trên.
55
- - Giữ nguyên các từ khóa: "tối ưu chi phí", "cam kết hỗ trợ", "minh bạch".
56
-
57
- QUY TẮC AN TOÀN (ANTI-HALLUCINATION):
58
- - Tuyệt đối KHÔNG sáng tạo thêm gói cước hay cam kết nào ngoài Core Message.
59
- - Xưng hô: Chỉ dùng "Mình" và "Em".
60
-
61
- OUTPUT: Trả về câu trả lời trọn vẹn, giọng điệu nhẹ nhàng, chân thành.
62
- Hãy trả lời theo một đoạn văn bản hoàn chỉnh. Hãy đảm bảo sẵn sàng để có thể đọc liền mạch bởi text to speech. Ngoài ra đoạn văn cần có tiết tấu chậm, dễ nghe.
63
- """
64
-
65
- # 3. GỌI LLM
66
- if self.llm_client:
67
- try:
68
- # Gọi API (Giả lập)
69
- response = self.llm_client.generate_content(prompt)
70
-
71
- # Double-check (Lớp bảo vệ cuối cùng bằng code)
72
- # Nếu AI lỡ miệng dùng "Anh/Chị", ta cưỡng chế replace ngay lập tức
73
- final_text = response.text.replace("Anh", "Mình").replace("Chị", "Mình").replace("Quý khách", "Mình").replace("bạn", "mình")
74
-
75
- return final_text
76
- except Exception as e:
77
- # Fallback an toàn nếu AI sập: Trả về nguyên văn kịch bản gốc
78
- return self.CORE_MESSAGE
79
- else:
80
- return "Lỗi: Chưa kết nối LLM Client."
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ import re
3
+ import asyncio
4
+
5
+ class CompetitorStrategy:
6
+ def __init__(self, llm_client, data_engine):
7
+ self.llm_client = llm_client
8
+ self.data_engine = data_engine
9
+
10
+ self.cleaner_regex = re.compile(
11
+ r"^(.*?>>>|dưới đây là.*?|sau đây là.*?|câu trả lời.*?|đoạn văn.*?|viết lại.*?|output:)",
12
+ re.IGNORECASE | re.MULTILINE | re.DOTALL
13
+ )
14
+
15
+ CORE_MESSAGE = (
16
+ "Thực sự thì việc mình cân nhắc tìm phương án tiết kiệm hơn là điều rất dễ hiểu hợp thôi ạ. "
17
+ "Tuy nhiên, em cũng xin phép chia sẻ thêm một chút mỗi nhà mạng sẽ thế mạnh riêng về vùng phủ sóng "
18
+ "hay độ ổn định, nên trải nghiệm thực tế đôi khi sẽ khác nhau. "
19
+ "Bởi nhiều khi, việc giữ được đường truyền ổn định để mình làm việc, giải trí "
20
+ "lại quan trọng hơn một chút chênh lệch nhỏ về giá cả. "
21
+ "Do đó, trước khi mình đưa ra quyết định cuối cùng, mình cứ để em kiểm tra lại xem hiện tại "
22
+ "có chương trình ưu đãi nào tốt hơn để tối ưu chi phí cho mình không nhé? "
23
+ "Còn nếu sau khi cân nhắc mà mình vẫn muốn ngưng sử dụng, thì chắc chắn bên em sẽ hỗ trợ mình "
24
+ "theo đúng quy trình, nhanh chóng và minh bạch ạ."
25
+ )
26
+
27
+ def execute(self, customer_id, complaint_text):
28
+ ctx = self.data_engine.get_full_context(customer_id)
29
+ if not ctx: return "Lỗi: Không tìm thấy khách hàng."
30
+
31
+ print(f" ⚡ [Strategy Competitor] ID {customer_id}: Input: '{complaint_text}'")
32
+
33
+ prompt = f"""
34
+ Nhiệm vụ: Đóng vai nhân viên CSKH, nói lại nội dung sau với khách (Xưng Em - Mình).
35
+ NỘI DUNG GỐC: "{self.CORE_MESSAGE}"
36
+ YÊU CẦU:
37
+ - Bỏ qua mọi lời chào hỏi, giải thích.
38
+ - Bắt đầu ngay lập tức bằng nội dung hội thoại.
39
+ - KHÔNG xuống dòng.
40
+ BẮT ĐẦU TRẢ LỜI NGAY SAU DẤU MŨI TÊN:
41
+ >>> """
42
+
43
+ if self.llm_client:
44
+ try:
45
+ response = self.llm_client.generate_content(prompt)
46
+ raw_text = response.text.strip()
47
+
48
+ if ">>>" in raw_text:
49
+ final_text = raw_text.split(">>>")[-1].strip()
50
+ else:
51
+ final_text = self.cleaner_regex.sub("", raw_text).strip()
52
+
53
+ if "\n" in final_text:
54
+ final_text = " ".join([l.strip() for l in final_text.split('\n') if l.strip()])
55
+
56
+ replacements = { "Anh/Chị": "Mình", "Quý khách": "Mình", "Anh": "Mình", "Chị": "Mình", "anh": "mình", "chị": "mình" }
57
+ for old, new in replacements.items():
58
+ if old in final_text or old.lower() in final_text.lower():
59
+ final_text = final_text.replace(old, new)
60
+
61
+ if not final_text: return self.CORE_MESSAGE.replace("\n", " ")
62
+ return final_text
63
+ except Exception as e:
64
+ print(f" [ERROR] Competitor Strategy: {e}")
65
+ return self.CORE_MESSAGE.replace("\n", " ")
66
+ else:
67
+ return "Lỗi: Chưa kết nối LLM Client."
68
+
69
+ # --- [NEW] HÀM STREAMING ---
70
+ async def execute_stream_gen(self, customer_id, complaint_text):
71
+ print(f" 🌊 [Stream Competitor] ID {customer_id}")
72
+
73
+ prompt = f"""
74
+ Nhiệm vụ: Đóng vai nhân viên CSKH, nói lại nội dung sau với khách (Xưng Em - Mình).
75
+ NỘI DUNG GỐC: "{self.CORE_MESSAGE}"
76
+ YÊU CẦU:
77
+ - Bắt đầu ngay lập tức bằng nội dung hội thoại.
78
+ - KHÔNG có lời dẫn.
79
+ BẮT ĐẦU TRẢ LỜI NGAY SAU DẤU MŨI TÊN:
80
+ >>> """
81
+
82
+ if self.llm_client and hasattr(self.llm_client, 'ai_service'):
83
+ try:
84
+ async for chunk in self.llm_client.ai_service.chat_gemini_stream(prompt):
85
+ if ">>>" in chunk:
86
+ chunk = chunk.replace(">>>", "")
87
+ yield chunk
88
+ except Exception as e:
89
+ print(f"Stream Error: {e}")
90
+ yield self.CORE_MESSAGE
91
+ else:
92
+ yield self.CORE_MESSAGE