Co-authored-by: 段舒康 <kdletters@qq.com> Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/85 Co-authored-by: Linghong <ink29535@proton.me> Co-committed-by: Linghong <ink29535@proton.me>
10 KiB
外部 OpenAPI 与 API Key 接入方案
背景
外部调用方需要通过稳定 HTTP 契约使用图片画布编辑器内的素材生成、编辑和管理能力,并能创建项目、保存画板布局和管理账号级素材库。该能力必须走 server-rs + Axum + SpacetimeDB 正式链路,不能把 API Key、画板状态、素材状态或生成结果放到前端临时状态中。
v1 范围
本期新增外部 API 命名空间:
/api/external/v1
v1 只开放以下能力:
POST /api/external/v1/assets/direct-upload-tickets:创建素材直传 OSS 凭证。POST /api/external/v1/assets/objects/confirm:确认已上传素材对象,ownerUserId固定为 API Key 所属账号。GET /api/external/v1/assets/read-url:获取私有素材读取签名 URL。GET /api/external/v1/editor/projects:列出当前 API Key 所属账号的图片画布项目。POST /api/external/v1/editor/projects:创建图片画布项目。GET /api/external/v1/editor/projects/recent:读取当前账号最近图片画布项目。GET /api/external/v1/editor/projects/{projectId}:读取项目与默认画布。PATCH /api/external/v1/editor/projects/{projectId}/metadata:更新图片画布项目标题。DELETE /api/external/v1/editor/projects/{projectId}:删除图片画布项目,并级联清理默认画布和项目资源元数据。PATCH /api/external/v1/editor/projects/{projectId}/canvas:保存默认画布的 viewport 和 layers。POST /api/external/v1/editor/projects/{projectId}/resources:创建项目画布资源记录。GET /api/external/v1/editor/assets/library:读取账号级编辑器素材库。POST /api/external/v1/editor/assets/folders:创建素材文件夹。PATCH /api/external/v1/editor/assets/folders/{folderId}:更新素材文件夹名称或折叠状态。DELETE /api/external/v1/editor/assets/folders/{folderId}:删除素材文件夹并返回最新素材库。POST /api/external/v1/editor/assets:创建素材记录。PATCH /api/external/v1/editor/assets/{assetId}:更新素材名称或所在文件夹。DELETE /api/external/v1/editor/assets/{assetId}:删除素材记录。POST /api/external/v1/editor/images/generations:调用编辑器图片素材生成能力;通过kind支持普通图、规范图spec、角色图character、快速编辑参考图quick-edit、UI 设计图ui-design和宣发素材publication-material。可选传入projectId和assetFolderId,生成后按站内编辑器规则写入editor_project_resource和账号级editor_asset。POST /api/external/v1/editor/images/edits:重绘 / 调整已有图片,结果可写入项目资源和素材库。POST /api/external/v1/editor/icon-spritesheets/generations:按规范图生成图标 spritesheet,并拆分为独立图标素材。POST /api/external/v1/editor/ui-designs/assets/extractions:从 UI 设计图中提取 / 拆分素材。POST /api/external/v1/editor/character-animations/generations:基于角色图片生成角色动画预览和帧序列。POST /api/external/v1/editor/videos/generations:生成编辑器视频素材,支持现有 Seedance / Kling / Veo 模型参数和参考媒体限制。POST /api/external/v1/editor/audios/sound-effects/generations:生成编辑器音效素材。POST /api/external/v1/editor/audios/background-music/generations:生成编辑器背景音乐素材。GET /api/external/v1/openapi.json:导出本版本 OpenAPI 3.1 JSON。
角色图生成、图标 spritesheet 和 UI 素材提取的 2xx 成功响应可携带可选结构化 warning { code, reason },当前稳定 code 为 postprocess-failed-source-preserved。provider 原图已保存但透明背景处理最终失败时,接口返回原图,不返回不存在的透明处理图,图标和 UI 也不继续拆分;有 projectId + canvasCompletion 时由原图完成画布写回,无画布上下文时只返回原图及实际存在的资源 / 素材快照。调用方应展示 warning,但不得把任务改判为失败。该降级只覆盖透明背景处理的最终失败,phase 上报、原图或透明处理图持久化、画布写回失败仍返回错误。图标 / UI 已成功生成透明图、只有自动拆分失败时继续使用既有 sliceWarning;服务端保证通用 warning 与 sliceWarning 互斥,防御性客户端若收到异常双字段响应仍以通用 warning 为准。
管理 API Key 的登录态接口保留在站内个人中心链路,但不写入外部 OpenAPI JSON:
GET /api/profile/api-keys
POST /api/profile/api-keys
DELETE /api/profile/api-keys/{keyId}
前端入口位于登录后个人中心的 我的 → 开发者 API Key,用于查看当前 Key、创建新 Key、复制一次性明文和撤销已创建 Key。外部 OpenAPI 只描述 /api/external/v1 下可由 API Key 调用的接口,不混入登录态 API Key 管理接口。
鉴权
外部调用使用 Bearer API Key:
Authorization: Bearer tnr_sk_xxx
规则:
- API Key 归属于
owner_user_id,外部接口只能访问该账号自己的项目、画布和生成素材。 - 明文 Key 只在创建接口返回一次,后端只保存
key_hash与key_prefix。 - API Key 被撤销后立即不可再用于外部接口。
- 外部 API 鉴权不复用登录态 JWT,不检查 refresh session;它是独立开发者凭据。
- OpenAPI JSON 公共可读,不需要鉴权。
数据模型
新增 SpacetimeDB private 表:
external_api_key
字段:
key_id:主键。owner_user_id:所属账号。name:用户可识别名称。key_prefix:前缀片段,用于列表展示和排障。key_hash:完整 Key 的 SHA-256 十六进制摘要,唯一。scopes_json:作用域 JSON,v1 固定包含editor:project、editor:canvas、editor:image-generate、editor:asset。其中editor:image-generate覆盖图片生成、重绘、规范图、宣发图、图标拆分、UI 素材拆分、角色动画、视频、音效和音乐生成。created_at/last_used_at/revoked_at/updated_at。
SpacetimeDB procedure:
create_external_api_key_and_returnlist_external_api_keys_and_returnrevoke_external_api_key_and_returnauthenticate_external_api_key_and_return
素材生成与落库
外部生成接口复用站内编辑器已有 handler 和 DTO,不维护第二套生成语义:
- 图片生成 / 重绘 / 规范图 / 宣发图 / UI 设计图复用
/api/editor/images/generations与/api/editor/images/edits的校验、模型归一、计费和持久化规则。 - 图标 spritesheet 和 UI 设计图素材提取复用站内拆分逻辑,生成图集后按连通域切片,并把图集与切片都按请求写入项目资源和素材库。
- 角色动画、视频、音效和背景音乐复用站内编辑器生成链路;请求携带
assetFolderId时按站内规则写入素材库,音频类外部调用使用 API Key 所属账号作为 asset owner。 - API Key 管理接口仍只属于登录态个人中心,不进入外部 OpenAPI JSON。
素材外部生成成功后,后端拿到素材后:
- 通过 OSS / asset object adapter 持久化媒体文件。
- 写入
editor_asset,让生成素材进入账号级素材库。 - 如果请求带
projectId,写入editor_project_resource。 - 返回图片读取地址、素材 ID、资源 ID、尺寸、prompt、model、provider 和 taskId。
如果请求未带 projectId,只生成并写入素材库;调用方可随后创建项目或自行保存画板布局。
素材与项目资源操作
外部素材操作复用站内图片画布素材库和项目资源的后端事实源:
- 外部上传素材时先调用
POST /api/external/v1/assets/direct-upload-tickets获取 OSS 表单直传参数,上传完成后调用POST /api/external/v1/assets/objects/confirm写入asset_object,再用assetObjectId/objectKey创建账号级素材或项目资源记录。 - 外部读取私有 generated / uploaded 素材预览时调用
GET /api/external/v1/assets/read-url获取短期签名 URL;不开放浏览器 STS 写权限。 - 素材库读取、文件夹创建 / 更新 / 删除、素材创建 / 更新 / 删除、项目画布资源创建全部通过
api-server -> spacetime-client -> spacetime-module。 - 所有外部素材接口使用 API Key 所属的
owner_user_id,不能由请求体传入 owner。 - 素材库仍是账号级事实源,不归属于单个项目;项目画布内资源继续使用
editor_project_resource。 - 素材创建和项目资源创建接口只保存记录和元数据;图片二进制上传、签名读取和生成图持久化继续复用已有资产 / 生成链路。
OpenAPI 导出
OpenAPI 3.1 JSON 固定落在:
docs/openapi/genarrative-external-v1.openapi.json
服务端 GET /api/external/v1/openapi.json 使用同一份 JSON,通过 include_str! 导出,避免运行时生成结果与仓库文档漂移。
验收
- API Key 创建只返回一次明文,列表不返回明文。
- 撤销后的 API Key 调用外部接口返回
401。 - 外部图片生成、重绘、图标拆分、UI 素材拆分、视频、音效和音乐生成成功后,生成结果按请求同时出现在画布资源和账号级素材库。
- 角色图、图标 spritesheet 和 UI 素材提取的 2xx 成功响应允许携带
EditorGenerationWarning;provider 原图保留降级与自动拆分降级必须保持成功状态,并分别使用通用warning与兼容sliceWarning表达。 - 外部视频、角色动画、音效和音乐接口使用站内编辑器相同的请求校验、模型限制和价格校验。
- OpenAPI JSON 能被
serde_json解析,且 security scheme 为 Bearer API Key。 - OpenAPI JSON 不包含
/api/profile/api-keys、UserAccessToken或 API Key 管理 schema。 - 外部素材库接口覆盖当前已有素材操作:直传凭证、素材对象确认、签名读取、读取素材库、创建 / 更新 / 删除文件夹、创建 / 更新 / 删除素材、创建项目画布资源。
- 外部项目接口覆盖当前已有项目管理操作:项目列表、最近项目、创建、读取、重命名、删除和默认画布保存。
- 外部素材生成接口覆盖当前已有编辑器素材操作:生图、重绘 / 调整、规范图生成、宣发素材生成、图标素材生成与拆分、UI 设计图生成与拆分、角色动画、视频、音效和背景音乐。
- 修改 SpacetimeDB schema 后运行
npm run spacetime:generate与npm run check:spacetime-schema。