PINE-AI-Amdocs / backend /precomputation /logic /precompute_context.py
maitrang04's picture
Upload 48 files
0649d3e verified
import pandas as pd
import json
import re
from pydantic import BaseModel
from typing import Optional, List
from backend.config.setting import (
PRE_TEST_CUSTOMER_CSV,
PRE_PRODUCT_JSON,
PRE_LAW_JSON
)
def load_data():
data = {}
try:
data['customers'] = pd.read_csv(PRE_TEST_CUSTOMER_CSV)
data['customers'].columns = data['customers'].columns.str.strip()
except Exception as e:
print(e)
data['customers'] = pd.DataFrame()
try:
with open(PRE_PRODUCT_JSON, encoding="utf-8") as f:
data['products'] = json.load(f)
except:
data['products'] = []
try:
with open(PRE_LAW_JSON, encoding="utf-8") as f:
data['laws'] = json.load(f)
except:
data['laws'] = []
return data
# ==============================================================================
# 2. HÀM HỖ TRỢ LOGIC
# ==============================================================================
def extract_price(text):
"""Trích xuất giá tiền từ chuỗi mô tả (VD: '100.000đ' -> 100000)"""
text = str(text).replace('.', '').replace(',', '')
match = re.search(r'(\d{4,6})', text)
return int(match.group(1)) if match else 0
def check_segment_rules(customer, product, p_price, current_spend):
"""
Logic tính điểm phù hợp cho gói cước.
CHIẾN THUẬT: UPSELL TOÀN DIỆN (Luôn ưu tiên gói giá trị cao hơn/bằng)
"""
segment = customer.get('Segment', 'C')
# churn_score = customer.get('Churn Score', 0) # Tạm thời bỏ qua Churn Score để tập trung Upsell
desc_lower = product.get('desc', '').lower()
score = 0
# ---------------------------------------------------------
# CHIẾN THUẬT CHUNG CHO MỌI KHÁCH HÀNG: UPSELL LÀ ƯU TIÊN SỐ 1
# ---------------------------------------------------------
# 1. Ưu tiên gói có giá CAO HƠN hoặc BẰNG gói hiện tại (Tăng doanh thu)
if p_price >= current_spend:
score += 50 # Điểm cộng rất lớn cho việc Upsell
# Nếu giá cao hơn nhưng không quá đắt (trong tầm chấp nhận +20% đến +50%)
if p_price <= current_spend * 1.5:
score += 20
else:
# Nếu gói rẻ hơn -> Downsell (Trừ điểm, trừ khi gói đó quá ngon)
score -= 10
# 2. Phân loại theo Segment để cộng thêm điểm phụ
if segment == 'A': # Khách VIP -> Thích Dịch vụ VIP, Data khủng
if "vip" in desc_lower or "300gb" in desc_lower: score += 40
if p_price > 150000: score += 30 # Khách giàu thích gói đắt
elif segment == 'B': # Khách trẻ/Văn phòng -> Thích Mạng Xã Hội
if any(x in desc_lower for x in ['tiktok', 'youtube', 'facebook', 'social']): score += 40
# Gói tầm trung (90k - 150k) là sweet spot
if 90000 <= p_price <= 150000: score += 20
elif segment == 'C': # Khách rủi ro -> Thích Khuyến mãi/Miễn phí (Nhưng vẫn cố Upsell)
if "miễn phí" in desc_lower or "tặng" in desc_lower: score += 40
# Với khách C, nếu Upsell thì phải Upsell nhẹ (chênh lệch ít)
if p_price >= current_spend and abs(p_price - current_spend) <= 20000:
score += 30 # Upsell khéo léo
# 3. Điểm cộng tính năng (Data theo ngày là xu hướng hot)
if "gb/ngày" in desc_lower: score += 15
return max(0, score)
def build_smartbot_context(customer_id):
"""Xây dựng Context và danh sách gói cước gợi ý"""
df = data['customers']
# Tìm cột ID gói cước (thường là 'id' hoặc 'package_id')
package_id_col = 'id' if 'id' in df.columns else None
# Lấy thông tin khách hàng
customer = df[df['Customer ID'] == customer_id]
if customer.empty: return None, []
cust_info = customer.iloc[0].to_dict()
# --- 1. LẤY THÔNG TIN GÓI ĐANG DÙNG ---
current_pkg_id = cust_info.get(package_id_col)
current_pkg_details = None
if current_pkg_id:
for p in data['products']:
if p['id'] == current_pkg_id:
current_pkg_details = p
break
# Xác định giá gói hiện tại để làm mốc so sánh Upsell
if current_pkg_details:
current_price = extract_price(current_pkg_details['desc'])
current_pkg_desc_str = f"{current_pkg_details['name']} ({current_price:,}đ)"
current_spend = current_price
else:
# Fallback nếu dữ liệu lỗi
current_spend = cust_info.get('Monthly Charge', 0)
# Nếu Monthly Charge trong CSV là số nhỏ (VD: 50 -> 50$), ta nhân tạm để ra VND (Demo)
if current_spend < 1000: current_spend = current_spend * 2000
current_pkg_desc_str = f"Gói cước hiện tại ({int(current_spend):,}đ/tháng)"
segment = cust_info.get('Segment', 'Unknown')
churn_score = cust_info.get('Churn Score', 0)
# --- 2. TÌM GÓI GỢI Ý (CHIẾN THUẬT UPSELL) ---
recommendations = []
for p in data['products']:
p_price = extract_price(p['desc'])
if p_price == 0: continue
# Loại bỏ gói trùng ID (Không mời lại gói đang dùng)
if current_pkg_id and p['id'] == current_pkg_id:
continue
# Loại bỏ nếu giá trùng (nếu không có ID) -> Để tránh mời gói y hệt
if not current_pkg_id and abs(p_price - current_spend) <= 1000:
continue
score = check_segment_rules(cust_info, p, p_price, current_spend)
# Gắn nhãn trạng thái để AI dễ chém gió
status_tag = ""
if p_price > current_spend: status_tag = "NÂNG CẤP (UPSELL)"
elif p_price == current_spend: status_tag = "NGANG GIÁ (BETTER VALUE)"
else: status_tag = "TIẾT KIỆM (DOWNSELL)"
recommendations.append({
"name": p['name'],
"price": p_price,
"score": score,
"status": status_tag,
"desc": p['desc']
})
# Sắp xếp theo điểm số (Score cao nhất lên đầu)
recommendations.sort(key=lambda x: x['score'], reverse=True)
top_prods = recommendations[:5]
# --- 3. TẠO CONTEXT VĂN BẢN (CHO GEMINI/VOICEBOT) ---
products_str = ""
for i, p in enumerate(top_prods):
recommend_label = " [ƯU TIÊN SỐ 1]" if i == 0 else ""
products_str += f"- {p['name']} ({p['price']:,}đ): {p['desc']}\n -> {recommend_label} (Điểm: {p['score']} - {p['status']})\n"
# Lấy thông tin pháp lý (nếu có)
laws_str = ""
for i, law in enumerate(data['laws']):
if i >= 2: break
laws_str += f"- {law.get('topic', '')}: {law.get('content_summary', '')}\n"
final_context = f"""
==================================================
BỐI CẢNH TƯ VẤN: Khách hàng ID {customer_id} (Phân khúc {segment})
==================================================
--- HỒ SƠ KHÁCH HÀNG ---
- Đang dùng: {current_pkg_desc_str}
- Mức chi tiêu hiện tại: {int(current_spend):,} VND/tháng
- Phân khúc: {segment}
- Rủi ro rời mạng (Churn): {churn_score}/100
--- MỤC TIÊU CHIẾN DỊCH ---
- Ưu tiên hàng đầu: UPSELL (Bán gói cước giá trị cao hơn hoặc bằng).
- Chỉ Downsell (bán gói rẻ hơn) nếu khách cực kỳ gay gắt về giá.
- Nhấn mạnh vào: Data khủng, Ứng dụng miễn phí (Tiktok, Youtube) để khỏa lấp vấn đề giá.
--- DANH SÁCH GÓI CƯỚC ĐỀ XUẤT (Đã sắp xếp theo độ ưu tiên) ---
{products_str}
--- THÔNG TIN BỔ TRỢ ---
{laws_str}
--- YÊU CẦU ĐỐI VỚI AI/VOICEBOT ---
Hãy đóng vai tư vấn viên VNPT chuyên nghiệp.
1. So sánh trực tiếp gói đang dùng và gói gợi ý: "Anh/Chị đang dùng [Tên gói cũ] ({int(current_spend):,}đ), gói [Tên gói mới] ({top_prods[0]['price']:,}đ) có ưu điểm..."
2. Nêu bật sự khác biệt cụ thể (VD: Gói cũ chỉ có X GB, gói mới có Y GB).
3. Thuyết phục khách hàng chuyển đổi dựa trên lợi ích thực tế.
4. Đừng vội vàng, hấp tấp, hãy tạo cảm giác thoải mái cho khách hàng.
5. Đừng dồn ép khách hàng, hãy để họ cảm thấy đây là lựa chọn của họ.
6. Kết thúc bằng câu hỏi mở để khách hàng dễ dàng đồng ý chuyển đổi. VDu: "Anh/chị thấy gói này thế nào ạ?"
7. Hạn chế nhắc đến rủi ro rời mạng/churn score trực tiếp.
8. Hãy trả lời theo 1 đoạn văn bản hoàn chỉnh.
9. Sử dụng tiếng Việt có dấu, ngữ pháp chuẩn.
10. Đừng tách đoạn văn bản thành nhiều phần nhỏ. Hãy đảm bảo chúng sẵn sàng để có thể đọc liền mạch bởi text to speech.
"""
return final_context, top_prods
# ==============================================================================