from fasthtml.common import *
from datasets import load_dataset
import datetime
from pbs_data import PBSPublicDataAPIClient
import os
from fasthtml_hf import setup_hf_backup
from fasthtml import FastHTML
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.interval import IntervalTrigger
import atexit
HF_TOKEN = os.environ.get("HF_TOKEN")
custom_css = Style("""
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f0f0f0;
}
h1 {
color: #2c3e50;
text-align: center;
margin-bottom: 30px;
}
form {
background-color: #ffffff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #2c3e50;
}
select, button {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #fff;
color: #333;
}
button {
background-color: #3498db;
color: white;
font-weight: bold;
cursor: pointer;
transition: background-color 0.3s;
}
button:hover {
background-color: #2980b9;
}
#results {
margin-top: 30px;
background-color: #ffffff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
#results h2 {
color: #2c3e50;
border-bottom: 2px solid #3498db;
padding-bottom: 10px;
}
#results p {
margin-bottom: 10px;
color: #333;
}
#results hr {
border: none;
border-top: 1px solid #eee;
margin: 20px 0;
}
a {
color: #3498db;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
""")
DATASET_NAME = "cmcmaster/rheumatology-biologics-dataset"
def load_data():
try:
dataset = load_dataset(DATASET_NAME, split="train")
# Create sets for dropdown options
drugs = set(dataset['drug'])
brands = set(dataset['brand'])
formulations = set(dataset['formulation'])
indications = set(dataset['indication'])
treatment_phases = set(dataset['treatment_phase'])
hospital_types = set(dataset['hospital_type'])
return {
'combinations': dataset,
'drugs': sorted(drugs),
'brands': sorted(brands),
'formulations': sorted(formulations),
'indications': sorted(indications),
'treatment_phases': sorted(treatment_phases),
'hospital_types': sorted(hospital_types)
}
except Exception as e:
print(f"An error occurred while loading data: {str(e)}")
return {
'combinations': [],
'drugs': [],
'brands': [],
'formulations': [],
'indications': [],
'treatment_phases': [],
'hospital_types': []
}
biologics_data = load_data()
app, rt = fast_app()
def search_biologics(drug, brand, formulation, indication, treatment_phase, hospital_type):
results = biologics_data['combinations'].filter(
lambda x: (not drug or x['drug'] == drug) and
(not brand or x['brand'] == brand) and
(not formulation or x['formulation'] == formulation) and
(not indication or x['indication'] == indication) and
(not treatment_phase or x['treatment_phase'] == treatment_phase) and
(not hospital_type or x['hospital_type'] == hospital_type)
)
if len(results) == 0:
return "No results found."
output = ""
for item in results:
output += f"""
{item['drug']} ({item['brand']})
PBS Code: {item['pbs_code']}
Formulation: {item['formulation']}
Indication: {item['indication']}
Treatment Phase: {item['treatment_phase']}
Streamlined Code: {item['streamlined_code'] or 'N/A'}
Authority Method: {item['authority_method']}
Online Application: {'Yes' if item['online_application'] else 'No'}
Hospital Type: {item['hospital_type']}
Schedule Year: {item['schedule_year']}
Schedule Month: {item['schedule_month']}
"""
return output
def update_options(drug, brand, formulation, indication, treatment_phase, hospital_type):
filtered = biologics_data['combinations'].filter(
lambda x: (not drug or x['drug'] == drug) and
(not brand or x['brand'] == brand) and
(not formulation or x['formulation'] == formulation) and
(not indication or x['indication'] == indication) and
(not treatment_phase or x['treatment_phase'] == treatment_phase) and
(not hospital_type or x['hospital_type'] == hospital_type)
)
options = {
'drugs': sorted(set(filtered['drug'])),
'brands': sorted(set(filtered['brand'])),
'formulations': sorted(set(filtered['formulation'])),
'indications': sorted(set(filtered['indication'])),
'treatment_phases': sorted(set(filtered['treatment_phase'])),
'hospital_types': sorted(set(filtered['hospital_type']))
}
return options
@rt('/')
def get():
return Div(
custom_css,
H1("Biologics Prescriber Helper"),
Form(
Div(
Label("Drug:"),
Select(Option("All", value=""), *[Option(drug, value=drug) for drug in biologics_data['drugs']], name="drug", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Brand:"),
Select(Option("All", value=""), *[Option(brand, value=brand) for brand in biologics_data['brands']], name="brand", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Formulation:"),
Select(Option("All", value=""), *[Option(formulation, value=formulation) for formulation in biologics_data['formulations']], name="formulation", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Indication:"),
Select(Option("All", value=""), *[Option(indication, value=indication) for indication in biologics_data['indications']], name="indication", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Treatment Phase:"),
Select(Option("All", value=""), *[Option(phase, value=phase) for phase in biologics_data['treatment_phases']], name="treatment_phase", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Hospital Type:"),
Select(Option("All", value=""), *[Option(ht, value=ht) for ht in biologics_data['hospital_types']], name="hospital_type", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Button("Search", type="submit"),
Button("Reset", hx_get="/reset", hx_target="#options")
),
hx_post="/search",
hx_target="#results",
id="options"
),
Div(id="results")
)
@rt('/reset')
def get():
return Div(
custom_css,
Form(
Div(
Label("Drug:"),
Select(Option("All", value=""), *[Option(drug, value=drug) for drug in biologics_data['drugs']], name="drug", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Brand:"),
Select(Option("All", value=""), *[Option(brand, value=brand) for brand in biologics_data['brands']], name="brand", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Formulation:"),
Select(Option("All", value=""), *[Option(formulation, value=formulation) for formulation in biologics_data['formulations']], name="formulation", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Indication:"),
Select(Option("All", value=""), *[Option(indication, value=indication) for indication in biologics_data['indications']], name="indication", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Treatment Phase:"),
Select(Option("All", value=""), *[Option(phase, value=phase) for phase in biologics_data['treatment_phases']], name="treatment_phase", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Hospital Type:"),
Select(Option("All", value=""), *[Option(ht, value=ht) for ht in biologics_data['hospital_types']], name="hospital_type", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Button("Search", type="submit"),
Button("Reset", hx_get="/reset", hx_target="#options")
),
hx_post="/search",
hx_target="#results",
id="options"
)
)
@rt('/update_options')
def get(drug: str = '', brand: str = '', formulation: str = '', indication: str = '', treatment_phase: str = '', hospital_type: str = ''):
options = update_options(drug, brand, formulation, indication, treatment_phase, hospital_type)
return Div(
custom_css,
Form(
Div(
Label("Drug:"),
Select(Option("All", value=""), *[Option(d, value=d, selected=(d == drug)) for d in options['drugs']], name="drug", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Brand:"),
Select(Option("All", value=""), *[Option(b, value=b, selected=(b == brand)) for b in options['brands']], name="brand", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Formulation:"),
Select(Option("All", value=""), *[Option(f, value=f, selected=(f == formulation)) for f in options['formulations']], name="formulation", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Indication:"),
Select(Option("All", value=""), *[Option(i, value=i, selected=(i == indication)) for i in options['indications']], name="indication", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Treatment Phase:"),
Select(Option("All", value=""), *[Option(p, value=p, selected=(p == treatment_phase)) for p in options['treatment_phases']], name="treatment_phase", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Label("Hospital Type:"),
Select(Option("All", value=""), *[Option(ht, value=ht, selected=(ht == hospital_type)) for ht in options['hospital_types']], name="hospital_type", hx_get="/update_options", hx_target="#options", hx_trigger="change", hx_include="[name='drug'],[name='brand'],[name='formulation'],[name='indication'],[name='treatment_phase'],[name='hospital_type']")
),
Div(
Button("Search", type="submit"),
Button("Reset", hx_get="/reset", hx_target="#options")
),
hx_post="/search",
hx_target="#results",
id="options"
)
)
@rt('/search')
def post(drug: str = '', brand: str = '', formulation: str = '', indication: str = '', treatment_phase: str = '', hospital_type: str = ''):
results = search_biologics(drug, brand, formulation, indication, treatment_phase, hospital_type)
return results
def update_data():
print(f"Updating data at {datetime.datetime.now()}")
client = PBSPublicDataAPIClient("2384af7c667342ceb5a736fe29f1dc6b", rate_limit=0.2)
try:
data = client.fetch_rheumatology_biologics_data()
client.save_data_to_hf(data, HF_TOKEN, DATASET_NAME)
print("Data updated successfully")
global biologics_data
biologics_data = load_data()
except Exception as e:
print(f"An error occurred while updating data: {str(e)}")
# Set up the scheduler
update_data()
# Set up the scheduler
scheduler = BackgroundScheduler()
scheduler.add_job(
func=update_data,
trigger=IntervalTrigger(hours=24),
id='update_data',
name='Update Data',
replace_existing=True
)
scheduler.start()
# Make sure to shut down the scheduler when the app is terminated
atexit.register(lambda: scheduler.shutdown())
setup_hf_backup(app)
serve()