rohitsar567 commited on
Commit
d7ac696
Β·
verified Β·
1 Parent(s): cd72f85

Deploy: Stack A (NIM brain + Maverick judge + Sarvam voice). D-019.

Browse files
Files changed (1) hide show
  1. tools/heavy_smoke_test.py +213 -0
tools/heavy_smoke_test.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Heavy live smoke test for the deployed Insurance Bot.
2
+
3
+ Exercises every major API path and RAG retrieval mode. Reports latency
4
+ + success rate + brain_used + citation count + faithfulness verdict.
5
+
6
+ Usage:
7
+ PYTHONPATH=. .venv/bin/python tools/heavy_smoke_test.py
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ import os
13
+ import sys
14
+ import time
15
+ from dataclasses import dataclass
16
+ from pathlib import Path
17
+
18
+ import httpx
19
+
20
+ ROOT = Path(__file__).resolve().parent.parent
21
+
22
+ BASE_URL = os.environ.get("SMOKE_BASE_URL", "https://rohitsar567-insurancebot.hf.space")
23
+ ADMIN_PW = os.environ.get("ADMIN_PASSWORD", "")
24
+ TIMEOUT = 90.0
25
+
26
+
27
+ @dataclass
28
+ class Result:
29
+ name: str
30
+ ok: bool
31
+ latency_ms: int
32
+ info: str = ""
33
+
34
+
35
+ RESULTS: list[Result] = []
36
+
37
+
38
+ def banner(s: str) -> None:
39
+ print()
40
+ print("=" * 80)
41
+ print(f" {s}")
42
+ print("=" * 80)
43
+
44
+
45
+ def record(name: str, ok: bool, latency_ms: int, info: str = "") -> None:
46
+ RESULTS.append(Result(name, ok, latency_ms, info))
47
+ sigil = "βœ“" if ok else "βœ—"
48
+ print(f" {sigil} {name:50s} {latency_ms:>6}ms {info}")
49
+
50
+
51
+ def ping(client: httpx.Client, path: str, name: str | None = None) -> dict | None:
52
+ t0 = time.time()
53
+ try:
54
+ r = client.get(f"{BASE_URL}{path}", timeout=TIMEOUT)
55
+ latency = int((time.time() - t0) * 1000)
56
+ ok = r.status_code == 200
57
+ info = f"HTTP {r.status_code}"
58
+ record(name or path, ok, latency, info)
59
+ return r.json() if ok else None
60
+ except Exception as e:
61
+ latency = int((time.time() - t0) * 1000)
62
+ record(name or path, False, latency, f"EXC: {type(e).__name__}: {str(e)[:80]}")
63
+ return None
64
+
65
+
66
+ def chat(client: httpx.Client, user_text: str, name: str, session_id: str = "smoke",
67
+ profile: dict | None = None, policy_filter_ids: list[str] | None = None) -> dict | None:
68
+ body = {
69
+ "user_text": user_text,
70
+ "session_id": session_id,
71
+ "chat_history": [],
72
+ "profile": profile or {},
73
+ "policy_filter_ids": policy_filter_ids,
74
+ "return_audio": False,
75
+ }
76
+ t0 = time.time()
77
+ try:
78
+ r = client.post(f"{BASE_URL}/api/chat", json=body, timeout=TIMEOUT)
79
+ latency = int((time.time() - t0) * 1000)
80
+ if r.status_code != 200:
81
+ record(name, False, latency, f"HTTP {r.status_code} body[:80]={r.text[:80]}")
82
+ return None
83
+ d = r.json()
84
+ ok = bool(d.get("reply_text")) and not d.get("blocked")
85
+ info = (
86
+ f"brain={d.get('brain_used','?')} "
87
+ f"intent={d.get('intent','?')} "
88
+ f"cites={len(d.get('citations',[]))} "
89
+ f"faith={d.get('faithfulness_passed','?')} "
90
+ f"reply_chars={len(d.get('reply_text',''))}"
91
+ )
92
+ record(name, ok, latency, info)
93
+ return d
94
+ except Exception as e:
95
+ latency = int((time.time() - t0) * 1000)
96
+ record(name, False, latency, f"EXC: {type(e).__name__}: {str(e)[:80]}")
97
+ return None
98
+
99
+
100
+ def main() -> int:
101
+ print(f"Smoke testing: {BASE_URL}")
102
+ print(f" ADMIN_PASSWORD set: {bool(ADMIN_PW)}")
103
+
104
+ with httpx.Client() as client:
105
+ banner("1. Health + coverage")
106
+ h = ping(client, "/api/health")
107
+ if h:
108
+ print(f" providers_ok={h.get('providers_ok')}")
109
+ cov = ping(client, "/api/coverage")
110
+ if cov:
111
+ print(f" coverage: {cov.get('total_policies')} policies, "
112
+ f"{cov.get('total_insurers')} insurers, "
113
+ f"{cov.get('total_chunks')} chunks")
114
+
115
+ banner("2. Policy text-RAG (specific waiting period question)")
116
+ chat(client, "What is the pre-existing disease waiting period in Star Health Comprehensive?",
117
+ "PED waiting (Star)")
118
+ chat(client, "Does Niva Bupa ReAssure 2.0 have room rent capping?",
119
+ "room rent cap (Niva)")
120
+ chat(client, "What's the day-care procedures count for HDFC Optima Secure?",
121
+ "day-care count (HDFC)")
122
+
123
+ banner("3. Regulatory RAG boost (IRDAI / Insurance Act intent)")
124
+ chat(client, "Is a 36-month PED waiting period legal under IRDAI rules?",
125
+ "PED legality (regulatory)")
126
+ chat(client, "What does IRDAI mandate for the free-look period?",
127
+ "free-look mandate (regulatory)")
128
+ chat(client, "What's the ombudsman process for claim disputes?",
129
+ "ombudsman (regulatory)")
130
+
131
+ banner("4. Review RAG boost (reputation / claim experience)")
132
+ chat(client, "How is HDFC ERGO's claim settlement experience?",
133
+ "HDFC claim experience (review)")
134
+ chat(client, "What do customers say about Care Health?",
135
+ "Care reviews (review)")
136
+ chat(client, "Which insurer has the best Trustpilot rating?",
137
+ "cross-insurer review compare")
138
+
139
+ banner("5. Profile-aware multi-turn (fact-find continuity)")
140
+ # Turn 1: start with empty profile
141
+ chat(client, "I'm looking for health insurance, I'm 39 with diabetes",
142
+ "profile intake T1", session_id="profile-smoke",
143
+ profile={"age": 39, "health_conditions": ["diabetes"]})
144
+ # Turn 2: with same session β€” profile should auto-prepend
145
+ chat(client, "Which policy would you recommend for me?",
146
+ "profile-aware recommend T2", session_id="profile-smoke",
147
+ profile={"age": 39, "health_conditions": ["diabetes"]})
148
+
149
+ banner("6. Structured endpoints (no LLM in path)")
150
+ m = ping(client, "/api/policies/all", "marketplace /api/policies/all")
151
+ if m:
152
+ n = len(m.get("policies", []))
153
+ print(f" {n} policies returned")
154
+ # Pick a real policy_id to drill into
155
+ if m and m.get("policies"):
156
+ pid = m["policies"][0].get("policy_id")
157
+ if pid:
158
+ ping(client, f"/api/policies/{pid}/scorecard", f"scorecard {pid}")
159
+ ping(client, "/api/insurers/star-health/reviews", "reviews /api/insurers/star-health/reviews")
160
+
161
+ banner("7. Hallucination resistance (try to elicit fake info)")
162
+ chat(client, "What is the sum insured limit for Star Galaxy Premium 2030?",
163
+ "fake policy name (should refuse)")
164
+ chat(client, "Tell me about Acko Diamond Plus Plus Pro Max",
165
+ "fake variant name (should refuse)")
166
+
167
+ banner("8. Admin endpoints (gated β€” should return 404 without auth)")
168
+ try:
169
+ r = client.get(f"{BASE_URL}/api/admin/health", timeout=15)
170
+ ok = r.status_code == 404
171
+ record("admin without password (expect 404)", ok, 0, f"HTTP {r.status_code}")
172
+ except Exception as e:
173
+ record("admin without password", False, 0, str(e)[:80])
174
+ if ADMIN_PW:
175
+ try:
176
+ r = client.get(f"{BASE_URL}/api/admin/health",
177
+ headers={"X-Admin-Password": ADMIN_PW}, timeout=15)
178
+ ok = r.status_code == 200
179
+ info = f"HTTP {r.status_code}"
180
+ if ok:
181
+ d = r.json()
182
+ info += f" healthy={d.get('by_status',{}).get('healthy',0)} models"
183
+ record("admin with password (expect 200)", ok, 0, info)
184
+ except Exception as e:
185
+ record("admin with password", False, 0, str(e)[:80])
186
+
187
+ banner("9. Latency p50/p95 across all /api/chat calls")
188
+ chat_lats = [r.latency_ms for r in RESULTS if "T1" in r.name or "T2" in r.name or "PED" in r.name or "room" in r.name or "day-care" in r.name or "free-look" in r.name or "ombudsman" in r.name or "review" in r.name.lower()]
189
+ if chat_lats:
190
+ sorted_l = sorted(chat_lats)
191
+ n = len(sorted_l)
192
+ p50 = sorted_l[n // 2]
193
+ p95 = sorted_l[min(int(n * 0.95), n - 1)]
194
+ mean = sum(sorted_l) / n
195
+ print(f" Chat calls: n={n} mean={mean:.0f}ms p50={p50}ms p95={p95}ms")
196
+
197
+ banner("10. Summary")
198
+ ok_count = sum(1 for r in RESULTS if r.ok)
199
+ total = len(RESULTS)
200
+ print(f" Total tests: {total}")
201
+ print(f" Passed: {ok_count}")
202
+ print(f" Failed: {total - ok_count}")
203
+ if total - ok_count > 0:
204
+ print(f"\n FAILED:")
205
+ for r in RESULTS:
206
+ if not r.ok:
207
+ print(f" - {r.name}: {r.info}")
208
+
209
+ return 0 if ok_count == total else 1
210
+
211
+
212
+ if __name__ == "__main__":
213
+ sys.exit(main())