Files
algpkg-sdk/README.md
T
linaro 170e4a10a4 初始提交:algpkg-sdk(算法包开发 SDK)—— 从 sophon-edge 仓库拆分独立建库
本仓库原先内嵌在 sophon-edge 的 `algpkg-sdk/`(该仓库历史上的三次相关提交:
e8101ba「算法开发能力独立成项目」、090c406「契约名落地为真实模块 + 多模型 ctx」、
b666161「sail 存根 + 编写风格修正」)。现拆出独立建库,便于算法作者单独 clone/迭代、
也便于单独发版(打成 wheel 分发给第三方或进 worker 交付包的 vendor/)。

- 内容:`src/algpkg_sdk/`(api/manifest/loader/builder/testkit/cli)+ 契约名模块
  `src/video_algpkg_api/`、`examples/person-count`(完整示例)、`tests/`(pytest,无设备自动跳过)、
  `README.md`(已改成独立仓库口径:命令在项目根执行,配套 worker 用路径依赖/`ALGPKG_SDK_DIR`)、
  `pyproject.toml`(console script `algpkg`)、`uv.lock`;
- 不含 `.venv/`(`.gitignore` 已覆盖,clone 后 `uv sync` 重建)。

配套 worker 仓库(sophon-edge):
`workers/video/pyproject.toml` 以路径依赖指向本仓库(`path = "../../../algpkg-sdk"`,可用
`ALGPKG_SDK_DIR` 覆盖);交付打包 `deploy/pack_worker.py` 会把本仓库打成 wheel 放进 worker 包 `vendor/`。
2026-10-16 16:15:59 +08:00

