Skip to content
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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ print(f"FHIR conditions: {result.fhir.problem_list}") # Auto-converted to FHIR

```python
from healthchain.gateway import HealthChainAPI, FHIRGateway
from fhir.resources.patient import Patient
from healthchain.fhir.r4b import Patient

# Create healthcare application
app = HealthChainAPI(title="Multi-EHR Patient Data")
Expand Down
4 changes: 1 addition & 3 deletions cookbook/multi_ehr_data_aggregation.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@

from dotenv import load_dotenv

from fhir.resources.bundle import Bundle
from fhir.resources.condition import Condition
from fhir.resources.annotation import Annotation
from healthchain.fhir.r4b import Bundle, Condition, Annotation

from healthchain.gateway import FHIRGateway, HealthChainAPI
from healthchain.gateway.clients.fhir.base import FHIRAuthConfig
Expand Down
4 changes: 1 addition & 3 deletions cookbook/sepsis_fhir_batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@
import joblib
import logging
from dotenv import load_dotenv
from fhir.resources.patient import Patient
from fhir.resources.observation import Observation
from fhir.resources.riskassessment import RiskAssessment
from healthchain.fhir.r4b import Patient, Observation, RiskAssessment

from healthchain.gateway import HealthChainAPI, FHIRGateway
from healthchain.gateway.clients.fhir.base import FHIRAuthConfig
Expand Down
20 changes: 7 additions & 13 deletions docs/cookbook/clinical_coding.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,9 @@ First we'll need to convert the incoming CDA XML to FHIR. The [CdaAdapter](../re

```python
from healthchain.io import CdaAdapter
from healthchain.engine import create_interop

# Create an interop engine with default configuration
interop_engine = create_interop()
cda_adapter = CdaAdapter(engine=interop_engine)
# Create CDA adapter
cda_adapter = CdaAdapter()

# Parse the CDA document to a Document object
doc = cda_adapter.parse(request)
Expand Down Expand Up @@ -150,7 +148,7 @@ Use `.add_source` to register a FHIR endpoint you want to connect to with its co

```python
from healthchain.gateway import FHIRGateway
from healthchain.gateway.clients.fhir.base import FHIRAuthConfig
from healthchain.gateway.clients import FHIRAuthConfig
from dotenv import load_dotenv

load_dotenv()
Expand Down Expand Up @@ -193,7 +191,7 @@ def ai_coding_workflow(request: CdaRequest):
condition, source="epic-notereader", tag_code="cdi"
)
# Send to external FHIR server via gateway
fhir_gateway.create(condition, source="billing")
fhir_gateway.create(condition, source="medplum")

# Return processed CDA response to the legacy system
cda_response = cda_adapter.format(doc)
Expand Down Expand Up @@ -224,7 +222,7 @@ from healthchain.sandbox import SandboxClient

# Create sandbox client for SOAP/CDA testing
client = SandboxClient(
url="http://localhost:8000/notereader/ProcessDocument",
url="http://localhost:8000/notereader/?wsdl",
workflow="sign-note-inpatient",
protocol="soap"
)
Expand All @@ -242,14 +240,9 @@ client.load_from_path("./data/notereader_cda.xml")
Now for the moment of truth! Start your service and run the sandbox to see the complete workflow in action.

```python
import uvicorn
import threading

# Start the API server in a separate thread
def start_api():
uvicorn.run(app, port=8000)

api_thread = threading.Thread(target=start_api, daemon=True)
api_thread = threading.Thread(target=app.run, daemon=True)
api_thread.start()

