File size: 9,246 Bytes
0649d3e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
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

# ==============================================================================