wavespeed 1.0.13__tar.gz → 2.0.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.
- wavespeed-2.0.0/.github/workflows/tests.yml +39 -0
- wavespeed-2.0.0/CHANGELOG.md +53 -0
- wavespeed-2.0.0/CLAUDE.md +57 -0
- {wavespeed-1.0.13/src/wavespeed.egg-info → wavespeed-2.0.0}/PKG-INFO +2 -143
- {wavespeed-1.0.13 → wavespeed-2.0.0}/README.md +0 -139
- {wavespeed-1.0.13 → wavespeed-2.0.0}/pyproject.toml +1 -3
- {wavespeed-1.0.13 → wavespeed-2.0.0}/src/wavespeed/__init__.py +6 -6
- {wavespeed-1.0.13 → wavespeed-2.0.0}/src/wavespeed/_version.py +1 -1
- {wavespeed-1.0.13 → wavespeed-2.0.0}/src/wavespeed/api/__init__.py +25 -1
- {wavespeed-1.0.13 → wavespeed-2.0.0}/src/wavespeed/api/client.py +20 -0
- wavespeed-2.0.0/src/wavespeed/config.py +42 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0/src/wavespeed.egg-info}/PKG-INFO +2 -143
- wavespeed-2.0.0/src/wavespeed.egg-info/SOURCES.txt +36 -0
- wavespeed-2.0.0/src/wavespeed.egg-info/requires.txt +5 -0
- wavespeed-2.0.0/src/wavespeed.egg-info/scm_file_list.json +31 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/src/wavespeed.egg-info/scm_version.json +2 -2
- {wavespeed-1.0.13 → wavespeed-2.0.0}/tests/test_api.py +27 -0
- wavespeed-2.0.0/tests/test_config.py +62 -0
- wavespeed-1.0.13/.dockerignore +0 -12
- wavespeed-1.0.13/CLAUDE.md +0 -86
- wavespeed-1.0.13/images/build_and_push.sh +0 -113
- wavespeed-1.0.13/images/test_worker/Dockerfile +0 -32
- wavespeed-1.0.13/images/test_worker/build_and_test.sh +0 -18
- wavespeed-1.0.13/images/test_worker/handler.py +0 -101
- wavespeed-1.0.13/images/test_worker/requirements.txt +0 -1
- wavespeed-1.0.13/images/test_worker/test_input.json +0 -8
- wavespeed-1.0.13/src/wavespeed/config.py +0 -274
- wavespeed-1.0.13/src/wavespeed/serverless/__init__.py +0 -176
- wavespeed-1.0.13/src/wavespeed/serverless/modules/__init__.py +0 -54
- wavespeed-1.0.13/src/wavespeed/serverless/modules/fastapi.py +0 -450
- wavespeed-1.0.13/src/wavespeed/serverless/modules/handler.py +0 -74
- wavespeed-1.0.13/src/wavespeed/serverless/modules/health.py +0 -61
- wavespeed-1.0.13/src/wavespeed/serverless/modules/heartbeat.py +0 -140
- wavespeed-1.0.13/src/wavespeed/serverless/modules/http.py +0 -247
- wavespeed-1.0.13/src/wavespeed/serverless/modules/job.py +0 -236
- wavespeed-1.0.13/src/wavespeed/serverless/modules/local.py +0 -147
- wavespeed-1.0.13/src/wavespeed/serverless/modules/logger.py +0 -205
- wavespeed-1.0.13/src/wavespeed/serverless/modules/progress.py +0 -141
- wavespeed-1.0.13/src/wavespeed/serverless/modules/scaler.py +0 -266
- wavespeed-1.0.13/src/wavespeed/serverless/modules/state.py +0 -185
- wavespeed-1.0.13/src/wavespeed/serverless/utils/__init__.py +0 -23
- wavespeed-1.0.13/src/wavespeed/serverless/utils/boto3_utils.py +0 -365
- wavespeed-1.0.13/src/wavespeed/serverless/utils/validator.py +0 -173
- wavespeed-1.0.13/src/wavespeed/serverless/worker.py +0 -74
- wavespeed-1.0.13/src/wavespeed.egg-info/SOURCES.txt +0 -72
- wavespeed-1.0.13/src/wavespeed.egg-info/requires.txt +0 -7
- wavespeed-1.0.13/src/wavespeed.egg-info/scm_file_list.json +0 -67
- wavespeed-1.0.13/tests/test_config.py +0 -82
- wavespeed-1.0.13/tests/test_serverless/__init__.py +0 -1
- wavespeed-1.0.13/tests/test_serverless/test_modules/__init__.py +0 -1
- wavespeed-1.0.13/tests/test_serverless/test_modules/test_fastapi.py +0 -449
- wavespeed-1.0.13/tests/test_serverless/test_modules/test_handler.py +0 -195
- wavespeed-1.0.13/tests/test_serverless/test_modules/test_http.py +0 -320
- wavespeed-1.0.13/tests/test_serverless/test_modules/test_job.py +0 -394
- wavespeed-1.0.13/tests/test_serverless/test_modules/test_local.py +0 -246
- wavespeed-1.0.13/tests/test_serverless/test_modules/test_logger.py +0 -216
- wavespeed-1.0.13/tests/test_serverless/test_modules/test_progress.py +0 -181
- wavespeed-1.0.13/tests/test_serverless/test_modules/test_scaler.py +0 -239
- wavespeed-1.0.13/tests/test_serverless/test_modules/test_state.py +0 -222
- wavespeed-1.0.13/tests/test_serverless/test_utils/__init__.py +0 -1
- wavespeed-1.0.13/tests/test_serverless/test_utils/test_validator.py +0 -282
- wavespeed-1.0.13/tests/test_serverless/test_worker.py +0 -175
- {wavespeed-1.0.13 → wavespeed-2.0.0}/.github/workflows/claude.yml +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/.github/workflows/pre-commit.yml +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/.github/workflows/python-packages.yml +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/.github/workflows/python-publish.yml +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/.gitignore +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/.pre-commit-config.yaml +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/LICENSE +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/MANIFEST.in +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/VERSIONING.md +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/assets/wavespeed-logo-dark.svg +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/assets/wavespeed-logo-light.svg +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/pytest.ini +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/setup.cfg +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/src/wavespeed/_config_module.py +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/src/wavespeed.egg-info/dependency_links.txt +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/src/wavespeed.egg-info/not-zip-safe +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/src/wavespeed.egg-info/top_level.txt +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/tests/__init__.py +0 -0
- {wavespeed-1.0.13 → wavespeed-2.0.0}/tests/conftest.py +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
push:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
tags:
|
|
11
|
+
- "v[0-9]+*"
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
# The package advertises Python >=3.8, so every advertised version is tested.
|
|
19
|
+
# PEP 604 syntax is only legal at runtime on 3.10+, which is why the modules
|
|
20
|
+
# carrying annotations import `from __future__ import annotations`; this
|
|
21
|
+
# matrix is what keeps that from silently regressing.
|
|
22
|
+
test:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
strategy:
|
|
25
|
+
fail-fast: false
|
|
26
|
+
matrix:
|
|
27
|
+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
|
30
|
+
with:
|
|
31
|
+
fetch-depth: 0
|
|
32
|
+
persist-credentials: false
|
|
33
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
34
|
+
with:
|
|
35
|
+
python-version: ${{ matrix.python-version }}
|
|
36
|
+
- run: python -m pip install --upgrade pip
|
|
37
|
+
- run: pip install -e . pytest
|
|
38
|
+
- run: python -c "import wavespeed; print(wavespeed.__version__)"
|
|
39
|
+
- run: python -m pytest -q
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
|
|
5
|
+
Versions are derived from Git tags via `setuptools_scm` — see [VERSIONING.md](VERSIONING.md).
|
|
6
|
+
|
|
7
|
+
## 2.0.0
|
|
8
|
+
|
|
9
|
+
### Removed — BREAKING
|
|
10
|
+
|
|
11
|
+
**The serverless worker implementation has been removed from the SDK.**
|
|
12
|
+
|
|
13
|
+
WaveSpeed no longer offers serverless as an external product, so shipping a serverless worker in
|
|
14
|
+
the public SDK was misleading: it advertised a capability customers cannot buy. Everything below is
|
|
15
|
+
gone as of 2.0.0 and will not be restored.
|
|
16
|
+
|
|
17
|
+
- `wavespeed.serverless` — the entire package, including `serverless.start()`, the job scaler, the
|
|
18
|
+
handler-type dispatcher, the worker HTTP layer, the FastAPI local dev server, local test mode,
|
|
19
|
+
worker/job state tracking, heartbeat and progress reporting, the S3 (`boto3`) upload helpers, and
|
|
20
|
+
`wavespeed.serverless.utils.validate`.
|
|
21
|
+
- `wavespeed.config.serverless` — the serverless config namespace and its import-time environment
|
|
22
|
+
auto-detection (`RUNPOD_*` and `WAVERLESS_*` variables are no longer read by this package).
|
|
23
|
+
- `images/` — the `test_worker` Docker image and its build/push scripts, which existed only to
|
|
24
|
+
build and exercise the worker.
|
|
25
|
+
|
|
26
|
+
Anyone building workers against this package should pin `wavespeed<2` and plan to migrate.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- **Python 3.8 and 3.9 support is now real rather than aspirational.** `api/__init__.py` carried a
|
|
31
|
+
module-level PEP 604 annotation (`Client | None`) with no `__future__` import, so the package
|
|
32
|
+
could not be imported on 3.8 or 3.9 despite `requires-python = ">=3.8"`. CI now runs the suite on
|
|
33
|
+
3.8 through 3.12 so the claim stays honest.
|
|
34
|
+
- `typing_extensions` is now a declared dependency. It was imported at module scope but only
|
|
35
|
+
reached the environment transitively through `boto3`/`aiohttp` — removing those would have
|
|
36
|
+
produced an `ImportError` on a clean install.
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- Dependencies trimmed to what the API client actually needs. `aiohttp`, `aiohttp[speedups]`,
|
|
41
|
+
`aiohttp-retry`, and `boto3` are no longer installed; `typing_extensions` is now declared
|
|
42
|
+
explicitly (it was already imported by `wavespeed._config_module`).
|
|
43
|
+
- README and CLAUDE.md rewritten to describe an API-client-only SDK.
|
|
44
|
+
|
|
45
|
+
### Unchanged
|
|
46
|
+
|
|
47
|
+
The API client surface is untouched: `wavespeed.run`, `wavespeed.run_no_throw`,
|
|
48
|
+
`wavespeed.get_result`, `wavespeed.upload`, `wavespeed.Client`, `wavespeed.config.api`, and the
|
|
49
|
+
channel-attribution request headers all behave exactly as they did in 1.0.x.
|
|
50
|
+
|
|
51
|
+
## 1.0.14 and earlier
|
|
52
|
+
|
|
53
|
+
See the Git history and GitHub releases.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
WaveSpeed Python SDK - Official Python SDK for the WaveSpeedAI inference platform. It is an API
|
|
8
|
+
client only: it submits jobs to the hosted WaveSpeed API, polls for results, and uploads files.
|
|
9
|
+
|
|
10
|
+
> As of v2.0.0 the SDK no longer ships a serverless worker implementation. WaveSpeed does not offer
|
|
11
|
+
> serverless as an external product, so that code was removed rather than left in the public SDK.
|
|
12
|
+
|
|
13
|
+
## Commands
|
|
14
|
+
|
|
15
|
+
### Testing
|
|
16
|
+
```bash
|
|
17
|
+
# Run all tests
|
|
18
|
+
python -m pytest
|
|
19
|
+
|
|
20
|
+
# Run a single test file
|
|
21
|
+
python -m pytest tests/test_api.py
|
|
22
|
+
|
|
23
|
+
# Run a specific test
|
|
24
|
+
python -m pytest tests/test_api.py::TestClient::test_run_success -v
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Linting
|
|
28
|
+
```bash
|
|
29
|
+
pre-commit run --all-files
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Local Development
|
|
33
|
+
```bash
|
|
34
|
+
# Install in editable mode
|
|
35
|
+
pip install -e .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Architecture
|
|
39
|
+
|
|
40
|
+
### API client (`src/wavespeed/api/`)
|
|
41
|
+
|
|
42
|
+
- `client.py` - `Client`, the only transport. Synchronous, built on `requests`. Handles job
|
|
43
|
+
submission, result polling, terminal-status handling, file upload, and the channel-attribution
|
|
44
|
+
headers (`X-Client-Name`, etc.).
|
|
45
|
+
- `__init__.py` - module-level convenience wrappers over a lazily created default `Client`:
|
|
46
|
+
`run`, `run_no_throw`, `get_result`, `upload`.
|
|
47
|
+
|
|
48
|
+
`run` raises on failure; `run_no_throw` returns `{"status", "outputs", "task_id", "error"}` instead,
|
|
49
|
+
mirroring the JavaScript SDK. `get_result` recovers a task whose local wait timed out.
|
|
50
|
+
|
|
51
|
+
### Configuration (`src/wavespeed/config.py`)
|
|
52
|
+
|
|
53
|
+
A single `api` config class, installed as a config module by `_config_module.py` (the PyTorch-style
|
|
54
|
+
`install_config_module` shim). This gives `wavespeed.config.patch(...)` as a context manager /
|
|
55
|
+
decorator for tests. `Client` reads its defaults from `wavespeed.config.api`.
|
|
56
|
+
|
|
57
|
+
`WAVESPEED_API_KEY` seeds `config.api.api_key` at import time.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wavespeed
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: WaveSpeed Python Client — Official Python SDK for the WaveSpeed inference platform
|
|
5
5
|
Author-email: WaveSpeedAI <support@wavespeed.ai>
|
|
6
6
|
License: MIT
|
|
@@ -19,10 +19,8 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
19
19
|
Requires-Python: >=3.8
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: aiohttp[speedups]>=3.9.3
|
|
23
|
-
Requires-Dist: aiohttp-retry>=2.8.3
|
|
24
22
|
Requires-Dist: requests>=2.25.0
|
|
25
|
-
Requires-Dist:
|
|
23
|
+
Requires-Dist: typing_extensions>=4.5.0
|
|
26
24
|
Provides-Extra: test
|
|
27
25
|
Requires-Dist: pytest; extra == "test"
|
|
28
26
|
Dynamic: license-file
|
|
@@ -142,106 +140,8 @@ url = wavespeed.upload("/path/to/image.png")
|
|
|
142
140
|
print(url)
|
|
143
141
|
```
|
|
144
142
|
|
|
145
|
-
## Serverless Worker
|
|
146
|
-
|
|
147
|
-
Build serverless workers for the WaveSpeed platform.
|
|
148
|
-
|
|
149
|
-
### Basic Handler
|
|
150
|
-
|
|
151
|
-
```python
|
|
152
|
-
import wavespeed.serverless as serverless
|
|
153
|
-
|
|
154
|
-
def handler(job):
|
|
155
|
-
job_input = job["input"]
|
|
156
|
-
result = job_input.get("prompt", "").upper()
|
|
157
|
-
return {"output": result}
|
|
158
|
-
|
|
159
|
-
serverless.start({"handler": handler})
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### Async Handler
|
|
163
|
-
|
|
164
|
-
```python
|
|
165
|
-
import wavespeed.serverless as serverless
|
|
166
|
-
|
|
167
|
-
async def handler(job):
|
|
168
|
-
job_input = job["input"]
|
|
169
|
-
result = await process_async(job_input)
|
|
170
|
-
return {"output": result}
|
|
171
|
-
|
|
172
|
-
serverless.start({"handler": handler})
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### Generator Handler (Streaming)
|
|
176
|
-
|
|
177
|
-
```python
|
|
178
|
-
import wavespeed.serverless as serverless
|
|
179
|
-
|
|
180
|
-
def handler(job):
|
|
181
|
-
for i in range(10):
|
|
182
|
-
yield {"progress": i, "partial": f"chunk-{i}"}
|
|
183
|
-
|
|
184
|
-
serverless.start({"handler": handler})
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### Input Validation
|
|
188
|
-
|
|
189
|
-
```python
|
|
190
|
-
from wavespeed.serverless.utils import validate
|
|
191
|
-
|
|
192
|
-
INPUT_SCHEMA = {
|
|
193
|
-
"prompt": {"type": str, "required": True},
|
|
194
|
-
"max_tokens": {"type": int, "required": False, "default": 100},
|
|
195
|
-
"temperature": {
|
|
196
|
-
"type": float,
|
|
197
|
-
"required": False,
|
|
198
|
-
"default": 0.7,
|
|
199
|
-
"constraints": lambda x: 0 <= x <= 2,
|
|
200
|
-
},
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
def handler(job):
|
|
204
|
-
result = validate(job["input"], INPUT_SCHEMA)
|
|
205
|
-
if "errors" in result:
|
|
206
|
-
return {"error": result["errors"]}
|
|
207
|
-
|
|
208
|
-
validated = result["validated_input"]
|
|
209
|
-
# process with validated input...
|
|
210
|
-
return {"output": "done"}
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
### Concurrent Execution
|
|
214
|
-
|
|
215
|
-
Enable concurrent job processing with `concurrency_modifier`:
|
|
216
|
-
|
|
217
|
-
```python
|
|
218
|
-
import wavespeed.serverless as serverless
|
|
219
|
-
|
|
220
|
-
def handler(job):
|
|
221
|
-
return {"output": job["input"]["data"]}
|
|
222
|
-
|
|
223
|
-
def concurrency_modifier(current_concurrency):
|
|
224
|
-
return 2 # Process 2 jobs concurrently
|
|
225
|
-
|
|
226
|
-
serverless.start({
|
|
227
|
-
"handler": handler,
|
|
228
|
-
"concurrency_modifier": concurrency_modifier
|
|
229
|
-
})
|
|
230
|
-
```
|
|
231
|
-
|
|
232
143
|
## Local Development
|
|
233
144
|
|
|
234
|
-
### Test with JSON Input
|
|
235
|
-
|
|
236
|
-
```bash
|
|
237
|
-
# Using CLI argument
|
|
238
|
-
python handler.py --test_input '{"input": {"prompt": "hello"}}'
|
|
239
|
-
|
|
240
|
-
# Using test_input.json file (auto-detected)
|
|
241
|
-
echo '{"input": {"prompt": "hello"}}' > test_input.json
|
|
242
|
-
python handler.py
|
|
243
|
-
```
|
|
244
|
-
|
|
245
145
|
### Running Tests
|
|
246
146
|
|
|
247
147
|
```bash
|
|
@@ -255,54 +155,13 @@ python -m pytest tests/test_api.py
|
|
|
255
155
|
python -m pytest tests/test_api.py::TestClient::test_run_success -v
|
|
256
156
|
```
|
|
257
157
|
|
|
258
|
-
### FastAPI Development Server
|
|
259
|
-
|
|
260
|
-
```bash
|
|
261
|
-
python handler.py --waverless_serve_api --waverless_api_port 8000
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
Then use the interactive Swagger UI at `http://localhost:8000/` or make requests:
|
|
265
|
-
|
|
266
|
-
```bash
|
|
267
|
-
# Synchronous execution
|
|
268
|
-
curl -X POST http://localhost:8000/runsync \
|
|
269
|
-
-H "Content-Type: application/json" \
|
|
270
|
-
-d '{"input": {"prompt": "hello"}}'
|
|
271
|
-
|
|
272
|
-
# Async execution
|
|
273
|
-
curl -X POST http://localhost:8000/run \
|
|
274
|
-
-H "Content-Type: application/json" \
|
|
275
|
-
-d '{"input": {"prompt": "hello"}}'
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
## CLI Options
|
|
279
|
-
|
|
280
|
-
| Option | Description |
|
|
281
|
-
|--------|-------------|
|
|
282
|
-
| `--test_input JSON` | Run locally with JSON test input |
|
|
283
|
-
| `--waverless_serve_api` | Start FastAPI development server |
|
|
284
|
-
| `--waverless_api_host HOST` | API server host (default: localhost) |
|
|
285
|
-
| `--waverless_api_port PORT` | API server port (default: 8000) |
|
|
286
|
-
| `--waverless_log_level LEVEL` | Log level (DEBUG, INFO, WARN, ERROR) |
|
|
287
|
-
|
|
288
158
|
## Environment Variables
|
|
289
159
|
|
|
290
|
-
### API Client
|
|
291
|
-
|
|
292
160
|
| Variable | Description |
|
|
293
161
|
|----------|-------------|
|
|
294
162
|
| `WAVESPEED_API_KEY` | WaveSpeed API key |
|
|
295
163
|
| `WAVESPEED_CLIENT_NAME` | Channel-attribution name sent as the `X-Client-Name` header (overrides the `client_name` parameter; defaults to `wavespeed-python`) |
|
|
296
164
|
|
|
297
|
-
### Serverless Worker
|
|
298
|
-
|
|
299
|
-
| Variable | Description |
|
|
300
|
-
|----------|-------------|
|
|
301
|
-
| `WAVERLESS_POD_ID` | Worker/pod identifier |
|
|
302
|
-
| `WAVERLESS_API_KEY` | API authentication key |
|
|
303
|
-
| `WAVERLESS_WEBHOOK_GET_JOB` | Job fetch endpoint |
|
|
304
|
-
| `WAVERLESS_WEBHOOK_POST_OUTPUT` | Result submission endpoint |
|
|
305
|
-
|
|
306
165
|
## License
|
|
307
166
|
|
|
308
167
|
MIT
|
|
@@ -113,106 +113,8 @@ url = wavespeed.upload("/path/to/image.png")
|
|
|
113
113
|
print(url)
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
-
## Serverless Worker
|
|
117
|
-
|
|
118
|
-
Build serverless workers for the WaveSpeed platform.
|
|
119
|
-
|
|
120
|
-
### Basic Handler
|
|
121
|
-
|
|
122
|
-
```python
|
|
123
|
-
import wavespeed.serverless as serverless
|
|
124
|
-
|
|
125
|
-
def handler(job):
|
|
126
|
-
job_input = job["input"]
|
|
127
|
-
result = job_input.get("prompt", "").upper()
|
|
128
|
-
return {"output": result}
|
|
129
|
-
|
|
130
|
-
serverless.start({"handler": handler})
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### Async Handler
|
|
134
|
-
|
|
135
|
-
```python
|
|
136
|
-
import wavespeed.serverless as serverless
|
|
137
|
-
|
|
138
|
-
async def handler(job):
|
|
139
|
-
job_input = job["input"]
|
|
140
|
-
result = await process_async(job_input)
|
|
141
|
-
return {"output": result}
|
|
142
|
-
|
|
143
|
-
serverless.start({"handler": handler})
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### Generator Handler (Streaming)
|
|
147
|
-
|
|
148
|
-
```python
|
|
149
|
-
import wavespeed.serverless as serverless
|
|
150
|
-
|
|
151
|
-
def handler(job):
|
|
152
|
-
for i in range(10):
|
|
153
|
-
yield {"progress": i, "partial": f"chunk-{i}"}
|
|
154
|
-
|
|
155
|
-
serverless.start({"handler": handler})
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### Input Validation
|
|
159
|
-
|
|
160
|
-
```python
|
|
161
|
-
from wavespeed.serverless.utils import validate
|
|
162
|
-
|
|
163
|
-
INPUT_SCHEMA = {
|
|
164
|
-
"prompt": {"type": str, "required": True},
|
|
165
|
-
"max_tokens": {"type": int, "required": False, "default": 100},
|
|
166
|
-
"temperature": {
|
|
167
|
-
"type": float,
|
|
168
|
-
"required": False,
|
|
169
|
-
"default": 0.7,
|
|
170
|
-
"constraints": lambda x: 0 <= x <= 2,
|
|
171
|
-
},
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
def handler(job):
|
|
175
|
-
result = validate(job["input"], INPUT_SCHEMA)
|
|
176
|
-
if "errors" in result:
|
|
177
|
-
return {"error": result["errors"]}
|
|
178
|
-
|
|
179
|
-
validated = result["validated_input"]
|
|
180
|
-
# process with validated input...
|
|
181
|
-
return {"output": "done"}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### Concurrent Execution
|
|
185
|
-
|
|
186
|
-
Enable concurrent job processing with `concurrency_modifier`:
|
|
187
|
-
|
|
188
|
-
```python
|
|
189
|
-
import wavespeed.serverless as serverless
|
|
190
|
-
|
|
191
|
-
def handler(job):
|
|
192
|
-
return {"output": job["input"]["data"]}
|
|
193
|
-
|
|
194
|
-
def concurrency_modifier(current_concurrency):
|
|
195
|
-
return 2 # Process 2 jobs concurrently
|
|
196
|
-
|
|
197
|
-
serverless.start({
|
|
198
|
-
"handler": handler,
|
|
199
|
-
"concurrency_modifier": concurrency_modifier
|
|
200
|
-
})
|
|
201
|
-
```
|
|
202
|
-
|
|
203
116
|
## Local Development
|
|
204
117
|
|
|
205
|
-
### Test with JSON Input
|
|
206
|
-
|
|
207
|
-
```bash
|
|
208
|
-
# Using CLI argument
|
|
209
|
-
python handler.py --test_input '{"input": {"prompt": "hello"}}'
|
|
210
|
-
|
|
211
|
-
# Using test_input.json file (auto-detected)
|
|
212
|
-
echo '{"input": {"prompt": "hello"}}' > test_input.json
|
|
213
|
-
python handler.py
|
|
214
|
-
```
|
|
215
|
-
|
|
216
118
|
### Running Tests
|
|
217
119
|
|
|
218
120
|
```bash
|
|
@@ -226,54 +128,13 @@ python -m pytest tests/test_api.py
|
|
|
226
128
|
python -m pytest tests/test_api.py::TestClient::test_run_success -v
|
|
227
129
|
```
|
|
228
130
|
|
|
229
|
-
### FastAPI Development Server
|
|
230
|
-
|
|
231
|
-
```bash
|
|
232
|
-
python handler.py --waverless_serve_api --waverless_api_port 8000
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
Then use the interactive Swagger UI at `http://localhost:8000/` or make requests:
|
|
236
|
-
|
|
237
|
-
```bash
|
|
238
|
-
# Synchronous execution
|
|
239
|
-
curl -X POST http://localhost:8000/runsync \
|
|
240
|
-
-H "Content-Type: application/json" \
|
|
241
|
-
-d '{"input": {"prompt": "hello"}}'
|
|
242
|
-
|
|
243
|
-
# Async execution
|
|
244
|
-
curl -X POST http://localhost:8000/run \
|
|
245
|
-
-H "Content-Type: application/json" \
|
|
246
|
-
-d '{"input": {"prompt": "hello"}}'
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
## CLI Options
|
|
250
|
-
|
|
251
|
-
| Option | Description |
|
|
252
|
-
|--------|-------------|
|
|
253
|
-
| `--test_input JSON` | Run locally with JSON test input |
|
|
254
|
-
| `--waverless_serve_api` | Start FastAPI development server |
|
|
255
|
-
| `--waverless_api_host HOST` | API server host (default: localhost) |
|
|
256
|
-
| `--waverless_api_port PORT` | API server port (default: 8000) |
|
|
257
|
-
| `--waverless_log_level LEVEL` | Log level (DEBUG, INFO, WARN, ERROR) |
|
|
258
|
-
|
|
259
131
|
## Environment Variables
|
|
260
132
|
|
|
261
|
-
### API Client
|
|
262
|
-
|
|
263
133
|
| Variable | Description |
|
|
264
134
|
|----------|-------------|
|
|
265
135
|
| `WAVESPEED_API_KEY` | WaveSpeed API key |
|
|
266
136
|
| `WAVESPEED_CLIENT_NAME` | Channel-attribution name sent as the `X-Client-Name` header (overrides the `client_name` parameter; defaults to `wavespeed-python`) |
|
|
267
137
|
|
|
268
|
-
### Serverless Worker
|
|
269
|
-
|
|
270
|
-
| Variable | Description |
|
|
271
|
-
|----------|-------------|
|
|
272
|
-
| `WAVERLESS_POD_ID` | Worker/pod identifier |
|
|
273
|
-
| `WAVERLESS_API_KEY` | API authentication key |
|
|
274
|
-
| `WAVERLESS_WEBHOOK_GET_JOB` | Job fetch endpoint |
|
|
275
|
-
| `WAVERLESS_WEBHOOK_POST_OUTPUT` | Result submission endpoint |
|
|
276
|
-
|
|
277
138
|
## License
|
|
278
139
|
|
|
279
140
|
MIT
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""
|
|
2
2
|
WaveSpeedAI Python Client — Official Python SDK for WaveSpeedAI inference platform.
|
|
3
3
|
|
|
4
|
-
This library provides a clean, unified, and high-performance API
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
This library provides a clean, unified, and high-performance API client for
|
|
5
|
+
your applications. Effortlessly connect to all WaveSpeedAI models and
|
|
6
|
+
inference services with zero infrastructure overhead.
|
|
7
7
|
|
|
8
8
|
Example usage:
|
|
9
9
|
import wavespeed
|
|
@@ -21,10 +21,10 @@ except ImportError:
|
|
|
21
21
|
# Version file doesn't exist yet (e.g., during initial development)
|
|
22
22
|
__version__ = "0.0.0.dev0"
|
|
23
23
|
|
|
24
|
-
# Import config
|
|
24
|
+
# Import config so `wavespeed.config` is available after `import wavespeed`
|
|
25
25
|
from wavespeed import config # noqa: F401
|
|
26
26
|
|
|
27
27
|
# Import API client
|
|
28
|
-
from wavespeed.api import Client, run, run_no_throw, upload
|
|
28
|
+
from wavespeed.api import Client, get_result, run, run_no_throw, upload
|
|
29
29
|
|
|
30
|
-
__all__ = ["__version__", "Client", "run", "run_no_throw", "upload"]
|
|
30
|
+
__all__ = ["__version__", "Client", "get_result", "run", "run_no_throw", "upload"]
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# This file is automatically generated by setuptools_scm
|
|
2
|
-
__version__ = "
|
|
2
|
+
__version__ = "2.0.0"
|
|
@@ -17,11 +17,13 @@ Example usage:
|
|
|
17
17
|
print(url) # URL of the uploaded file
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
20
22
|
from typing import BinaryIO
|
|
21
23
|
|
|
22
24
|
from wavespeed.api.client import Client
|
|
23
25
|
|
|
24
|
-
__all__ = ["Client", "run", "run_no_throw", "upload"]
|
|
26
|
+
__all__ = ["Client", "get_result", "run", "run_no_throw", "upload"]
|
|
25
27
|
|
|
26
28
|
# Default client instance
|
|
27
29
|
_default_client: Client | None = None
|
|
@@ -96,6 +98,28 @@ def run(
|
|
|
96
98
|
)
|
|
97
99
|
|
|
98
100
|
|
|
101
|
+
def get_result(
|
|
102
|
+
request_id: str,
|
|
103
|
+
*,
|
|
104
|
+
timeout: float | None = None,
|
|
105
|
+
api_key: str | None = None,
|
|
106
|
+
) -> dict:
|
|
107
|
+
"""Fetch a prediction's current state by id.
|
|
108
|
+
|
|
109
|
+
Recovers a task whose local wait timed out — it keeps running server-side.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
request_id: The prediction request ID.
|
|
113
|
+
timeout: Request timeout in seconds.
|
|
114
|
+
api_key: Override the API key for this call.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Full API response, including ``data.status`` and ``data.outputs``.
|
|
118
|
+
"""
|
|
119
|
+
client = Client(api_key=api_key) if api_key else _get_default_client()
|
|
120
|
+
return client.get_result(request_id, timeout=timeout)
|
|
121
|
+
|
|
122
|
+
|
|
99
123
|
def run_no_throw(
|
|
100
124
|
model: str,
|
|
101
125
|
input: dict | None = None,
|
|
@@ -195,6 +195,26 @@ class Client:
|
|
|
195
195
|
|
|
196
196
|
return request_id, None
|
|
197
197
|
|
|
198
|
+
def get_result(
|
|
199
|
+
self, request_id: str, timeout: float | None = None
|
|
200
|
+
) -> dict[str, Any]:
|
|
201
|
+
"""Fetch a prediction's current state by id.
|
|
202
|
+
|
|
203
|
+
Useful for recovering a task whose local wait timed out: the task keeps
|
|
204
|
+
running server-side, and this returns whatever state it has reached.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
request_id: The prediction request ID.
|
|
208
|
+
timeout: Request timeout in seconds.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Full API response, including ``data.status`` and ``data.outputs``.
|
|
212
|
+
|
|
213
|
+
Raises:
|
|
214
|
+
RuntimeError: If fetching the result fails after retries.
|
|
215
|
+
"""
|
|
216
|
+
return self._get_result(request_id, timeout=timeout)
|
|
217
|
+
|
|
198
218
|
def _get_result(
|
|
199
219
|
self, request_id: str, timeout: float | None = None
|
|
200
220
|
) -> dict[str, Any]:
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Configuration module for WaveSpeed SDK."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from ._config_module import install_config_module
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
_save_config_ignore = {
|
|
11
|
+
# workaround: "Can't pickle <function ...>"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class api:
|
|
16
|
+
"""API client configuration options."""
|
|
17
|
+
|
|
18
|
+
# Authentication
|
|
19
|
+
api_key: Optional[str] = os.environ.get("WAVESPEED_API_KEY")
|
|
20
|
+
|
|
21
|
+
# API base URL
|
|
22
|
+
base_url: str = "https://api.wavespeed.ai"
|
|
23
|
+
|
|
24
|
+
# Connection timeout in seconds
|
|
25
|
+
connection_timeout: float = 10.0
|
|
26
|
+
|
|
27
|
+
# Total API call timeout in seconds
|
|
28
|
+
timeout: float = 36000.0
|
|
29
|
+
|
|
30
|
+
# Maximum number of retries for the entire operation (task-level retries)
|
|
31
|
+
max_retries: int = 0
|
|
32
|
+
|
|
33
|
+
# Maximum retries for idempotent result-query GET requests. Submission
|
|
34
|
+
# POSTs are intentionally sent at most once.
|
|
35
|
+
max_connection_retries: int = 5
|
|
36
|
+
|
|
37
|
+
# Base interval between retries in seconds (actual delay = retry_interval * attempt)
|
|
38
|
+
retry_interval: float = 1.0
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# adds patch, save_config, etc
|
|
42
|
+
install_config_module(sys.modules[__name__])
|