这是indexloc提供的服务,不要输入任何密码
Skip to content

Healthcare demo #133

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .data/aml/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
fake = Faker()

# Constants
CURRENT_DATE = datetime(2025, 2, 28)
CURRENT_DATE = datetime.today()
COUNTRIES = ["USA", "Canada", "UK", "Germany", "South Africa", "Cuba", "Iran", "Russia"]
HIGH_RISK_COUNTRIES = ["Cuba", "Iran", "Russia"]
CURRENCIES = ["USD", "CAD", "EUR", "ZAR", "BTC"]
Expand Down
44 changes: 44 additions & 0 deletions .data/healthcare/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: ${CONTAINER_PREFIX}
services:
# Databases
postgres:
image: postgres
container_name: ${CONTAINER_PREFIX}_postgres
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
- ./postgres/:/docker-entrypoint-initdb.d/
environment:
PGUSER: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- "5432:5432"
healthcheck:
test: "pg_isready -q -h postgres"
interval: 10s
timeout: 5s
retries: 30

redis:
image: redis:latest
restart: unless-stopped
ports:
- 6379:6379

caching:
build:
context: https://github.com/hasura/engine-plugin-caching.git
restart: unless-stopped
ports:
- 8787:8787
environment:
CACHING_PLUGIN_SECRET: ${CACHING_PLUGIN_SECRET}
CACHING_PLUGIN_REDIS_URL: ${CACHING_PLUGIN_REDIS_URL}
extra_hosts:
- local.hasura.dev=host-gateway
volumes:
- ../plugins/caching-config.js:/app/src/config.js

volumes:
postgres-data:
109 changes: 109 additions & 0 deletions .data/healthcare/generate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import csv
import random
from datetime import datetime, timedelta
import uuid
from faker import Faker
import os

fake = Faker()
OUTPUT_DIR = "postgres"
CURRENT_DATE = datetime.today()
os.makedirs(OUTPUT_DIR, exist_ok=True)

# Load HCPCS codes
def load_hcpcs_codes(file_path=f"{OUTPUT_DIR}/procedure_codes.csv"):
with open(file_path, "r") as f:
reader = csv.DictReader(f)
return [(row["ref.hcpc"], row["ref.category"], int(row["ref.avg_duration_minutes"])) for row in reader]

# Generate Patients and Insurance Plans
def generate_patients_and_insurance(num_patients=1000):
with open(f"{OUTPUT_DIR}/patients.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["patient.patient_id", "patient.first_name", "patient.last_name",
"patient.date_of_birth", "patient.insurance_plan_id"])
for _ in range(num_patients):
pid = fake.uuid4()[:20]
writer.writerow([
pid, fake.first_name(), fake.last_name(),
fake.date_of_birth(minimum_age=18, maximum_age=90).isoformat(),
f"PLAN{random.randint(1, 5):03d}"
])

