imaging-server-kit 0.0.2__tar.gz → 0.0.3__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.
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/Dockerfile-registry +1 -1
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/PKG-INFO +74 -44
- imaging_server_kit-0.0.3/README.md +121 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/pyproject.toml +1 -1
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit/__init__.py +6 -2
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit/_version.py +2 -2
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit/client.py +1 -1
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit/registry.py +2 -2
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit/server.py +15 -7
- imaging_server_kit-0.0.3/src/imaging_server_kit/static/index.css +47 -0
- imaging_server_kit-0.0.3/src/imaging_server_kit/static/info.css +124 -0
- imaging_server_kit-0.0.3/src/imaging_server_kit/templates/index.html +33 -0
- imaging_server_kit-0.0.3/src/imaging_server_kit/templates/info.html +78 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit.egg-info/PKG-INFO +74 -44
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit.egg-info/SOURCES.txt +0 -1
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit.egg-info/requires.txt +1 -1
- imaging_server_kit-0.0.2/README.md +0 -91
- imaging_server_kit-0.0.2/src/imaging_server_kit/autostartup_registry.py +0 -58
- imaging_server_kit-0.0.2/src/imaging_server_kit/static/index.css +0 -32
- imaging_server_kit-0.0.2/src/imaging_server_kit/static/info.css +0 -32
- imaging_server_kit-0.0.2/src/imaging_server_kit/templates/index.html +0 -25
- imaging_server_kit-0.0.2/src/imaging_server_kit/templates/info.html +0 -63
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/.dockerignore +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/.gitattributes +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/.github/workflows/publish.yml +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/.gitignore +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/Dockerfile +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/Dockerfile-GPU +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/LICENSE +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/MANIFEST.in +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/build.sh +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/examples/.gitkeep +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/main.py +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/setup.cfg +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit/assets/style.css +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit/encoding.py +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit/errors.py +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit/geometry.py +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit/serialization.py +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit/web_demo.py +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit.egg-info/dependency_links.txt +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit.egg-info/top_level.txt +0 -0
- {imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/start_registry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: imaging-server-kit
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: Deploy image processing algorithms in FastAPI servers.
|
|
5
5
|
Author-email: Mallory Wittwer <mallory.wittwer@epfl.ch>
|
|
6
6
|
License: Copyright (c) 2024, EPFL
|
|
@@ -54,92 +54,122 @@ Requires-Dist: tifffile
|
|
|
54
54
|
Requires-Dist: numpy
|
|
55
55
|
Requires-Dist: scikit-image
|
|
56
56
|
Requires-Dist: geojson
|
|
57
|
-
Requires-Dist: docker
|
|
58
57
|
Requires-Dist: jinja2
|
|
59
58
|
Requires-Dist: pyyaml
|
|
60
59
|
Requires-Dist: dash
|
|
61
60
|
Requires-Dist: dash-bootstrap-components
|
|
61
|
+
Requires-Dist: a2wsgi
|
|
62
62
|
Requires-Dist: pytest
|
|
63
63
|
|
|
64
64
|

|
|
65
65
|
# 🪐 Imaging Server Kit
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
Deploy image processing algorithms in FastAPI servers and easily run them in Napari, QuPath, and more.
|
|
68
68
|
|
|
69
|
-
##
|
|
70
|
-
|
|
71
|
-
Build the `imaging-server-kit` image with `docker`:
|
|
69
|
+
## Usage
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
### Algorithm servers
|
|
72
|
+
|
|
73
|
+
Set up and run a server with one, or multiple algorithms from the Imaging Server Kit collection (or your own):
|
|
74
|
+
|
|
75
|
+
- [StarDist](https://github.com/Imaging-Server-Kit/serverkit-stardist)
|
|
76
|
+
- [CellPose](https://github.com/Imaging-Server-Kit/serverkit-cellpose)
|
|
77
|
+
- [Spotiflow](https://github.com/Imaging-Server-Kit/serverkit-spotiflow)
|
|
78
|
+
- [Rembg](https://github.com/Imaging-Server-Kit/serverkit-rembg)
|
|
79
|
+
- [Scikit-image LoG detector](https://github.com/Imaging-Server-Kit/serverkit-skimage-LoG)
|
|
80
|
+
- [Orientationpy](https://github.com/Imaging-Server-Kit/serverkit-orientationpy)
|
|
81
|
+
<!-- - [Tau Fibrils Detector](https://github.com/Imaging-Server-Kit/serverkit-tau-fibrils-yolo) -->
|
|
82
|
+
|
|
83
|
+
To do that, the recommended way is to edit a `docker-compose.yml` file and pull server images from `registry.rcp.epfl.ch` (EPFL users only):
|
|
84
|
+
|
|
85
|
+
```{docker-compose.yml}
|
|
86
|
+
services:
|
|
87
|
+
servers_registry:
|
|
88
|
+
image: mallorywittwerepfl/imaging-server-kit:registry
|
|
89
|
+
ports:
|
|
90
|
+
- "8000:8000"
|
|
91
|
+
rembg:
|
|
92
|
+
image: registry.rcp.epfl.ch/imaging-server-kit/serverkit-rembg:latest
|
|
93
|
+
depends_on:
|
|
94
|
+
- servers_registry
|
|
95
|
+
skimage-log:
|
|
96
|
+
image: registry.rcp.epfl.ch/imaging-server-kit/serverkit-skimage-log:latest
|
|
97
|
+
depends_on:
|
|
98
|
+
- servers_registry
|
|
75
99
|
```
|
|
76
100
|
|
|
77
|
-
|
|
101
|
+
Start the server with
|
|
78
102
|
|
|
79
103
|
```
|
|
80
|
-
docker
|
|
81
|
-
docker build -t imaging-server-kit:gpu --file Dockerfile-GPU .
|
|
104
|
+
docker compose up
|
|
82
105
|
```
|
|
83
106
|
|
|
84
|
-
|
|
107
|
+
The server should be accessible at http://localhost:8000.
|
|
85
108
|
|
|
86
|
-
|
|
109
|
+
**Build the docker images yourself**
|
|
87
110
|
|
|
88
|
-
|
|
89
|
-
docker build -t serverkit/rembg .
|
|
90
|
-
docker run -it --rm -p 8000:8000 serverkit/rembg
|
|
91
|
-
```
|
|
111
|
+
To build the algorithm server images yourself (e.g. if you are not from EPFL), see [Reference Deployment](https://github.com/Imaging-Server-Kit/serverkit-deploy-docker).
|
|
92
112
|
|
|
93
|
-
**
|
|
113
|
+
**Create a server for your project**
|
|
94
114
|
|
|
95
|
-
|
|
115
|
+
To learn how to create a server for your project, see [Algorithm Server Template](https://github.com/Imaging-Server-Kit/cookiecutter-serverkit).
|
|
96
116
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
**Python client**
|
|
117
|
+
### Python client
|
|
100
118
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
pip install git+https://gitlab.com/epfl-center-for-imaging/imaging-server-kit.git
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Connect to an algorithm server and run algorithms from Python:
|
|
119
|
+
Once the server is running, connect to it and run algorithms from Python:
|
|
108
120
|
|
|
109
121
|
```python
|
|
110
122
|
from imaging_server_kit import Client
|
|
111
123
|
|
|
112
|
-
client = Client()
|
|
113
|
-
|
|
114
|
-
client.connect("http://localhost:7000")
|
|
124
|
+
client = Client("http://localhost:8000")
|
|
115
125
|
|
|
116
126
|
print(client.algorithms)
|
|
117
|
-
# [`rembg`, `stardist`, `
|
|
127
|
+
# [`rembg`, `stardist`, `cellpose`]
|
|
118
128
|
|
|
119
|
-
|
|
129
|
+
algo_output = client.run_algorithm(
|
|
120
130
|
algorithm="rembg",
|
|
121
131
|
image=(...),
|
|
122
132
|
rembg_model_name="silueta",
|
|
123
133
|
)
|
|
124
134
|
```
|
|
125
135
|
|
|
126
|
-
|
|
136
|
+
### Napari plugin
|
|
137
|
+
|
|
138
|
+
Once the server is running, use the [Napari Server Kit](https://github.com/Imaging-Server-Kit/napari-serverkit) plugin to connect to it and run algorithms in Napari.
|
|
127
139
|
|
|
128
|
-
|
|
140
|
+
### QuPath extension
|
|
129
141
|
|
|
130
|
-
|
|
142
|
+
Once the server is running, use the [QuPath Extension Server Kit](https://github.com/Imaging-Server-Kit/qupath-extension-serverkit) to connect to it and run algorithms from within QuPath.
|
|
131
143
|
|
|
132
|
-
|
|
144
|
+
## Install locally
|
|
133
145
|
|
|
134
|
-
|
|
146
|
+
Install the `imaging-server-kit` package with `pip`:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
pip install imaging-server-kit
|
|
150
|
+
```
|
|
135
151
|
|
|
136
|
-
|
|
152
|
+
or clone the project and install the development version:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
git clone https://github.com/Imaging-Server-Kit/imaging-server-kit.git
|
|
156
|
+
cd imaging-server-kit
|
|
157
|
+
pip install -e .
|
|
158
|
+
```
|
|
137
159
|
|
|
138
|
-
|
|
160
|
+
## Build with `docker`
|
|
139
161
|
|
|
140
|
-
|
|
162
|
+
Build the `imaging-server-kit` docker image for a specific Python version:
|
|
141
163
|
|
|
142
|
-
|
|
164
|
+
```
|
|
165
|
+
docker build --build-arg PYTHON_VERSION=3.9 -t imaging-server-kit:3.9 .
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Run [build.sh](./build.sh) to build docker images for Python 3.9, 3.10, 3.11, GPU and the server kit registry:
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
bash ./build.sh
|
|
172
|
+
```
|
|
143
173
|
|
|
144
174
|
## Contributing
|
|
145
175
|
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+

|
|
2
|
+
# 🪐 Imaging Server Kit
|
|
3
|
+
|
|
4
|
+
Deploy image processing algorithms in FastAPI servers and easily run them in Napari, QuPath, and more.
|
|
5
|
+
|
|
6
|
+
## Usage
|
|
7
|
+
|
|
8
|
+
### Algorithm servers
|
|
9
|
+
|
|
10
|
+
Set up and run a server with one, or multiple algorithms from the Imaging Server Kit collection (or your own):
|
|
11
|
+
|
|
12
|
+
- [StarDist](https://github.com/Imaging-Server-Kit/serverkit-stardist)
|
|
13
|
+
- [CellPose](https://github.com/Imaging-Server-Kit/serverkit-cellpose)
|
|
14
|
+
- [Spotiflow](https://github.com/Imaging-Server-Kit/serverkit-spotiflow)
|
|
15
|
+
- [Rembg](https://github.com/Imaging-Server-Kit/serverkit-rembg)
|
|
16
|
+
- [Scikit-image LoG detector](https://github.com/Imaging-Server-Kit/serverkit-skimage-LoG)
|
|
17
|
+
- [Orientationpy](https://github.com/Imaging-Server-Kit/serverkit-orientationpy)
|
|
18
|
+
<!-- - [Tau Fibrils Detector](https://github.com/Imaging-Server-Kit/serverkit-tau-fibrils-yolo) -->
|
|
19
|
+
|
|
20
|
+
To do that, the recommended way is to edit a `docker-compose.yml` file and pull server images from `registry.rcp.epfl.ch` (EPFL users only):
|
|
21
|
+
|
|
22
|
+
```{docker-compose.yml}
|
|
23
|
+
services:
|
|
24
|
+
servers_registry:
|
|
25
|
+
image: mallorywittwerepfl/imaging-server-kit:registry
|
|
26
|
+
ports:
|
|
27
|
+
- "8000:8000"
|
|
28
|
+
rembg:
|
|
29
|
+
image: registry.rcp.epfl.ch/imaging-server-kit/serverkit-rembg:latest
|
|
30
|
+
depends_on:
|
|
31
|
+
- servers_registry
|
|
32
|
+
skimage-log:
|
|
33
|
+
image: registry.rcp.epfl.ch/imaging-server-kit/serverkit-skimage-log:latest
|
|
34
|
+
depends_on:
|
|
35
|
+
- servers_registry
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Start the server with
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
docker compose up
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The server should be accessible at http://localhost:8000.
|
|
45
|
+
|
|
46
|
+
**Build the docker images yourself**
|
|
47
|
+
|
|
48
|
+
To build the algorithm server images yourself (e.g. if you are not from EPFL), see [Reference Deployment](https://github.com/Imaging-Server-Kit/serverkit-deploy-docker).
|
|
49
|
+
|
|
50
|
+
**Create a server for your project**
|
|
51
|
+
|
|
52
|
+
To learn how to create a server for your project, see [Algorithm Server Template](https://github.com/Imaging-Server-Kit/cookiecutter-serverkit).
|
|
53
|
+
|
|
54
|
+
### Python client
|
|
55
|
+
|
|
56
|
+
Once the server is running, connect to it and run algorithms from Python:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from imaging_server_kit import Client
|
|
60
|
+
|
|
61
|
+
client = Client("http://localhost:8000")
|
|
62
|
+
|
|
63
|
+
print(client.algorithms)
|
|
64
|
+
# [`rembg`, `stardist`, `cellpose`]
|
|
65
|
+
|
|
66
|
+
algo_output = client.run_algorithm(
|
|
67
|
+
algorithm="rembg",
|
|
68
|
+
image=(...),
|
|
69
|
+
rembg_model_name="silueta",
|
|
70
|
+
)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Napari plugin
|
|
74
|
+
|
|
75
|
+
Once the server is running, use the [Napari Server Kit](https://github.com/Imaging-Server-Kit/napari-serverkit) plugin to connect to it and run algorithms in Napari.
|
|
76
|
+
|
|
77
|
+
### QuPath extension
|
|
78
|
+
|
|
79
|
+
Once the server is running, use the [QuPath Extension Server Kit](https://github.com/Imaging-Server-Kit/qupath-extension-serverkit) to connect to it and run algorithms from within QuPath.
|
|
80
|
+
|
|
81
|
+
## Install locally
|
|
82
|
+
|
|
83
|
+
Install the `imaging-server-kit` package with `pip`:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
pip install imaging-server-kit
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
or clone the project and install the development version:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
git clone https://github.com/Imaging-Server-Kit/imaging-server-kit.git
|
|
93
|
+
cd imaging-server-kit
|
|
94
|
+
pip install -e .
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Build with `docker`
|
|
98
|
+
|
|
99
|
+
Build the `imaging-server-kit` docker image for a specific Python version:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
docker build --build-arg PYTHON_VERSION=3.9 -t imaging-server-kit:3.9 .
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Run [build.sh](./build.sh) to build docker images for Python 3.9, 3.10, 3.11, GPU and the server kit registry:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
bash ./build.sh
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Contributing
|
|
112
|
+
|
|
113
|
+
Contributions are very welcome.
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
This software is distributed under the terms of the [BSD-3](http://opensource.org/licenses/BSD-3-Clause) license.
|
|
118
|
+
|
|
119
|
+
## Issues
|
|
120
|
+
|
|
121
|
+
If you encounter any problems, please file an issue along with a detailed description.
|
|
@@ -29,11 +29,11 @@ dependencies = [
|
|
|
29
29
|
"numpy",
|
|
30
30
|
"scikit-image",
|
|
31
31
|
"geojson",
|
|
32
|
-
"docker", # For the autostartup regsitry
|
|
33
32
|
"jinja2", # For the /info route
|
|
34
33
|
"pyyaml", # For the /info route
|
|
35
34
|
"dash", # For the dash app
|
|
36
35
|
"dash-bootstrap-components", # For the dash app
|
|
36
|
+
"a2wsgi", # For the dash app
|
|
37
37
|
"pytest", # For testing
|
|
38
38
|
]
|
|
39
39
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
from
|
|
1
|
+
from ._version import version as __version__
|
|
2
|
+
try:
|
|
3
|
+
from ._version import version as __version__
|
|
4
|
+
except ImportError:
|
|
5
|
+
__version__ = "unknown"
|
|
6
|
+
|
|
2
7
|
from imaging_server_kit.client import Client
|
|
3
8
|
from imaging_server_kit.server import Server, Parameters
|
|
4
9
|
from imaging_server_kit.registry import Registry
|
|
5
|
-
from imaging_server_kit.autostartup_registry import AutoStartupRegistry
|
|
6
10
|
from imaging_server_kit.encoding import encode_contents, decode_contents
|
|
7
11
|
from imaging_server_kit.serialization import (
|
|
8
12
|
serialize_result_tuple,
|
|
@@ -52,7 +52,7 @@ class Client:
|
|
|
52
52
|
algo_params_encoded = self._encode_numpy_parameters(algo_params)
|
|
53
53
|
|
|
54
54
|
try:
|
|
55
|
-
endpoint = f"{self.server_url}/{algorithm}/"
|
|
55
|
+
endpoint = f"{self.server_url}/{algorithm}/process"
|
|
56
56
|
response = requests.post(
|
|
57
57
|
endpoint,
|
|
58
58
|
json=algo_params_encoded,
|
|
@@ -80,11 +80,11 @@ class Registry:
|
|
|
80
80
|
response = requests.get(f"{algo_url}/")
|
|
81
81
|
return response.json()
|
|
82
82
|
|
|
83
|
-
@self.app.post("/{algorithm}", status_code=status.HTTP_201_CREATED)
|
|
83
|
+
@self.app.post("/{algorithm}/process", status_code=status.HTTP_201_CREATED)
|
|
84
84
|
async def run_algorithm(algorithm, request: Request):
|
|
85
85
|
algo_url = self.services.get(algorithm)
|
|
86
86
|
data = await request.json()
|
|
87
|
-
response = requests.post(f"{algo_url}/{algorithm}/", json=data)
|
|
87
|
+
response = requests.post(f"{algo_url}/{algorithm}/process", json=data)
|
|
88
88
|
return response.json()
|
|
89
89
|
|
|
90
90
|
@self.app.get("/{algorithm}/parameters")
|
|
@@ -11,7 +11,9 @@ from fastapi.staticfiles import StaticFiles
|
|
|
11
11
|
from fastapi.templating import Jinja2Templates
|
|
12
12
|
from imaging_server_kit.web_demo import generate_dash_app
|
|
13
13
|
from pydantic import BaseModel, ConfigDict
|
|
14
|
-
from
|
|
14
|
+
from a2wsgi import WSGIMiddleware
|
|
15
|
+
# from starlette.middleware.wsgi import WSGIMiddleware
|
|
16
|
+
from contextlib import asynccontextmanager
|
|
15
17
|
|
|
16
18
|
templates_dir = importlib.resources.files("imaging_server_kit").joinpath("templates")
|
|
17
19
|
static_dir = importlib.resources.files("imaging_server_kit").joinpath("static")
|
|
@@ -47,7 +49,7 @@ class Server:
|
|
|
47
49
|
self.algorithm_name = algorithm_name
|
|
48
50
|
self.parameters_model = parameters_model
|
|
49
51
|
|
|
50
|
-
self.app = FastAPI(title=algorithm_name)
|
|
52
|
+
self.app = FastAPI(title=algorithm_name, lifespan=self.lifespan)
|
|
51
53
|
self.app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
|
|
52
54
|
|
|
53
55
|
# Set up the web demo app
|
|
@@ -63,14 +65,20 @@ class Server:
|
|
|
63
65
|
|
|
64
66
|
self.app.mount(f"/{algorithm_name}/demo", WSGIMiddleware(dash_app.server))
|
|
65
67
|
|
|
66
|
-
self.app.on_event("startup")(self.register_with_registry)
|
|
67
|
-
self.app.on_event("shutdown")(self.deregister_from_registry)
|
|
68
|
+
# self.app.on_event("startup")(self.register_with_registry)
|
|
69
|
+
# self.app.on_event("shutdown")(self.deregister_from_registry)
|
|
68
70
|
|
|
69
71
|
self.register_routes()
|
|
70
72
|
|
|
71
73
|
self.services = [self.algorithm_name]
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
@asynccontextmanager
|
|
76
|
+
async def lifespan(self, app: FastAPI):
|
|
77
|
+
await self.register_with_registry()
|
|
78
|
+
yield
|
|
79
|
+
await self.deregister_from_registry()
|
|
80
|
+
|
|
81
|
+
async def register_with_registry(self):
|
|
74
82
|
try:
|
|
75
83
|
response = requests.get(f"{REGISTRY_URL}/")
|
|
76
84
|
except Exception:
|
|
@@ -89,7 +97,7 @@ class Server:
|
|
|
89
97
|
else:
|
|
90
98
|
print(f"Failed to register {self.algorithm_name}: {response.json()}")
|
|
91
99
|
|
|
92
|
-
def deregister_from_registry(self):
|
|
100
|
+
async def deregister_from_registry(self):
|
|
93
101
|
deregister_url = f"{REGISTRY_URL}/deregister"
|
|
94
102
|
response = requests.post(deregister_url, json={"name": self.algorithm_name})
|
|
95
103
|
if response.status_code == 201:
|
|
@@ -124,7 +132,7 @@ class Server:
|
|
|
124
132
|
},
|
|
125
133
|
)
|
|
126
134
|
|
|
127
|
-
@self.app.post(f"/{self.algorithm_name}/", status_code=status.HTTP_201_CREATED)
|
|
135
|
+
@self.app.post(f"/{self.algorithm_name}/process", status_code=status.HTTP_201_CREATED)
|
|
128
136
|
async def run_algo(algo_params: self.parameters_model):
|
|
129
137
|
result_data_tuple = self.run_algorithm(**algo_params.dict())
|
|
130
138
|
serialized_results = serverkit.serialize_result_tuple(result_data_tuple)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
body {
|
|
2
|
+
font-family: Arial, sans-serif;
|
|
3
|
+
margin: 0;
|
|
4
|
+
padding: 0;
|
|
5
|
+
background-color: #f4f4f4;
|
|
6
|
+
color: #333;
|
|
7
|
+
}
|
|
8
|
+
.container {
|
|
9
|
+
max-width: 800px;
|
|
10
|
+
margin: 50px auto;
|
|
11
|
+
padding: 20px;
|
|
12
|
+
background-color: #fff;
|
|
13
|
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
|
14
|
+
border-radius: 8px;
|
|
15
|
+
}
|
|
16
|
+
p {
|
|
17
|
+
line-height: 1.6;
|
|
18
|
+
}
|
|
19
|
+
a {
|
|
20
|
+
color: #333;
|
|
21
|
+
text-decoration: none;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.card-product {
|
|
25
|
+
border-radius: 5px;
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
/* height: 80px; */
|
|
28
|
+
background: white;
|
|
29
|
+
/* box-shadow: 0 0 15px rgba(0,0,0,0.2); */
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.card-product h2 {
|
|
35
|
+
font-size: 16px;
|
|
36
|
+
font-weight: bold;
|
|
37
|
+
margin: 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.card-product .card-product-infos {
|
|
41
|
+
padding: 16px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.card-product:hover {
|
|
45
|
+
background-color: #f4f4f4;
|
|
46
|
+
}
|
|
47
|
+
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
body {
|
|
2
|
+
font-family: Arial, sans-serif;
|
|
3
|
+
margin: 0;
|
|
4
|
+
padding: 0;
|
|
5
|
+
background-color: #f4f4f4;
|
|
6
|
+
color: #333;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.container {
|
|
10
|
+
max-width: 800px;
|
|
11
|
+
margin: 50px auto;
|
|
12
|
+
padding: 20px;
|
|
13
|
+
background-color: #fff;
|
|
14
|
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
|
15
|
+
border-radius: 8px;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
p {
|
|
19
|
+
line-height: 1.6;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
a {
|
|
23
|
+
color: #333;
|
|
24
|
+
text-decoration: none;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
a:hover {
|
|
28
|
+
background-color: #f4f4f4;
|
|
29
|
+
border-radius: 5px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.keyword {
|
|
33
|
+
border-radius: 2px;
|
|
34
|
+
background-color: #f4f4f4;
|
|
35
|
+
padding: 2px 4px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.card-category {
|
|
39
|
+
flex-direction: column;
|
|
40
|
+
display: flex;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
align-items: center;
|
|
43
|
+
font-size: 18px;
|
|
44
|
+
border-radius: 5px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.card-category i {
|
|
48
|
+
font-size: 36px;
|
|
49
|
+
padding-top: 20px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.cards {
|
|
53
|
+
display: grid;
|
|
54
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
55
|
+
grid-gap: 16px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@media (min-width: 100px) and (max-width: 575px) {
|
|
59
|
+
.cards {
|
|
60
|
+
grid-template-columns: 1fr;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@media (min-width: 576px) {
|
|
65
|
+
.cards {
|
|
66
|
+
grid-template-columns: 1fr;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@media (min-width: 768px) {
|
|
71
|
+
.cards {
|
|
72
|
+
grid-template-columns: 1fr 1fr;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@media (min-width: 992px) {
|
|
77
|
+
.cards {
|
|
78
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@media (min-width: 1200px) {
|
|
83
|
+
.cards {
|
|
84
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
table {
|
|
89
|
+
width: 100%; /* Make the table span the full width of its container */
|
|
90
|
+
border-collapse: collapse; /* Remove gaps between table cells */
|
|
91
|
+
margin: 1rem 0; /* Add some spacing above and below the table */
|
|
92
|
+
font-size: 0.9rem; /* Slightly smaller font size for a subtle look */
|
|
93
|
+
color: #333; /* Dark gray text for readability */
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
thead {
|
|
97
|
+
color: #333; /* Ensure the text color contrasts well */
|
|
98
|
+
font-weight: bold; /* Bold text for the header */
|
|
99
|
+
text-align: left; /* Align text to the left for clarity */
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
thead th {
|
|
103
|
+
padding: 0.8rem; /* Add padding for better spacing */
|
|
104
|
+
border-bottom: 1px solid #ddd; /* Subtle bottom border */
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
tbody tr {
|
|
108
|
+
border-bottom: 1px solid #ddd; /* Add borders between rows */
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
tbody td {
|
|
112
|
+
padding: 0.8rem; /* Add padding for cell spacing */
|
|
113
|
+
vertical-align: top; /* Align content to the top for readability */
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
tbody td:first-child {
|
|
117
|
+
font-weight: bold; /* Emphasize the first column */
|
|
118
|
+
color: #555; /* Slightly darker text for the first column */
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
tbody td:last-child {
|
|
122
|
+
font-style: italic; /* Italicize the last column for variation */
|
|
123
|
+
color: #666; /* Subtle gray for less prominent data */
|
|
124
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
|
|
8
|
+
integrity="sha384-rbsA2VBKQat6jboKpBhxGzJLysoH5Wr1xEAWmupmCJA7D6hzBI7tWtK2p9jxX0/e" crossorigin="anonymous">
|
|
9
|
+
<link rel="stylesheet" href="/static/index.css">
|
|
10
|
+
</head>
|
|
11
|
+
|
|
12
|
+
<body>
|
|
13
|
+
<div class="container">
|
|
14
|
+
<h1>Running servers</h1>
|
|
15
|
+
{% for service in services %}
|
|
16
|
+
<a href="/{{ service }}/info">
|
|
17
|
+
<div class="card-product">
|
|
18
|
+
<div class="card-product-infos">
|
|
19
|
+
<h2>{{ service }}</h2>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</a>
|
|
23
|
+
{% endfor %}
|
|
24
|
+
</div>
|
|
25
|
+
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"
|
|
26
|
+
integrity="sha384-QFfYf8qpCIem7U+Uz5XYW6XPiA5sdP7ePLCTDBSMF0Os3J8nt9wM5L3yZGOI+73s"
|
|
27
|
+
crossorigin="anonymous"></script>
|
|
28
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js"
|
|
29
|
+
integrity="sha384-Q8KdjMRRhHpXEmsdpu2x9NkRBe/HHU6hLmjNw07uGpD7jz1zPoj2a9t8WbQhAjc"
|
|
30
|
+
crossorigin="anonymous"></script>
|
|
31
|
+
</body>
|
|
32
|
+
|
|
33
|
+
</html>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
|
|
8
|
+
integrity="sha384-rbsA2VBKQat6jboKpBhxGzJLysoH5Wr1xEAWmupmCJA7D6hzBI7tWtK2p9jxX0/e" crossorigin="anonymous">
|
|
9
|
+
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
|
10
|
+
<link rel="stylesheet" href="/static/info.css">
|
|
11
|
+
</head>
|
|
12
|
+
|
|
13
|
+
<body>
|
|
14
|
+
<div class="container">
|
|
15
|
+
<h1>{{ algo_info.project_name }}</h1>
|
|
16
|
+
|
|
17
|
+
<p>{{ algo_info.description }}</p>
|
|
18
|
+
|
|
19
|
+
<p><strong>Keywords:</strong>
|
|
20
|
+
{% for used_for_tag in algo_info.used_for %}
|
|
21
|
+
<span class="keyword">{{ used_for_tag }}</span>
|
|
22
|
+
{% endfor %}
|
|
23
|
+
{% for tag in algo_info.tags %}
|
|
24
|
+
<span class="keyword">{{ tag }}</span>
|
|
25
|
+
{% endfor %}
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
<div class="cards">
|
|
29
|
+
<a href="{{ algo_info.project_url }}">
|
|
30
|
+
<div class="card-category">
|
|
31
|
+
<i class="fa-solid fa-house"></i>
|
|
32
|
+
<p>Project Homepage</p>
|
|
33
|
+
</div>
|
|
34
|
+
</a>
|
|
35
|
+
<a href="{{ algo_info.serverkit_repo_url }}">
|
|
36
|
+
<div class="card-category">
|
|
37
|
+
<i class="fa-brands fa-github"></i>
|
|
38
|
+
<p>Server Kit Repository</p>
|
|
39
|
+
</div>
|
|
40
|
+
</a>
|
|
41
|
+
<a href="/demo">
|
|
42
|
+
<div class="card-category">
|
|
43
|
+
<i class="fa-solid fa-rocket"></i>
|
|
44
|
+
<p>Web demo</p>
|
|
45
|
+
</div>
|
|
46
|
+
</a>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<!-- <h3><strong>Parameters</strong></h3> -->
|
|
50
|
+
<table>
|
|
51
|
+
<thead>
|
|
52
|
+
<tr>
|
|
53
|
+
<th>Parameter</th>
|
|
54
|
+
<th></th>
|
|
55
|
+
<th>Default</th>
|
|
56
|
+
</tr>
|
|
57
|
+
</thead>
|
|
58
|
+
<tbody>
|
|
59
|
+
{% for key, val in algo_params.items() %}
|
|
60
|
+
<tr>
|
|
61
|
+
<td>{{ key }}</td>
|
|
62
|
+
<td>{{ val.get("description") }}</td>
|
|
63
|
+
<td>{{ val.get("default") }}</td>
|
|
64
|
+
</tr>
|
|
65
|
+
{% endfor %}
|
|
66
|
+
</tbody>
|
|
67
|
+
</table>
|
|
68
|
+
</div>
|
|
69
|
+
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"
|
|
70
|
+
integrity="sha384-QFfYf8qpCIem7U+Uz5XYW6XPiA5sdP7ePLCTDBSMF0Os3J8nt9wM5L3yZGOI+73s"
|
|
71
|
+
crossorigin="anonymous"></script>
|
|
72
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js"
|
|
73
|
+
integrity="sha384-Q8KdjMRRhHpXEmsdpu2x9NkRBe/HHU6hLmjNw07uGpD7jz1zPoj2a9t8WbQhAjc"
|
|
74
|
+
crossorigin="anonymous"></script>
|
|
75
|
+
|
|
76
|
+
</body>
|
|
77
|
+
|
|
78
|
+
</html>
|
{imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: imaging-server-kit
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: Deploy image processing algorithms in FastAPI servers.
|
|
5
5
|
Author-email: Mallory Wittwer <mallory.wittwer@epfl.ch>
|
|
6
6
|
License: Copyright (c) 2024, EPFL
|
|
@@ -54,92 +54,122 @@ Requires-Dist: tifffile
|
|
|
54
54
|
Requires-Dist: numpy
|
|
55
55
|
Requires-Dist: scikit-image
|
|
56
56
|
Requires-Dist: geojson
|
|
57
|
-
Requires-Dist: docker
|
|
58
57
|
Requires-Dist: jinja2
|
|
59
58
|
Requires-Dist: pyyaml
|
|
60
59
|
Requires-Dist: dash
|
|
61
60
|
Requires-Dist: dash-bootstrap-components
|
|
61
|
+
Requires-Dist: a2wsgi
|
|
62
62
|
Requires-Dist: pytest
|
|
63
63
|
|
|
64
64
|

|
|
65
65
|
# 🪐 Imaging Server Kit
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
Deploy image processing algorithms in FastAPI servers and easily run them in Napari, QuPath, and more.
|
|
68
68
|
|
|
69
|
-
##
|
|
70
|
-
|
|
71
|
-
Build the `imaging-server-kit` image with `docker`:
|
|
69
|
+
## Usage
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
### Algorithm servers
|
|
72
|
+
|
|
73
|
+
Set up and run a server with one, or multiple algorithms from the Imaging Server Kit collection (or your own):
|
|
74
|
+
|
|
75
|
+
- [StarDist](https://github.com/Imaging-Server-Kit/serverkit-stardist)
|
|
76
|
+
- [CellPose](https://github.com/Imaging-Server-Kit/serverkit-cellpose)
|
|
77
|
+
- [Spotiflow](https://github.com/Imaging-Server-Kit/serverkit-spotiflow)
|
|
78
|
+
- [Rembg](https://github.com/Imaging-Server-Kit/serverkit-rembg)
|
|
79
|
+
- [Scikit-image LoG detector](https://github.com/Imaging-Server-Kit/serverkit-skimage-LoG)
|
|
80
|
+
- [Orientationpy](https://github.com/Imaging-Server-Kit/serverkit-orientationpy)
|
|
81
|
+
<!-- - [Tau Fibrils Detector](https://github.com/Imaging-Server-Kit/serverkit-tau-fibrils-yolo) -->
|
|
82
|
+
|
|
83
|
+
To do that, the recommended way is to edit a `docker-compose.yml` file and pull server images from `registry.rcp.epfl.ch` (EPFL users only):
|
|
84
|
+
|
|
85
|
+
```{docker-compose.yml}
|
|
86
|
+
services:
|
|
87
|
+
servers_registry:
|
|
88
|
+
image: mallorywittwerepfl/imaging-server-kit:registry
|
|
89
|
+
ports:
|
|
90
|
+
- "8000:8000"
|
|
91
|
+
rembg:
|
|
92
|
+
image: registry.rcp.epfl.ch/imaging-server-kit/serverkit-rembg:latest
|
|
93
|
+
depends_on:
|
|
94
|
+
- servers_registry
|
|
95
|
+
skimage-log:
|
|
96
|
+
image: registry.rcp.epfl.ch/imaging-server-kit/serverkit-skimage-log:latest
|
|
97
|
+
depends_on:
|
|
98
|
+
- servers_registry
|
|
75
99
|
```
|
|
76
100
|
|
|
77
|
-
|
|
101
|
+
Start the server with
|
|
78
102
|
|
|
79
103
|
```
|
|
80
|
-
docker
|
|
81
|
-
docker build -t imaging-server-kit:gpu --file Dockerfile-GPU .
|
|
104
|
+
docker compose up
|
|
82
105
|
```
|
|
83
106
|
|
|
84
|
-
|
|
107
|
+
The server should be accessible at http://localhost:8000.
|
|
85
108
|
|
|
86
|
-
|
|
109
|
+
**Build the docker images yourself**
|
|
87
110
|
|
|
88
|
-
|
|
89
|
-
docker build -t serverkit/rembg .
|
|
90
|
-
docker run -it --rm -p 8000:8000 serverkit/rembg
|
|
91
|
-
```
|
|
111
|
+
To build the algorithm server images yourself (e.g. if you are not from EPFL), see [Reference Deployment](https://github.com/Imaging-Server-Kit/serverkit-deploy-docker).
|
|
92
112
|
|
|
93
|
-
**
|
|
113
|
+
**Create a server for your project**
|
|
94
114
|
|
|
95
|
-
|
|
115
|
+
To learn how to create a server for your project, see [Algorithm Server Template](https://github.com/Imaging-Server-Kit/cookiecutter-serverkit).
|
|
96
116
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
**Python client**
|
|
117
|
+
### Python client
|
|
100
118
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
pip install git+https://gitlab.com/epfl-center-for-imaging/imaging-server-kit.git
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Connect to an algorithm server and run algorithms from Python:
|
|
119
|
+
Once the server is running, connect to it and run algorithms from Python:
|
|
108
120
|
|
|
109
121
|
```python
|
|
110
122
|
from imaging_server_kit import Client
|
|
111
123
|
|
|
112
|
-
client = Client()
|
|
113
|
-
|
|
114
|
-
client.connect("http://localhost:7000")
|
|
124
|
+
client = Client("http://localhost:8000")
|
|
115
125
|
|
|
116
126
|
print(client.algorithms)
|
|
117
|
-
# [`rembg`, `stardist`, `
|
|
127
|
+
# [`rembg`, `stardist`, `cellpose`]
|
|
118
128
|
|
|
119
|
-
|
|
129
|
+
algo_output = client.run_algorithm(
|
|
120
130
|
algorithm="rembg",
|
|
121
131
|
image=(...),
|
|
122
132
|
rembg_model_name="silueta",
|
|
123
133
|
)
|
|
124
134
|
```
|
|
125
135
|
|
|
126
|
-
|
|
136
|
+
### Napari plugin
|
|
137
|
+
|
|
138
|
+
Once the server is running, use the [Napari Server Kit](https://github.com/Imaging-Server-Kit/napari-serverkit) plugin to connect to it and run algorithms in Napari.
|
|
127
139
|
|
|
128
|
-
|
|
140
|
+
### QuPath extension
|
|
129
141
|
|
|
130
|
-
|
|
142
|
+
Once the server is running, use the [QuPath Extension Server Kit](https://github.com/Imaging-Server-Kit/qupath-extension-serverkit) to connect to it and run algorithms from within QuPath.
|
|
131
143
|
|
|
132
|
-
|
|
144
|
+
## Install locally
|
|
133
145
|
|
|
134
|
-
|
|
146
|
+
Install the `imaging-server-kit` package with `pip`:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
pip install imaging-server-kit
|
|
150
|
+
```
|
|
135
151
|
|
|
136
|
-
|
|
152
|
+
or clone the project and install the development version:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
git clone https://github.com/Imaging-Server-Kit/imaging-server-kit.git
|
|
156
|
+
cd imaging-server-kit
|
|
157
|
+
pip install -e .
|
|
158
|
+
```
|
|
137
159
|
|
|
138
|
-
|
|
160
|
+
## Build with `docker`
|
|
139
161
|
|
|
140
|
-
|
|
162
|
+
Build the `imaging-server-kit` docker image for a specific Python version:
|
|
141
163
|
|
|
142
|
-
|
|
164
|
+
```
|
|
165
|
+
docker build --build-arg PYTHON_VERSION=3.9 -t imaging-server-kit:3.9 .
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Run [build.sh](./build.sh) to build docker images for Python 3.9, 3.10, 3.11, GPU and the server kit registry:
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
bash ./build.sh
|
|
172
|
+
```
|
|
143
173
|
|
|
144
174
|
## Contributing
|
|
145
175
|
|
{imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit.egg-info/SOURCES.txt
RENAMED
|
@@ -15,7 +15,6 @@ start_registry.py
|
|
|
15
15
|
examples/.gitkeep
|
|
16
16
|
src/imaging_server_kit/__init__.py
|
|
17
17
|
src/imaging_server_kit/_version.py
|
|
18
|
-
src/imaging_server_kit/autostartup_registry.py
|
|
19
18
|
src/imaging_server_kit/client.py
|
|
20
19
|
src/imaging_server_kit/encoding.py
|
|
21
20
|
src/imaging_server_kit/errors.py
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-

|
|
2
|
-
# 🪐 Imaging Server Kit
|
|
3
|
-
|
|
4
|
-
Run seamlessly interoperable algorithms on images using FastAPI.
|
|
5
|
-
|
|
6
|
-
## Setup
|
|
7
|
-
|
|
8
|
-
Build the `imaging-server-kit` image with `docker`:
|
|
9
|
-
|
|
10
|
-
```
|
|
11
|
-
docker build -t imaging-server-kit:3.9 .
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
or build specific images:
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
docker build -t imaging-server-kit:3.10 --file Dockerfile-3.10 .
|
|
18
|
-
docker build -t imaging-server-kit:gpu --file Dockerfile-GPU .
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
**Run an algorithm server**
|
|
22
|
-
|
|
23
|
-
The server will be running on `http://localhost:8000`.
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
docker build -t serverkit/rembg .
|
|
27
|
-
docker run -it --rm -p 8000:8000 serverkit/rembg
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
**Run an algorithm server with multiple algorithms**
|
|
31
|
-
|
|
32
|
-
See [deployment](./reference_deployment/README.md). The server will be running on `http://localhost:7000`.
|
|
33
|
-
|
|
34
|
-
## Usage
|
|
35
|
-
|
|
36
|
-
**Python client**
|
|
37
|
-
|
|
38
|
-
Install the `imaging-server-kit` package with `pip`:
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
pip install git+https://gitlab.com/epfl-center-for-imaging/imaging-server-kit.git
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Connect to an algorithm server and run algorithms from Python:
|
|
45
|
-
|
|
46
|
-
```python
|
|
47
|
-
from imaging_server_kit import Client
|
|
48
|
-
|
|
49
|
-
client = Client()
|
|
50
|
-
|
|
51
|
-
client.connect("http://localhost:7000")
|
|
52
|
-
|
|
53
|
-
print(client.algorithms)
|
|
54
|
-
# [`rembg`, `stardist`, `sam2`]
|
|
55
|
-
|
|
56
|
-
data_tuple = client.run_algorithm(
|
|
57
|
-
algorithm="rembg",
|
|
58
|
-
image=(...),
|
|
59
|
-
rembg_model_name="silueta",
|
|
60
|
-
)
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
More [examples](./examples/).
|
|
64
|
-
|
|
65
|
-
**Napari client**
|
|
66
|
-
|
|
67
|
-
Coming soon.
|
|
68
|
-
|
|
69
|
-
**Web client**
|
|
70
|
-
|
|
71
|
-
Coming soon.
|
|
72
|
-
|
|
73
|
-
**QuPath client**
|
|
74
|
-
|
|
75
|
-
Coming soon.
|
|
76
|
-
|
|
77
|
-
**Fiji plugin**
|
|
78
|
-
|
|
79
|
-
Coming soon.
|
|
80
|
-
|
|
81
|
-
## Contributing
|
|
82
|
-
|
|
83
|
-
Contributions are very welcome.
|
|
84
|
-
|
|
85
|
-
## License
|
|
86
|
-
|
|
87
|
-
This software is distributed under the terms of the [BSD-3](http://opensource.org/licenses/BSD-3-Clause) license.
|
|
88
|
-
|
|
89
|
-
## Issues
|
|
90
|
-
|
|
91
|
-
If you encounter any problems, please file an issue along with a detailed description.
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
from fastapi import FastAPI
|
|
2
|
-
import docker
|
|
3
|
-
|
|
4
|
-
class AutoStartupRegistry:
|
|
5
|
-
def __init__(self, algo_servers) -> None:
|
|
6
|
-
self.algo_servers = algo_servers
|
|
7
|
-
self.app = FastAPI()
|
|
8
|
-
self.app.on_event("shutdown")(self.stop_all_algorithm_containers) # This doesn't work.
|
|
9
|
-
self.docker_client = docker.from_env()
|
|
10
|
-
self.services = {}
|
|
11
|
-
self.register_routes()
|
|
12
|
-
|
|
13
|
-
def register_routes(self):
|
|
14
|
-
@self.app.get("/")
|
|
15
|
-
def home():
|
|
16
|
-
return list_services()
|
|
17
|
-
|
|
18
|
-
@self.app.get("/services")
|
|
19
|
-
def list_services():
|
|
20
|
-
return {"services": list(self.services.keys())}
|
|
21
|
-
|
|
22
|
-
@self.app.get("/{algorithm}")
|
|
23
|
-
def get_algorithm_url(algorithm):
|
|
24
|
-
if algorithm not in self.services.keys():
|
|
25
|
-
container_url = self.start_algorithm_container(algorithm)
|
|
26
|
-
else:
|
|
27
|
-
container_url = self.services.get(algorithm).get("url")
|
|
28
|
-
return {"url": container_url}
|
|
29
|
-
|
|
30
|
-
def start_algorithm_container(self, algorithm):
|
|
31
|
-
algorithm_server_image = self.algo_servers[algorithm].get('image')
|
|
32
|
-
|
|
33
|
-
port = self.algo_servers[algorithm].get('port')
|
|
34
|
-
|
|
35
|
-
container = self.docker_client.containers.run(
|
|
36
|
-
image=algorithm_server_image,
|
|
37
|
-
ports={"8000/tcp": port},
|
|
38
|
-
detach=True,
|
|
39
|
-
remove=True,
|
|
40
|
-
name=f"serverkit-server-{algorithm}"
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
container_url = f"http://localhost:{port}"
|
|
44
|
-
|
|
45
|
-
self.services[algorithm] = {
|
|
46
|
-
"container": container,
|
|
47
|
-
"url": container_url,
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return container_url
|
|
51
|
-
|
|
52
|
-
def stop_algorithm_container(self, algorithm):
|
|
53
|
-
container = self.services[algorithm].get("container")
|
|
54
|
-
container.stop()
|
|
55
|
-
|
|
56
|
-
def stop_all_algorithm_containers(self):
|
|
57
|
-
for algorithm in self.services.keys():
|
|
58
|
-
self.stop_algorithm_container(algorithm)
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
body {
|
|
2
|
-
font-family: Arial, sans-serif;
|
|
3
|
-
margin: 0;
|
|
4
|
-
padding: 0;
|
|
5
|
-
background-color: #f4f4f4;
|
|
6
|
-
color: #333;
|
|
7
|
-
}
|
|
8
|
-
.container {
|
|
9
|
-
max-width: 800px;
|
|
10
|
-
margin: 50px auto;
|
|
11
|
-
padding: 20px;
|
|
12
|
-
background-color: #fff;
|
|
13
|
-
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
|
14
|
-
border-radius: 8px;
|
|
15
|
-
}
|
|
16
|
-
h1 {
|
|
17
|
-
color: #007BFF;
|
|
18
|
-
}
|
|
19
|
-
p {
|
|
20
|
-
line-height: 1.6;
|
|
21
|
-
}
|
|
22
|
-
a {
|
|
23
|
-
color: #007BFF;
|
|
24
|
-
text-decoration: none;
|
|
25
|
-
}
|
|
26
|
-
a:hover {
|
|
27
|
-
text-decoration: underline;
|
|
28
|
-
}
|
|
29
|
-
ul {
|
|
30
|
-
list-style-type: disc;
|
|
31
|
-
padding-left: 20px;
|
|
32
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
body {
|
|
2
|
-
font-family: Arial, sans-serif;
|
|
3
|
-
margin: 0;
|
|
4
|
-
padding: 0;
|
|
5
|
-
background-color: #f4f4f4;
|
|
6
|
-
color: #333;
|
|
7
|
-
}
|
|
8
|
-
.container {
|
|
9
|
-
max-width: 800px;
|
|
10
|
-
margin: 50px auto;
|
|
11
|
-
padding: 20px;
|
|
12
|
-
background-color: #fff;
|
|
13
|
-
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
|
14
|
-
border-radius: 8px;
|
|
15
|
-
}
|
|
16
|
-
h1 {
|
|
17
|
-
color: #007BFF;
|
|
18
|
-
}
|
|
19
|
-
p {
|
|
20
|
-
line-height: 1.6;
|
|
21
|
-
}
|
|
22
|
-
a {
|
|
23
|
-
color: #007BFF;
|
|
24
|
-
text-decoration: none;
|
|
25
|
-
}
|
|
26
|
-
a:hover {
|
|
27
|
-
text-decoration: underline;
|
|
28
|
-
}
|
|
29
|
-
ul {
|
|
30
|
-
list-style-type: disc;
|
|
31
|
-
padding-left: 20px;
|
|
32
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="UTF-8">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<link rel="stylesheet" href="/static/index.css">
|
|
8
|
-
</head>
|
|
9
|
-
|
|
10
|
-
<body>
|
|
11
|
-
<div class="container">
|
|
12
|
-
<h1>Running servers</h1>
|
|
13
|
-
|
|
14
|
-
<ul>
|
|
15
|
-
{% for service in services %}
|
|
16
|
-
<li>
|
|
17
|
-
<a href="/{{ service }}/info">{{ service }}</a>
|
|
18
|
-
</li>
|
|
19
|
-
{% endfor %}
|
|
20
|
-
</ul>
|
|
21
|
-
|
|
22
|
-
</div>
|
|
23
|
-
</body>
|
|
24
|
-
|
|
25
|
-
</html>
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="UTF-8">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<link rel="stylesheet" href="/static/info.css">
|
|
8
|
-
</head>
|
|
9
|
-
|
|
10
|
-
<body>
|
|
11
|
-
<div class="container">
|
|
12
|
-
<h1>{{ algo_info.project_name }}</h1>
|
|
13
|
-
<p>Package name: {{ algo_info.package_name }}</p>
|
|
14
|
-
<p>Serverkit project author: {{ algo_info.serverkit_author }}</p>
|
|
15
|
-
<p>Description: {{ algo_info.description }}</p>
|
|
16
|
-
<p><a href="{{ algo_info.project_url }}">Original Project</a></p>
|
|
17
|
-
<p><a href="{{ algo_info.serverkit_repo_url }}">ServerKit Repository</a></p>
|
|
18
|
-
<p><a href="/demo">Web demo</a></p>
|
|
19
|
-
<p>Used for:
|
|
20
|
-
<ul>
|
|
21
|
-
{% for used_for_tag in algo_info.used_for %}
|
|
22
|
-
<li>{{ used_for_tag }}</li>
|
|
23
|
-
{% endfor %}
|
|
24
|
-
</ul>
|
|
25
|
-
</p>
|
|
26
|
-
<p>Tags:
|
|
27
|
-
<ul>
|
|
28
|
-
{% for tag in algo_info.tags %}
|
|
29
|
-
<li>{{ tag }}</li>
|
|
30
|
-
{% endfor %}
|
|
31
|
-
</ul>
|
|
32
|
-
</p>
|
|
33
|
-
<p>Algorithm parameters:</p>
|
|
34
|
-
<table>
|
|
35
|
-
<thead>
|
|
36
|
-
<tr>
|
|
37
|
-
<th>Parameter</th>
|
|
38
|
-
<th>Title</th>
|
|
39
|
-
<th>Description</th>
|
|
40
|
-
<th>Type</th>
|
|
41
|
-
<th>Widget Type</th>
|
|
42
|
-
<th>Default</th>
|
|
43
|
-
<th>Required</th>
|
|
44
|
-
</tr>
|
|
45
|
-
</thead>
|
|
46
|
-
<tbody>
|
|
47
|
-
{% for key, val in algo_params.items() %}
|
|
48
|
-
<tr>
|
|
49
|
-
<td>{{ key }}</td>
|
|
50
|
-
<td>{{ val.get("title") }}</td>
|
|
51
|
-
<td>{{ val.get("description") }}</td>
|
|
52
|
-
<td>{{ val.get("type") }}</td>
|
|
53
|
-
<td>{{ val.get("widget_type") }}</td>
|
|
54
|
-
<td>{{ val.get("default") }}</td>
|
|
55
|
-
<td>{{ val.get("required") }}</td>
|
|
56
|
-
</tr>
|
|
57
|
-
{% endfor %}
|
|
58
|
-
</tbody>
|
|
59
|
-
</table>
|
|
60
|
-
</div>
|
|
61
|
-
</body>
|
|
62
|
-
|
|
63
|
-
</html>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit/assets/style.css
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit/serialization.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{imaging_server_kit-0.0.2 → imaging_server_kit-0.0.3}/src/imaging_server_kit.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|