ace-engine-sdk 0.2.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.
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0
4
+
5
+ - MNet and ICAA17K use the managed private-asset and inference endpoints by default; an uploaded asset can be reused, and `legacy=True` explicitly selects the compatibility file endpoint.
6
+ - Preserve service request IDs, model fields, timings, costs and idempotency replay information. Expose lookup and recovery operations without automatic model POST retries or automatic endpoint fallback.
7
+ - Add formal IQA uploads, image/video task submission, polling, listing, cancellation and configuration. Waiting deadlines do not cancel or recreate tasks; retain partial/failed/cancelled distinctions and recovery context.
8
+ - Retain old API-Key construction and scoring methods; add `access_key_secret`, user-token authentication for managed endpoints, explicit errors, context-manager cleanup, additional scoring methods, and typed binary outputs.
9
+ - Correct image MIME handling and API-prefix normalization. Do not follow redirects, leak credentials in error details, or write binary output without an explicit request.
10
+ - Replace inaccurate uniform score examples with actual server contracts, clarify resource expiry and recovery, and add isolated HTTP protocol tests.
11
+ - Minimum Python version is now 3.9. The package remains `ace-engine-sdk`, imported as `ace_engine`.
12
+
13
+ Local verification on 2026-11-10: protocol tests passed on requests 2.25.1 and 2.34.2; actual shared-backend verification passed for private upload, MNet, ICAA17K, same-key replay, JWT status lookup, invalid-key rejection, the legacy contrast endpoint and an IQA exposure task. Wallet changes matched the ledger; the synthetic account, input assets and IQA outputs were removed. This does not establish availability of every optional algorithm or all video/metric combinations. Verification did not deploy services or upload to PyPI; package publication is a separate manual workflow.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ACE
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.
@@ -0,0 +1,3 @@
1
+ include README.md LICENSE CHANGELOG.md PUBLISHING.md requirements.txt
2
+ recursive-include examples *.py
3
+ recursive-include tests *.py
@@ -0,0 +1,248 @@
1
+ Metadata-Version: 2.4
2
+ Name: ace-engine-sdk
3
+ Version: 0.2.0
4
+ Summary: AceEngine image quality evaluation SDK
5
+ Home-page: https://github.com/YuqiPlus/ACEngine-Client
6
+ Author: YuqiPlus
7
+ Author-email: silverwjq@163.com
8
+ License-Expression: MIT
9
+ Project-URL: Documentation, https://github.com/YuqiPlus/ACEngine-Client#readme
10
+ Project-URL: Source, https://github.com/YuqiPlus/ACEngine-Client
11
+ Project-URL: Issues, https://github.com/YuqiPlus/ACEngine-Client/issues
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: requests>=2.25.0
18
+ Dynamic: author
19
+ Dynamic: author-email
20
+ Dynamic: classifier
21
+ Dynamic: description
22
+ Dynamic: description-content-type
23
+ Dynamic: home-page
24
+ Dynamic: license-file
25
+ Dynamic: license-expression
26
+ Dynamic: project-url
27
+ Dynamic: requires-dist
28
+ Dynamic: requires-python
29
+ Dynamic: summary
30
+
31
+ # ACEngine Client SDK
32
+
33
+ 用于调用 ACE 美学计算服务的 Python SDK。支持 MNet / ICAA17K 的私有资源调用、IQA 图片/视频异步任务,以及现有单项评分和图像/视频处理接口。
34
+
35
+ 本文档对应 **SDK 0.2.0**,需要 Python 3.9 或更新版本。发行状态以 PyPI 和 GitHub 的实际版本为准;尚未发布的改动请使用本地源码安装。维护者首次发布步骤见 [PUBLISHING.md](PUBLISHING.md)。
36
+
37
+ ## 安装
38
+
39
+ 发布到 PyPI 后,用户可以直接安装:
40
+
41
+ ```bash
42
+ pip install ace-engine-sdk
43
+ ```
44
+
45
+ ```bash
46
+ # GitHub 主分支
47
+ pip install --upgrade git+https://github.com/YuqiPlus/ACEngine-Client.git
48
+
49
+ # 本地开发
50
+ pip install -e .
51
+
52
+ # 已有的 0.1.0 标签(不含本轮新功能)
53
+ pip install git+https://github.com/YuqiPlus/ACEngine-Client.git@v0.1.0
54
+ ```
55
+
56
+ HTTPS 不通时可以使用 SSH(需要已经配置 GitHub SSH 密钥):
57
+
58
+ ```bash
59
+ pip install git+ssh://git@github.com/YuqiPlus/ACEngine-Client.git
60
+ ```
61
+
62
+ 代理、证书和网络连接由本机配置,不在 SDK 中固定代理地址,也不关闭 HTTPS 证书验证。卸载包名为 `ace-engine-sdk`:
63
+
64
+ ```bash
65
+ pip show ace-engine-sdk
66
+ pip uninstall ace-engine-sdk
67
+ ```
68
+
69
+ ## 快速开始
70
+
71
+ 密钥放在环境变量里,勿写进共享代码。示例占位符需要替换成控制台颁发的有效凭证:
72
+
73
+ ```bash
74
+ export ACE_ENGINE_ACCESS_KEY_ID="your-key-id"
75
+ export ACE_ENGINE_ACCESS_KEY_SECRET="your-key-secret"
76
+ ```
77
+
78
+ Windows PowerShell:
79
+
80
+ ```powershell
81
+ $env:ACE_ENGINE_ACCESS_KEY_ID="your-key-id"
82
+ $env:ACE_ENGINE_ACCESS_KEY_SECRET="your-key-secret"
83
+ ```
84
+
85
+ ```python
86
+ import os
87
+ from ace_engine import AceClient
88
+
89
+ with AceClient(
90
+ access_key_id=os.environ["ACE_ENGINE_ACCESS_KEY_ID"],
91
+ access_key_secret=os.environ["ACE_ENGINE_ACCESS_KEY_SECRET"],
92
+ raise_for_errors=True,
93
+ ) as client:
94
+ response = client.mnet("photo.png")
95
+ print(response["data"]) # 保留后端原始模型字段
96
+ print(response["meta"]) # requestId、assetId、costCents、durationMs、replayed 等
97
+ ```
98
+
99
+ 默认服务为 `https://ace-aesthetics.cn`,接口前缀为 `/ibt`。`base_url` 也接受 `https://ace-aesthetics.cn/ibt`,不会重复拼接前缀。自建网关可以配置 `base_url` 和 `api_prefix`;只有直接连接不带统一前缀的网关时才使用 `api_prefix=""`。
100
+
101
+ 旧的三参数构造 `AceClient(base_url, access_key_id, sign)` 继续可用,`sign` 是 `access_key_secret` 的兼容名称。两者同时传入时必须一致。`from ace_engine import Client` 也是同一客户端的别名。
102
+
103
+ ## 上传一次,调用多个模型
104
+
105
+ 下面使用 `client` 的片段应放在上面的 `with AceClient(...) as client:` 代码块内;离开代码块后连接已关闭。
106
+
107
+ ```python
108
+ uploaded = client.upload_asset("photo.png")
109
+ asset_id = uploaded["data"]["assetId"]
110
+
111
+ mnet_key = client.new_idempotency_key()
112
+ response = client.mnet(asset_id=asset_id, idempotency_key=mnet_key)
113
+
114
+ # 新的模型调用意图使用新的幂等键
115
+ icaa_key = client.new_idempotency_key()
116
+ response = client.icaa17k(asset_id=asset_id, idempotency_key=icaa_key)
117
+
118
+ # 检查资源 / 查询已经提交的调用,不重新执行模型
119
+ asset = client.get_asset(asset_id)
120
+ status = client.get_inference(response["meta"]["requestId"])
121
+ ```
122
+
123
+ `client.infer("mnet", asset_id, idempotency_key=...)` 和 `client.infer("icaa17k", ...)` 提供相同的底层入口。`mnet("photo.png")`、`icaa17k("photo.png")` 自动先上传再调用。
124
+
125
+ `import_asset(image_url)` 将网址交给服务端的允许来源检查;SDK 不下载任意网址,也不绕过后端来源限制。资源属于凭证对应的用户/团队,会按服务端保留策略过期;不能假定资源永久有效。
126
+
127
+ ### 幂等、错误和计费
128
+
129
+ 一次逻辑调用使用一个幂等键,网络超时或响应丢失后的恢复必须沿用原键。不同模型或不同图片使用新键。
130
+
131
+ ```python
132
+ from ace_engine import AceError
133
+
134
+ key = client.new_idempotency_key() # 调用前由业务持久化保存 key 和 asset_id
135
+ try:
136
+ response = client.infer("mnet", asset_id, idempotency_key=key)
137
+ except AceError as error:
138
+ print(error.code, error.request_id, error.idempotency_key)
139
+ # 有 request_id 时先 get_inference(request_id) 查看 RUNNING / SETTLING / SUCCEEDED / FAILED。
140
+ # 状态允许恢复时,再使用同一个模型、asset_id、key 调用 infer。
141
+ # 不要因超时直接换一个新 key。
142
+ ```
143
+
144
+ SDK **不自动重试模型 POST,不在错误后自动换旧接口重发**。MNet / ICAA 的服务端负责幂等、结算和余额检查;SDK 透传其 `costCents` 等实际字段,不估算费用、不伪造结果。`replayed=True` 表示服务端返回此前调用的结果,不是一次新的计费意图。
145
+
146
+ 默认 `raise_for_errors=False`,兼容 0.1 的字典返回方式,调用方应检查 `code` / `success`。HTTP 和业务错误保留原始业务码、说明、请求编号和 HTTP 状态(`httpStatus`)。本地或网络错误使用 `errorType` 区分。
147
+
148
+ 网络/协议异常可能带 `outcomeUnknown=True`:这表示客户端不能确认提交结果,不能据此推断模型未运行或未扣款。错误中的 `meta` 保留可用的 `assetId`、`idempotencyKey`、`taskId` 等恢复信息。密钥和令牌会从 SDK 返回的错误中脱敏;SDK 不打印请求或凭证,不跟随重定向发送凭证。
149
+
150
+ `raise_for_errors=True` 会抛出 `AceError`,其 `.response` 保留相同的错误字典。响应数据及费用字段以实际部署版本为准。
151
+
152
+ ## IQA 异步评估
153
+
154
+ ```python
155
+ # 一张或多张图片;默认等待完成
156
+ response = client.iqa(
157
+ ["photo1.png", "photo2.jpg"],
158
+ selections=["sharpness", "exposure", "contrast", "noise"],
159
+ wait_timeout=300,
160
+ )
161
+ print(response["data"]["status"])
162
+ print(response["data"].get("result"))
163
+ ```
164
+
165
+ 图片每任务最多 50 张,视频每任务 1 个。图片单文件上限 20 MiB,视频 100 MiB;还受服务端实际配额限制。支持的指标为:`sharpness`、`color_accuracy`、`saturation`、`exposure`、`contrast`、`noise`、`holistic`、`overall_iqa`。`holistic` 需要至少一项基础指标;视频不支持 `overall_iqa`。
166
+
167
+ 异步提交、查询和取消:
168
+
169
+ ```python
170
+ asset = client.upload_iqa_asset("clip.mp4", kind="video")
171
+ asset_ids = [asset["data"]["assetId"]]
172
+ key = client.new_idempotency_key()
173
+ created = client.create_iqa_task(
174
+ asset_ids, kind="video", selections=["exposure"], idempotency_key=key,
175
+ )
176
+ task_id = created["data"]["taskId"]
177
+
178
+ response = client.get_iqa_task(task_id)
179
+ response = client.wait_iqa_task(task_id, wait_timeout=600, poll_interval=2)
180
+ # client.cancel_iqa_task(task_id) # 只有显式调用才请求取消
181
+ # client.list_iqa_tasks()
182
+ ```
183
+
184
+ 也可以 `client.iqa("photo.png", selections=["exposure"], wait=False)`,返回已创建的任务。`wait_timeout` 只限制客户端等待,超时不会自动取消、重建或重新扣费;保存错误 `meta.taskId` 后继续查询。
185
+
186
+ `SUCCEEDED` 是完成,`PARTIAL` 表示部分结果可用(需要检查任务里的 errors),`FAILED` / `CANCELLED` 在等待接口中作为错误返回。查询接口保留服务端原始状态。等待网络中断后继续查询原任务,不要重新上传并创建另一个任务。若创建响应丢失,应使用原 `asset_ids`、指标、kind 和幂等键恢复;IQA 重传文件会产生新资源 ID,不能假定与原任务等价。
187
+
188
+ MNet/ICAA 的资源与 IQA 的资源是不同接口管理的资源,不能混用 ID。IQA 输出可能包含短期签名图片/CSV/视频链接;保留签名参数,失效后重新查询任务,SDK 不向这些链接转发账户凭证。
189
+
190
+ `get_iqa_config()` 读取配置;`configure_iqa(config)` 显式提交服务端要求的完整权重/阈值对象。`iqa()` 不会暗中修改账户默认设置,也不支持旧网页中曾出现但服务端并无对应参数的 `weights={...}` 用法。
191
+
192
+ ## 兼容的单项文件接口
193
+
194
+ 以下方法接受本地图片,继续调用对应的 `/api/file/...` 接口:
195
+
196
+ | 方法 | 用途 |
197
+ | --- | --- |
198
+ | `sharpness(path)` | 清晰度 |
199
+ | `color(path)` | 色彩 |
200
+ | `contrast(path)` | 对比度 |
201
+ | `noise(path)` | 噪声 |
202
+ | `exposure(path)` | 曝光 |
203
+ | `holistic(path)` | 综合质量 |
204
+ | `evaluate_all(path)` | 服务端定义的综合评估 |
205
+ | `overall_iqa(path)` | 高分辨率整体质量 |
206
+ | `roc4mllm(path)` | 多模态评价 |
207
+ | `physique(path)` / `paa(path)` | 体态评价 |
208
+ | `human(path)` | 人像评价 |
209
+
210
+ 这些接口使用 API-Key 表单鉴权,保留服务端各自的数据字段,不统一捏造成 `{score, level}`。实际可用性取决于部署的模型服务、凭证权限和余额。
211
+
212
+ MNet / ICAA 默认走新资源接口;只有明确连接旧版服务时才使用 `client.mnet(path, legacy=True)` 或 `client.icaa17k(path, legacy=True)`。普通单项文件接口没有统一幂等保障,超时后不能盲目重发;SDK 不自动重试。
213
+
214
+ ## 图像和视频输出
215
+
216
+ ```python
217
+ from ace_engine import BinaryResult
218
+
219
+ result = client.creative_crop("photo.jpg")
220
+ if isinstance(result, BinaryResult):
221
+ result.save("crop.jpg") # 默认拒绝覆盖已有文件
222
+
223
+ # 返回 BinaryResult,保留真实 Content-Type
224
+ result = client.acellm("photo.jpg", selections=["exposure"])
225
+ result = client.highlight("clip.mp4", query="a person running")
226
+
227
+ # JSON 响应
228
+ result = client.videomamba("clip.mp4", query="a person running")
229
+ ```
230
+
231
+ 二进制成功返回 `BinaryResult(content, content_type, request_id)`;失败仍按统一错误机制处理,不把 JSON 报错写成图片或视频。内容在内存中,只有显式 `.save()` 才写文件;覆盖需要 `overwrite=True`。
232
+
233
+ ## 网站登录令牌
234
+
235
+ 已有有效普通用户 JWT 时,可使用 `AceClient(token=token)` 访问新资源、模型调用和正式 IQA 任务接口。SDK 不负责登录、验证码或刷新令牌。API-Key 与 JWT 必须选择一种,不能混传;旧的单项文件接口需要 API-Key,不自动切换鉴权身份。
236
+
237
+ ## 命令行示例与验证
238
+
239
+ ```bash
240
+ python test_my_sdk.py photo.png --model mnet
241
+ python test_my_sdk.py photo.png --model icaa17k --idempotency-key your-persisted-key
242
+ python test_my_sdk.py photo.png --model iqa --selections exposure noise
243
+
244
+ python -m unittest discover -s tests -v
245
+ python -m build
246
+ ```
247
+
248
+ `ACE_ENGINE_BASE_URL`、`ACE_ENGINE_API_PREFIX`、`ACE_ENGINE_ACCESS_KEY_ID`、`ACE_ENGINE_ACCESS_KEY_SECRET`(兼容 `ACE_ENGINE_SIGN`)及 `ACE_ENGINE_TOKEN` 可供示例程序使用。测试使用隔离的本机 HTTP 服务,不依赖真实密钥、不执行模型、不产生费用。实际联调需另用测试账号核对模型、状态和账单,不能用传输测试代替真实验证。
@@ -0,0 +1,52 @@
1
+ # 发布 ace-engine-sdk
2
+
3
+ 本仓库通过 `.github/workflows/publish.yml` 手动发布。推送代码不会上传发行包;只有在 GitHub Actions 手动运行发布流程后,才会尝试创建 PyPI 项目并上传。
4
+
5
+ ## 首次配置
6
+
7
+ 1. 在 PyPI 验证注册邮箱,并启用双重验证。
8
+ 2. 打开 https://pypi.org/manage/account/publishing/ ,在新增待创建项目的发布者(pending publisher)中选择 GitHub。
9
+ 3. 填写以下内容并添加:
10
+
11
+ | 字段 | 值 |
12
+ | --- | --- |
13
+ | PyPI Project Name | `ace-engine-sdk` |
14
+ | Owner / GitHub owner | `YuqiPlus` |
15
+ | Repository name | `ACEngine-Client` |
16
+ | Workflow name | `publish.yml` |
17
+ | Environment name | `pypi` |
18
+
19
+ 这里的 Owner 是 GitHub 仓库所有者,不是 PyPI 用户名。Workflow name 只填写文件名。配置 pending publisher 并不会立即发布,也不会预占包名;首次成功上传时才创建项目。
20
+
21
+ 4. 在 GitHub 的 `YuqiPlus/ACEngine-Client` 仓库设置 → Environments 中建立 `pypi` 环境。其名称须与上表一致;可将允许发布的分支限制为 `main`。
22
+
23
+ 这条方式使用 GitHub 的短期身份认证,不需要把 PyPI 密码或长期上传 Token 放进仓库。
24
+
25
+ ## 获得推送与发布授权后
26
+
27
+ 1. 核对版本号、CHANGELOG 与构建内容,确保 SDK 和 `.github/workflows/publish.yml` 已配套提交到 `main`。
28
+ 2. 在 GitHub Actions 选择 **Publish to PyPI** → **Run workflow**,分支选择 `main`,版本填写 `0.2.0`。
29
+ 3. 流程在固定的 Ubuntu 24.04 环境测试 Python 3.9、3.12、3.14,避免 `ubuntu-latest` 升级导致旧版 Python 无法安装;构建 wheel 与源码包,并严格检查元数据。指定版本必须与已安装包版本、`ace_engine.__version__` 一致。
30
+ 4. 校验全部通过后,单独的发布任务通过 `pypi` 环境上传到正式 PyPI。工作流只接受手动触发,普通 push 和 PR 不会发布;在其他分支手动运行也不会进入发布。
31
+ 5. 打开 https://pypi.org/project/ace-engine-sdk/0.2.0/ ,并在干净环境执行:
32
+
33
+ ```bash
34
+ python -m pip install --index-url https://pypi.org/simple ace-engine-sdk==0.2.0
35
+ python -c "from ace_engine import AceClient, __version__; print(__version__)"
36
+ ```
37
+
38
+ 6. 确认安装可用后,再更新网站的待发布标记和安装说明。网站发布另行安排,SDK 上传不会部署网站或模型服务。
39
+
40
+ 若修改工作流后重新发布,请从 `main` 点击 **Run workflow** 创建新运行。旧失败记录的 **Re-run jobs** 使用原提交的工作流,不会采用后续修复。
41
+
42
+ ## 本地发布前检查
43
+
44
+ ```bash
45
+ python -m unittest discover -s tests -v
46
+ python -m build
47
+ python -m twine check --strict dist/ace_engine_sdk-0.2.0*
48
+ ```
49
+
50
+ 测试不调用实际模型,不需要业务 API-Key。发布校验通过不等于已经上传;只有正式上传成功后,别人才能通过 `pip install ace-engine-sdk` 获取发行包。后续有代码变化时递增版本并重新构建,不能覆盖已经上传的同名文件。
51
+
52
+ 官方说明:https://docs.pypi.org/trusted-publishers/creating-a-project-through-oidc/
@@ -0,0 +1,218 @@
1
+ # ACEngine Client SDK
2
+
3
+ 用于调用 ACE 美学计算服务的 Python SDK。支持 MNet / ICAA17K 的私有资源调用、IQA 图片/视频异步任务,以及现有单项评分和图像/视频处理接口。
4
+
5
+ 本文档对应 **SDK 0.2.0**,需要 Python 3.9 或更新版本。发行状态以 PyPI 和 GitHub 的实际版本为准;尚未发布的改动请使用本地源码安装。维护者首次发布步骤见 [PUBLISHING.md](PUBLISHING.md)。
6
+
7
+ ## 安装
8
+
9
+ 发布到 PyPI 后,用户可以直接安装:
10
+
11
+ ```bash
12
+ pip install ace-engine-sdk
13
+ ```
14
+
15
+ ```bash
16
+ # GitHub 主分支
17
+ pip install --upgrade git+https://github.com/YuqiPlus/ACEngine-Client.git
18
+
19
+ # 本地开发
20
+ pip install -e .
21
+
22
+ # 已有的 0.1.0 标签(不含本轮新功能)
23
+ pip install git+https://github.com/YuqiPlus/ACEngine-Client.git@v0.1.0
24
+ ```
25
+
26
+ HTTPS 不通时可以使用 SSH(需要已经配置 GitHub SSH 密钥):
27
+
28
+ ```bash
29
+ pip install git+ssh://git@github.com/YuqiPlus/ACEngine-Client.git
30
+ ```
31
+
32
+ 代理、证书和网络连接由本机配置,不在 SDK 中固定代理地址,也不关闭 HTTPS 证书验证。卸载包名为 `ace-engine-sdk`:
33
+
34
+ ```bash
35
+ pip show ace-engine-sdk
36
+ pip uninstall ace-engine-sdk
37
+ ```
38
+
39
+ ## 快速开始
40
+
41
+ 密钥放在环境变量里,勿写进共享代码。示例占位符需要替换成控制台颁发的有效凭证:
42
+
43
+ ```bash
44
+ export ACE_ENGINE_ACCESS_KEY_ID="your-key-id"
45
+ export ACE_ENGINE_ACCESS_KEY_SECRET="your-key-secret"
46
+ ```
47
+
48
+ Windows PowerShell:
49
+
50
+ ```powershell
51
+ $env:ACE_ENGINE_ACCESS_KEY_ID="your-key-id"
52
+ $env:ACE_ENGINE_ACCESS_KEY_SECRET="your-key-secret"
53
+ ```
54
+
55
+ ```python
56
+ import os
57
+ from ace_engine import AceClient
58
+
59
+ with AceClient(
60
+ access_key_id=os.environ["ACE_ENGINE_ACCESS_KEY_ID"],
61
+ access_key_secret=os.environ["ACE_ENGINE_ACCESS_KEY_SECRET"],
62
+ raise_for_errors=True,
63
+ ) as client:
64
+ response = client.mnet("photo.png")
65
+ print(response["data"]) # 保留后端原始模型字段
66
+ print(response["meta"]) # requestId、assetId、costCents、durationMs、replayed 等
67
+ ```
68
+
69
+ 默认服务为 `https://ace-aesthetics.cn`,接口前缀为 `/ibt`。`base_url` 也接受 `https://ace-aesthetics.cn/ibt`,不会重复拼接前缀。自建网关可以配置 `base_url` 和 `api_prefix`;只有直接连接不带统一前缀的网关时才使用 `api_prefix=""`。
70
+
71
+ 旧的三参数构造 `AceClient(base_url, access_key_id, sign)` 继续可用,`sign` 是 `access_key_secret` 的兼容名称。两者同时传入时必须一致。`from ace_engine import Client` 也是同一客户端的别名。
72
+
73
+ ## 上传一次,调用多个模型
74
+
75
+ 下面使用 `client` 的片段应放在上面的 `with AceClient(...) as client:` 代码块内;离开代码块后连接已关闭。
76
+
77
+ ```python
78
+ uploaded = client.upload_asset("photo.png")
79
+ asset_id = uploaded["data"]["assetId"]
80
+
81
+ mnet_key = client.new_idempotency_key()
82
+ response = client.mnet(asset_id=asset_id, idempotency_key=mnet_key)
83
+
84
+ # 新的模型调用意图使用新的幂等键
85
+ icaa_key = client.new_idempotency_key()
86
+ response = client.icaa17k(asset_id=asset_id, idempotency_key=icaa_key)
87
+
88
+ # 检查资源 / 查询已经提交的调用,不重新执行模型
89
+ asset = client.get_asset(asset_id)
90
+ status = client.get_inference(response["meta"]["requestId"])
91
+ ```
92
+
93
+ `client.infer("mnet", asset_id, idempotency_key=...)` 和 `client.infer("icaa17k", ...)` 提供相同的底层入口。`mnet("photo.png")`、`icaa17k("photo.png")` 自动先上传再调用。
94
+
95
+ `import_asset(image_url)` 将网址交给服务端的允许来源检查;SDK 不下载任意网址,也不绕过后端来源限制。资源属于凭证对应的用户/团队,会按服务端保留策略过期;不能假定资源永久有效。
96
+
97
+ ### 幂等、错误和计费
98
+
99
+ 一次逻辑调用使用一个幂等键,网络超时或响应丢失后的恢复必须沿用原键。不同模型或不同图片使用新键。
100
+
101
+ ```python
102
+ from ace_engine import AceError
103
+
104
+ key = client.new_idempotency_key() # 调用前由业务持久化保存 key 和 asset_id
105
+ try:
106
+ response = client.infer("mnet", asset_id, idempotency_key=key)
107
+ except AceError as error:
108
+ print(error.code, error.request_id, error.idempotency_key)
109
+ # 有 request_id 时先 get_inference(request_id) 查看 RUNNING / SETTLING / SUCCEEDED / FAILED。
110
+ # 状态允许恢复时,再使用同一个模型、asset_id、key 调用 infer。
111
+ # 不要因超时直接换一个新 key。
112
+ ```
113
+
114
+ SDK **不自动重试模型 POST,不在错误后自动换旧接口重发**。MNet / ICAA 的服务端负责幂等、结算和余额检查;SDK 透传其 `costCents` 等实际字段,不估算费用、不伪造结果。`replayed=True` 表示服务端返回此前调用的结果,不是一次新的计费意图。
115
+
116
+ 默认 `raise_for_errors=False`,兼容 0.1 的字典返回方式,调用方应检查 `code` / `success`。HTTP 和业务错误保留原始业务码、说明、请求编号和 HTTP 状态(`httpStatus`)。本地或网络错误使用 `errorType` 区分。
117
+
118
+ 网络/协议异常可能带 `outcomeUnknown=True`:这表示客户端不能确认提交结果,不能据此推断模型未运行或未扣款。错误中的 `meta` 保留可用的 `assetId`、`idempotencyKey`、`taskId` 等恢复信息。密钥和令牌会从 SDK 返回的错误中脱敏;SDK 不打印请求或凭证,不跟随重定向发送凭证。
119
+
120
+ `raise_for_errors=True` 会抛出 `AceError`,其 `.response` 保留相同的错误字典。响应数据及费用字段以实际部署版本为准。
121
+
122
+ ## IQA 异步评估
123
+
124
+ ```python
125
+ # 一张或多张图片;默认等待完成
126
+ response = client.iqa(
127
+ ["photo1.png", "photo2.jpg"],
128
+ selections=["sharpness", "exposure", "contrast", "noise"],
129
+ wait_timeout=300,
130
+ )
131
+ print(response["data"]["status"])
132
+ print(response["data"].get("result"))
133
+ ```
134
+
135
+ 图片每任务最多 50 张,视频每任务 1 个。图片单文件上限 20 MiB,视频 100 MiB;还受服务端实际配额限制。支持的指标为:`sharpness`、`color_accuracy`、`saturation`、`exposure`、`contrast`、`noise`、`holistic`、`overall_iqa`。`holistic` 需要至少一项基础指标;视频不支持 `overall_iqa`。
136
+
137
+ 异步提交、查询和取消:
138
+
139
+ ```python
140
+ asset = client.upload_iqa_asset("clip.mp4", kind="video")
141
+ asset_ids = [asset["data"]["assetId"]]
142
+ key = client.new_idempotency_key()
143
+ created = client.create_iqa_task(
144
+ asset_ids, kind="video", selections=["exposure"], idempotency_key=key,
145
+ )
146
+ task_id = created["data"]["taskId"]
147
+
148
+ response = client.get_iqa_task(task_id)
149
+ response = client.wait_iqa_task(task_id, wait_timeout=600, poll_interval=2)
150
+ # client.cancel_iqa_task(task_id) # 只有显式调用才请求取消
151
+ # client.list_iqa_tasks()
152
+ ```
153
+
154
+ 也可以 `client.iqa("photo.png", selections=["exposure"], wait=False)`,返回已创建的任务。`wait_timeout` 只限制客户端等待,超时不会自动取消、重建或重新扣费;保存错误 `meta.taskId` 后继续查询。
155
+
156
+ `SUCCEEDED` 是完成,`PARTIAL` 表示部分结果可用(需要检查任务里的 errors),`FAILED` / `CANCELLED` 在等待接口中作为错误返回。查询接口保留服务端原始状态。等待网络中断后继续查询原任务,不要重新上传并创建另一个任务。若创建响应丢失,应使用原 `asset_ids`、指标、kind 和幂等键恢复;IQA 重传文件会产生新资源 ID,不能假定与原任务等价。
157
+
158
+ MNet/ICAA 的资源与 IQA 的资源是不同接口管理的资源,不能混用 ID。IQA 输出可能包含短期签名图片/CSV/视频链接;保留签名参数,失效后重新查询任务,SDK 不向这些链接转发账户凭证。
159
+
160
+ `get_iqa_config()` 读取配置;`configure_iqa(config)` 显式提交服务端要求的完整权重/阈值对象。`iqa()` 不会暗中修改账户默认设置,也不支持旧网页中曾出现但服务端并无对应参数的 `weights={...}` 用法。
161
+
162
+ ## 兼容的单项文件接口
163
+
164
+ 以下方法接受本地图片,继续调用对应的 `/api/file/...` 接口:
165
+
166
+ | 方法 | 用途 |
167
+ | --- | --- |
168
+ | `sharpness(path)` | 清晰度 |
169
+ | `color(path)` | 色彩 |
170
+ | `contrast(path)` | 对比度 |
171
+ | `noise(path)` | 噪声 |
172
+ | `exposure(path)` | 曝光 |
173
+ | `holistic(path)` | 综合质量 |
174
+ | `evaluate_all(path)` | 服务端定义的综合评估 |
175
+ | `overall_iqa(path)` | 高分辨率整体质量 |
176
+ | `roc4mllm(path)` | 多模态评价 |
177
+ | `physique(path)` / `paa(path)` | 体态评价 |
178
+ | `human(path)` | 人像评价 |
179
+
180
+ 这些接口使用 API-Key 表单鉴权,保留服务端各自的数据字段,不统一捏造成 `{score, level}`。实际可用性取决于部署的模型服务、凭证权限和余额。
181
+
182
+ MNet / ICAA 默认走新资源接口;只有明确连接旧版服务时才使用 `client.mnet(path, legacy=True)` 或 `client.icaa17k(path, legacy=True)`。普通单项文件接口没有统一幂等保障,超时后不能盲目重发;SDK 不自动重试。
183
+
184
+ ## 图像和视频输出
185
+
186
+ ```python
187
+ from ace_engine import BinaryResult
188
+
189
+ result = client.creative_crop("photo.jpg")
190
+ if isinstance(result, BinaryResult):
191
+ result.save("crop.jpg") # 默认拒绝覆盖已有文件
192
+
193
+ # 返回 BinaryResult,保留真实 Content-Type
194
+ result = client.acellm("photo.jpg", selections=["exposure"])
195
+ result = client.highlight("clip.mp4", query="a person running")
196
+
197
+ # JSON 响应
198
+ result = client.videomamba("clip.mp4", query="a person running")
199
+ ```
200
+
201
+ 二进制成功返回 `BinaryResult(content, content_type, request_id)`;失败仍按统一错误机制处理,不把 JSON 报错写成图片或视频。内容在内存中,只有显式 `.save()` 才写文件;覆盖需要 `overwrite=True`。
202
+
203
+ ## 网站登录令牌
204
+
205
+ 已有有效普通用户 JWT 时,可使用 `AceClient(token=token)` 访问新资源、模型调用和正式 IQA 任务接口。SDK 不负责登录、验证码或刷新令牌。API-Key 与 JWT 必须选择一种,不能混传;旧的单项文件接口需要 API-Key,不自动切换鉴权身份。
206
+
207
+ ## 命令行示例与验证
208
+
209
+ ```bash
210
+ python test_my_sdk.py photo.png --model mnet
211
+ python test_my_sdk.py photo.png --model icaa17k --idempotency-key your-persisted-key
212
+ python test_my_sdk.py photo.png --model iqa --selections exposure noise
213
+
214
+ python -m unittest discover -s tests -v
215
+ python -m build
216
+ ```
217
+
218
+ `ACE_ENGINE_BASE_URL`、`ACE_ENGINE_API_PREFIX`、`ACE_ENGINE_ACCESS_KEY_ID`、`ACE_ENGINE_ACCESS_KEY_SECRET`(兼容 `ACE_ENGINE_SIGN`)及 `ACE_ENGINE_TOKEN` 可供示例程序使用。测试使用隔离的本机 HTTP 服务,不依赖真实密钥、不执行模型、不产生费用。实际联调需另用测试账号核对模型、状态和账单,不能用传输测试代替真实验证。
@@ -0,0 +1,6 @@
1
+ from .client import AceClient
2
+ from .results import AceError, BinaryResult
3
+
4
+ Client = AceClient
5
+ __version__ = "0.2.0"
6
+ __all__ = ["AceClient", "Client", "AceError", "BinaryResult", "__version__"]