# 绘画模型分辨率定价与站点接入

本功能复用既有接口，版本 1 是显式启用的增量合同。2026-09-24 已部署分辨率定价功能，并按运营授权完成 26 条规则的一次性初始化；后续仓库更新不会自动改写人工售价。

## 价格归属

- RokoAPI：模型美元价。管理员填写分辨率表，保存为可执行 `v2:` 表达式；公开 `pricing_display.rates` 为表达式的派生结果。
- Star-Task：用户积分售价。站点规则优先于全局规则；美元价格仅作为换算来源。
- 历史规则、固定 `cost_points`、旧 `quality=1K/2K/4K` 站点不会被批量迁移。只在管理员明确发布新规则时启用严格分档。
- 公开目录不等于调用授权。前端使用 Star-Task `GET /v1/models?view=products&site_id=...` 返回的可调用模式及精确 `task_model` / `task_type`。

## 前端报价与提交

使用既有用户 JWT 鉴权、站点身份及 CORS 约定；不在浏览器持有供应商 Token 或站点定价管理 Token。

```http
POST /v1/pricing/quote
Authorization: Bearer <USER_JWT>
Content-Type: application/json

{
  "site_id": "your-site",
  "model": "<modes[].task_model>",
  "task_type": "text-to-image",
  "input": { "prompt": "画一座海边灯塔", "resolution": "2K", "n": 2 }
}
```

响应仍为现有 `ok` 包装格式；示例价格仅演示，不是生产售价：

```json
{
  "ok": true,
  "site_id": "your-site",
  "model": "<modes[].task_model>",
  "task_type": "text-to-image",
  "cost_points": 10,
  "breakdown": [{ "id": "catalog_rate", "key": "resolution=2k", "units": 2, "points": 10 }],
  "pricing_version": 3,
  "pricing_revision": "<64位十六进制摘要>",
  "normalized_input": { "prompt": "画一座海边灯塔", "resolution": "2k", "n": 2 }
}
```

`pricing_revision` 和 `normalized_input` 仅在新的严格图片规则生效时出现。保留数值型 `pricing_version`，不要把它改当任务报价锁；它是规则集合的兼容版本。`pricing_revision` 绑定实际选中的规则、站点、模型、模式、计费参数和总价。

用户改变分辨率、画质、数量或参考图后重新报价。异步报价响应应防止乱序覆盖：只展示与当前参数对应的最新结果。提交前显示“预计消耗 X 积分”；模型卡片的 `cost_points` / `reference_price` 仍用于概览，不能代替当前参数的报价。

```http
POST /v1/tasks
Authorization: Bearer <USER_JWT>
Content-Type: application/json

{
  "site_id": "your-site",
  "model": "<modes[].task_model>",
  "task_type": "text-to-image",
  "input": { "prompt": "画一座海边灯塔", "resolution": "2K", "n": 2 },
  "options": { "pricing_revision": "<quote返回的摘要>" },
  "idempotency_key": "<本次提交的唯一键>"
}
```

- 新站推荐传 `options.pricing_revision`。价格变化时返回 HTTP 409 `PRICING_CONFLICT`，且不会扣款；重新报价并让用户确认后再提交。
- 老站不传这个可选字段，仍按提交时服务端现行规则创建任务。
- 不传客户端计算的积分；服务端重新计算，供应商预估价格不能覆盖严格分档的站点售价。
- SDK 新增 `client.quoteTask({ model, task_type, input })`；现有 `createTask` 增加可选 `options.pricing_revision`，不改变返回类型。

## 参数与结算

内部 `resolution` 为小写，大小写输入等价；界面可以显示大写。缺省使用已发布规则的 `default_resolution`。只有明确支持历史别名的合同才把 `quality=2K` 当分辨率；真实 `quality=high` 不与分辨率混淆。

像素尺寸只接受合同 `size_to_resolution` 的精确映射，不能按最长边自行猜测。不同模型不保证有相同档位；不支持 4K 的模型不能显示 4K。冲突参数、不支持档位、非整数或越界 `n` 返回 400；严格规则没有“未匹配就用最低价/最高价”的退路。

按张为 `unit=output`，总价为单价乘 `n`；按请求为 `unit=request`，不乘 `n`。美元转换积分后，在总价处统一取整。任务 metadata 冻结规则、参数版本和报价明细，发布新价不影响已创建任务。成功输出张数可信且少于请求数量时按冻结规则退差额；无法确定数量时保留预扣，不根据猜测退款。全失败沿用现有幂等退款路径。结算积分以 usage 记录为准，任务的 `cost_points` 仍保留原预扣含义，兼容旧站。

## 站点后端自定义积分表

沿用已授权的 `/site-api/v1/pricing/models/<TASK_MODEL>`，先 GET 当前 `etag`，再 PUT。使用独立站点定价 Token；该接口不接受浏览器调用。价格是整表覆盖。

