zmq-vision 0.3.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.
- zmq_vision-0.3.0/.env.example +8 -0
- zmq_vision-0.3.0/CHANGELOG.md +81 -0
- zmq_vision-0.3.0/CONTRIBUTING.md +19 -0
- zmq_vision-0.3.0/LICENSE +21 -0
- zmq_vision-0.3.0/MANIFEST.in +7 -0
- zmq_vision-0.3.0/Makefile +25 -0
- zmq_vision-0.3.0/PKG-INFO +278 -0
- zmq_vision-0.3.0/README.md +234 -0
- zmq_vision-0.3.0/docs/architecture.md +73 -0
- zmq_vision-0.3.0/docs/assets/banner.svg +16 -0
- zmq_vision-0.3.0/docs/assets/demo-output.txt +6 -0
- zmq_vision-0.3.0/docs/assets/demo.svg +17 -0
- zmq_vision-0.3.0/docs/assets.md +5 -0
- zmq_vision-0.3.0/docs/migration.md +20 -0
- zmq_vision-0.3.0/docs/releases/0.3.0.md +12 -0
- zmq_vision-0.3.0/docs/releasing.md +17 -0
- zmq_vision-0.3.0/docs/validation.md +30 -0
- zmq_vision-0.3.0/examples/custom_backend.py +32 -0
- zmq_vision-0.3.0/examples/legacy/README.md +5 -0
- zmq_vision-0.3.0/examples/legacy/client_async.py +43 -0
- zmq_vision-0.3.0/examples/legacy/client_loop.py +55 -0
- zmq_vision-0.3.0/examples/legacy/inference_server_tf.py +176 -0
- zmq_vision-0.3.0/examples/legacy/inference_server_torch.py +133 -0
- zmq_vision-0.3.0/examples/sample.png +0 -0
- zmq_vision-0.3.0/pyproject.toml +75 -0
- zmq_vision-0.3.0/scripts/check_distribution.py +60 -0
- zmq_vision-0.3.0/scripts/render_assets.py +56 -0
- zmq_vision-0.3.0/setup.cfg +4 -0
- zmq_vision-0.3.0/src/zmq_inference/__init__.py +22 -0
- zmq_vision-0.3.0/src/zmq_inference/__main__.py +5 -0
- zmq_vision-0.3.0/src/zmq_inference/cli/__init__.py +1 -0
- zmq_vision-0.3.0/src/zmq_inference/cli/main.py +217 -0
- zmq_vision-0.3.0/src/zmq_inference/client/__init__.py +6 -0
- zmq_vision-0.3.0/src/zmq_inference/client/async_client.py +110 -0
- zmq_vision-0.3.0/src/zmq_inference/client/base.py +65 -0
- zmq_vision-0.3.0/src/zmq_inference/client/sync_client.py +109 -0
- zmq_vision-0.3.0/src/zmq_inference/core/__init__.py +12 -0
- zmq_vision-0.3.0/src/zmq_inference/core/config.py +85 -0
- zmq_vision-0.3.0/src/zmq_inference/core/logging.py +57 -0
- zmq_vision-0.3.0/src/zmq_inference/core/protocol.py +159 -0
- zmq_vision-0.3.0/src/zmq_inference/data/__init__.py +1 -0
- zmq_vision-0.3.0/src/zmq_inference/data/imagenet_classes.json +1 -0
- zmq_vision-0.3.0/src/zmq_inference/demo.py +45 -0
- zmq_vision-0.3.0/src/zmq_inference/py.typed +0 -0
- zmq_vision-0.3.0/src/zmq_inference/server/__init__.py +5 -0
- zmq_vision-0.3.0/src/zmq_inference/server/base.py +176 -0
- zmq_vision-0.3.0/src/zmq_inference/server/demo_server.py +32 -0
- zmq_vision-0.3.0/src/zmq_inference/server/tf_server.py +133 -0
- zmq_vision-0.3.0/src/zmq_inference/server/torch_server.py +124 -0
- zmq_vision-0.3.0/src/zmq_inference/utils/__init__.py +12 -0
- zmq_vision-0.3.0/src/zmq_inference/utils/image.py +77 -0
- zmq_vision-0.3.0/src/zmq_inference/utils/labels.py +43 -0
- zmq_vision-0.3.0/src/zmq_vision.egg-info/PKG-INFO +278 -0
- zmq_vision-0.3.0/src/zmq_vision.egg-info/SOURCES.txt +66 -0
- zmq_vision-0.3.0/src/zmq_vision.egg-info/dependency_links.txt +1 -0
- zmq_vision-0.3.0/src/zmq_vision.egg-info/entry_points.txt +3 -0
- zmq_vision-0.3.0/src/zmq_vision.egg-info/requires.txt +23 -0
- zmq_vision-0.3.0/src/zmq_vision.egg-info/top_level.txt +1 -0
- zmq_vision-0.3.0/tests/__init__.py +1 -0
- zmq_vision-0.3.0/tests/conftest.py +104 -0
- zmq_vision-0.3.0/tests/test_backends.py +50 -0
- zmq_vision-0.3.0/tests/test_cli.py +85 -0
- zmq_vision-0.3.0/tests/test_config.py +34 -0
- zmq_vision-0.3.0/tests/test_image_utils.py +90 -0
- zmq_vision-0.3.0/tests/test_integration.py +279 -0
- zmq_vision-0.3.0/tests/test_protocol.py +151 -0
- zmq_vision-0.3.0/tests/test_server.py +75 -0
- zmq_vision-0.3.0/tests/test_sync_client.py +21 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Reference only: the library reads exported variables, not .env files.
|
|
2
|
+
# On a trusted LAN, explicitly change the server bind host to 0.0.0.0.
|
|
3
|
+
ZMQ_HOST=127.0.0.1
|
|
4
|
+
ZMQ_PORT=5576
|
|
5
|
+
ZMQ_MODEL=mobilenetv2_100
|
|
6
|
+
ZMQ_DEVICE=auto
|
|
7
|
+
ZMQ_SERVER_HOST=127.0.0.1
|
|
8
|
+
ZMQ_TIMEOUT_MS=30000
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## [0.3.0] - 2026-10-25
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- ZMQ Vision branding and `zmq-vision` distribution/CLI, retaining `zmq_inference` imports.
|
|
15
|
+
- Download-free TCP demo, readiness protocol, environment diagnostics, and JSON CLI output.
|
|
16
|
+
- Bounded model workers and admission, validation limits, overload responses, and startup failure reporting.
|
|
17
|
+
- Real TCP, concurrent client, timeout, cancellation, shutdown, CLI, and optional real-model tests.
|
|
18
|
+
- CI across supported Python versions, distribution checks, tagged GitHub releases, and manual OIDC PyPI publishing.
|
|
19
|
+
- Architecture, migration, contribution, and release guides; captured demo visualization; missing MIT license file.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Moved library to `src/`, sample to `examples/`, and original scripts to `examples/legacy/`.
|
|
24
|
+
- Consolidated metadata into `pyproject.toml`; removed obsolete GPU requirements and duplicate label data.
|
|
25
|
+
- Updated dependency ranges to current supported releases, with ML frameworks kept optional.
|
|
26
|
+
- Included the Windows-only Tornado selector bridge required by PyZMQ asyncio.
|
|
27
|
+
- Applied model-specific timm transforms and direct TensorFlow/Keras inference.
|
|
28
|
+
- Made localhost binding and one client attempt the defaults; health no longer performs inference.
|
|
29
|
+
- Replaced request threads and the in-process proxy with bounded futures and one socket-owning thread.
|
|
30
|
+
- Reset client sockets after timeout/cancellation and correlate every response.
|
|
31
|
+
|
|
32
|
+
See [migration notes](docs/migration.md) for API and default changes.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## [0.2.0] - 2026-05-24
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- **Complete package overhaul**: flat scripts migrated to the `zmq_inference` Python package.
|
|
41
|
+
- **Abstract base classes** for server (`BaseInferenceServer`) and client (`BaseInferenceClient`) with clean extension points.
|
|
42
|
+
- **Dataclass-based configuration** (`ServerConfig`, `ClientConfig`) with full environment-variable support.
|
|
43
|
+
- **Typed protocol layer** (`InferenceRequest`, `InferenceResponse`, `Prediction`) with JSON serialisation helpers.
|
|
44
|
+
- **Click CLI** entry point (`zmq-inference serve | infer | health`).
|
|
45
|
+
- **Full test suite** (`tests/`) with pytest, pytest-asyncio, and pytest-cov.
|
|
46
|
+
- **pyproject.toml** build system with optional extras (`torch`, `tf`, `dev`).
|
|
47
|
+
- **Async client** (`AsyncClient`) using `zmq.asyncio`.
|
|
48
|
+
- **Structured logging** via `zmq_inference.core.logging`.
|
|
49
|
+
- **ImageNet labels** bundled as package data under `zmq_inference/data/`.
|
|
50
|
+
- **Makefile** for common development tasks.
|
|
51
|
+
- Updated dependencies to modern versions (pyzmq>=25, Pillow>=9, numpy>=1.23).
|
|
52
|
+
- TensorFlow server modernised: removed `tf.compat.v1` session usage; uses `model.predict` with `tf.function` warm-up.
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
|
|
56
|
+
- `zmq_inference/server/base.py` — abstract `BaseInferenceServer` (threading.Thread + ZMQ loop).
|
|
57
|
+
- `zmq_inference/server/torch_server.py` — PyTorch/timm implementation.
|
|
58
|
+
- `zmq_inference/server/tf_server.py` — TensorFlow/Keras implementation (TF2 style).
|
|
59
|
+
- `zmq_inference/client/base.py` — abstract `BaseInferenceClient`.
|
|
60
|
+
- `zmq_inference/client/sync_client.py` — synchronous client with retry logic.
|
|
61
|
+
- `zmq_inference/client/async_client.py` — asyncio client.
|
|
62
|
+
- `zmq_inference/core/config.py` — `ServerConfig` and `ClientConfig` dataclasses.
|
|
63
|
+
- `zmq_inference/core/protocol.py` — request/response dataclasses.
|
|
64
|
+
- `zmq_inference/core/logging.py` — structured logging helpers.
|
|
65
|
+
- `zmq_inference/utils/image.py` — `encode_image`, `decode_image`, `preprocess_for_display`.
|
|
66
|
+
- `zmq_inference/utils/labels.py` — `load_imagenet_labels`, `get_label` (uses `importlib.resources`).
|
|
67
|
+
- `zmq_inference/cli/main.py` — Click CLI: `serve`, `infer`, `health` commands.
|
|
68
|
+
- `.env.example` — environment variable reference.
|
|
69
|
+
- `.gitignore` — comprehensive Python + ML project ignore rules.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## [0.1.0] - 2024-06-12
|
|
74
|
+
|
|
75
|
+
### Added
|
|
76
|
+
|
|
77
|
+
- Initial ZMQ inference server supporting PyTorch (timm) and TensorFlow (Keras) backends.
|
|
78
|
+
- Synchronous polling client (`client_loop.py`).
|
|
79
|
+
- Async client using `asyncio.to_thread` (`client_async.py`).
|
|
80
|
+
- `imagenet_classes.json` label file.
|
|
81
|
+
- `requirements.txt` with pinned dependencies.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Use Python 3.10+ and install `python -m pip install -e ".[dev]"` in a virtual environment. The `src/` layout ensures tests exercise an installed package.
|
|
4
|
+
|
|
5
|
+
Before submitting a change:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
ruff check .
|
|
9
|
+
ruff format --check .
|
|
10
|
+
python -m pytest -m "not torch and not tf"
|
|
11
|
+
python -m build
|
|
12
|
+
python -m twine check dist/*
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Test transport changes with real localhost sockets. Keep ML imports lazy so the core package remains usable without either framework. Exercise optional model changes using `tests/test_backends.py`; document which backend, version, device, and weights were tested. Random weights validate plumbing, not classification accuracy.
|
|
16
|
+
|
|
17
|
+
Preserve the `zmq_inference` API unless a breaking change is documented in the changelog. Add a regression test for behavior changes, update affected examples, and describe user-visible outcomes in pull requests. Do not commit weights, tokens, `.env`, or generated build artifacts.
|
|
18
|
+
|
|
19
|
+
See [architecture](docs/architecture.md) for threading and delivery constraints.
|
zmq_vision-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Jamal Saeedi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
PYTHON ?= python
|
|
2
|
+
|
|
3
|
+
.PHONY: install install-torch install-tf test test-fast lint format format-check build check-dist demo
|
|
4
|
+
install:
|
|
5
|
+
$(PYTHON) -m pip install -e '.[dev]'
|
|
6
|
+
install-torch:
|
|
7
|
+
$(PYTHON) -m pip install -e '.[torch,dev]'
|
|
8
|
+
install-tf:
|
|
9
|
+
$(PYTHON) -m pip install -e '.[tf,dev]'
|
|
10
|
+
test:
|
|
11
|
+
$(PYTHON) -m pytest --cov=zmq_inference --cov-report=term-missing
|
|
12
|
+
test-fast:
|
|
13
|
+
$(PYTHON) -m pytest -m 'not torch and not tf' -q
|
|
14
|
+
lint:
|
|
15
|
+
$(PYTHON) -m ruff check .
|
|
16
|
+
format:
|
|
17
|
+
$(PYTHON) -m ruff format .
|
|
18
|
+
format-check:
|
|
19
|
+
$(PYTHON) -m ruff format --check .
|
|
20
|
+
build:
|
|
21
|
+
$(PYTHON) -m build
|
|
22
|
+
check-dist:
|
|
23
|
+
$(PYTHON) -m twine check dist/*
|
|
24
|
+
demo:
|
|
25
|
+
$(PYTHON) -m zmq_inference demo
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zmq-vision
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Serve image models over ZeroMQ with sync and async Python clients
|
|
5
|
+
Author-email: Jamal Saeedi <jamal.saeedi7@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jamal-saeedi/zmq-vision
|
|
8
|
+
Project-URL: Repository, https://github.com/jamal-saeedi/zmq-vision
|
|
9
|
+
Project-URL: Issues, https://github.com/jamal-saeedi/zmq-vision/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/jamal-saeedi/zmq-vision/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: zeromq,inference,computer-vision,pytorch,tensorflow
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: pyzmq<28,>=27.2
|
|
26
|
+
Requires-Dist: Pillow<14,>=12.1
|
|
27
|
+
Requires-Dist: click<9,>=8.3
|
|
28
|
+
Requires-Dist: tornado<7,>=6.5.10; sys_platform == "win32"
|
|
29
|
+
Provides-Extra: torch
|
|
30
|
+
Requires-Dist: torch<3,>=2.11; extra == "torch"
|
|
31
|
+
Requires-Dist: torchvision<1,>=0.26; extra == "torch"
|
|
32
|
+
Requires-Dist: timm<2,>=1.0.30; extra == "torch"
|
|
33
|
+
Provides-Extra: tf
|
|
34
|
+
Requires-Dist: tensorflow<3,>=2.21; extra == "tf"
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: pytest<10,>=8.4; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-asyncio<2,>=1; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-cov<8,>=6; extra == "dev"
|
|
39
|
+
Requires-Dist: numpy<3,>=2.2; extra == "dev"
|
|
40
|
+
Requires-Dist: ruff<1,>=0.14; extra == "dev"
|
|
41
|
+
Requires-Dist: build<2,>=1.3; extra == "dev"
|
|
42
|
+
Requires-Dist: twine<8,>=6; extra == "dev"
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
|
|
45
|
+
<p align="center">
|
|
46
|
+
<img src="https://raw.githubusercontent.com/jamal-saeedi/zmq-vision/main/docs/assets/banner.svg" alt="ZMQ Vision — image models, one messaging interface" width="920">
|
|
47
|
+
</p>
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
<a href="https://github.com/jamal-saeedi/zmq-vision/actions/workflows/ci.yml"><img src="https://github.com/jamal-saeedi/zmq-vision/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
51
|
+
<img src="https://img.shields.io/badge/Python-3.10%E2%80%933.14-3776AB" alt="Python 3.10–3.14">
|
|
52
|
+
<img src="https://img.shields.io/badge/PyZMQ-27.2-7C3AED" alt="PyZMQ 27.2">
|
|
53
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-10B981" alt="MIT license"></a>
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
# ZMQ Vision
|
|
57
|
+
|
|
58
|
+
**Serve image models over ZeroMQ with the same synchronous, asynchronous, and command-line clients.**
|
|
59
|
+
|
|
60
|
+
A small Python library that separates model execution from messaging. Run an ImageNet classifier with PyTorch/timm or TensorFlow/Keras, or implement three methods to serve your own image model. The core package uses PyZMQ, Pillow, and Click, plus a Windows-only Tornado bridge for asyncio.
|
|
61
|
+
|
|
62
|
+
Built by [Jamal Saeedi](https://github.com/jamal-saeedi). This project demonstrates transport design, bounded concurrency, model integration, Python packaging, and tests against real TCP sockets.
|
|
63
|
+
|
|
64
|
+
[Quick start](#quick-start) · [Model backends](#use-a-trained-model) · [Python API](#python-api) · [Architecture](#architecture) · [Development](#development)
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
Python 3.10 or newer; a virtual environment is recommended.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
git clone https://github.com/jamal-saeedi/zmq-vision.git
|
|
72
|
+
cd zmq-vision
|
|
73
|
+
python -m venv .venv
|
|
74
|
+
# Linux / macOS
|
|
75
|
+
source .venv/bin/activate
|
|
76
|
+
# Windows PowerShell: .venv\Scripts\Activate.ps1
|
|
77
|
+
python -m pip install --upgrade pip
|
|
78
|
+
python -m pip install .
|
|
79
|
+
zmq-vision demo
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The demo starts a server on an available localhost TCP port, checks readiness, sends generated images through both clients, checks their responses, and shuts down. It downloads no weights and needs no GPU. Its backend ranks mean RGB intensity; it is **not a trained classifier**.
|
|
83
|
+
|
|
84
|
+
<p align="center">
|
|
85
|
+
<img src="https://raw.githubusercontent.com/jamal-saeedi/zmq-vision/main/docs/assets/demo.svg" alt="Captured terminal output from the working sync and async TCP demo" width="920">
|
|
86
|
+
</p>
|
|
87
|
+
|
|
88
|
+
The image is captured from a real run; timings vary by machine. Run `zmq-vision demo --json` for inspectable output or `zmq-vision doctor` for installed versions.
|
|
89
|
+
|
|
90
|
+
Install directly from GitHub without cloning:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
python -m pip install "git+https://github.com/jamal-saeedi/zmq-vision.git"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The distribution is named `zmq-vision`. PyPI publication is a separate release step; the source install above works before publication. Existing `zmq_inference` imports and the `zmq-inference` command remain supported. See [migration notes](docs/migration.md).
|
|
97
|
+
|
|
98
|
+
## Use a trained model
|
|
99
|
+
|
|
100
|
+
Choose one extra; neither ML framework is required by the core package.
|
|
101
|
+
|
|
102
|
+
| Backend | Install from this checkout | Model | First run |
|
|
103
|
+
| --- | --- | --- | --- |
|
|
104
|
+
| Demo | `python -m pip install .` | Mean RGB intensity | Offline |
|
|
105
|
+
| PyTorch | `python -m pip install ".[torch]"` | ImageNet-1k models from timm | Downloads weights |
|
|
106
|
+
| TensorFlow | `python -m pip install ".[tf]"` | Keras MobileNet | Downloads weights |
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Terminal 1: PyTorch, CPU
|
|
110
|
+
zmq-vision serve --backend torch --model mobilenetv2_100 --device cpu
|
|
111
|
+
|
|
112
|
+
# Terminal 2
|
|
113
|
+
zmq-vision health
|
|
114
|
+
zmq-vision infer examples/sample.png
|
|
115
|
+
zmq-vision infer examples/sample.png --async --json
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Or start TensorFlow with `zmq-vision serve --backend tf --device cpu`.
|
|
119
|
+
|
|
120
|
+
For a fully offline transport example, use `zmq-vision serve --backend demo`, then send any image. `--no-pretrained` is available for ML smoke tests; randomly initialized model predictions are not meaningful. Framework and model-weight licenses apply separately. CPU/GPU installation and Python support depend on the selected framework's wheels; use Python 3.12 for the tested ML configuration.
|
|
121
|
+
|
|
122
|
+
## Python API
|
|
123
|
+
|
|
124
|
+
### Synchronous
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
from zmq_inference import ClientConfig
|
|
128
|
+
from zmq_inference.client import SyncClient
|
|
129
|
+
|
|
130
|
+
with SyncClient(ClientConfig(host="127.0.0.1", port=5576, timeout_ms=5000)) as client:
|
|
131
|
+
assert client.ping().ok
|
|
132
|
+
response = client.infer("examples/sample.png")
|
|
133
|
+
if not response.ok:
|
|
134
|
+
raise RuntimeError(response.error)
|
|
135
|
+
for prediction in response.predictions:
|
|
136
|
+
print(prediction.label, prediction.confidence)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Asynchronous
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
import asyncio
|
|
143
|
+
from zmq_inference.client.async_client import AsyncClient
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
async def main():
|
|
147
|
+
async with AsyncClient() as client:
|
|
148
|
+
response = await client.infer("examples/sample.png")
|
|
149
|
+
print(response)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
asyncio.run(main())
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
One async client serializes its exchanges so concurrent callers cannot consume each other's replies. Use multiple clients for concurrent server requests. A synchronous client belongs to the thread that connected it.
|
|
156
|
+
|
|
157
|
+
### Your own backend
|
|
158
|
+
|
|
159
|
+
Implement `load_model()`, `preprocess(image)`, and `predict(input)` on `BaseInferenceServer`. Transport, validation, error responses, queue limits, and lifecycle are provided. See the complete [custom backend example](examples/custom_backend.py).
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from zmq_inference import ServerConfig
|
|
163
|
+
from zmq_inference.server.demo_server import DemoInferenceServer
|
|
164
|
+
|
|
165
|
+
server = DemoInferenceServer(ServerConfig(port=5576))
|
|
166
|
+
server.start()
|
|
167
|
+
try:
|
|
168
|
+
server.wait_until_ready(timeout=10) # surfaces model-load and bind errors
|
|
169
|
+
server.join()
|
|
170
|
+
except KeyboardInterrupt:
|
|
171
|
+
pass
|
|
172
|
+
finally:
|
|
173
|
+
server.stop()
|
|
174
|
+
server.join()
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Architecture
|
|
178
|
+
|
|
179
|
+
```mermaid
|
|
180
|
+
flowchart LR
|
|
181
|
+
A[Sync client] --> D[DEALER sockets]
|
|
182
|
+
B[Async clients] --> D
|
|
183
|
+
C[CLI] --> D
|
|
184
|
+
D <-->|TCP · JSON · request IDs| R[ROUTER\nnetwork thread]
|
|
185
|
+
R --> Q[Bounded pending work]
|
|
186
|
+
Q --> W[Model worker pool]
|
|
187
|
+
W --> M{Backend}
|
|
188
|
+
M --> P[PyTorch / timm]
|
|
189
|
+
M --> T[TensorFlow / Keras]
|
|
190
|
+
M --> X[Demo / custom model]
|
|
191
|
+
X --> F[Completed responses]
|
|
192
|
+
P --> F
|
|
193
|
+
T --> F
|
|
194
|
+
F --> R
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
- **Socket ownership:** only the network thread touches the server socket. Workers return results through futures.
|
|
198
|
+
- **Bounded work:** one model worker and at most 16 accepted requests by default; overload returns an explicit busy response. Increase workers only for a thread-safe backend.
|
|
199
|
+
- **Response correlation:** clients match request IDs and replace their socket after a timeout or cancellation. Late replies cannot be returned as the next request's result.
|
|
200
|
+
- **Predictable lifecycle:** readiness means the model loaded and TCP bound. Shutdown stops admission, cancels queued work, and waits for active predictions.
|
|
201
|
+
- **Model preprocessing:** PyTorch uses the model's timm data configuration; TensorFlow uses MobileNet preprocessing and bundled ImageNet labels.
|
|
202
|
+
|
|
203
|
+
The earlier ROUTER/DEALER in-process proxy and thread-per-request design have been replaced. The client/server TCP connection still uses DEALER/ROUTER. [Protocol and limits](docs/architecture.md) cover delivery semantics and tradeoffs.
|
|
204
|
+
|
|
205
|
+
## Configuration
|
|
206
|
+
|
|
207
|
+
Explicit Python arguments or CLI options override environment defaults. `.env` files are not loaded automatically; `.env.example` documents variables you can export.
|
|
208
|
+
|
|
209
|
+
| Variable | Default | Used by |
|
|
210
|
+
| --- | --- | --- |
|
|
211
|
+
| `ZMQ_HOST` | `127.0.0.1` | Server bind host |
|
|
212
|
+
| `ZMQ_SERVER_HOST` | `127.0.0.1` | Client destination |
|
|
213
|
+
| `ZMQ_PORT` | `5576` | Both |
|
|
214
|
+
| `ZMQ_MODEL` | `mobilenetv2_100` | PyTorch model |
|
|
215
|
+
| `ZMQ_DEVICE` | `auto` | `auto`, `cpu`, or `cuda` |
|
|
216
|
+
| `ZMQ_TIMEOUT_MS` | `30000` | Client timeout per attempt |
|
|
217
|
+
|
|
218
|
+
Use `zmq-vision serve --help` and `zmq-vision infer --help` for options. Python `ServerConfig` also exposes message and decoded-image limits: 8 MiB per frame and 16 million pixels by default. Oversized frames are disconnected by libzmq; the client reaches its timeout. `--top-k` on `infer` limits displayed results; `serve --top-k` controls how many predictions are returned.
|
|
219
|
+
|
|
220
|
+
Defaults bind to localhost. For a trusted LAN, explicitly use `--host 0.0.0.0`; clients specify the server's address. This protocol has no built-in authentication or encryption. Use a secured private network or tunnel for remote traffic.
|
|
221
|
+
|
|
222
|
+
## Development
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
python -m pip install -e ".[dev]"
|
|
226
|
+
python -m pytest -m "not torch and not tf"
|
|
227
|
+
ruff check .
|
|
228
|
+
ruff format --check .
|
|
229
|
+
python -m build
|
|
230
|
+
python -m twine check dist/*
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Optional real-model tests (CPU, random weights, no downloads):
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
python -m pip install -e ".[torch,tf,dev]"
|
|
237
|
+
python -m pytest tests/test_backends.py
|
|
238
|
+
# Also download and exercise pretrained weights:
|
|
239
|
+
ZMQ_VISION_TEST_PRETRAINED=1 python -m pytest tests/test_backends.py
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Core CI covers Python 3.10–3.14 on Linux, with additional Windows and macOS jobs. Separate jobs exercise both ML backends on Python 3.12. Distribution checks install a built wheel in a new environment and run the demo outside the checkout. See the [recorded validation](docs/validation.md), [contributing guide](CONTRIBUTING.md), and [release instructions](docs/releasing.md).
|
|
243
|
+
|
|
244
|
+
```text
|
|
245
|
+
src/zmq_inference/ Installable library; legacy import name preserved
|
|
246
|
+
cli/ serve, infer, health, demo, doctor
|
|
247
|
+
client/ Synchronous and asyncio transports
|
|
248
|
+
core/ Configuration, protocol, logging
|
|
249
|
+
server/ Shared lifecycle and optional model backends
|
|
250
|
+
data/ Bundled ImageNet labels
|
|
251
|
+
utils/ Image serialization and resource loading
|
|
252
|
+
examples/ Runnable custom backend and original sample image
|
|
253
|
+
legacy/ Archived 2024 scripts; separate wire protocol
|
|
254
|
+
tests/ Unit, real TCP, CLI, and optional ML tests
|
|
255
|
+
docs/ Architecture, migration, release guide, visual assets
|
|
256
|
+
.github/workflows/ Checks, tagged GitHub releases, manual PyPI publishing
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Scope and limitations
|
|
260
|
+
|
|
261
|
+
This is an image inference transport library. It does not train models, batch requests, guarantee exactly-once execution, or provide multi-host scheduling. Retries can repeat inference; treat custom predictors as side-effect free. Health checks share worker admission and may time out under load. A hung model call can delay shutdown because Python cannot safely kill its thread.
|
|
262
|
+
|
|
263
|
+
A language model is not included: text generation needs a text protocol, token limits, and different response semantics. Adding a small LLM without that design would dilute the working vision interface. The backend extension point supports future image-oriented models without making their dependencies mandatory.
|
|
264
|
+
|
|
265
|
+
## Troubleshooting
|
|
266
|
+
|
|
267
|
+
| Symptom | Check |
|
|
268
|
+
| --- | --- |
|
|
269
|
+
| Timeout | `zmq-vision health --host HOST --port PORT`; confirm server readiness, firewall, and model load |
|
|
270
|
+
| Missing backend | Install the corresponding `[torch]` or `[tf]` extra |
|
|
271
|
+
| Address already in use | Choose another `--port`; startup failures return a nonzero exit status |
|
|
272
|
+
| Unexpected model result | Use pretrained weights, an ImageNet-1k model, and a suitable input image |
|
|
273
|
+
| Runtime / GPU failure | Run `zmq-vision doctor`, try `--device cpu`, and verify framework installation |
|
|
274
|
+
| Server busy | Reduce concurrent clients or size `--max-pending` for your deployment |
|
|
275
|
+
|
|
276
|
+
## License
|
|
277
|
+
|
|
278
|
+
[MIT](LICENSE). Original sample image and ImageNet label mapping are retained from this repository's earlier versions; their original upstream provenance was not recorded. See [asset notes](docs/assets.md).
|