File size: 7,034 Bytes
30adccc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f30514b
30adccc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f30514b
 
 
 
 
 
30adccc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import json
from pathlib import Path
import os
from langchain_google_genai import ChatGoogleGenerativeAI

# --- Data Loading ---
try:
    print("Loading personas for RecommendationHandler module...")
    # ABSOLUTE_PATH_TO_CONFIG = '/Users/jts-ai-sumana/rabbitlife_gemini/config/personas.json'
        # with open(ABSOLUTE_PATH_TO_CONFIG, "r", encoding="utf-8") as f:
    PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
    CONFIG_PATH = PROJECT_ROOT / "config" / "personas.json"
    with open(CONFIG_PATH, "r", encoding="utf-8") as f:
        PERSONAS = json.load(f)
    print(f"✅ Personas config loaded successfully from: {CONFIG_PATH}")
except Exception as e:
    PERSONAS = {}
    print(f"‼️ ERROR: Could not load personas.json: {e}")

# --- LLM Initialization ---
try:
    INTEREST_LLM = ChatGoogleGenerativeAI(
        model="gemini-2.5-flash", 
        google_api_key=os.getenv("GOOGLE_API_KEY"),
        temperature=0, 
    )
    print("✅ LLM for interest classification initialized.")
except Exception as e:
    INTEREST_LLM = None
    print(f"‼️ ERROR initializing LLM for RecommendationHandler: {e}")


#  RECOMMENDATION ###
def generate_recommendation_from_profile(
    age: int,
    gender: str, # M, F
    salary: int,
    original_interest: str
) -> dict:
    if not PERSONAS or not INTEREST_LLM:
        return {"error": "Module not initialized correctly."}

    # print(f"\n--- Generating Recommendation Profile ---")
    # print(f"Input Data: Age={age}, Gender='{gender}', Salary={salary}, Interest='{original_interest}'")

    # 1. หา Persona ที่ตรงกับอายุ
    matched_persona = next((details for _, details in PERSONAS.items() if details.get("age_min", -1) <= age <= details.get("age_max", -1)), None)
    if not matched_persona:
        return {"error": f"No matching persona found for age {age}."}
    # print(f"-> Matched Persona: '{matched_persona.get('persona_name', 'N/A')}'")
    
    # 2. หา Tier ที่ตรงกับเงินเดือน
    products_from_tier = []
    salary_tiers = matched_persona.get('recommendations_by_salary', [])
    for tier in salary_tiers:
        if tier.get("salary_min", 0) <= salary <= tier.get("salary_max", float('inf')):
            products_from_tier = tier.get("products", [])
            # print(f"-> Matched Salary Tier: '{tier.get('tier_name')}'")
            break
    if not products_from_tier and salary_tiers:
        products_from_tier = salary_tiers[0].get("products", [])

    # 3. รวบรวม product จาก Tier และเพศ
    all_tier_products = [p for p in products_from_tier if p.get('gender') == 'all' or p.get('gender') == gender]
    
    # 4. กรองตาม Interest - LLM
    interest_prompt = f"""Analyze the user's interest and classify it into ONE of these categories:
    'ประกันคุ้มครองชีวิต', 'ประกันเพื่อการลงทุน', 'ประกันสุขภาพ', 'ประกันอุบัติเหตุ', 'ทั่วไป'.
    User Interest: "{original_interest}"
    Category:"""
    
    response = INTEREST_LLM.invoke(interest_prompt)    
    target_insurance_type = response.content.strip()
    # print(f"-> LLM classified interest as: '{target_insurance_type}'")

    products_to_recommend = all_tier_products
    searched_outside_tier = False

    valid_types = ['ประกันเพื่อการลงทุน', 'ประกันสุขภาพ', 'ประกันอุบัติเหตุ', 'ประกันคุ้มครองชีวิต']
    
    if target_insurance_type in valid_types:
        # print(f"-> Filtering for interest: '{target_insurance_type}' across all tiers...")
        
        all_persona_products = []
        for tier_fallback in matched_persona.get('recommendations_by_salary', []):
            all_persona_products.extend(tier_fallback.get('products', []))
        # print(all_persona_products)
        
        gender_filtered_products = [p for p in all_persona_products if p.get('gender') == 'all' or p.get('gender') == gender]
        final_filtered_products = [p for p in gender_filtered_products if p.get('insurance_type') == target_insurance_type]

        if final_filtered_products:
            # print(f"-> Found {len(final_filtered_products)} matching products.")
            products_to_recommend = final_filtered_products
        else:
            print(f"-> CRITICAL: No product of type '{target_insurance_type}' found anywhere in this persona.")
            return {"error": f"ขออภัยค่ะ เราไม่พบผลิตภัณฑ์ประเภท '{target_insurance_type}' ที่เหมาะสมกับโปรไฟล์ของคุณในขณะนี้ค่ะ"}


    # 5. ตรวจสอบและเพิ่มสัญญาหลักถ้าจำเป็น
    has_basic_plan = any(p.get('plan_type') == 'Basic' for p in products_to_recommend)
    auto_added_main_plan = False 
    if not has_basic_plan and any(p.get('plan_type') == 'Rider' for p in products_to_recommend):
        # print("-> Filtered list only has Riders. Adding a default main plan.")
        default_main_plans = [p for p in all_tier_products if p.get('plan_type') == 'Basic']
        if default_main_plans:
            products_to_recommend.insert(0, default_main_plans[0])
            auto_added_main_plan = True


    # 6. จัดกลุ่มและเตรียมข้อมูลสำหรับส่งคืน
    main_plans_pre = [p for p in products_to_recommend if p.get('plan_type') == 'Basic']
    main_plans = [dict(t) for t in {tuple(d.items()) for d in main_plans_pre}]
    riders_pre = [p for p in products_to_recommend if p.get('plan_type') == 'Rider']
    riders = [dict(t) for t in {tuple(d.items()) for d in riders_pre}]

    print(main_plans)

    main_plans_str = "ไม่มีแผนประกันหลักที่แนะนำ"
    if main_plans:
        main_plans_str = "\n".join([f"• **{p.get('product_name')}**: {p.get('product_description')}" for p in main_plans])
    riders_str = "ไม่มีสัญญาเพิ่มเติมที่แนะนำ"
    if riders:
        riders_str = "\n".join([f"• **{p.get('product_name')}**: {p.get('product_description')}" for p in riders])

    return {
        "age": age, "gender": gender, "salary": f"{salary:,}",
        "persona_name": matched_persona['persona_name'],
        "persona_description": matched_persona['description'],
        "original_interest": original_interest,
        "main_plans_str": main_plans_str.strip(),
        "riders_str": riders_str.strip(),
        "auto_added_main_plan": auto_added_main_plan,
        "searched_outside_tier": searched_outside_tier,
        "interest_category": target_insurance_type if target_insurance_type != 'ทั่วไป' else 'ประกัน'
    }