junaid17 commited on
Commit
320aeb1
·
verified ·
1 Parent(s): 20994e6

Upload 13 files

Browse files
Dockerfile ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ # Prevent Python from writing pyc files
4
+ ENV PYTHONDONTWRITEBYTECODE=1
5
+ ENV PYTHONUNBUFFERED=1
6
+
7
+ WORKDIR /app
8
+
9
+ # Install system dependencies (required for sklearn / xgboost)
10
+ RUN apt-get update && apt-get install -y \
11
+ build-essential \
12
+ gcc \
13
+ && rm -rf /var/lib/apt/lists/*
14
+
15
+ # Copy and install dependencies first (better caching)
16
+ COPY requirements.txt .
17
+ RUN pip install --no-cache-dir --upgrade pip \
18
+ && pip install --no-cache-dir -r requirements.txt
19
+
20
+ # Copy application code
21
+ COPY . .
22
+
23
+ # Hugging Face expects port 7860
24
+ EXPOSE 7860
25
+
26
+ # Start FastAPI
27
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from pydantic import BaseModel, Field
3
+ from typing import Annotated, Literal
4
+ from prediction_helper import predict
5
+ from one_shot_bot import generate_advice
6
+ from chatbot_advisor import ask_chatbot
7
+
8
+ class ModelInput(BaseModel):
9
+ gender: Annotated[Literal["male", "female"], Field(description="Enter your gender")]
10
+ marital_status: Annotated[Literal["married", "unmarried"], Field(description="Enter your marital status")]
11
+ age: Annotated[int, Field(gt=0, lt=110, description="Enter your age")]
12
+ number_of_dependants: Annotated[int, Field(gt=0, lt=8)]
13
+ income_lakhs: Annotated[float, Field(gt=0,description="Enter your annual income in lakhs")]
14
+ genetical_risk: Annotated[int, Field(gt=0, lt=6)]
15
+ insurance_plan: Annotated[Literal['Bronze', 'Silver', 'Gold'], Field(description="Choose one of the given plans")]
16
+ employment_status: Annotated[Literal['Salaried', 'Self-Employed', 'Freelancer'], Field()]
17
+ bmi_category: Annotated[Literal['Normal', 'Obesity', 'Overweight', 'Underweight'], Field()]
18
+ smoking_status: Annotated[Literal['No Smoking', 'Regular', 'Occasional'], Field()]
19
+ region: Annotated[Literal['Northwest', 'Southeast', 'Northeast', 'Southwest'], Field()]
20
+ medical_history: Annotated[
21
+ Literal[
22
+ 'No Disease', 'Diabetes', 'High blood pressure', 'Diabetes & High blood pressure',
23
+ 'Thyroid', 'Heart disease', 'High blood pressure & Heart disease',
24
+ 'Diabetes & Thyroid', 'Diabetes & Heart disease'
25
+ ],
26
+ Field()
27
+ ]
28
+
29
+ class ModelOutput(BaseModel):
30
+ yearly : float
31
+ monthly : float
32
+ advice : str
33
+
34
+ class ChatMessage(BaseModel):
35
+ thread_id : str
36
+ message : str
37
+ yearly_cost : float
38
+ monthly_cost : float
39
+ ai_summary : str
40
+
41
+ app = FastAPI()
42
+
43
+ @app.get("/plans")
44
+ def plans():
45
+ return {
46
+ "Bronze": "Basic coverage, low premium.",
47
+ "Silver": "Balance of premium and coverage.",
48
+ "Gold": "Premium cost with highest benefits."
49
+ }
50
+
51
+
52
+ @app.get("/home")
53
+ def home():
54
+ return {"message": "Welcome! The API is live"}
55
+
56
+ @app.post("/predict", response_model=ModelOutput)
57
+ def predict_output(input_data: ModelInput):
58
+ try:
59
+ data = input_data.model_dump()
60
+
61
+ converted_data = {
62
+ "Gender": data["gender"].title(),
63
+ "Marital Status": data["marital_status"].title(),
64
+ "Age": data["age"],
65
+ "Number of Dependants": data["number_of_dependants"],
66
+ "Income in Lakhs": data["income_lakhs"],
67
+ "Genetical Risk": data["genetical_risk"],
68
+ "Insurance Plan": data["insurance_plan"].title(),
69
+ "Employment Status": data["employment_status"],
70
+ "BMI Category": data["bmi_category"],
71
+ "Smoking Status": data["smoking_status"],
72
+ "Region": data["region"],
73
+ "Medical History": data["medical_history"]
74
+ }
75
+
76
+ yearly_prediction = float(predict(converted_data))
77
+ monthly = round(yearly_prediction / 12, 2)
78
+
79
+ advice = generate_advice(
80
+ yearly_premium=yearly_prediction,
81
+ monthly_premium=monthly,
82
+ age=input_data.age,
83
+ gender=input_data.gender,
84
+ marital_status=input_data.marital_status,
85
+ dependents=input_data.number_of_dependants,
86
+ bmi_category=input_data.bmi_category,
87
+ smoking_status=input_data.smoking_status,
88
+ medical_history=input_data.medical_history,
89
+ genetic_risk=input_data.genetical_risk,
90
+ region=input_data.region,
91
+ income_lakhs=input_data.income_lakhs,
92
+ employment_status=input_data.employment_status,
93
+ insurance_plan=input_data.insurance_plan
94
+ )
95
+
96
+ return ModelOutput(yearly=yearly_prediction, monthly=monthly, advice=advice)
97
+
98
+ except Exception as e:
99
+ raise HTTPException(status_code=500, detail=f"Prediction Failed: {str(e)}")
100
+
101
+
102
+ @app.post('/chat')
103
+ def chat(input_data : ChatMessage):
104
+ try:
105
+ yearly_cost = input_data.yearly_cost
106
+ monthly_cost = input_data.monthly_cost
107
+ ai_summary = input_data.ai_summary
108
+
109
+ response = ask_chatbot(
110
+ yearly_cost=yearly_cost,
111
+ monthly_cost=monthly_cost,
112
+ ai_summary=ai_summary,
113
+ user_message=input_data.message,
114
+ thread_id=input_data.thread_id
115
+ )
116
+ return {"response": response}
117
+
118
+ except Exception as e:
119
+ raise HTTPException(status_code=500, detail=str(e))
chatbot_advisor.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langgraph.graph import StateGraph, START, END
2
+ from typing import TypedDict,Annotated
3
+ from langchain_core.messages import HumanMessage, BaseMessage, AIMessage, SystemMessage
4
+ from langchain_groq import ChatGroq
5
+ from langgraph.checkpoint.memory import MemorySaver
6
+ from dotenv import load_dotenv
7
+ from langgraph.graph.message import add_messages
8
+ import os
9
+ load_dotenv()
10
+
11
+ class ChatState(TypedDict):
12
+ messages : Annotated[list[BaseMessage], add_messages]
13
+
14
+ llm = ChatGroq(model="openai/gpt-oss-20b", api_key=os.getenv("GROQ_API_KEY"), streaming=True)
15
+
16
+ SYSTEM_MESSAGE = SystemMessage(
17
+ content=(
18
+ """You are CareWise AI, a helpful health insurance guidance assistant designed to help users understand their estimated insurance premium and explore suitable coverage options based on the information they provide.
19
+
20
+ Your role is to:
21
+ - Explain premium estimates in a simple and friendly way
22
+ - Help users make sense of the key factors influencing cost
23
+ - Offer useful and relevant recommendations on insurance plans, budgeting, and coverage fit
24
+ - Provide supportive guidance without making guarantees or medical claims
25
+
26
+ Your response style should be:
27
+
28
+ - Clear, conversational, and human-like (avoid robotic tone)
29
+ - Short and structured rather than long or overwhelming
30
+ - Warm, encouraging, and professional
31
+ - Empathetic and respectful, especially when discussing health-related factors
32
+ - Neutral and non-judgmental (never shame lifestyle or medical conditions)
33
+
34
+ When responding:
35
+
36
+ - Reference user context when helpful (age, plan type, lifestyle factors, etc.)
37
+ - Focus on the most meaningful cost drivers rather than listing everything
38
+ - Provide actionable suggestions (example: exploring plan tiers, budgeting tips, preventive care habits, lifestyle improvements, or coverage add-ons)
39
+ - Keep explanations simple and avoid technical insurance language unless useful and easy to explain
40
+ - Avoid long paragraphs; use short sentences or small chunks for clarity
41
+
42
+ Safety Rules:
43
+
44
+ - Do NOT give medical advice, diagnoses, treatment recommendations, or anything that could be interpreted as professional health guidance
45
+ - Do NOT make financial guarantees or legal statements
46
+ - You may suggest healthy habits only in general, non-medical wording (e.g., "staying active may help overall well-being")
47
+ - Never promise that a specific plan or behavior will reduce premiums
48
+
49
+ If the user asks a question outside your scope, gently redirect them to a licensed insurance advisor or healthcare professional.
50
+
51
+ Your priority is helping users feel informed, confident, and supported while exploring insurance costs and coverage options.
52
+ """
53
+ )
54
+ )
55
+
56
+ def chat_node(state : ChatState):
57
+ user_query = state['messages']
58
+ query = [SYSTEM_MESSAGE]+user_query
59
+ response = llm.invoke(query)
60
+ return {'messages': [response]}
61
+
62
+ checkpointer = MemorySaver()
63
+ graph = StateGraph(ChatState)
64
+ graph.add_node("chat_node", chat_node)
65
+ graph.add_edge(START, 'chat_node')
66
+ graph.add_edge('chat_node', END)
67
+
68
+ insurance_chatbot = graph.compile(checkpointer=checkpointer)
69
+
70
+ thread_id='1'
71
+ config = {'configurable' : {'thread_id' : thread_id}}
72
+
73
+ def format_chat_input(yearly_cost, monthly_cost, ai_summary, user_message):
74
+ return f"""
75
+ Below is the most recent health insurance evaluation. Use this information while responding.
76
+
77
+ INSURANCE ESTIMATE
78
+ ------------------
79
+ • Yearly Premium: ₹{yearly_cost:,.2f}
80
+ • Monthly Cost: ₹{monthly_cost:,.2f}
81
+
82
+ AI PLAN SUMMARY
83
+ ---------------
84
+ {ai_summary}
85
+
86
+ USER QUESTION
87
+ -------------
88
+ {user_message}
89
+
90
+ Respond as CareWise AI using a warm, clear, and supportive tone. Make your answer helpful and easy to understand.
91
+ """
92
+
93
+ def ask_chatbot(yearly_cost, monthly_cost, ai_summary, user_message, thread_id):
94
+ formatted_msg = format_chat_input(yearly_cost, monthly_cost, ai_summary, user_message)
95
+
96
+ initial_state = {
97
+ "messages": [HumanMessage(content=formatted_msg)]
98
+ }
99
+
100
+ config = {"configurable": {"thread_id": thread_id}}
101
+
102
+ response = insurance_chatbot.invoke(initial_state, config=config)
103
+ return response["messages"][-1].content
data_segmentation.ipynb ADDED
@@ -0,0 +1,433 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 10,
6
+ "id": "35b7f880",
7
+ "metadata": {
8
+ "scrolled": true
9
+ },
10
+ "outputs": [
11
+ {
12
+ "data": {
13
+ "text/html": [
14
+ "<div>\n",
15
+ "<style scoped>\n",
16
+ " .dataframe tbody tr th:only-of-type {\n",
17
+ " vertical-align: middle;\n",
18
+ " }\n",
19
+ "\n",
20
+ " .dataframe tbody tr th {\n",
21
+ " vertical-align: top;\n",
22
+ " }\n",
23
+ "\n",
24
+ " .dataframe thead th {\n",
25
+ " text-align: right;\n",
26
+ " }\n",
27
+ "</style>\n",
28
+ "<table border=\"1\" class=\"dataframe\">\n",
29
+ " <thead>\n",
30
+ " <tr style=\"text-align: right;\">\n",
31
+ " <th></th>\n",
32
+ " <th>Age</th>\n",
33
+ " <th>Gender</th>\n",
34
+ " <th>Region</th>\n",
35
+ " <th>Marital_status</th>\n",
36
+ " <th>Number Of Dependants</th>\n",
37
+ " <th>BMI_Category</th>\n",
38
+ " <th>Smoking_Status</th>\n",
39
+ " <th>Employment_Status</th>\n",
40
+ " <th>Income_Level</th>\n",
41
+ " <th>Income_Lakhs</th>\n",
42
+ " <th>Medical History</th>\n",
43
+ " <th>Insurance_Plan</th>\n",
44
+ " <th>Annual_Premium_Amount</th>\n",
45
+ " </tr>\n",
46
+ " </thead>\n",
47
+ " <tbody>\n",
48
+ " <tr>\n",
49
+ " <th>0</th>\n",
50
+ " <td>26</td>\n",
51
+ " <td>Male</td>\n",
52
+ " <td>Northwest</td>\n",
53
+ " <td>Unmarried</td>\n",
54
+ " <td>0</td>\n",
55
+ " <td>Normal</td>\n",
56
+ " <td>No Smoking</td>\n",
57
+ " <td>Salaried</td>\n",
58
+ " <td>&lt;10L</td>\n",
59
+ " <td>6</td>\n",
60
+ " <td>Diabetes</td>\n",
61
+ " <td>Bronze</td>\n",
62
+ " <td>9053</td>\n",
63
+ " </tr>\n",
64
+ " <tr>\n",
65
+ " <th>1</th>\n",
66
+ " <td>29</td>\n",
67
+ " <td>Female</td>\n",
68
+ " <td>Southeast</td>\n",
69
+ " <td>Married</td>\n",
70
+ " <td>2</td>\n",
71
+ " <td>Obesity</td>\n",
72
+ " <td>Regular</td>\n",
73
+ " <td>Salaried</td>\n",
74
+ " <td>&lt;10L</td>\n",
75
+ " <td>6</td>\n",
76
+ " <td>Diabetes</td>\n",
77
+ " <td>Bronze</td>\n",
78
+ " <td>16339</td>\n",
79
+ " </tr>\n",
80
+ " <tr>\n",
81
+ " <th>2</th>\n",
82
+ " <td>49</td>\n",
83
+ " <td>Female</td>\n",
84
+ " <td>Northeast</td>\n",
85
+ " <td>Married</td>\n",
86
+ " <td>2</td>\n",
87
+ " <td>Normal</td>\n",
88
+ " <td>No Smoking</td>\n",
89
+ " <td>Self-Employed</td>\n",
90
+ " <td>10L - 25L</td>\n",
91
+ " <td>20</td>\n",
92
+ " <td>High blood pressure</td>\n",
93
+ " <td>Silver</td>\n",
94
+ " <td>18164</td>\n",
95
+ " </tr>\n",
96
+ " <tr>\n",
97
+ " <th>3</th>\n",
98
+ " <td>30</td>\n",
99
+ " <td>Female</td>\n",
100
+ " <td>Southeast</td>\n",
101
+ " <td>Married</td>\n",
102
+ " <td>3</td>\n",
103
+ " <td>Normal</td>\n",
104
+ " <td>No Smoking</td>\n",
105
+ " <td>Salaried</td>\n",
106
+ " <td>&gt; 40L</td>\n",
107
+ " <td>77</td>\n",
108
+ " <td>No Disease</td>\n",
109
+ " <td>Gold</td>\n",
110
+ " <td>20303</td>\n",
111
+ " </tr>\n",
112
+ " <tr>\n",
113
+ " <th>4</th>\n",
114
+ " <td>18</td>\n",
115
+ " <td>Male</td>\n",
116
+ " <td>Northeast</td>\n",
117
+ " <td>Unmarried</td>\n",
118
+ " <td>0</td>\n",
119
+ " <td>Overweight</td>\n",
120
+ " <td>Regular</td>\n",
121
+ " <td>Self-Employed</td>\n",
122
+ " <td>&gt; 40L</td>\n",
123
+ " <td>99</td>\n",
124
+ " <td>High blood pressure</td>\n",
125
+ " <td>Silver</td>\n",
126
+ " <td>13365</td>\n",
127
+ " </tr>\n",
128
+ " </tbody>\n",
129
+ "</table>\n",
130
+ "</div>"
131
+ ],
132
+ "text/plain": [
133
+ " Age Gender Region Marital_status Number Of Dependants BMI_Category \\\n",
134
+ "0 26 Male Northwest Unmarried 0 Normal \n",
135
+ "1 29 Female Southeast Married 2 Obesity \n",
136
+ "2 49 Female Northeast Married 2 Normal \n",
137
+ "3 30 Female Southeast Married 3 Normal \n",
138
+ "4 18 Male Northeast Unmarried 0 Overweight \n",
139
+ "\n",
140
+ " Smoking_Status Employment_Status Income_Level Income_Lakhs \\\n",
141
+ "0 No Smoking Salaried <10L 6 \n",
142
+ "1 Regular Salaried <10L 6 \n",
143
+ "2 No Smoking Self-Employed 10L - 25L 20 \n",
144
+ "3 No Smoking Salaried > 40L 77 \n",
145
+ "4 Regular Self-Employed > 40L 99 \n",
146
+ "\n",
147
+ " Medical History Insurance_Plan Annual_Premium_Amount \n",
148
+ "0 Diabetes Bronze 9053 \n",
149
+ "1 Diabetes Bronze 16339 \n",
150
+ "2 High blood pressure Silver 18164 \n",
151
+ "3 No Disease Gold 20303 \n",
152
+ "4 High blood pressure Silver 13365 "
153
+ ]
154
+ },
155
+ "execution_count": 10,
156
+ "metadata": {},
157
+ "output_type": "execute_result"
158
+ }
159
+ ],
160
+ "source": [
161
+ "import pandas as pd\n",
162
+ "df = pd.read_excel(\"premiums.xlsx\")\n",
163
+ "df.head()"
164
+ ]
165
+ },
166
+ {
167
+ "cell_type": "code",
168
+ "execution_count": 11,
169
+ "id": "2b820232",
170
+ "metadata": {},
171
+ "outputs": [
172
+ {
173
+ "data": {
174
+ "text/plain": [
175
+ "(50000, 13)"
176
+ ]
177
+ },
178
+ "execution_count": 11,
179
+ "metadata": {},
180
+ "output_type": "execute_result"
181
+ }
182
+ ],
183
+ "source": [
184
+ "df.shape"
185
+ ]
186
+ },
187
+ {
188
+ "cell_type": "code",
189
+ "execution_count": 12,
190
+ "id": "206a3cdb",
191
+ "metadata": {
192
+ "scrolled": false
193
+ },
194
+ "outputs": [
195
+ {
196
+ "data": {
197
+ "text/plain": [
198
+ "count 50000.000000\n",
199
+ "mean 34.593480\n",
200
+ "std 15.000437\n",
201
+ "min 18.000000\n",
202
+ "25% 22.000000\n",
203
+ "50% 31.000000\n",
204
+ "75% 45.000000\n",
205
+ "max 356.000000\n",
206
+ "Name: Age, dtype: float64"
207
+ ]
208
+ },
209
+ "execution_count": 12,
210
+ "metadata": {},
211
+ "output_type": "execute_result"
212
+ }
213
+ ],
214
+ "source": [
215
+ "df.Age.describe()"
216
+ ]
217
+ },
218
+ {
219
+ "cell_type": "code",
220
+ "execution_count": 13,
221
+ "id": "8b905a77",
222
+ "metadata": {},
223
+ "outputs": [],
224
+ "source": [
225
+ "df_young = df[df.Age<=25]\n",
226
+ "df_rest = df[df.Age>25]"
227
+ ]
228
+ },
229
+ {
230
+ "cell_type": "code",
231
+ "execution_count": 14,
232
+ "id": "f1d671ec",
233
+ "metadata": {},
234
+ "outputs": [
235
+ {
236
+ "data": {
237
+ "text/plain": [
238
+ "((20096, 13), (29904, 13))"
239
+ ]
240
+ },
241
+ "execution_count": 14,
242
+ "metadata": {},
243
+ "output_type": "execute_result"
244
+ }
245
+ ],
246
+ "source": [
247
+ "df_young.shape, df_rest.shape"
248
+ ]
249
+ },
250
+ {
251
+ "cell_type": "code",
252
+ "execution_count": 15,
253
+ "id": "f566ae1c",
254
+ "metadata": {},
255
+ "outputs": [],
256
+ "source": [
257
+ "df_young.to_excel(\"premiums_young.xlsx\", index=False)\n",
258
+ "df_rest.to_excel(\"premiums_rest.xlsx\", index=False)"
259
+ ]
260
+ },
261
+ {
262
+ "cell_type": "code",
263
+ "execution_count": null,
264
+ "id": "ebcc0f68",
265
+ "metadata": {},
266
+ "outputs": [],
267
+ "source": []
268
+ },
269
+ {
270
+ "cell_type": "code",
271
+ "execution_count": 2,
272
+ "id": "469c45f4",
273
+ "metadata": {},
274
+ "outputs": [
275
+ {
276
+ "data": {
277
+ "text/html": [
278
+ "<div>\n",
279
+ "<style scoped>\n",
280
+ " .dataframe tbody tr th:only-of-type {\n",
281
+ " vertical-align: middle;\n",
282
+ " }\n",
283
+ "\n",
284
+ " .dataframe tbody tr th {\n",
285
+ " vertical-align: top;\n",
286
+ " }\n",
287
+ "\n",
288
+ " .dataframe thead th {\n",
289
+ " text-align: right;\n",
290
+ " }\n",
291
+ "</style>\n",
292
+ "<table border=\"1\" class=\"dataframe\">\n",
293
+ " <thead>\n",
294
+ " <tr style=\"text-align: right;\">\n",
295
+ " <th></th>\n",
296
+ " <th>Age</th>\n",
297
+ " <th>Gender</th>\n",
298
+ " <th>Region</th>\n",
299
+ " <th>Marital_status</th>\n",
300
+ " <th>Number Of Dependants</th>\n",
301
+ " <th>BMI_Category</th>\n",
302
+ " <th>Smoking_Status</th>\n",
303
+ " <th>Employment_Status</th>\n",
304
+ " <th>Income_Level</th>\n",
305
+ " <th>Income_Lakhs</th>\n",
306
+ " <th>Medical History</th>\n",
307
+ " <th>Insurance_Plan</th>\n",
308
+ " <th>Annual_Premium_Amount</th>\n",
309
+ " <th>Genetical_Risk</th>\n",
310
+ " </tr>\n",
311
+ " </thead>\n",
312
+ " <tbody>\n",
313
+ " <tr>\n",
314
+ " <th>0</th>\n",
315
+ " <td>26</td>\n",
316
+ " <td>Male</td>\n",
317
+ " <td>Northwest</td>\n",
318
+ " <td>Unmarried</td>\n",
319
+ " <td>0</td>\n",
320
+ " <td>Normal</td>\n",
321
+ " <td>No Smoking</td>\n",
322
+ " <td>Salaried</td>\n",
323
+ " <td>&lt;10L</td>\n",
324
+ " <td>6</td>\n",
325
+ " <td>Diabetes</td>\n",
326
+ " <td>Bronze</td>\n",
327
+ " <td>9053</td>\n",
328
+ " <td>5</td>\n",
329
+ " </tr>\n",
330
+ " <tr>\n",
331
+ " <th>1</th>\n",
332
+ " <td>29</td>\n",
333
+ " <td>Female</td>\n",
334
+ " <td>Southeast</td>\n",
335
+ " <td>Married</td>\n",
336
+ " <td>2</td>\n",
337
+ " <td>Obesity</td>\n",
338
+ " <td>Regular</td>\n",
339
+ " <td>Salaried</td>\n",
340
+ " <td>&lt;10L</td>\n",
341
+ " <td>6</td>\n",
342
+ " <td>Diabetes</td>\n",
343
+ " <td>Bronze</td>\n",
344
+ " <td>16339</td>\n",
345
+ " <td>0</td>\n",
346
+ " </tr>\n",
347
+ " </tbody>\n",
348
+ "</table>\n",
349
+ "</div>"
350
+ ],
351
+ "text/plain": [
352
+ " Age Gender Region Marital_status Number Of Dependants BMI_Category \\\n",
353
+ "0 26 Male Northwest Unmarried 0 Normal \n",
354
+ "1 29 Female Southeast Married 2 Obesity \n",
355
+ "\n",
356
+ " Smoking_Status Employment_Status Income_Level Income_Lakhs Medical History \\\n",
357
+ "0 No Smoking Salaried <10L 6 Diabetes \n",
358
+ "1 Regular Salaried <10L 6 Diabetes \n",
359
+ "\n",
360
+ " Insurance_Plan Annual_Premium_Amount Genetical_Risk \n",
361
+ "0 Bronze 9053 5 \n",
362
+ "1 Bronze 16339 0 "
363
+ ]
364
+ },
365
+ "execution_count": 2,
366
+ "metadata": {},
367
+ "output_type": "execute_result"
368
+ }
369
+ ],
370
+ "source": [
371
+ "import pandas as pd\n",
372
+ "df = pd.read_excel(\"premiums_with_gr.xlsx\")\n",
373
+ "df.head(2)"
374
+ ]
375
+ },
376
+ {
377
+ "cell_type": "code",
378
+ "execution_count": 17,
379
+ "id": "48104400",
380
+ "metadata": {},
381
+ "outputs": [
382
+ {
383
+ "data": {
384
+ "text/plain": [
385
+ "((20096, 14), (29904, 14))"
386
+ ]
387
+ },
388
+ "execution_count": 17,
389
+ "metadata": {},
390
+ "output_type": "execute_result"
391
+ }
392
+ ],
393
+ "source": [
394
+ "df_young = df[df.Age<=25]\n",
395
+ "df_rest = df[df.Age>25]\n",
396
+ "\n",
397
+ "df_young.shape, df_rest.shape"
398
+ ]
399
+ },
400
+ {
401
+ "cell_type": "code",
402
+ "execution_count": 18,
403
+ "id": "18a2d9ce",
404
+ "metadata": {},
405
+ "outputs": [],
406
+ "source": [
407
+ "df_young.to_excel(\"premiums_young_with_gr.xlsx\", index=False)\n",
408
+ "df_rest.to_excel(\"premiums_rest_with_gr.xlsx\", index=False)"
409
+ ]
410
+ }
411
+ ],
412
+ "metadata": {
413
+ "kernelspec": {
414
+ "display_name": "Python 3 (ipykernel)",
415
+ "language": "python",
416
+ "name": "python3"
417
+ },
418
+ "language_info": {
419
+ "codemirror_mode": {
420
+ "name": "ipython",
421
+ "version": 3
422
+ },
423
+ "file_extension": ".py",
424
+ "mimetype": "text/x-python",
425
+ "name": "python",
426
+ "nbconvert_exporter": "python",
427
+ "pygments_lexer": "ipython3",
428
+ "version": "3.10.11"
429
+ }
430
+ },
431
+ "nbformat": 4,
432
+ "nbformat_minor": 5
433
+ }
main.py ADDED
@@ -0,0 +1,488 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+ import uuid
4
+
5
+ # Page configuration
6
+ st.set_page_config(
7
+ page_title="HealthGuard AI: Insurance Cost Predictor",
8
+ page_icon="🏥",
9
+ layout="wide"
10
+ )
11
+
12
+ # Initialize session storage
13
+ if "chat_history" not in st.session_state:
14
+ st.session_state.chat_history = []
15
+ if "thread_id" not in st.session_state:
16
+ st.session_state.thread_id = str(uuid.uuid4())
17
+ if "analysis_done" not in st.session_state:
18
+ st.session_state.analysis_done = False
19
+ if "show_info" not in st.session_state:
20
+ st.session_state.show_info = False
21
+
22
+ # ========================= ENHANCED UI STYLING =========================
23
+ st.markdown("""
24
+ <style>
25
+ @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;700&display=swap');
26
+ * {
27
+ font-family: 'Montserrat', 'Inter', sans-serif;
28
+ }
29
+ .main {
30
+ background: linear-gradient(135deg, #212d3b 0%, #223a57 100%);
31
+ padding: 2rem 0;
32
+ }
33
+ .header-container {
34
+ background: linear-gradient(135deg, #243b55 0%, #141e30 100%);
35
+ padding: 2rem;
36
+ border-radius: 16px;
37
+ box-shadow: 0 8px 32px rgba(36, 59, 85,0.13);
38
+ margin-bottom: 2rem;
39
+ text-align: center;
40
+ }
41
+ .header-title {
42
+ color: white;
43
+ font-size: 2.5rem;
44
+ font-weight: 700;
45
+ margin: 0;
46
+ text-shadow: 2px 2px 6px rgba(20,30,48,0.2);
47
+ font-family: 'Montserrat', sans-serif;
48
+ }
49
+ .header-subtitle {
50
+ color: #aab3cf;
51
+ font-size: 1.1rem;
52
+ margin-top: 0.5rem;
53
+ font-family: 'Montserrat', sans-serif;
54
+ }
55
+ .section-card {
56
+ background: #25304b;
57
+ padding: 1.5rem;
58
+ border-radius: 12px;
59
+ box-shadow: 0 4px 8px rgba(36, 59, 85,0.12);
60
+ margin-bottom: 1.5rem;
61
+ border-left: 4px solid #27ae60;
62
+ color: #f3f4fa;
63
+ }
64
+ .section-title {
65
+ color: #f1f7fc;
66
+ font-size: 1.3rem;
67
+ font-weight: 700;
68
+ margin-bottom: 1rem;
69
+ display: flex;
70
+ align-items: center;
71
+ gap: 0.5rem;
72
+ font-family: 'Montserrat', sans-serif;
73
+ }
74
+ .info-box {
75
+ background: linear-gradient(135deg, #344667 0%, #27ae60 100%);
76
+ color: #f1f7fc;
77
+ padding: 1rem;
78
+ border-radius: 10px;
79
+ margin: 1rem 0;
80
+ border-left: 4px solid #18aad5;
81
+ animation: slideIn 0.5s ease-out;
82
+ }
83
+ @keyframes slideIn {
84
+ from { opacity: 0; transform: translateY(-10px); }
85
+ to { opacity: 1; transform: translateY(0); }
86
+ }
87
+ .metric-card {
88
+ background: linear-gradient(135deg, #27ae60 0%, #243b55 100%);
89
+ padding: 1.2rem;
90
+ border-radius: 12px;
91
+ color: #f3f4fa;
92
+ text-align: center;
93
+ box-shadow: 0 4px 15px rgba(39, 174, 96, 0.2);
94
+ transition: transform 0.3s ease;
95
+ }
96
+ .metric-card:hover {
97
+ transform: translateY(-5px);
98
+ }
99
+ .metric-value {
100
+ font-size: 2rem;
101
+ font-weight: 700;
102
+ margin: 0.5rem 0;
103
+ font-family: 'Montserrat', sans-serif;
104
+ }
105
+ .metric-label {
106
+ font-size: 0.9rem;
107
+ opacity: 0.92;
108
+ }
109
+ .result-card {
110
+ background: linear-gradient(135deg, #27ae60 0%, #2d375b 100%);
111
+ padding: 2rem;
112
+ border-radius: 16px;
113
+ color: #f4f8ff;
114
+ box-shadow: 0 8px 32px rgba(39, 174, 96, 0.10);
115
+ margin: 1.5rem 0;
116
+ }
117
+ .result-grid {
118
+ display: grid;
119
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
120
+ gap: 1.5rem;
121
+ margin-top: 1rem;
122
+ }
123
+ .result-item {
124
+ background: rgba(25,40,65,0.2);
125
+ padding: 1.5rem;
126
+ border-radius: 12px;
127
+ backdrop-filter: blur(10px);
128
+ }
129
+ .result-item-label {
130
+ font-size: 0.9rem;
131
+ opacity: 0.9;
132
+ margin-bottom: 0.5rem;
133
+ }
134
+ .result-item-value {
135
+ font-size: 1.8rem;
136
+ font-weight: 700;
137
+ }
138
+ .advisor-box {
139
+ background: linear-gradient(135deg, #27ae60 0%, #243b55 100%);
140
+ color: #f5f5fa;
141
+ padding: 1.5rem;
142
+ border-radius: 12px;
143
+ margin-top: 1.5rem;
144
+ border-left: 4px solid #18aad5;
145
+ box-shadow: 0 4px 15px rgba(39, 174, 96, 0.1);
146
+ }
147
+ .advisor-box h4 {
148
+ color: #f1f7fc;
149
+ margin-top: 0;
150
+ }
151
+ .chat-container {
152
+ background: #24304e;
153
+ color: #fff;
154
+ padding: 1.5rem;
155
+ border-radius: 12px;
156
+ box-shadow: 0 4px 6px rgba(36, 48, 78,0.12);
157
+ max-height: 400px;
158
+ overflow-y: auto;
159
+ margin-bottom: 1rem;
160
+ }
161
+ .chat-bubble-user {
162
+ background: linear-gradient(135deg, #27ae60 0%, #243b55 100%);
163
+ color: white;
164
+ padding: 12px 18px;
165
+ border-radius: 18px 18px 4px 18px;
166
+ margin: 8px 0 8px auto;
167
+ max-width: 70%;
168
+ text-align: right;
169
+ box-shadow: 0 2px 8px rgba(39, 174, 96, 0.13);
170
+ animation: slideInRight 0.3s ease-out;
171
+ font-family: 'Montserrat', sans-serif;
172
+ }
173
+ .chat-bubble-bot {
174
+ background: #20293b;
175
+ border: 2px solid #2a3d6a;
176
+ color: #ebf2f8;
177
+ padding: 12px 18px;
178
+ border-radius: 18px 18px 18px 4px;
179
+ margin: 8px auto 8px 0;
180
+ max-width: 70%;
181
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
182
+ animation: slideInLeft 0.3s ease-out;
183
+ font-family: 'Montserrat', sans-serif;
184
+ }
185
+ @keyframes slideInRight {
186
+ from { opacity: 0; transform: translateX(20px); }
187
+ to { opacity: 1; transform: translateX(0); }
188
+ }
189
+ @keyframes slideInLeft {
190
+ from { opacity: 0; transform: translateX(-20px); }
191
+ to { opacity: 1; transform: translateX(0); }
192
+ }
193
+ .stButton>button {
194
+ width: 100%;
195
+ background: linear-gradient(135deg, #27ae60 0%, #223a57 100%);
196
+ color: white;
197
+ font-weight: 600;
198
+ border: none;
199
+ border-radius: 10px;
200
+ padding: 0.8rem;
201
+ font-size: 1rem;
202
+ font-family: 'Montserrat', sans-serif;
203
+ transition: all 0.3s ease;
204
+ box-shadow: 0 4px 15px rgba(39, 174, 96, 0.13);
205
+ }
206
+ .stButton>button:hover {
207
+ transform: translateY(-2px);
208
+ box-shadow: 0 6px 20px rgba(39, 174, 96, 0.20);
209
+ }
210
+ .stNumberInput>div>div>input,
211
+ .stSelectbox>div>div>select,
212
+ .stTextInput>div>div>input {
213
+ border-radius: 8px;
214
+ border: 2px solid #233269;
215
+ padding: 0.5rem;
216
+ transition: border-color 0.3s ease;
217
+ background: #2d375b;
218
+ color: #e9ecfa;
219
+ font-family: 'Montserrat', sans-serif;
220
+ }
221
+ .stNumberInput>div>div>input:focus,
222
+ .stSelectbox>div>div>select:focus,
223
+ .stTextInput>div>div>input:focus {
224
+ border-color: #27ae60;
225
+ box-shadow: 0 0 0 3px rgba(39, 174, 96, 0.1);
226
+ }
227
+ .alert-banner {
228
+ background: linear-gradient(135deg, #233269 0%, #27ae60 100%);
229
+ color: #fff;
230
+ padding: 1rem;
231
+ border-radius: 10px;
232
+ margin: 1rem 0;
233
+ border-left: 4px solid #18aad5;
234
+ display: flex;
235
+ align-items: center;
236
+ gap: 0.5rem;
237
+ }
238
+ .chat-container::-webkit-scrollbar {
239
+ width: 8px;
240
+ }
241
+ .chat-container::-webkit-scrollbar-track {
242
+ background: #1a2336;
243
+ border-radius: 10px;
244
+ }
245
+ .chat-container::-webkit-scrollbar-thumb {
246
+ background: #27ae60;
247
+ border-radius: 10px;
248
+ }
249
+ .chat-container::-webkit-scrollbar-thumb:hover {
250
+ background: #229954;
251
+ }
252
+ </style>
253
+ """, unsafe_allow_html=True)
254
+
255
+ # ========================= HEADER =========================
256
+ st.markdown("""
257
+ <div class="header-container">
258
+ <h1 class="header-title">🏥 HealthGuard AI</h1>
259
+ <p class="header-subtitle">AI-Powered Health Insurance Cost Prediction Platform</p>
260
+ </div>
261
+ """, unsafe_allow_html=True)
262
+
263
+ # Alert Banner
264
+ st.markdown("""
265
+ <div class="alert-banner">
266
+ ⚠️ <strong>Note:</strong> First request may take up to 20 seconds (API cold start).
267
+ </div>
268
+ """, unsafe_allow_html=True)
269
+
270
+ # Info Toggle
271
+ if st.button("ℹ️ How It Works"):
272
+ st.session_state.show_info = not st.session_state.show_info
273
+
274
+ if st.session_state.show_info:
275
+ st.markdown("""
276
+ <div class="info-box">
277
+ <h4>📊 About HealthGuard AI</h4>
278
+ <p><strong>What we analyze:</strong></p>
279
+ <ul>
280
+ <li>Personal demographics and health profile</li>
281
+ <li>Lifestyle factors (smoking, BMI category)</li>
282
+ <li>Medical history and genetic risk factors</li>
283
+ <li>Financial capacity and employment status</li>
284
+ </ul>
285
+ <p><strong>Our AI provides:</strong></p>
286
+ <ul>
287
+ <li>Accurate annual premium predictions</li>
288
+ <li>Monthly payment breakdowns</li>
289
+ <li>Personalized health insurance advice</li>
290
+ <li>Interactive Q&A with AI health advisor</li>
291
+ </ul>
292
+ </div>
293
+ """, unsafe_allow_html=True)
294
+
295
+ # Categorical options
296
+ categorical_options = {
297
+ 'Gender': ['Male', 'Female'],
298
+ 'Marital Status': ['Unmarried', 'Married'],
299
+ 'BMI Category': ['Normal', 'Obesity', 'Overweight', 'Underweight'],
300
+ 'Smoking Status': ['No Smoking', 'Regular', 'Occasional'],
301
+ 'Employment Status': ['Salaried', 'Self-Employed', 'Freelancer'],
302
+ 'Region': ['Northwest', 'Southeast', 'Northeast', 'Southwest'],
303
+ 'Medical History': [
304
+ 'No Disease', 'Diabetes', 'High blood pressure', 'Diabetes & High blood pressure',
305
+ 'Thyroid', 'Heart disease', 'High blood pressure & Heart disease',
306
+ 'Diabetes & Thyroid', 'Diabetes & Heart disease'
307
+ ],
308
+ 'Insurance Plan': ['Bronze', 'Silver', 'Gold']
309
+ }
310
+
311
+ # ========================= INPUT FORM =========================
312
+ col_left, col_right = st.columns([1, 1], gap="large")
313
+
314
+ with col_left:
315
+ st.markdown('<div class="section-card">', unsafe_allow_html=True)
316
+ st.markdown('<div class="section-title">👤 Personal Information</div>', unsafe_allow_html=True)
317
+
318
+ age = st.number_input('Age', min_value=18, max_value=100, value=30, step=1)
319
+ gender = st.selectbox('Gender', categorical_options['Gender'])
320
+ marital_status = st.selectbox('Marital Status', categorical_options['Marital Status'])
321
+ number_of_dependants = st.number_input('Number of Dependants', min_value=0, max_value=7, value=2, step=1)
322
+ region = st.selectbox('Region', categorical_options['Region'])
323
+
324
+ st.markdown('</div>', unsafe_allow_html=True)
325
+
326
+ st.markdown('<div class="section-card">', unsafe_allow_html=True)
327
+ st.markdown('<div class="section-title">💼 Financial Details</div>', unsafe_allow_html=True)
328
+
329
+ income_lakhs = st.number_input('Annual Income (Lakhs)', min_value=1, max_value=200, value=10, step=1)
330
+ employment_status = st.selectbox('Employment Status', categorical_options['Employment Status'])
331
+ insurance_plan = st.selectbox('Insurance Plan', categorical_options['Insurance Plan'])
332
+
333
+ st.markdown('</div>', unsafe_allow_html=True)
334
+
335
+ with col_right:
336
+ st.markdown('<div class="section-card">', unsafe_allow_html=True)
337
+ st.markdown('<div class="section-title">🏥 Health Information</div>', unsafe_allow_html=True)
338
+
339
+ bmi_category = st.selectbox('BMI Category', categorical_options['BMI Category'])
340
+ smoking_status = st.selectbox('Smoking Status', categorical_options['Smoking Status'])
341
+ medical_history = st.selectbox('Medical History', categorical_options['Medical History'])
342
+ genetical_risk = st.number_input('Genetical Risk (1-5)', min_value=1, max_value=5, value=3, step=1)
343
+
344
+ st.markdown('</div>', unsafe_allow_html=True)
345
+
346
+ # Risk indicator
347
+ risk_color = "#e74c3c" if genetical_risk >= 4 else "#f39c12" if genetical_risk == 3 else "#27ae60"
348
+ st.markdown(f"""
349
+ <div class="metric-card" style="background: linear-gradient(135deg, {risk_color} 0%, #243b55 100%);">
350
+ <div class="metric-label">Genetic Risk Level</div>
351
+ <div class="metric-value">{genetical_risk}/5</div>
352
+ </div>
353
+ """, unsafe_allow_html=True)
354
+
355
+ # Prepare input dictionary
356
+ input_dict = {
357
+ 'age': age,
358
+ 'number_of_dependants': number_of_dependants,
359
+ 'income_lakhs': income_lakhs,
360
+ 'genetical_risk': genetical_risk,
361
+ 'insurance_plan': insurance_plan,
362
+ 'employment_status': employment_status,
363
+ 'gender': gender.lower(),
364
+ 'marital_status': marital_status.lower(),
365
+ 'bmi_category': bmi_category,
366
+ 'smoking_status': smoking_status,
367
+ 'region': region,
368
+ 'medical_history': medical_history
369
+ }
370
+
371
+ # ========================= PREDICTION BUTTON =========================
372
+ st.markdown("<br>", unsafe_allow_html=True)
373
+
374
+ if st.button("💰 Calculate Insurance Premium", use_container_width=True):
375
+ API_URL = st.secrets["API_URL"]
376
+
377
+ with st.spinner('🤖 Calculating your premium...'):
378
+ try:
379
+ response = requests.post(API_URL, json=input_dict, timeout=30)
380
+
381
+ if response.status_code == 200:
382
+ result = response.json()
383
+ yearly = result['yearly']
384
+ monthly = result['monthly']
385
+ advice = result['advice']
386
+
387
+ # Display Results
388
+ st.markdown('<div class="result-card">', unsafe_allow_html=True)
389
+ st.markdown('<h3 style="margin-top:0; color:white;">📊 Premium Calculation Results</h3>', unsafe_allow_html=True)
390
+ st.markdown(f"""
391
+ <div class="result-grid">
392
+ <div class="result-item">
393
+ <div class="result-item-label">Annual Premium</div>
394
+ <div class="result-item-value">₹ {yearly:,.2f}</div>
395
+ </div>
396
+ <div class="result-item">
397
+ <div class="result-item-label">Monthly Premium</div>
398
+ <div class="result-item-value">₹ {monthly:,.2f}</div>
399
+ </div>
400
+ <div class="result-item">
401
+ <div class="result-item-label">Insurance Plan</div>
402
+ <div class="result-item-value">{insurance_plan}</div>
403
+ </div>
404
+ </div>
405
+ """, unsafe_allow_html=True)
406
+ st.markdown('</div>', unsafe_allow_html=True)
407
+
408
+ # Display advice
409
+ st.markdown(f"""
410
+ <div class="advisor-box">
411
+ <h4>💡 AI Health Advisor Insights</h4>
412
+ <p>{advice}</p>
413
+ </div>
414
+ """, unsafe_allow_html=True)
415
+
416
+ # Store results in session state
417
+ st.session_state.yearly_cost = yearly
418
+ st.session_state.monthly_cost = monthly
419
+ st.session_state.ai_summary = advice
420
+ st.session_state.analysis_done = True
421
+
422
+ st.success("✅ Calculation complete! You can now chat with our AI assistant below.")
423
+ else:
424
+ st.error(f"❌ API Error: {response.status_code}")
425
+
426
+ except requests.exceptions.Timeout:
427
+ st.error("⏱️ Request timed out. Please try again.")
428
+ except Exception as e:
429
+ st.error(f"❌ Connection error: {str(e)}")
430
+
431
+ # ========================= CHATBOT =========================
432
+ if st.session_state.analysis_done:
433
+ st.markdown("<br><br>", unsafe_allow_html=True)
434
+ st.markdown('<div class="section-card">', unsafe_allow_html=True)
435
+ st.markdown('<div class="section-title">💬 Interactive Health Insurance Assistant</div>', unsafe_allow_html=True)
436
+
437
+ if st.session_state.chat_history:
438
+ st.markdown('<div class="chat-container">', unsafe_allow_html=True)
439
+ for role, msg in st.session_state.chat_history:
440
+ bubble = "chat-bubble-user" if role == "user" else "chat-bubble-bot"
441
+ prefix = "You: " if role == "user" else "🤖 Assistant: "
442
+ st.markdown(f"<div class='{bubble}'><strong>{prefix}</strong>{msg}</div>", unsafe_allow_html=True)
443
+ st.markdown('</div>', unsafe_allow_html=True)
444
+
445
+ user_query = st.text_input("Ask a question about your insurance:", placeholder="e.g., How can I reduce my premium costs?")
446
+
447
+ col_send, col_clear = st.columns([3, 1])
448
+ with col_send:
449
+ send_button = st.button("📤 Send Message", use_container_width=True)
450
+ with col_clear:
451
+ if st.button("🗑️ Clear Chat", use_container_width=True):
452
+ st.session_state.chat_history = []
453
+ st.session_state.thread_id = str(uuid.uuid4())
454
+ st.experimental_rerun()
455
+
456
+ if send_button and user_query.strip():
457
+ CHAT_URL = st.secrets["CHAT_URL"]
458
+ payload = {
459
+ "thread_id": st.session_state.thread_id,
460
+ "message": user_query,
461
+ "yearly_cost": st.session_state.yearly_cost,
462
+ "monthly_cost": st.session_state.monthly_cost,
463
+ "ai_summary": st.session_state.ai_summary
464
+ }
465
+
466
+ with st.spinner("🤖 Thinking..."):
467
+ try:
468
+ r = requests.post(CHAT_URL, json=payload, timeout=30)
469
+ if r.status_code == 200:
470
+ reply = r.json()["response"]
471
+ st.session_state.chat_history.append(("user", user_query))
472
+ st.session_state.chat_history.append(("bot", reply))
473
+ st.experimental_rerun()
474
+ else:
475
+ st.error(f"❌ Chat server error: {r.status_code}")
476
+ except Exception as e:
477
+ st.error(f"❌ Chat failed: {e}")
478
+
479
+ st.markdown('</div>', unsafe_allow_html=True)
480
+
481
+ # Footer
482
+ st.markdown("<br><br>", unsafe_allow_html=True)
483
+ st.markdown("""
484
+ <div style='text-align: center; color: #7f8c8d; font-size: 0.9rem;'>
485
+ <p>🏥 HealthGuard AI © 2025 | Powered by Advanced Machine Learning</p>
486
+ <p style='font-size: 0.8rem;'>For demonstration purposes only. Not medical or financial advice.</p>
487
+ </div>
488
+ """, unsafe_allow_html=True)
ml_premium_prediction.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
ml_premium_prediction_rest.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
ml_premium_prediction_rest_with_gr.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
ml_premium_prediction_young.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
ml_premium_prediction_young_with_gr.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
one_shot_bot.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_groq import ChatGroq
2
+ from langchain_core.prompts import PromptTemplate
3
+ import os
4
+ from dotenv import load_dotenv
5
+ load_dotenv()
6
+
7
+ llm = ChatGroq(model="openai/gpt-oss-20b", api_key=os.getenv("GROQ_API_KEY"), streaming=True)
8
+
9
+ prompt = PromptTemplate.from_template("""
10
+ You are a friendly but professional insurance assistant.
11
+
12
+ Write a short, conversational explanation of the premium.
13
+ Keep it human, warm, and simple — avoid sounding like a report or policy document.
14
+
15
+ Response Format:
16
+ 1) One-line casual greeting.
17
+ 2) State the premium clearly.
18
+ 3) A short, natural explanation (2–4 sentences max) of why the cost is what it is, based on the user's data. Mention only the most meaningful factors, not a full list.
19
+ 4) Give 1–2 helpful suggestions (upgrade recommendation, lifestyle tip, or policy fit).
20
+ 5) End with a short invitation to continue with the chatbot, like know more about healthcare insourence planes and their cost
21
+
22
+ Tone rules:
23
+ - No long paragraphs.
24
+ - No medical diagnosis or guarantees.
25
+ - Avoid corporate insurance jargon.
26
+ - Keep under 10 total sentences.
27
+
28
+ User + Model Data:
29
+ yearly_premium: ₹{yearly_premium}
30
+ monthly_premium : ₹{monthly_premium}
31
+ Age: {age}, Gender: {gender}, Marital Status: {marital_status}, Dependents: {dependents}
32
+ BMI: {bmi_category}, Smoking: {smoking_status}, Medical History: {medical_history}, Genetics: Risk {genetic_risk}
33
+ Region: {region}, Income: {income_lakhs} lakhs, Employment: {employment_status}, Plan: {insurance_plan}
34
+
35
+ Now generate the response.
36
+
37
+
38
+ """)
39
+
40
+ def generate_advice(yearly_premium, monthly_premium, age, gender, marital_status, dependents, bmi_category, smoking_status,
41
+ medical_history, genetic_risk, region, income_lakhs, employment_status, insurance_plan):
42
+ formatted_prompt = prompt.format(
43
+ yearly_premium=yearly_premium,
44
+ monthly_premium=monthly_premium,
45
+ age=age,
46
+ gender=gender,
47
+ marital_status=marital_status,
48
+ dependents=dependents,
49
+ bmi_category=bmi_category,
50
+ smoking_status=smoking_status,
51
+ medical_history=medical_history,
52
+ genetic_risk=genetic_risk,
53
+ region=region,
54
+ income_lakhs=income_lakhs,
55
+ employment_status=employment_status,
56
+ insurance_plan=insurance_plan
57
+ )
58
+
59
+ result = llm.invoke(formatted_prompt)
60
+ return result.content
61
+
62
+ """print(generate_advice(
63
+ predicted_premium=7621,
64
+ age=30,
65
+ gender="Male",
66
+ marital_status="Unmarried",
67
+ dependents=2,
68
+ bmi_category="Normal",
69
+ smoking_status="No Smoking",
70
+ medical_history="No Disease",
71
+ genetic_risk=3,
72
+ region="Northwest",
73
+ income_lakhs=10,
74
+ employment_status="Salaried",
75
+ insurance_plan="Bronze"))"""
prediction_helper.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import joblib
3
+
4
+ model_young = joblib.load("artifacts/model_young.joblib")
5
+ model_rest = joblib.load("artifacts/model_rest.joblib")
6
+ scaler_young = joblib.load("artifacts/scaler_young.joblib")
7
+ scaler_rest = joblib.load("artifacts/scaler_rest.joblib")
8
+
9
+ def calculate_normalized_risk(medical_history):
10
+ risk_scores = {
11
+ "diabetes": 6,
12
+ "heart disease": 8,
13
+ "high blood pressure": 6,
14
+ "thyroid": 5,
15
+ "no disease": 0,
16
+ "none": 0
17
+ }
18
+ diseases = medical_history.lower().split(" & ")
19
+ total_risk_score = sum(risk_scores.get(disease, 0) for disease in diseases)
20
+
21
+ max_score = 14
22
+ min_score = 0
23
+ normalized_risk_score = (total_risk_score - min_score) / (max_score - min_score)
24
+ return normalized_risk_score
25
+ def preprocess_input(input_dict):
26
+
27
+ expected_columns = [
28
+ 'age', 'number_of_dependants', 'income_lakhs', 'insurance_plan', 'genetical_risk', 'normalized_risk_score',
29
+ 'gender_Male', 'region_Northwest', 'region_Southeast', 'region_Southwest', 'marital_status_Unmarried',
30
+ 'bmi_category_Obesity', 'bmi_category_Overweight', 'bmi_category_Underweight', 'smoking_status_Occasional',
31
+ 'smoking_status_Regular', 'employment_status_Salaried', 'employment_status_Self-Employed'
32
+ ]
33
+
34
+ insurance_plan_encoding = {'Bronze': 1, 'Silver': 2, 'Gold': 3}
35
+
36
+ df = pd.DataFrame(0, columns=expected_columns, index=[0])
37
+
38
+
39
+ for key, value in input_dict.items():
40
+ if key == 'Gender' and value == 'Male':
41
+ df['gender_Male'] = 1
42
+ elif key == 'Region':
43
+ if value == 'Northwest':
44
+ df['region_Northwest'] = 1
45
+ elif value == 'Southeast':
46
+ df['region_Southeast'] = 1
47
+ elif value == 'Southwest':
48
+ df['region_Southwest'] = 1
49
+ elif key == 'Marital Status' and value == 'Unmarried':
50
+ df['marital_status_Unmarried'] = 1
51
+ elif key == 'BMI Category':
52
+ if value == 'Obesity':
53
+ df['bmi_category_Obesity'] = 1
54
+ elif value == 'Overweight':
55
+ df['bmi_category_Overweight'] = 1
56
+ elif value == 'Underweight':
57
+ df['bmi_category_Underweight'] = 1
58
+ elif key == 'Smoking Status':
59
+ if value == 'Occasional':
60
+ df['smoking_status_Occasional'] = 1
61
+ elif value == 'Regular':
62
+ df['smoking_status_Regular'] = 1
63
+ elif key == 'Employment Status':
64
+ if value == 'Salaried':
65
+ df['employment_status_Salaried'] = 1
66
+ elif value == 'Self-Employed':
67
+ df['employment_status_Self-Employed'] = 1
68
+ elif key == 'Insurance Plan':
69
+ df['insurance_plan'] = insurance_plan_encoding.get(value, 1)
70
+ elif key == 'Age':
71
+ df['age'] = value
72
+ elif key == 'Number of Dependants':
73
+ df['number_of_dependants'] = value
74
+ elif key == 'Income in Lakhs':
75
+ df['income_lakhs'] = value
76
+ elif key == "Genetical Risk":
77
+ df['genetical_risk'] = value
78
+
79
+
80
+ df['normalized_risk_score'] = calculate_normalized_risk(input_dict['Medical History'])
81
+ df = handle_scaling(input_dict['Age'], df)
82
+
83
+ return df
84
+
85
+ def handle_scaling(age, df):
86
+
87
+ if age <= 25:
88
+ scaler_object = scaler_young
89
+ else:
90
+ scaler_object = scaler_rest
91
+
92
+ cols_to_scale = scaler_object['cols_to_scale']
93
+ scaler = scaler_object['scaler']
94
+
95
+ df['income_level'] = None
96
+ df[cols_to_scale] = scaler.transform(df[cols_to_scale])
97
+
98
+ df.drop('income_level', axis='columns', inplace=True)
99
+
100
+ return df
101
+
102
+ def predict(input_dict):
103
+ input_df = preprocess_input(input_dict)
104
+
105
+ if input_dict['Age'] <= 25:
106
+ prediction = model_young.predict(input_df)
107
+ else:
108
+ prediction = model_rest.predict(input_df)
109
+
110
+ return int(prediction[0])
requirements.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ joblib==1.3.2
2
+ pandas==2.0.2
3
+ streamlit==1.22.0
4
+ numpy==1.25.0
5
+ scikit-learn==1.3.0
6
+ xgboost==2.0.3
7
+ fastapi
8
+ uvicorn
9
+ pydantic
10
+ langchain
11
+ langchain-community
12
+ langchain-groq
13
+ langgraph
14
+