iints-sdk-python35 1.5.10__tar.gz → 1.5.12__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {iints_sdk_python35-1.5.10/src/iints_sdk_python35.egg-info → iints_sdk_python35-1.5.12}/PKG-INFO +3 -1
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/pyproject.toml +3 -1
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/__init__.py +4 -2
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/ai/assistant.py +3 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/ai/prompts.py +17 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/reporting.py +250 -69
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/api/base_algorithm.py +2 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/cli/cli.py +529 -22
- iints_sdk_python35-1.5.12/src/iints/core/algorithms/mpc_controller.py +207 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/devices/models.py +103 -15
- iints_sdk_python35-1.5.12/src/iints/core/digital_twin.py +168 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/patient/bergman_model.py +40 -16
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/patient/hovorka_model.py +162 -42
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/physiology_variation.py +39 -2
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/safety/config.py +6 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/simulator.py +240 -0
- iints_sdk_python35-1.5.12/src/iints/presets/evidence_sources.yaml +235 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/presets/presets.json +80 -49
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/__init__.py +30 -0
- iints_sdk_python35-1.5.12/src/iints/research/forecasting.py +679 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/predictor.py +8 -0
- iints_sdk_python35-1.5.12/src/iints/research/results_manager.py +535 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/utils/plotting.py +9 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12/src/iints_sdk_python35.egg-info}/PKG-INFO +3 -1
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints_sdk_python35.egg-info/SOURCES.txt +4 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints_sdk_python35.egg-info/requires.txt +2 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_bergman.py +17 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_onboarding.py +84 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_physiology_variation.py +27 -1
- iints_sdk_python35-1.5.10/src/iints/presets/evidence_sources.yaml +0 -123
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/LICENSE +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/LICENSE-MIT-IINTS-LEGACY +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/NOTICE +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/README.md +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/setup.cfg +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/ai/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/ai/backends/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/ai/backends/base.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/ai/backends/mistral_api.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/ai/backends/ollama.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/ai/cli.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/ai/mdmp_guard.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/ai/model_catalog.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/ai/prepare.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/algorithm_xray.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/baseline.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/booth_demo.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/carelink_workbench.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/clinical_benchmark.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/clinical_metrics.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/clinical_tir_analyzer.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/diabetes_metrics.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/edge_efficiency.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/edge_performance_monitor.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/eucys_results.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/evidence_bundle.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/explainability.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/explainable_ai.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/hardware_benchmark.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/metrics.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/population_report.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/poster.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/run_quality.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/safety_index.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/safety_visualizer.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/sensor_filtering.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/study_analysis.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/study_engine.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/study_experiment.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/study_poster.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/study_protocol.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/analysis/validator.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/api/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/api/registry.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/api/template_algorithm.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/assets/iints_logo.png +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/cli/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/cli/patient_cli.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/algorithms/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/algorithms/battle_runner.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/algorithms/clinical_baseline.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/algorithms/correction_bolus.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/algorithms/discovery.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/algorithms/fixed_basal_bolus.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/algorithms/hybrid_algorithm.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/algorithms/imitation_controller.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/algorithms/lstm_algorithm.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/algorithms/mock_algorithms.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/algorithms/neural_controller.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/algorithms/pid_controller.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/algorithms/standard_pump_algo.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/device.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/device_manager.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/devices/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/patient/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/patient/models.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/patient/patient_factory.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/patient/profile.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/safety/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/safety/input_validator.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/safety/supervisor.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/simulation/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/simulation/scenario_parser.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/core/supervisor.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/adapter.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/certify.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/column_mapper.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/contracts.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/datasets.json +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/demo/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/demo/demo_cgm.csv +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/evidence.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/guardians.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/importer.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/ingestor.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/mdmp_visualizer.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/medtronic_live.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/nightscout.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/physiology_residual_profiles.json +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/quality_checker.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/realism_dashboard.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/realism_governance.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/realism_reference.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/realism_references.json +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/realism_validator.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/registry.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/research_catalog.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/runner.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/study_corruption.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/synthetic_mirror.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/tidepool.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/universal_parser.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/virtual_patients/clinic_safe_baseline.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/virtual_patients/clinic_safe_hyper_challenge.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/virtual_patients/clinic_safe_hypo_prone.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/virtual_patients/clinic_safe_midnight.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/virtual_patients/clinic_safe_pizza.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/virtual_patients/clinic_safe_stress_meal.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/virtual_patients/default_patient.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/virtual_patients/patient_559_config.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/virtual_patients/reference_azt1d_t1d.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/virtual_patients/reference_free_living_t1d.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/data/virtual_patients/reference_hupa_ucm_t1d.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/demo_assets.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/emulation/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/emulation/legacy_base.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/emulation/medtronic_780g.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/emulation/omnipod_5.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/emulation/tandem_controliq.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/highlevel.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/jetson/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/jetson/endurance.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/jetson/research_pipeline.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/learning/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/learning/autonomous_optimizer.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/learning/learning_system.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/live_patient/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/live_patient/api.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/live_patient/daemon.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/live_patient/edge_benchmark.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/live_patient/edge_ops.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/live_patient/fpga.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/live_patient/long_study.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/live_patient/medtronic_direct.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/live_patient/pico_pump.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/live_patient/runtime.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/live_patient/service_export.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/live_patient/uno_q.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/mdmp/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/mdmp/backend.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/mdmp/eu_ai_pact.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/metrics.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/population/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/population/generator.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/population/runner.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/presets/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/presets/forecast_calibration_profiles.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/presets/golden_benchmark.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/presets/safety_contract_default.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/presets/validation_profiles.yaml +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/audit.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/calibration_gate.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/config.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/control.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/control_eval.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/data_blend.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/dataset.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/evaluation.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/local_ai.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/local_ai_gate.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/losses.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/metrics.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/model_registry.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/research/neural_control.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/scenarios/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/scenarios/generator.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/scenarios/study_pack.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/default_algorithm.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/demos/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/demos/live_stage_demo.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/pico_pump/README.md +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/pico_pump/code.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/pico_pump/serial_protocol.txt +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/scenarios/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/scenarios/chaos_insulin_stacking.json +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/scenarios/chaos_runaway_ai.json +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/scenarios/example_scenario.json +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/scenarios/exercise_stress.json +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/uno_q/README.md +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/templates/uno_q/iints_supervisor_bridge.ino +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/utils/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/utils/csv_safety.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/utils/run_io.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/utils/url_safety.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/validation/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/validation/golden.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/validation/replay.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/validation/run_doctor.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/validation/run_validation.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/validation/safety_contract.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/validation/schemas.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/visualization/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/visualization/cockpit.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints/visualization/uncertainty_cloud.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints_sdk_python35.egg-info/dependency_links.txt +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints_sdk_python35.egg-info/entry_points.txt +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/iints_sdk_python35.egg-info/top_level.txt +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_ai/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_ai/lineage.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/audit.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/bias_hooks.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/bundle.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/certification.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/cli.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/compare.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/conformance.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/contracts.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/crypto.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/data/conformance/vectors/delegation.json +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/data/conformance/vectors/fingerprint.json +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/data/conformance/vectors/grading.json +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/data/conformance/vectors/signing.json +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/delegate.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/diffing.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/drift.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/exceptions.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/fingerprint.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/fingerprint_store.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/hf.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/keys/mdmp_pub_v1.pem +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/llm_provenance.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/migrate.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/policy.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/prov.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/registry.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/runner.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/schema_export.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/synthetic.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/trust.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_core/visualizer.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_flavors/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_integrations/__init__.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_integrations/dvc.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_integrations/mlflow.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/src/mdmp_integrations/wandb.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_ci_governance.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_algorithm_loading.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_booth_demo.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_carelink_workbench.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_cloud_import_security.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_demo_export.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_demo_live.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_edge_runtime.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_expo_tools.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_fpga.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_patient_runtime.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_poster.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_research_workflows.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_cli_run_summary.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_install_doctor.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_jetson_endurance.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_plugin_system.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_population.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_presets_realism.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_research_realism_tools.py +0 -0
- {iints_sdk_python35-1.5.10 → iints_sdk_python35-1.5.12}/tests/test_simulator_calibration.py +0 -0
{iints_sdk_python35-1.5.10/src/iints_sdk_python35.egg-info → iints_sdk_python35-1.5.12}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iints-sdk-python35
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.12
|
|
4
4
|
Summary: A pre-clinical Edge-AI SDK for diabetes management validation.
|
|
5
5
|
Author-email: Rune Bobbaers <rune.bobbaers@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -34,6 +34,7 @@ Requires-Dist: fpdf2<3.0.0,>=2.8.0; extra == "reports"
|
|
|
34
34
|
Requires-Dist: matplotlib<4.0.0,>=3.5.0; extra == "reports"
|
|
35
35
|
Requires-Dist: openpyxl<4.0.0,>=3.0.0; extra == "reports"
|
|
36
36
|
Requires-Dist: pillow<13.0.0,>=12.1.1; extra == "reports"
|
|
37
|
+
Requires-Dist: SciencePlots<3.0.0,>=2.1.0; extra == "reports"
|
|
37
38
|
Requires-Dist: seaborn<1.0.0,>=0.11.0; extra == "reports"
|
|
38
39
|
Provides-Extra: full
|
|
39
40
|
Requires-Dist: fpdf2<3.0.0,>=2.8.0; extra == "full"
|
|
@@ -41,6 +42,7 @@ Requires-Dist: matplotlib<4.0.0,>=3.5.0; extra == "full"
|
|
|
41
42
|
Requires-Dist: openpyxl<4.0.0,>=3.0.0; extra == "full"
|
|
42
43
|
Requires-Dist: pyserial<4.0,>=3.5; extra == "full"
|
|
43
44
|
Requires-Dist: pillow<13.0.0,>=12.1.1; extra == "full"
|
|
45
|
+
Requires-Dist: SciencePlots<3.0.0,>=2.1.0; extra == "full"
|
|
44
46
|
Requires-Dist: seaborn<1.0.0,>=0.11.0; extra == "full"
|
|
45
47
|
Provides-Extra: dev
|
|
46
48
|
Requires-Dist: pytest<10.0.0,>=7.0.0; extra == "dev"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "iints-sdk-python35"
|
|
7
|
-
version = "1.5.
|
|
7
|
+
version = "1.5.12"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Rune Bobbaers", email="rune.bobbaers@gmail.com" },
|
|
10
10
|
]
|
|
@@ -44,6 +44,7 @@ reports = [
|
|
|
44
44
|
"matplotlib>=3.5.0,<4.0.0",
|
|
45
45
|
"openpyxl>=3.0.0,<4.0.0",
|
|
46
46
|
"pillow>=12.1.1,<13.0.0",
|
|
47
|
+
"SciencePlots>=2.1.0,<3.0.0",
|
|
47
48
|
"seaborn>=0.11.0,<1.0.0",
|
|
48
49
|
]
|
|
49
50
|
full = [
|
|
@@ -52,6 +53,7 @@ full = [
|
|
|
52
53
|
"openpyxl>=3.0.0,<4.0.0",
|
|
53
54
|
"pyserial>=3.5,<4.0",
|
|
54
55
|
"pillow>=12.1.1,<13.0.0",
|
|
56
|
+
"SciencePlots>=2.1.0,<3.0.0",
|
|
55
57
|
"seaborn>=0.11.0,<1.0.0",
|
|
56
58
|
]
|
|
57
59
|
dev = [
|
|
@@ -11,7 +11,7 @@ except ImportError: # pragma: no cover - Python < 3.8 fallback
|
|
|
11
11
|
try:
|
|
12
12
|
__version__ = version("iints-sdk-python35")
|
|
13
13
|
except PackageNotFoundError: # pragma: no cover - source tree fallback
|
|
14
|
-
__version__ = "1.5.
|
|
14
|
+
__version__ = "1.5.12"
|
|
15
15
|
|
|
16
16
|
# Note to developers: this SDK is currently maintained by a single author.
|
|
17
17
|
# Please report bugs via GitHub issues and feel free to contribute fixes via PRs.
|
|
@@ -237,9 +237,10 @@ def generate_agp_assets(
|
|
|
237
237
|
output_dir: Optional[str] = None,
|
|
238
238
|
subject_name: str = "Research simulation",
|
|
239
239
|
summary_json_path: Optional[str] = None,
|
|
240
|
+
export_svg: bool = True,
|
|
240
241
|
) -> Optional[dict]:
|
|
241
242
|
"""
|
|
242
|
-
Export AGP-style PNG assets and summary JSON from dense CGM/simulation data.
|
|
243
|
+
Export AGP-style PNG/SVG assets and summary JSON from dense CGM/simulation data.
|
|
243
244
|
"""
|
|
244
245
|
if output_dir is None:
|
|
245
246
|
return None
|
|
@@ -249,6 +250,7 @@ def generate_agp_assets(
|
|
|
249
250
|
output_dir,
|
|
250
251
|
subject_name=subject_name,
|
|
251
252
|
summary_json_path=summary_json_path,
|
|
253
|
+
export_svg=export_svg,
|
|
252
254
|
)
|
|
253
255
|
|
|
254
256
|
# You can also define __all__ to explicitly control what gets imported with `from iints import *`
|
|
@@ -133,3 +133,6 @@ class IINTSAssistant:
|
|
|
133
133
|
|
|
134
134
|
def review_realism(self, run: dict[str, Any]) -> AIResponse:
|
|
135
135
|
return self._run_task("review_realism", run)
|
|
136
|
+
|
|
137
|
+
def predict_insulin(self, payload: dict[str, Any]) -> AIResponse:
|
|
138
|
+
return self._run_task("predict_insulin", payload)
|
|
@@ -10,6 +10,7 @@ TaskName = Literal[
|
|
|
10
10
|
"detect_anomalies",
|
|
11
11
|
"generate_report",
|
|
12
12
|
"review_realism",
|
|
13
|
+
"predict_insulin",
|
|
13
14
|
]
|
|
14
15
|
MAX_PROMPT_PAYLOAD_CHARS = 12000
|
|
15
16
|
|
|
@@ -71,6 +72,22 @@ TASK_TEMPLATES: dict[TaskName, str] = {
|
|
|
71
72
|
"Focus on glycemic ranges, excursion patterns, insulin behavior, safety overrides, and whether the data looks internally coherent.\n\n"
|
|
72
73
|
"Input JSON:\n{data}"
|
|
73
74
|
),
|
|
75
|
+
"predict_insulin": (
|
|
76
|
+
"You are reviewing a simulated bi-hormonal (Insulin + Glucagon) dose candidate inside the IINTS-AF research sandbox.\n"
|
|
77
|
+
"You are not controlling a real pump, not treating a patient, and not giving medical advice.\n"
|
|
78
|
+
"You will be provided with the current biological state of the patient, which now includes deep science metrics like "
|
|
79
|
+
"active_insulin, insulin_effect, plasma_glucagon_pg_ml, and the haaf_metric (Hypoglycemia-Associated Autonomic Failure memory). "
|
|
80
|
+
"You will also see a mathematically optimal insulin dose calculated by a deterministic MPC solver running differential equations.\n\n"
|
|
81
|
+
"Your task is to critique the candidate and decide on both Insulin and Glucagon doses for research simulation only. "
|
|
82
|
+
"Never increase insulin above the deterministic MPC dose or safety caps. "
|
|
83
|
+
"If glucose is low, predicted low, falling quickly, or active insulin is high, reduce the insulin dose to 0.0. "
|
|
84
|
+
"If the patient is in severe hypoglycemia risk and HAAF is high (meaning natural rescue is failing), "
|
|
85
|
+
"you may propose a simulation-only glucagon rescue candidate. The simulator will still apply hard glucagon safety caps.\n"
|
|
86
|
+
"Respond with a short explanation followed by exactly this format:\n"
|
|
87
|
+
"FINAL_DOSE: <number>\n"
|
|
88
|
+
"FINAL_GLUCAGON_DOSE_MG: <number>\n\n"
|
|
89
|
+
"Input JSON:\n{data}"
|
|
90
|
+
),
|
|
74
91
|
}
|
|
75
92
|
|
|
76
93
|
|
|
@@ -3,21 +3,31 @@ import tempfile
|
|
|
3
3
|
import logging
|
|
4
4
|
import json
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Any, Dict, Optional
|
|
6
|
+
from typing import Any, Dict, List, Optional
|
|
7
7
|
|
|
8
8
|
os.environ.setdefault("MPLBACKEND", "Agg")
|
|
9
|
+
os.environ.setdefault("MPLCONFIGDIR", str(Path(tempfile.gettempdir()) / "iints-matplotlib"))
|
|
9
10
|
|
|
10
11
|
import matplotlib.pyplot as plt
|
|
11
12
|
import numpy as np
|
|
12
13
|
import pandas as pd
|
|
13
14
|
from fpdf import FPDF
|
|
14
15
|
from fpdf.enums import XPos, YPos
|
|
16
|
+
from matplotlib.patches import Patch
|
|
15
17
|
|
|
16
18
|
from iints.analysis.clinical_metrics import ClinicalMetricsCalculator
|
|
17
19
|
from iints.utils.plotting import apply_plot_style
|
|
18
20
|
|
|
19
21
|
logger = logging.getLogger("iints")
|
|
20
22
|
|
|
23
|
+
AGP_TIR_STACK = [
|
|
24
|
+
("very_low_lt_54", "Very Low", "<54 mg/dL", "#8B0000", "white"),
|
|
25
|
+
("low_54_69", "Low", "54-69 mg/dL", "#D32F2F", "white"),
|
|
26
|
+
("target_70_180", "Target", "70-180 mg/dL", "#4CAF50", "black"),
|
|
27
|
+
("high_181_250", "High", "181-250 mg/dL", "#FFD54F", "black"),
|
|
28
|
+
("very_high_gt_250", "Very High", ">250 mg/dL", "#F57C00", "black"),
|
|
29
|
+
]
|
|
30
|
+
|
|
21
31
|
|
|
22
32
|
class ClinicalReportGenerator:
|
|
23
33
|
"""Generate a clean, publication-ready PDF report."""
|
|
@@ -170,6 +180,7 @@ class ClinicalReportGenerator:
|
|
|
170
180
|
*,
|
|
171
181
|
target_low: float,
|
|
172
182
|
target_high: float,
|
|
183
|
+
svg_path: Optional[Path] = None,
|
|
173
184
|
) -> None:
|
|
174
185
|
apply_plot_style()
|
|
175
186
|
step = max(1, int(round(self._infer_step_minutes(df))))
|
|
@@ -187,37 +198,78 @@ class ClinicalReportGenerator:
|
|
|
187
198
|
p75 = q[0.75].to_numpy(dtype=float)
|
|
188
199
|
p95 = q[0.95].to_numpy(dtype=float)
|
|
189
200
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
sns.set_style("whitegrid")
|
|
201
|
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4.6), gridspec_kw={"width_ratios": [4.5, 1.4]})
|
|
193
202
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
plt.axhspan(target_low, target_high, color="#2E7D32", alpha=0.08)
|
|
199
|
-
plt.axhline(target_low, color="#424242", linestyle="--", linewidth=1.0)
|
|
200
|
-
plt.axhline(target_high, color="#424242", linestyle="--", linewidth=1.0)
|
|
203
|
+
# Panel 1: AGP Curve
|
|
204
|
+
ax1.fill_between(x, p05, p95, color="#D0D0D0", label="5-95%", alpha=0.5, linewidth=0)
|
|
205
|
+
ax1.fill_between(x, p25, p75, color="#A0A0A0", label="25-75%", alpha=0.8, linewidth=0)
|
|
206
|
+
ax1.plot(x, p50, color="#103b5c", linewidth=2.5, label="Median")
|
|
201
207
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
ax.spines['left'].set_color('#333333')
|
|
206
|
-
ax.spines['bottom'].set_color('#333333')
|
|
208
|
+
ax1.axhspan(target_low, target_high, color="#2ca02c", alpha=0.1)
|
|
209
|
+
ax1.axhline(target_low, color="#2ca02c", linestyle=":", linewidth=1)
|
|
210
|
+
ax1.axhline(target_high, color="#2ca02c", linestyle=":", linewidth=1)
|
|
207
211
|
|
|
208
|
-
|
|
212
|
+
ax1.set_xlim(0, 24)
|
|
209
213
|
ymax = max(350.0, float(np.nanmax(p95)) + 20.0)
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
+
ax1.set_ylim(40, ymax)
|
|
215
|
+
ax1.set_xticks([0, 3, 6, 9, 12, 15, 18, 21, 24])
|
|
216
|
+
ax1.set_xticklabels(["12a", "3a", "6a", "9a", "12p", "3p", "6p", "9p", "12a"])
|
|
217
|
+
ax1.set_ylabel("Glucose (mg/dL)", fontweight="bold")
|
|
214
218
|
|
|
215
|
-
|
|
216
|
-
|
|
219
|
+
report_day_count = int(max(1, df["day_index"].nunique()))
|
|
220
|
+
title = "Single-Day Glucose Profile" if report_day_count < 2 else "Ambulatory Glucose Profile (AGP)"
|
|
221
|
+
ax1.set_title(title, fontweight="bold")
|
|
217
222
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
223
|
+
# Panel 2: TIR Bar
|
|
224
|
+
summary = self._agp_summary(df, target_low=target_low, target_high=target_high)
|
|
225
|
+
pct_map = summary["time_ranges_pct"]
|
|
226
|
+
bottom = 0.0
|
|
227
|
+
legend_handles = []
|
|
228
|
+
for key, label, range_text, color, text_color in AGP_TIR_STACK:
|
|
229
|
+
val = float(pct_map.get(key, 0.0))
|
|
230
|
+
legend_handles.append(
|
|
231
|
+
Patch(
|
|
232
|
+
facecolor=color,
|
|
233
|
+
edgecolor="none",
|
|
234
|
+
label=f"{label} ({range_text}) {val:.0f}%",
|
|
235
|
+
)
|
|
236
|
+
)
|
|
237
|
+
if val > 0:
|
|
238
|
+
ax2.bar([0], [val], bottom=[bottom], color=color, width=0.48)
|
|
239
|
+
if val >= 6:
|
|
240
|
+
ax2.text(
|
|
241
|
+
0,
|
|
242
|
+
bottom + val / 2.0,
|
|
243
|
+
f"{val:.0f}%",
|
|
244
|
+
ha="center",
|
|
245
|
+
va="center",
|
|
246
|
+
color=text_color,
|
|
247
|
+
fontweight="bold",
|
|
248
|
+
fontsize=9,
|
|
249
|
+
)
|
|
250
|
+
bottom += val
|
|
251
|
+
|
|
252
|
+
ax2.set_ylim(0, 100)
|
|
253
|
+
ax2.set_xlim(-0.5, 0.5)
|
|
254
|
+
ax2.set_xticks([0])
|
|
255
|
+
ax2.set_xticklabels(["TIR"])
|
|
256
|
+
ax2.set_yticks([0, 25, 50, 75, 100])
|
|
257
|
+
ax2.set_ylabel("% Time", fontweight="bold")
|
|
258
|
+
ax2.set_title("Time in Range", fontweight="bold")
|
|
259
|
+
ax2.legend(
|
|
260
|
+
handles=list(reversed(legend_handles)),
|
|
261
|
+
loc="center left",
|
|
262
|
+
bbox_to_anchor=(1.02, 0.5),
|
|
263
|
+
frameon=False,
|
|
264
|
+
fontsize=7,
|
|
265
|
+
borderaxespad=0.0,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
fig.tight_layout()
|
|
269
|
+
fig.savefig(output_path, dpi=600, bbox_inches="tight")
|
|
270
|
+
if svg_path is not None:
|
|
271
|
+
fig.savefig(svg_path, format="svg", bbox_inches="tight")
|
|
272
|
+
plt.close(fig)
|
|
221
273
|
|
|
222
274
|
def _plot_daily_profiles(
|
|
223
275
|
self,
|
|
@@ -227,14 +279,21 @@ class ClinicalReportGenerator:
|
|
|
227
279
|
target_low: float,
|
|
228
280
|
target_high: float,
|
|
229
281
|
max_days: int = 14,
|
|
282
|
+
svg_path: Optional[Path] = None,
|
|
230
283
|
) -> None:
|
|
231
284
|
apply_plot_style()
|
|
232
285
|
day_ids = sorted(df["day_index"].unique().tolist())[:max_days]
|
|
233
286
|
if not day_ids:
|
|
234
287
|
day_ids = [0]
|
|
235
|
-
|
|
288
|
+
# A single-day AGP should not render as one tiny panel in a 7-day grid.
|
|
289
|
+
# Keep the 7-column layout for longer reports, but let short reports breathe.
|
|
290
|
+
if len(day_ids) <= 3:
|
|
291
|
+
cols = len(day_ids)
|
|
292
|
+
else:
|
|
293
|
+
cols = 7
|
|
236
294
|
rows = int(np.ceil(len(day_ids) / cols))
|
|
237
|
-
|
|
295
|
+
fig_height = max(1.9, rows * 1.45 if cols >= 7 else 2.35)
|
|
296
|
+
fig, axes = plt.subplots(rows, cols, figsize=(10, fig_height), squeeze=False)
|
|
238
297
|
for ax in axes.ravel():
|
|
239
298
|
ax.axis("off")
|
|
240
299
|
|
|
@@ -262,45 +321,94 @@ class ClinicalReportGenerator:
|
|
|
262
321
|
ax.spines['bottom'].set_color("#888888")
|
|
263
322
|
ax.spines['bottom'].set_linewidth(0.5)
|
|
264
323
|
|
|
265
|
-
fig.
|
|
266
|
-
fig.
|
|
267
|
-
|
|
324
|
+
fig.tight_layout()
|
|
325
|
+
fig.savefig(output_path, dpi=600, bbox_inches="tight")
|
|
326
|
+
if svg_path is not None:
|
|
327
|
+
fig.savefig(svg_path, format="svg", bbox_inches="tight")
|
|
268
328
|
plt.close(fig)
|
|
269
329
|
|
|
270
330
|
@staticmethod
|
|
271
|
-
def
|
|
272
|
-
|
|
331
|
+
def _extract_xai_events(df: pd.DataFrame) -> List[Dict[str, Any]]:
|
|
332
|
+
"""Extract explainable-event strings into a structured export list."""
|
|
333
|
+
if "explainable_events" not in df.columns:
|
|
334
|
+
return []
|
|
335
|
+
|
|
336
|
+
events: List[Dict[str, Any]] = []
|
|
337
|
+
for row_index, row in df.dropna(subset=["explainable_events"]).iterrows():
|
|
338
|
+
raw_events = row.get("explainable_events")
|
|
339
|
+
if isinstance(raw_events, str):
|
|
340
|
+
parts = [part.strip() for part in raw_events.split(";") if part.strip()]
|
|
341
|
+
elif isinstance(raw_events, (list, tuple)):
|
|
342
|
+
parts = [str(part).strip() for part in raw_events if str(part).strip()]
|
|
343
|
+
else:
|
|
344
|
+
continue
|
|
345
|
+
|
|
346
|
+
time_minutes = row.get("time_minutes")
|
|
347
|
+
try:
|
|
348
|
+
normalized_time = None if pd.isna(time_minutes) else float(time_minutes)
|
|
349
|
+
except (TypeError, ValueError):
|
|
350
|
+
normalized_time = None
|
|
351
|
+
|
|
352
|
+
for event in parts:
|
|
353
|
+
events.append(
|
|
354
|
+
{
|
|
355
|
+
"row_index": str(row_index),
|
|
356
|
+
"time_minutes": normalized_time,
|
|
357
|
+
"event": event,
|
|
358
|
+
}
|
|
359
|
+
)
|
|
360
|
+
return events
|
|
361
|
+
|
|
362
|
+
@staticmethod
|
|
363
|
+
def _section_header(pdf: FPDF, title: str, width: float = 0) -> None:
|
|
364
|
+
pdf.set_fill_color(35, 55, 67)
|
|
273
365
|
pdf.set_text_color(255, 255, 255)
|
|
274
366
|
pdf.set_font("Helvetica", "B", 9)
|
|
275
|
-
pdf.cell(
|
|
276
|
-
pdf.set_text_color(
|
|
367
|
+
pdf.cell(width, 5.5, title, fill=True, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
|
|
368
|
+
pdf.set_text_color(25, 35, 43)
|
|
277
369
|
|
|
278
370
|
@staticmethod
|
|
279
371
|
def _range_bar(pdf: FPDF, x: float, y: float, width: float, height: float, summary: Dict[str, Any]) -> None:
|
|
280
372
|
ranges = [
|
|
281
|
-
("very_high_gt_250", (
|
|
282
|
-
("high_181_250", (
|
|
283
|
-
("target_70_180", (
|
|
284
|
-
("low_54_69", (
|
|
285
|
-
("very_low_lt_54", (
|
|
373
|
+
("very_high_gt_250", (230, 126, 34), "Very High", ">250 mg/dL"),
|
|
374
|
+
("high_181_250", (248, 200, 48), "High", "181-250 mg/dL"),
|
|
375
|
+
("target_70_180", (86, 160, 88), "Target Range", "70-180 mg/dL"),
|
|
376
|
+
("low_54_69", (204, 57, 57), "Low", "54-69 mg/dL"),
|
|
377
|
+
("very_low_lt_54", (126, 29, 33), "Very Low", "<54 mg/dL"),
|
|
286
378
|
]
|
|
287
|
-
current_y = y
|
|
288
379
|
total_h = height
|
|
289
380
|
pct_map = summary["time_ranges_pct"]
|
|
290
|
-
|
|
291
|
-
|
|
381
|
+
|
|
382
|
+
current_y = y
|
|
383
|
+
for key, color, _label, _range_text in ranges:
|
|
292
384
|
pct = float(pct_map.get(key, 0.0))
|
|
293
|
-
part_h =
|
|
385
|
+
part_h = total_h * pct / 100.0
|
|
294
386
|
pdf.set_fill_color(*color)
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
pdf.set_font("Helvetica", "", 8)
|
|
298
|
-
minutes = summary["time_ranges_minutes"].get(key, 0.0)
|
|
299
|
-
pdf.cell(0, 4, f"{label}: {pct:.0f}% ({ClinicalReportGenerator._format_duration(minutes)})")
|
|
387
|
+
if part_h > 0:
|
|
388
|
+
pdf.rect(x, current_y, width, part_h, style="F")
|
|
300
389
|
current_y += part_h
|
|
301
|
-
pdf.set_draw_color(
|
|
390
|
+
pdf.set_draw_color(85, 95, 103)
|
|
302
391
|
pdf.rect(x, y, width, height)
|
|
303
392
|
|
|
393
|
+
label_x = x + width + 7
|
|
394
|
+
row_y = y - 1
|
|
395
|
+
pdf.set_font("Helvetica", "", 7.3)
|
|
396
|
+
for idx, (key, color, label, range_text) in enumerate(ranges):
|
|
397
|
+
pct = float(pct_map.get(key, 0.0))
|
|
398
|
+
minutes = float(summary["time_ranges_minutes"].get(key, 0.0))
|
|
399
|
+
line_y = row_y + idx * 10.8
|
|
400
|
+
pdf.set_fill_color(*color)
|
|
401
|
+
pdf.rect(label_x, line_y + 1.4, 3.4, 3.4, style="F")
|
|
402
|
+
pdf.set_xy(label_x + 5, line_y)
|
|
403
|
+
pdf.set_font("Helvetica", "B", 7.3)
|
|
404
|
+
pdf.cell(24, 3.6, label)
|
|
405
|
+
pdf.set_font("Helvetica", "", 7.0)
|
|
406
|
+
pdf.cell(22, 3.6, range_text)
|
|
407
|
+
pdf.set_font("Helvetica", "B", 7.3)
|
|
408
|
+
pdf.cell(12, 3.6, f"{pct:.0f}%", align="R")
|
|
409
|
+
pdf.set_font("Helvetica", "", 6.8)
|
|
410
|
+
pdf.cell(0, 3.6, f" ({ClinicalReportGenerator._format_duration(minutes)})")
|
|
411
|
+
|
|
304
412
|
def generate_agp_pdf(
|
|
305
413
|
self,
|
|
306
414
|
simulation_data: pd.DataFrame,
|
|
@@ -337,19 +445,44 @@ class ClinicalReportGenerator:
|
|
|
337
445
|
pdf.add_page()
|
|
338
446
|
pdf.set_margins(8, 8, 8)
|
|
339
447
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
pdf.
|
|
344
|
-
|
|
345
|
-
pdf.
|
|
346
|
-
pdf.
|
|
448
|
+
header_y = 8
|
|
449
|
+
title_w = 121
|
|
450
|
+
meta_x = 134
|
|
451
|
+
pdf.set_xy(8, header_y)
|
|
452
|
+
title_size = 15 if len(title) <= 72 else 13
|
|
453
|
+
pdf.set_text_color(25, 35, 43)
|
|
454
|
+
pdf.set_font("Helvetica", "B", title_size)
|
|
455
|
+
pdf.multi_cell(title_w, 6.2, title, align="L")
|
|
456
|
+
title_bottom = pdf.get_y()
|
|
457
|
+
|
|
458
|
+
pdf.set_xy(meta_x, header_y)
|
|
459
|
+
pdf.set_font("Helvetica", "B", 8)
|
|
460
|
+
pdf.set_text_color(25, 35, 43)
|
|
461
|
+
pdf.cell(0, 4, "Name", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
|
|
462
|
+
pdf.set_xy(meta_x, header_y + 4.5)
|
|
463
|
+
pdf.set_font("Helvetica", "", 7.2)
|
|
464
|
+
pdf.multi_cell(64, 3.5, subject_name)
|
|
465
|
+
meta_bottom = pdf.get_y()
|
|
466
|
+
pdf.set_xy(meta_x, max(meta_bottom + 1.5, header_y + 12))
|
|
467
|
+
pdf.set_font("Helvetica", "B", 8)
|
|
468
|
+
pdf.cell(0, 4, "Report type", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
|
|
469
|
+
pdf.set_xy(meta_x, pdf.get_y())
|
|
470
|
+
pdf.set_font("Helvetica", "", 7.2)
|
|
471
|
+
pdf.multi_cell(64, 3.5, "Research simulation / educational")
|
|
472
|
+
meta_bottom = pdf.get_y()
|
|
473
|
+
|
|
474
|
+
header_bottom = max(title_bottom, meta_bottom, header_y + 23)
|
|
475
|
+
pdf.set_draw_color(170, 181, 188)
|
|
476
|
+
pdf.line(8, header_bottom + 1.5, 202, header_bottom + 1.5)
|
|
477
|
+
pdf.set_y(header_bottom + 5)
|
|
347
478
|
|
|
348
479
|
left_x = 8
|
|
349
480
|
right_x = 112
|
|
481
|
+
left_w = 98
|
|
482
|
+
right_w = 90
|
|
350
483
|
top_y = pdf.get_y()
|
|
351
484
|
pdf.set_xy(left_x, top_y)
|
|
352
|
-
self._section_header(pdf, "GLUCOSE STATISTICS AND TARGETS")
|
|
485
|
+
self._section_header(pdf, "GLUCOSE STATISTICS AND TARGETS", left_w)
|
|
353
486
|
pdf.set_font("Helvetica", "", 8)
|
|
354
487
|
pdf.cell(0, 5, f"Report period: {summary['report_days']} day(s)", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
|
|
355
488
|
pdf.cell(0, 5, f"Time CGM/simulation active: {summary['data_active_pct']:.1f}%", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
|
|
@@ -382,22 +515,36 @@ class ClinicalReportGenerator:
|
|
|
382
515
|
pdf.cell(0, 5, str(safety_report.get("bolus_interventions_count", 0)), new_x=XPos.LMARGIN, new_y=YPos.NEXT)
|
|
383
516
|
|
|
384
517
|
pdf.set_xy(right_x, top_y)
|
|
385
|
-
self._section_header(pdf, "TIME IN RANGES")
|
|
386
|
-
self._range_bar(pdf, right_x +
|
|
518
|
+
self._section_header(pdf, "TIME IN RANGES", right_w)
|
|
519
|
+
self._range_bar(pdf, right_x + 3, top_y + 12, 13, 55, summary)
|
|
387
520
|
|
|
388
|
-
|
|
521
|
+
agp_y = max(100, top_y + 74)
|
|
522
|
+
pdf.set_xy(8, agp_y)
|
|
389
523
|
self._section_header(pdf, "AMBULATORY GLUCOSE PROFILE (AGP-STYLE)")
|
|
390
524
|
pdf.set_font("Helvetica", "", 7)
|
|
525
|
+
if summary["report_days"] < 2:
|
|
526
|
+
agp_note = (
|
|
527
|
+
"Single-day AGP-style view: percentile bands collapse toward the visible trace. "
|
|
528
|
+
"Use multi-day CGM/simulation data for a full AGP percentile profile."
|
|
529
|
+
)
|
|
530
|
+
else:
|
|
531
|
+
agp_note = (
|
|
532
|
+
"AGP-style summary of glucose values over the report period, with median (50%) "
|
|
533
|
+
"and percentile bands shown as a single modal day."
|
|
534
|
+
)
|
|
391
535
|
pdf.multi_cell(
|
|
392
536
|
0,
|
|
393
537
|
4,
|
|
394
|
-
|
|
538
|
+
agp_note,
|
|
395
539
|
)
|
|
396
|
-
pdf.
|
|
540
|
+
agp_image_y = pdf.get_y() + 2
|
|
541
|
+
pdf.image(str(agp_plot), x=12, y=agp_image_y, w=186)
|
|
397
542
|
|
|
398
|
-
|
|
543
|
+
daily_y = agp_image_y + 78
|
|
544
|
+
pdf.set_xy(8, daily_y)
|
|
399
545
|
self._section_header(pdf, "DAILY GLUCOSE PROFILES")
|
|
400
|
-
pdf.
|
|
546
|
+
daily_image_y = pdf.get_y() + 4
|
|
547
|
+
pdf.image(str(daily_plot), x=10, y=daily_image_y, w=190)
|
|
401
548
|
|
|
402
549
|
pdf.set_xy(8, 285)
|
|
403
550
|
pdf.set_font("Helvetica", "I", 7)
|
|
@@ -420,8 +567,9 @@ class ClinicalReportGenerator:
|
|
|
420
567
|
target_low: float = 70.0,
|
|
421
568
|
target_high: float = 180.0,
|
|
422
569
|
summary_json_path: Optional[str] = None,
|
|
570
|
+
export_svg: bool = True,
|
|
423
571
|
) -> Dict[str, str]:
|
|
424
|
-
"""Export AGP-style
|
|
572
|
+
"""Export AGP-style PNG/SVG assets and summary JSON without creating a PDF."""
|
|
425
573
|
output_path = Path(output_dir)
|
|
426
574
|
output_path.mkdir(parents=True, exist_ok=True)
|
|
427
575
|
df = self._prepare_agp_frame(simulation_data)
|
|
@@ -430,18 +578,51 @@ class ClinicalReportGenerator:
|
|
|
430
578
|
|
|
431
579
|
agp_plot = output_path / "agp_profile.png"
|
|
432
580
|
daily_plot = output_path / "daily_profiles.png"
|
|
581
|
+
agp_svg = output_path / "agp_profile.svg" if export_svg else None
|
|
582
|
+
daily_svg = output_path / "daily_profiles.svg" if export_svg else None
|
|
433
583
|
summary_file = Path(summary_json_path) if summary_json_path else output_path / "agp_summary.json"
|
|
434
584
|
summary_file.parent.mkdir(parents=True, exist_ok=True)
|
|
435
585
|
|
|
436
|
-
self._plot_agp_profile(
|
|
437
|
-
|
|
586
|
+
self._plot_agp_profile(
|
|
587
|
+
df,
|
|
588
|
+
agp_plot,
|
|
589
|
+
target_low=target_low,
|
|
590
|
+
target_high=target_high,
|
|
591
|
+
svg_path=agp_svg,
|
|
592
|
+
)
|
|
593
|
+
self._plot_daily_profiles(
|
|
594
|
+
df,
|
|
595
|
+
daily_plot,
|
|
596
|
+
target_low=target_low,
|
|
597
|
+
target_high=target_high,
|
|
598
|
+
svg_path=daily_svg,
|
|
599
|
+
)
|
|
438
600
|
summary_file.write_text(json.dumps(summary, indent=2), encoding="utf-8")
|
|
439
601
|
|
|
440
|
-
|
|
602
|
+
xai_file = output_path / "xai_events.txt"
|
|
603
|
+
xai_json_file = output_path / "xai_events.json"
|
|
604
|
+
xai_events = self._extract_xai_events(df)
|
|
605
|
+
|
|
606
|
+
with open(xai_file, "w", encoding="utf-8") as f:
|
|
607
|
+
f.write("=== IINTS Explainable AI (XAI) Events Log ===\n")
|
|
608
|
+
if xai_events:
|
|
609
|
+
for entry in xai_events:
|
|
610
|
+
f.write(f"- {entry['event']}\n")
|
|
611
|
+
else:
|
|
612
|
+
f.write("No significant XAI events detected.\n")
|
|
613
|
+
xai_json_file.write_text(json.dumps(xai_events, indent=2), encoding="utf-8")
|
|
614
|
+
|
|
615
|
+
outputs = {
|
|
441
616
|
"agp_profile_png": str(agp_plot),
|
|
442
617
|
"daily_profiles_png": str(daily_plot),
|
|
443
618
|
"summary_json": str(summary_file),
|
|
619
|
+
"xai_events_txt": str(xai_file),
|
|
620
|
+
"xai_events_json": str(xai_json_file),
|
|
444
621
|
}
|
|
622
|
+
if agp_svg is not None and daily_svg is not None:
|
|
623
|
+
outputs["agp_profile_svg"] = str(agp_svg)
|
|
624
|
+
outputs["daily_profiles_svg"] = str(daily_svg)
|
|
625
|
+
return outputs
|
|
445
626
|
|
|
446
627
|
def export_plots(self, simulation_data: pd.DataFrame, output_dir: str) -> Dict[str, str]:
|
|
447
628
|
output_path = Path(output_dir)
|
|
@@ -56,6 +56,7 @@ class AlgorithmMetadata:
|
|
|
56
56
|
class AlgorithmResult:
|
|
57
57
|
"""Result of an insulin prediction with uncertainty"""
|
|
58
58
|
total_insulin_delivered: float
|
|
59
|
+
total_glucagon_delivered_mg: float = 0.0
|
|
59
60
|
bolus_insulin: float = 0.0
|
|
60
61
|
basal_insulin: float = 0.0
|
|
61
62
|
correction_bolus: float = 0.0
|
|
@@ -77,6 +78,7 @@ class AlgorithmResult:
|
|
|
77
78
|
def to_dict(self) -> Dict:
|
|
78
79
|
return {
|
|
79
80
|
'total_insulin_delivered': self.total_insulin_delivered,
|
|
81
|
+
'total_glucagon_delivered_mg': self.total_glucagon_delivered_mg,
|
|
80
82
|
'bolus_insulin': self.bolus_insulin,
|
|
81
83
|
'basal_insulin': self.basal_insulin,
|
|
82
84
|
'correction_bolus': self.correction_bolus,
|