import pandas as pd import json import re from pathlib import Path # --- Data Loading --- try: print("Loading data for CustomerDataHandler module...") PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent # หา Path ของ Root Directory DATA_PATH = PROJECT_ROOT / "data" CONFIG_PATH = PROJECT_ROOT / "config" # customer df CUSTOMER_DF = pd.read_csv(DATA_PATH / "mock_customer_data.csv") COLUMN_MAP_DF = pd.read_csv(DATA_PATH / "column_mapping.csv") COLUMN_MAP_DICT = pd.Series(COLUMN_MAP_DF.Description.values, index=COLUMN_MAP_DF.Field_name).to_dict() # dict mapping # persona json # 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: with open(CONFIG_PATH / "personas.json", "r", encoding="utf-8") as f: PERSONAS = json.load(f) print("✅ Customer data, mapping, and personas loaded successfully.") except Exception as e: print(f"‼️ ERROR: Could not load data/config files for CustomerDataHandler: {e}") CUSTOMER_DF = pd.DataFrame() COLUMN_MAP_DICT = {} PERSONAS = {} # map ชื่อ: ประเภท PLAN_NAME_TO_TYPE_MAP = { "Smart Term Bronze 5": "ประกันคุ้มครองชีวิต", "Smart Term Bronze 10": "ประกันคุ้มครองชีวิต", "Chai Leoy 99/20": "ประกันคุ้มครองชีวิต", "Chai Leoy 99/10": "ประกันคุ้มครองชีวิต", "Chai Leoy 99/5": "ประกันคุ้มครองชีวิต", "High Protect 3/3": "ประกันคุ้มครองชีวิต", "Smart Wellness 90/15": "ประกันคุ้มครองชีวิต", "Save 5 C": "ประกันคุ้มครองชีวิต", "Sabai Jai 14/5": "ประกันเพื่อการลงทุน", "Jai Jai 25/9": "ประกันเพื่อการลงทุน", "Protection Plus 18/9": "ประกันเพื่อการลงทุน", "Jai Jai 12/6": "ประกันเพื่อการลงทุน", "Jai Jai 15/6": "ประกันเพื่อการลงทุน", "Health Protect (สัญญาเพิ่มเติมสุขภาพค่ารักษาพยาบาล)": "ประกันสุขภาพ", "Health Smile": "ประกันสุขภาพ", "Worry Free Cancer (สัญญาเพิ่มเติมคุ้มครองโรคมะเร็ง)": "ประกันสุขภาพ", "Worry Free 50 Critical Illness": "ประกันสุขภาพ", "Rider HIB 365 (สัญญาเพิ่มเติมสุขภาพค่าชดเชยรายวัน)": "ประกันสุขภาพ", "PA Max (สัญญาเพิ่มเติมสุขภาพค่ารักษาผู้ป่วยนอก)": "ประกันสุขภาพ", "PA Prompt (สัญญาเพิ่มเติมสุขภาพค่ารักษาผู้ป่วยนอก)": "ประกันสุขภาพ", "สัญญาเพิ่มเติมยกเว้นเบี้ยประกันภัย": "ประกันสุขภาพ", "OPD": "ประกันสุขภาพ", "Mental Health": "ประกันสุขภาพ", "PA Max (อุบัติเหตุส่วนบุคคล)": "ประกันอุบัติเหตุ", "PA Prompt (อุบัติเหตุส่วนบุคคล)": "ประกันอุบัติเหตุ", "Rider ADD (สัญญาเพิ่มเติมอุบัติเหตุ)": "ประกันอุบัติเหตุ", "Rider AI (สัญญาเพิ่มเติมอุบัติเหตุ)": "ประกันอุบัติเหตุ", "Rider ADB (สัญญาเพิ่มเติมอุบัติเหตุ)": "ประกันอุบัติเหตุ", "PA Max (สัญญาเพิ่มเติมสุขภาพค่ารักษาเนื่องจากอุบัติเหตุ)": "ประกันอุบัติเหตุ", "PA Prompt (สัญญาเพิ่มเติมสุขภาพค่ารักษาเนื่องจากอุบัติเหตุ)": "ประกันอุบัติเหตุ", "Rider ADB and ADD(สัญญาเพิ่มเติมอุบัติเหตุ)": "ประกันอุบัติเหตุ" } # --- Utilize Fuctions --- def clean_name(name): if not isinstance(name, str): return "" return re.sub(r'\s*\(.*\)\s*', '', name).strip() def find_customer_data(identifier: str) -> pd.DataFrame | None: """ return df """ if CUSTOMER_DF.empty: return None identifier = str(identifier).strip() # ลองค้นหาด้วยเลขบัตรประชาชนก่อน numeric_identifier = re.sub(r'\D', '', identifier) if len(numeric_identifier) == 13: result_df = CUSTOMER_DF[CUSTOMER_DF['insured_id_number'] == int(numeric_identifier)] if not result_df.empty: return result_df # ถ้าไม่เจอ ลองค้นหาด้วยชื่อ-นามสกุล name_parts = identifier.split() if len(name_parts) >= 2: firstname, lastname = name_parts[0], " ".join(name_parts[1:]) result_df = CUSTOMER_DF[(CUSTOMER_DF['insured_firstname'] == firstname) & (CUSTOMER_DF['insured_lastname'] == lastname)] if not result_df.empty: return result_df return None def translate_and_format_data(customer_df: pd.DataFrame) -> str: """ เลือกคอลัมน์ที่ต้องการ --> แปลชื่อคอลัมน์เป็นภาษาไทย --> และแปลงเป็น JSON string """ columns_to_show = [ 'policy_no', 'policy_plan_name', 'plan_type', 'total_premium', 'policy_status', 'policy_effective_date', 'premium_duedate', 'policy_maturity_date', 'sum_insured_first' ] existing_columns = [col for col in columns_to_show if col in customer_df.columns] df_to_format = customer_df[existing_columns].copy() df_to_format.rename(columns=COLUMN_MAP_DICT, inplace=True) return df_to_format.to_json(orient='records', force_ascii=False, indent=2) def find_recommendation_gaps(customer_df: pd.DataFrame) -> list: """ วิเคราะห์ข้อมูลกรมธรรม์ของลูกค้าเพื่อหาผลิตภัณฑ์ที่น่าแนะนำเพิ่มเติม (Gap Analysis) โดยพิจารณาจาก Age และ Salary """ # print("[Gap Analysis] Starting analysis for existing customer...") if customer_df.empty or not PERSONAS: return [] try: customer_info = customer_df.iloc[0] age = customer_info.get('insured_age_latest') gender = str(customer_info.get('insured_gender', '')).upper() salary = customer_info.get('insured_salary', 0) if age is None or not gender: # print("[Gap Analysis] Missing age or gender. Cannot perform analysis.") return [] # print(f"[Gap Analysis] Analyzing profile: Age={age}, Gender='{gender}', Salary={salary}") # หา 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 [] # หา 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", []) break if not products_from_tier and salary_tiers: products_from_tier = salary_tiers[0].get("products", []) # ดึงลิสต์ผลิตภัณฑ์ที่ ideal จาก Tier และ เพศ ideal_products = [p for p in products_from_tier if p.get('gender') == 'all' or p.get('gender') == gender] # ดึงลิสต์ผลิตภัณฑ์ที่ "มีอยู่แล้ว" และทำความสะอาดชื่อ existing_products_raw = set(customer_df['policy_plan_name'].unique()) existing_products_names = {clean_name(name) for name in existing_products_raw} # หา Gaps gaps = [] for ideal_product in ideal_products: ideal_product_name_clean = clean_name(ideal_product.get('product_name', '')) if ideal_product_name_clean not in existing_products_names: gaps.append(ideal_product) gaps.sort(key=lambda x: ('Rider' not in x.get('product_category', '')), reverse=False) # print(f"[Gap Analysis] Found {len(gaps)} potential products to recommend.") return gaps except Exception as e: print(f"‼️ ERROR during Gap Analysis: {e}") import traceback traceback.print_exc() return [] def generate_upsell_text_from_gaps(gaps: list) -> str: """สร้างประโยค Upsell สั้นๆ จาก Gap ที่หาเจอ""" if gaps: main_recommendation = gaps[0] return (f"\n\nจากข้อมูลความคุ้มครองปัจจุบัน สังเกตว่าแผนประกันของท่านจะครอบคลุมยิ่งขึ้น " f"หากมีสัญญาเพิ่มเติม **{main_recommendation['product_name']}** " f"ซึ่งจะช่วยดูแลในเรื่อง{main_recommendation.get('product_description', 'ความคุ้มครองเพิ่มเติม')}ค่ะ" f"\n\nสนใจรับข้อมูลเพิ่มเติมเกี่ยวกับแผนนี้ไหมคะ") return ""