Skip to main content

Nodae BYOM SDK — NodaeBridge and NodaeModelAdapter for sponsor containers

Project description

nodae_bridge

Nodae BYOM SDK v1.0.4 — the bridge between your ML model and the Nodae federated healthcare platform by Intheris Health.

Overview

nodae_bridge is the Python package your Docker container uses when participating in federated training or inference across hospital sites. It provides:

  • NodaeBridge — file-based I/O helpers (/data/output)
  • NodaeModelAdapter — the interface your model class must implement
  • run.py — the container entrypoint dispatcher (python -m nodae_bridge.run)

Core principle: algorithms travel, data stays local. Patient data never leaves the hospital; your container receives a privacy-safe DataFrame and returns only model weights or aggregate statistics.

Installation

pip install nodae_bridge

Minimum Python version: 3.10. Add it alongside your ML framework in your Dockerfile:

RUN pip install nodae_bridge scikit-learn   # or torch, xgboost, etc.

Quick Start

from nodae_bridge import NodaeModelAdapter, ModelSpec, TrainingConfig, LocalTrainResult, InferenceResult
import pandas as pd

class MyModel(NodaeModelAdapter):

    def get_model_spec(self) -> ModelSpec:
        return ModelSpec(
            model_id="my-model-v1",
            name="My Federated Model",
            version="1.0.0",
            input_columns=["age", "length_of_stay", "drg_weight"],
            output_names=["risk_score"],
            min_samples=50,
        )

    def initialize(self, config: dict) -> None:
        pass

    def get_weights(self) -> bytes:
        return b""

    def set_weights(self, weights: bytes) -> None:
        pass

    def local_train(self, data: pd.DataFrame, round_number: int, config: TrainingConfig) -> LocalTrainResult:
        return LocalTrainResult(weights=self.get_weights(), sample_count=len(data), loss=0.0)

    def local_inference(self, data: pd.DataFrame) -> InferenceResult:
        return InferenceResult(prediction_distribution={"low": len(data)}, sample_count=len(data))

Your Dockerfile:

FROM python:3.11-slim
WORKDIR /app
RUN pip install nodae_bridge torch --index-url https://download.pytorch.org/whl/cpu
COPY model.py .
CMD ["python", "-m", "nodae_bridge.run"]

Data Schema

Your container receives local patient data at /data/input.parquet as a privacy-safe DataFrame. No PII is ever exposed.

Column Type Description
patient_id str Anonymized SHA-256 hash
age int Computed from DOB
gender str MALE / FEMALE / OTHER / UNKNOWN
admission_type str EMERGENCY / ELECTIVE / TRANSFER / AMBULATORY
discharge_disposition str HOME / TRANSFER / DECEASED / REHABILITATION
length_of_stay int Hospitalization days
primary_diagnosis str ICD-10 code
num_secondary_diagnoses int Count
drg_code str SwissDRG code
drg_weight float DRG cost weight
num_procedures int Count
num_medications int Count
num_lab_results int Count
insurance_type str Swiss insurance category

Always call fillna() before passing data to your model — not all columns are populated for every patient.

API Reference

Core I/O

Method Description
NodaeBridge.get_data() Load /data/input.parquet as a DataFrame
NodaeBridge.get_weights() Load global model weights; b"" on round 0
NodaeBridge.get_config() Load training/inference config dict
NodaeBridge.get_site_metadata() Convenience wrapper for config["site_metadata"]
NodaeBridge.save_weights(bytes) Write updated weights to /output/weights.bin (required)
NodaeBridge.save_metrics(dict) Write aggregate metrics to /output/metrics.json
NodaeBridge.log(str) Print timestamped message to stdout

Extended scope (byom_data_scope="extended")

Register with byom_data_scope="extended" to receive additional raw data files. Returns empty DataFrame/dict when absent (standard scope), so imports are always safe.

Method Returns Content
NodaeBridge.get_labs() DataFrame Per-result lab data: patient_id, loinc_code, test_name, value, unit, flag, date, …
NodaeBridge.get_vitals() DataFrame Latest vitals per patient: bp_systolic, heart_rate, temperature, weight_kg, …
NodaeBridge.get_procedures() DataFrame Per-procedure: patient_id, code, description, date, source
NodaeBridge.get_signals() dict Study-specific template signals: {patient_id: {signal_key: value}}

Feature engineering is the container's responsibility — the platform exposes raw data only.

FHIR scope (byom_data_scope="fhir")

Available when registered with byom_data_scope="fhir". The host writes one FHIR R4 Bundle per cohort patient under /data/fhir/. The standard input.parquet is always present alongside the bundles.

