Spaces:
Sleeping
Sleeping
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 'ประกัน'
} |