rohitsar567 commited on
Commit
83532c8
·
verified ·
1 Parent(s): d1c5011

Deploy v1 — single-Docker FastAPI + Next.js + RAG + voice + faithfulness

Browse files
backend/premium_calculator.py CHANGED
@@ -54,8 +54,15 @@ FALLBACK_SI = {
54
  "2500000": 3.1, "5000000": 4.6, "10000000": 7.2,
55
  }
56
  FALLBACK_CITY = {"metro": 1.0, "tier1": 0.92, "tier2": 0.82}
57
- # family_size=0 is the slider's "self-only" marker treated identically to 1
58
- FALLBACK_FLOATER = {0: 1.0, 1: 1.0, 2: 1.65, 3: 2.0, 4: 2.4, 5: 2.7, 6: 2.95}
 
 
 
 
 
 
 
59
 
60
  # Pre-existing-disease loading factors. Sources: Acko + PolicyBazaar coverage
61
  # articles on PED loading (typical 25-50% premium uplift depending on severity).
 
54
  "2500000": 3.1, "5000000": 4.6, "10000000": 7.2,
55
  }
56
  FALLBACK_CITY = {"metro": 1.0, "tier1": 0.92, "tier2": 0.82}
57
+ # family_size = NUMBER OF DEPENDENTS COVERED (in addition to self).
58
+ # 0 = self only (individual policy, no floater premium uplift)
59
+ # 1 = self + 1 dependent (couple cover)
60
+ # 2 = self + 2 dependents (small family)
61
+ # ...
62
+ # Source: typical retail family-floater rate cards from PolicyBazaar +
63
+ # InsuranceDekho — individual base, ~1.5× for couple, ~2× for family of 3,
64
+ # ~2.4× for family of 4, scaling thereafter.
65
+ FALLBACK_FLOATER = {0: 1.0, 1: 1.50, 2: 1.85, 3: 2.20, 4: 2.55, 5: 2.85, 6: 3.10}
66
 
67
  # Pre-existing-disease loading factors. Sources: Acko + PolicyBazaar coverage
68
  # articles on PED loading (typical 25-50% premium uplift depending on severity).
