Python SDK 概述
Darra AI SDK 的 Python 绑定。只翻译 C ABI 的类型和错误码,零密码学、零容器格式逻辑。cffi 只走 ABI 模式(ffi.dlopen),不编译任何 C 扩展。
权威契约:Core/include/darra_ai.h。语义冲突时以头文件为准。包版本 1.0.0,与 __version__ / pyproject.toml 一致。
from darra_ai import Session
import darra_ai 不加载 native。第一次调用碰 Core 的 API(Session.open / runtime.ensure / diagnostics.collect / version() / authoring.*)才 dlopen。
安装
pip install darra-ai
PyPI 分发名为 darra-ai(pip install 用此名),代码内导入名为 darra_ai(from darra_ai import Session)。两者是独立概念(PEP 427),不要混用。
开发树(Darra.AI.Studio.SDK/Python/):
pip install -e .
依赖 cffi>=1.15。wheel 按平台内嵌 darra_ai/_native/<plat>/darraai_core.dll|so。本仓库此时尚未发布 native,get_lib() 会抛 DarraLoadError。
找不到库时按顺序找:
- 包内
_native/<平台>/ - 环境变量
DARRA_AI_CORE_PATH(文件或目录) - 系统加载器搜索路径
平台目录名:win_amd64 / linux_x86_64 / linux_aarch64。
Windows 库名候选:darraai_core.dll、DarraAI.Core.dll。Linux:darraai_core.so、libdarraai_core.so。
加载后立即核 ABI:darra_version() 的 major 必须等于 1,不等抛 DarraLoadError,禁止继续调用。
环境要求
| 项目 | 要求 |
|---|---|
| 操作系统 | Windows x64 / Linux x86_64 / Linux ARM64(RK3588) |
| Python | ≥ 3.10(cffi ABI 模式,同一份纯 Python 不按解释器版本拆 wheel) |
| 依赖 | cffi ≥ 1.15 |
| native | DarraAI.Core(wheel 内嵌或 DARRA_AI_CORE_PATH) |
| 不在 v1 | macOS、32 位 |
快速开始
from darra_ai import Session, runtime
runtime.ensure() # None = 按硬件自动选 Provider 包
with Session.open("model.darmodel", key_path="model.darmkey") as s:
print(s.meta())
jpg = open("photo.jpg", "rb").read()
print(s.infer_image(jpg))
明文 ONNX(Studio 试跑 / 客户自有未加密模型)走同一推理路径:
with Session.open_plain("model.onnx") as s:
print(s.infer_image(jpg))
工业相机裸缓冲:
from darra_ai import IMAGE_BGR888
result = s.infer_image(frame, format=IMAGE_BGR888, width=1920, height=1080)
Session 可作上下文管理器,退出 with 块时自动 close()。完整脚本见 SDK 树 examples/infer_image.py。
类别与访问
数据用属性,不用 get_xxx()。下表覆盖 darra_ai 公开符号(__all__ + 三个子模块函数)。_ffi / _util 不是公开 API。
| 类别 | 成员 | 类型 | 访问 | 说明 |
|---|---|---|---|---|
| 图像格式 | IMAGE_AUTO | int(0) | 常量 | 编码图自动嗅探 |
IMAGE_ENCODED | int(1) | 常量 | 已编码 JPG/PNG/BMP 字节流 | |
IMAGE_RGB888 | int(2) | 常量 | 裸 RGB888 像素 | |
IMAGE_BGR888 | int(3) | 常量 | 裸 BGR888 像素 | |
| 版本 | version() | tuple[int, int, int] | 方法 | (major, minor, patch)。会加载 native |
version_string() | str | 方法 | 形如 1.0.0+runtime / 1.0.0+authoring。会加载 native | |
| 会话打开 | Session.open | Session | 方法 | 打开加密容器 .darmodel(DARM1) |
Session.open_plain | Session | 方法 | 打开明文 .onnx;跳过容器解码与验票 | |
Session.open_ex | Session | 方法 | 可扩展入口,当前翻译到 open | |
Session.close | None | 方法 | 关闭会话。重复 close / 未打开均为 no-op | |
| 会话元信息 | meta() | dict | 方法 | 会话元信息 JSON 对象(有缓存) |
task | str | None | 只读 | detect / classify / segment / pose / ocr / anomaly。缺席为 None | |
labels | list[str] | 只读 | 类别标签。缺席或非数组则为空列表 | |
input_width | int | 只读 | 模型输入宽。未知为 0 | |
input_height | int | 只读 | 模型输入高。未知为 0 | |
channels | int | 只读 | 模型输入通道数。未知为 0 | |
layout | str | None | 只读 | 张量布局(如 NCHW / NHWC)。先读 input.layout,再读顶层 layout | |
payload_kind | str | None | 只读 | onnx / trt-engine / openvino / rknn | |
provider_id | str | None | 只读 | 实际选中的 Provider ID(不是 prefer 入参) | |
encrypted | bool | 只读 | 是否加密容器会话。明文 ONNX 为 False | |
| 推理 | infer_image | dict | 方法 | 对一张图跑推理,返回结果 JSON 对象 |
| 会话选项 | SessionOptions.key_path | str | None | 读写 | 授权文件路径。构造本对象不加载 native |
SessionOptions.password | str | None | 读写 | 密码通道 | |
SessionOptions.prefer_provider | str | None | 读写 | 指名 Provider;None = 自动选 | |
| 运行时 | runtime.ensure | None | 方法 | 确保 Provider / profile 已装好 |
runtime.cancel | None | 方法 | 取消当前在飞的 ensure。无在飞操作为 no-op | |
| 诊断 | diagnostics.collect | dict | 方法 | 本机环境自检 JSON。禁止在 PLC 扫描周期等实时路径调用 |
| authoring | authoring.encrypt_onnx | None | 方法 | 明文 .onnx → .darmodel。仅 authoring 构建 |
authoring.issue_key | None | 方法 | 签发 .darmkey。仅 authoring 构建 | |
authoring.fingerprint_perturb | None | 方法 | 逐客户权重扰动。仅 authoring 构建 | |
| 错误 | DarraError.code | int | None | 只读 | darra_error_code;绑定侧错误为 None |
DarraError.message | str | 只读 | 错误描述 | |
DarraError.hint | str | 只读 | 修复建议,与 错误码目录 一致 |
只读属性全部从 meta() 的附录 B JSON 派生。
会话
Session.open
@classmethod
def open(
cls,
container_path: str,
*,
key_path: str | None = None,
password: str | None = None,
prefer_provider: str | None = None,
) -> Session
打开加密容器(.darmodel,DARM1)建会话。
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| container_path | str | — | 容器路径,不能为空 |
| key_path | str | None | None | 授权文件 |
| password | str | None | None | 密码通道 |
| prefer_provider | str | None | None | 指名 Provider |
key_path 与 password 至少给一个;都给则 key 文件优先验票。prefer_provider 为 None 时按 载荷 × 硬件 × 已装包 自动选;指名但不可用 = fail-closed,绝不静默降级。
Session.open_plain
@classmethod
def open_plain(
cls,
onnx_path: str,
*,
prefer_provider: str | None = None,
) -> Session
打开明文 .onnx 建会话。与 open 同一推理路径,只跳过容器解码与验票。训练格式(.pt / .pth / Paddle)不是运行时载荷,Core 报 DARRA_UNSUPPORTED_PAYLOAD。
Session.open_ex
@classmethod
def open_ex(
cls,
container_path: str,
options: SessionOptions | None = None,
) -> Session
可扩展入口,对齐 C# OpenEx。options 为 None 时等同全部可选通道为空。当前翻译到 open;Core 追加 darra_session_open_ex 后只换调用点。
Session.infer_image
def infer_image(
self,
image_bytes: bytes | bytearray | memoryview,
*,
format: int = IMAGE_AUTO,
width: int = 0,
height: int = 0,
stride: int = 0,
) -> dict
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| image_bytes | bytes / bytearray / memoryview | — | 图像字节 |
| format | int | IMAGE_AUTO | 见图像格式常量 |
| width | int | 0 | 裸缓冲必须 >0 |
| height | int | 0 | 裸缓冲必须 >0 |
| stride | int | 0 | 0 = 紧凑排列(width × 3) |
IMAGE_AUTO / IMAGE_ENCODED:image_bytes 为 JPG/PNG/BMP 编码字节流,忽略宽高。IMAGE_RGB888 / IMAGE_BGR888:裸像素,必须给 width/height;缺宽高或未知 format 抛 InternalError(码 18)。
返回结果 JSON 对象。会话已关闭再调抛 InternalError。
Session.close
def close(self) -> None
关闭会话并释放全部资源。重复 close / 未打开均为 no-op。也实现 __enter__ / __exit__。
运行时
runtime.ensure
def ensure(
profile_or_provider_id: str | None = None,
offline_zip: str | None = None,
progress: Callable[[float, str], None] | None = None,
) -> None
确保指定 Provider / profile 已装好;没装就探测→选包→下载→校验→解压登记。已装且清单匹配 → 直接成功。进程内互斥串行。取消或失败不留半成品。
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
| profile_or_provider_id | str | None | None | 细包 ID 或场景整合包名;None = 按硬件自动选 |
| offline_zip | str | None | None | 本地离线整合包 zip;None = 在线下载 |
| progress | 回调 | None | None | (percent, stage)。percent 为 0..100;stage 为 probe / manifest / download / verify / install / done |
进度回调在 SDK 工作线程触发,回调内禁止再调任何 Darra AI API(含 cancel)。回调异常被吞掉,以免穿越 C 边界崩进程。
runtime.cancel
def cancel() -> None
请求取消当前在飞的 ensure(任意线程可调;进度回调内禁止)。没有在飞的 ensure 时为 no-op。被取消的 ensure 抛 CancelledError。
诊断
diagnostics.collect
def collect() -> dict
采集本机环境诊断,返回 JSON 对象。尽力而为:单个字段采不到时为 null 或缺席,整体不失败。去敏:不含密钥 / 密码 / token / 机器指纹字节。可能触发 WMI / NVML / sysfs,耗时数百毫秒,禁止在 PLC 扫描周期等实时路径调用。
authoring
encrypt_onnx / issue_key / fingerprint_perturb 只随 AI Studio 的 authoring 构建导出。客户机 runtime 包物理上没有这些符号;访问时 cffi 抛 AttributeError,由 authoring.py 包装成 DarraError(code 为 None)。不是权限开关,是物理隔离。
调用顺序:fingerprint_perturb → encrypt_onnx → issue_key。扰动必须发生在加密前。
authoring.encrypt_onnx
def encrypt_onnx(onnx_path: str, out_container_path: str) -> None
明文 .onnx 加密打包成 .darmodel(DARM1)。
authoring.issue_key
def issue_key(
container_path: str,
out_key_path: str,
*,
password: str | None = None,
bind_machine: bool = False,
trial_runs: int = 0,
) -> None
为容器签发 .darmkey(DARMK2)。password 为 None = 本授权不启用密码通道。bind_machine=True 绑定签发时的机器指纹。trial_runs>0 为试用计次;0 = 永久授权。
authoring.fingerprint_perturb
def fingerprint_perturb(
onnx_path: str,
out_onnx_path: str,
customer_seed: int,
) -> None
逐客户权重扰动指纹(盗版溯源,不是防 dump)。同一 customer_seed 永远产出同一份扰动结果。必须在 encrypt_onnx 之前调用。
错误
失败时抛 DarraError 子类(code / message / hint)。hint 文案与 错误码目录 一致,可原样展示给最终用户。native 找不到或 ABI 主版本不是 1 时抛 DarraLoadError(code 为 None)。
exception_for_code(code, message, hint="") 按码构造对应子类;未知新码兜底为 DarraError 基类,code 原样保留。
| 异常 | 码 | 说明 |
|---|---|---|
DarraError | — | 基类。绑定侧错误 code 为 None |
DarraLoadError | None | native 加载失败或 ABI 不匹配 |
IoNotFoundError | 1 | 文件不存在 |
IoDeniedError | 2 | 文件存在但读写被拒 |
BadContainerError | 3 | .darmodel 损坏 / 非 DARM1 |
BadLicenseError | 4 | .darmkey 损坏或与容器不配对 |
PasswordRequiredError | 5 | 需要密码但没给 |
PasswordWrongError | 6 | 密码错误 |
MachineMismatchError | 7 | 绑机授权用在非目标机器 |
TrialExhaustedError | 8 | 试用计次已用完 |
UnsupportedPayloadError | 9 | 载荷类型当前平台/Provider 不支持 |
UnsupportedPlatformError | 10 | OS/架构不在支持矩阵 |
ProviderMissingError | 11 | 运行时 Provider 包未安装 |
ProviderAbiMismatchError | 12 | Provider 包与 Core ABI 不匹配 |
HardwareMissingError | 13 | 未探测到所需硬件 |
DriverTooOldError | 14 | 驱动版本低于 Provider 要求(SDK 不代装) |
NetworkFailedError | 15 | 清单 / 运行时包下载失败 |
ChecksumMismatchError | 16 | 下载包或离线包 sha256 校验不过 |
CancelledError | 17 | ensure 被取消 |
InternalError | 18 | SDK 内部错误;也用于调用方参数契约违反 |
try:
with Session.open("model.darmodel", key_path="model.darmkey") as s:
s.infer_image(jpg)
except DarraError as ex:
print(ex) # [码] 描述 | 建议: hint
诚实边界
- 不承诺 dump 免疫:授权机 + 管理员级调试器在会话存活期暂停 dump 挡不住。本 SDK 防的是静态拷走 / 转发 / 无授权运行 / 常规 dump 工具。
- 加密单向:官方不提供解回明文的通道;永久密码只用于无限次推理。
- 驱动 / OS 级依赖不自动装:NVIDIA 驱动过旧、RK3588 板镜像缺 NPU 驱动,SDK 只诊断不代劳。
- macOS 不在 v1;rknn 载荷只在 linux-arm64 板端,Windows 上如实拒绝。
- 推理不承诺硬实时。