fish-edge-gateway-sdk (Python)
接入 apex-edge-gateway 的服务侧 SDK:manifest 声明与暴露、internal auth、trace 透传。协议契约见仓库 docs/contracts/。
安装(不发布 PyPI,直接 git 依赖)
# requirements.txt / pyproject dependency(锁 tag 或 commit,不要追 main)
fish-edge-gateway-sdk @ git+ssh://git@github.com/fishaudio/apex-edge-gateway.git@<tag-or-sha>#subdirectory=sdk-python
# 本地开发
pip install "fish-edge-gateway-sdk @ git+ssh://git@github.com/fishaudio/apex-edge-gateway.git@main#subdirectory=sdk-python"
# uv
uv add "fish-edge-gateway-sdk @ git+ssh://git@github.com/fishaudio/apex-edge-gateway.git@main#subdirectory=sdk-python"
# CI / Docker(https + token,避免挂 ssh key)
pip install "fish-edge-gateway-sdk @ git+https://${GITHUB_TOKEN}@github.com/fishaudio/apex-edge-gateway.git@<sha>#subdirectory=sdk-python"
版本锁定约定:SDK 变更打 sdk-python/vX.Y.Z 形式的 git tag,服务锁 tag 升级;紧急验证可锁 commit sha。
集成
from fastapi import Depends, FastAPI
from fish_edge_gateway_sdk import edge_route, mount_edge, require_gateway
app = FastAPI()
@app.post("/internal/asr", dependencies=[Depends(require_gateway)])
@edge_route(auth="internal")
async def asr(payload: dict) -> dict: ...
mount_edge(app, service="omni-asr") # 挂载 GET /.edge/manifest
功能门禁(manifest 契约 §9B,仅 auth="api_key"):调用方 team 不具备要求的 feature 时,gateway 直接回 403 feature_required,请求不会下落到其它路由,handler 无需再判断。feature 名不超过 64 个字符,每条路由合计不超过 4096 个。带门禁的 manifest 自动声明 schema_version: 2:先升级 gateway 再发布(旧 gateway 会拒绝 v2 manifest,而不是不设门禁地服务它)。
@app.post("/v1/tts-pro")
@edge_route(auth="api_key", protocol="bytes",
requires_features=["tts-pro"], # 全部需要
requires_any_of=[["voice-clone", "enterprise"]]) # 每组至少一个
async def tts_pro(...): ...
上报用量(Usage 与计费维度)
用量随响应走,gateway 读取后剥离,客户端不可见。Usage 是一个计费对象:tokens 加计费维度(如 model_id)。model_id 永远是一个字符串;归属多个模型 = 多个对象。所有 helper 都接受 int | Usage | Sequence[Usage]。
from fish_edge_gateway_sdk import Usage, usage_header, usage_json_field, usage_event, usage_reserve_event
usage_header(120) # {"x-fish-usage-tokens": "120"}(无维度:与 0.2 字节一致)
usage_header([Usage(70).model_id("voice-alice"), Usage(50).model_id("voice-bob")])
# {"x-fish-usage": '[{"model_id":"voice-alice","tokens":70},{"model_id":"voice-bob","tokens":50}]'}
usage_json_field(Usage(120).model_id("voice-alice")) # {"x-fish-usage": {"tokens": 120, "model_id": "voice-alice"}}
usage_event(usage=Usage(70).model_id("voice-alice"), seq=1, trace_id=tid)
# {"event": "x-fish-usage", "tokens": 70, "model_id": "voice-alice", "seq": 1, "idempotency_key": ...}
usage_event(usage=objs, seq=2, trace_id=tid) # 多个对象:{"event": ..., "usage": [...], "seq": 2, ...}
usage_reserve_event(objs) # WS 预留,整组替换上一个预留
usage_sse_event(objs) # SSE 终结事件:同上平铺/数组规则,无 seq;空序列 = tokens 0
- 一个对象:字段与
event/seq平铺;多个:放在usage数组里。usage_final_event的total_tokens是所有事件所有对象的 Σ tokens,count是 usage 事件数。 - 维度 key 匹配
^[a-z][a-z0-9_]{0,31}$,且不能是保留字段(eventseqtotal_tokenscountusagetrace_idtokensidempotency_keyquantitydeveloper_id);值只能是整数 / 字符串 / 布尔(不支持浮点)。违反时Usage(...)/with_dim/model_id抛ValueError。Usage不可变且可哈希。 - 空序列上报 tokens 0:这是显式的免费上报,不是缺失。
usage_header/usage_json_field也接受tokens=n关键字(与usage二选一)。 x-fish-usageheader 与数组形态需要支持它们的 gateway;不带维度的调用(usage_header(n)、usage_event(tokens=n, ...))线上字节不变。
k8s Service 侧标注(manifest 契约 §2.1):
metadata:
annotations:
fish.audio/edge-discovery: enable
# 可选:manifest 端点与业务端口分离时
# fish.audio/edge-discovery-port: "9090"
# fish.audio/edge-discovery-url: /.edge/manifest
gateway 侧无需额外授权:发现 namespace 的成员资格就是信任边界(manifest 契约 §11),被发现的 manifest 其 route 直接编译。
形态按 Accept 协商的端点(protocol="negotiated")
一个端点这次回 SSE、下次回裸音频或 JSON 时声明 protocol="negotiated",gateway 按每个响应的 Content-Type 计费(manifest 契约 §9)。两条约束:
- WebSocket 形态是独立的
ws路由:FastAPI WebSocket 端点上只接受protocol="ws"(negotiated会在mount_edge时报错),且要放在不同的 path 上——同 path +GET的两条声明只有先声明的生效。完整例子见examples/negotiated_demo.py。 - 免费形态显式报 0:不收费的响应发
usage_header(0);什么都不发 = usage 缺失,gateway 计入gateway_usage_missing_total并告警(usage 契约 §8)。
上线顺序:所有 DC 的 gateway 升级到支持 negotiated 的版本之后,服务才能发布带 negotiated 的 manifest——旧 gateway 会拒掉整份 manifest(manifest 契约 §9 Rollout)。
环境变量
| 变量 | 语义 |
|---|---|
FISH_EDGE_GATEWAY_TOKEN |
期望的 x-fish-gateway-token。未设 = 观察模式(只记日志) |
FISH_EDGE_REQUIRE_GATEWAY |
1 时强制校验(403 拒绝非 gateway 流量)。P6 gateway 下发 token 后开启 |
开发
pip install -e "sdk-python[dev]"
pytest sdk-python/tests -q
Metadata
Release files for fish-edge-gateway-sdk 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| fish_edge_gateway_sdk-0.3.0.tar.gz | 49.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fish_edge_gateway_sdk-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 73.3 kB
Release files / fish_edge_gateway_sdk-0.3.0.tar.gz
| Download URL | fish_edge_gateway_sdk-0.3.0.tar.gz |
|---|---|
| Size | 49.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9e594e71d060f910c5a1a5086dafabd9e86c376c355f43b9c039ebe7c225dea7
|
|
BLAKE2b-256 checksum How to use checksums |
eeafde86bf0920b111e492315f375768841184a431ec37dadac6f00fe15f40eb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / fish_edge_gateway_sdk-0.3.0-py3-none-any.whl
| Download URL | fish_edge_gateway_sdk-0.3.0-py3-none-any.whl |
|---|---|
| Size | 24.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6568938ee54a01e1a548dd74fd638307c77177427c3ec715b403d3f7ee0d8a36
|
|
BLAKE2b-256 checksum How to use checksums |
d1145690fa3e68d48fd7fe924c712e91056a38687641189d5c7dc37ff97d6ec7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for fish-edge-gateway-sdk 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.