frontend/src/app/page.tsx CHANGED
@@ -440,20 +440,22 @@ function PremiumCalculatorPanel({ onClose }: { onClose: () => void }) {
440
  const [sumInsured, setSumInsured] = useState(1000000);
441
  const [cityTier, setCityTier] = useState<"metro" | "tier1" | "tier2">("metro");
442
  const [smoker, setSmoker] = useState(false);
443
- const [familySize, setFamilySize] = useState(2);
 
 
444
  const [estimate, setEstimate] = useState<PremiumEstimateResponse | null>(null);
445
  const [busy, setBusy] = useState(false);
446
 
447
  useEffect(() => {
448
  const handler = setTimeout(() => {
449
  setBusy(true);
450
- postPremiumEstimate({ age, sum_insured_inr: sumInsured, city_tier: cityTier, smoker, family_size: familySize })
451
  .then(setEstimate)
452
  .catch(() => setEstimate(null))
453
  .finally(() => setBusy(false));
454
  }, 200); // debounce
455
  return () => clearTimeout(handler);
456
- }, [age, sumInsured, cityTier, smoker, familySize]);
457
 
458
  const fmtINR = (v: number) => `₹${v.toLocaleString("en-IN")}`;
459
  const siDisplay = sumInsured >= 10000000 ? `${sumInsured / 10000000} cr` : `${sumInsured / 100000} L`;
@@ -506,15 +508,41 @@ function PremiumCalculatorPanel({ onClose }: { onClose: () => void }) {
506
  <div>
507
  <label className="flex items-center justify-between text-xs mb-1">
508
  <span className="font-medium">Family covered</span>
509
- <span className="font-mono">{familySize} {familySize === 1 ? "person" : "people"}</span>
510
  </label>
511
  <input
512
- type="range" min={1} max={6} step={1}
513
  value={familySize}
514
  onChange={(e) => setFamilySize(parseInt(e.target.value))}
515
  className="w-full accent-[var(--primary)]"
516
  />
517
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
518
  <div className="flex items-center gap-3 flex-wrap text-xs">
519
  <span className="font-medium">City tier:</span>
520
  {(["metro", "tier1", "tier2"] as const).map((t) => (
@@ -1131,17 +1159,19 @@ function PerPolicyPremiumEstimator({ policy }: { policy: MarketplacePolicy }) {
1131
  const [si, setSI] = useState(defaultSI);
1132
  const [city, setCity] = useState<"metro" | "tier1" | "tier2">("metro");
1133
  const [smoker, setSmoker] = useState(false);
1134
- const [fam, setFam] = useState(1);
 
 
1135
  const [est, setEst] = useState<PremiumEstimateResponse | null>(null);
1136
  const [busy, setBusy] = useState(false);
1137
  useEffect(() => {
1138
  const t = setTimeout(() => {
1139
  setBusy(true);
1140
- postPremiumEstimate({ age, sum_insured_inr: si, city_tier: city, smoker, family_size: fam, policy_id: policy.policy_id })
1141
  .then(setEst).catch(() => setEst(null)).finally(() => setBusy(false));
1142
  }, 150);
1143
  return () => clearTimeout(t);
1144
- }, [age, si, city, smoker, fam, policy.policy_id]);
1145
  const fmt = (v: number) => `₹${v.toLocaleString("en-IN")}`;
1146
  const siDisp = si >= 10000000 ? `${si / 10000000} cr` : `${si / 100000} L`;
1147
  return (
@@ -1161,9 +1191,28 @@ function PerPolicyPremiumEstimator({ policy }: { policy: MarketplacePolicy }) {
1161
  </div>
1162
  <div>
1163
  <div className="flex items-center justify-between text-[10px] uppercase tracking-wide text-[var(--muted-foreground)] font-semibold">
1164
- <span>Family size</span><span className="font-mono">{fam}</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1165
  </div>
1166
- <input type="range" min={1} max={6} value={fam} onChange={(e) => setFam(parseInt(e.target.value))} className="w-full accent-[var(--primary)]" />
1167
  </div>
1168
  <div className="flex items-center gap-2 flex-wrap text-[11px] pt-1">
1169
  {(["metro", "tier1", "tier2"] as const).map((t) => (
 
440
  const [sumInsured, setSumInsured] = useState(1000000);
441
  const [cityTier, setCityTier] = useState<"metro" | "tier1" | "tier2">("metro");
442
  const [smoker, setSmoker] = useState(false);
443
+ const [familySize, setFamilySize] = useState(0);
444
+ const [ped, setPed] = useState<"none" | "diabetes_or_hypertension" | "heart_disease" | "multiple">("none");
445
+ const [copay, setCopay] = useState(0);
446
  const [estimate, setEstimate] = useState<PremiumEstimateResponse | null>(null);
447
  const [busy, setBusy] = useState(false);
448
 
449
  useEffect(() => {
450
  const handler = setTimeout(() => {
451
  setBusy(true);
452
+ postPremiumEstimate({ age, sum_insured_inr: sumInsured, city_tier: cityTier, smoker, family_size: familySize, pre_existing_conditions: ped, copayment_pct: copay })
453
  .then(setEstimate)
454
  .catch(() => setEstimate(null))
455
  .finally(() => setBusy(false));
456
  }, 200); // debounce
457
  return () => clearTimeout(handler);
458
+ }, [age, sumInsured, cityTier, smoker, familySize, ped, copay]);
459
 
460
  const fmtINR = (v: number) => `₹${v.toLocaleString("en-IN")}`;
461
  const siDisplay = sumInsured >= 10000000 ? `${sumInsured / 10000000} cr` : `${sumInsured / 100000} L`;
 
508
  <div>
509
  <label className="flex items-center justify-between text-xs mb-1">
510
  <span className="font-medium">Family covered</span>
511
+ <span className="font-mono">{familySize === 0 ? "Self only" : `Self + ${familySize} dependent${familySize === 1 ? "" : "s"}`}</span>
512
  </label>
513
  <input
514
+ type="range" min={0} max={6} step={1}
515
  value={familySize}
516
  onChange={(e) => setFamilySize(parseInt(e.target.value))}
517
  className="w-full accent-[var(--primary)]"
518
  />
519
  </div>
520
+ <div>
521
+ <label className="block text-xs mb-1 font-medium">Pre-existing conditions</label>
522
+ <select
523
+ value={ped}
524
+ onChange={(e) => setPed(e.target.value as typeof ped)}
525
+ className="w-full text-xs bg-transparent border border-[var(--border)] rounded-md px-2 py-1.5 outline-none focus:border-[var(--primary)]"
526
+ >
527
+ <option value="none">None</option>
528
+ <option value="diabetes_or_hypertension">Diabetes or hypertension</option>
529
+ <option value="heart_disease">Heart disease</option>
530
+ <option value="multiple">Multiple conditions</option>
531
+ </select>
532
+ </div>
533
+ <div>
534
+ <label className="flex items-center justify-between text-xs mb-1">
535
+ <span className="font-medium">Voluntary co-pay</span>
536
+ <span className="font-mono">{copay}%</span>
537
+ </label>
538
+ <input
539
+ type="range" min={0} max={40} step={5}
540
+ value={copay}
541
+ onChange={(e) => setCopay(parseInt(e.target.value))}
542
+ className="w-full accent-[var(--primary)]"
543
+ />
544
+ <p className="text-[10px] text-[var(--muted-foreground)] mt-0.5">Higher co-pay = lower premium; you pay this % of each claim</p>
545
+ </div>
546
  <div className="flex items-center gap-3 flex-wrap text-xs">
547
  <span className="font-medium">City tier:</span>
548
  {(["metro", "tier1", "tier2"] as const).map((t) => (
 
1159
  const [si, setSI] = useState(defaultSI);
1160
  const [city, setCity] = useState<"metro" | "tier1" | "tier2">("metro");
1161
  const [smoker, setSmoker] = useState(false);
1162
+ const [fam, setFam] = useState(0);
1163
+ const [ped, setPed] = useState<"none" | "diabetes_or_hypertension" | "heart_disease" | "multiple">("none");
1164
+ const [copay, setCopay] = useState(0);
1165
  const [est, setEst] = useState<PremiumEstimateResponse | null>(null);
1166
  const [busy, setBusy] = useState(false);
1167
  useEffect(() => {
1168
  const t = setTimeout(() => {
1169
  setBusy(true);
1170
+ postPremiumEstimate({ age, sum_insured_inr: si, city_tier: city, smoker, family_size: fam, policy_id: policy.policy_id, pre_existing_conditions: ped, copayment_pct: copay })
1171
  .then(setEst).catch(() => setEst(null)).finally(() => setBusy(false));
1172
  }, 150);
1173
  return () => clearTimeout(t);
1174
+ }, [age, si, city, smoker, fam, ped, copay, policy.policy_id]);
1175
  const fmt = (v: number) => `₹${v.toLocaleString("en-IN")}`;
1176
  const siDisp = si >= 10000000 ? `${si / 10000000} cr` : `${si / 100000} L`;
1177
  return (
 
1191
  </div>
1192
  <div>
1193
  <div className="flex items-center justify-between text-[10px] uppercase tracking-wide text-[var(--muted-foreground)] font-semibold">
1194
+ <span>Family covered</span><span className="font-mono">{fam === 0 ? "Self only" : `Self + ${fam}`}</span>
1195
+ </div>
1196
+ <input type="range" min={0} max={6} value={fam} onChange={(e) => setFam(parseInt(e.target.value))} className="w-full accent-[var(--primary)]" />
1197
+ </div>
1198
+ <div>
1199
+ <div className="text-[10px] uppercase tracking-wide text-[var(--muted-foreground)] font-semibold mb-0.5">Pre-existing conditions</div>
1200
+ <select
1201
+ value={ped}
1202
+ onChange={(e) => setPed(e.target.value as typeof ped)}
1203
+ className="w-full text-[11px] bg-transparent border border-[var(--border)] rounded px-1.5 py-1"
1204
+ >
1205
+ <option value="none">None</option>
1206
+ <option value="diabetes_or_hypertension">Diabetes / hypertension</option>
1207
+ <option value="heart_disease">Heart disease</option>
1208
+ <option value="multiple">Multiple</option>
1209
+ </select>
1210
+ </div>
1211
+ <div>
1212
+ <div className="flex items-center justify-between text-[10px] uppercase tracking-wide text-[var(--muted-foreground)] font-semibold">
1213
+ <span>Co-pay</span><span className="font-mono">{copay}%</span>
1214
  </div>
1215
+ <input type="range" min={0} max={40} step={5} value={copay} onChange={(e) => setCopay(parseInt(e.target.value))} className="w-full accent-[var(--primary)]" />
1216
  </div>
1217
  <div className="flex items-center gap-2 flex-wrap text-[11px] pt-1">
1218
  {(["metro", "tier1", "tier2"] as const).map((t) => (