170 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# algpkg-sdk —— 算法包开发 SDK
独立项目:**算法作者只依赖本项目**,即可完成「写算法 → 本地跑通 → 打包 → 自检 → 交付 `.mbank`」,
不需要 worker 仓库,也不需要了解 worker 内部结构。
```text
算法包开发(本项目) 设备运行(worker)
────────────────────── ──────────────────
写代码 / 本地测试 / 打包 / 签名 → .mbank → 上传 → 挂载 → 推理
用的接口 = algpkg_sdk.api 同一份接口(别名 video_algpkg_api)
```
## 1. 安装
> 本项目是**独立仓库**(2026-10-16 从 sophon-edge 仓库拆出):
> `git clone <本仓库地址> && cd algpkg-sdk`(目录名即项目名;下文命令都在**本项目根**执行)。
```bash
# 从本项目根安装(开发态;也可打成 wheel 分发给第三方)
uv pip install -e . # 只做静态检查/打包的机器
uv pip install -e '.[device]' # 设备上(含 sophon-arm,可跑推理)
```
配套的 **worker(视频推理系统)仓库**只在使用 `algpkg` 工具链做集成联调时才需要:
worker 侧 `workers/video/pyproject.toml` 以**路径依赖**指向本项目(`path = "../../../algpkg-sdk"`),
交付打包(`deploy/pack_worker.py`)会把本项目打成 wheel 放进 worker 交付包的 `vendor/`;
路径可用环境变量 **`ALGPKG_SDK_DIR`** 覆盖(三个开发脚本与打包脚本都认它)。
依赖很轻:`module-bank`(`.mbank` 读写)、`orjson`、`numpy`。
**设备推理包(sophon-arm)是可选的** —— 没有 NPU 的机器照样能打包与做静态校验。
## 2. 三步上手
```bash
# ① 生成脚手架(目录骨架 + manifest 模板 + 可运行示例 + 自测说明)
algpkg init /tmp/smoke-detect --id demo.smoke-detect --name 抽烟检测 --version 1.0.0
# ② 实现 /tmp/smoke-detect/<包内代码目录>/__init__.py 的 load() / infer()
# 模型放 /tmp/smoke-detect/models/,或打包时用 --model 指定
# ③ 打包 + 自检(不需要设备)
algpkg build /tmp/smoke-detect --out demo.smoke-detect-1.0.0.mbank
algpkg inspect demo.smoke-detect-1.0.0.mbank # 清单/模型/快照/签名
algpkg verify demo.smoke-detect-1.0.0.mbank # 结构与模型校验
```
## 3. 本地测试(不需要 worker)
```bash
# 静态检查:manifest 合法性 / 包结构 / 模型文件 / 代码可导入(试加载)
algpkg check demo.smoke-detect-1.0.0.mbank
algpkg check demo.smoke-detect-1.0.0.mbank --deep # 再实例化入口类(需设备)
# 设备上真跑:图片或视频,warmup 后统计单帧耗时,可画框存图
algpkg run demo.smoke-detect-1.0.0.mbank --source clip.mp4 --frames 5 --save-annotated out/
algpkg run a-1.0.0.mbank --source a.jpg --params '{"conf":0.3}'
# 两个包/版本对拍(逐帧检出数 + 逐位一致性)
algpkg compare a-1.0.0.mbank b-1.0.0.mbank --source clip.mp4
```
同样能力在 Python 里直接调(适合写进自己的 pytest):
```python
from algpkg_sdk import testkit
report = testkit.check("demo.smoke-detect-1.0.0.mbank") # 任意机器
runs = testkit.run("demo.smoke-detect-1.0.0.mbank", source="clip.mp4",
params={"conf": 0.3}, save_annotated="out/") # 设备
print(runs.summary())
print(testkit.compare(runs, testkit.run("old.mbank", source="clip.mp4")))
```
## 4. 写算法:接口契约
包内代码只应导入 `video_algpkg_api`(接口契约名,= `algpkg_sdk.api` 的同一批对象)+ 设备框架:
> 装好本 SDK 后,这个导入名在**任何工具里都直接可用**:IDE 补全 / mypy / pyright /
> 本地 `python -c "import video_algpkg_api"`(SDK 自带同名真实模块 + PEP 561 `py.typed`)。
> 设备运行时 worker 仍注册同名别名,两条解析路径拿到的是同一批对象;
> **不要**自己 vendor/复制一份同名模块(两份实现分叉 = "本地过、设备挂")。
```python
from video_algpkg_api import Algorithm, AlgoContext, AlgoResult, AlgoError
class Algorithm(Algorithm): # 类名与 manifest.entry 一致
kind = "detector"
def load(self) -> None:
data = self.ctx.model_bytes() # 包内模型字节(不落盘,直接给引擎)
conf = float(self.ctx.param("conf", 0.25))
self._labels = self.ctx.read_asset("assets/labels.txt").decode().splitlines()
self._engine = MyEngine(data, self.ctx.dev_id, conf) # 例如 sail.Engine(bytes, …)
def infer(self, frame) -> AlgoResult: # 单帧;抽帧由运行方控制
return AlgoResult(boxes=self._engine(frame)) # (N,6): x1,y1,x2,y2,score,cls
def draw(self, frame, result): # 可选:自定义叠加
return None
def close(self) -> None: # 实例回收时调用
self._engine = None
```
| 用法 | 说明 |
| ---- | ---- |
| `ctx.model_bytes(name)` / `ctx.read_asset(rel)` | 读**包内**文件(模型/类别表/阈值表),不落盘;不给名 = 选中模型,给名 = 任意已声明模型(多模型包,见下) |
| `ctx.param(key, default)` | 任务参数(`params_schema` 默认值已合并,越界在装载时被拒) |
| `ctx.dev_id` / `ctx.logger` / `ctx.meta` | 设备号 / 日志 / 选中模型的元信息(精度、分辨率…) |
| `infer` 返回 | `AlgoResult(boxes=(N,6), counts={"person": n}, value=n, labels=[...])` |
| `load()` 抛异常 | 任务转 failed,错误信息带包 id/版本(先在本地 `algpkg check --deep` 拦住) |
约定:同一实例不会被并发调用(运行方串行化),但 `infer` 不要长时间阻塞;
线程与内存预算见《算法包开发指南》§5。
**多模型包**(如"检测 + 二次判定/误报过滤"):一个包声明多份模型(`manifest.models[]`),
代码里 `ctx.model_bytes("fp_filter")` 按名字取第二份——不必硬编码包内路径:
```python
def load(self):
self._det = ctx.model_bytes() # 选中模型(manifest 里 default 的那份)
self._cls = ctx.model_bytes("fp_filter") # 第二份:裁检测框 → 分类判误报
```
两级管线写在 `infer()` 里:返回**过滤后**的 boxes 即可,告警/统计/叠加图自动跟着走
(运行时不做级联,这就是"包内级联"的标准形态;细节与算力旋钮见《算法包开发指南》§5)。
## 5. 打包选项
```bash
algpkg build <源目录> --out x.mbank \
--model <模型名>=<磁盘路径> \ # 模型不在源码目录时显式指定(包内路径以 manifest 为准)
--encrypt <Fernet KEY> \ # 加密包内代码(明文源码会被删除;模型不加密)
--pyarmor \ # PyArmor 混淆(需授权)
--sign <KEY> --key-id <ID> # HMAC-SHA256 签名(对称;设备侧配相同密钥验签)
algpkg list <目录> # 列目录内的包(id/版本/大小)
```
## 6. 目录结构
```text
algpkg-sdk/
├── pyproject.toml 项目定义(scripts: algpkg)
├── src/algpkg_sdk/
│ ├── api.py 接口契约(Algorithm / AlgoContext / AlgoResult)+ 别名注册
│ ├── manifest.py 清单字段与校验(models / params_schema / alarm / legacy…)
│ ├── loader.py AlgoPackage:读 svfs、挂代码(试加载)、构造实例
│ ├── builder.py 打包(module_bank 打代码 + svfs 放模型/资源 + 快照=版本 + 签名)
│ ├── testkit.py 本地测试台:check / run / compare(无需 worker)
│ └── cli.py algpkg build|inspect|verify|init|list|check|run|compare
├── examples/person-count/ 完整示例:人员计数(自带实现,只依赖本 SDK)
│ └── …
└── tests/ pytest(无设备跑静态,有设备跑推理,自动跳过)
```
## 7. 自测
```bash
cd algpkg-sdk
uv run pytest # 静态用例;标记为 device 的用例在无 NPU 机器上自动跳过
uv run pytest -m device # 设备上跑推理用例
```
## 8. 与设备的对接
1. `algpkg build` 产出单文件 `.mbank`;
2. 在设备「算法管理」页上传(或 `POST /api/v1/video/algorithm/install` 分片上传 → `commit`);
3. 任务里选择该算法(参数表单由 `manifest.params_schema` 生成),可与其他算法并行;
4. 现场排障与完整字段表见仓库文档《算法包开发指南》;设计依据见《算法包与多算法任务设计》。