iints-sdk-python35 1.3.0__py3-none-any.whl → 1.3.2__py3-none-any.whl

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/__init__.py CHANGED
@@ -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.3.0"
14
+ __version__ = "1.3.2"
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.
@@ -231,9 +231,13 @@ def _build_commands_markdown(
231
231
  supervisor_dir = run_outputs["03_supervisor_override"]["output_dir"]
232
232
  return (
233
233
  "# Booth Demo Commands\n\n"
234
+ "## Showable live demo script\n\n"
235
+ "```bash\n"
236
+ f"python3 {example_script} --output-dir {output_dir}\n"
237
+ "```\n\n"
234
238
  "## Run from source tree\n\n"
235
239
  "```bash\n"
236
- f"PYTHONPATH=src python3 {example_script} --output-dir {output_dir}\n"
240
+ f"PYTHONPATH=src python3 examples/demos/06_booth_demo.py --output-dir {output_dir}\n"
237
241
  "```\n\n"
238
242
  "## Run via installed CLI\n\n"
239
243
  "```bash\n"
@@ -258,12 +262,17 @@ def _build_live_demo_script_text(
258
262
  "IINTS-AF BOOTH LIVE DEMO SCRIPT\n"
259
263
  "===============================\n\n"
260
264
  "1. WHAT CODE TO SHOW FIRST\n"
261
- "- Show examples/demos/06_booth_demo.py first.\n"
262
- " Reason: it is the shortest, clearest orchestration file and shows the whole story in one screen.\n"
263
- "- If someone asks how it really works, open src/iints/analysis/booth_demo.py.\n"
264
- " Reason: that file defines the three scenarios and writes the poster, talk track, and run bundle outputs.\n\n"
265
+ "- Show examples/demos/07_live_stage_demo.py first.\n"
266
+ " Reason: the top of that file exposes the patient profile, output folder, duration, and seed on one screen.\n"
267
+ "- Point out the visible SDK feature calls in that script:\n"
268
+ " run_full(...), generate_results_poster(...), and prepare_ai_ready_artifacts(...).\n"
269
+ "- Point out that you can swap PATIENT_CONFIG to another packaged profile such as patient_559_config or clinic_safe_hypo_prone.\n"
270
+ "- If someone asks how the full bundle is generated, open examples/demos/06_booth_demo.py and then src/iints/analysis/booth_demo.py.\n"
271
+ " Reason: those files define the three scenarios and write the poster, talk track, and run bundle outputs.\n\n"
265
272
  "2. LIVE COMMAND TO RUN\n"
266
- "- From the repository root, run:\n"
273
+ "- From the repository root, run the live stage script:\n"
274
+ " ./scripts/run_live_stage_demo.sh\n"
275
+ "- Or run the booth bundle directly:\n"
267
276
  " ./scripts/run_booth_demo.sh\n"
268
277
  "- Or use the installed CLI:\n"
269
278
  " iints demo-booth --output-dir results/booth_demo\n\n"
@@ -304,6 +313,7 @@ def _build_live_demo_script_text(
304
313
  def build_booth_demo(
305
314
  output_dir: str | Path = "./results/booth_demo",
306
315
  *,
316
+ patient_config: str | Path | dict[str, Any] = "default_patient",
307
317
  duration_minutes: int = 360,
308
318
  time_step: int = 5,
309
319
  seed: int = 42,
@@ -326,7 +336,7 @@ def build_booth_demo(
326
336
  outputs = run_full(
327
337
  algorithm=spec.algorithm_factory(),
328
338
  scenario=spec.scenario,
329
- patient_config="default_patient",
339
+ patient_config=patient_config,
330
340
  duration_minutes=duration_minutes,
331
341
  time_step=time_step,
332
342
  seed=seed,
@@ -375,6 +385,7 @@ def build_booth_demo(
375
385
 
376
386
  summary_payload = {
377
387
  "output_dir": str(resolved_output),
388
+ "patient_config": str(patient_config),
378
389
  "duration_minutes": duration_minutes,
379
390
  "time_step_minutes": time_step,
380
391
  "seed": seed,
@@ -395,7 +406,7 @@ def build_booth_demo(
395
406
  }
396
407
  _write_json(resolved_output / "demo_summary.json", summary_payload)
397
408
 
398
- example_script = Path("examples/demos/06_booth_demo.py")
409
+ example_script = Path("examples/demos/07_live_stage_demo.py")
399
410
  commands_markdown = _build_commands_markdown(
400
411
  output_dir=resolved_output,
401
412
  example_script=example_script,
iints/cli/cli.py CHANGED
@@ -53,6 +53,7 @@ from iints.data.registry import (
53
53
  )
54
54
  from iints.data.contracts import load_contract_yaml
55
55
  from iints.data.synthetic_mirror import generate_synthetic_mirror
56
+ from iints.demo_assets import export_live_stage_demo
56
57
  from iints.mdmp.backend import (
57
58
  MDMP_GRADE_ORDER,
58
59
  active_mdmp_backend,
@@ -2740,6 +2741,39 @@ def demo_booth(
2740
2741
  )
2741
2742
 
2742
2743
 
2744
+ @app.command("demo-export")
2745
+ def demo_export(
2746
+ output_dir: Annotated[
2747
+ Path,
2748
+ typer.Option(help="Directory where the bundled live stage demo files should be written."),
2749
+ ] = Path("./iints_demo"),
2750
+ overwrite: Annotated[
2751
+ bool,
2752
+ typer.Option("--overwrite/--no-overwrite", help="Allow overwriting exported demo files."),
2753
+ ] = False,
2754
+ ) -> None:
2755
+ """Export the showable live demo code from the installed SDK."""
2756
+ console = Console()
2757
+ try:
2758
+ outputs = export_live_stage_demo(output_dir=output_dir, overwrite=overwrite)
2759
+ except FileExistsError as exc:
2760
+ console.print(f"[bold red]Demo export stopped:[/bold red] {exc}")
2761
+ raise typer.Exit(code=1)
2762
+ except Exception as exc:
2763
+ console.print(f"[bold red]Demo export failed:[/bold red] {exc}")
2764
+ raise typer.Exit(code=1)
2765
+
2766
+ table = Table(title="IINTS Demo Export")
2767
+ table.add_column("Artifact", style="cyan")
2768
+ table.add_column("Path", overflow="fold")
2769
+ table.add_row("script", outputs["script_path"])
2770
+ table.add_row("notes", outputs["notes_path"])
2771
+ console.print(table)
2772
+ console.print(
2773
+ "[green]Next:[/green] open `07_live_stage_demo.py`, explain the visible SDK calls, then run `python 07_live_stage_demo.py`."
2774
+ )
2775
+
2776
+
2743
2777
  @app.command()
2744
2778
  def report(
2745
2779
  results_csv: Annotated[Path, typer.Option(help="Path to a simulation results CSV")],
iints/demo_assets.py ADDED
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+
3
+ from importlib.resources import files
4
+ from pathlib import Path
5
+
6
+
7
+ def export_live_stage_demo(output_dir: str | Path = '.', *, overwrite: bool = False) -> dict[str, str]:
8
+ """Export the bundled live stage demo script for users running the installed SDK."""
9
+ resolved_output = Path(output_dir).expanduser().resolve()
10
+ resolved_output.mkdir(parents=True, exist_ok=True)
11
+
12
+ script_target = resolved_output / '07_live_stage_demo.py'
13
+ notes_target = resolved_output / 'RUN_ME_FIRST.txt'
14
+
15
+ if not overwrite and script_target.exists():
16
+ raise FileExistsError(f'Demo script already exists: {script_target}')
17
+ if not overwrite and notes_target.exists():
18
+ raise FileExistsError(f'Instruction file already exists: {notes_target}')
19
+
20
+ script_content = files('iints.templates.demos').joinpath('live_stage_demo.py').read_text(encoding='utf-8')
21
+ notes_content = (
22
+ 'IINTS LIVE DEMO EXPORT\n'
23
+ '======================\n\n'
24
+ 'This folder was exported from the installed IINTS SDK.\n\n'
25
+ '1. Activate the virtual environment that contains IINTS.\n'
26
+ '2. Open 07_live_stage_demo.py and point to:\n'
27
+ ' - PATIENT_CONFIG\n'
28
+ ' - OUTPUT_DIR\n'
29
+ ' - DURATION_MINUTES\n'
30
+ ' - TIME_STEP_MINUTES\n'
31
+ ' - SEED\n'
32
+ '3. Explain that the script visibly calls:\n'
33
+ ' - run_full(...)\n'
34
+ ' - generate_results_poster(...)\n'
35
+ ' - prepare_ai_ready_artifacts(...)\n'
36
+ '4. Run:\n'
37
+ ' python 07_live_stage_demo.py\n'
38
+ '5. Open the generated files under results/booth_demo_live/.\n\n'
39
+ 'Tip: if you also cloned the SDK repo, you can run the repo wrapper instead:\n'
40
+ ' ./scripts/run_live_stage_demo.sh\n'
41
+ )
42
+
43
+ script_target.write_text(script_content, encoding='utf-8')
44
+ notes_target.write_text(notes_content, encoding='utf-8')
45
+
46
+ return {
47
+ 'output_dir': str(resolved_output),
48
+ 'script_path': str(script_target),
49
+ 'notes_path': str(notes_target),
50
+ }
@@ -0,0 +1 @@
1
+ """Bundled demo script templates for installed IINTS users."""
@@ -0,0 +1,410 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import json
6
+ import sys
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ SDK_SRC = Path(__file__).resolve().parents[2] / "src"
11
+ if SDK_SRC.exists():
12
+ sys.path.insert(0, str(SDK_SRC))
13
+
14
+ from iints.ai.prepare import prepare_ai_ready_artifacts
15
+ from iints.analysis.poster import generate_results_poster
16
+ from iints.core.algorithms.mock_algorithms import RunawayAIAlgorithm
17
+ from iints.core.algorithms.pid_controller import PIDController
18
+ from iints.highlevel import run_full
19
+
20
+ # FAIR DEMO SCRIPT
21
+ # ----------------
22
+ # This is the file to show first on a booth stand.
23
+ # It deliberately calls visible SDK features so you can explain the pipeline:
24
+ #
25
+ # 1. `run_full(...)`
26
+ # Runs a scenario and writes a real run bundle: CSV, PDF report, audit trail,
27
+ # baseline comparison, metadata, and a reproducibility manifest.
28
+ # 2. `generate_results_poster(...)`
29
+ # Turns the three run bundles into one visual poster you can show to a jury.
30
+ # 3. `prepare_ai_ready_artifacts(...)`
31
+ # Prepares the supervisor case for a local AI explanation, gated by MDMP.
32
+ #
33
+ # The knobs below are the first things to point at live.
34
+ PATIENT_CONFIG = "default_patient"
35
+ OUTPUT_DIR = "results/booth_demo_live"
36
+ DURATION_MINUTES = 360
37
+ TIME_STEP_MINUTES = 5
38
+ SEED = 42
39
+ PREPARE_AI = True
40
+
41
+ # Other good packaged patient configs to mention live:
42
+ # - patient_559_config
43
+ # - clinic_safe_baseline
44
+ # - clinic_safe_stress_meal
45
+ # - clinic_safe_hypo_prone
46
+ # - clinic_safe_hyper_challenge
47
+ # - clinic_safe_midnight
48
+ # - clinic_safe_pizza
49
+
50
+
51
+ ScenarioSpec = dict[str, Any]
52
+
53
+
54
+ SCENARIOS: list[ScenarioSpec] = [
55
+ {
56
+ "slug": "01_normal_run",
57
+ "label": "Normal Run",
58
+ "headline": "The controller keeps glucose in range during a calm day.",
59
+ "algorithm_factory": PIDController,
60
+ "scenario": {
61
+ "scenario_name": "Live Demo - Normal Run",
62
+ "schema_version": "1.1",
63
+ "scenario_version": "1.0",
64
+ "description": "One moderate meal to show stable closed-loop control.",
65
+ "stress_events": [
66
+ {
67
+ "start_time": 45,
68
+ "event_type": "meal",
69
+ "value": 35,
70
+ "reported_value": 35,
71
+ "absorption_delay_minutes": 10,
72
+ "duration": 45,
73
+ }
74
+ ],
75
+ },
76
+ },
77
+ {
78
+ "slug": "02_meal_stress_test",
79
+ "label": "Meal Stress Test",
80
+ "headline": "The same controller handles meals and exercise under stress.",
81
+ "algorithm_factory": PIDController,
82
+ "scenario": {
83
+ "scenario_name": "Live Demo - Meal Stress Test",
84
+ "schema_version": "1.1",
85
+ "scenario_version": "1.0",
86
+ "description": "Two bigger meals plus exercise to stress the controller.",
87
+ "stress_events": [
88
+ {
89
+ "start_time": 45,
90
+ "event_type": "meal",
91
+ "value": 70,
92
+ "reported_value": 70,
93
+ "absorption_delay_minutes": 15,
94
+ "duration": 75,
95
+ },
96
+ {
97
+ "start_time": 150,
98
+ "event_type": "meal",
99
+ "value": 45,
100
+ "reported_value": 45,
101
+ "absorption_delay_minutes": 10,
102
+ "duration": 50,
103
+ },
104
+ {
105
+ "start_time": 210,
106
+ "event_type": "exercise",
107
+ "value": 0.5,
108
+ "duration": 35,
109
+ },
110
+ ],
111
+ },
112
+ },
113
+ {
114
+ "slug": "03_supervisor_override",
115
+ "label": "Supervisor Override",
116
+ "headline": "A deliberately unsafe AI policy is blocked by the safety supervisor.",
117
+ "algorithm_factory": lambda: RunawayAIAlgorithm(max_bolus=5.0),
118
+ "scenario": {
119
+ "scenario_name": "Live Demo - Supervisor Override",
120
+ "schema_version": "1.1",
121
+ "scenario_version": "1.0",
122
+ "description": "A chaos run where a bad AI keeps asking for too much insulin.",
123
+ "stress_events": [
124
+ {
125
+ "start_time": 30,
126
+ "event_type": "meal",
127
+ "value": 60,
128
+ "reported_value": 60,
129
+ },
130
+ {
131
+ "start_time": 120,
132
+ "event_type": "exercise",
133
+ "value": 0.8,
134
+ "duration": 60,
135
+ },
136
+ {
137
+ "start_time": 200,
138
+ "event_type": "sensor_error",
139
+ "value": 180,
140
+ },
141
+ ],
142
+ },
143
+ },
144
+ ]
145
+
146
+
147
+ def _write_json(path: Path, payload: dict[str, Any]) -> None:
148
+ path.parent.mkdir(parents=True, exist_ok=True)
149
+ path.write_text(json.dumps(payload, indent=2, sort_keys=True), encoding="utf-8")
150
+
151
+
152
+ def _write_text(path: Path, content: str) -> None:
153
+ path.parent.mkdir(parents=True, exist_ok=True)
154
+ path.write_text(content, encoding="utf-8")
155
+
156
+
157
+ def _run_single_scenario(
158
+ spec: ScenarioSpec,
159
+ *,
160
+ output_root: Path,
161
+ patient_config: str,
162
+ duration_minutes: int,
163
+ time_step_minutes: int,
164
+ seed: int,
165
+ ) -> dict[str, str]:
166
+ run_dir = output_root / spec["slug"]
167
+ outputs = run_full(
168
+ algorithm=spec["algorithm_factory"](),
169
+ scenario=spec["scenario"],
170
+ patient_config=patient_config,
171
+ duration_minutes=duration_minutes,
172
+ time_step=time_step_minutes,
173
+ seed=seed,
174
+ output_dir=run_dir,
175
+ enable_profiling=False,
176
+ )
177
+ return {
178
+ "slug": spec["slug"],
179
+ "label": spec["label"],
180
+ "headline": spec["headline"],
181
+ "output_dir": str(run_dir),
182
+ "results_csv": str(outputs["results_csv"]),
183
+ "report_pdf": str(outputs["report_pdf"]),
184
+ "run_manifest_path": str(outputs["run_manifest_path"]),
185
+ "run_metadata_path": str(outputs["run_metadata_path"]),
186
+ }
187
+
188
+
189
+ def _build_demo_summary(
190
+ *,
191
+ output_dir: Path,
192
+ patient_config: str,
193
+ duration_minutes: int,
194
+ time_step_minutes: int,
195
+ seed: int,
196
+ scenario_outputs: list[dict[str, str]],
197
+ poster_outputs: dict[str, str],
198
+ ai_outputs: dict[str, str],
199
+ ai_status: str,
200
+ ) -> dict[str, Any]:
201
+ return {
202
+ "output_dir": str(output_dir),
203
+ "patient_config": patient_config,
204
+ "duration_minutes": duration_minutes,
205
+ "time_step_minutes": time_step_minutes,
206
+ "seed": seed,
207
+ "poster_png": poster_outputs["poster_png"],
208
+ "poster_summary_json": poster_outputs["summary_json"],
209
+ "ai_status": ai_status,
210
+ "scenarios": scenario_outputs,
211
+ "ai_outputs": ai_outputs,
212
+ }
213
+
214
+
215
+ def _build_jury_talk_track(summary: dict[str, Any]) -> str:
216
+ lines = [
217
+ "# IINTS-AF Jury Talk Track",
218
+ "",
219
+ "## What this script shows",
220
+ "",
221
+ "- `run_full(...)` for real reproducible run bundles",
222
+ "- `generate_results_poster(...)` for one visual story",
223
+ "- `prepare_ai_ready_artifacts(...)` for optional local AI explanation",
224
+ "",
225
+ "## Walkthrough",
226
+ "",
227
+ "1. Show the constants at the top of `examples/demos/07_live_stage_demo.py`.",
228
+ "2. Say that swapping `PATIENT_CONFIG` reruns the same pipeline for another patient.",
229
+ "3. Run `./scripts/run_live_stage_demo.sh`.",
230
+ "4. Open the poster and explain the three panels from left to right.",
231
+ "5. If someone wants proof, open a scenario folder and show `results.csv`, `clinical_report.pdf`, and `run_manifest.json`.",
232
+ "",
233
+ "## Scenario story",
234
+ "",
235
+ ]
236
+ for scenario in summary["scenarios"]:
237
+ lines.extend(
238
+ [
239
+ f"### {scenario['label']}",
240
+ "",
241
+ f"- {scenario['headline']}",
242
+ f"- Run folder: `{scenario['output_dir']}`",
243
+ f"- CSV: `{scenario['results_csv']}`",
244
+ f"- PDF: `{scenario['report_pdf']}`",
245
+ "",
246
+ ]
247
+ )
248
+ lines.extend(
249
+ [
250
+ "## Optional AI step",
251
+ "",
252
+ summary["ai_status"],
253
+ "",
254
+ "```bash",
255
+ "iints ai local-check --model ministral-3:3b",
256
+ f"iints ai report {summary['scenarios'][2]['output_dir']} --model ministral-3:3b",
257
+ f"iints ai explain {summary['scenarios'][2]['output_dir']} --model ministral-3:3b",
258
+ "```",
259
+ "",
260
+ ]
261
+ )
262
+ return "\n".join(lines) + "\n"
263
+
264
+
265
+ def _build_live_demo_notes(summary: dict[str, Any]) -> str:
266
+ return (
267
+ "IINTS-AF LIVE DEMO NOTES\n"
268
+ "========================\n\n"
269
+ "1. Show `examples/demos/07_live_stage_demo.py`.\n"
270
+ "2. Point to PATIENT_CONFIG, OUTPUT_DIR, DURATION_MINUTES, TIME_STEP_MINUTES, and SEED.\n"
271
+ "3. Explain that the script visibly uses these SDK features:\n"
272
+ " - run_full(...)\n"
273
+ " - generate_results_poster(...)\n"
274
+ " - prepare_ai_ready_artifacts(...)\n\n"
275
+ "4. Run: ./scripts/run_live_stage_demo.sh\n"
276
+ f"5. Open poster: {summary['poster_png']}\n"
277
+ f"6. Normal run folder: {summary['scenarios'][0]['output_dir']}\n"
278
+ f"7. Stress run folder: {summary['scenarios'][1]['output_dir']}\n"
279
+ f"8. Supervisor run folder: {summary['scenarios'][2]['output_dir']}\n\n"
280
+ "9. Explain the three panels:\n"
281
+ " - Normal Run = control case\n"
282
+ " - Meal Stress Test = harder physiology\n"
283
+ " - Supervisor Override = bad AI gets blocked\n"
284
+ )
285
+
286
+
287
+ def _build_run_commands(summary: dict[str, Any]) -> str:
288
+ supervisor_dir = summary["scenarios"][2]["output_dir"]
289
+ return (
290
+ "# Live Demo Commands\n\n"
291
+ "## Showable script\n\n"
292
+ "```bash\n"
293
+ "python3 examples/demos/07_live_stage_demo.py\n"
294
+ "```\n\n"
295
+ "## Recommended live command\n\n"
296
+ "```bash\n"
297
+ "./scripts/run_live_stage_demo.sh\n"
298
+ "```\n\n"
299
+ "## Installed CLI alternative\n\n"
300
+ "```bash\n"
301
+ "iints demo-booth --output-dir results/booth_demo\n"
302
+ "```\n\n"
303
+ "## Optional AI step\n\n"
304
+ "```bash\n"
305
+ "iints ai local-check --model ministral-3:3b\n"
306
+ f"iints ai report {supervisor_dir} --model ministral-3:3b\n"
307
+ f"iints ai explain {supervisor_dir} --model ministral-3:3b\n"
308
+ "```\n"
309
+ )
310
+
311
+
312
+ def main() -> None:
313
+ parser = argparse.ArgumentParser(description="Fair-friendly live demo runner for the IINTS-AF SDK.")
314
+ parser.add_argument("--patient-config", default=PATIENT_CONFIG, help="Packaged patient profile name or path to a YAML config.")
315
+ parser.add_argument("--output-dir", default=OUTPUT_DIR, help="Directory where the demo bundle should be written.")
316
+ parser.add_argument("--duration", type=int, default=DURATION_MINUTES, help="Simulation duration in minutes.")
317
+ parser.add_argument("--time-step", type=int, default=TIME_STEP_MINUTES, help="Simulation time step in minutes.")
318
+ parser.add_argument("--seed", type=int, default=SEED, help="Deterministic random seed.")
319
+ parser.add_argument(
320
+ "--prepare-ai",
321
+ dest="prepare_ai",
322
+ action="store_true",
323
+ default=PREPARE_AI,
324
+ help="Prepare AI-ready artifacts for the Supervisor Override scenario.",
325
+ )
326
+ parser.add_argument(
327
+ "--skip-ai",
328
+ dest="prepare_ai",
329
+ action="store_false",
330
+ help="Skip AI-ready artifact generation.",
331
+ )
332
+ args = parser.parse_args()
333
+
334
+ output_dir = Path(args.output_dir).expanduser().resolve()
335
+ output_dir.mkdir(parents=True, exist_ok=True)
336
+
337
+ scenario_outputs = [
338
+ _run_single_scenario(
339
+ spec,
340
+ output_root=output_dir,
341
+ patient_config=args.patient_config,
342
+ duration_minutes=args.duration,
343
+ time_step_minutes=args.time_step,
344
+ seed=args.seed,
345
+ )
346
+ for spec in SCENARIOS
347
+ ]
348
+
349
+ poster_outputs = generate_results_poster(
350
+ run_dirs=[item["output_dir"] for item in scenario_outputs],
351
+ labels=[item["label"] for item in scenario_outputs],
352
+ output_path=output_dir / "booth_demo_poster.png",
353
+ summary_output_path=output_dir / "booth_demo_poster.json",
354
+ poster_title="288 Decisions. Every Day. We Test Them All.",
355
+ subtitle="Three SDK features in one story: simulate, stress, and protect.",
356
+ )
357
+
358
+ ai_outputs: dict[str, str] = {}
359
+ ai_status = "AI preparation was skipped."
360
+ if args.prepare_ai:
361
+ try:
362
+ ai_outputs = prepare_ai_ready_artifacts(scenario_outputs[2]["output_dir"], create_dev_mdmp_cert=True)
363
+ ai_status = "AI-ready artifacts were created for the Supervisor Override scenario."
364
+ except Exception as exc:
365
+ ai_status = f"AI preparation did not block the demo, but it could not finish cleanly: {exc}"
366
+
367
+ summary = _build_demo_summary(
368
+ output_dir=output_dir,
369
+ patient_config=args.patient_config,
370
+ duration_minutes=args.duration,
371
+ time_step_minutes=args.time_step,
372
+ seed=args.seed,
373
+ scenario_outputs=scenario_outputs,
374
+ poster_outputs=poster_outputs,
375
+ ai_outputs=ai_outputs,
376
+ ai_status=ai_status,
377
+ )
378
+ _write_json(output_dir / "demo_summary.json", summary)
379
+ _write_text(output_dir / "JURY_TALK_TRACK.md", _build_jury_talk_track(summary))
380
+ _write_text(output_dir / "BEURS_LIVE_DEMO_SCRIPT.txt", _build_live_demo_notes(summary))
381
+ _write_text(output_dir / "run_commands.md", _build_run_commands(summary))
382
+
383
+ print("IINTS Live Stage Demo complete.")
384
+ print(f"Patient config: {args.patient_config}")
385
+ print("")
386
+ print("SDK features this script just demonstrated:")
387
+ print("1. run_full(...) -> real run bundles per scenario")
388
+ print("2. generate_results_poster(...) -> one poster from those bundles")
389
+ print("3. prepare_ai_ready_artifacts(...) -> optional AI-ready supervisor case")
390
+ print("")
391
+ print("What to show next:")
392
+ print(f"1. Poster: {poster_outputs['poster_png']}")
393
+ print(f"2. Jury guide: {output_dir / 'JURY_TALK_TRACK.md'}")
394
+ print(f"3. Live demo script: {output_dir / 'BEURS_LIVE_DEMO_SCRIPT.txt'}")
395
+ print(f"4. Commands: {output_dir / 'run_commands.md'}")
396
+ print("")
397
+ print("Three scenario folders:")
398
+ for scenario in scenario_outputs:
399
+ print(f"- {scenario['label']}: {scenario['output_dir']}")
400
+ print("")
401
+ print("Suggested booth flow:")
402
+ print("- Show the constants and the visible SDK API calls in this file.")
403
+ print("- Run this script once.")
404
+ print("- Open the poster and explain the three panels from left to right.")
405
+ print("- If people want proof, open a scenario folder and show the CSV, PDF, and manifest.")
406
+ print(json.dumps(summary, indent=2, sort_keys=True))
407
+
408
+
409
+ if __name__ == "__main__":
410
+ main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iints-sdk-python35
3
- Version: 1.3.0
3
+ Version: 1.3.2
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
@@ -71,7 +71,7 @@ Docs (GitHub Pages): [python35.github.io/IINTS-SDK](https://python35.github.io/I
71
71
  python3 -m venv .venv
72
72
  source .venv/bin/activate
73
73
  python -m pip install -U pip
74
- pip install iints-sdk-python35
74
+ python -m pip install -U "iints-sdk-python35[mdmp]"
75
75
  ```
76
76
 
77
77
  ```bash
@@ -81,6 +81,14 @@ cd iints_quickstart
81
81
  iints presets run --name baseline_t1d --algo algorithms/example_algorithm.py
82
82
  ```
83
83
 
84
+ If you want the clearest install/path rules first, read:
85
+ - `docs/INSTALLATION.md`
86
+
87
+ Short rule:
88
+ - installed `iints ...` commands can run from any folder
89
+ - `python -m pip install -e ".[mdmp]"` only works from the SDK repo root
90
+ - after `iints quickstart`, switch into the generated project folder
91
+
84
92
  ## CareLink Import
85
93
 
86
94
  The SDK can now ingest Medtronic CareLink / MiniMed CSV exports and convert them into the standard IINTS schema:
@@ -127,19 +135,27 @@ That workbench is designed for three things:
127
135
  The SDK now includes a research-only AI assistant layer for explanations and run summaries.
128
136
  It is gated by MDMP verification before any LLM call is allowed.
129
137
 
130
- Use an active virtual environment for the full flow:
138
+ Use an active virtual environment for the full flow.
139
+
140
+ If you installed the released SDK from PyPI, run:
131
141
 
132
142
  ```bash
133
143
  python3 -m venv .venv
134
144
  source .venv/bin/activate
135
145
  python -m pip install -U pip
136
- python -m pip install -e ".[mdmp]"
146
+ python -m pip install -U "iints-sdk-python35[mdmp]"
147
+ ```
148
+
149
+ If you are developing from source instead, first move into the SDK repo root and then run:
150
+
151
+ ```bash
152
+ cd /path/to/IINTS-SDK
153
+ python -m pip install -U -e ".[mdmp]"
137
154
  ```
138
155
 
139
156
  Run the open local Mistral model locally with Ollama:
140
157
 
141
158
  ```bash
142
- python -m pip install -e ".[mdmp]"
143
159
  ollama pull ministral-3:8b
144
160
  iints ai models
145
161
  ```
@@ -239,14 +255,54 @@ You can also run it through the CLI:
239
255
  iints demo-booth --output-dir results/booth_demo
240
256
  ```
241
257
 
258
+ For a cleaner live explanation, show this source file first:
259
+
260
+ ```bash
261
+ examples/demos/07_live_stage_demo.py
262
+ ```
263
+
264
+ That file is deliberately small and readable, so you can point to:
265
+ - `PATIENT_CONFIG`
266
+ - `OUTPUT_DIR`
267
+ - `DURATION_MINUTES`
268
+ - `TIME_STEP_MINUTES`
269
+ - `SEED`
270
+
271
+ Then run:
272
+
273
+ ```bash
274
+ ./scripts/run_live_stage_demo.sh
275
+ ```
276
+
277
+ That shell wrapper resolves the SDK repo root automatically, so it still works if you launch it from another working directory via its full path.
278
+
279
+ And open:
280
+ - `results/booth_demo_live/booth_demo_poster.png`
281
+ - `results/booth_demo_live/JURY_TALK_TRACK.md`
282
+ - `results/booth_demo_live/BEURS_LIVE_DEMO_SCRIPT.txt`
283
+
284
+ What makes this script good for a booth:
285
+ - it visibly calls `run_full(...)`
286
+ - it visibly calls `generate_results_poster(...)`
287
+ - it visibly calls `prepare_ai_ready_artifacts(...)`
288
+ - you can point to one patient setting and explain how the same pipeline reruns for another patient
289
+
290
+ If you installed the SDK on another machine and do not have the repository checkout there, export the same demo code with:
291
+
292
+ ```bash
293
+ iints demo-export --output-dir iints_demo
294
+ cd iints_demo
295
+ python 07_live_stage_demo.py
296
+ ```
297
+
242
298
  ## Updating The SDK
243
299
 
244
- If another machine is missing newer commands like `iints ai ...` or `iints demo-booth`, upgrade inside the active virtual environment:
300
+ If another machine is missing newer commands like `iints ai ...` or `iints demo-booth`, upgrade inside the active virtual environment to the latest release:
245
301
 
246
302
  ```bash
247
303
  source .venv/bin/activate
248
304
  python -m pip install -U pip
249
- python -m pip install -U "iints-sdk-python35[mdmp]==1.3.0"
305
+ python -m pip install -U "iints-sdk-python35[mdmp]"
250
306
  hash -r
251
307
  python -c "import iints; print(iints.__version__)"
252
308
  ```
@@ -260,6 +316,8 @@ iints-sdk-doctor
260
316
  Full guide:
261
317
  - `docs/UPDATING.md`
262
318
 
319
+ If you specifically need to reproduce a known environment, you can pin an exact release number instead of using the unpinned upgrade command above.
320
+
263
321
  Troubleshooting:
264
322
  - If `iints ai ...` says `No such command 'ai'`, your environment usually still has a legacy `iints` package installed alongside `iints-sdk-python35`.
265
323
  - Run `iints-sdk-doctor` first.
@@ -267,7 +325,7 @@ Troubleshooting:
267
325
 
268
326
  ```bash
269
327
  python -m pip uninstall -y iints iints-sdk-python35
270
- python -m pip install -U "iints-sdk-python35[mdmp]==1.3.0"
328
+ python -m pip install -U "iints-sdk-python35[mdmp]"
271
329
  hash -r
272
330
  ```
273
331
 
@@ -1,4 +1,5 @@
1
- iints/__init__.py,sha256=s1XULKZVzVJ5hsjHybit0pJpgAHBIVdE-G6wc98TWV4,6879
1
+ iints/__init__.py,sha256=Es2ooqFwm2hLeKbqbJG__d6HA2rdBkMPz27SCe3BIm0,6879
2
+ iints/demo_assets.py,sha256=h9bXB6aBptwtvd2drAjg4wp3XE7zXuESxVG8vJgSUJU,2071
2
3
  iints/highlevel.py,sha256=DX12LRmL6YaYY99P0c_P93xfHe4mZjqyLhTYuS6L6hI,20491
3
4
  iints/metrics.py,sha256=O9hqOqJpUhUJDqsbfuqRMS9dkV97gzcgh3Y2jYUqHzg,907
4
5
  iints/ai/__init__.py,sha256=nyRDcFfSHI4a3NbTvySipFc3_inqRMEsr6xIEipWuyo,575
@@ -15,7 +16,7 @@ iints/ai/backends/ollama.py,sha256=3VWi37ueh7oeNK6tPrq3Ks8gbfQhzgNlMHHnV_6BxAY,1
15
16
  iints/analysis/__init__.py,sha256=qz0Su0PtICIBLlUgfq37YW4IkK6BuyfOWaqC6t4NKQM,640
16
17
  iints/analysis/algorithm_xray.py,sha256=-AtXkZsgnsiFQ_K-IozjIDWkq-dDn0i0zmqWVMhINP4,15952
17
18
  iints/analysis/baseline.py,sha256=PCFVb5vX0lYKChZvVk-8I_B5NLQQwGyx7Y6M3XjpIEY,3458
18
- iints/analysis/booth_demo.py,sha256=qpcLwLDqEiCon9RrK2GQrNvkdsb6mkoilAv8EXJsT_s,17131
19
+ iints/analysis/booth_demo.py,sha256=nVjn04VLNndfW1WivZvTKOisTV4V9onil5XeCbhqwqA,17900
19
20
  iints/analysis/carelink_workbench.py,sha256=SZLUamITycXgJpVUhAvsVmU1H_9vSNxp7zl4Ym2cadA,28241
20
21
  iints/analysis/clinical_benchmark.py,sha256=FP3L2Ntub6vpWxCwI91BSQ-Y9pTuFqkt2SYjb91Q7DE,7766
21
22
  iints/analysis/clinical_metrics.py,sha256=a9JNEV7Jzr_DZqS5o8UhHpB7TTkBZ9pp_OqSKN43OZc,18441
@@ -39,7 +40,7 @@ iints/api/registry.py,sha256=h2syJwacFbgrtgnVK20JwlXivvVO31zeJ_Ez4KBkn1g,3240
39
40
  iints/api/template_algorithm.py,sha256=AFs9AymL3ddWAjgpOkF1Oa3TeOSg56siyDt_BmsAND8,9195
40
41
  iints/assets/iints_logo.png,sha256=rWzP8XqIYDrPCTp378w73zA1snKCUHrZ76vwslro-uk,700372
41
42
  iints/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
- iints/cli/cli.py,sha256=hp2N_1DpRiHkOw6huGAVEOPn-K0sPGokbsxQw6rR0k0,220938
43
+ iints/cli/cli.py,sha256=Gt-OaS4BtSfr5YVB6CQsBFW-7ZPEHOEB8qBn3OQd2a0,222261
43
44
  iints/core/__init__.py,sha256=rRH2lTmikavR7BgeJCUla0ZmPbZxATR6rEcSSv_tet4,28
44
45
  iints/core/device.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
46
  iints/core/device_manager.py,sha256=479_CNn6YescDLWDE7w1BbwuLwRUmCUOColAVTEWQc8,2078
@@ -128,6 +129,8 @@ iints/scenarios/__init__.py,sha256=8rH1LQlxfp6h7vQwkSkOV_HAj1PO61rFZt1e0nAAOE8,1
128
129
  iints/scenarios/generator.py,sha256=OJgsBFqByX5wbvaf_Qr1a9Vz8mY7CPvjFJLPBJNfA4Y,3027
129
130
  iints/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
130
131
  iints/templates/default_algorithm.py,sha256=Wmo2qByEfH84XZYnMZkSjYPAlTaob71mbUtXGRfxi8s,3486
132
+ iints/templates/demos/__init__.py,sha256=M84ipt4rGkG6Xx8Tb1E4P3fbeTKIvNmz5b_KXNFRNNY,63
133
+ iints/templates/demos/live_stage_demo.py,sha256=AGaI5gMcfri9TUMm1Q0ym6L_flqFQKkQNdIk3L6iJXY,14974
131
134
  iints/templates/scenarios/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
135
  iints/templates/scenarios/chaos_insulin_stacking.json,sha256=SyQsBsXOFvkoOjCgz3mjP3sYVZwoVzRAr9ix9N5pBKY,648
133
136
  iints/templates/scenarios/chaos_runaway_ai.json,sha256=x39fkG_kDIknW7J-_WtbIi9Cg-gxrgfDOpWVb5d9Scw,544
@@ -145,9 +148,9 @@ iints/validation/schemas.py,sha256=uXhiPxyfyvOgCA83ZPBIzlITOu663fWctYxOMXUyf1I,4
145
148
  iints/visualization/__init__.py,sha256=OdxVHDpY-9bDt8DTWWd-dspn1p0O9T908Cck-IGFaiM,640
146
149
  iints/visualization/cockpit.py,sha256=Y7hoJXcTEWQ8yLiU5X5abT58uqGGsQllftXJwqerG1E,25057
147
150
  iints/visualization/uncertainty_cloud.py,sha256=I5nNzSitgai21rkul31YNtJriSEmCeTsW0GWW2HUskY,19848
148
- iints_sdk_python35-1.3.0.dist-info/licenses/LICENSE,sha256=b1luljj2mWWDW10t_qFIqd9Z6euXAcDBmIXowWuUlm4,1417
149
- iints_sdk_python35-1.3.0.dist-info/METADATA,sha256=i7LlkYoLExo1fYreCnPQ0wKfGCQV8hY9lS0u6XLp4WM,12639
150
- iints_sdk_python35-1.3.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
151
- iints_sdk_python35-1.3.0.dist-info/entry_points.txt,sha256=aVioeLytTHG7WM7L3LIZ6XDJCKiSfqG-nVUQDVHPpQk,578
152
- iints_sdk_python35-1.3.0.dist-info/top_level.txt,sha256=7Usr6NQKiC9SpNFyCis81MmgXy71lDCr5unR8BNXZ0E,6
153
- iints_sdk_python35-1.3.0.dist-info/RECORD,,
151
+ iints_sdk_python35-1.3.2.dist-info/licenses/LICENSE,sha256=b1luljj2mWWDW10t_qFIqd9Z6euXAcDBmIXowWuUlm4,1417
152
+ iints_sdk_python35-1.3.2.dist-info/METADATA,sha256=FBAzFYfrxxe_oJNkcfuVAQRpIJPoi4ytimYmI4cmTjg,14445
153
+ iints_sdk_python35-1.3.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
154
+ iints_sdk_python35-1.3.2.dist-info/entry_points.txt,sha256=aVioeLytTHG7WM7L3LIZ6XDJCKiSfqG-nVUQDVHPpQk,578
155
+ iints_sdk_python35-1.3.2.dist-info/top_level.txt,sha256=7Usr6NQKiC9SpNFyCis81MmgXy71lDCr5unR8BNXZ0E,6
156
+ iints_sdk_python35-1.3.2.dist-info/RECORD,,