with open(f"{OUTPUT_DIR}/insurance_plans.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["patient.plan_id", "patient.plan_name", "patient.payer_name"])
for i in range(10):
writer.writerow([
f"PLAN{i+1:03d}", fake.company() + " Plan",
random.choice([
"UnitedHealthcare", "Aetna", "Cigna", "Blue Cross Blue Shield",
"Humana", "Kaiser Permanente", "Anthem", "Molina Healthcare",
"Health Net", "WellCare", "Centene", "Ambetter", "Oscar Health",
"Medica", "Priority Health", "Highmark", "Florida Blue",
"Empire BlueCross", "Regence BlueShield", "Premera Blue Cross"
])
])

# Generate Operators and Schedule with Variance
def generate_operators_and_schedule(num_operators=10):
with open(f"{OUTPUT_DIR}/operators.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["ops.operator_id", "ops.full_name", "ops.region", "ops.specialty"])
for i in range(num_operators):
writer.writerow([f"OP{i:03d}", fake.name(), "Region1",
random.choice(["Radiology", "Cardiology", "Orthopedics"])])

busy_operators = ["OP000", "OP001", "OP002"] # 30% busier
start_date = CURRENT_DATE

with open(f"{OUTPUT_DIR}/operator_schedule.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["ops.operator_id", "ops.work_date", "ops.booked_minutes", "ops.max_minutes"])
for i in range(num_operators):
op_id = f"OP{i:03d}"
for day in range(14):
work_date = start_date + timedelta(days=day)
booked = random.randint(200, 400) if op_id in busy_operators else random.randint(0, 150)
writer.writerow([op_id, work_date.date().isoformat(), booked, 480])

# Generate Cases with Variance
def generate_cases(num_cases=1000):
hcpcs_codes = load_hcpcs_codes()
patients = [row["patient.patient_id"] for row in csv.DictReader(open(f"{OUTPUT_DIR}/patients.csv"))]
operators = [row["ops.operator_id"] for row in csv.DictReader(open(f"{OUTPUT_DIR}/operators.csv"))]
start_date = CURRENT_DATE

with open(f"{OUTPUT_DIR}/cases.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["ops.patient_id", "ops.clinic_id", "ops.procedure_code", "ops.urgency_level",
"ops.recommended_date", "ops.status", "ops.operator_id", "ops.region", "ops.created_at"])

for _ in range(num_cases):
hcpc, category, duration = random.choice(hcpcs_codes)
urgency = random.choices(
["critical", "emergency", "urgent", "semi-urgent", "routine"],
weights=[10, 20, 30, 20, 20]
)[0]
rec_date = start_date + timedelta(days=random.randint(0, 13))
status_roll = random.random()
if status_roll < 0.6:
status, op_id = "pending", ""
elif status_roll < 0.9:
status, op_id = "assigned", random.choice(operators[:3]) # Busier operators
else:
status, op_id = "completed", random.choice(operators)

writer.writerow([
random.choice(patients), "CL001", hcpc, urgency, rec_date.date().isoformat(),
status, op_id, "Region1", datetime.now().isoformat()
])

if __name__ == "__main__":
print("Generating patients and insurance...")
generate_patients_and_insurance(5000)
print("Generating operators and schedule...")
generate_operators_and_schedule(20)
print("Generating cases...")
generate_cases(10000)
print(f"Data generation complete. Files saved in {OUTPUT_DIR}/")
39 changes: 39 additions & 0 deletions .data/healthcare/postgres/1-create-ref.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
CREATE DATABASE ref;

\c ref;

CREATE TABLE drug_reference (
product_ndc VARCHAR(11) PRIMARY KEY,
proprietary_name VARCHAR(200),
nonproprietary_name VARCHAR(200),
dosage_form_name VARCHAR(50),
route_name VARCHAR(100),
labeler_name VARCHAR(200),
substance_name VARCHAR(400),
active_ingredients_info VARCHAR(400)
);

CREATE TABLE drug_packaging (
ndc_package_code VARCHAR(12) PRIMARY KEY,
product_ndc VARCHAR(11) REFERENCES drug_reference(product_ndc),
package_description VARCHAR(150)
);

CREATE TABLE procedure_codes (
hcpc VARCHAR(5) PRIMARY KEY,
long_description TEXT NOT NULL,
short_description VARCHAR(100),
category VARCHAR(50),
avg_duration_minutes INT
);

\COPY drug_reference FROM '/docker-entrypoint-initdb.d/drug_reference.csv' WITH (FORMAT csv, HEADER true);
\COPY drug_packaging FROM '/docker-entrypoint-initdb.d/drug_packaging.csv' WITH (FORMAT csv, HEADER true);
\COPY procedure_codes FROM '/docker-entrypoint-initdb.d/procedure_codes.csv' WITH (FORMAT csv, HEADER true);

CREATE INDEX idx_drug_packaging_product_ndc ON drug_packaging(product_ndc);
CREATE INDEX idx_drug_reference_proprietary_name ON drug_reference(proprietary_name);
CREATE INDEX idx_drug_reference_nonproprietary_name ON drug_reference(nonproprietary_name);
CREATE INDEX idx_drug_reference_labeler_name ON drug_reference(labeler_name);
CREATE INDEX idx_drug_reference_active_ingredients ON drug_reference(active_ingredients_info);
CREATE INDEX idx_procedure_codes_category ON procedure_codes(category);
25 changes: 25 additions & 0 deletions .data/healthcare/postgres/2-create-patient.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
CREATE DATABASE patient;

\c patient;

CREATE TABLE insurance_plans (
plan_id VARCHAR(20) PRIMARY KEY,
plan_name VARCHAR(100),
payer_name VARCHAR(100)
);

CREATE TABLE patients (
patient_id VARCHAR(20) PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
date_of_birth DATE,
insurance_plan_id VARCHAR(20) REFERENCES insurance_plans(plan_id)
);

\COPY insurance_plans FROM '/docker-entrypoint-initdb.d/insurance_plans.csv' WITH (FORMAT csv, HEADER true);
\COPY patients FROM '/docker-entrypoint-initdb.d/patients.csv' WITH (FORMAT csv, HEADER true);

CREATE INDEX idx_patients_last_name ON patients(last_name);
CREATE INDEX idx_patients_first_name ON patients(first_name);
CREATE INDEX idx_patients_insurance_plan_id ON patients(insurance_plan_id);
CREATE INDEX idx_insurance_plans_payer_name ON insurance_plans(payer_name);
49 changes: 49 additions & 0 deletions .data/healthcare/postgres/3-create-ops.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
CREATE DATABASE ops;

\c ops;

CREATE TABLE operators (
operator_id VARCHAR(10) PRIMARY KEY,
full_name VARCHAR(100),
region VARCHAR(50),
specialty VARCHAR(50)
);

CREATE TABLE operator_schedule (
schedule_id SERIAL PRIMARY KEY,
operator_id VARCHAR(10) REFERENCES operators(operator_id),
work_date DATE,
booked_minutes INT DEFAULT 0,
max_minutes INT DEFAULT 480,
UNIQUE (operator_id, work_date)
);

CREATE TABLE cases (
case_id SERIAL PRIMARY KEY,
patient_id VARCHAR(20),
clinic_id VARCHAR(10) NOT NULL,
procedure_code VARCHAR(5),
urgency_level VARCHAR(20),
recommended_date DATE NOT NULL,
status VARCHAR(20),
operator_id VARCHAR(10) REFERENCES operators(operator_id),
region VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

\COPY operators FROM '/docker-entrypoint-initdb.d/operators.csv' WITH (FORMAT csv, HEADER true);
\COPY operator_schedule(operator_id, work_date, booked_minutes, max_minutes) FROM '/docker-entrypoint-initdb.d/operator_schedule.csv' WITH (FORMAT csv, HEADER true);
\COPY cases(patient_id, clinic_id, procedure_code, urgency_level, recommended_date, status, operator_id, region, created_at) FROM '/docker-entrypoint-initdb.d/cases.csv' WITH (FORMAT csv, HEADER true);

CREATE INDEX idx_cases_patient_id ON cases(patient_id);
CREATE INDEX idx_cases_clinic_id ON cases(clinic_id);
CREATE INDEX idx_cases_procedure_code ON cases(procedure_code);
CREATE INDEX idx_cases_urgency_level ON cases(urgency_level);
CREATE INDEX idx_cases_status ON cases(status);
CREATE INDEX idx_cases_created_at ON cases(created_at DESC);
CREATE INDEX idx_cases_operator_id ON cases(operator_id);
CREATE INDEX idx_cases_region ON cases(region);
CREATE INDEX idx_operators_full_name ON operators(full_name);
CREATE INDEX idx_operators_specialty ON operators(specialty);
CREATE INDEX idx_operator_schedule_operator_id ON operator_schedule(operator_id);
CREATE INDEX idx_operator_schedule_work_date ON operator_schedule(work_date);
3 changes: 3 additions & 0 deletions .data/healthcare/postgres/cases.csv
Git LFS file not shown
3 changes: 3 additions & 0 deletions .data/healthcare/postgres/drug_packaging.csv
Git LFS file not shown
3 changes: 3 additions & 0 deletions .data/healthcare/postgres/drug_reference.csv
Git LFS file not shown
3 changes: 3 additions & 0 deletions .data/healthcare/postgres/insurance_plans.csv
Git LFS file not shown
3 changes: 3 additions & 0 deletions .data/healthcare/postgres/operator_schedule.csv
Git LFS file not shown
3 changes: 3 additions & 0 deletions .data/healthcare/postgres/operators.csv
Git LFS file not shown
3 changes: 3 additions & 0 deletions .data/healthcare/postgres/patients.csv
Git LFS file not shown
3 changes: 3 additions & 0 deletions .data/healthcare/postgres/procedure_codes.csv
Git LFS file not shown
33 changes: 33 additions & 0 deletions hasura/.env.healthcare.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
PATIENT_OPS_OPERATIONS_AUTHORIZATION_HEADER="Bearer LmI9HLQ_4_1uBum5OwND0A=="
PATIENT_OPS_OPERATIONS_CONNECTION_URI="postgres://postgres:hbGciOiJIUzI1NiIsInR5cCI6IkpX@local.hasura.dev/ops"
PATIENT_OPS_OPERATIONS_HASURA_SERVICE_TOKEN_SECRET="LmI9HLQ_4_1uBum5OwND0A=="
PATIENT_OPS_OPERATIONS_OTEL_EXPORTER_OTLP_ENDPOINT="http://local.hasura.dev:4317"
PATIENT_OPS_OPERATIONS_OTEL_SERVICE_NAME="patient_ops_operations"
PATIENT_OPS_OPERATIONS_READ_URL="http://local.hasura.dev:5622"
PATIENT_OPS_OPERATIONS_WRITE_URL="http://local.hasura.dev:5622"
PATIENT_OPS_PATIENTS_AUTHORIZATION_HEADER="Bearer fKIMgAcGptTqCNymJvTuAw=="
PATIENT_OPS_PATIENTS_CONNECTION_URI="postgres://postgres:hbGciOiJIUzI1NiIsInR5cCI6IkpX@local.hasura.dev/patient"
PATIENT_OPS_PATIENTS_HASURA_SERVICE_TOKEN_SECRET="fKIMgAcGptTqCNymJvTuAw=="
PATIENT_OPS_PATIENTS_OTEL_EXPORTER_OTLP_ENDPOINT="http://local.hasura.dev:4317"
PATIENT_OPS_PATIENTS_OTEL_SERVICE_NAME="patient_ops_patients"
PATIENT_OPS_PATIENTS_READ_URL="http://local.hasura.dev:6650"
PATIENT_OPS_PATIENTS_WRITE_URL="http://local.hasura.dev:6650"
REFERENCE_REFERENCE_AUTHORIZATION_HEADER="Bearer 16LYhcdSWhCeglOecVKddA=="
REFERENCE_REFERENCE_CONNECTION_URI="postgres://postgres:hbGciOiJIUzI1NiIsInR5cCI6IkpX@local.hasura.dev/ref"
REFERENCE_REFERENCE_HASURA_SERVICE_TOKEN_SECRET="16LYhcdSWhCeglOecVKddA=="
REFERENCE_REFERENCE_OTEL_EXPORTER_OTLP_ENDPOINT="http://local.hasura.dev:4317"
REFERENCE_REFERENCE_OTEL_SERVICE_NAME="reference_reference"
REFERENCE_REFERENCE_READ_URL="http://local.hasura.dev:5655"
REFERENCE_REFERENCE_WRITE_URL="http://local.hasura.dev:5655"
JWT_SECRET="KGOUts9A6hU2dWQQiQHdNN5VZBixs+BAh74RwDElxps"
CACHING_PLUGIN_PRE_PARSE_URL="http://local.hasura.dev:8787/pre-parse"
CACHING_PLUGIN_PRE_RESPONSE_URL="http://local.hasura.dev:8787/pre-response"
CACHING_PLUGIN_REDIS_URL="redis://local.hasura.dev:6379"
CACHING_PLUGIN_SECRET="zZkhKqFjqXR4g5MZCsJUZCnhCcoPyZ"
GLOBALS_GLOBAL_FUNCTIONS_AUTHORIZATION_HEADER="Bearer YQ=="
GLOBALS_GLOBAL_FUNCTIONS_HASURA_CONNECTOR_PORT=5756
GLOBALS_GLOBAL_FUNCTIONS_HASURA_SERVICE_TOKEN_SECRET="YQ=="
GLOBALS_GLOBAL_FUNCTIONS_OTEL_EXPORTER_OTLP_ENDPOINT="http://local.hasura.dev:4317"
GLOBALS_GLOBAL_FUNCTIONS_OTEL_SERVICE_NAME="globals_global_functions"
GLOBALS_GLOBAL_FUNCTIONS_READ_URL="http://local.hasura.dev:5756"
GLOBALS_GLOBAL_FUNCTIONS_WRITE_URL="http://local.hasura.dev:5756"
Loading