实现 Raw GPT Image 2 图片编辑代理

新增受 Bearer 保护的 /api/raw/v1/images/edit JSON 路由

按单图 image 与可选 mask 转发 GPT Image 2 参数

固定 model 与 n 并返回仅含 data[].b64_json 的响应

复用钱包计费与退款边界并补充单元测试
This commit is contained in:
2026-09-08 10:36:48 +08:00
parent 302b4addae
commit 4e1316e272
13 changed files with 423 additions and 37 deletions
@@ -18,12 +18,10 @@ POST /api/raw/v1/images/edit
```json
{
"images": [
{
"data": "<base64>",
"mimeType": "image/png"
}
],
"image": {
"data": "<base64>",
"mimeType": "image/png"
},
"mask": {
"data": "<base64>",
"mimeType": "image/png"
@@ -37,7 +35,7 @@ POST /api/raw/v1/images/edit
}
```
`images` 是必填数组,数组成员结构固定为 `{ data, mimeType }`;`mask` 可选并使用相同结构。输入格式由成员的 MIME 类型和解码后的图片字节共同确定,服务端不把输入格式另建成请求参数。`prompt` 必填。`quality`、`background` 和 `output_format` 采用 GPT Image 模型支持的值。`width`、`height` 为整数,组成发送给 provider 的输出尺寸;不把尺寸改写成业务字符串字段。
`image` 是必填的单图结构 `{ data, mimeType }`;`mask` 可选并使用相同结构。输入格式由 MIME 类型和解码后的图片字节共同确定,服务端不把输入格式另建成请求参数。`prompt` 必填。`quality`、`background` 和 `output_format` 采用 GPT Image 模型支持的值。`width`、`height` 为整数,组成发送给 provider 的输出尺寸;不把尺寸改写成业务字符串字段。
服务端发送给 `platform-image` 时固定注入:
@@ -68,14 +66,15 @@ n = 1
所有请求、JSON、base64、图片结构和 provider 参数检查必须在扣费前完成。预检查失败直接返回 4xx,不产生钱包流水,也不调用 provider。
检查通过后,api-server 调用一个 raw 图片操作的 SpacetimeDB 事务 procedure,在同一事务内完成:
检查通过后,api-server 进入现有资产操作计费边界,通过 SpacetimeDB 钱包事务 procedure 原子完成:
1. 以认证后的用户和请求 ID 建立 raw 操作幂等事实;
2. 按现有图片编辑算法解析价格:GPT Image 2 长边不超过 1536 使用 1K 价格,否则使用 2K 价格;当前默认价格为 3 / 5 泥点;
3. 原子扣除用户泥点并写入 `asset_operation_consume` 流水;
4. 持久化操作状态,供 provider 返回后成功或失败收口。
1. 按现有图片编辑算法解析价格:GPT Image 2 长边不超过 1536 使用 1K 价格,否则使用 2K 价格;当前默认价格为 3 / 5 泥点;
2. 以认证后的用户、`raw-image-edit` 命名空间和请求 ID 组成幂等扣费流水 ID;
3. 原子扣除用户泥点并写入 `asset_operation_consume` 流水。
provider 调用在 SpacetimeDB 事务之外执行。成功后调用同一 raw 操作的完成 procedure;失败后调用失败 procedure,由数据库事务写入退款 outbox / settlement 事实。进程崩溃时不依赖 Rust future `Drop` 才能发现需要退款;恢复处理根据持久化的 raw 操作状态完成退款。
provider 调用在 SpacetimeDB 事务之外执行。失败时由现有计费边界把幂等退款事实写入 SpacetimeDB refund outbox,再由 worker 完成退款。
TODO:新增 raw 操作持久化状态,将“创建 raw 操作事实 + 扣费”收入同一事务,并由恢复 worker 对“已扣费但未收口”状态自动退款,填补进程在扣费后、写入 refund outbox 前崩溃的窗口。
raw 操作使用独立的 operation / ledger 命名空间,例如 `raw-image-edit`,不能复用编辑器资源 ID、编辑器任务 ID 或 `external_generation_job`。
@@ -83,7 +82,7 @@ raw 操作使用独立的 operation / ledger 命名空间,例如 `raw-image-ed
`platform-image` 保留 VectorEngine 协议细节。raw handler 只负责:认证、JSON DTO、base64 解码、预检查、计费编排和响应映射。provider 请求仍由 `platform-image` 统一构造,并携带 `model`、`n`、`quality`、`background`、`output_format`、尺寸及图片参考字节。
provider 返回的原始 `size` 必须沿 `GeneratedImages` 结果传回 api-server;raw handler 从该字段解析响应尺寸,再编码 `data[].b64_json`。
provider 结果统一解码为图片字节;raw handler 只将这些字节编码到 `data[].b64_json`。
## 代码拆分