Files
TrueGrowth/openspec/changes/archive/2026-04-29-add-music-analyzer-suno-edit-actions/design.md

119 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Context
当前音频生成链路已经支持:
- `music``lyrics` 两类 Suno 提交动作
- 统一通过 `/suno/submit/music``/suno/submit/lyrics` 提交
- 统一通过 `/suno/fetch/{task_id}` 轮询
- 将音乐结果标准化为 `primaryClipId / clipIds / clips`
同时,项目已有两个关键前提:
- 爆款音乐工具倾向使用统一工作流,而不是拆散成多个独立工具
- `clip_id` 才是 Suno 续写所需的真实片段标识,不能退化成列表层的 `id`
## Goals / Non-Goals
- Goals:
- 在统一表单中支持新生成、续写、Infill 三类音乐动作
- 根据动作自动约束和显隐 `continue_clip_id / continue_at / infill_start_s / infill_end_s`
- 把轮询里发现的 `clip_id` 串到续写和 Infill 请求
- 尽量复用现有 `/suno/submit/music` 与轮询标准化逻辑
- Non-Goals:
- 本次不引入新的独立音乐编辑工具
- 本次不实现 clip 拼接 `concat`
- 本次不实现音频波形编辑器
## Decisions
- Decision: 统一入口 + 动作切换
-`GeneratePage` 中增加动作枚举,例如 `generate | continue | infill`
- 表单仍保持单页结构,但根据动作切换展示不同字段
- Decision: 参数按动作严格约束
- `generate`
- 使用 `prompt / title / tags / mv`
- 不发送 `continue_clip_id / continue_at / infill_start_s / infill_end_s`
- `continue`
- 必须有 `continue_clip_id`
- 必须有 `continue_at`
- 可继续使用 `prompt / title / tags / mv`
- 不发送 `infill_start_s / infill_end_s`
- `infill`
- 必须有 `continue_clip_id`
- 必须有 `continue_at`
- 必须有 `infill_start_s / infill_end_s`
- 要求 `infill_start_s < infill_end_s`
- Decision: 续写目标优先来自已生成片段
- 每个 `GeneratedClip` 必须稳定保存轮询得到的真实 `clip_id`
- 点击片段上的“续写 / Infill”入口时自动把目标 `clip_id` 带入表单
- 若当前任务还没有真实 `clip_id`,则禁止进入续写动作
- Decision: 仍走同一 Suno submit 接口
- 三种动作都沿用 `POST /suno/submit/music`
- 通过 body 中是否携带 `continue_clip_id / continue_at / infill_start_s / infill_end_s` 决定服务端行为
## Data Model
```ts
type SunoMusicEditAction = 'generate' | 'continue' | 'infill';
interface MusicAnalysisRecord {
continueFromClipId?: string | null;
continueAt?: number | null;
infillStartS?: number | null;
infillEndS?: number | null;
musicEditAction?: SunoMusicEditAction | null;
}
interface AudioGenerationRequest {
prompt: string;
title?: string;
tags?: string;
mv?: string;
continueClipId?: string;
continueAt?: number;
params?: {
infillStartS?: number | null;
infillEndS?: number | null;
};
}
```
## UI Strategy
- 在“爆款音乐生成 -> 生成”页面增加动作切换区:
- `新生成`
- `续写`
- `Infill`
- 在已生成片段卡片上增加快捷入口:
- `续写`
- `Infill`
- 字段展示策略:
- `新生成`:标题 / 风格标签 / 歌词 / 版本 / 调用次数
- `续写`:目标片段 / 续写起点秒数 / 标题 / 风格标签 / 歌词 / 版本 / 调用次数
- `Infill`:目标片段 / 续写起点秒数 / Infill 开始秒数 / Infill 结束秒数 / 标题 / 风格标签 / 歌词 / 版本 / 调用次数
- 表单校验失败时,错误提示继续贴近提交按钮
## Risks / Trade-offs
- 风险:统一表单状态过多,切动作时容易串值
- Mitigation将动作相关字段单独建模并在切换动作时只保留兼容字段
- 风险:用户不知道 `continue_at``infill_start_s/end_s` 的区别
- MitigationUI 文案明确区分“续写起点”和“局部重绘窗口”
- 风险:早期轮询返回有 `clip_id`、最终结果缺 `clip_id`
- Mitigation在轮询层缓存并回填真实 `clip_id`
## Open Questions
- 是否需要在第一版允许手动输入 `continue_clip_id`,还是只允许从已生成片段选择
- 是否要在统一表单中直接支持“续写完成后自动拼接完整音频”,还是留到后续 `concat` 能力再做