# 拼图 APIMart 图片模型路由接入 2026-05-01 ## 背景 拼图创作已收口为填表式流程,首图生成和结果页关卡重新生成都由 `server-rs/crates/api-server/src/puzzle.rs` 执行外部图片 I/O,再把正式图写入 OSS 与 SpacetimeDB。新的模型选择只影响图片生成上游,不改变 SpacetimeDB 表结构、拼图草稿结构或前端运行时规则。 本轮参考 APIMart 文档: 1. `https://docs.apimart.ai/cn/api-reference/images/gpt-image-2/generation` 2. `https://docs.apimart.ai/cn/api-reference/images/gemini-3.1-flash/generation` 两条文档均指向 OpenAI 兼容风格的图片生成入口:`POST https://api.apimart.ai/v1/images/generations`,头部使用 `Authorization: Bearer {APIMART_API_KEY}`。请求体至少包含 `model`、`prompt`、`n`、`size`。返回体按 OpenAI images 兼容格式优先读取 `data[].url`,若供应商返回异步任务结构,则继续按 `task_id` / `tasks/{task_id}` 轮询并提取图片 URL。 ## 模型选项 拼图图片生成支持三个选项: | 前端显示 | 请求值 | 上游 | | --- | --- | --- | | 原模型 | `original` | 继续使用现有 DashScope 文生图 / 图生图链路 | | `gpt-image-2` | `gpt-image-2` | APIMart `/v1/images/generations` | | `nanobanana2` | `gemini-3.1-flash-image-preview` | APIMart `/v1/images/generations` | 默认值为 `original`。前端只负责展示和传递所选模型,不能把模型路由逻辑、上游请求体拼装或 API Key 暴露到浏览器。 ## 前端交互 1. 拼图创作表单的“画面描述”输入框左下角显示当前调用模型。 2. 拼图结果页关卡详情的“画面描述”输入框左下角同样显示当前调用模型。 3. 点击模型标识弹出轻量选择菜单,支持 `原模型`、`gpt-image-2`、`nanobanana2` 三项。 4. 菜单只是模型选择控件,不写入说明性规则文案。 5. 参考图入口继续在画面描述输入框右下角,模型选择在左下角,两者不得遮挡文本。 6. 表单创建 session、自动保存表单草稿、首图生成失败重试时都要保留当前模型选择。 7. 结果页关卡重新生成时将当前模型随 `generate_puzzle_images` action 传给后端。 ## 后端路由 1. `CreatePuzzleAgentSessionRequest` 与 `ExecutePuzzleAgentActionRequest` 增加可选 `imageModel` 字段;该字段不进入 SpacetimeDB reducer 输入结构。 2. `compile_puzzle_draft_with_initial_cover` 与 `generate_puzzle_image_candidates` 增加图片模型参数。 3. `imageModel` 归一化规则: - 空值、`original` 或未知值统一回落为原 DashScope 链路; - `gpt-image-2` 走 APIMart; - `gemini-3.1-flash-image-preview` 走 APIMart,前端显示名为 `nanobanana2`。 4. APIMart 文生图和图生图共用 `POST /v1/images/generations`。有参考图时,后端将参考图 Data URL 作为 `image_urls` 数组传入;若上游不接受该字段,错误按上游失败返回,不在前端降级伪造结果。 5. APIMart 尺寸使用文档要求的比例写法 `1:1`;原 DashScope 继续使用像素写法 `1024*1024`。`gemini-3.1-flash-image-preview` 额外带 `resolution = "1K"`,对齐约 1024px 的拼图正方形素材。 6. APIMart 生成成功后仍下载远程图片,沿用现有 OSS 私有对象、`asset_object` 和 `asset_entity_binding` 写入流程。 7. APIMart 错误统一映射为 `502 UPSTREAM_ERROR`,`details.provider = "apimart"`,保留上游状态码、业务 message 和截断后的 raw excerpt。 ## 环境变量 新增服务端环境变量: ```text APIMART_BASE_URL="https://api.apimart.ai/v1" APIMART_API_KEY="YOUR_APIMART_API_KEY" APIMART_IMAGE_REQUEST_TIMEOUT_MS=180000 ``` `APIMART_API_KEY` 只能存在于本地或部署环境,不写入 Git 跟踪文件。若选择 APIMart 模型但缺少 key,后端返回服务不可用错误,前端展示现有错误面板。 ## 验收 1. 创作表单和关卡详情的画面描述框左下角能切换 `原模型`、`gpt-image-2`、`nanobanana2`。 2. 点击“生成草稿”时,后端首图生成使用当前表单选择的模型。 3. 点击“生成画面 / 重新生成画面”时,后端当前关卡图片生成使用关卡详情选择的模型。 4. 选择 `original` 时,现有 DashScope 请求体、尺寸和错误处理保持兼容。 5. 选择 APIMart 模型时,请求 `POST {APIMART_BASE_URL}/images/generations`,使用 `Authorization: Bearer {APIMART_API_KEY}`,`model` 等于请求值,`size = 1:1`。 6. 不改 SpacetimeDB 表结构,因此无需更新 `migration.rs` 或重新生成 bindings。 7. 后端改动后运行对应 Rust 测试,并按项目约束用 `npm run api-server:maincloud` 重启验证。