iints-sdk-python35 0.1.7__tar.gz → 0.1.9__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.
Files changed (100) hide show
  1. {iints_sdk_python35-0.1.7/src/iints_sdk_python35.egg-info → iints_sdk_python35-0.1.9}/PKG-INFO +17 -3
  2. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/README.md +16 -2
  3. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/pyproject.toml +2 -1
  4. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/__init__.py +1 -1
  5. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/reporting.py +109 -25
  6. iints_sdk_python35-0.1.9/src/iints/assets/iints_logo.png +0 -0
  7. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/cli/cli.py +12 -5
  8. iints_sdk_python35-0.1.9/src/iints/templates/default_algorithm.py +91 -0
  9. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9/src/iints_sdk_python35.egg-info}/PKG-INFO +17 -3
  10. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints_sdk_python35.egg-info/SOURCES.txt +1 -0
  11. iints_sdk_python35-0.1.7/src/iints/templates/default_algorithm.py +0 -56
  12. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/LICENSE +0 -0
  13. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/setup.cfg +0 -0
  14. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/__init__.py +0 -0
  15. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/algorithm_xray.py +0 -0
  16. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/baseline.py +0 -0
  17. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/clinical_benchmark.py +0 -0
  18. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/clinical_metrics.py +0 -0
  19. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/clinical_tir_analyzer.py +0 -0
  20. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/diabetes_metrics.py +0 -0
  21. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/edge_performance_monitor.py +0 -0
  22. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/explainability.py +0 -0
  23. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/explainable_ai.py +0 -0
  24. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/hardware_benchmark.py +0 -0
  25. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/metrics.py +0 -0
  26. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/sensor_filtering.py +0 -0
  27. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/analysis/validator.py +0 -0
  28. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/api/__init__.py +0 -0
  29. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/api/base_algorithm.py +0 -0
  30. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/api/template_algorithm.py +0 -0
  31. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/cli/__init__.py +0 -0
  32. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/__init__.py +0 -0
  33. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/algorithms/__init__.py +0 -0
  34. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/algorithms/battle_runner.py +0 -0
  35. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/algorithms/correction_bolus.py +0 -0
  36. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/algorithms/discovery.py +0 -0
  37. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/algorithms/fixed_basal_bolus.py +0 -0
  38. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/algorithms/hybrid_algorithm.py +0 -0
  39. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/algorithms/lstm_algorithm.py +0 -0
  40. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/algorithms/mock_algorithms.py +0 -0
  41. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/algorithms/pid_controller.py +0 -0
  42. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/algorithms/standard_pump_algo.py +0 -0
  43. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/device.py +0 -0
  44. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/device_manager.py +0 -0
  45. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/devices/__init__.py +0 -0
  46. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/devices/models.py +0 -0
  47. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/patient/__init__.py +0 -0
  48. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/patient/models.py +0 -0
  49. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/patient/patient_factory.py +0 -0
  50. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/patient/profile.py +0 -0
  51. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/safety/__init__.py +0 -0
  52. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/safety/input_validator.py +0 -0
  53. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/safety/supervisor.py +0 -0
  54. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/simulation/__init__.py +0 -0
  55. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/simulation/scenario_parser.py +0 -0
  56. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/simulator.py +0 -0
  57. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/core/supervisor.py +0 -0
  58. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/__init__.py +0 -0
  59. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/adapter.py +0 -0
  60. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/column_mapper.py +0 -0
  61. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/demo/__init__.py +0 -0
  62. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/demo/demo_cgm.csv +0 -0
  63. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/importer.py +0 -0
  64. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/ingestor.py +0 -0
  65. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/quality_checker.py +0 -0
  66. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/universal_parser.py +0 -0
  67. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/virtual_patients/clinic_safe_baseline.yaml +0 -0
  68. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/virtual_patients/clinic_safe_hyper_challenge.yaml +0 -0
  69. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/virtual_patients/clinic_safe_hypo_prone.yaml +0 -0
  70. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/virtual_patients/clinic_safe_midnight.yaml +0 -0
  71. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/virtual_patients/clinic_safe_pizza.yaml +0 -0
  72. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/virtual_patients/clinic_safe_stress_meal.yaml +0 -0
  73. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/virtual_patients/default_patient.yaml +0 -0
  74. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/data/virtual_patients/patient_559_config.yaml +0 -0
  75. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/emulation/__init__.py +0 -0
  76. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/emulation/legacy_base.py +0 -0
  77. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/emulation/medtronic_780g.py +0 -0
  78. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/emulation/omnipod_5.py +0 -0
  79. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/emulation/tandem_controliq.py +0 -0
  80. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/highlevel.py +0 -0
  81. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/learning/__init__.py +0 -0
  82. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/learning/autonomous_optimizer.py +0 -0
  83. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/learning/learning_system.py +0 -0
  84. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/metrics.py +0 -0
  85. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/presets/__init__.py +0 -0
  86. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/presets/presets.json +0 -0
  87. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/templates/__init__.py +0 -0
  88. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/templates/scenarios/__init__.py +0 -0
  89. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/templates/scenarios/example_scenario.json +0 -0
  90. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/utils/__init__.py +0 -0
  91. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/utils/plotting.py +0 -0
  92. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/validation/__init__.py +0 -0
  93. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/validation/schemas.py +0 -0
  94. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/visualization/__init__.py +0 -0
  95. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/visualization/cockpit.py +0 -0
  96. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints/visualization/uncertainty_cloud.py +0 -0
  97. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints_sdk_python35.egg-info/dependency_links.txt +0 -0
  98. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints_sdk_python35.egg-info/entry_points.txt +0 -0
  99. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints_sdk_python35.egg-info/requires.txt +0 -0
  100. {iints_sdk_python35-0.1.7 → iints_sdk_python35-0.1.9}/src/iints_sdk_python35.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iints-sdk-python35
