streamtrace 0.1.0__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.
- streamtrace-0.1.0/PKG-INFO +218 -0
- streamtrace-0.1.0/README.md +170 -0
- streamtrace-0.1.0/__init__.py +57 -0
- streamtrace-0.1.0/dag.py +386 -0
- streamtrace-0.1.0/decorators/__init__.py +0 -0
- streamtrace-0.1.0/decorators/app_decorator.py +77 -0
- streamtrace-0.1.0/decorators/infer_decorator.py +88 -0
- streamtrace-0.1.0/decorators/input_decorator.py +103 -0
- streamtrace-0.1.0/decorators/output_decorator.py +106 -0
- streamtrace-0.1.0/decorators/postprocess_decorator.py +64 -0
- streamtrace-0.1.0/decorators/preprocess_decorator.py +69 -0
- streamtrace-0.1.0/pyproject.toml +77 -0
- streamtrace-0.1.0/serializers.py +583 -0
- streamtrace-0.1.0/setup.cfg +4 -0
- streamtrace-0.1.0/streamtrace.egg-info/PKG-INFO +218 -0
- streamtrace-0.1.0/streamtrace.egg-info/SOURCES.txt +23 -0
- streamtrace-0.1.0/streamtrace.egg-info/dependency_links.txt +1 -0
- streamtrace-0.1.0/streamtrace.egg-info/requires.txt +34 -0
- streamtrace-0.1.0/streamtrace.egg-info/top_level.txt +1 -0
- streamtrace-0.1.0/widgets/__init__.py +0 -0
- streamtrace-0.1.0/widgets/input_widgets.py +114 -0
- streamtrace-0.1.0/widgets/output_widgets.py +139 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: streamtrace
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Streamtrace SDK — decorator-based ML pipeline contracts for clinical AI
|
|
5
|
+
Author: James Mihalich
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/james-mihalich/streamtrac-sdk
|
|
8
|
+
Project-URL: Repository, https://github.com/james-mihalich/streamtrac-sdk
|
|
9
|
+
Keywords: machine learning,pipeline,mlops,clinical ai,dag,decorators,medical imaging
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
Provides-Extra: medical
|
|
21
|
+
Requires-Dist: nibabel>=3.2; extra == "medical"
|
|
22
|
+
Requires-Dist: pydicom>=2.3; extra == "medical"
|
|
23
|
+
Requires-Dist: numpy>=1.24; extra == "medical"
|
|
24
|
+
Provides-Extra: imaging
|
|
25
|
+
Requires-Dist: Pillow>=9.0; extra == "imaging"
|
|
26
|
+
Requires-Dist: matplotlib>=3.5; extra == "imaging"
|
|
27
|
+
Requires-Dist: numpy>=1.24; extra == "imaging"
|
|
28
|
+
Provides-Extra: plotting
|
|
29
|
+
Requires-Dist: matplotlib>=3.5; extra == "plotting"
|
|
30
|
+
Requires-Dist: plotly>=5.0; extra == "plotting"
|
|
31
|
+
Requires-Dist: bokeh>=3.0; extra == "plotting"
|
|
32
|
+
Provides-Extra: data
|
|
33
|
+
Requires-Dist: pandas>=1.5; extra == "data"
|
|
34
|
+
Requires-Dist: numpy>=1.24; extra == "data"
|
|
35
|
+
Provides-Extra: mesh
|
|
36
|
+
Requires-Dist: trimesh>=3.9; extra == "mesh"
|
|
37
|
+
Requires-Dist: numpy>=1.24; extra == "mesh"
|
|
38
|
+
Provides-Extra: all
|
|
39
|
+
Requires-Dist: nibabel>=3.2; extra == "all"
|
|
40
|
+
Requires-Dist: pydicom>=2.3; extra == "all"
|
|
41
|
+
Requires-Dist: Pillow>=9.0; extra == "all"
|
|
42
|
+
Requires-Dist: matplotlib>=3.5; extra == "all"
|
|
43
|
+
Requires-Dist: plotly>=5.0; extra == "all"
|
|
44
|
+
Requires-Dist: bokeh>=3.0; extra == "all"
|
|
45
|
+
Requires-Dist: pandas>=1.5; extra == "all"
|
|
46
|
+
Requires-Dist: trimesh>=3.9; extra == "all"
|
|
47
|
+
Requires-Dist: numpy>=1.24; extra == "all"
|
|
48
|
+
|
|
49
|
+
# streamtrace
|
|
50
|
+
|
|
51
|
+
Decorator-based ML pipeline contracts for clinical AI. Define your pipeline once with typed decorators, get a validated execution DAG and a deployable frontend app.
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install streamtrace
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Install extras for the output types your pipeline produces:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install streamtrace[medical] # NIfTI + DICOM (nibabel, pydicom, numpy)
|
|
63
|
+
pip install streamtrace[imaging] # images + matplotlib (Pillow, matplotlib, numpy)
|
|
64
|
+
pip install streamtrace[plotting] # interactive plots (matplotlib, plotly, bokeh)
|
|
65
|
+
pip install streamtrace[data] # tabular output (pandas, numpy)
|
|
66
|
+
pip install streamtrace[mesh] # 3D geometry (trimesh, numpy)
|
|
67
|
+
pip install streamtrace[all] # everything
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Quick start
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import streamtrace as st
|
|
74
|
+
|
|
75
|
+
@st.app(title="Cardiac Segmentation", version="1.0.0",
|
|
76
|
+
docker_base="pytorch/pytorch:2.1.0-cuda12.1-cudnn8-runtime",
|
|
77
|
+
requirements=["nibabel", "scipy"])
|
|
78
|
+
class CardiacSegmentation:
|
|
79
|
+
|
|
80
|
+
@st.input(title="CT Scan",
|
|
81
|
+
widget=st.FileInput(accepted_types=[st.InputDataType.NIFTI]),
|
|
82
|
+
returns="scan")
|
|
83
|
+
def load_scan(self, path):
|
|
84
|
+
import nibabel as nib
|
|
85
|
+
return nib.load(path).get_fdata()
|
|
86
|
+
|
|
87
|
+
@st.input(title="Threshold",
|
|
88
|
+
widget=st.TextInput(default="0.5", placeholder="0.0 – 1.0"),
|
|
89
|
+
returns="threshold")
|
|
90
|
+
def set_threshold(self, value):
|
|
91
|
+
return float(value)
|
|
92
|
+
|
|
93
|
+
@st.preprocess(returns="normalized")
|
|
94
|
+
def normalize(self, scan):
|
|
95
|
+
lo, hi = scan.min(), scan.max()
|
|
96
|
+
return (scan - lo) / (hi - lo + 1e-8)
|
|
97
|
+
|
|
98
|
+
@st.infer(returns="raw_mask",
|
|
99
|
+
device="cuda",
|
|
100
|
+
weights_path="checkpoints/best.pth")
|
|
101
|
+
def segment(self, normalized, threshold):
|
|
102
|
+
import torch
|
|
103
|
+
model = torch.load("checkpoints/best.pth", map_location="cpu")
|
|
104
|
+
model.eval()
|
|
105
|
+
with torch.no_grad():
|
|
106
|
+
t = torch.FloatTensor(normalized).unsqueeze(0).unsqueeze(0)
|
|
107
|
+
pred = model(t).squeeze().numpy()
|
|
108
|
+
return (pred > threshold).astype("uint8")
|
|
109
|
+
|
|
110
|
+
@st.postprocess(returns="mask")
|
|
111
|
+
def clean(self, raw_mask):
|
|
112
|
+
from scipy.ndimage import binary_fill_holes
|
|
113
|
+
return binary_fill_holes(raw_mask).astype("uint8")
|
|
114
|
+
|
|
115
|
+
@st.output(title="Segmentation",
|
|
116
|
+
widget=st.FileOutput(data_type=st.OutputDataType.NIFTI,
|
|
117
|
+
filename="segmentation.nii.gz"))
|
|
118
|
+
def save(self, mask):
|
|
119
|
+
import nibabel as nib
|
|
120
|
+
return nib.Nifti1Image(mask, affine=None)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Pipeline contract
|
|
124
|
+
|
|
125
|
+
A Streamtrace pipeline is a class decorated with `@st.app`. Each method in the class maps to one node in the execution DAG via its decorator. Wiring is automatic: a method's parameter names are matched against the `returns=` alias of other nodes.
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
@st.input → @st.preprocess → @st.infer → @st.postprocess → @st.output
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Decorators
|
|
132
|
+
|
|
133
|
+
| Decorator | Purpose | Key args |
|
|
134
|
+
|-----------|---------|---------|
|
|
135
|
+
| `@st.app` | Marks the pipeline class | `title`, `version`, `description`, `docker_base`, `requirements` |
|
|
136
|
+
| `@st.input` | User-provided value (file, text, etc.) | `title`, `widget`, `required`, `returns` |
|
|
137
|
+
| `@st.preprocess` | Data preparation before inference | `title`, `returns` |
|
|
138
|
+
| `@st.infer` | Model inference step | `title`, `returns`, `device`, `weights_path` |
|
|
139
|
+
| `@st.postprocess` | Clean-up after inference | `title`, `returns` |
|
|
140
|
+
| `@st.output` | Final (or intermediate) result | `title`, `widget`, `returns`, `intermediate` |
|
|
141
|
+
|
|
142
|
+
### Wiring via `returns`
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
@st.input(returns="scan") # produces key "scan"
|
|
146
|
+
def load_scan(self, path): ...
|
|
147
|
+
|
|
148
|
+
@st.preprocess(returns="normalized")
|
|
149
|
+
def normalize(self, scan): ... # "scan" resolves to load_scan's output
|
|
150
|
+
|
|
151
|
+
@st.infer(returns="mask")
|
|
152
|
+
def segment(self, normalized): ... # "normalized" resolves to normalize's output
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
If `returns` is omitted the method name is used as the output key.
|
|
156
|
+
|
|
157
|
+
## Input widgets
|
|
158
|
+
|
|
159
|
+
| Widget | Description |
|
|
160
|
+
|--------|-------------|
|
|
161
|
+
| `FileInput(accepted_types=[...], max_size_mb=500)` | File upload |
|
|
162
|
+
| `TextInput(default="", placeholder="", max_length=None)` | Single-line text |
|
|
163
|
+
|
|
164
|
+
**Accepted file types** — `InputDataType.ANY`, `.NIFTI`, `.DICOM`, `.PNG`, `.NUMPY`
|
|
165
|
+
|
|
166
|
+
## Output widgets
|
|
167
|
+
|
|
168
|
+
| Widget | Description |
|
|
169
|
+
|--------|-------------|
|
|
170
|
+
| `FileOutput(data_type=OutputDataType.File, filename=None)` | Generic file download |
|
|
171
|
+
| `ImageOutput(caption="", max_size_mb=50)` | PNG / matplotlib figure |
|
|
172
|
+
| `PlotOutput(interactive=True)` | Plotly / Bokeh / matplotlib |
|
|
173
|
+
| `MetricOutput(label="", precision=3)` | Numeric value or dict of metrics |
|
|
174
|
+
|
|
175
|
+
**Output data types** — `File`, `Image`, `Plot`, `NIFTI`, `DICOM`, `Mesh`, `CSV`, `JSON`, `Text`, `Metric`
|
|
176
|
+
|
|
177
|
+
Intermediate outputs are uploaded to the frontend while the pipeline is still running:
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
@st.output(title="Slice Preview", widget=st.ImageOutput(), intermediate=True)
|
|
181
|
+
def preview(self, normalized): ...
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## DAG inspection
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from streamtrace import build_dag
|
|
188
|
+
|
|
189
|
+
dag = build_dag(CardiacSegmentation)
|
|
190
|
+
|
|
191
|
+
# Validate wiring before deploying
|
|
192
|
+
errors = dag.validate()
|
|
193
|
+
if errors:
|
|
194
|
+
for e in errors:
|
|
195
|
+
print(e)
|
|
196
|
+
|
|
197
|
+
# Topological execution order
|
|
198
|
+
for node in dag.topological_sort():
|
|
199
|
+
print(node.phase, "→", node.name, "produces", node.output_key)
|
|
200
|
+
|
|
201
|
+
# JSON schema (used by streamtrace push)
|
|
202
|
+
import json
|
|
203
|
+
print(json.dumps(dag.to_schema(), indent=2))
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Streamtrace CLI
|
|
207
|
+
|
|
208
|
+
The SDK is the contract layer. The [streamtrace CLI](https://github.com/james-mihalich/streamtrac-sdk) handles the rest:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
streamtrace init # surveys your codebase and classifies existing code
|
|
212
|
+
streamtrace configure # builds and validates a complete executable pipeline
|
|
213
|
+
streamtrace push # deploys to Streamtrace infrastructure
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
MIT
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# streamtrace
|
|
2
|
+
|
|
3
|
+
Decorator-based ML pipeline contracts for clinical AI. Define your pipeline once with typed decorators, get a validated execution DAG and a deployable frontend app.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install streamtrace
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Install extras for the output types your pipeline produces:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install streamtrace[medical] # NIfTI + DICOM (nibabel, pydicom, numpy)
|
|
15
|
+
pip install streamtrace[imaging] # images + matplotlib (Pillow, matplotlib, numpy)
|
|
16
|
+
pip install streamtrace[plotting] # interactive plots (matplotlib, plotly, bokeh)
|
|
17
|
+
pip install streamtrace[data] # tabular output (pandas, numpy)
|
|
18
|
+
pip install streamtrace[mesh] # 3D geometry (trimesh, numpy)
|
|
19
|
+
pip install streamtrace[all] # everything
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick start
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
import streamtrace as st
|
|
26
|
+
|
|
27
|
+
@st.app(title="Cardiac Segmentation", version="1.0.0",
|
|
28
|
+
docker_base="pytorch/pytorch:2.1.0-cuda12.1-cudnn8-runtime",
|
|
29
|
+
requirements=["nibabel", "scipy"])
|
|
30
|
+
class CardiacSegmentation:
|
|
31
|
+
|
|
32
|
+
@st.input(title="CT Scan",
|
|
33
|
+
widget=st.FileInput(accepted_types=[st.InputDataType.NIFTI]),
|
|
34
|
+
returns="scan")
|
|
35
|
+
def load_scan(self, path):
|
|
36
|
+
import nibabel as nib
|
|
37
|
+
return nib.load(path).get_fdata()
|
|
38
|
+
|
|
39
|
+
@st.input(title="Threshold",
|
|
40
|
+
widget=st.TextInput(default="0.5", placeholder="0.0 – 1.0"),
|
|
41
|
+
returns="threshold")
|
|
42
|
+
def set_threshold(self, value):
|
|
43
|
+
return float(value)
|
|
44
|
+
|
|
45
|
+
@st.preprocess(returns="normalized")
|
|
46
|
+
def normalize(self, scan):
|
|
47
|
+
lo, hi = scan.min(), scan.max()
|
|
48
|
+
return (scan - lo) / (hi - lo + 1e-8)
|
|
49
|
+
|
|
50
|
+
@st.infer(returns="raw_mask",
|
|
51
|
+
device="cuda",
|
|
52
|
+
weights_path="checkpoints/best.pth")
|
|
53
|
+
def segment(self, normalized, threshold):
|
|
54
|
+
import torch
|
|
55
|
+
model = torch.load("checkpoints/best.pth", map_location="cpu")
|
|
56
|
+
model.eval()
|
|
57
|
+
with torch.no_grad():
|
|
58
|
+
t = torch.FloatTensor(normalized).unsqueeze(0).unsqueeze(0)
|
|
59
|
+
pred = model(t).squeeze().numpy()
|
|
60
|
+
return (pred > threshold).astype("uint8")
|
|
61
|
+
|
|
62
|
+
@st.postprocess(returns="mask")
|
|
63
|
+
def clean(self, raw_mask):
|
|
64
|
+
from scipy.ndimage import binary_fill_holes
|
|
65
|
+
return binary_fill_holes(raw_mask).astype("uint8")
|
|
66
|
+
|
|
67
|
+
@st.output(title="Segmentation",
|
|
68
|
+
widget=st.FileOutput(data_type=st.OutputDataType.NIFTI,
|
|
69
|
+
filename="segmentation.nii.gz"))
|
|
70
|
+
def save(self, mask):
|
|
71
|
+
import nibabel as nib
|
|
72
|
+
return nib.Nifti1Image(mask, affine=None)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Pipeline contract
|
|
76
|
+
|
|
77
|
+
A Streamtrace pipeline is a class decorated with `@st.app`. Each method in the class maps to one node in the execution DAG via its decorator. Wiring is automatic: a method's parameter names are matched against the `returns=` alias of other nodes.
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
@st.input → @st.preprocess → @st.infer → @st.postprocess → @st.output
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Decorators
|
|
84
|
+
|
|
85
|
+
| Decorator | Purpose | Key args |
|
|
86
|
+
|-----------|---------|---------|
|
|
87
|
+
| `@st.app` | Marks the pipeline class | `title`, `version`, `description`, `docker_base`, `requirements` |
|
|
88
|
+
| `@st.input` | User-provided value (file, text, etc.) | `title`, `widget`, `required`, `returns` |
|
|
89
|
+
| `@st.preprocess` | Data preparation before inference | `title`, `returns` |
|
|
90
|
+
| `@st.infer` | Model inference step | `title`, `returns`, `device`, `weights_path` |
|
|
91
|
+
| `@st.postprocess` | Clean-up after inference | `title`, `returns` |
|
|
92
|
+
| `@st.output` | Final (or intermediate) result | `title`, `widget`, `returns`, `intermediate` |
|
|
93
|
+
|
|
94
|
+
### Wiring via `returns`
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
@st.input(returns="scan") # produces key "scan"
|
|
98
|
+
def load_scan(self, path): ...
|
|
99
|
+
|
|
100
|
+
@st.preprocess(returns="normalized")
|
|
101
|
+
def normalize(self, scan): ... # "scan" resolves to load_scan's output
|
|
102
|
+
|
|
103
|
+
@st.infer(returns="mask")
|
|
104
|
+
def segment(self, normalized): ... # "normalized" resolves to normalize's output
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
If `returns` is omitted the method name is used as the output key.
|
|
108
|
+
|
|
109
|
+
## Input widgets
|
|
110
|
+
|
|
111
|
+
| Widget | Description |
|
|
112
|
+
|--------|-------------|
|
|
113
|
+
| `FileInput(accepted_types=[...], max_size_mb=500)` | File upload |
|
|
114
|
+
| `TextInput(default="", placeholder="", max_length=None)` | Single-line text |
|
|
115
|
+
|
|
116
|
+
**Accepted file types** — `InputDataType.ANY`, `.NIFTI`, `.DICOM`, `.PNG`, `.NUMPY`
|
|
117
|
+
|
|
118
|
+
## Output widgets
|
|
119
|
+
|
|
120
|
+
| Widget | Description |
|
|
121
|
+
|--------|-------------|
|
|
122
|
+
| `FileOutput(data_type=OutputDataType.File, filename=None)` | Generic file download |
|
|
123
|
+
| `ImageOutput(caption="", max_size_mb=50)` | PNG / matplotlib figure |
|
|
124
|
+
| `PlotOutput(interactive=True)` | Plotly / Bokeh / matplotlib |
|
|
125
|
+
| `MetricOutput(label="", precision=3)` | Numeric value or dict of metrics |
|
|
126
|
+
|
|
127
|
+
**Output data types** — `File`, `Image`, `Plot`, `NIFTI`, `DICOM`, `Mesh`, `CSV`, `JSON`, `Text`, `Metric`
|
|
128
|
+
|
|
129
|
+
Intermediate outputs are uploaded to the frontend while the pipeline is still running:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
@st.output(title="Slice Preview", widget=st.ImageOutput(), intermediate=True)
|
|
133
|
+
def preview(self, normalized): ...
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## DAG inspection
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from streamtrace import build_dag
|
|
140
|
+
|
|
141
|
+
dag = build_dag(CardiacSegmentation)
|
|
142
|
+
|
|
143
|
+
# Validate wiring before deploying
|
|
144
|
+
errors = dag.validate()
|
|
145
|
+
if errors:
|
|
146
|
+
for e in errors:
|
|
147
|
+
print(e)
|
|
148
|
+
|
|
149
|
+
# Topological execution order
|
|
150
|
+
for node in dag.topological_sort():
|
|
151
|
+
print(node.phase, "→", node.name, "produces", node.output_key)
|
|
152
|
+
|
|
153
|
+
# JSON schema (used by streamtrace push)
|
|
154
|
+
import json
|
|
155
|
+
print(json.dumps(dag.to_schema(), indent=2))
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Streamtrace CLI
|
|
159
|
+
|
|
160
|
+
The SDK is the contract layer. The [streamtrace CLI](https://github.com/james-mihalich/streamtrac-sdk) handles the rest:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
streamtrace init # surveys your codebase and classifies existing code
|
|
164
|
+
streamtrace configure # builds and validates a complete executable pipeline
|
|
165
|
+
streamtrace push # deploys to Streamtrace infrastructure
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
MIT
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Streamtrace SDK — decorator-based ML pipeline contracts for clinical AI.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
import streamtrace as st
|
|
6
|
+
|
|
7
|
+
@st.app(title="Cardiac Segmentation", version="1.0.0")
|
|
8
|
+
class MyPipeline:
|
|
9
|
+
|
|
10
|
+
@st.input(title="CT Scan", widget=st.FileInput(...), returns="scan")
|
|
11
|
+
def load_scan(self, path): ...
|
|
12
|
+
|
|
13
|
+
@st.preprocess(title="Normalize", returns="normalized")
|
|
14
|
+
def normalize(self, scan): ...
|
|
15
|
+
|
|
16
|
+
@st.infer(title="Segment", returns="mask", weights_path="model.pt")
|
|
17
|
+
def segment(self, normalized): ...
|
|
18
|
+
|
|
19
|
+
@st.postprocess(title="Clean Mask", returns="clean_mask")
|
|
20
|
+
def clean(self, mask): ...
|
|
21
|
+
|
|
22
|
+
@st.output(title="Result", widget=st.FileOutput(...))
|
|
23
|
+
def save(self, clean_mask): ...
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from .decorators.app_decorator import app, get_app_metadata, is_app
|
|
27
|
+
from .decorators.input_decorator import input, get_input_metadata, is_input
|
|
28
|
+
from .decorators.preprocess_decorator import preprocess, get_preprocess_metadata, is_preprocess
|
|
29
|
+
from .decorators.infer_decorator import infer, get_infer_metadata, is_infer
|
|
30
|
+
from .decorators.postprocess_decorator import postprocess, get_postprocess_metadata, is_postprocess
|
|
31
|
+
from .decorators.output_decorator import output, get_output_metadata, is_output
|
|
32
|
+
|
|
33
|
+
from .widgets.input_widgets import FileInput, TextInput, InputDataType
|
|
34
|
+
from .widgets.output_widgets import FileOutput, ImageOutput, PlotOutput, MetricOutput, OutputDataType
|
|
35
|
+
|
|
36
|
+
from .dag import build_dag, DAG, Node
|
|
37
|
+
|
|
38
|
+
__version__ = "0.1.0"
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
# App
|
|
42
|
+
"app", "get_app_metadata", "is_app",
|
|
43
|
+
# Node decorators
|
|
44
|
+
"input", "get_input_metadata", "is_input",
|
|
45
|
+
"preprocess", "get_preprocess_metadata", "is_preprocess",
|
|
46
|
+
"infer", "get_infer_metadata", "is_infer",
|
|
47
|
+
"postprocess", "get_postprocess_metadata", "is_postprocess",
|
|
48
|
+
"output", "get_output_metadata", "is_output",
|
|
49
|
+
# Input widgets
|
|
50
|
+
"FileInput", "TextInput", "InputDataType",
|
|
51
|
+
# Output widgets
|
|
52
|
+
"FileOutput", "ImageOutput", "PlotOutput", "MetricOutput", "OutputDataType",
|
|
53
|
+
# DAG
|
|
54
|
+
"build_dag", "DAG", "Node",
|
|
55
|
+
# Version
|
|
56
|
+
"__version__",
|
|
57
|
+
]
|