收紧编辑器媒体引用契约

禁止当前画布与外部编辑器接口接收 Data URL 和 Blob URL
生成请求统一先上传 OSS 并使用稳定资源引用
角色动画和视频签名前校验资源归属并支持资源与素材 ID
同步前后端 256KB 引用限制及相关文档测试
This commit is contained in:
2026-07-17 16:44:01 +08:00
parent 93b27a2307
commit 18af49c27f
18 changed files with 697 additions and 393 deletions
+15 -15
View File
@@ -240,21 +240,21 @@
- 验证:`npm run test -- src/components/image-editor/ImageCanvasEditorModel.test.ts src/components/image-editor/ImageCanvasGenerationComposerView.test.tsx src/components/image-editor/ImageCanvasEditorGenerationIntegration.test.tsx --reporter verbose`。
- 关联:`src/components/image-editor/ImageCanvasEditorModel.ts`、`src/components/image-editor/ImageCanvasPublicationMaterialsDemoPanelView.tsx`、`src/components/image-editor/ImageCanvasEditorGenerationIntegration.test.tsx`。
## 图片画布快速编辑不要直接提交普通图片 URL
## 图片画布生成请求不要直接提交临时媒体源
- 现象:图片画布快速编辑站内示例图、历史 generated 图或 OSS generated 图时,后端返回 `修改图片参考图必须是图片 Data URL。`。
- 原因:快速编辑直接把图层 `src` 塞进 `/api/editor/images/generations` 的 `referenceImageSrcs`;默认示例图和部分持久化图层的 `src` 是 `/creation-type-references/*.webp`、`/generated-*` 或 OSS URL,而 `api-server` 的编辑参考图解析只接收 `data:image/*;base64,...`。
- 处理:前端统一通过 `resolveEditorImageReferenceDataUrl(...)` 在提交前读取图片字节并转成图片 Data URL;Data URL 原样透传,`/generated-*` 和 generated OSS URL 先走 `/api/assets/read-url` 换签后由浏览器直读 OSS,直读失败时才 fallback 到 `/api/assets/read-bytes`,普通 public 路径直接 fetch。
- 验证:`npm run test -- src/services/image-editor/editorImageReference.test.ts src/components/image-editor/ImageCanvasEditorView.test.tsx -t "editorImageReference|converts non-data-url quick edit source images before submitting references"`。
- 关联:`src/services/image-editor/editorImageReference.ts`、`src/components/image-editor/ImageCanvasEditorView.tsx`、`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`。
- 现象:图片画布快速编辑、参考生成、去背景或角色动画提交 Data URL / Blob URL 时,前端或后端返回“必须先上传 OSS”。
- 原因:Data URL / Blob URL 体积大且不能作为持久引用;如果写入外部生成队列,请求体会膨胀,worker 也无法稳定复用浏览器临时资源。
- 处理:提交前优先复用图层已有 `objectKey`、项目资源 ID 或素材 ID;未登记的本地图片和普通 public 图片路径先通过 `resolveEditorGenerationMediaReference(...)` 读取并上传 OSS,再把稳定引用交给生成接口。Data URL 只允许用于浏览器内压缩、标注等临时处理,不能进入 API 请求、队列载荷或项目持久化。
- 验证:`npm run test -- src/services/image-editor/editorProjectClient.test.ts src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.test.tsx`;`cargo test -p api-server inline_data_url --manifest-path server-rs/Cargo.toml`。
- 关联:`src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.ts`、`src/services/image-editor/editorProjectClient.ts`、`server-rs/crates/api-server/src/editor_generation_queue.rs`、`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`。
## 图片编辑器角色动画不要默认提交大图 Data URL
## 图片编辑器角色动画必须提交稳定图片引用
- 现象:图片编辑器里对角色图点击 `生成动画` 后,后端返回 `Failed to buffer the request body: length limit exceeded`,请求还没进入角色动画 handler。
- 原因:角色动画生成请求曾把角色图片 `src` 原样作为 `sourceImageSrc` 放进 JSON;角色图如果是较大的 Data URL,会超过 Axum 默认 `2MB` body limit,在 `Json` 提取器阶段被拦截。
- 处理:前端在角色图已持久化时优先提交 `objectKey`,只把 Data URL 作为未持久化本地临时图兜底;后端 `/api/editor/character-animations/generations` 单独配置 `12MB` body limit 兼容旧请求,但新链路不应依赖传大图 JSON。
- 验证:`npm run test -- src/components/image-editor/ImageCanvasEditorView.test.tsx -t "only exposes character animation"`;`cargo test -p api-server editor_character_animation_accepts_character_image_body_above_default_limit --manifest-path server-rs/Cargo.toml`。
- 关联:`src/components/image-editor/ImageCanvasEditorView.tsx`、`server-rs/crates/api-server/src/modules/play_flow.rs`、`server-rs/crates/api-server/src/app.rs`、`docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md`。
- 现象:图片编辑器里对尚未上传的角色图点击 `生成动画` 后,前端或后端返回 `sourceImageSrc 必须先上传 OSS`。
- 原因:角色动画会进入外部生成队列,浏览器 Data URL / Blob URL 既不适合持久任务,也会放大 JSON 请求体。
- 处理:前端统一通过 `resolveEditorGenerationMediaReference(...)` 取得 `objectKey` 或画板资源引用;本地临时角色图必须先上传 OSS。后端在入队前同步拒绝内联媒体,不再通过放宽 body limit 兼容 Data URL。
- 验证:`npm run test -- src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.test.tsx`;`cargo test -p api-server editor_character_animation --manifest-path server-rs/Cargo.toml`。
- 关联:`src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.ts`、`server-rs/crates/api-server/src/character_animation_assets.rs`、`server-rs/crates/api-server/src/app.rs`、`docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md`。
## 图片编辑器角色动画抽帧不要采到视频尾点
@@ -328,11 +328,11 @@
- 验证:`npm run test -- src/services/assetReadUrlService.test.ts --reporter verbose` 应覆盖大量不同 objectKey 同时换签时首批限量放行、后续按间隔派发;发布现场同类页面刷新时,Nginx `GET /api/assets/read-url` 429 应从 `upstream_status=-` / `genarrative_api_rps` 收敛。
- 关联:`src/services/assetReadUrlService.ts`、`src/hooks/useResolvedAssetReadUrl.ts`、`src/components/ResolvedAssetImage.tsx`、`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`。
## 图片编辑器 Seedance 2.0 参考媒体不要提交视频 Data URL
## 图片编辑器 Seedance 2.0 参考媒体只提交稳定引用
- 现象:画板生成视频选择 Seedance 2.0 并上传参考视频后,请求体暴涨、可能返回 `413` 或上游拒绝 `video_url.url`;文档示例或测试如果写 `data:video/mp4;base64,...`,后续实现很容易照抄。
- 原因:火山 Seedance 2.0 参考视频只支持公网 URL 或 `asset://` 素材 ID,项目内画板资源应以 `objectKey` 由后端换签;视频不支持 Base64 / `data:video`,且 50MB 视频转 Base64 后会逼近或超过 64MB 请求体上限。参考音频虽然支持 Base64,但也不能单独输入,且大文件同样不应塞进 JSON。
- 处理:参考视频 / 音频上传先走 `/api/assets/direct-upload-tickets` 直传 OSS,再 `/api/assets/objects/confirm` 确认;前端保留 signed URL 做预览,提交生成时优先使用 `objectKey`。后端归一化必须拒绝 `data:video/*`,非 Seedance 模型携带参考字段也必须拒绝;Ark body 显式带 `generate_audio:false`。
- 原因:画板生成会进入持久队列,Base64 / Data URL / Blob URL 会放大请求和任务 JSON;直接签名客户端给出的 objectKey 又会绕过跨账号素材归属校验。项目资源 ID、素材 ID 和 objectKey 必须先解析到当前 owner 的正式对象,公网 URL 与 `asset://` 才能按供应商契约直接透传。
- 处理:本地参考图片 / 视频 / 音频先走 `/api/assets/direct-upload-tickets` 直传 OSS,再 `/api/assets/objects/confirm` 确认;前端保留 signed URL 做预览,提交生成时使用 `objectKey`、项目资源 ID 或素材 ID。后端归一化拒绝全部 `data:*` / `blob:*`,签名 OSS URL 前统一校验 owner;稳定引用字段总长度限制为 `256KB`,非 Seedance 模型携带参考字段也必须拒绝;Ark body 显式带 `generate_audio:false`。
- 验证:`npx vitest run src/components/image-editor/useImageCanvasUploadWorkflow.test.tsx src/components/image-editor/ImageCanvasGenerationSubmissionModel.test.ts src/services/image-editor/editorReferenceUploadClient.test.ts --reporter verbose`;`cargo test -p api-server editor_video --manifest-path server-rs/Cargo.toml`;`cargo test -p shared-contracts editor_video_request_supports_seedance_multimodal_references --manifest-path server-rs/Cargo.toml`。
- 关联:`src/services/image-editor/editorReferenceUploadClient.ts`、`src/components/image-editor/useImageCanvasUploadWorkflow.ts`、`src/components/image-editor/ImageCanvasGenerationSubmissionModel.ts`、`server-rs/crates/api-server/src/character_animation_assets.rs`、`docs/【编辑器】生成类面板Lovart统一改造方案-2026-06-17.md`。
File diff suppressed because one or more lines are too long
@@ -160,11 +160,11 @@
- 参考媒体只对 `seedance2.0-fast` / `seedance2.0` 开放;切换到 Kling 等非 Seedance 模型时,前端不提交 `referenceImageSrcs` / `referenceVideoSrcs` / `referenceAudioSrcs`,后端收到非 Seedance 参考字段必须拒绝。
- 多模态参考按火山 Seedance 2.0 文档限制:参考图片 0~9 张,参考视频 0~3 个,参考音频 0~3 段;音频不可单独输入,必须至少搭配 1 张参考图片或 1 个参考视频。
- 参考图片支持 URL / Base64 / `asset://` / 画板资源路径;格式为 jpeg、png、webp、bmp、tiff、gif、heic、heif,单张小于 30MB,请求体总大小不超过 64MB。
- 参考视频只支持 URL / `asset://` / 画板资源路径,不支持 Base64 / `data:video/*`;格式为 mp4、mov,单个文件不超过 50MB,单个时长 [2, 15] 秒,最多 3 个且总时长不超过 15 秒。
- 参考音频支持 URL / Base64 / `asset://` / 画板资源路径;格式为 wav、mp3,单个文件不超过 15MB,单个时长 [2, 15] 秒,最多 3 段且总时长不超过 15 秒。
- 前端上传参考视频 / 参考音频必须走 `/api/assets/direct-upload-tickets` 直传 OSS,再 `/api/assets/objects/confirm` 入库;前端状态保存 signed URL 供预览,同时保存 `objectKey` / `assetObjectId`,提交生成时优先使用 `objectKey`。
- 后端接收画板资源 `objectKey` 后统一重新签名为 Ark 可读 URL,再按文档构造 `content`:`image_url` + `role=reference_image`、`video_url` + `role=reference_video`、`audio_url` + `role=reference_audio`。
- 参考图片支持公网 URL、`asset://`、当前账号的 `objectKey`、项目资源 ID 或素材 ID;格式为 jpeg、png、webp、bmp、tiff、gif、heic、heif,单张小于 30MB,不接受 Base64 / Data URL / Blob URL。
- 参考视频支持公网 URL、`asset://`、当前账号的 `objectKey`、项目资源 ID 或素材 ID;格式为 mp4、mov,单个文件不超过 50MB,单个时长 [2, 15] 秒,最多 3 个且总时长不超过 15 秒,不接受 Base64 / Data URL / Blob URL。
- 参考音频支持公网 URL、`asset://`、当前账号的 `objectKey`、项目资源 ID 或素材 ID;格式为 wav、mp3,单个文件不超过 15MB,单个时长 [2, 15] 秒,最多 3 段且总时长不超过 15 秒,不接受 Base64 / Data URL / Blob URL。三类参考媒体最终提交的稳定引用字段总长度不得超过 `256KB`。
- 前端本地参考媒体必须走 `/api/assets/direct-upload-tickets` 直传 OSS,再 `/api/assets/objects/confirm` 入库;前端状态保存 signed URL 供预览,同时保存 `objectKey` / `assetObjectId`,提交生成时使用稳定引用。
- 后端接收 `objectKey`、项目资源 ID 或素材 ID 后,先解析并校验对象属于当前 owner,再重新签名为 Ark 可读 URL,并按文档构造 `content`:`image_url` + `role=reference_image`、`video_url` + `role=reference_video`、`audio_url` + `role=reference_audio`。
- 画板生成视频按静音 toggle 映射 Ark `generate_audio`:`sound=on` 时传 `true`,`sound=off` 时传 `false`,不能只依赖上游默认值。
- Seedance 2.0 文档提示不支持直接上传含真人人脸的参考图 / 视频;当前画板尚未做真人脸授权证明、来源声明或服务端人脸拦截,后续开放真人素材前必须补授权/来源确认链路。
@@ -147,9 +147,9 @@
### Prompt 与生成契约
- 前端提交到 `POST /api/editor/character-animations/generations`。
- 请求必须带上角色图片来源、原始尺寸、动画描述、分辨率、画面比例、帧数和时长,并可通过 `assetFolderId` 指定中间视频素材落点。角色图片已经持久化到 OSS 时,`sourceImageSrc` 必须优先传 `objectKey`;只有未持久化的本地临时图片才允许传 Data URL。
- 请求必须带上角色图片来源、原始尺寸、动画描述、分辨率、画面比例、帧数和时长,并可通过 `assetFolderId` 指定中间视频素材落点。`sourceImageSrc` 只允许传当前账号的 `objectKey`、项目资源 ID 或素材 ID;未持久化的本地临时图片必须先上传 OSS,不能提交 Data URL 或 Blob URL。后端解析稳定引用后必须校验对象属于当前 owner,再读取 OSS 内容。
- 后端使用角色图片作为首帧和尾帧参考,模型固定映射到 `doubao-seedance-2-0-fast-260128`。
- 后端路由兼容旧 Data URL 请求并单独放宽 JSON body limit 到 `12MB`,但该限额只作为兼容兜底,不作为新链路默认传大图的方式。
- 后端在内联执行和队列入队前都会拒绝 Data URL / Blob URL;路由使用默认 JSON body limit,不再为内联图片请求单独放宽。
- 后端 prompt 使用以下固定骨架,并把面板输入追加到 `动作描述:` 后:
```text