3
- Version: 0.1.7
3
+ Version: 0.1.9
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
  Project-URL: Homepage, https://github.com/python35/IINTS-SDK
@@ -33,10 +33,15 @@ Provides-Extra: torch
33
33
  Requires-Dist: torch>=1.9.0; extra == "torch"
34
34
  Dynamic: license-file
35
35
 
36
- # IINTS-AF SDK (v0.1.5)
36
+ # IINTS-AF SDK
37
+ [![PyPI version](https://badge.fury.io/py/iints-sdk-python35.svg)](https://badge.fury.io/py/iints-sdk-python35)
37
38
  [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/python35/IINTS-SDK/blob/main/examples/notebooks/00_Quickstart.ipynb)
38
39
  [![Python Package CI](https://github.com/python35/IINTS-SDK/actions/workflows/python-package.yml/badge.svg)](https://github.com/python35/IINTS-SDK/actions/workflows/python-package.yml)
39
40
 
41
+ <div style="text-align:center;">
42
+ <img src="Ontwerp zonder titel.png" alt="" style="display:block; margin:0 auto;">
43
+ </div>
44
+
40
45
  ## Intelligent Insulin Titration System for Artificial Pancreas
41
46
 
42
47
  IINTS-AF is a **safety-first simulation and validation platform** for insulin dosing algorithms. It lets you test AI or classical controllers on virtual patients, enforce deterministic safety constraints, and generate audit-ready clinical reports before anything touches a real patient.
@@ -54,6 +59,14 @@ IINTS-AF is a **safety-first simulation and validation platform** for insulin do
54
59
  * ML engineers benchmarking AI controllers with medical safety rails
55
60
  * Developers building decision-support systems for closed-loop insulin delivery
56
61
 
62
+ ## Installation
63
+
64
+ Install the SDK directly via PyPI:
65
+
66
+ ```bash
67
+ pip install iints-sdk-python35
68
+ ```
69
+
57
70
  ### Quick Start (CLI)
58
71
  ```bash
59
72
  iints quickstart --project-name iints_quickstart
@@ -99,7 +112,8 @@ outputs = iints.run_simulation(
99
112
  ```
100
113
 
101
114
  ### Notebook Guide
102
- Hands-on Jupyter notebooks live in `examples/notebooks/` and cover the full workflow (each is Colab-ready):
115
+ Hands-on Jupyter notebooks live in [`examples/notebooks/`](examples/notebooks/)
116
+
103
117
 
104
118
  * Quickstart end-to-end run
105
119
  * Presets + scenario validation
@@ -1,7 +1,12 @@
1
- # IINTS-AF SDK (v0.1.5)
1
+ # IINTS-AF SDK
2
+ [![PyPI version](https://badge.fury.io/py/iints-sdk-python35.svg)](https://badge.fury.io/py/iints-sdk-python35)
2
3
  [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/python35/IINTS-SDK/blob/main/examples/notebooks/00_Quickstart.ipynb)
3
4
  [![Python Package CI](https://github.com/python35/IINTS-SDK/actions/workflows/python-package.yml/badge.svg)](https://github.com/python35/IINTS-SDK/actions/workflows/python-package.yml)
4
5
 
6
+ <div style="text-align:center;">
7
+ <img src="Ontwerp zonder titel.png" alt="" style="display:block; margin:0 auto;">
8
+ </div>
9
+
5
10
  ## Intelligent Insulin Titration System for Artificial Pancreas
6
11
 
7
12
  IINTS-AF is a **safety-first simulation and validation platform** for insulin dosing algorithms. It lets you test AI or classical controllers on virtual patients, enforce deterministic safety constraints, and generate audit-ready clinical reports before anything touches a real patient.
@@ -19,6 +24,14 @@ IINTS-AF is a **safety-first simulation and validation platform** for insulin do
19
24
  * ML engineers benchmarking AI controllers with medical safety rails
20
25
  * Developers building decision-support systems for closed-loop insulin delivery
21
26
 
27
+ ## Installation
28
+
29
+ Install the SDK directly via PyPI:
30
+
31
+ ```bash
32
+ pip install iints-sdk-python35
33
+ ```
34
+
22
35
  ### Quick Start (CLI)
23
36
  ```bash
24
37
  iints quickstart --project-name iints_quickstart
@@ -64,7 +77,8 @@ outputs = iints.run_simulation(
64
77
  ```
65
78
 
66
79
  ### Notebook Guide
67
- Hands-on Jupyter notebooks live in `examples/notebooks/` and cover the full workflow (each is Colab-ready):
80
+ Hands-on Jupyter notebooks live in [`examples/notebooks/`](examples/notebooks/)
81
+
68
82
 
69
83
  * Quickstart end-to-end run
70
84
  * Presets + scenario validation
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "iints-sdk-python35"
7
- version = "0.1.7"
7
+ version = "0.1.9"
8
8
  authors = [
9
9
  { name="Rune Bobbaers", email="rune.bobbaers@gmail.com" },
10
10
  ]
@@ -54,6 +54,7 @@ iints = "iints.cli.cli:app"
54
54
  iints = [
55
55
  "templates/*.py",
56
56
  "templates/scenarios/*.json",
57
+ "assets/*.png",
57
58
  "data/virtual_patients/*.yaml",
58
59
  "data/demo/*.csv",
59
60
  "presets/*.json",
@@ -3,7 +3,7 @@
3
3
  import pandas as pd # Required for type hints like pd.DataFrame
4
4
  from typing import Optional
5
5
 
6
- __version__ = "0.1.5"
6
+ __version__ = "0.1.9"
7
7
 
8
8
  # API Components for Algorithm Development
9
9
  from .api.base_algorithm import (
@@ -1,11 +1,15 @@
1
+ import os
1
2
  import tempfile
2
3
  from pathlib import Path
3
4
  from typing import Any, Dict, Optional
4
5
 
6
+ os.environ.setdefault("MPLBACKEND", "Agg")
7
+
5
8
  import matplotlib.pyplot as plt
6
9
  import numpy as np
7
10
  import pandas as pd
8
11
  from fpdf import FPDF
12
+ from fpdf.enums import XPos, YPos
9
13
 
10
14
  from iints.analysis.clinical_metrics import ClinicalMetricsCalculator
11
15
  from iints.utils.plotting import apply_plot_style
@@ -17,6 +21,30 @@ class ClinicalReportGenerator:
17
21
  def __init__(self) -> None:
18
22
  self.metrics_calculator = ClinicalMetricsCalculator()
19
23
 
24
+ def _resolve_logo_path(self) -> Optional[Path]:
25
+ candidates = []
26
+ # Package asset (installed)
27
+ candidates.append(Path(__file__).resolve().parent.parent / "assets" / "iints_logo.png")
28
+ # Repo root img/ (dev)
29
+ candidates.append(Path(__file__).resolve().parents[3] / "img" / "iints_logo.png")
30
+ for path in candidates:
31
+ if path.exists():
32
+ return path
33
+ return None
34
+
35
+ def _render_logo(self, pdf: FPDF) -> None:
36
+ logo_path = self._resolve_logo_path()
37
+ if not logo_path:
38
+ return
39
+ try:
40
+ logo_width = 36
41
+ x_pos = pdf.w - pdf.r_margin - logo_width
42
+ y_pos = 6
43
+ pdf.image(str(logo_path), x=x_pos, y=y_pos, w=logo_width)
44
+ except Exception:
45
+ # Fallback silently if image fails to load
46
+ return
47
+
20
48
  def _plot_glucose(self, df: pd.DataFrame, output_path: Path) -> None:
21
49
  apply_plot_style()
22
50
  plt.figure(figsize=(10, 4))
@@ -104,44 +132,93 @@ class ClinicalReportGenerator:
104
132
  pdf = FPDF()
105
133
  pdf.set_auto_page_break(auto=True, margin=12)
106
134
  pdf.add_page()
135
+ self._render_logo(pdf)
107
136
 
108
137
  pdf.set_font("Helvetica", "B", 16)
109
- pdf.cell(0, 10, title, ln=1)
138
+ pdf.cell(0, 10, title, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
110
139
 
111
140
  pdf.set_font("Helvetica", "", 11)
112
- pdf.cell(0, 7, f"Duration: {simulation_data['time_minutes'].max()/60:.1f} hours", ln=1)
113
- pdf.cell(0, 7, f"Data points: {len(simulation_data)}", ln=1)
141
+ pdf.cell(
142
+ 0,
143
+ 7,
144
+ f"Duration: {simulation_data['time_minutes'].max()/60:.1f} hours",
145
+ new_x=XPos.LMARGIN,
146
+ new_y=YPos.NEXT,
147
+ )
148
+ pdf.cell(0, 7, f"Data points: {len(simulation_data)}", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
114
149
 
115
150
  pdf.ln(3)
116
151
  pdf.set_font("Helvetica", "B", 12)
117
- pdf.cell(0, 8, "Clinical Metrics", ln=1)
152
+ pdf.cell(0, 8, "Clinical Metrics", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
118
153
  pdf.set_font("Helvetica", "", 10)
119
- pdf.cell(0, 6, f"TIR (70-180): {metrics.get('tir_70_180', 0):.1f}%", ln=1)
120
- pdf.cell(0, 6, f"Time <70: {metrics.get('tir_below_70', 0):.1f}%", ln=1)
121
- pdf.cell(0, 6, f"Time >180: {metrics.get('tir_above_180', 0):.1f}%", ln=1)
122
- pdf.cell(0, 6, f"CV: {metrics.get('cv', 0):.1f}%", ln=1)
123
- pdf.cell(0, 6, f"GMI: {metrics.get('gmi', 0):.1f}%", ln=1)
154
+ pdf.cell(
155
+ 0,
156
+ 6,
157
+ f"TIR (70-180): {metrics.get('tir_70_180', 0):.1f}%",
158
+ new_x=XPos.LMARGIN,
159
+ new_y=YPos.NEXT,
160
+ )
161
+ pdf.cell(
162
+ 0,
163
+ 6,
164
+ f"Time <70: {metrics.get('tir_below_70', 0):.1f}%",
165
+ new_x=XPos.LMARGIN,
166
+ new_y=YPos.NEXT,
167
+ )
168
+ pdf.cell(
169
+ 0,
170
+ 6,
171
+ f"Time >180: {metrics.get('tir_above_180', 0):.1f}%",
172
+ new_x=XPos.LMARGIN,
173
+ new_y=YPos.NEXT,
174
+ )
175
+ pdf.cell(
176
+ 0,
177
+ 6,
178
+ f"CV: {metrics.get('cv', 0):.1f}%",
179
+ new_x=XPos.LMARGIN,
180
+ new_y=YPos.NEXT,
181
+ )
182
+ pdf.cell(
183
+ 0,
184
+ 6,
185
+ f"GMI: {metrics.get('gmi', 0):.1f}%",
186
+ new_x=XPos.LMARGIN,
187
+ new_y=YPos.NEXT,
188
+ )
124
189
 
125
190
  pdf.ln(2)
126
191
  pdf.set_font("Helvetica", "B", 12)
127
- pdf.cell(0, 8, "Safety Summary", ln=1)
192
+ pdf.cell(0, 8, "Safety Summary", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
128
193
  pdf.set_font("Helvetica", "", 10)
129
- pdf.cell(0, 6, f"Total violations: {safety_report.get('total_violations', 0)}", ln=1)
130
- pdf.cell(0, 6, f"Bolus interventions: {safety_report.get('bolus_interventions_count', 0)}", ln=1)
194
+ pdf.cell(
195
+ 0,
196
+ 6,
197
+ f"Total violations: {safety_report.get('total_violations', 0)}",
198
+ new_x=XPos.LMARGIN,
199
+ new_y=YPos.NEXT,
200
+ )
201
+ pdf.cell(
202
+ 0,
203
+ 6,
204
+ f"Bolus interventions: {safety_report.get('bolus_interventions_count', 0)}",
205
+ new_x=XPos.LMARGIN,
206
+ new_y=YPos.NEXT,
207
+ )
131
208
  top_reasons = self._top_safety_reasons(simulation_data)
132
209
  if top_reasons:
133
210
  pdf.ln(1)
134
211
  pdf.set_font("Helvetica", "B", 10)
135
- pdf.cell(0, 6, "Top intervention reasons:", ln=1)
212
+ pdf.cell(0, 6, "Top intervention reasons:", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
136
213
  pdf.set_font("Helvetica", "", 10)
137
214
  for reason, count in top_reasons.items():
138
- pdf.cell(0, 5, f"- {reason}: {count}", ln=1)
215
+ pdf.cell(0, 5, f"- {reason}: {count}", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
139
216
 
140
217
  baseline = safety_report.get("baseline_comparison")
141
218
  if baseline and baseline.get("rows"):
142
219
  pdf.ln(3)
143
220
  pdf.set_font("Helvetica", "B", 12)
144
- pdf.cell(0, 7, "Head-to-Head Comparison", ln=1)
221
+ pdf.cell(0, 7, "Head-to-Head Comparison", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
145
222
  pdf.set_font("Helvetica", "B", 9)
146
223
  col_widths = [52, 26, 26, 26, 30]
147
224
  headers = ["Algorithm", "TIR 70-180", "Time <70", "Time >180", "Safety Overrides"]
@@ -160,12 +237,12 @@ class ClinicalReportGenerator:
160
237
 
161
238
  pdf.ln(4)
162
239
  pdf.set_font("Helvetica", "B", 12)
163
- pdf.cell(0, 8, "Glucose Trace", ln=1)
240
+ pdf.cell(0, 8, "Glucose Trace", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
164
241
  pdf.image(str(glucose_plot), w=180)
165
242
 
166
243
  pdf.ln(4)
167
244
  pdf.set_font("Helvetica", "B", 12)
168
- pdf.cell(0, 8, "Insulin Delivery", ln=1)
245
+ pdf.cell(0, 8, "Insulin Delivery", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
169
246
  pdf.image(str(insulin_plot), w=180)
170
247
 
171
248
  pdf.output(str(output_file))
@@ -200,11 +277,18 @@ class ClinicalReportGenerator:
200
277
  pdf = FPDF()
201
278
  pdf.set_auto_page_break(auto=True, margin=12)
202
279
  pdf.add_page()
280
+ self._render_logo(pdf)
203
281
 
204
282
  pdf.set_font("Helvetica", "B", 18)
205
- pdf.cell(0, 12, title, ln=1)
283
+ pdf.cell(0, 12, title, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
206
284
  pdf.set_font("Helvetica", "", 11)
207
- pdf.cell(0, 7, f"Duration: {simulation_data['time_minutes'].max()/60:.1f} hours", ln=1)
285
+ pdf.cell(
286
+ 0,
287
+ 7,
288
+ f"Duration: {simulation_data['time_minutes'].max()/60:.1f} hours",
289
+ new_x=XPos.LMARGIN,
290
+ new_y=YPos.NEXT,
291
+ )
208
292
  pdf.ln(2)
209
293
 
210
294
  # Metric tiles
@@ -231,30 +315,30 @@ class ClinicalReportGenerator:
231
315
  pdf.set_fill_color(230, 244, 246)
232
316
  pdf.rect(x, y, tile_w, tile_h, style="F")
233
317
  pdf.set_xy(x + 2, y + 3)
234
- pdf.cell(tile_w - 4, 5, label, ln=1)
318
+ pdf.cell(tile_w - 4, 5, label, new_x=XPos.LEFT, new_y=YPos.NEXT)
235
319
  pdf.set_font("Helvetica", "B", 13)
236
320
  pdf.set_xy(x + 2, y + 9)
237
- pdf.cell(tile_w - 4, 8, value, ln=1)
321
+ pdf.cell(tile_w - 4, 8, value, new_x=XPos.LEFT, new_y=YPos.NEXT)
238
322
  pdf.set_font("Helvetica", "B", 10)
239
323
 
240
324
  pdf.ln(36)
241
325
  pdf.set_font("Helvetica", "B", 12)
242
- pdf.cell(0, 8, "Glucose Trace", ln=1)
326
+ pdf.cell(0, 8, "Glucose Trace", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
243
327
  pdf.image(str(glucose_plot), w=180)
244
328
 
245
329
  pdf.ln(4)
246
330
  pdf.set_font("Helvetica", "B", 12)
247
- pdf.cell(0, 8, "Insulin Delivery", ln=1)
331
+ pdf.cell(0, 8, "Insulin Delivery", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
248
332
  pdf.image(str(insulin_plot), w=180)
249
333
 
250
334
  top_reasons = self._top_safety_reasons(simulation_data)
251
335
  if top_reasons:
252
336
  pdf.ln(4)
253
337
  pdf.set_font("Helvetica", "B", 11)
254
- pdf.cell(0, 7, "Top Safety Interventions", ln=1)
338
+ pdf.cell(0, 7, "Top Safety Interventions", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
255
339
  pdf.set_font("Helvetica", "", 10)
256
340
  for reason, count in top_reasons.items():
257
- pdf.cell(0, 5, f"- {reason}: {count}", ln=1)
341
+ pdf.cell(0, 5, f"- {reason}: {count}", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
258
342
 
259
343
  pdf.output(str(output_file))
260
344
 
@@ -334,7 +334,7 @@ def presets_show(
334
334
  def presets_run(
335
335
  name: Annotated[str, typer.Option(help="Preset name (e.g., baseline_t1d)")],
336
336
  algo: Annotated[Path, typer.Option(help="Path to the algorithm Python file")],
337
- output_dir: Annotated[Path, typer.Option(help="Directory to save outputs")] = Path("./results/presets"),
337
+ output_dir: Annotated[Optional[Path], typer.Option(help="Directory to save outputs")] = None,
338
338
  compare_baselines: Annotated[bool, typer.Option(help="Run PID and standard pump baselines in the background")] = True,
339
339
  seed: Annotated[Optional[int], typer.Option(help="Random seed for deterministic runs")] = None,
340
340
  ):
@@ -392,13 +392,20 @@ def presets_run(
392
392
  for event in build_stress_events(stress_event_payloads):
393
393
  simulator.add_stress_event(event)
394
394
 
395
+ if output_dir is None:
396
+ output_dir = algo.parent / "results" / "presets"
397
+ output_dir = output_dir.expanduser()
398
+ if not output_dir.is_absolute():
399
+ output_dir = (Path.cwd() / output_dir).resolve()
400
+ else:
401
+ output_dir = output_dir.resolve()
395
402
  output_dir.mkdir(parents=True, exist_ok=True)
396
403
  results_df, safety_report = simulator.run_batch(duration)
397
404
 
398
405
  algo_name = algorithm_instance.get_algorithm_metadata().name.replace(" ", "_").lower()
399
406
  results_file = output_dir / f"preset_{name}_{algo_name}.csv"
400
407
  results_df.to_csv(results_file, index=False)
401
- console.print(f"Results saved to: [link file://{results_file}]{results_file}[/link]")
408
+ console.print(f"Results saved to: [link=file://{results_file}]{results_file}[/link]")
402
409
 
403
410
  audit_dir = output_dir / "audit"
404
411
  try:
@@ -424,7 +431,7 @@ def presets_run(
424
431
 
425
432
  report_path = output_dir / f"preset_{name}_{algo_name}.pdf"
426
433
  iints.generate_report(results_df, str(report_path), safety_report)
427
- console.print(f"PDF report saved to: [link file://{report_path}]{report_path}[/link]")
434
+ console.print(f"PDF report saved to: [link=file://{report_path}]{report_path}[/link]")
428
435
 
429
436
 
430
437
  @presets_app.command("create")
@@ -657,7 +664,7 @@ def run(
657
664
 
658
665
  simulation_results_df.to_csv(results_file, index=False)
659
666
 
660
- console.print(f"\nSimulation completed. Results saved to: [link file://{results_file}]{results_file}[/link]") # Formatted link
667
+ console.print(f"\nSimulation completed. Results saved to: [link=file://{results_file}]{results_file}[/link]") # Formatted link
661
668
  console.print("\n--- Safety Report ---")
662
669
  for key, value in safety_report.items():
663
670
  console.print(f"{key}: {value}")
@@ -761,7 +768,7 @@ def report(
761
768
  generator.export_plots(results_df, str(plots_dir))
762
769
  output_path.parent.mkdir(parents=True, exist_ok=True)
763
770
  iints.generate_report(results_df, str(output_path), safety_report)
764
- console.print(f"PDF report saved to: [link file://{output_path}]{output_path}[/link]")
771
+ console.print(f"PDF report saved to: [link=file://{output_path}]{output_path}[/link]")
765
772
 
766
773
  if audit_output_dir:
767
774
  audit_output_dir.mkdir(parents=True, exist_ok=True)
@@ -0,0 +1,91 @@
1
+ from iints import InsulinAlgorithm, AlgorithmInput, AlgorithmResult, AlgorithmMetadata
2
+ from typing import Dict, Any
3
+
4
+ class {{ALGO_NAME}}(InsulinAlgorithm):
5
+ def __init__(self, settings: Dict[str, Any] = None):
6
+ super().__init__(settings)
7
+ self.set_algorithm_metadata(AlgorithmMetadata(
8
+ name="{{ALGO_NAME}}",
9
+ author="{{AUTHOR_NAME}}",
10
+ description="A new custom insulin algorithm.",
11
+ algorithm_type="rule_based" # Change as appropriate
12
+ ))
13
+ # Initialize any specific state or parameters for your algorithm here
14
+
15
+ def predict_insulin(self, data: AlgorithmInput) -> Dict[str, Any]:
16
+ # --- SAFETY-FIRST STARTER LOGIC ---
17
+ # This template is intentionally conservative to avoid hypoglycemia.
18
+
19
+ self.why_log = []
20
+
21
+ current_glucose = data.current_glucose
22
+ iob = data.insulin_on_board
23
+ carbs = data.carb_intake
24
+
25
+ previous_glucose = self.state.get("previous_glucose", current_glucose)
26
+ glucose_trend = (current_glucose - previous_glucose) / max(data.time_step, 1)
27
+ self.state["previous_glucose"] = current_glucose
28
+
29
+ total_insulin = 0.0
30
+ bolus_insulin = 0.0
31
+ basal_insulin = 0.0
32
+ correction_bolus = 0.0
33
+ meal_bolus = 0.0
34
+
35
+ # Hard safety cutoff
36
+ if current_glucose < 90:
37
+ self._log_reason("Glucose below 90 mg/dL; holding insulin.", "safety_cutoff", current_glucose)
38
+ return {
39
+ "total_insulin_delivered": 0.0,
40
+ "bolus_insulin": 0.0,
41
+ "basal_insulin": 0.0,
42
+ "correction_bolus": 0.0,
43
+ "meal_bolus": 0.0,
44
+ }
45
+
46
+ # If glucose is falling quickly, avoid correction bolus
47
+ if glucose_trend < -1.0:
48
+ self._log_reason(
49
+ f"Glucose dropping at {glucose_trend:.2f} mg/dL/min; skipping correction bolus.",
50
+ "safety_trend",
51
+ glucose_trend,
52
+ )
53
+ else:
54
+ # Conservative correction only if quite high
55
+ if current_glucose > 180:
56
+ correction_bolus = (current_glucose - 140) / self.isf
57
+ correction_bolus = min(max(correction_bolus, 0.0), 0.5)
58
+ total_insulin += correction_bolus
59
+ self._log_reason(
60
+ f"Conservative correction bolus {correction_bolus:.2f} U.",
61
+ "correction",
62
+ current_glucose,
63
+ )
64
+
65
+ # Meal bolus (capped)
66
+ if carbs > 0:
67
+ meal_bolus = min(carbs / self.icr, 2.0)
68
+ total_insulin += meal_bolus
69
+ self._log_reason(
70
+ f"Meal bolus {meal_bolus:.2f} U for {carbs:.0f} g carbs.",
71
+ "meal_bolus",
72
+ carbs,
73
+ )
74
+
75
+ # Optional: cap total insulin based on IOB
76
+ if iob > 2.0:
77
+ total_insulin = min(total_insulin, 0.2)
78
+ self._log_reason("High IOB; capping total insulin to 0.2 U.", "iob_cap", iob)
79
+
80
+ total_insulin = max(0.0, total_insulin)
81
+ bolus_insulin = total_insulin
82
+
83
+ self._log_reason(f"Final insulin decision: {total_insulin:.2f} units", "decision", total_insulin)
84
+
85
+ return {
86
+ "total_insulin_delivered": total_insulin,
87
+ "bolus_insulin": bolus_insulin,
88
+ "basal_insulin": basal_insulin,
89
+ "correction_bolus": correction_bolus,
90
+ "meal_bolus": meal_bolus,
91
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iints-sdk-python35
3
- Version: 0.1.7
3
+ Version: 0.1.9
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
  Project-URL: Homepage, https://github.com/python35/IINTS-SDK
@@ -33,10 +33,15 @@ Provides-Extra: torch
33
33
  Requires-Dist: torch>=1.9.0; extra == "torch"
34
34
  Dynamic: license-file
35
35
 
36
- # IINTS-AF SDK (v0.1.5)
36
+ # IINTS-AF SDK
37
+ [![PyPI version](https://badge.fury.io/py/iints-sdk-python35.svg)](https://badge.fury.io/py/iints-sdk-python35)
37
38
  [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/python35/IINTS-SDK/blob/main/examples/notebooks/00_Quickstart.ipynb)
38
39
  [![Python Package CI](https://github.com/python35/IINTS-SDK/actions/workflows/python-package.yml/badge.svg)](https://github.com/python35/IINTS-SDK/actions/workflows/python-package.yml)
39
40
 
41
+ <div style="text-align:center;">
42
+ <img src="Ontwerp zonder titel.png" alt="" style="display:block; margin:0 auto;">
43
+ </div>
44
+
40
45
  ## Intelligent Insulin Titration System for Artificial Pancreas
41
46
 
42
47
  IINTS-AF is a **safety-first simulation and validation platform** for insulin dosing algorithms. It lets you test AI or classical controllers on virtual patients, enforce deterministic safety constraints, and generate audit-ready clinical reports before anything touches a real patient.
@@ -54,6 +59,14 @@ IINTS-AF is a **safety-first simulation and validation platform** for insulin do
54
59
  * ML engineers benchmarking AI controllers with medical safety rails
55
60
  * Developers building decision-support systems for closed-loop insulin delivery
56
61
 
62
+ ## Installation
63
+
64
+ Install the SDK directly via PyPI:
65
+
66
+ ```bash
67
+ pip install iints-sdk-python35
68
+ ```
69
+
57
70
  ### Quick Start (CLI)
58
71
  ```bash
59
72
  iints quickstart --project-name iints_quickstart
@@ -99,7 +112,8 @@ outputs = iints.run_simulation(
99
112
  ```
100
113
 
101
114
  ### Notebook Guide
102
- Hands-on Jupyter notebooks live in `examples/notebooks/` and cover the full workflow (each is Colab-ready):
115
+ Hands-on Jupyter notebooks live in [`examples/notebooks/`](examples/notebooks/)
116
+
103
117
 
104
118
  * Quickstart end-to-end run
105
119
  * Presets + scenario validation
@@ -22,6 +22,7 @@ src/iints/analysis/validator.py
22
22
  src/iints/api/__init__.py
23
23
  src/iints/api/base_algorithm.py
24
24
  src/iints/api/template_algorithm.py
25
+ src/iints/assets/iints_logo.png
25
26
  src/iints/cli/__init__.py
26
27
  src/iints/cli/cli.py
27
28
  src/iints/core/__init__.py
@@ -1,56 +0,0 @@
1
- from iints import InsulinAlgorithm, AlgorithmInput, AlgorithmResult, AlgorithmMetadata
2
- from typing import Dict, Any
3
-
4
- class {{ALGO_NAME}}(InsulinAlgorithm):
5
- def __init__(self, settings: Dict[str, Any] = None):
6
- super().__init__(settings)
7
- self.set_algorithm_metadata(AlgorithmMetadata(
8
- name="{{ALGO_NAME}}",
9
- author="{{AUTHOR_NAME}}",
10
- description="A new custom insulin algorithm.",
11
- algorithm_type="rule_based" # Change as appropriate
12
- ))
13
- # Initialize any specific state or parameters for your algorithm here
14
-
15
- def predict_insulin(self, data: AlgorithmInput) -> Dict[str, Any]:
16
- # --- YOUR ALGORITHM LOGIC GOES HERE ---
17
- # This is a basic placeholder. Implement your actual insulin prediction logic.
18
-
19
- # Example: Deliver 0.1 units if glucose is above 120 mg/dL
20
- total_insulin = 0.0
21
- bolus_insulin = 0.0
22
- basal_insulin = 0.0
23
- correction_bolus = 0.0
24
- meal_bolus = 0.0
25
-
26
- if data.current_glucose > 120:
27
- correction_bolus = (data.current_glucose - 120) / self.isf / 5 # Example: 1 unit per 50 mg/dL above 120
28
- total_insulin += correction_bolus
29
- self._log_reason(f"Correcting high glucose", "glucose_level", data.current_glucose, f"Delivered {correction_bolus:.2f} units to reduce {data.current_glucose} mg/dL")
30
-
31
- if data.carb_intake > 0:
32
- meal_bolus = data.carb_intake / self.icr
33
- total_insulin += meal_bolus
34
- self._log_reason(f"Meal intake detected", "carb_intake", data.carb_intake, f"Delivered {meal_bolus:.2f} units for {data.carb_intake}g carbs")
35
-
36
- # Simulate basal rate (e.g., a continuous small delivery)
37
- # For simplicity, let's assume a fixed basal delivery over the time step
38
- # You might integrate this with your overall basal strategy
39
- # basal_insulin = 0.01 * data.time_step # Example: 0.01 units per minute basal
40
- # total_insulin += basal_insulin
41
- self._log_reason(f"Maintaining basal rate", "basal", data.time_step, f"Delivered {basal_insulin:.2f} units basal")
42
-
43
-
44
- # Ensure no negative insulin delivery
45
- total_insulin = max(0.0, total_insulin)
46
-
47
- # Store important decisions in the why_log for transparency
48
- self._log_reason(f"Final insulin decision: {total_insulin:.2f} units", "decision", total_insulin)
49
-
50
- return {
51
- "total_insulin_delivered": total_insulin,
52
- "bolus_insulin": bolus_insulin, # You might differentiate between meal and correction bolus here
53
- "basal_insulin": basal_insulin,
54
- "correction_bolus": correction_bolus,
55
- "meal_bolus": meal_bolus,
56
- }