```json
{
  "expected_etag": "<GET返回值>",
  "pricing": {
    "type": "image_resolution",
    "contract_version": 1,
    "field": "resolution",
    "default_resolution": "1K",
    "unit": "output",
    "prices": { "1K": 3, "2K": 5, "4K": 9 }
  }
}
```

`contract_version: 1` 明确启用新规则。省略它保留旧版发布与兜底行为；并非所有历史站点都必须立即升级。`field: quality` 用于已经通过该字段传分辨率的旧站。默认单位为 `output`，如需按整次请求收费可选 `request`。价表须覆盖模型已声明的所有分辨率；如果模型声明只有 1K/2K，不得增加 4K。管理 API 仍要求整数积分、遵守授权 Token 的最低积分限制。

先调用 `/preview` 检查默认档位、各档位及 `n=2`，再发布。`type: inherit` 恢复全局规则。包含独立画质、参考图附加费的复杂零售价继续使用平台管理员结构化规则，不要用这个仅含分辨率的简表意外删除这些收费项。

## 平台后台导入与自动跟随

沿用管理员接口：

1. `POST /internal/admin/providers/rokoapi/catalog/<MODEL_ID>/pricing-draft`，请求 `{ "points_per_usd": 100, "update_mode": "manual" }`。
2. 检查返回的 `rules_json`、完整档位、换算系数及精确目标绑定。
3. `PUT /internal/admin/providers/rokoapi/catalog/<MODEL_ID>/pricing`，请求包含 `scope: global`、`target_model`、相同的 `confirm_model` 和 `rules_json`。

默认 `manual`，上游调价只提示，不覆盖现有售价。明确传 `update_mode: follow` 后，后续目录同步重新按同一换算系数生成全局价格，并在同一个 D1 batch 内发布；并发管理员修改受到旧版本和旧规则 CAS 条件保护。无标记的历史规则视为手动。跟随规则属于自动换算价格，不应再手工改其中的单行价格；要保留独立利润/售价请改成 manual。

站点自定义规则始终保留，不参与自动跟随。上游新表缺档、无法安全导入或版本不可用时保留上次完整规则，并增加 `pricing_skipped_bindings`；新增而未定价的档位会报价失败。取消跟随：生成/发布 `manual` 草稿。

RokoAPI 发布的 `generation_config.resolution_pricing.version=1` 使导入草稿包含 `input_contract`。新模型首次无本地售价时仍按既有默认系数生成初始手动价格；已存在本地规则的模型必须显式生成草稿和发布，不会因本次部署自动改价。

## 发布与回滚

1. 先部署兼容代码；不需要新增数据库表或迁移，不修改已有站点 Token、模型 ID 或路由。
2. RokoAPI 后台为指定模型填入真实单价、支持档位和默认档位；检查美元目录。
3. Star-Task 生成草稿，核对积分售价，再显式发布选定的全局或站点规则。
4. 新前端按报价接口升级；旧前端继续正常提交。
5. 回滚规则沿用既有站点历史回滚或恢复继承；已创建任务继续用自身快照。

## 开发验证

覆盖大小写、历史 quality 别名、像素映射、默认档位、批量取整、缺档/重复档拒绝、部分成功退差、冻结价格、过期报价拒绝、旧站无版本提交、目录跟随和站点覆盖保留。测试不调用付费模型、不修改线上价格。

## 2026-09-24：首次上线价格初始化

按本次明确的运营要求，支持 1K 的图片模型将 2K/4K 初始化为同画质的 1K 售价；只生成模型实际支持的档位，Grok 目前不增加 4K。每个站点使用自己的 1K 积分，保留数量单位、参考图附加费、画质差异和旧参数兼容。没有独立规则的模型沿用 `model_groups.default_cost_points`，不按上游美元价格重新换算。

这是一次性初始化，后续 2K/4K 可分别手动修改。现有旧规则不强制切换严格参数合同，也不自动开启 `follow`；因此已接入前端无需随此次部署同步升级。已有严格合同则继续使用原合同。

运维工具 `scripts/prepare-image-resolution-prices.py` 从只读导出的定价、模型绑定生成 `apply.sql`、`rollback.sql` 和 `expected.json`；更新包含旧版本及旧 JSON 比对，重跑不会覆盖后续人工价格。执行后必须重新读取 D1，对比每条预期规则及版本；失败比对时重新审阅，不可去除并发保护。


### 上线验证结果

2026-09-24 首次功能上线版本：`9bcbe22f-7890-4c6b-8a8b-eb5ebfde98cc`。全局及 site-08 共 26 条规则已在 D1 生效，逐条核对价格 JSON、版本、启用状态均一致。另用生产回读规则验证同画质、数量（1/3）及参考图下 1K/2K/4K 的报价一致，26 项通过；原项目全量测试 322 项通过，1 项付费外部集成跳过。健康接口及开发文档已在线验证。

RokoAPI 的 8 个模型美元价已于 2026-09-24 完成部署和初始化；公开目录各档价格、表达式及哈希验证通过。前端继续使用现有参数和服务端报价接口，Star-Task 独立积分售价不会因美元价调整而自动改变。
