已被取代(2026-06-25) 参见 00-roadmap-elevenlabs-parity.md 与规范 01–03。保留以作历史参考。
Stories Editor 与 Audiobook — 成熟度规范¶
汇编于 2026-06-13。目标为 v0.3.x continuous-to-main 开发线。以下每个工作项均以上述两个功能的当前实现为基准(文件:行号引用见下文)。
0. TL;DR — 核心决策¶
Stories Editor 和 Audiobook 是同一任务的两个创作前端: 分章节长篇幅 TTS → 带章节标记的音频文件。目前它们构建在迥异的技术栈上,而这种分歧正是大多数成熟度差距的根源:
| Stories Editor | Audiobook | |
|---|---|---|
| 渲染 | 客户端 Web Audio 拼接(逐 chunk decodeAudioData,在内存中 concat) |
服务端 GPU 池 → ffmpeg .m4b |
| 状态 | 仅 localStorage(omnivoice.app) |
尽力而为的 job_store,退出即丢弃 |
| 优势 | 多角色对白、逐行音色/语速、自动选角 | 章节标记、SSE 进度、可扩展到长书 |
| 上限 | 无法渲染 10 小时的长书(浏览器内存、无恢复、无响度标准化) | 单一文本域,无封面/元数据,无预览/重试/恢复 |
建议:收敛到一个服务端章节化渲染核心;保留两个不同的创作前端。 Stories Editor 的 “Generate full” 会将其 cast/台词编译为 Audiobook 后端已在使用的同一 Chapter[]/Span[] 模型,并提交同一任务。这消除了重复工作,解除了 Stories 在浏览器端的规模上限,并且让两个功能免费获得恢复、响度标准化、封面和元数据。
Stories 保留快速的客户端单行预览(低延迟、无任务开销)。只有完整导出迁移到服务端。
考虑的替代方案: 将两者完全分离,各自独立成熟。已否决——这会使工作量翻倍(两套元数据系统、两条标准化路径、两套恢复机制),并让 Stories 永远无法渲染整本书长度的输出。如果负责人希望保持分离,则仅适用 §2 + §3 前端部分,并放弃 §1。
1. 共享渲染核心(新)— 后端¶
新模块 backend/services/longform_render.py,对 audiobook 管线进行泛化(该管线已有正确的形态)。
- 规范任务模型(已存在于
backend/services/audiobook.py:47-86):Project → Chapter(title, spans) → Span(voice_id, text, pause_ms_after)。将其提升至此模块;Audiobook 与 Stories 都编译为该模型。 - 复用
synthesize_chapter(audiobook.py:140)、build_chapter_ffmetadata(:186)、build_concat_list(:207)、build_m4b_cmd(:221)。将build_*_cmd泛化,使其接受 metadata + cover + format。 - 新增能力(每项都是一个独立、可测试的纯构建器 + 接入步骤):
- 全局元数据 → FFMETADATA
[global]:title、artist(作者)、album、composer/narrator、date(年份)、genre、comment。 - 封面图 → ffmpeg
-i cover.jpg -map 2 -disposition:v attached_pic(MP4COVR)。在服务端校验图片(大小/类型)。 - 响度标准化 → 两遍 ffmpeg
loudnorm,使用 ACX 预设(目标 ≈ -19…-21 LUFS 综合响度,≤ -3 dB 真实峰值,噪底 < -60 dB)。开关 + 预设(ACX/Podcast -16 LUFS/Off)。 - 逐章节检查点 / 恢复:以
hash(span_texts + voice_ids + pauses + engine + voice refs)为键缓存每个已渲染章节的 WAV。重试时,跳过哈希已有缓存 WAV 的章节 → 在不重新渲染已完成章节的情况下恢复失败/长任务。 - 并行章节合成:将章节并发提交到现有
_gpu_pool(受池大小限制),而非严格串行。 - 输出格式:
m4b(带章节的 AAC,当前支持)、mp3(通过 ID3 CHAP 帧带章节)、per-chapter files(zip)、stems(每个音色一条音轨 —— Stories 现有的 stems 概念,服务端实现)。 - 任务持久化 / 库:新增 alembic 表
longform_jobs(id、kind=audiobook|story、title、status、output_path、chapters JSON、metadata JSON、created_at)。完成的书/故事会重新出现在项目/库中,并可再次下载。向后兼容迁移(增量表)。
2. Audiobook 标签页 — 成熟度(前端 + 轻量后端)¶
锚点:frontend/src/pages/AudiobookTab.jsx、frontend/src/api/audiobook.ts、backend/api/routers/audiobook.py、backend/services/audiobook.py。
P0
- 元数据面板:标题、作者、朗读者、年份、类型、描述、封面图片选择器。接入 §1.1/§1.2。
- 逐章节预览:渲染单个章节(新增 POST /audiobook/preview,复用 synthesize_chapter),让用户在提交整本书之前先试听。
- 章节级重试:章节失败不会终止整个任务;将其标记,让用户只重跑该章节(利用 §1.4 的检查点)。
- 恢复:重新连接/重启中断的任务,跳过已缓存章节。
- 响度标准化开关(ACX 预设默认关闭;需显式选择启用)。
P1
- 导入 → 自动分章:.txt(按 # H1 / ^Chapter \d+ 切分)、EPUB(spine + TOC → 章节;本地解析,无需网络)、拖放文件。
- 发音词典:按项目设置 word→phoneme/重拼覆盖,在合成前应用(与 Stories 共享)。
- ETA + 更丰富的进度(已完成章节数/总数、已用时间、预计剩余时间)。
P2
- SSML-lite([emphasis]、[slow]/[fast]、[spell])映射到引擎 instruct + 分块速率。批处理(排队多本书)。
3. Stories Editor — 成熟度(前端 + 后端)¶
锚点:frontend/src/components/StoriesEditor.jsx(749 行单体)、frontend/src/store/storiesSlice.ts、frontend/src/utils/storyExport.js、frontend/src/utils/parseScript.js。
P0
- 将 “Generate full” 迁移到共享服务端任务(§1)。新增 storyToSpans() 编译器:cast + 台词 + [voice:]/[pause] 标记 → Chapter[]/Span[]。storyExport.js 缩减为仅预览(保留 StoriesEditor.jsx:271-322 处流畅的客户端单行播放)。
- 逐行重新生成(目前只有完整导出存在)。
- 中止/取消进行中的导出(目前循环没有中止信号)。
- 将情绪/语气字段接通到 instruct(storiesSlice.ts:17 “Phase 3” 桩代码;语气标签会插入文本标记,但从未进入合成环节)。
P1
- 组件拆分:CastPanel.jsx / StoryLine.jsx / LineDrawer.jsx
(已在 docs/superpowers/specs/2026-05-30-stories-editor-studio-design.md 中标注)。
- 逐行波形 + 时长缩略图。
- 带标记的分章 M4B 导出(复用 §1;Stories 已在 StoriesEditor.jsx:46 检测 # 章节行)。
- 可选的服务器持久化项目(DB),使大型演员阵容/长脚本突破 localStorage 限制;惰性迁移现有 localStorage 项目。
P2 - EPUB/剧本导入打磨;更丰富的自动选角(性别/声音匹配)。
4. 跨领域关注点¶
- 响度标准化、元数据+封面、续播/检查点、并行合成均位于 §1,并被两个功能共同使用——只需构建一次。
- 发音词典共享服务(用于 Audiobook P1 + Stories)。
- DB:通过 alembic 新增
longform_jobs(+ 可选的story_projects),采用增量式、经过测试的升级路径。现有omnivoice_data/和 localStorage 不受影响。 - i18n:在
audiobook.*和stories.*下新增键;不硬编码 CJK。 - 测试:扩展
tests/test_audiobook.py—— loudnorm argv(两遍处理形态)、全局元数据 + 封面 ffmeta/argv、storyToSpans()编译器、续播跳过(缓存章节哈希 → 跳过)、EPUB→章节解析。前端:元数据面板、逐行重新生成、中止。
5. 遵守的约束¶
- 跨平台一致性:ffmpeg
loudnorm/COVR/aac在 mac/Win/Linux 上行为一致(ffmpeg 已随附)。响度开关默认关闭 → 不会产生默认行为差异。EPUB 解析在本地进行。 - 本地优先:无云端、无账户;所有渲染/导入均在设备端完成。
- 向后兼容数据:alembic 增量表;localStorage 项目惰性迁移,绝不破坏。
- 版本管理:以 v0.3.x 行上的持续合入主分支补丁形式发布;除非所有者要求,否则不发布 RC,不新增次要版本。
6. 建议的 PR 切分¶
- 共享的
longform_render核心 + loudnorm + 全局元数据/封面构建器 (仅后端,接在 Audiobook 后面)。先做纯构建器 + 测试。 - Audiobook 元数据 + 封面 UI。
- 逐章预览 + 重试 + 续播(检查点)。
- 文本/EPUB 导入 + 自动分章。
- Stories “Generate” → 共享任务;
storyToSpans();逐行重新生成;emotion→instruct。 - Stories 组件拆分 + 逐行波形;分章 M4B。
- DB 任务库(Projects/Library 显示已完成的书/故事)。
- (P2)SSML-lite、批处理、发音词典 UI。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 om/VoiceStudio