@@ -852,24 +852,59 @@ def extract_insurance_hybrid(text):
852852 if key not in data :
853853 data [key ] = "N/A"
854854
855+ # Helper to convert Lakhs/Crores to actual numbers
856+ def _parse_indian_amount (num_str , suffix_str = "" ):
857+ """Convert amount with optional Lakhs/Crore suffix to actual number."""
858+ try :
859+ base_val = clean_and_convert_to_float (num_str )
860+ if base_val is None :
861+ return None
862+ suffix_lower = suffix_str .lower ().strip () if suffix_str else ""
863+ if suffix_lower in ("lakh" , "lakhs" , "lac" , "lacs" ):
864+ return base_val * 100000
865+ elif suffix_lower in ("crore" , "crores" , "cr" ):
866+ return base_val * 10000000
867+ return base_val
868+ except Exception :
869+ return None
870+
871+ # Patterns that capture amount AND optional Lakhs/Crore suffix
872+ # Priority order: Annual Sum Insured (most specific for health) > Sum Insured/Assured > Cover Amount
855873 sum_patterns = (
856874 [
857- r"(?i)Sum\s*(?:Assured|Insured)[\s:\-]*(?:Rs\.?|₹)?\s*([\d,]+) " ,
858- r"(?i)Life\s*Cover[\s:\-]*(?:Rs\.?|₹)?\s*([\d,]+) " ,
859- r"(?i)Death\s*Benefit[\s:\-]*(?:Rs\.?|₹)?\s*([\d,]+) "
875+ r"(?i)Sum\s*(?:Assured|Insured)[\s:\-]*(?:Rs\.?|₹)?\s*([\d,]+(?:\.\d+)?)\s*(Lakhs?|Lacs?|Crores?|Cr)? " ,
876+ r"(?i)Life\s*Cover[\s:\-]*(?:Rs\.?|₹)?\s*([\d,]+(?:\.\d+)?)\s*(Lakhs?|Lacs?|Crores?|Cr)? " ,
877+ r"(?i)Death\s*Benefit[\s:\-]*(?:Rs\.?|₹)?\s*([\d,]+(?:\.\d+)?)\s*(Lakhs?|Lacs?|Crores?|Cr)? "
860878 ] if is_life_insurance else [
861- r"(?i)Sum\s*(?:Insured|Assured)[\s:\-]*(?:Rs\.?|₹)?\s*([\d,]+)" ,
862- r"(?i)Cover(?:age)?\s*Amount[\s:\-]*(?:Rs\.?|₹)?\s*([\d,]+)" ,
863- r"(?i)Policy\s*Coverage[\s:\-]*(?:Rs\.?|₹)?\s*([\d,]+)"
879+ # Highest priority: "Annual Sum Insured" - this is the actual policy value
880+ r"(?i)Annual\s+Sum\s+Insured[\s:\-\|]*(?:Rs\.?|₹)?\s*([\d,]+(?:\.\d+)?)\s*(Lakhs?|Lacs?|Crores?|Cr)?" ,
881+ # Next: general Sum Insured/Assured patterns
882+ r"(?i)Sum\s*(?:Insured|Assured)[\s:\-]*(?:Rs\.?|₹)?\s*([\d,]+(?:\.\d+)?)\s*(Lakhs?|Lacs?|Crores?|Cr)?" ,
883+ r"(?i)Cover(?:age)?\s*Amount[\s:\-]*(?:Rs\.?|₹)?\s*([\d,]+(?:\.\d+)?)\s*(Lakhs?|Lacs?|Crores?|Cr)?" ,
884+ r"(?i)Policy\s*Coverage[\s:\-]*(?:Rs\.?|₹)?\s*([\d,]+(?:\.\d+)?)\s*(Lakhs?|Lacs?|Crores?|Cr)?"
864885 ]
865886 )
866887
888+ # Try patterns in priority order; for general patterns, find all matches and pick the largest
889+ sum_value = None
867890 for pattern in sum_patterns :
868- match = re .search (pattern , text , re .IGNORECASE )
869- if match :
870- data ["sum_assured_or_insured" ] = clean_and_convert_to_float (match .group (1 ))
871- break
872- if "sum_assured_or_insured" not in data :
891+ matches = list (re .finditer (pattern , text , re .IGNORECASE ))
892+ if matches :
893+ # Parse all matches and pick the largest value (to avoid partial matches like "₹5 Lakhs" from descriptions)
894+ best_val = None
895+ for m in matches :
896+ num_part = m .group (1 ) if m .lastindex >= 1 else None
897+ suffix_part = m .group (2 ) if m .lastindex >= 2 else ""
898+ parsed = _parse_indian_amount (num_part , suffix_part )
899+ if parsed is not None and (best_val is None or parsed > best_val ):
900+ best_val = parsed
901+ if best_val is not None :
902+ sum_value = best_val
903+ break
904+
905+ if sum_value is not None :
906+ data ["sum_assured_or_insured" ] = sum_value
907+ else :
873908 data ["sum_assured_or_insured" ] = "N/A"
874909
875910 premium_patterns = [
@@ -3996,9 +4031,15 @@ def generate_financial_plan_pdf(q: dict, analysis: dict, output_path: str, doc_i
39964031 term_gap = max (0 , required_term_cover - life_cover )
39974032 health_gap = max (0 , required_health_cover - health_cover )
39984033
3999- # Estimate monthly premiums (rough estimates)
4000- term_premium_yearly = (term_gap / 100000 ) * 700 if term_gap > 0 else 0 # ~Rs.700/lakh/year
4001- health_premium_yearly = (health_gap / 100000 ) * 3000 if health_gap > 0 else 0 # ~Rs.3000/lakh/year
4034+ # Use age-adjusted premium rates (matching llm_sections.py PriorityAllocationEngine)
4035+ # Term insurance: Rs. 500/lakh (age < 35), Rs. 700/lakh (age < 45), Rs. 1200/lakh (age >= 45)
4036+ # Health insurance: Rs. 2500/lakh (age < 35), Rs. 3500/lakh (age < 45), Rs. 5000/lakh (age >= 45)
4037+ client_age = _safe_float (age , 35 ) # Default to 35 if age not available
4038+ term_rate_per_lakh = 500 if client_age < 35 else (700 if client_age < 45 else 1200 )
4039+ health_rate_per_lakh = 2500 if client_age < 35 else (3500 if client_age < 45 else 5000 )
4040+
4041+ term_premium_yearly = (term_gap / 100000 ) * term_rate_per_lakh if term_gap > 0 else 0
4042+ health_premium_yearly = (health_gap / 100000 ) * health_rate_per_lakh if health_gap > 0 else 0
40024043 total_insurance_yearly = term_premium_yearly + health_premium_yearly
40034044 monthly_insurance_equivalent = total_insurance_yearly / 12
40044045
0 commit comments