# Send requests and save responses with sandbox client
Expand Down Expand Up @@ -472,3 +465,4 @@ A clinical coding service that bridges legacy CDA systems with modern FHIR infra
- **Add validation**: Implement FHIR resource validation before sending to external servers.
- **Expand to other workflows**: Adapt the pattern for lab results, medications, or radiology reports.
- **Build on it**: Use the extracted conditions in the [Data Aggregation example](./multi_ehr_aggregation.md) to combine with other FHIR sources.
- **Go to production**: Scaffold a project with `healthchain new` and run with `healthchain serve` — see [From cookbook to service](./index.md#from-cookbook-to-service).
12 changes: 4 additions & 8 deletions docs/cookbook/discharge_summarizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ from healthchain.models import CDSRequest, CDSResponse
cds_service = CDSHooksService()

# Define the CDS service function
@cds_service.hook("encounter-discharge", id="discharge-summary")
@cds_service.hook("encounter-discharge", id="discharge-summarizer")
def handle_discharge_summary(request: CDSRequest) -> CDSResponse:
"""Process discharge summaries with AI"""
# Parse CDS request to internal Document format
Expand Down Expand Up @@ -183,14 +183,9 @@ client.load_free_text(
Put it all together and run both the service and sandbox client:

```python
import uvicorn
import threading

# Start the API server in a separate thread
def start_api():
uvicorn.run(app, port=8000)

api_thread = threading.Thread(target=start_api, daemon=True)
api_thread = threading.Thread(target=app.run, daemon=True)
api_thread.start()

# Send requests and save responses with sandbox client
Expand All @@ -203,7 +198,7 @@ client.save_results("./output/")
Once running, your service will be available at:

- **Service discovery**: `http://localhost:8000/cds-services`
- **Discharge summary endpoint**: `http://localhost:8000/cds-services/discharge-summary`
- **Discharge summary endpoint**: `http://localhost:8000/cds/cds-services/discharge-summarizer`

??? example "Example CDS Response"

Expand Down Expand Up @@ -257,3 +252,4 @@ A CDS Hooks service for discharge workflows that integrates seamlessly with EHR
- **Add validation**: Implement checks for required discharge elements (medications, follow-ups, equipment).
- **Multi-card support**: Expand to generate separate cards for different discharge aspects (medication reconciliation, transportation, follow-up scheduling).
- **Integrate with workflows**: Deploy to Epic App Orchard or Cerner Code Console for production EHR integration.
- **Go to production**: Scaffold a project with `healthchain new` and run with `healthchain serve` — see [From cookbook to service](./index.md#from-cookbook-to-service).
6 changes: 2 additions & 4 deletions docs/cookbook/format_conversion.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ for resource in fhir_resources:
Generate a CDA document from FHIR resources:

```python
from fhir.resources.condition import Condition
from fhir.resources.patient import Patient
from healthchain.fhir.r4b import Condition, Patient

# Create FHIR resources
patient = Patient(
Expand Down Expand Up @@ -171,8 +170,7 @@ for resource in fhir_resources:
Generate an HL7v2 message from FHIR resources:

```python
from fhir.resources.patient import Patient
from fhir.resources.encounter import Encounter
from healthchain.fhir.r4b import Patient, Encounter

patient = Patient(
resourceType="Patient",
Expand Down
64 changes: 62 additions & 2 deletions docs/cookbook/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,65 @@ Hands-on, production-ready examples for building healthcare AI applications with

---

!!! tip "What next?"
See the source code for each recipe, experiment with the sandboxes, and adapt the patterns for your projects!
## From cookbook to service

Cookbooks are standalone scripts — run them directly to explore and experiment. When you're ready to build a proper service, scaffold a project and move your logic in:

```bash
# 1. Run a cookbook locally
python cookbook/sepsis_cds_hooks.py

# 2. Scaffold a project
healthchain new my-sepsis-service -t cds-hooks
cd my-sepsis-service

# 3. Move your hook logic into app.py, then run with config
healthchain serve
```

`app.run()` (used in cookbooks) is a convenience wrapper — equivalent to running uvicorn directly. `healthchain serve` reads `healthchain.yaml` for port, TLS, and deployment settings, and prints a startup banner so you can see what's active at a glance.

**What moves from your script into `healthchain.yaml`:**

```python
# cookbook — everything hardcoded in Python
gateway = FHIRGateway()
gateway.add_source("medplum", FHIRAuthConfig.from_env("MEDPLUM").to_connection_string())

llm = ChatAnthropic(model="claude-opus-4-6", max_tokens=512)

app = HealthChainAPI(title="My App", port=8000, service_type="fhir-gateway")
```

```yaml
# healthchain.yaml — port, sources, and LLM provider declared here
service:
type: fhir-gateway
port: 8000

sources:
medplum:
env_prefix: MEDPLUM # credentials stay in .env

llm:
provider: anthropic
model: claude-opus-4-6
max_tokens: 512
```

```python
# app.py — load from config instead
from healthchain.config.appconfig import AppConfig
from healthchain.gateway import FHIRGateway, HealthChainAPI

config = AppConfig.load()
gateway = FHIRGateway.from_config(config)
llm = config.llm.to_langchain()

app = HealthChainAPI(title="My App")
```

Credentials (API keys, client secrets) always stay in `.env` — never in `healthchain.yaml`.

!!! tip "Configuration reference"
See the [configuration reference](../reference/config.md) for all available settings — security, compliance, eval, and more.
7 changes: 3 additions & 4 deletions docs/cookbook/ml_model_deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,7 @@ Query patients from FHIR server → Run predictions → Write RiskAssessment bac
Configure the [FHIRGateway](../reference/gateway/fhir_gateway.md) with your FHIR source:

```python
from fhir.resources.patient import Patient
from fhir.resources.observation import Observation
from healthchain.fhir.r4b import Patient, Observation
from healthchain.gateway import FHIRGateway
from healthchain.gateway.clients.fhir.base import FHIRAuthConfig
from healthchain.fhir import merge_bundles
Expand Down Expand Up @@ -513,5 +512,5 @@ Both patterns:
- **Add more features**: Extend `sepsis_vitals.yaml` with lab values, medications, or other Observations
- **Add more FHIR sources**: The gateway supports multiple sources—see the cookbook script for Epic sandbox configuration, or the [FHIR Sandbox Setup guide](./setup_fhir_sandboxes.md)
- **Automate batch runs**: Schedule screening jobs with cron, Airflow, or cloud schedulers; or use [FHIR Subscriptions](https://www.hl7.org/fhir/subscription.html) to trigger on new ICU admissions ([PRs welcome!](https://github.com/dotimplement/HealthChain/pulls))
- **Combine patterns**: Use batch screening to identify high-risk patients, then enable CDS
alerts for those patients
- **Combine patterns**: Use batch screening to identify high-risk patients, then enable CDS alerts for those patients
- **Go to production**: Scaffold a project with `healthchain new` and run with `healthchain serve` — see [From cookbook to service](./index.md#from-cookbook-to-service).
11 changes: 8 additions & 3 deletions docs/cookbook/multi_ehr_aggregation.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,17 @@ def get_unified_patient(patient_id: str, sources: List[str]) -> Bundle:
Register the gateway with [HealthChainAPI](../reference/gateway/api.md) to create REST endpoints.

```python
import uvicorn
from healthchain.gateway import HealthChainAPI

app = HealthChainAPI()
app = HealthChainAPI(
title="Multi-EHR Data Aggregation",
description="Aggregate patient data from multiple FHIR sources",
port=8888,
service_type="fhir-gateway",
)
app.register_gateway(gateway, path="/fhir")

uvicorn.run(app)
app.run()
```

!!! tip "FHIR Endpoints Provided by the Service"
Expand Down Expand Up @@ -405,3 +409,4 @@ A production-ready data aggregation service with:
- **Expand resource types**: Change `Condition` to `MedicationStatement`, `Observation`, or `Procedure` to aggregate different data.
- **Add processing**: Extend the pipeline with terminology mapping, entity extraction, or quality checks.
- **Build on it**: Use aggregated data in the [Clinical Coding tutorial](./clinical_coding.md) or feed it to your LLM application.
- **Go to production**: Scaffold a project with `healthchain new` and run with `healthchain serve` — see [From cookbook to service](./index.md#from-cookbook-to-service).
2 changes: 1 addition & 1 deletion docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The [**HealthChainAPI**](./reference/gateway/api.md) provides a unified interfac

```python
from healthchain.gateway import HealthChainAPI, FHIRGateway
from fhir.resources.patient import Patient
from healthchain.fhir.r4b import Patient

# Create your healthcare application
app = HealthChainAPI(title="My Healthcare AI App")
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The [**HealthChainAPI**](./gateway/api.md) provides a unified interface for conn

```python
from healthchain.gateway import HealthChainAPI, FHIRGateway
from fhir.resources.patient import Patient
from healthchain.fhir.r4b import Patient

# Create your healthcare application
app = HealthChainAPI(title="My Healthcare AI App")
Expand Down
67 changes: 67 additions & 0 deletions docs/reference/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ eval:
site:
name: ""
environment: development

# FHIR data sources — credentials stay in .env
# sources:
# medplum:
# env_prefix: MEDPLUM

# LLM provider for LangChain-based pipelines
# llm:
# provider: anthropic
# model: claude-opus-4-6
# max_tokens: 512
```

---
Expand Down Expand Up @@ -116,3 +127,59 @@ The `card_feedback` event closes the evaluation loop — it provides implicit gr
|-------|------|---------|-------------|
| `name` | string | `""` | Hospital or organisation name — displayed in `healthchain status` |
| `environment` | string | `development` | Deployment environment — `development`, `staging`, or `production` |

---

## `sources`

Declare FHIR data sources here. Credentials stay in environment variables — only source names and env prefixes are stored in config.

```yaml
sources:
medplum:
env_prefix: MEDPLUM # reads MEDPLUM_CLIENT_ID, MEDPLUM_BASE_URL, etc.
epic:
env_prefix: EPIC
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `<name>` | object | — | Arbitrary source name used in `gateway.search(..., source="<name>")` |
| `<name>.env_prefix` | string | — | Prefix for env vars: `{PREFIX}_CLIENT_ID`, `{PREFIX}_CLIENT_SECRET`, `{PREFIX}_BASE_URL`, `{PREFIX}_TOKEN_URL` |

With sources declared, use `FHIRGateway.from_config()` instead of `gateway.add_source()`:

```python
from healthchain.gateway import FHIRGateway
from healthchain.config.appconfig import AppConfig

gateway = FHIRGateway.from_config(AppConfig.load())
```

---

## `llm`

LLM provider settings for LangChain-based pipelines. API key is read from the standard environment variable for each provider (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, etc.).

```yaml
llm:
provider: anthropic
model: claude-opus-4-6
max_tokens: 512
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `provider` | string | `anthropic` | LLM provider — `anthropic`, `openai`, or `google` |
| `model` | string | `claude-opus-4-6` | Model ID passed to the LangChain chat model |
| `max_tokens` | int | `512` | Maximum tokens for model response |

Use `llm.to_langchain()` to instantiate the configured model:

```python
from healthchain.config.appconfig import AppConfig

config = AppConfig.load()
llm = config.llm.to_langchain() # returns ChatAnthropic / ChatOpenAI / ChatGoogleGenerativeAI
```
Loading
Loading