Files
TrueGrowth/openspec/changes/add-audio-generation-suno-routing/design.md

256 lines
7.0 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
`opentu` 当前的生成体系围绕三类模态构建:
- `text`
- `image`
- `video`
这三个模态已经贯穿以下层级:
- `model-config` 中的静态模型类型
- `settings-manager` 中的默认路由 preset
- `provider-routing` 中的 operation 与 binding
- `model-adapters` 中的适配器接口
- `task-queue` 与历史记录中的任务类型与结果结构
- `AIInputBar` 与设置页中的模型/模式切换
因此“增加音频层”并不是简单地再加一个 UI 选项,而是需要把音频模态接入整条调用链。
Suno 的特殊点在于,它暴露的是一组能力动作,而不是一组可以直接照抄提交的模型:
- 发现能力示例:
- `suno_music`
- `suno-continue`
- `suno-continue-uploaded`
- `suno-remix`
- `suno-remix-uploaded`
- `suno-infill`
- `suno-lyrics`
- `suno-tags`
- `suno_act_tags`
- `suno_act_timing`
- 真实音乐生成提交接口:
- `POST /suno/submit/music`
- 真实版本切换字段:
- `mv`
- 真实状态查询接口:
- `GET /suno/fetch/{task_id}`
因此,如果把 `suno_music` 这类标识直接当成“可调用模型 ID”最终会出现两个问题
1. UI 上看到的能力动作和请求里真正需要的 `mv`、续写参数混在一起
2. 运行时发现层与执行层之间失去稳定映射
## Goals / Non-Goals
- Goals:
-`opentu` 增加一等音频生成模态
- 为 Suno 建立“能力动作 -> 执行规则 -> 版本参数”的明确映射
- 复用现有多供应商路由和任务轮询思路,而不是单独再造一套音频系统
- 先跑通音乐生成和单任务查询闭环
- Non-Goals:
- 本次不一次性覆盖 Suno 全量能力
- 本次不实现完整的画布音频后处理编辑器
- 本次不让发现到的所有 Suno 能力都自动出现在 UI 主路径中
## Decisions
- Decision: 引入 `audio` 作为一等模态
- `ModelType``GenerationType``TaskType``ProviderOperation`、默认 preset 都增加 `audio`
- 音频不再借用文本或视频通道透传
- Decision: 区分“能力动作”和“执行版本”
- `suno_music``suno-continue` 等发现项表示能力或操作入口
- `mv` 表示真实执行使用的 Suno 版本,例如 `chirp-v3-0``chirp-v3-5`
- 续写上传场景通过 `mv + '-upload'` 表达
- Decision: Suno 初始切片只做 `music submit + fetch`
- 首批只支持 `POST /suno/submit/music`
- 首批只支持 `GET /suno/fetch/{task_id}`
- 其余 Suno 动作先作为已发现但未激活的能力保留在元数据层
- Decision: UI 不直接展示所有发现能力
- 用户主路径先暴露统一的 `音频` 模式
- 进入音频模式后,再根据绑定能力展示当前支持的生成方式和字段
- 避免让用户直接面对一串 `suno-*` 能力代号
- Decision: 任务轮询采用 provider-specific 标准化
- `/suno/fetch/{task_id}` 返回的 `status/progress/data` 需要统一转换成内部任务状态
- 不能强制复用视频任务的原始响应结构
## Proposed Data Model
```ts
type ModelType = 'text' | 'image' | 'video' | 'audio';
type SunoAction =
| 'music'
| 'continue'
| 'continue-uploaded'
| 'lyrics'
| 'tags'
| 'remix'
| 'remix-uploaded'
| 'infill'
| 'infill-uploaded';
interface ProviderAudioBindingMetadata {
action: SunoAction | string;
versionField?: string;
versionOptions?: string[];
defaultVersion?: string;
supportsContinuation?: boolean;
supportsUploadContinuation?: boolean;
supportsLyricsPrompt?: boolean;
supportsTags?: boolean;
supportsTitle?: boolean;
taskIdField?: string;
resultAudioUrlPath?: string;
}
interface AudioGenerationRequest {
prompt: string;
model?: string;
modelRef?: ModelRef | null;
title?: string;
tags?: string;
mv?: string;
continueClipId?: string;
continueAt?: number;
params?: Record<string, unknown>;
}
interface AudioGenerationResult {
url: string;
title?: string;
duration?: number | null;
waveformUrl?: string;
raw?: unknown;
}
```
## Suno Binding Strategy
### Capability Layer
发现层保留原始能力标识,例如:
- `suno_music`
- `suno-continue`
- `suno-continue-uploaded`
- `suno-lyrics`
- `suno-tags`
这些标识用于:
- 推断该 profile 是否支持音频
- 推断该 profile 支持哪些音频动作
- 决定 UI 允许展示哪些高级入口
### Execution Layer
执行层不直接按发现能力 ID 发请求,而是映射成:
- `submitPath`
- `pollPathTemplate`
- `action`
- `mv` 规则
- 字段可用性
例如首批音乐生成统一映射为:
```ts
{
operation: 'audio',
protocol: 'tuzi.suno.music',
submitPath: '/suno/submit/music',
pollPathTemplate: '/suno/fetch/{task_id}',
metadata: {
audio: {
action: 'music',
versionField: 'mv',
versionOptions: ['chirp-v3-0', 'chirp-v3-5'],
defaultVersion: 'chirp-v3-5',
supportsContinuation: true,
supportsUploadContinuation: true,
supportsTags: true,
supportsTitle: true,
supportsLyricsPrompt: true
}
}
}
```
当用户选择“续写已上传音频”时,不改 submitPath而是通过 metadata 规则把:
- `mv=chirp-v3-5`
转换为:
- `mv=chirp-v3-5-upload`
## UI Strategy
### Settings
- 在默认路由 preset 中增加 `audio`
- 音频默认路由保存 `ModelRef`
- 如果当前 provider profile 未发现音频能力,则不允许被选为音频默认路由
### AI Input Bar
- 增加 `音频` 模式
- 进入音频模式后,参数区支持:
- `mv`
- `title`
- `tags`
- `continue_clip_id`
- `continue_at`
- 默认交互仍保持与图片/视频一致:
- 选择模型
- 输入提示词
- 提交任务
### Task And History
- 任务类型增加 `audio`
- 历史记录支持展示音频结果
- 结果结构至少包含:
- 音频 URL
- 标题
- 创建时间
- 执行状态
## Migration Plan
1. 先补核心类型层和 preset 路由层的 `audio`
2. 再补 provider routing / adapter / service 的 Suno 音频闭环
3. 再补 AI 输入栏和设置页入口
4. 最后补任务列表、历史记录和结果回显
## Risks / Trade-offs
- 风险: 音频能力切入口过大,影响现有图片/视频链路
- Mitigation: 首批只做 `music submit + fetch`,不扩张到所有 Suno 动作
- 风险: 发现能力与执行规则混在一起,导致后续高级动作难扩展
- Mitigation: 明确拆分 capability layer 和 execution layer
- 风险: UI 直接暴露 `suno-*` 原始能力名,增加理解成本
- Mitigation: 主路径只暴露 `音频` 模式和人类可理解的操作标签
- 风险: 音频结果结构与视频结果结构不同,历史记录复用成本高
- Mitigation: 在 `TaskResult` 中增加音频最小字段集,而不是强行套用视频字段
## Open Questions
- 首批是否需要同时支持“仅生成纯音乐”和“包含人声/歌词”的 UI 开关
- `suno_lyrics``suno_tags` 是否应该作为后续独立工具,还是继续作为音乐生成前的辅助步骤
- 音频结果进入画布后,第一版是否只作为可播放资源卡片,而不引入完整音频节点编辑器