Method Returns Description
NodaeBridge.list_fhir_patients() list[str] Patient IDs (anonymized hashes) with FHIR bundles; reads index.json
NodaeBridge.get_fhir_bundle(patient_id) Optional[dict] Full FHIR R4 Bundle dict for one patient, or None

Each bundle contains: Patient (age, gender, LOS, DRG — no PHI), Conditions (ICD-10 + SNOMED), Observations (LOINC-coded labs and vitals), Procedures (CHOP), MedicationStatements, AllergyIntolerances, a Basic resource for template_signals, and an ImagingStudy reference when DICOM data is present.

for pid in NodaeBridge.list_fhir_patients():
    bundle = NodaeBridge.get_fhir_bundle(pid)
    entries = {e["resource"]["resourceType"]: e["resource"] for e in bundle["entry"]}
    # access any field directly — no platform-imposed field selection

SCAFFOLD (aggregation_strategy="scaffold")

Used when the study uses SCAFFOLD to correct client drift in non-IID populations.

Method Description
NodaeBridge.get_control_variates() Load global control variate from /data/control_variates.bin; b"" when not active
NodaeBridge.save_control_variate_delta(bytes) Write per-site delta to /output/control_variates.bin

config["scaffold_enabled"] is true when the host has sent a global control variate. If save_control_variate_delta() is not called, the aggregator falls back to FedAvg for this site (backward compatible).

Imaging (imaging_access=True)

Available when registered with imaging_access=True and the SA host has BYOM_DICOM_STORE_ENABLED=True. A read-only DICOM store is mounted at /data/imaging/.

Method Returns Description
NodaeBridge.get_imaging() Optional[Path] Path to /data/imaging/, or None if unavailable
NodaeBridge.list_imaging_series() list[dict] Manifest: patient_id, study_uid, modality, slice_count, path
import pydicom
from pathlib import Path

base = NodaeBridge.get_imaging()
for series in NodaeBridge.list_imaging_series():
    if series["modality"] != "CT":
        continue
    slices = sorted((base / series["path"]).glob("*.dcm"))
    datasets = [pydicom.dcmread(str(s)) for s in slices]
    # HU windowing, segmentation, feature extraction — container's responsibility

Changelog

1.0.5 (June 2026)

  • Added list_fhir_patients(), get_fhir_bundle() — FHIR R4 bundle access for byom_data_scope="fhir"
  • Added FHIR_PATH class constant

1.0.4 (June 2026)

  • Added get_imaging(), list_imaging_series() — DICOM store access
  • Updated get_site_metadata() docs to include imaging.* keys

1.0.3 (June 2026)

  • Added get_control_variates(), save_control_variate_delta() — SCAFFOLD support

1.0.2 (June 2026)

  • Added get_signals() — template signal access
  • Added get_labs(), get_vitals(), get_procedures() — extended data scope

1.0.1 (June 2026)

  • Added get_site_metadata() convenience wrapper

1.0.0 (June 2026)

  • Initial release: NodaeBridge, NodaeModelAdapter, run.py entrypoint

License

Proprietary — Intheris Health. Contact support@intheris-health.com for access. \x00

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nodae_bridge-1.0.5.tar.gz (15.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nodae_bridge-1.0.5-py3-none-any.whl (14.1 kB view details)

Uploaded Python 3

File details

Details for the file nodae_bridge-1.0.5.tar.gz.

File metadata

  • Download URL: nodae_bridge-1.0.5.tar.gz
  • Upload date:
  • Size: 15.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.0 {"installer":{"name":"uv","version":"0.11.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for nodae_bridge-1.0.5.tar.gz
Algorithm Hash digest
SHA256 caba747e22f70ab033dd430a53925408000639343cd2116fbe77a39c83292352
MD5 f03dfb7a5c89e705f435b7af698840bf
BLAKE2b-256 ed4781444fff6b9bd31ab77b854bb2513bba1bf894b2a930085b2143f152f64e

See more details on using hashes here.

File details

Details for the file nodae_bridge-1.0.5-py3-none-any.whl.

File metadata

  • Download URL: nodae_bridge-1.0.5-py3-none-any.whl
  • Upload date:
  • Size: 14.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.0 {"installer":{"name":"uv","version":"0.11.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for nodae_bridge-1.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 03dc5f2f8d5c8b6327ea8a3ddd1aa87acb64f5027d3e02138e32e749a6997a85
MD5 865863fa05e169812a93c2a9de9fc1e1
BLAKE2b-256 aae236131e51882f883374ddc0019b3cfcae6d3d09ee5b814d0f6b47160d9e0d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page