SURESHBEEKHANI commited on
Commit
52d98a1
·
verified ·
1 Parent(s): db13a96

Upload 33 files

Browse files
backend/Dockerfile ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # docker/Dockerfile
2
+
3
+ FROM python:3.11-slim
4
+
5
+ ENV USER=uv-example-user \
6
+ PYTHONDONTWRITEBYTECODE=1 \
7
+ PYTHONUNBUFFERED=1 \
8
+ UV_PROJECT_ENVIRONMENT=/usr/local
9
+
10
+ # Install required packages and dependencies
11
+ RUN apt-get update && apt-get install --no-install-recommends -y \
12
+ curl \
13
+ && apt-get clean \
14
+ && rm -rf /var/lib/apt/lists/* \
15
+ && useradd -m -s /bin/bash $USER
16
+
17
+ # Set the working directory
18
+ ENV APP_DIR=/home/$USER/src
19
+ WORKDIR $APP_DIR
20
+
21
+ # Copy application files
22
+ COPY . $APP_DIR
23
+
24
+ # Install Python dependencies
25
+ RUN pip install --no-cache-dir -r requirements.txt
26
+
27
+ # Set Python path
28
+ ENV PYTHONPATH=$APP_DIR
29
+
30
+ # Change ownership of the application directory
31
+ RUN chown -R "$USER":"$USER" $APP_DIR
32
+ USER $USER
33
+
34
+ # Command to run the FastAPI app
35
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
backend/__pycache__/app.cpython-312.pyc ADDED
Binary file (1.06 kB). View file
 
backend/app.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from routes.home import router as home_router
3
+ from routes.predict import router as predict_router
4
+ from routes.auth import router as auth_router
5
+ from database.database import engine, Base
6
+ import uvicorn
7
+
8
+ Base.metadata.create_all(bind=engine)
9
+
10
+ app = FastAPI(title="Insurance Premium Prediction API with Auth")
11
+
12
+ # Include routers
13
+ app.include_router(home_router, prefix="/api", tags=["General"])
14
+ app.include_router(predict_router, prefix="/api", tags=["Prediction"])
15
+ app.include_router(auth_router, prefix="/api/auth", tags=["Authentication"])
16
+
17
+ # Add a root endpoint
18
+ @app.get("/")
19
+ def read_root():
20
+ return {"message": "Welcome to the Insurance Premium Prediction API"}
21
+
22
+ if __name__ == "__main__":
23
+ """
24
+ Run the FastAPI app using uvicorn.
25
+ """
26
+ uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)
27
+ # To run the app, use the command: uvicorn app:app --reload
backend/config/__pycache__/city_tier.cpython-312.pyc ADDED
Binary file (730 Bytes). View file
 
backend/config/city_tier.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ tier_1_cities = ["Mumbai", "Delhi", "Bangalore", "Chennai", "Kolkata", "Hyderabad", "Pune"]
2
+ tier_2_cities = [
3
+ "Jaipur", "Chandigarh", "Indore", "Lucknow", "Patna", "Ranchi", "Visakhapatnam", "Coimbatore",
4
+ "Bhopal", "Nagpur", "Vadodara", "Surat", "Rajkot", "Jodhpur", "Raipur", "Amritsar", "Varanasi",
5
+ "Agra", "Dehradun", "Mysore", "Jabalpur", "Guwahati", "Thiruvananthapuram", "Ludhiana", "Nashik",
6
+ "Allahabad", "Udaipur", "Aurangabad", "Hubli", "Belgaum", "Salem", "Vijayawada", "Tiruchirappalli",
7
+ "Bhavnagar", "Gwalior", "Dhanbad", "Bareilly", "Aligarh", "Gaya", "Kozhikode", "Warangal",
8
+ "Kolhapur", "Bilaspur", "Jalandhar", "Noida", "Guntur", "Asansol", "Siliguri"
9
+ ]
backend/database/__pycache__/database.cpython-312.pyc ADDED
Binary file (565 Bytes). View file
 
backend/database/database.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # database.py
2
+ from sqlalchemy import create_engine
3
+ from sqlalchemy.ext.declarative import declarative_base
4
+ from sqlalchemy.orm import sessionmaker
5
+
6
+ # Replace with your actual database URL
7
+ DATABASE_URL = "sqlite:///./insurance.db"
8
+
9
+ engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
10
+ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
11
+ Base = declarative_base()
backend/insurance.db ADDED
Binary file (16.4 kB). View file
 
backend/model/__pycache__/predict.cpython-312.pyc ADDED
Binary file (1.4 kB). View file
 
backend/model/model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:99679b393250929802df797963a88de637f6d6f8304277d813f730bfdf424ab9
3
+ size 473714
backend/model/predict.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pickle
2
+ import pandas as pd
3
+
4
+ # import the ml model
5
+ with open('model/model.pkl', 'rb') as f:
6
+ model = pickle.load(f)
7
+
8
+ # MLFlow
9
+ MODEL_VERSION = '1.0.0'
10
+
11
+ # Get class labels from model (important for matching probabilities to class names)
12
+ class_labels = model.classes_.tolist()
13
+
14
+ def predict_output(user_input: dict):
15
+
16
+ df = pd.DataFrame([user_input])
17
+
18
+ # Predict the class
19
+ predicted_class = model.predict(df)[0]
20
+
21
+ # Get probabilities for all classes
22
+ probabilities = model.predict_proba(df)[0]
23
+ confidence = max(probabilities)
24
+
25
+ # Create mapping: {class_name: probability}
26
+ class_probs = dict(zip(class_labels, map(lambda p: round(p, 4), probabilities)))
27
+
28
+ return {
29
+ "predicted_category": predicted_class,
30
+ "confidence": round(confidence, 4),
31
+ "class_probabilities": class_probs
32
+ }
backend/models/__pycache__/user.cpython-312.pyc ADDED
Binary file (646 Bytes). View file
 
backend/models/__pycache__/utils.cpython-312.pyc ADDED
Binary file (1.39 kB). View file
 
backend/models/user.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # models/user.py
2
+ from sqlalchemy import Column, Integer, String
3
+ from database.database import Base
4
+
5
+ class User(Base):
6
+ __tablename__ = "users"
7
+
8
+ id = Column(Integer, primary_key=True, index=True)
9
+ username = Column(String, unique=True, index=True)
10
+ password = Column(String)
backend/models/utils.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # utils.py
2
+ from passlib.context import CryptContext
3
+ from jose import jwt
4
+ from datetime import datetime, timedelta
5
+
6
+ SECRET_KEY = "mysecret"
7
+ ALGORITHM = "HS256"
8
+ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
9
+
10
+ def hash_password(password: str):
11
+ return pwd_context.hash(password)
12
+
13
+ def verify_password(plain: str, hashed: str):
14
+ return pwd_context.verify(plain, hashed)
15
+
16
+ def create_token(data: dict, expires_minutes: int = 60):
17
+ data = data.copy()
18
+ expire = datetime.utcnow() + timedelta(minutes=expires_minutes)
19
+ data.update({"exp": expire})
20
+ return jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM)
backend/requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ sqlalchemy
4
+ pydantic
5
+ requests
6
+ passlib[bcrypt]
7
+ pandas
8
+ scikit-learn
backend/routes/__pycache__/auth.cpython-312.pyc ADDED
Binary file (2.61 kB). View file
 
backend/routes/__pycache__/home.cpython-312.pyc ADDED
Binary file (884 Bytes). View file
 
backend/routes/__pycache__/predict.cpython-312.pyc ADDED
Binary file (1.47 kB). View file
 
backend/routes/auth.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # routes/auth.py
2
+ from fastapi import APIRouter, Depends, HTTPException
3
+ from sqlalchemy.orm import Session
4
+ from models.user import User
5
+ from database.database import SessionLocal
6
+ from schema.signloginRequest import SignupRequest, LoginRequest
7
+ from passlib.context import CryptContext
8
+
9
+ router = APIRouter()
10
+
11
+ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
12
+
13
+ # Dependency to get DB session
14
+ def get_db():
15
+ db = SessionLocal()
16
+ try:
17
+ yield db
18
+ finally:
19
+ db.close()
20
+
21
+
22
+ @router.post("/signup")
23
+ def signup(request: SignupRequest, db: Session = Depends(get_db)):
24
+ if db.query(User).filter(User.username == request.username).first():
25
+ raise HTTPException(status_code=400, detail="Username already exists")
26
+ hashed_password = pwd_context.hash(request.password)
27
+ user = User(username=request.username, password=hashed_password)
28
+ db.add(user)
29
+ db.commit()
30
+ db.refresh(user)
31
+ return {"message": "User created successfully"}
32
+
33
+ @router.post("/login")
34
+ def login(request: LoginRequest, db: Session = Depends(get_db)):
35
+ user = db.query(User).filter(User.username == request.username).first()
36
+ if not user or not pwd_context.verify(request.password, user.password):
37
+ raise HTTPException(status_code=401, detail="Invalid credentials")
38
+ return {"message": "Login successful"}
backend/routes/home.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # routes/home.py
2
+ from fastapi import APIRouter
3
+ from model.predict import model, MODEL_VERSION
4
+
5
+ # Create router
6
+ router = APIRouter()
7
+
8
+ @router.get("/")
9
+ def home():
10
+ """
11
+ Human-readable welcome endpoint.
12
+ """
13
+ return {"message": "Insurance Premium Prediction API"}
14
+
15
+ @router.get("/health")
16
+ def health_check():
17
+ """
18
+ Machine-readable health check endpoint.
19
+ """
20
+ return {
21
+ "status": "OK",
22
+ "version": MODEL_VERSION,
23
+ "model_loaded": model is not None
24
+ }
backend/routes/predict.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # routes/predict.py
2
+ from fastapi import APIRouter
3
+ from fastapi.responses import JSONResponse
4
+ from pydantic import BaseModel
5
+ import pandas as pd
6
+ import pickle
7
+ from schema.user_input import UserInput
8
+ from schema.prediction_response import PredictionResponse
9
+ from model.predict import predict_output
10
+
11
+ # Create router
12
+ router = APIRouter()
13
+
14
+ @router.post("/predict", response_model=PredictionResponse)
15
+ def predict_premium(data: UserInput):
16
+ """
17
+ Predict insurance premium based on user input.
18
+ """
19
+ user_input = {
20
+ "bmi": data.bmi,
21
+ "age_group": data.age_group,
22
+ "lifestyle_risk": data.lifestyle_risk,
23
+ "city_tier": data.city_tier,
24
+ "income_lpa": data.income_lpa,
25
+ "occupation": data.occupation
26
+ }
27
+
28
+ try:
29
+ prediction = predict_output(user_input)
30
+ return JSONResponse(status_code=200, content={"response": prediction})
31
+ except Exception as e:
32
+ return JSONResponse(status_code=500, content={"error": str(e)})
33
+
backend/schema/__pycache__/prediction_response.cpython-312.pyc ADDED
Binary file (1.01 kB). View file
 
backend/schema/__pycache__/signloginRequest.cpython-312.pyc ADDED
Binary file (627 Bytes). View file
 
backend/schema/__pycache__/user_input.cpython-312.pyc ADDED
Binary file (3.49 kB). View file
 
backend/schema/prediction_response.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, Field
2
+ from typing import Dict
3
+
4
+ class PredictionResponse(BaseModel):
5
+ predicted_category: str = Field(
6
+ ...,
7
+ description="The predicted insurance premium category",
8
+ example="High"
9
+ )
10
+ confidence: float = Field(
11
+ ...,
12
+ description="Model's confidence score for the predicted class (range: 0 to 1)",
13
+ example=0.8432
14
+ )
15
+ class_probabilities: Dict[str, float] = Field(
16
+ ...,
17
+ description="Probability distribution across all possible classes",
18
+ example={"Low": 0.01, "Medium": 0.15, "High": 0.84}
19
+ )
backend/schema/signloginRequest.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+
3
+ # Pydantic models for request validation
4
+ class SignupRequest(BaseModel):
5
+ username: str
6
+ password: str
7
+
8
+ class LoginRequest(BaseModel):
9
+ username: str
10
+ password: str
backend/schema/user_input.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, Field, computed_field, field_validator
2
+ from typing import Literal, Annotated
3
+ from config.city_tier import tier_1_cities, tier_2_cities
4
+
5
+
6
+ # pydantic model to validate incoming data
7
+ class UserInput(BaseModel):
8
+
9
+ age: Annotated[int, Field(..., gt=0, lt=120, description='Age of the user')]
10
+ weight: Annotated[float, Field(..., gt=0, description='Weight of the user')]
11
+ height: Annotated[float, Field(..., gt=0, lt=2.5, description='Height of the user')]
12
+ income_lpa: Annotated[float, Field(..., gt=0, description='Annual salary of the user in lpa')]
13
+ smoker: Annotated[bool, Field(..., description='Is user a smoker')]
14
+ city: Annotated[str, Field(..., description='The city that the user belongs to')]
15
+ occupation: Annotated[Literal['retired', 'freelancer', 'student', 'government_job',
16
+ 'business_owner', 'unemployed', 'private_job'], Field(..., description='Occupation of the user')]
17
+
18
+ @field_validator('city')
19
+ @classmethod
20
+ def normalize_city(cls, v: str) -> str:
21
+ v = v.strip().title()
22
+ return v
23
+
24
+ @computed_field
25
+ @property
26
+ def bmi(self) -> float:
27
+ return self.weight/(self.height**2)
28
+
29
+ @computed_field
30
+ @property
31
+ def lifestyle_risk(self) -> str:
32
+ if self.smoker and self.bmi > 30:
33
+ return "high"
34
+ elif self.smoker or self.bmi > 27:
35
+ return "medium"
36
+ else:
37
+ return "low"
38
+
39
+ @computed_field
40
+ @property
41
+ def age_group(self) -> str:
42
+ if self.age < 25:
43
+ return "young"
44
+ elif self.age < 45:
45
+ return "adult"
46
+ elif self.age < 60:
47
+ return "middle_aged"
48
+ return "senior"
49
+
50
+ @computed_field
51
+ @property
52
+ def city_tier(self) -> int:
53
+ if self.city in tier_1_cities:
54
+ return 1
55
+ elif self.city in tier_2_cities:
56
+ return 2
57
+ else:
58
+ return 3
59
+ # Pydantic model for input validation
60
+ class PredictionInput(BaseModel):
61
+ age: int
62
+ weight: float
63
+ height: float
64
+ income_lpa: float
65
+ smoker: bool
66
+ city: str
67
+ occupation: str
docker-compose.yml ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: "3.9"
2
+
3
+ services:
4
+ backend:
5
+ build:
6
+ context: ./backend
7
+ dockerfile: Dockerfile
8
+ container_name: insurance-backend
9
+ ports:
10
+ - "8000:8000"
11
+ environment:
12
+ - PYTHONUNBUFFERED=1
13
+ volumes:
14
+ - ./backend:/home/uv-example-user/src
15
+ command: ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
16
+
17
+ frontend:
18
+ build:
19
+ context: ./frontend
20
+ dockerfile: Dockerfile
21
+ container_name: insurance-frontend
22
+ ports:
23
+ - "8501:8501"
24
+ environment:
25
+ - STREAMLIT_SERVER_PORT=8501
26
+ volumes:
27
+ - ./frontend:/app
28
+ command: ["streamlit", "run", "frontend.py", "--server.port=8501", "--server.address=0.0.0.0"]
frontend/Dockerfile ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # filepath: d:\Insurance Premium Predictor\frontend\Dockerfile
2
+ FROM python:3.11-slim
3
+
4
+ # Install required packages
5
+ RUN apt-get update && apt-get install --no-install-recommends -y \
6
+ curl \
7
+ && apt-get clean \
8
+ && rm -rf /var/lib/apt/lists/*
9
+
10
+ # Set the working directory
11
+ WORKDIR /app
12
+
13
+ # Copy application files
14
+ COPY . /app
15
+
16
+ # Upgrade pip and install Python dependencies
17
+ RUN pip install --upgrade pip && pip install --no-cache-dir -r requirements.txt
18
+
19
+ # Command to run the Streamlit app
20
+ CMD ["streamlit", "run", "frontend.py", "--server.port=8501", "--server.address=0.0.0.0"]
frontend/__pycache__/app.cpython-312.pyc ADDED
Binary file (7.34 kB). View file
 
frontend/frontend.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+
4
+ # Update API_URL to use the backend service name
5
+ API_URL = "http://127.0.0.1:8000"
6
+ st.set_page_config(page_title="Insurance Premium Predictor", layout="centered")
7
+
8
+ # Resize title and subtitle
9
+ st.markdown("<h1 style='text-align: center; font-size: 36px;'>Insurance Premium Category Predictor</h1>", unsafe_allow_html=True)
10
+ st.markdown("<h3 style='text-align: center; font-size: 20px;'>Enter your details below to predict your insurance premium category:</h3>", unsafe_allow_html=True)
11
+
12
+ # Session state to track login status
13
+ if "logged_in" not in st.session_state:
14
+ st.session_state.logged_in = False
15
+
16
+ # Sidebar for Authentication
17
+ with st.sidebar:
18
+ st.markdown("## Authentication")
19
+ auth_mode = st.selectbox("Choose an option", ["Login", "Signup"], help="Select whether to log in or sign up.")
20
+
21
+ if auth_mode == "Login":
22
+ st.markdown("### Login")
23
+ login_username = st.text_input("Username", key="login_username", help="Enter your username.")
24
+ login_password = st.text_input("Password", type="password", key="login_password", help="Enter your password.")
25
+ if st.button("Login"):
26
+ login_data = {"username": login_username, "password": login_password}
27
+ try:
28
+ with st.spinner("Logging in..."):
29
+ response = requests.post(API_URL + "/api/auth/login", json=login_data, timeout=10)
30
+ response.raise_for_status()
31
+ st.success("Login successful!")
32
+ st.session_state.logged_in = True # Set login status to True
33
+ except requests.exceptions.HTTPError as e:
34
+ st.error(f"Login failed: {response.json().get('detail', str(e))}")
35
+ except requests.exceptions.RequestException as e:
36
+ st.error(f"An error occurred: {e}")
37
+
38
+ elif auth_mode == "Signup":
39
+ st.markdown("### Signup")
40
+ signup_username = st.text_input("Signup Username", key="signup_username", help="Enter a unique username.")
41
+ signup_password = st.text_input("Signup Password", type="password", key="signup_password", help="Enter a secure password.")
42
+ if st.button("Signup"):
43
+ signup_data = {"username": signup_username, "password": signup_password}
44
+ try:
45
+ with st.spinner("Creating account..."):
46
+ response = requests.post(API_URL + "/api/auth/signup", json=signup_data, timeout=10)
47
+ response.raise_for_status()
48
+ st.success("Account created successfully! You can now log in.")
49
+ except requests.exceptions.HTTPError as e:
50
+ st.error(f"Signup failed: {response.json().get('detail', str(e))}")
51
+ except requests.exceptions.RequestException as e:
52
+ st.error(f"An error occurred: {e}")
53
+
54
+ # Show Prediction Section only if logged in
55
+ if st.session_state.logged_in:
56
+ # Display all input fields in a single column
57
+ age = st.number_input("Age", min_value=1, max_value=119, value=30, help="Enter your age in years.")
58
+ weight = st.number_input("Weight (kg)", min_value=1.0, value=65.0, help="Enter your weight in kilograms.")
59
+ height = st.number_input("Height (m)", min_value=0.5, max_value=2.5, value=1.7, help="Enter your height in meters.")
60
+ income_lpa = st.number_input("Annual Income (LPA)", min_value=0.1, value=10.0, help="Enter your annual income in lakhs per annum.")
61
+ smoker = st.selectbox("Are you a smoker?", options=["Yes", "No"], help="Select 'Yes' if you are a smoker, otherwise 'No'.")
62
+ city = st.text_input("City", value="Mumbai", help="Enter the city you reside in.")
63
+ occupation = st.selectbox(
64
+ "Occupation",
65
+ ['retired', 'freelancer', 'student', 'government_job', 'business_owner', 'unemployed', 'private_job'],
66
+ help="Select your occupation from the dropdown."
67
+ )
68
+
69
+ # Submit button for Prediction
70
+ if st.button("Predict Premium Category"):
71
+ input_data = {
72
+ "age": age,
73
+ "weight": weight,
74
+ "height": height,
75
+ "income_lpa": income_lpa,
76
+ "smoker": smoker.lower() == "yes",
77
+ "city": city,
78
+ "occupation": occupation
79
+ }
80
+
81
+ try:
82
+ with st.spinner("Predicting..."):
83
+ # Increased timeout to 30 seconds
84
+ response = requests.post(API_URL + "/api/predict", json=input_data, timeout=30)
85
+ response.raise_for_status() # Raise HTTPError for bad responses (4xx and 5xx)
86
+
87
+ result = response.json()
88
+ if "response" in result:
89
+ prediction = result["response"]
90
+ st.success(f"Predicted Insurance Premium Category: **{prediction['predicted_category']}**")
91
+ st.markdown(f"**Confidence:** {prediction['confidence']:.2f}")
92
+ st.markdown("### Class Probabilities:")
93
+ st.json(prediction["class_probabilities"])
94
+ else:
95
+ st.error("Unexpected response format from the API.")
96
+ st.json(result)
97
+
98
+ except requests.exceptions.ConnectionError:
99
+ st.error("❌ Could not connect to the FastAPI server. Please ensure it is running.")
100
+ except requests.exceptions.Timeout:
101
+ st.error("⏳ The request timed out. Please try again later.")
102
+ except requests.exceptions.RequestException as e:
103
+ st.error(f"⚠️ An error occurred: {e}")
104
+ else:
105
+ st.warning("Please log in to access the prediction feature.")
frontend/requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ streamlit==1.45.1
2
+ pandas
3
+ requests
4
+ altair==5.5.0
5
+ numpy
6
+ python-dateutil
7
+ pytz