Upload 19 files
Browse files- README.md +21 -14
- requirements.txt +2 -0
- thicc/.DS_Store +0 -0
- thicc/ai_logic/intent_parser.py +25 -0
- thicc/app.py +65 -0
- thicc/data/.DS_Store +0 -0
- thicc/data/data_loader.py +31 -0
- thicc/data/hospitals/cedars_sinai_medical_center_data.csv +8 -0
- thicc/data/hospitals/cleveland_clinic_data.csv +6 -0
- thicc/data/hospitals/houston_methodist_hospital_data.csv +8 -0
- thicc/data/hospitals/johns_hopkins_hospital_data.csv +8 -0
- thicc/data/hospitals/massachusetts_general_hospital_data.csv +8 -0
- thicc/data/hospitals/mayo_clinic_data.csv +8 -0
- thicc/data/hospitals/newyork_presbyterian_hospital_data.csv +8 -0
- thicc/data/hospitals/northwestern_memorial_hospital_data.csv +8 -0
- thicc/data/hospitals/ucla_medical_center_data.csv +8 -0
- thicc/data/hospitals/ucsf_medical_center_data.csv +8 -0
- thicc/insurance/cost_estimator.py +13 -0
- thicc/insurance/plans.py +14 -0
README.md
CHANGED
|
@@ -1,14 +1,21 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
## Prerequisites
|
| 2 |
+
|
| 3 |
+
- Python 3.8 or higher
|
| 4 |
+
- Install the required dependencies:
|
| 5 |
+
|
| 6 |
+
```bash
|
| 7 |
+
pip install -r requirements.txt
|
| 8 |
+
```
|
| 9 |
+
|
| 10 |
+
## How to Run
|
| 11 |
+
|
| 12 |
+
1. Run the application:
|
| 13 |
+
```bash
|
| 14 |
+
python thicc/app.py
|
| 15 |
+
```
|
| 16 |
+
|
| 17 |
+
3. Open the Gradio interface in your browser using the URL provided in the terminal (e.g., `http://127.0.0.1:7860`).
|
| 18 |
+
|
| 19 |
+
## Sample Data
|
| 20 |
+
|
| 21 |
+
The application uses a sample CSV file (`sample_data.csv`) located in the project directory. You can modify this file to include your own data.
|
requirements.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
pandas
|
thicc/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
thicc/ai_logic/intent_parser.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pandas as pd
|
| 2 |
+
|
| 3 |
+
# TODO: Use LLM to parse user intent.
|
| 4 |
+
# For now adding simple rules
|
| 5 |
+
def parse_intent(user_input: str, services_data: pd.DataFrame):
|
| 6 |
+
"""
|
| 7 |
+
Parses the user's input to determine their intent.
|
| 8 |
+
|
| 9 |
+
Args:
|
| 10 |
+
user_input (str): The input string from the user.
|
| 11 |
+
|
| 12 |
+
Returns:
|
| 13 |
+
str: The identified intent of the user.
|
| 14 |
+
"""
|
| 15 |
+
user_input = user_input.lower()
|
| 16 |
+
if "help" in user_input or "support" in user_input or "services" in user_input:
|
| 17 |
+
return "list_services"
|
| 18 |
+
|
| 19 |
+
res = services_data[
|
| 20 |
+
services_data["description"].apply(lambda desc: desc.lower() in user_input)
|
| 21 |
+
]
|
| 22 |
+
|
| 23 |
+
if res.empty is False:
|
| 24 |
+
return res.iloc[0]["intent"]
|
| 25 |
+
return None
|
thicc/app.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from ai_logic.intent_parser import parse_intent
|
| 3 |
+
from data.data_loader import list_services, load_services_data, HOSPITALS
|
| 4 |
+
from insurance import plans, cost_estimator
|
| 5 |
+
|
| 6 |
+
# Dropdown so the user can choose their insurance plan
|
| 7 |
+
plan_dropdown = gr.Dropdown(
|
| 8 |
+
choices=list(plans.SAMPLE_PLANS.keys()) + ["No Insurance"],
|
| 9 |
+
value="PPO",
|
| 10 |
+
label="Select plan",
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
hospital_dropdown = gr.Dropdown(
|
| 14 |
+
choices=HOSPITALS.keys(),
|
| 15 |
+
value=list(HOSPITALS.keys())[0],
|
| 16 |
+
label="Select a Hospital",
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
# - plan_name is now a parameter
|
| 20 |
+
def respond(message, history, plan_name: str, hospital_name: str) -> str:
|
| 21 |
+
hospital_data_path = HOSPITALS.get(hospital_name)
|
| 22 |
+
services_data = load_services_data(hospital_data_path)
|
| 23 |
+
|
| 24 |
+
requested_info = parse_intent(message, services_data)
|
| 25 |
+
|
| 26 |
+
if requested_info is None or requested_info == "list_services":
|
| 27 |
+
services_list = list_services(services_data)
|
| 28 |
+
return "Available services:\n" + "\n".join(services_list)
|
| 29 |
+
|
| 30 |
+
service_data = services_data[
|
| 31 |
+
services_data["intent"].str.contains(
|
| 32 |
+
requested_info,
|
| 33 |
+
case=False,
|
| 34 |
+
na=False,
|
| 35 |
+
)
|
| 36 |
+
]
|
| 37 |
+
|
| 38 |
+
if service_data.empty:
|
| 39 |
+
return "Sorry, no information found for your request."
|
| 40 |
+
|
| 41 |
+
service_description = service_data.iloc[0]["description"]
|
| 42 |
+
price = service_data.iloc[0]["negotiated_rate"]
|
| 43 |
+
|
| 44 |
+
# Map dropdown choice -> InsurancePlan object
|
| 45 |
+
if plan_name == "No Insurance":
|
| 46 |
+
plan = plans.NO_INSURANCE_PLAN
|
| 47 |
+
else:
|
| 48 |
+
plan = plans.SAMPLE_PLANS.get(plan_name, plans.NO_INSURANCE_PLAN)
|
| 49 |
+
|
| 50 |
+
cost = cost_estimator.estimate_cost(price, plan, deductible_met=True)
|
| 51 |
+
|
| 52 |
+
return f"The estimated cost for {service_description} under the {plan_name} plan is ${cost:.2f}."
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
demo = gr.ChatInterface(
|
| 56 |
+
fn=respond,
|
| 57 |
+
title="THICC Cost Chatbot",
|
| 58 |
+
type="messages",
|
| 59 |
+
additional_inputs=[plan_dropdown, hospital_dropdown],
|
| 60 |
+
additional_inputs_accordion="Tells us about your insurance plan and hospital",
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
if __name__ == "__main__":
|
| 64 |
+
# share=True for Colab; locally use demo.launch()
|
| 65 |
+
demo.launch()
|
thicc/data/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
thicc/data/data_loader.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pandas as pd
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
|
| 4 |
+
# Directory of this file: .../thicc/data
|
| 5 |
+
BASE_DIR = Path(__file__).resolve().parent
|
| 6 |
+
|
| 7 |
+
HOSPITALS = {
|
| 8 |
+
"Mayo Clinic": BASE_DIR / "hospitals" / "mayo_clinic_data.csv",
|
| 9 |
+
"Cleveland Clinic": BASE_DIR / "hospitals" / "cleveland_clinic_data.csv",
|
| 10 |
+
"Johns Hopkins Hospital": BASE_DIR / "hospitals" / "johns_hopkins_hospital_data.csv",
|
| 11 |
+
"Massachusetts General Hospital": BASE_DIR / "hospitals" / "massachusetts_general_hospital_data.csv",
|
| 12 |
+
"UCLA Medical Center": BASE_DIR / "hospitals" / "ucla_medical_center_data.csv",
|
| 13 |
+
"Cedars-Sinai Medical Center": BASE_DIR / "hospitals" / "cedars_sinai_medical_center_data.csv",
|
| 14 |
+
"NewYork-Presbyterian Hospital": BASE_DIR / "hospitals" / "newyork_presbyterian_hospital_data.csv",
|
| 15 |
+
"Northwestern Memorial Hospital": BASE_DIR / "hospitals" / "northwestern_memorial_hospital_data.csv",
|
| 16 |
+
"UCSF Medical Center": BASE_DIR / "hospitals" / "ucsf_medical_center_data.csv",
|
| 17 |
+
"Houston Methodist Hospital": BASE_DIR / "hospitals" / "houston_methodist_hospital_data.csv",
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
def load_services_data(path) -> pd.DataFrame:
|
| 21 |
+
"""Load price data from a CSV file."""
|
| 22 |
+
df = pd.read_csv(path)
|
| 23 |
+
return df[[
|
| 24 |
+
"intent",
|
| 25 |
+
"description",
|
| 26 |
+
"gross_charge",
|
| 27 |
+
"negotiated_rate",
|
| 28 |
+
]]
|
| 29 |
+
|
| 30 |
+
def list_services(services_data: pd.DataFrame) -> list[str]:
|
| 31 |
+
return services_data["description"].tolist()
|
thicc/data/hospitals/cedars_sinai_medical_center_data.csv
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
intent,description,gross_charge,negotiated_rate
|
| 2 |
+
"mri_information","MRI",1300,1080
|
| 3 |
+
"xray_information","X-Ray",2180,1780
|
| 4 |
+
"general_consultation","General Consultation",1620,1320
|
| 5 |
+
"neurosurgery_information","Neurosurgery",20000,17000
|
| 6 |
+
"pain_management_information","Pain Management",2500,2000
|
| 7 |
+
"endocrinology_information","Endocrinology",3700,3100
|
| 8 |
+
"bariatric_surgery_information","Bariatric Surgery",15000,12000
|
thicc/data/hospitals/cleveland_clinic_data.csv
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
intent,description,gross_charge,negotiated_rate
|
| 2 |
+
"mri_information","MRI",1320,1100
|
| 3 |
+
"xray_information","X-Ray",2200,1800
|
| 4 |
+
"general_consultation","General Consultation",1550,1250
|
| 5 |
+
"cardiac_surgery_information","Cardiac Surgery",15000,12000
|
| 6 |
+
"dialysis_information","Dialysis",4000,3200
|
thicc/data/hospitals/houston_methodist_hospital_data.csv
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
intent,description,gross_charge,negotiated_rate
|
| 2 |
+
"mri_information","MRI",1310,1090
|
| 3 |
+
"xray_information","X-Ray",2130,1730
|
| 4 |
+
"general_consultation","General Consultation",1610,1310
|
| 5 |
+
"transplant_surgery_information","Transplant Surgery",48000,40000
|
| 6 |
+
"wound_care_information","Wound Care",1800,1400
|
| 7 |
+
"hyperbaric_therapy_information","Hyperbaric Therapy",3500,3000
|
| 8 |
+
"occupational_therapy_information","Occupational Therapy",2100,1700
|
thicc/data/hospitals/johns_hopkins_hospital_data.csv
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
intent,description,gross_charge,negotiated_rate
|
| 2 |
+
"mri_information","MRI",1400,1150
|
| 3 |
+
"xray_information","X-Ray",2050,1600
|
| 4 |
+
"general_consultation","General Consultation",1700,1400
|
| 5 |
+
"organ_transplant_information","Organ Transplant",50000,42000
|
| 6 |
+
"pediatric_care_information","Pediatric Care",3000,2500
|
| 7 |
+
"sleep_disorder_clinic_information","Sleep Disorder Clinic",2100,1700
|
| 8 |
+
"infectious_disease_information","Infectious Disease",4200,3500
|
thicc/data/hospitals/massachusetts_general_hospital_data.csv
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
intent,description,gross_charge,negotiated_rate
|
| 2 |
+
"mri_information","MRI",1280,1050
|
| 3 |
+
"xray_information","X-Ray",2150,1750
|
| 4 |
+
"general_consultation","General Consultation",1650,1350
|
| 5 |
+
"fertility_treatment_information","Fertility Treatment",12000,10000
|
| 6 |
+
"oncology_information","Oncology",8000,7000
|
| 7 |
+
"burn_unit_information","Burn Unit",6000,5000
|
| 8 |
+
"speech_therapy_information","Speech Therapy",1800,1400
|
thicc/data/hospitals/mayo_clinic_data.csv
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
intent,description,gross_charge,negotiated_rate
|
| 2 |
+
"mri_information","MRI",1234,1000
|
| 3 |
+
"xray_information","X-Ray",2100,1700
|
| 4 |
+
"general_consultation","General Consultation",1600,1300
|
| 5 |
+
"sleep_medicine_information","Sleep Medicine",2200,1800
|
| 6 |
+
"rheumatology_information","Rheumatology",3500,2900
|
| 7 |
+
"geriatrics_information","Geriatrics",2500,2000
|
| 8 |
+
"nutrition_counseling_information","Nutrition Counseling",1200,900
|
thicc/data/hospitals/newyork_presbyterian_hospital_data.csv
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
intent,description,gross_charge,negotiated_rate
|
| 2 |
+
"mri_information","MRI",1370,1130
|
| 3 |
+
"xray_information","X-Ray",2120,1720
|
| 4 |
+
"general_consultation","General Consultation",1680,1380
|
| 5 |
+
"psychiatric_care_information","Psychiatric Care",4000,3500
|
| 6 |
+
"rehabilitation_information","Rehabilitation",2200,1800
|
| 7 |
+
"neonatal_care_information","Neonatal Care",5000,4200
|
| 8 |
+
"speech_pathology_information","Speech Pathology",2100,1700
|
thicc/data/hospitals/northwestern_memorial_hospital_data.csv
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
intent,description,gross_charge,negotiated_rate
|
| 2 |
+
"mri_information","MRI",1290,1060
|
| 3 |
+
"xray_information","X-Ray",2170,1770
|
| 4 |
+
"general_consultation","General Consultation",1630,1330
|
| 5 |
+
"dermatology_information","Dermatology",1200,900
|
| 6 |
+
"allergy_treatment_information","Allergy Treatment",1100,850
|
| 7 |
+
"urology_information","Urology",2700,2200
|
| 8 |
+
"pulmonology_information","Pulmonology",3500,2900
|
thicc/data/hospitals/ucla_medical_center_data.csv
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
intent,description,gross_charge,negotiated_rate
|
| 2 |
+
"mri_information","MRI",1350,1120
|
| 3 |
+
"xray_information","X-Ray",2250,1850
|
| 4 |
+
"general_consultation","General Consultation",1580,1280
|
| 5 |
+
"sports_medicine_information","Sports Medicine",3500,3000
|
| 6 |
+
"plastic_surgery_information","Plastic Surgery",9000,7500
|
| 7 |
+
"immunology_information","Immunology",3200,2700
|
| 8 |
+
"gastroenterology_information","Gastroenterology",4100,3500
|
thicc/data/hospitals/ucsf_medical_center_data.csv
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
intent,description,gross_charge,negotiated_rate
|
| 2 |
+
"mri_information","MRI",1390,1160
|
| 3 |
+
"xray_information","X-Ray",2190,1790
|
| 4 |
+
"general_consultation","General Consultation",1690,1390
|
| 5 |
+
"aids_hiv_care_information","AIDS/HIV Care",7000,6000
|
| 6 |
+
"genetic_counseling_information","Genetic Counseling",2500,2000
|
| 7 |
+
"transgender_health_information","Transgender Health",6000,5000
|
| 8 |
+
"integrative_medicine_information","Integrative Medicine",3200,2700
|
thicc/insurance/cost_estimator.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .plans import InsurancePlan
|
| 2 |
+
|
| 3 |
+
def estimate_cost(price: float, plan: InsurancePlan | None = None, deductible_met: bool = False) -> float:
|
| 4 |
+
price = float(price)
|
| 5 |
+
|
| 6 |
+
if plan is None or getattr(plan, "plan_name", "") == "No Insurance":
|
| 7 |
+
return price # No insurance, full price
|
| 8 |
+
|
| 9 |
+
if deductible_met:
|
| 10 |
+
# If deductible is met, only copay and coinsurance apply
|
| 11 |
+
return plan.copay or (price * plan.coinsurance)
|
| 12 |
+
|
| 13 |
+
return min(price, plan.deductible) + plan.copay
|
thicc/insurance/plans.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class InsurancePlan:
|
| 2 |
+
def __init__(self, plan_name, copay, deductible, coinsurance):
|
| 3 |
+
self.plan_name = plan_name
|
| 4 |
+
self.copay = copay
|
| 5 |
+
self.deductible = deductible
|
| 6 |
+
self.coinsurance = coinsurance
|
| 7 |
+
|
| 8 |
+
SAMPLE_PLANS = {
|
| 9 |
+
"HMO": InsurancePlan("HMO", 25, 0, 0.0),
|
| 10 |
+
"PPO": InsurancePlan("PPO", 20, 500, 0.2),
|
| 11 |
+
"HDHP": InsurancePlan("HDHP", 20, 1500, 0.1),
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
NO_INSURANCE_PLAN = InsurancePlan("No Insurance", 0, 0, 1.0)
|