AIserver 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.
- aiserver-0.1.0/.github/dependabot.yml +12 -0
- aiserver-0.1.0/.github/workflows/ci.yml +59 -0
- aiserver-0.1.0/.github/workflows/release.yml +65 -0
- aiserver-0.1.0/.gitignore +11 -0
- aiserver-0.1.0/CHANGELOG.md +14 -0
- aiserver-0.1.0/CONTRIBUTING.md +20 -0
- aiserver-0.1.0/LICENSE +21 -0
- aiserver-0.1.0/PKG-INFO +188 -0
- aiserver-0.1.0/README.md +150 -0
- aiserver-0.1.0/SECURITY.md +22 -0
- aiserver-0.1.0/docs/README.zh-CN.md +98 -0
- aiserver-0.1.0/examples/__init__.py +1 -0
- aiserver-0.1.0/examples/basic.py +26 -0
- aiserver-0.1.0/pyproject.toml +75 -0
- aiserver-0.1.0/src/aiserver/__init__.py +8 -0
- aiserver-0.1.0/src/aiserver/application.py +353 -0
- aiserver-0.1.0/src/aiserver/cli.py +91 -0
- aiserver-0.1.0/src/aiserver/context.py +27 -0
- aiserver-0.1.0/src/aiserver/middleware.py +94 -0
- aiserver-0.1.0/src/aiserver/models.py +68 -0
- aiserver-0.1.0/src/aiserver/py.typed +1 -0
- aiserver-0.1.0/tests/test_application.py +139 -0
- aiserver-0.1.0/tests/test_cli.py +20 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
name: ${{ matrix.os }} / Python ${{ matrix.python }}
|
|
14
|
+
runs-on: ${{ matrix.os }}
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
os: [ubuntu-latest, windows-latest]
|
|
19
|
+
python: ["3.11", "3.14"]
|
|
20
|
+
steps:
|
|
21
|
+
- name: Check out repository
|
|
22
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
23
|
+
|
|
24
|
+
- name: Set up Python
|
|
25
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
26
|
+
with:
|
|
27
|
+
python-version: ${{ matrix.python }}
|
|
28
|
+
cache: pip
|
|
29
|
+
|
|
30
|
+
- name: Install project
|
|
31
|
+
run: python -m pip install -e ".[dev]"
|
|
32
|
+
|
|
33
|
+
- name: Lint
|
|
34
|
+
run: python -m ruff check .
|
|
35
|
+
|
|
36
|
+
- name: Test
|
|
37
|
+
run: python -m pytest
|
|
38
|
+
|
|
39
|
+
package:
|
|
40
|
+
name: Package validation
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
steps:
|
|
43
|
+
- name: Check out repository
|
|
44
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
45
|
+
|
|
46
|
+
- name: Set up Python
|
|
47
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
48
|
+
with:
|
|
49
|
+
python-version: "3.12"
|
|
50
|
+
cache: pip
|
|
51
|
+
|
|
52
|
+
- name: Install build tools
|
|
53
|
+
run: python -m pip install build twine
|
|
54
|
+
|
|
55
|
+
- name: Build distributions
|
|
56
|
+
run: python -m build
|
|
57
|
+
|
|
58
|
+
- name: Check distributions
|
|
59
|
+
run: python -m twine check dist/*
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
id-token: write
|
|
11
|
+
attestations: write
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
release:
|
|
15
|
+
name: Build and publish GitHub release
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- name: Check out repository
|
|
19
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
20
|
+
|
|
21
|
+
- name: Set up Python
|
|
22
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.12"
|
|
25
|
+
cache: pip
|
|
26
|
+
|
|
27
|
+
- name: Install project and build tools
|
|
28
|
+
run: python -m pip install -e ".[dev]"
|
|
29
|
+
|
|
30
|
+
- name: Verify tag version
|
|
31
|
+
run: >-
|
|
32
|
+
python -c "import os, pathlib, tomllib;
|
|
33
|
+
version=tomllib.loads(pathlib.Path('pyproject.toml').read_text('utf-8'))['project']['version'];
|
|
34
|
+
expected=os.environ['GITHUB_REF_NAME'].removeprefix('v');
|
|
35
|
+
assert version == expected, f'tag {expected} does not match package {version}'"
|
|
36
|
+
|
|
37
|
+
- name: Lint and test
|
|
38
|
+
run: |
|
|
39
|
+
python -m ruff check .
|
|
40
|
+
python -m pytest
|
|
41
|
+
|
|
42
|
+
- name: Build and validate distributions
|
|
43
|
+
run: |
|
|
44
|
+
python -m build
|
|
45
|
+
python -m twine check dist/*
|
|
46
|
+
|
|
47
|
+
- name: Generate checksums
|
|
48
|
+
working-directory: dist
|
|
49
|
+
run: sha256sum aiserver-* > SHA256SUMS.txt
|
|
50
|
+
|
|
51
|
+
- name: Attest build provenance
|
|
52
|
+
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
|
|
53
|
+
with:
|
|
54
|
+
subject-path: "dist/aiserver-*"
|
|
55
|
+
|
|
56
|
+
- name: Publish GitHub release
|
|
57
|
+
env:
|
|
58
|
+
GH_TOKEN: ${{ github.token }}
|
|
59
|
+
run: >-
|
|
60
|
+
gh release create "$GITHUB_REF_NAME"
|
|
61
|
+
dist/*
|
|
62
|
+
--repo "$GITHUB_REPOSITORY"
|
|
63
|
+
--verify-tag
|
|
64
|
+
--generate-notes
|
|
65
|
+
--title "$GITHUB_REF_NAME"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
## 0.1.0 - 2026-08-20
|
|
6
|
+
|
|
7
|
+
- Rebuilt AIserver from scratch as a local-first AI inference task server.
|
|
8
|
+
- Added typed task registration with generated OpenAPI schemas.
|
|
9
|
+
- Added direct execution and in-memory asynchronous jobs.
|
|
10
|
+
- Added progress reporting, timeouts, concurrency limits, and lifecycle hooks.
|
|
11
|
+
- Added optional bearer-token authentication and request-size limits.
|
|
12
|
+
- Added a safe CLI that binds to localhost by default.
|
|
13
|
+
|
|
14
|
+
This release does not preserve the unrelated API from the historical 0.0.x package.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
AIserver keeps a deliberately small scope: single-process, local-first serving for typed Python
|
|
4
|
+
inference tasks. Discuss substantial features in an issue before implementing them.
|
|
5
|
+
|
|
6
|
+
## Development setup
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
python -m venv .venv
|
|
10
|
+
.venv/Scripts/pip install -e ".[dev]"
|
|
11
|
+
python -m ruff check .
|
|
12
|
+
python -m pytest
|
|
13
|
+
python -m build
|
|
14
|
+
python -m twine check dist/*
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Use the activation command appropriate for your shell on Linux or macOS.
|
|
18
|
+
|
|
19
|
+
Do not include model weights, credentials, private model inputs, generated datasets, or telemetry
|
|
20
|
+
in a contribution. New behavior should include focused tests and documentation.
|
aiserver-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NocoldBob
|
|
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.
|
aiserver-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: AIserver
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A lightweight, local-first Python server for typed AI inference tasks
|
|
5
|
+
Project-URL: Homepage, https://github.com/NocoldBob/AIserver
|
|
6
|
+
Project-URL: Documentation, https://github.com/NocoldBob/AIserver#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/NocoldBob/AIserver.git
|
|
8
|
+
Project-URL: Issues, https://github.com/NocoldBob/AIserver/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/NocoldBob/AIserver/blob/main/CHANGELOG.md
|
|
10
|
+
Author: NocoldBob
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: ai,fastapi,inference,local-first,model-serving
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Environment :: Web Environment
|
|
16
|
+
Classifier: Framework :: FastAPI
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
27
|
+
Requires-Python: >=3.11
|
|
28
|
+
Requires-Dist: fastapi<1.0,>=0.115
|
|
29
|
+
Requires-Dist: pydantic<3.0,>=2.8
|
|
30
|
+
Requires-Dist: uvicorn<1.0,>=0.30
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: build<2.0,>=1.2; extra == 'dev'
|
|
33
|
+
Requires-Dist: httpx2<3.0,>=2.10; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest<10.0,>=8.3; extra == 'dev'
|
|
35
|
+
Requires-Dist: ruff<1.0,>=0.9; extra == 'dev'
|
|
36
|
+
Requires-Dist: twine<7.0,>=6.0; extra == 'dev'
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# AIserver
|
|
40
|
+
|
|
41
|
+
[](https://pypi.org/project/AIserver/)
|
|
42
|
+
[](https://pypi.org/project/AIserver/)
|
|
43
|
+
[](https://github.com/NocoldBob/AIserver/actions/workflows/ci.yml)
|
|
44
|
+
[](LICENSE)
|
|
45
|
+
|
|
46
|
+
[中文说明](docs/README.zh-CN.md)
|
|
47
|
+
|
|
48
|
+
AIserver is a lightweight, local-first Python server for exposing AI inference functions as
|
|
49
|
+
secure, typed, and concurrency-controlled HTTP APIs.
|
|
50
|
+
|
|
51
|
+
It is intentionally smaller than a model runtime or distributed serving platform. Bring any
|
|
52
|
+
Python model or pipeline you already use; AIserver handles request validation, task execution,
|
|
53
|
+
job status, progress, lifecycle hooks, and conservative network defaults.
|
|
54
|
+
|
|
55
|
+
## Features
|
|
56
|
+
|
|
57
|
+
- Turn typed Python functions into documented HTTP endpoints.
|
|
58
|
+
- Run tasks directly or submit in-memory asynchronous jobs.
|
|
59
|
+
- Limit concurrency per task to protect CPU, GPU, and model memory.
|
|
60
|
+
- Report progress from synchronous or asynchronous inference code.
|
|
61
|
+
- Apply per-task timeouts and bounded job history.
|
|
62
|
+
- Load and release models with startup and shutdown hooks.
|
|
63
|
+
- Protect private endpoints with `AISERVER_TOKEN`.
|
|
64
|
+
- Reject oversized request bodies and bind to localhost by default.
|
|
65
|
+
- Generate OpenAPI documentation automatically at `/docs`.
|
|
66
|
+
- No telemetry, model downloads, protocol proxy, or request-body logging.
|
|
67
|
+
|
|
68
|
+
## Requirements
|
|
69
|
+
|
|
70
|
+
- Python 3.11 or newer
|
|
71
|
+
- Windows, Linux, or macOS
|
|
72
|
+
|
|
73
|
+
## Install
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install AIserver
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Until `0.1.0` is available on PyPI, install the wheel from the GitHub Release or build from source.
|
|
80
|
+
|
|
81
|
+
## Quick start
|
|
82
|
+
|
|
83
|
+
Create `app.py`:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from aiserver import AIServer, TaskContext
|
|
87
|
+
|
|
88
|
+
server = AIServer("demo")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@server.task(concurrency=2, timeout=30)
|
|
92
|
+
def classify(text: str, context: TaskContext) -> dict[str, str]:
|
|
93
|
+
context.report(0.5, "running inference")
|
|
94
|
+
return {"label": text.upper()}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Run it:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
aiserver run app:server
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Open `http://127.0.0.1:8000/docs`, or call it directly:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
curl -X POST http://127.0.0.1:8000/v1/tasks/classify/run \
|
|
107
|
+
-H "Content-Type: application/json" \
|
|
108
|
+
-d '{"text":"hello"}'
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Submit the same task as a job:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
curl -X POST http://127.0.0.1:8000/v1/tasks/classify/jobs \
|
|
115
|
+
-H "Content-Type: application/json" \
|
|
116
|
+
-d '{"text":"hello"}'
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Poll the returned `status_url` to read progress and the final result.
|
|
120
|
+
|
|
121
|
+
## Lifecycle hooks
|
|
122
|
+
|
|
123
|
+
Keep large model objects in your application module and initialize them once:
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
model = None
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@server.on_startup
|
|
130
|
+
def load_model():
|
|
131
|
+
global model
|
|
132
|
+
model = load_your_model()
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@server.on_shutdown
|
|
136
|
+
def release_model():
|
|
137
|
+
global model
|
|
138
|
+
model = None
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
AIserver is deliberately single-process so tasks can share an in-memory model. Its asynchronous
|
|
142
|
+
job records are not persistent and are lost when the process restarts.
|
|
143
|
+
|
|
144
|
+
## LAN access
|
|
145
|
+
|
|
146
|
+
The CLI refuses unauthenticated non-loopback binding by default. Set the token in the environment,
|
|
147
|
+
then start the server:
|
|
148
|
+
|
|
149
|
+
```powershell
|
|
150
|
+
$env:AISERVER_TOKEN = "use-a-long-random-value"
|
|
151
|
+
aiserver run app:server --host 0.0.0.0
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Clients can use either header:
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
Authorization: Bearer <token>
|
|
158
|
+
X-API-Key: <token>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Do not pass tokens on the command line or commit them to source control. Use a reverse proxy with
|
|
162
|
+
TLS before exposing AIserver outside a trusted private network.
|
|
163
|
+
|
|
164
|
+
## Scope
|
|
165
|
+
|
|
166
|
+
AIserver is not an LLM inference engine, OpenAI/Anthropic protocol gateway, model downloader,
|
|
167
|
+
distributed scheduler, or hosted control plane. Projects that need those capabilities should use
|
|
168
|
+
specialized runtimes and platforms.
|
|
169
|
+
|
|
170
|
+
## Historical package notice
|
|
171
|
+
|
|
172
|
+
Version `0.1.0` is a clean rewrite. It does not preserve the unrelated remote-chat and robot demo
|
|
173
|
+
APIs from the historical `0.0.x` releases. Those releases should not be used.
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
python -m venv .venv
|
|
179
|
+
.venv/Scripts/pip install -e ".[dev]"
|
|
180
|
+
ruff check .
|
|
181
|
+
pytest
|
|
182
|
+
python -m build
|
|
183
|
+
python -m twine check dist/*
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
MIT
|
aiserver-0.1.0/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# AIserver
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/AIserver/)
|
|
4
|
+
[](https://pypi.org/project/AIserver/)
|
|
5
|
+
[](https://github.com/NocoldBob/AIserver/actions/workflows/ci.yml)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
[中文说明](docs/README.zh-CN.md)
|
|
9
|
+
|
|
10
|
+
AIserver is a lightweight, local-first Python server for exposing AI inference functions as
|
|
11
|
+
secure, typed, and concurrency-controlled HTTP APIs.
|
|
12
|
+
|
|
13
|
+
It is intentionally smaller than a model runtime or distributed serving platform. Bring any
|
|
14
|
+
Python model or pipeline you already use; AIserver handles request validation, task execution,
|
|
15
|
+
job status, progress, lifecycle hooks, and conservative network defaults.
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- Turn typed Python functions into documented HTTP endpoints.
|
|
20
|
+
- Run tasks directly or submit in-memory asynchronous jobs.
|
|
21
|
+
- Limit concurrency per task to protect CPU, GPU, and model memory.
|
|
22
|
+
- Report progress from synchronous or asynchronous inference code.
|
|
23
|
+
- Apply per-task timeouts and bounded job history.
|
|
24
|
+
- Load and release models with startup and shutdown hooks.
|
|
25
|
+
- Protect private endpoints with `AISERVER_TOKEN`.
|
|
26
|
+
- Reject oversized request bodies and bind to localhost by default.
|
|
27
|
+
- Generate OpenAPI documentation automatically at `/docs`.
|
|
28
|
+
- No telemetry, model downloads, protocol proxy, or request-body logging.
|
|
29
|
+
|
|
30
|
+
## Requirements
|
|
31
|
+
|
|
32
|
+
- Python 3.11 or newer
|
|
33
|
+
- Windows, Linux, or macOS
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install AIserver
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Until `0.1.0` is available on PyPI, install the wheel from the GitHub Release or build from source.
|
|
42
|
+
|
|
43
|
+
## Quick start
|
|
44
|
+
|
|
45
|
+
Create `app.py`:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from aiserver import AIServer, TaskContext
|
|
49
|
+
|
|
50
|
+
server = AIServer("demo")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@server.task(concurrency=2, timeout=30)
|
|
54
|
+
def classify(text: str, context: TaskContext) -> dict[str, str]:
|
|
55
|
+
context.report(0.5, "running inference")
|
|
56
|
+
return {"label": text.upper()}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Run it:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
aiserver run app:server
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Open `http://127.0.0.1:8000/docs`, or call it directly:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
curl -X POST http://127.0.0.1:8000/v1/tasks/classify/run \
|
|
69
|
+
-H "Content-Type: application/json" \
|
|
70
|
+
-d '{"text":"hello"}'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Submit the same task as a job:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
curl -X POST http://127.0.0.1:8000/v1/tasks/classify/jobs \
|
|
77
|
+
-H "Content-Type: application/json" \
|
|
78
|
+
-d '{"text":"hello"}'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Poll the returned `status_url` to read progress and the final result.
|
|
82
|
+
|
|
83
|
+
## Lifecycle hooks
|
|
84
|
+
|
|
85
|
+
Keep large model objects in your application module and initialize them once:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
model = None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@server.on_startup
|
|
92
|
+
def load_model():
|
|
93
|
+
global model
|
|
94
|
+
model = load_your_model()
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@server.on_shutdown
|
|
98
|
+
def release_model():
|
|
99
|
+
global model
|
|
100
|
+
model = None
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
AIserver is deliberately single-process so tasks can share an in-memory model. Its asynchronous
|
|
104
|
+
job records are not persistent and are lost when the process restarts.
|
|
105
|
+
|
|
106
|
+
## LAN access
|
|
107
|
+
|
|
108
|
+
The CLI refuses unauthenticated non-loopback binding by default. Set the token in the environment,
|
|
109
|
+
then start the server:
|
|
110
|
+
|
|
111
|
+
```powershell
|
|
112
|
+
$env:AISERVER_TOKEN = "use-a-long-random-value"
|
|
113
|
+
aiserver run app:server --host 0.0.0.0
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Clients can use either header:
|
|
117
|
+
|
|
118
|
+
```text
|
|
119
|
+
Authorization: Bearer <token>
|
|
120
|
+
X-API-Key: <token>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Do not pass tokens on the command line or commit them to source control. Use a reverse proxy with
|
|
124
|
+
TLS before exposing AIserver outside a trusted private network.
|
|
125
|
+
|
|
126
|
+
## Scope
|
|
127
|
+
|
|
128
|
+
AIserver is not an LLM inference engine, OpenAI/Anthropic protocol gateway, model downloader,
|
|
129
|
+
distributed scheduler, or hosted control plane. Projects that need those capabilities should use
|
|
130
|
+
specialized runtimes and platforms.
|
|
131
|
+
|
|
132
|
+
## Historical package notice
|
|
133
|
+
|
|
134
|
+
Version `0.1.0` is a clean rewrite. It does not preserve the unrelated remote-chat and robot demo
|
|
135
|
+
APIs from the historical `0.0.x` releases. Those releases should not be used.
|
|
136
|
+
|
|
137
|
+
## Development
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
python -m venv .venv
|
|
141
|
+
.venv/Scripts/pip install -e ".[dev]"
|
|
142
|
+
ruff check .
|
|
143
|
+
pytest
|
|
144
|
+
python -m build
|
|
145
|
+
python -m twine check dist/*
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
MIT
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
Security fixes are provided for the latest released version.
|
|
6
|
+
|
|
7
|
+
## Reporting a vulnerability
|
|
8
|
+
|
|
9
|
+
Use GitHub private vulnerability reporting for this repository. Do not open a public issue
|
|
10
|
+
containing credentials, private model inputs, or internal network details.
|
|
11
|
+
|
|
12
|
+
## Security defaults
|
|
13
|
+
|
|
14
|
+
- `aiserver run` binds to `127.0.0.1` by default.
|
|
15
|
+
- Non-loopback binding requires `AISERVER_TOKEN` unless the operator explicitly passes
|
|
16
|
+
`--allow-unauthenticated`.
|
|
17
|
+
- Tokens are read from the environment and are not accepted as command-line values.
|
|
18
|
+
- AIserver does not include telemetry or request-body logging.
|
|
19
|
+
- Uploaded or submitted values are never treated as executable code.
|
|
20
|
+
|
|
21
|
+
AIserver is a single-process development and LAN-serving tool. Put it behind a production
|
|
22
|
+
reverse proxy when exposing it beyond a trusted private network.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# AIserver 中文说明
|
|
2
|
+
|
|
3
|
+
AIserver 是一个轻量、本地优先的 Python AI 任务服务器,用于把推理函数快速发布为
|
|
4
|
+
安全、类型明确并支持并发控制的 HTTP API。
|
|
5
|
+
|
|
6
|
+
它不是模型推理引擎或云平台。你可以继续使用 PyTorch、ONNX Runtime、TensorRT、
|
|
7
|
+
OpenCV、Ollama 客户端或任意 Python 代码,AIserver 只负责可靠地对外提供任务接口。
|
|
8
|
+
|
|
9
|
+
## 主要能力
|
|
10
|
+
|
|
11
|
+
- 根据 Python 类型注解自动校验输入并生成 OpenAPI 文档。
|
|
12
|
+
- 同一个任务既可以直接执行,也可以提交为内存异步任务。
|
|
13
|
+
- 为每个任务设置并发数,避免多个请求耗尽显存或内存。
|
|
14
|
+
- 支持进度、状态、结果查询和任务超时。
|
|
15
|
+
- 通过启动和关闭钩子统一加载、释放模型。
|
|
16
|
+
- 默认只监听 `127.0.0.1`。
|
|
17
|
+
- 使用 `AISERVER_TOKEN` 保护局域网接口。
|
|
18
|
+
- 限制请求体大小,不记录请求内容,不包含遥测。
|
|
19
|
+
|
|
20
|
+
## 安装
|
|
21
|
+
|
|
22
|
+
```powershell
|
|
23
|
+
pip install AIserver
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 快速开始
|
|
27
|
+
|
|
28
|
+
新建 `app.py`:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from aiserver import AIServer, TaskContext
|
|
32
|
+
|
|
33
|
+
server = AIServer("demo")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@server.task(concurrency=1, timeout=60)
|
|
37
|
+
def detect(image_path: str, context: TaskContext) -> dict:
|
|
38
|
+
context.report(0.2, "loading image")
|
|
39
|
+
result = model.predict(image_path)
|
|
40
|
+
context.report(0.9, "formatting result")
|
|
41
|
+
return {"detections": result}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
启动:
|
|
45
|
+
|
|
46
|
+
```powershell
|
|
47
|
+
aiserver run app:server
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
然后访问 `http://127.0.0.1:8000/docs`,可以直接在浏览器中调试接口。
|
|
51
|
+
|
|
52
|
+
### 直接执行
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
POST /v1/tasks/detect/run
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
请求会等待任务完成并直接返回结果,适合耗时较短的推理。
|
|
59
|
+
|
|
60
|
+
### 异步任务
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
POST /v1/tasks/detect/jobs
|
|
64
|
+
GET /v1/jobs/{job_id}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
提交接口立即返回任务 ID,随后通过状态接口查询进度和结果,适合长时间推理。
|
|
68
|
+
|
|
69
|
+
## 局域网使用
|
|
70
|
+
|
|
71
|
+
开放到局域网前先设置长随机令牌:
|
|
72
|
+
|
|
73
|
+
```powershell
|
|
74
|
+
$env:AISERVER_TOKEN = "请替换为长随机值"
|
|
75
|
+
aiserver run app:server --host 0.0.0.0
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
客户端通过以下任一种请求头提交令牌:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
Authorization: Bearer <token>
|
|
82
|
+
X-API-Key: <token>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
令牌不要写进源码、命令行参数或公开日志。需要通过互联网访问时,应在前面部署带
|
|
86
|
+
TLS 的反向代理。
|
|
87
|
+
|
|
88
|
+
## 当前边界
|
|
89
|
+
|
|
90
|
+
- 单进程运行,便于多个任务共享同一个内存模型。
|
|
91
|
+
- 异步任务记录只保存在内存,程序重启后不会保留。
|
|
92
|
+
- 超时可以停止等待异步函数,但无法强制终止已经在线程中运行的同步模型代码。
|
|
93
|
+
- 不负责下载模型、转换模型协议、分布式调度或云端管理。
|
|
94
|
+
|
|
95
|
+
## 旧版本说明
|
|
96
|
+
|
|
97
|
+
`0.1.0` 是完全重写版本,不兼容历史 `0.0.x` 中的远程聊天和机器人演示接口。旧版本
|
|
98
|
+
不应继续使用。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Runnable AIserver examples."""
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Run with: aiserver run examples.basic:server"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
from aiserver import AIServer, TaskContext
|
|
8
|
+
|
|
9
|
+
server = AIServer("AIserver example")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@server.task(concurrency=4, timeout=10)
|
|
13
|
+
def add(a: float, b: float) -> dict[str, float]:
|
|
14
|
+
"""Add two numbers."""
|
|
15
|
+
|
|
16
|
+
return {"value": a + b}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@server.task(concurrency=1, timeout=30)
|
|
20
|
+
def simulated_inference(text: str, context: TaskContext) -> dict[str, str]:
|
|
21
|
+
"""Demonstrate a long-running, concurrency-limited inference job."""
|
|
22
|
+
|
|
23
|
+
for step in range(5):
|
|
24
|
+
time.sleep(0.2)
|
|
25
|
+
context.report((step + 1) / 5, f"step {step + 1} of 5")
|
|
26
|
+
return {"output": text.upper()}
|