fix: delay wooden fish audio upload
This commit is contained in:
81
docs/test-cases/【测试用例】敲木鱼音频延迟上传与本地标准化-2026-06-06.md
Normal file
81
docs/test-cases/【测试用例】敲木鱼音频延迟上传与本地标准化-2026-06-06.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# 敲木鱼音频延迟上传与本地标准化测试用例
|
||||
|
||||
## 覆盖目标
|
||||
|
||||
- 选择上传或录音结束后只在浏览器本地处理,不请求 OSS 上传凭证。
|
||||
- 用户点击 `生成` 时才上传处理后的音频 Blob/File,并把确认后的 `WoodenFishAudioAsset` 放入创建 session payload。
|
||||
- 上传和录音统一执行前后声音过小片段裁切、最长 1 秒限制、近似 `-15 LKFS` 响度平衡和峰值保护。
|
||||
- 音频面板明确显示 `最长 1 秒`,并正确处理上传、录音、重置、禁用和错误状态。
|
||||
- OSS 上传 client 只接收 Blob/File,不接受 Data URL,并覆盖上传凭证、OSS POST、资产确认和错误分支。
|
||||
|
||||
## 音频处理 helper
|
||||
|
||||
- 空文件:`size=0`,报 `音频文件为空,请重新选择。`
|
||||
- 非音频 MIME:`text/plain`,报 `请选择音频文件。`
|
||||
- 浏览器没有 `AudioContext`:报 `当前浏览器不支持音频处理。`
|
||||
- `decodeAudioData` 失败:报 `音频解码失败,请重新选择。`
|
||||
- 全静音或声音全低于阈值:报 `音频声音过小,请重新录制或上传。`
|
||||
- 前后静音裁切:低于阈值的头尾帧被裁掉,`startFrame` 和 `frameCount` 正确。
|
||||
- 裁切后刚好 `1000ms`:允许通过。
|
||||
- 裁切后超过 `1000ms`:报 `音频最长 1 秒。`
|
||||
- 上传来源 `uploaded` 与录音来源 `recorded`:返回 pending asset 保留对应 source。
|
||||
- 原文件名有扩展名:输出 `.wav` 文件名;无扩展名补 `.wav`;空白文件名输出 `creative-audio.wav`。
|
||||
- `URL.createObjectURL` 存在:`audioSrc` / `previewUrl` 为 blob URL;不存在时返回空字符串且不阻断处理。
|
||||
- 近似响度平衡:低 RMS 样本被拉向 `-15 LKFS` 目标。
|
||||
- 峰值保护:高峰值样本增益后不超过 `peakCeiling`。
|
||||
- 零能量 section:归一化阶段报声音过小。
|
||||
- WAV 编码:写入 RIFF/WAVE/data header、PCM16 数据长度和采样值。
|
||||
|
||||
## 音频输入面板
|
||||
|
||||
- 传入 `limitLabel` 时显示 `最长 1 秒`;未传入时不显示限制标签。
|
||||
- 无资产时显示默认音效文案。
|
||||
- 有资产且 `audioSrc` 存在时渲染 `<audio controls>`。
|
||||
- 有资产但无 `audioSrc` 时显示 `音效已选择`。
|
||||
- 点击重置调用 `onAssetChange(null)`。
|
||||
- 上传取消选择时不读取音频、不写入资产。
|
||||
- 上传成功后调用 `readFileAsAsset(file, 'uploaded')`,清空错误并写入资产。
|
||||
- 上传失败时展示错误,不写入资产。
|
||||
- 浏览器不支持录音时提示 `当前浏览器不支持录音。`
|
||||
- 麦克风启动失败时透传启动错误。
|
||||
- 录音停止后把 Blob 包成 File,并以 `recorded` 来源读取。
|
||||
- 录音保存失败时展示错误。
|
||||
- disabled 状态不启动录音,文件输入禁用。
|
||||
|
||||
## 木鱼工作台链路
|
||||
|
||||
- 音频面板显示 `最长 1 秒`,并只保留上传和录音入口。
|
||||
- 选择上传音频后只调用本地处理 helper,不调用 `uploadWoodenFishHitSoundAsset`。
|
||||
- 点击 `生成` 且有 pending 音频时,先上传处理后的 WAV,再调用 `woodenFishClient.createSession`。
|
||||
- 上传给 OSS 的文件是处理后的 WAV,文件名和 MIME 为 `.wav` / `audio/wav`。
|
||||
- 提交 payload 使用 OSS confirmed asset,不包含 `data:audio`。
|
||||
- 未选择音频时不上传 OSS,payload 使用默认木鱼音。
|
||||
- 处理阶段报超过 1 秒时展示错误,不写入用户音频;继续生成时走默认木鱼音。
|
||||
- OSS 上传失败时停留工作台,展示错误,不创建 session。
|
||||
- `createSession` 失败时停留工作台,展示错误。
|
||||
- 提交中重复点击 `生成` 不重复上传、不重复创建 session。
|
||||
- 替换本地音频时回收旧 `previewUrl`。
|
||||
|
||||
## 木鱼音频上传 client
|
||||
|
||||
- 空 Blob/File、超过 20MB、非音频 MIME 均在本地拒绝,不创建上传凭证。
|
||||
- File 上传默认使用 `file.name` 和 `file.type`。
|
||||
- Blob 上传支持通过显式文件名扩展推断 `audio/wav` 等音频 MIME。
|
||||
- Blob 缺少 MIME 且扩展未知时拒绝上传。
|
||||
- direct upload ticket 请求包含 `legacyPrefix`、path segments、fileName、contentType、access、maxSizeBytes 和木鱼音频 metadata。
|
||||
- OSS POST 成功后调用 `/api/assets/objects/confirm`。
|
||||
- OSS POST 非 2xx 时提示 `上传敲击音效失败。`,不确认资产对象。
|
||||
- confirm 失败时透传确认错误。
|
||||
- confirm 请求包含 bucket、objectKey、contentType、contentLength、assetKind、accessPolicy 和 entityId。
|
||||
- 成功返回的 `WoodenFishAudioAsset` 包含 assetObjectId、audioObjectKey、audioSrc、source 和 prompt。
|
||||
|
||||
## 验证命令
|
||||
|
||||
```bash
|
||||
npm run test -- src/components/common/creativeAudioProcessing.test.ts
|
||||
npm run test -- src/components/common/CreativeAudioInputPanel.test.tsx
|
||||
npm run test -- src/components/unified-creation/workspaces/WoodenFishCreationWorkspace.test.tsx
|
||||
npm run test -- src/services/wooden-fish/woodenFishAssetClient.test.ts
|
||||
npm run typecheck
|
||||
npm run check:encoding
|
||||
```
|
||||
@@ -174,7 +174,7 @@ npm run check:server-rs-ddd
|
||||
- Match3D 1:1 容器 UI:VectorEngine `/v1/images/edits` multipart 参考图。该容器参考图是后端生图协议输入,必须通过 `include_bytes!` 随 `api-server` 编译进二进制,避免 API 单独发布或运行目录缺少 `public/` 时生成失败。
|
||||
- 敲木鱼敲击物和背景环境图:VectorEngine `/v1/images/edits`,模型固定 `gpt-image-2`。敲击物支持 multipart 多参考图,第一张固定为后端内嵌默认木鱼图,用户上传图只作为新主题参考;prompt 必须要求 `1:1` 真实透明 alpha PNG 并禁止黑底、白底、棋盘格和任何实底背景。当前敲击物上传 OSS 前不做服务端抠图后处理,避免误伤玉米等主体像素。背景环境图只使用第一步抠图完成后的透明敲击物图作为参考,prompt 必须要求中央主体预留区保持干净,中央 40% 区域禁止出现主题主体、主体局部特写、轮廓影子或重复元素,主题元素只能作为外围氛围,且必须显式声明不继承任何绿色底色、绿幕底色或纯绿色画布。
|
||||
- Hyper3D / Rodin:只保留后端安全代理和旧数据兼容;Rodin 提交、状态、下载和响应解析归属 `platform-hyper3d`,`api-server/src/hyper3d_generation.rs` 只做路由、配置和错误 envelope 映射;新 Match3D 草稿和批量新增不再生成 GLB。
|
||||
- 音频:视觉小说专用音频路由保留;VectorEngine Suno/Vidu provider 协议、任务提交/查询、音频 URL 提取、下载、MIME/extension 归一和 OSS put 请求准备归属 `platform-audio`。`api-server/src/vector_engine_audio_generation.rs` 只做路由、配置、计费、asset object confirm、entity binding 和错误 envelope 映射;拼图、抓大鹅和敲木鱼提示词生成音效入口暂时关闭,通用 `/api/creation/audio/*` 对这些目标返回 `410 Gone`。敲木鱼创作只接收上传 / 录音音频资产;未提供时由 `api-server` 写回内置默认木鱼音 `/wooden-fish/default-hit-sound.mp3`。
|
||||
- 音频:视觉小说专用音频路由保留;VectorEngine Suno/Vidu provider 协议、任务提交/查询、音频 URL 提取、下载、MIME/extension 归一和 OSS put 请求准备归属 `platform-audio`。`api-server/src/vector_engine_audio_generation.rs` 只做路由、配置、计费、asset object confirm、entity binding 和错误 envelope 映射;拼图、抓大鹅和敲木鱼提示词生成音效入口暂时关闭,通用 `/api/creation/audio/*` 对这些目标返回 `410 Gone`。敲木鱼创作只接收上传 / 录音音频资产;前端选择或录音阶段只在浏览器本地处理待提交音频,统一限制裁切后最长 1 秒、裁掉前后声音过小片段,并用浏览器端近似响度算法平衡到 `-15 LKFS` 后做峰值保护。点击生成时才直传 OSS 并确认 `asset_object`,创作 JSON 只提交轻量 `WoodenFishAudioAsset`,不得继续上传 Data URL 音频;未提供时由 `api-server` 写回内置默认木鱼音 `/wooden-fish/default-hit-sound.mp3`。
|
||||
- OSS:私有 generated legacy path 进入浏览器前必须通过 `/api/assets/read-url` 换签;不要裸请求 `/generated-*`。OSS 签名、读签名、HEAD 和 PUT 的结构化日志由 `platform-oss` 输出,排查资产写入 / 确认失败时优先按 `operation`、`object_key` / `key_prefix`、`status_class`、`error_kind` 和 `elapsed_ms` 下钻。
|
||||
- 外部 API 失败审计:外部供应商调用未成功时,`api-server` 必须发送 OTLP 失败事件并写入 `tracking_event`。VectorEngine 图片 provider 在 `platform-image` 内输出结构化日志和 `PlatformImageFailureAudit`,覆盖 `request_send`、`response_body`、`upstream_status`、`response_parse`、`missing_image` 和 `image_download` 阶段;`api-server` 只把该 audit 映射成 `external_api_call_failure`,`scope_kind = module`、`scope_id = provider`、`module_key = external-api`。metadata 固定包含 provider、endpoint、operation、failureStage、statusCode、statusClass、timeout、retryable、errorMessage、latencyMs、promptChars、referenceImageCount、imageModel、rawExcerpt,以及在调用方可获得上下文时补充的 `userId`(触发者)和 `profileId`(草稿 / 作品 / 场景作用域)。图片生成入口应优先把 owner user id 和 profile id 透传到失败审计,不要只保留 provider 级聚合,否则很难按“谁触发、哪个作品触发”定位问题。入库优先复用 tracking outbox,outbox 不可写或保护阈值拒绝时回退同步写 SpacetimeDB;不得新增前端兜底或在 SpacetimeDB reducer 内做外部 I/O。
|
||||
- 外部生成运行记录:所有外部生成编排的完成态统一写入 `tracking_event`,`event_key = external_generation_run`,`scope_kind = module`,`scope_id = provider`,`module_key = external-generation`。metadata 固定包含 `runId`、`provider`、`operation`、`requestLabel`、`requestPayload`、`status`、`success`、`failureReason`、`providerRequestId`、`resultPayload`、`startedAtMicros`、`completedAtMicros` 和 `durationMs`。这类记录只用于运行审计和排障,不再走 `ai_task` 旧表。
|
||||
|
||||
@@ -188,7 +188,7 @@ RPG / 拼图等运行态存档仍以 `/api/profile/save-archives` 的后端列
|
||||
创作输入固定为:
|
||||
|
||||
1. `敲什么`:敲击物单图资产槽位。默认模板使用内置透明 PNG `/wooden-fish/default-hit-object.png` 作为 `bundled-default` 敲击物资产,避免默认关键词被重新语义化改形;用户输入自定义关键词或上传参考图时,后端必须以默认木鱼图作为基础结构和画风参考,使用 image2 生成最终敲击物图案,上传图只作为新主题参考,不直接进入运行态。自定义 `compile-draft` / `regenerate-hit-object` 必须完成 image2 -> OSS 私有对象 -> asset object 登记和绑定后,再由 `api-server` 注入真实 `hitObjectAsset.imageSrc`,不能只写 `/generated-wooden-fish-assets/...` 占位路径,也不能接受前端请求自带的 `hitObjectAsset` 短路生成。
|
||||
2. `敲击音效`:音频资产槽位,当前创作阶段只支持用户上传或麦克风录制;麦克风录制结束后,前端会自动裁掉音频开头连续静音段,再把裁剪后的录音作为 `recorded` 音频资产写入表单。上传音频不做裁剪;浏览器音频解码或裁剪失败时保留原始录音继续保存,不能让用户录音丢失。未提供音频时统一写回内置默认木鱼音 `/wooden-fish/default-hit-sound.mp3`。提示词生成音效入口临时关闭,通用 `/api/creation/audio/sound-effect` 对木鱼 `hit_sound` 目标也返回 `410 Gone`;`hitSoundPrompt` 只作为历史兼容字段保留,不参与当前创作流程,也不得由 `spacetime-client` 合成假音频路径。
|
||||
2. `敲击音效`:音频资产槽位,当前创作阶段只支持用户上传或麦克风录制;音频面板必须在前端明确显示 `最长 1 秒`。选择文件或录音结束后,前端只在浏览器本地解码并生成待提交音频对象,不在选择阶段请求 `/api/assets/direct-upload-tickets`。上传和录音统一裁掉前后声音过小片段,裁切后仍超过 1 秒时提示错误且不写入表单状态;有效音频按浏览器端近似算法做响度平衡,目标为 GY/T 377-2023 口径下的 `-15 LKFS`,并做峰值保护后重新编码为可上传 Blob。用户点击 `生成` 时才把处理后的音频直传 OSS、确认 `asset_object`,创作 session/action 只提交 `hitSoundAsset.assetObjectId`、`audioSrc` 和对象 key 等轻量字段;未提供音频时统一写回内置默认木鱼音 `/wooden-fish/default-hit-sound.mp3`。提示词生成音效入口临时关闭,通用 `/api/creation/audio/sound-effect` 对木鱼 `hit_sound` 目标也返回 `410 Gone`;`hitSoundPrompt` 只作为历史兼容字段保留,不参与当前创作流程,也不得由 `spacetime-client` 合成假音频路径。后端对敲木鱼创作 JSON 的放宽 body limit 仅用于兼容旧小程序 Data URL 请求,不作为新链路输入方式。
|
||||
3. `功德有什么`:最多 8 条飘字,创作态首屏只保留一个默认词条 `幸运`,其下提供加号格继续追加词条;创作态只保存词条名,运行态飘字展示时再追加 `+1`。运行态顶部总数卡采用品牌化徽标样式,子项计数器预置展示在可展开面板中,未出现词条初始值为 0。
|
||||
4. `作品标题 / 作品简介 / 主题标签`:不再放在创作工作台首屏,改为生成草稿后的结果页补录区,提交试玩或发布前必须先写回当前作品信息。主题标签编辑样式对齐拼图结果页的胶囊标签编辑器。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user