iints-sdk-python35 1.1.0__tar.gz → 1.1.2__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.1.0/src/iints_sdk_python35.egg-info → iints_sdk_python35-1.1.2}/PKG-INFO +39 -10
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/README.md +38 -9
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/pyproject.toml +2 -1
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/__init__.py +9 -1
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/ai/__init__.py +5 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/ai/backends/mistral_api.py +1 -1
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/ai/backends/ollama.py +76 -3
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/ai/cli.py +176 -21
- iints_sdk_python35-1.1.2/src/iints/ai/model_catalog.py +55 -0
- iints_sdk_python35-1.1.2/src/iints/ai/prepare.py +342 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/cli/cli.py +29 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2/src/iints_sdk_python35.egg-info}/PKG-INFO +39 -10
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints_sdk_python35.egg-info/SOURCES.txt +3 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints_sdk_python35.egg-info/entry_points.txt +1 -0
- iints_sdk_python35-1.1.2/tests/test_install_doctor.py +32 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/LICENSE +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/setup.cfg +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/ai/assistant.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/ai/backends/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/ai/backends/base.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/ai/mdmp_guard.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/ai/prompts.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/algorithm_xray.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/baseline.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/clinical_benchmark.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/clinical_metrics.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/clinical_tir_analyzer.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/diabetes_metrics.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/edge_efficiency.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/edge_performance_monitor.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/explainability.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/explainable_ai.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/hardware_benchmark.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/metrics.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/population_report.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/reporting.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/safety_index.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/sensor_filtering.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/analysis/validator.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/api/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/api/base_algorithm.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/api/registry.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/api/template_algorithm.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/assets/iints_logo.png +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/cli/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/algorithms/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/algorithms/battle_runner.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/algorithms/correction_bolus.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/algorithms/discovery.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/algorithms/fixed_basal_bolus.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/algorithms/hybrid_algorithm.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/algorithms/lstm_algorithm.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/algorithms/mock_algorithms.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/algorithms/pid_controller.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/algorithms/standard_pump_algo.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/device.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/device_manager.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/devices/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/devices/models.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/patient/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/patient/bergman_model.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/patient/models.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/patient/patient_factory.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/patient/profile.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/safety/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/safety/config.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/safety/input_validator.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/safety/supervisor.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/simulation/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/simulation/scenario_parser.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/simulator.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/core/supervisor.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/adapter.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/column_mapper.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/contracts.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/datasets.json +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/demo/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/demo/demo_cgm.csv +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/guardians.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/importer.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/ingestor.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/mdmp_visualizer.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/nightscout.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/quality_checker.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/registry.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/runner.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/synthetic_mirror.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/tidepool.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/universal_parser.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/virtual_patients/clinic_safe_baseline.yaml +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/virtual_patients/clinic_safe_hyper_challenge.yaml +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/virtual_patients/clinic_safe_hypo_prone.yaml +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/virtual_patients/clinic_safe_midnight.yaml +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/virtual_patients/clinic_safe_pizza.yaml +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/virtual_patients/clinic_safe_stress_meal.yaml +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/virtual_patients/default_patient.yaml +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/data/virtual_patients/patient_559_config.yaml +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/emulation/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/emulation/legacy_base.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/emulation/medtronic_780g.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/emulation/omnipod_5.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/emulation/tandem_controliq.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/highlevel.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/learning/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/learning/autonomous_optimizer.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/learning/learning_system.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/mdmp/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/mdmp/backend.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/metrics.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/population/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/population/generator.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/population/runner.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/presets/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/presets/evidence_sources.yaml +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/presets/forecast_calibration_profiles.yaml +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/presets/golden_benchmark.yaml +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/presets/presets.json +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/presets/safety_contract_default.yaml +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/presets/validation_profiles.yaml +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/research/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/research/audit.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/research/calibration_gate.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/research/config.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/research/dataset.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/research/evaluation.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/research/losses.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/research/metrics.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/research/model_registry.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/research/predictor.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/scenarios/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/scenarios/generator.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/templates/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/templates/default_algorithm.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/templates/scenarios/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/templates/scenarios/chaos_insulin_stacking.json +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/templates/scenarios/chaos_runaway_ai.json +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/templates/scenarios/example_scenario.json +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/templates/scenarios/exercise_stress.json +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/utils/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/utils/plotting.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/utils/run_io.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/validation/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/validation/golden.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/validation/replay.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/validation/run_validation.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/validation/safety_contract.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/validation/schemas.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/visualization/__init__.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/visualization/cockpit.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints/visualization/uncertainty_cloud.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints_sdk_python35.egg-info/dependency_links.txt +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints_sdk_python35.egg-info/requires.txt +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/src/iints_sdk_python35.egg-info/top_level.txt +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/tests/test_bergman.py +0 -0
- {iints_sdk_python35-1.1.0 → iints_sdk_python35-1.1.2}/tests/test_population.py +0 -0
{iints_sdk_python35-1.1.0/src/iints_sdk_python35.egg-info → iints_sdk_python35-1.1.2}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iints-sdk-python35
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.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
|
|
@@ -81,7 +81,7 @@ cd iints_quickstart
|
|
|
81
81
|
iints presets run --name baseline_t1d --algo algorithms/example_algorithm.py
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
## AI Assistant (Ministral via Ollama)
|
|
84
|
+
## AI Assistant (Ministral 3 Open-Weight via Ollama)
|
|
85
85
|
|
|
86
86
|
The SDK now includes a research-only AI assistant layer for explanations and run summaries.
|
|
87
87
|
It is gated by MDMP verification before any LLM call is allowed.
|
|
@@ -95,30 +95,59 @@ python -m pip install -U pip
|
|
|
95
95
|
python -m pip install -e ".[mdmp]"
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
Run
|
|
98
|
+
Run the open local Mistral model locally with Ollama:
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
python -m pip install -e ".[mdmp]"
|
|
102
|
+
ollama pull ministral-3:8b
|
|
103
|
+
iints ai models
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Recommended first-time setup:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
ollama pull ministral-3:8b
|
|
110
|
+
iints ai local-check --model ministral-3:8b
|
|
103
111
|
```
|
|
104
112
|
|
|
105
|
-
|
|
113
|
+
Recommended flow:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
iints quickstart --project-name iints_quickstart
|
|
117
|
+
cd iints_quickstart
|
|
118
|
+
iints presets run --name baseline_t1d --algo algorithms/example_algorithm.py
|
|
119
|
+
iints ai prepare results/<run_id>
|
|
120
|
+
iints ai report results/<run_id>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Direct JSON mode still works if you already have your own payloads and signed MDMP artifact:
|
|
106
124
|
|
|
107
125
|
```bash
|
|
108
126
|
iints ai explain results/step.json \
|
|
109
127
|
--mdmp-cert results/report.signed.mdmp
|
|
110
|
-
|
|
111
|
-
iints ai report results/simulation_run.json \
|
|
112
|
-
--mdmp-cert results/report.signed.mdmp \
|
|
113
|
-
--output results/ai_report.md
|
|
114
128
|
```
|
|
115
129
|
|
|
116
130
|
Notes:
|
|
117
131
|
- AI analysis is blocked if the MDMP artifact is invalid.
|
|
118
132
|
- Minimum required MDMP grade defaults to `research_grade`.
|
|
133
|
+
- The SDK now targets the open local `Ministral 3` Ollama model by default.
|
|
134
|
+
- Users can choose a larger or smaller local Mistral-family model with `--model ...`.
|
|
119
135
|
- Large JSON payloads are clipped automatically before prompt generation to keep local inference stable.
|
|
136
|
+
- `iints ai prepare <run_dir>` now creates AI-ready JSON payloads and, when MDMP is installed, a local development certificate plus keypair in `<run_dir>/ai/`.
|
|
137
|
+
- After `iints ai prepare`, you can point `iints ai explain|trends|anomalies|report` directly at the run directory.
|
|
120
138
|
- Output is research-only and not medical advice.
|
|
121
139
|
|
|
140
|
+
Troubleshooting:
|
|
141
|
+
- If `iints ai ...` says `No such command 'ai'`, your environment usually still has a legacy `iints` package installed alongside `iints-sdk-python35`.
|
|
142
|
+
- Run `iints-sdk-doctor` first.
|
|
143
|
+
- If it reports a conflict, repair the environment with:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
python -m pip uninstall -y iints iints-sdk-python35
|
|
147
|
+
python -m pip install -U "iints-sdk-python35[mdmp]==1.1.2"
|
|
148
|
+
hash -r
|
|
149
|
+
```
|
|
150
|
+
|
|
122
151
|
## MDMP (Short)
|
|
123
152
|
MDMP is the data-quality protocol used by IINTS.
|
|
124
153
|
|
|
@@ -30,7 +30,7 @@ cd iints_quickstart
|
|
|
30
30
|
iints presets run --name baseline_t1d --algo algorithms/example_algorithm.py
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
## AI Assistant (Ministral via Ollama)
|
|
33
|
+
## AI Assistant (Ministral 3 Open-Weight via Ollama)
|
|
34
34
|
|
|
35
35
|
The SDK now includes a research-only AI assistant layer for explanations and run summaries.
|
|
36
36
|
It is gated by MDMP verification before any LLM call is allowed.
|
|
@@ -44,30 +44,59 @@ python -m pip install -U pip
|
|
|
44
44
|
python -m pip install -e ".[mdmp]"
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
Run
|
|
47
|
+
Run the open local Mistral model locally with Ollama:
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
python -m pip install -e ".[mdmp]"
|
|
51
|
+
ollama pull ministral-3:8b
|
|
52
|
+
iints ai models
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Recommended first-time setup:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
ollama pull ministral-3:8b
|
|
59
|
+
iints ai local-check --model ministral-3:8b
|
|
52
60
|
```
|
|
53
61
|
|
|
54
|
-
|
|
62
|
+
Recommended flow:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
iints quickstart --project-name iints_quickstart
|
|
66
|
+
cd iints_quickstart
|
|
67
|
+
iints presets run --name baseline_t1d --algo algorithms/example_algorithm.py
|
|
68
|
+
iints ai prepare results/<run_id>
|
|
69
|
+
iints ai report results/<run_id>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Direct JSON mode still works if you already have your own payloads and signed MDMP artifact:
|
|
55
73
|
|
|
56
74
|
```bash
|
|
57
75
|
iints ai explain results/step.json \
|
|
58
76
|
--mdmp-cert results/report.signed.mdmp
|
|
59
|
-
|
|
60
|
-
iints ai report results/simulation_run.json \
|
|
61
|
-
--mdmp-cert results/report.signed.mdmp \
|
|
62
|
-
--output results/ai_report.md
|
|
63
77
|
```
|
|
64
78
|
|
|
65
79
|
Notes:
|
|
66
80
|
- AI analysis is blocked if the MDMP artifact is invalid.
|
|
67
81
|
- Minimum required MDMP grade defaults to `research_grade`.
|
|
82
|
+
- The SDK now targets the open local `Ministral 3` Ollama model by default.
|
|
83
|
+
- Users can choose a larger or smaller local Mistral-family model with `--model ...`.
|
|
68
84
|
- Large JSON payloads are clipped automatically before prompt generation to keep local inference stable.
|
|
85
|
+
- `iints ai prepare <run_dir>` now creates AI-ready JSON payloads and, when MDMP is installed, a local development certificate plus keypair in `<run_dir>/ai/`.
|
|
86
|
+
- After `iints ai prepare`, you can point `iints ai explain|trends|anomalies|report` directly at the run directory.
|
|
69
87
|
- Output is research-only and not medical advice.
|
|
70
88
|
|
|
89
|
+
Troubleshooting:
|
|
90
|
+
- If `iints ai ...` says `No such command 'ai'`, your environment usually still has a legacy `iints` package installed alongside `iints-sdk-python35`.
|
|
91
|
+
- Run `iints-sdk-doctor` first.
|
|
92
|
+
- If it reports a conflict, repair the environment with:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
python -m pip uninstall -y iints iints-sdk-python35
|
|
96
|
+
python -m pip install -U "iints-sdk-python35[mdmp]==1.1.2"
|
|
97
|
+
hash -r
|
|
98
|
+
```
|
|
99
|
+
|
|
71
100
|
## MDMP (Short)
|
|
72
101
|
MDMP is the data-quality protocol used by IINTS.
|
|
73
102
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "iints-sdk-python35"
|
|
7
|
-
version = "1.1.
|
|
7
|
+
version = "1.1.2"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Rune Bobbaers", email="rune.bobbaers@gmail.com" },
|
|
10
10
|
]
|
|
@@ -65,6 +65,7 @@ mdmp = [
|
|
|
65
65
|
|
|
66
66
|
[project.scripts]
|
|
67
67
|
iints = "iints.cli.cli:app"
|
|
68
|
+
iints-sdk-doctor = "iints_sdk_python35_doctor:main"
|
|
68
69
|
|
|
69
70
|
[project.entry-points."iints.algorithms"]
|
|
70
71
|
"PID Controller" = "iints.core.algorithms.pid_controller:PIDController"
|
|
@@ -3,7 +3,15 @@
|
|
|
3
3
|
import pandas as pd # Required for type hints like pd.DataFrame
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
try:
|
|
7
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
8
|
+
except ImportError: # pragma: no cover - Python < 3.8 fallback
|
|
9
|
+
from importlib_metadata import PackageNotFoundError, version # type: ignore
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
__version__ = version("iints-sdk-python35")
|
|
13
|
+
except PackageNotFoundError: # pragma: no cover - source tree fallback
|
|
14
|
+
__version__ = "1.1.2"
|
|
7
15
|
|
|
8
16
|
# Note to developers: this SDK is currently maintained by a single author.
|
|
9
17
|
# Please report bugs via GitHub issues and feel free to contribute fixes via PRs.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from .assistant import AIResponse, IINTSAssistant
|
|
2
2
|
from .backends import DEFAULT_MINISTRAL_MODEL, DEFAULT_OLLAMA_HOST, OllamaBackend
|
|
3
3
|
from .mdmp_guard import GuardResult, MDMPGuard
|
|
4
|
+
from .model_catalog import LocalMistralModelProfile, list_local_mistral_models
|
|
5
|
+
from .prepare import prepare_ai_ready_artifacts
|
|
4
6
|
|
|
5
7
|
__all__ = [
|
|
6
8
|
"AIResponse",
|
|
@@ -10,4 +12,7 @@ __all__ = [
|
|
|
10
12
|
"OllamaBackend",
|
|
11
13
|
"GuardResult",
|
|
12
14
|
"MDMPGuard",
|
|
15
|
+
"LocalMistralModelProfile",
|
|
16
|
+
"list_local_mistral_models",
|
|
17
|
+
"prepare_ai_ready_artifacts",
|
|
13
18
|
]
|
|
@@ -13,5 +13,5 @@ class MistralAPIBackend:
|
|
|
13
13
|
def complete(self, *, system_prompt: str, user_prompt: str) -> str:
|
|
14
14
|
raise RuntimeError(
|
|
15
15
|
"Cloud fallback is not enabled in this SDK build yet. "
|
|
16
|
-
"Use mode='local' with Ollama for Ministral."
|
|
16
|
+
"Use mode='local' with Ollama for the open Ministral 3 model."
|
|
17
17
|
)
|
|
@@ -6,12 +6,19 @@ from urllib import error, request
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
DEFAULT_OLLAMA_HOST = "http://127.0.0.1:11434"
|
|
9
|
-
DEFAULT_MINISTRAL_MODEL = "
|
|
9
|
+
DEFAULT_MINISTRAL_MODEL = "ministral-3:8b"
|
|
10
|
+
LEGACY_MINISTRAL_MODEL = "mistral/ministral-8b-instruct"
|
|
11
|
+
MIN_OLLAMA_VERSION_FOR_MINISTRAL_3 = (0, 13, 1)
|
|
10
12
|
MINISTRAL_MODEL_ALIASES = (
|
|
11
13
|
DEFAULT_MINISTRAL_MODEL,
|
|
14
|
+
"ministral-3",
|
|
15
|
+
"ministral-3:latest",
|
|
16
|
+
"ministral-3:8b",
|
|
17
|
+
"ministral-3:8b-instruct",
|
|
12
18
|
"ministral",
|
|
13
19
|
"ministral-8b",
|
|
14
20
|
"ministral-8b-instruct",
|
|
21
|
+
LEGACY_MINISTRAL_MODEL,
|
|
15
22
|
)
|
|
16
23
|
|
|
17
24
|
|
|
@@ -23,7 +30,7 @@ class OllamaBackend:
|
|
|
23
30
|
*,
|
|
24
31
|
model_name: str = DEFAULT_MINISTRAL_MODEL,
|
|
25
32
|
base_url: str | None = None,
|
|
26
|
-
timeout_seconds: float =
|
|
33
|
+
timeout_seconds: float = 120.0,
|
|
27
34
|
) -> None:
|
|
28
35
|
self.model_name = model_name
|
|
29
36
|
self.base_url = (base_url or os.getenv("OLLAMA_HOST") or DEFAULT_OLLAMA_HOST).rstrip("/")
|
|
@@ -33,6 +40,28 @@ class OllamaBackend:
|
|
|
33
40
|
def _pull_hint(self) -> str:
|
|
34
41
|
return f"ollama pull {self.model_name}"
|
|
35
42
|
|
|
43
|
+
def _requires_ministral_3_runtime(self) -> bool:
|
|
44
|
+
requested = self.model_name.strip().lower()
|
|
45
|
+
return requested.startswith("ministral-3") or requested == "ministral"
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def _parse_version(raw_version: str) -> tuple[int, ...] | None:
|
|
49
|
+
value = raw_version.strip().lower().lstrip("v")
|
|
50
|
+
numeric_parts: list[int] = []
|
|
51
|
+
for part in value.split("."):
|
|
52
|
+
digits = ""
|
|
53
|
+
for char in part:
|
|
54
|
+
if char.isdigit():
|
|
55
|
+
digits += char
|
|
56
|
+
else:
|
|
57
|
+
break
|
|
58
|
+
if not digits:
|
|
59
|
+
break
|
|
60
|
+
numeric_parts.append(int(digits))
|
|
61
|
+
if not numeric_parts:
|
|
62
|
+
return None
|
|
63
|
+
return tuple(numeric_parts)
|
|
64
|
+
|
|
36
65
|
def _request_json(
|
|
37
66
|
self,
|
|
38
67
|
path: str,
|
|
@@ -79,6 +108,27 @@ class OllamaBackend:
|
|
|
79
108
|
return False
|
|
80
109
|
return True
|
|
81
110
|
|
|
111
|
+
def server_version(self) -> str | None:
|
|
112
|
+
try:
|
|
113
|
+
response = self._request_json("/api/version", method="GET")
|
|
114
|
+
except Exception:
|
|
115
|
+
return None
|
|
116
|
+
raw_version = response.get("version")
|
|
117
|
+
if isinstance(raw_version, str) and raw_version.strip():
|
|
118
|
+
return raw_version.strip()
|
|
119
|
+
return None
|
|
120
|
+
|
|
121
|
+
def version_supported(self) -> tuple[bool | None, str | None]:
|
|
122
|
+
version = self.server_version()
|
|
123
|
+
if version is None:
|
|
124
|
+
return None, None
|
|
125
|
+
if not self._requires_ministral_3_runtime():
|
|
126
|
+
return True, version
|
|
127
|
+
parsed = self._parse_version(version)
|
|
128
|
+
if parsed is None:
|
|
129
|
+
return None, version
|
|
130
|
+
return parsed >= MIN_OLLAMA_VERSION_FOR_MINISTRAL_3, version
|
|
131
|
+
|
|
82
132
|
def list_models(self) -> list[str]:
|
|
83
133
|
response = self._request_json("/api/tags", method="GET")
|
|
84
134
|
raw_models = response.get("models", [])
|
|
@@ -102,12 +152,24 @@ class OllamaBackend:
|
|
|
102
152
|
return installed_lookup[self.model_name.lower()]
|
|
103
153
|
|
|
104
154
|
requested = self.model_name.strip().lower()
|
|
105
|
-
if requested in {
|
|
155
|
+
if requested in {
|
|
156
|
+
"ministral",
|
|
157
|
+
"ministral-3",
|
|
158
|
+
"ministral-3:latest",
|
|
159
|
+
"ministral-3:8b",
|
|
160
|
+
"ministral-3:8b-instruct",
|
|
161
|
+
"ministral-8b",
|
|
162
|
+
"ministral-8b-instruct",
|
|
163
|
+
}:
|
|
106
164
|
for alias in MINISTRAL_MODEL_ALIASES:
|
|
107
165
|
resolved = installed_lookup.get(alias.lower())
|
|
108
166
|
if resolved is not None:
|
|
109
167
|
return resolved
|
|
110
168
|
|
|
169
|
+
for installed_name in installed:
|
|
170
|
+
lowered = installed_name.lower()
|
|
171
|
+
if "ministral-3" in lowered and "8b" in lowered:
|
|
172
|
+
return installed_name
|
|
111
173
|
for installed_name in installed:
|
|
112
174
|
lowered = installed_name.lower()
|
|
113
175
|
if "ministral" in lowered and "8b" in lowered:
|
|
@@ -116,6 +178,14 @@ class OllamaBackend:
|
|
|
116
178
|
return None
|
|
117
179
|
|
|
118
180
|
def ensure_model_ready(self) -> str:
|
|
181
|
+
version_ok, version = self.version_supported()
|
|
182
|
+
if version_ok is False:
|
|
183
|
+
required_version = ".".join(str(part) for part in MIN_OLLAMA_VERSION_FOR_MINISTRAL_3)
|
|
184
|
+
raise RuntimeError(
|
|
185
|
+
"The open Ministral 3 local model requires a newer Ollama runtime.\n"
|
|
186
|
+
f"Detected Ollama: {version}\n"
|
|
187
|
+
f"Required Ollama: >= {required_version}"
|
|
188
|
+
)
|
|
119
189
|
try:
|
|
120
190
|
resolved = self.resolve_model_name()
|
|
121
191
|
except RuntimeError:
|
|
@@ -137,6 +207,7 @@ class OllamaBackend:
|
|
|
137
207
|
return resolved
|
|
138
208
|
|
|
139
209
|
def healthcheck(self) -> dict[str, object]:
|
|
210
|
+
version_ok, version = self.version_supported()
|
|
140
211
|
installed = self.list_models()
|
|
141
212
|
resolved = self.resolve_model_name() if installed else None
|
|
142
213
|
return {
|
|
@@ -148,6 +219,8 @@ class OllamaBackend:
|
|
|
148
219
|
"ready": resolved is not None,
|
|
149
220
|
"pull_command": None if resolved is not None else self._pull_hint(),
|
|
150
221
|
"timeout_seconds": self.timeout_seconds,
|
|
222
|
+
"server_version": version,
|
|
223
|
+
"version_ok": version_ok,
|
|
151
224
|
}
|
|
152
225
|
|
|
153
226
|
def complete(self, *, system_prompt: str, user_prompt: str) -> str:
|
|
@@ -7,10 +7,13 @@ from typing import Any, Optional
|
|
|
7
7
|
import typer
|
|
8
8
|
from rich.console import Console
|
|
9
9
|
from rich.panel import Panel
|
|
10
|
+
from rich.table import Table
|
|
10
11
|
from typing_extensions import Annotated
|
|
11
12
|
|
|
12
13
|
from .assistant import AIResponse, IINTSAssistant
|
|
13
14
|
from .backends import DEFAULT_MINISTRAL_MODEL, OllamaBackend
|
|
15
|
+
from .model_catalog import list_local_mistral_models
|
|
16
|
+
from .prepare import prepare_ai_ready_artifacts
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
app = typer.Typer(help="Research-only AI assistant commands gated by MDMP certification.")
|
|
@@ -34,6 +37,57 @@ def _load_json_payload(path: Path, label: str) -> Any:
|
|
|
34
37
|
return payload
|
|
35
38
|
|
|
36
39
|
|
|
40
|
+
def _default_prepared_payload(task: str, ai_dir: Path) -> Path:
|
|
41
|
+
candidates = {
|
|
42
|
+
"explain": ["step_riskiest.json", "step_latest.json"],
|
|
43
|
+
"trends": ["trends_payload.json"],
|
|
44
|
+
"anomalies": ["anomalies_payload.json"],
|
|
45
|
+
"report": ["report_payload.json"],
|
|
46
|
+
}.get(task, [])
|
|
47
|
+
for filename in candidates:
|
|
48
|
+
candidate = ai_dir / filename
|
|
49
|
+
if candidate.is_file():
|
|
50
|
+
return candidate
|
|
51
|
+
expected = ", ".join(candidates) if candidates else "prepared payload"
|
|
52
|
+
raise typer.BadParameter(
|
|
53
|
+
f"No prepared AI payload found in {ai_dir}. Expected one of: {expected}. "
|
|
54
|
+
"Run `iints ai prepare <run_dir>` first."
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _resolve_cli_inputs(
|
|
59
|
+
*,
|
|
60
|
+
task: str,
|
|
61
|
+
input_path: Path,
|
|
62
|
+
mdmp_cert: Path | None,
|
|
63
|
+
public_key: Path | None,
|
|
64
|
+
trust_store: Path | None,
|
|
65
|
+
) -> tuple[Path, Path, Path | None]:
|
|
66
|
+
resolved_input = input_path
|
|
67
|
+
resolved_cert = mdmp_cert
|
|
68
|
+
resolved_public_key = public_key
|
|
69
|
+
|
|
70
|
+
if input_path.is_dir():
|
|
71
|
+
ai_dir = input_path / "ai"
|
|
72
|
+
resolved_input = _default_prepared_payload(task, ai_dir)
|
|
73
|
+
if resolved_cert is None:
|
|
74
|
+
candidate_cert = ai_dir / "report.signed.mdmp"
|
|
75
|
+
if candidate_cert.is_file():
|
|
76
|
+
resolved_cert = candidate_cert
|
|
77
|
+
if resolved_public_key is None and trust_store is None:
|
|
78
|
+
candidate_public_key = ai_dir / "keys" / "mdmp_pub_v1.pem"
|
|
79
|
+
if candidate_public_key.is_file():
|
|
80
|
+
resolved_public_key = candidate_public_key
|
|
81
|
+
|
|
82
|
+
if resolved_cert is None:
|
|
83
|
+
raise typer.BadParameter(
|
|
84
|
+
"No MDMP certificate provided. Pass --mdmp-cert or run "
|
|
85
|
+
"`iints ai prepare <run_dir>` to generate a local development certificate."
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return resolved_input, resolved_cert, resolved_public_key
|
|
89
|
+
|
|
90
|
+
|
|
37
91
|
def _write_output(path: Path | None, response: AIResponse) -> None:
|
|
38
92
|
if path is None:
|
|
39
93
|
return
|
|
@@ -64,6 +118,7 @@ def _render_local_check(console: Console, status: dict[str, object]) -> None:
|
|
|
64
118
|
f"Endpoint: {status.get('base_url')}",
|
|
65
119
|
f"Requested model: {status.get('requested_model')}",
|
|
66
120
|
f"Resolved local model: {resolved_model}",
|
|
121
|
+
f"Server version: {status.get('server_version') or 'unknown'}",
|
|
67
122
|
f"Timeout (s): {status.get('timeout_seconds')}",
|
|
68
123
|
f"Installed models: {installed_text}",
|
|
69
124
|
(
|
|
@@ -78,9 +133,81 @@ def _render_local_check(console: Console, status: dict[str, object]) -> None:
|
|
|
78
133
|
)
|
|
79
134
|
)
|
|
80
135
|
if ready:
|
|
81
|
-
console.print("[green]Local Ollama backend is ready for Ministral inference.[/green]")
|
|
136
|
+
console.print("[green]Local Ollama backend is ready for open Ministral 3 inference.[/green]")
|
|
82
137
|
else:
|
|
83
138
|
console.print("[bold red]Local Ollama backend is reachable, but the requested model is missing.[/bold red]")
|
|
139
|
+
if status.get("version_ok") is False:
|
|
140
|
+
console.print("[bold red]Ollama is too old for the open Ministral 3 runtime.[/bold red]")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@app.command("models")
|
|
144
|
+
def models() -> None:
|
|
145
|
+
console = Console()
|
|
146
|
+
table = Table(title="IINTS AI Local Mistral Model Guide")
|
|
147
|
+
table.add_column("Model Tag", style="cyan", no_wrap=True)
|
|
148
|
+
table.add_column("Best For", style="green")
|
|
149
|
+
table.add_column("Approx Download")
|
|
150
|
+
table.add_column("System RAM")
|
|
151
|
+
table.add_column("GPU VRAM")
|
|
152
|
+
table.add_column("Notes", overflow="fold")
|
|
153
|
+
|
|
154
|
+
for profile in list_local_mistral_models():
|
|
155
|
+
vram = f"{profile.recommended_vram_gb}+ GB" if profile.recommended_vram_gb is not None else "CPU-only"
|
|
156
|
+
table.add_row(
|
|
157
|
+
profile.tag,
|
|
158
|
+
profile.fit,
|
|
159
|
+
f"{profile.approx_download_gb:.1f} GB",
|
|
160
|
+
f"{profile.recommended_system_ram_gb}+ GB",
|
|
161
|
+
vram,
|
|
162
|
+
profile.notes,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
console.print(table)
|
|
166
|
+
console.print(
|
|
167
|
+
"[dim]Tip:[/dim] start with "
|
|
168
|
+
f"`{DEFAULT_MINISTRAL_MODEL}` unless you know your hardware can comfortably run a larger local model."
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@app.command("prepare")
|
|
173
|
+
def prepare(
|
|
174
|
+
run_dir: Annotated[Path, typer.Argument(help="Run output directory containing results.csv and run_metadata.json.")],
|
|
175
|
+
create_dev_mdmp_cert: Annotated[
|
|
176
|
+
bool,
|
|
177
|
+
typer.Option(
|
|
178
|
+
"--create-dev-mdmp-cert/--no-create-dev-mdmp-cert",
|
|
179
|
+
help="Generate a local development MDMP certificate and keypair for AI commands.",
|
|
180
|
+
),
|
|
181
|
+
] = True,
|
|
182
|
+
grade: Annotated[str, typer.Option(help="Grade to embed in the local development MDMP certificate.")] = "research_grade",
|
|
183
|
+
expires_days: Annotated[int, typer.Option(help="Certificate expiry window in days for local development certs.")] = 30,
|
|
184
|
+
key_dir: Annotated[Optional[Path], typer.Option(help="Optional directory to store the generated local MDMP keypair.")] = None,
|
|
185
|
+
) -> None:
|
|
186
|
+
console = Console()
|
|
187
|
+
try:
|
|
188
|
+
outputs = prepare_ai_ready_artifacts(
|
|
189
|
+
run_dir,
|
|
190
|
+
create_dev_mdmp_cert=create_dev_mdmp_cert,
|
|
191
|
+
grade=grade,
|
|
192
|
+
expires_days=expires_days,
|
|
193
|
+
key_dir=key_dir,
|
|
194
|
+
)
|
|
195
|
+
except Exception as exc:
|
|
196
|
+
console.print(f"[bold red]Error:[/bold red] {exc}")
|
|
197
|
+
raise typer.Exit(code=1)
|
|
198
|
+
|
|
199
|
+
table = Table(title="IINTS AI Prepared Artifacts")
|
|
200
|
+
table.add_column("Artifact", style="cyan")
|
|
201
|
+
table.add_column("Path", overflow="fold")
|
|
202
|
+
for key, value in outputs.items():
|
|
203
|
+
table.add_row(key, value)
|
|
204
|
+
console.print(table)
|
|
205
|
+
console.print("[green]Prepared AI payloads are ready.[/green]")
|
|
206
|
+
if "mdmp_cert" in outputs:
|
|
207
|
+
console.print(
|
|
208
|
+
"[green]You can now run:[/green] "
|
|
209
|
+
f"`iints ai report {run_dir}` or `iints ai explain {run_dir}`"
|
|
210
|
+
)
|
|
84
211
|
|
|
85
212
|
|
|
86
213
|
def _build_assistant(
|
|
@@ -135,8 +262,8 @@ def local_check(
|
|
|
135
262
|
|
|
136
263
|
@app.command("explain")
|
|
137
264
|
def explain(
|
|
138
|
-
input_json: Annotated[Path, typer.Argument(help="JSON file with a single simulation step or decision context.")],
|
|
139
|
-
mdmp_cert: Annotated[Path, typer.Option(help="Signed MDMP artifact required before AI analysis can run.")],
|
|
265
|
+
input_json: Annotated[Path, typer.Argument(help="Prepared run directory or JSON file with a single simulation step or decision context.")],
|
|
266
|
+
mdmp_cert: Annotated[Optional[Path], typer.Option(help="Signed MDMP artifact required before AI analysis can run.")] = None,
|
|
140
267
|
mode: Annotated[str, typer.Option(help="AI backend mode. Use 'local' for Ollama/Ministral.")] = "auto",
|
|
141
268
|
model: Annotated[str, typer.Option(help="Ollama model name to use.")] = DEFAULT_MINISTRAL_MODEL,
|
|
142
269
|
minimum_grade: Annotated[str, typer.Option(help="Minimum MDMP grade required to allow analysis.")] = "research_grade",
|
|
@@ -148,13 +275,20 @@ def explain(
|
|
|
148
275
|
) -> None:
|
|
149
276
|
console = Console()
|
|
150
277
|
try:
|
|
151
|
-
|
|
152
|
-
|
|
278
|
+
resolved_input, resolved_cert, resolved_public_key = _resolve_cli_inputs(
|
|
279
|
+
task="explain",
|
|
280
|
+
input_path=input_json,
|
|
153
281
|
mdmp_cert=mdmp_cert,
|
|
282
|
+
public_key=public_key,
|
|
283
|
+
trust_store=trust_store,
|
|
284
|
+
)
|
|
285
|
+
payload = _load_json_payload(resolved_input, "Input JSON")
|
|
286
|
+
assistant = _build_assistant(
|
|
287
|
+
mdmp_cert=resolved_cert,
|
|
154
288
|
mode=mode,
|
|
155
289
|
model=model,
|
|
156
290
|
minimum_grade=minimum_grade,
|
|
157
|
-
public_key=
|
|
291
|
+
public_key=resolved_public_key,
|
|
158
292
|
trust_store=trust_store,
|
|
159
293
|
ollama_host=ollama_host,
|
|
160
294
|
timeout_seconds=timeout_seconds,
|
|
@@ -169,8 +303,8 @@ def explain(
|
|
|
169
303
|
|
|
170
304
|
@app.command("trends")
|
|
171
305
|
def trends(
|
|
172
|
-
input_json: Annotated[Path, typer.Argument(help="JSON file with glucose trace data or a run payload.")],
|
|
173
|
-
mdmp_cert: Annotated[Path, typer.Option(help="Signed MDMP artifact required before AI analysis can run.")],
|
|
306
|
+
input_json: Annotated[Path, typer.Argument(help="Prepared run directory or JSON file with glucose trace data or a run payload.")],
|
|
307
|
+
mdmp_cert: Annotated[Optional[Path], typer.Option(help="Signed MDMP artifact required before AI analysis can run.")] = None,
|
|
174
308
|
mode: Annotated[str, typer.Option(help="AI backend mode. Use 'local' for Ollama/Ministral.")] = "auto",
|
|
175
309
|
model: Annotated[str, typer.Option(help="Ollama model name to use.")] = DEFAULT_MINISTRAL_MODEL,
|
|
176
310
|
minimum_grade: Annotated[str, typer.Option(help="Minimum MDMP grade required to allow analysis.")] = "research_grade",
|
|
@@ -182,13 +316,20 @@ def trends(
|
|
|
182
316
|
) -> None:
|
|
183
317
|
console = Console()
|
|
184
318
|
try:
|
|
185
|
-
|
|
186
|
-
|
|
319
|
+
resolved_input, resolved_cert, resolved_public_key = _resolve_cli_inputs(
|
|
320
|
+
task="trends",
|
|
321
|
+
input_path=input_json,
|
|
187
322
|
mdmp_cert=mdmp_cert,
|
|
323
|
+
public_key=public_key,
|
|
324
|
+
trust_store=trust_store,
|
|
325
|
+
)
|
|
326
|
+
payload = _load_json_payload(resolved_input, "Input JSON")
|
|
327
|
+
assistant = _build_assistant(
|
|
328
|
+
mdmp_cert=resolved_cert,
|
|
188
329
|
mode=mode,
|
|
189
330
|
model=model,
|
|
190
331
|
minimum_grade=minimum_grade,
|
|
191
|
-
public_key=
|
|
332
|
+
public_key=resolved_public_key,
|
|
192
333
|
trust_store=trust_store,
|
|
193
334
|
ollama_host=ollama_host,
|
|
194
335
|
timeout_seconds=timeout_seconds,
|
|
@@ -203,8 +344,8 @@ def trends(
|
|
|
203
344
|
|
|
204
345
|
@app.command("anomalies")
|
|
205
346
|
def anomalies(
|
|
206
|
-
input_json: Annotated[Path, typer.Argument(help="JSON file with simulation results or run summary.")],
|
|
207
|
-
mdmp_cert: Annotated[Path, typer.Option(help="Signed MDMP artifact required before AI analysis can run.")],
|
|
347
|
+
input_json: Annotated[Path, typer.Argument(help="Prepared run directory or JSON file with simulation results or run summary.")],
|
|
348
|
+
mdmp_cert: Annotated[Optional[Path], typer.Option(help="Signed MDMP artifact required before AI analysis can run.")] = None,
|
|
208
349
|
mode: Annotated[str, typer.Option(help="AI backend mode. Use 'local' for Ollama/Ministral.")] = "auto",
|
|
209
350
|
model: Annotated[str, typer.Option(help="Ollama model name to use.")] = DEFAULT_MINISTRAL_MODEL,
|
|
210
351
|
minimum_grade: Annotated[str, typer.Option(help="Minimum MDMP grade required to allow analysis.")] = "research_grade",
|
|
@@ -216,13 +357,20 @@ def anomalies(
|
|
|
216
357
|
) -> None:
|
|
217
358
|
console = Console()
|
|
218
359
|
try:
|
|
219
|
-
|
|
220
|
-
|
|
360
|
+
resolved_input, resolved_cert, resolved_public_key = _resolve_cli_inputs(
|
|
361
|
+
task="anomalies",
|
|
362
|
+
input_path=input_json,
|
|
221
363
|
mdmp_cert=mdmp_cert,
|
|
364
|
+
public_key=public_key,
|
|
365
|
+
trust_store=trust_store,
|
|
366
|
+
)
|
|
367
|
+
payload = _load_json_payload(resolved_input, "Input JSON")
|
|
368
|
+
assistant = _build_assistant(
|
|
369
|
+
mdmp_cert=resolved_cert,
|
|
222
370
|
mode=mode,
|
|
223
371
|
model=model,
|
|
224
372
|
minimum_grade=minimum_grade,
|
|
225
|
-
public_key=
|
|
373
|
+
public_key=resolved_public_key,
|
|
226
374
|
trust_store=trust_store,
|
|
227
375
|
ollama_host=ollama_host,
|
|
228
376
|
timeout_seconds=timeout_seconds,
|
|
@@ -237,8 +385,8 @@ def anomalies(
|
|
|
237
385
|
|
|
238
386
|
@app.command("report")
|
|
239
387
|
def report(
|
|
240
|
-
input_json: Annotated[Path, typer.Argument(help="JSON file with run-level simulation outputs.")],
|
|
241
|
-
mdmp_cert: Annotated[Path, typer.Option(help="Signed MDMP artifact required before AI analysis can run.")],
|
|
388
|
+
input_json: Annotated[Path, typer.Argument(help="Prepared run directory or JSON file with run-level simulation outputs.")],
|
|
389
|
+
mdmp_cert: Annotated[Optional[Path], typer.Option(help="Signed MDMP artifact required before AI analysis can run.")] = None,
|
|
242
390
|
mode: Annotated[str, typer.Option(help="AI backend mode. Use 'local' for Ollama/Ministral.")] = "auto",
|
|
243
391
|
model: Annotated[str, typer.Option(help="Ollama model name to use.")] = DEFAULT_MINISTRAL_MODEL,
|
|
244
392
|
minimum_grade: Annotated[str, typer.Option(help="Minimum MDMP grade required to allow analysis.")] = "research_grade",
|
|
@@ -250,13 +398,20 @@ def report(
|
|
|
250
398
|
) -> None:
|
|
251
399
|
console = Console()
|
|
252
400
|
try:
|
|
253
|
-
|
|
254
|
-
|
|
401
|
+
resolved_input, resolved_cert, resolved_public_key = _resolve_cli_inputs(
|
|
402
|
+
task="report",
|
|
403
|
+
input_path=input_json,
|
|
255
404
|
mdmp_cert=mdmp_cert,
|
|
405
|
+
public_key=public_key,
|
|
406
|
+
trust_store=trust_store,
|
|
407
|
+
)
|
|
408
|
+
payload = _load_json_payload(resolved_input, "Input JSON")
|
|
409
|
+
assistant = _build_assistant(
|
|
410
|
+
mdmp_cert=resolved_cert,
|
|
256
411
|
mode=mode,
|
|
257
412
|
model=model,
|
|
258
413
|
minimum_grade=minimum_grade,
|
|
259
|
-
public_key=
|
|
414
|
+
public_key=resolved_public_key,
|
|
260
415
|
trust_store=trust_store,
|
|
261
416
|
ollama_host=ollama_host,
|
|
262
417
|
timeout_seconds=timeout_seconds,
|