VoiceStudio Voice Gallery 架构解析:基于 instruct 词汇表生成数百个设计声音原型
【免费下载链接】VoiceStudioVoiceStudio is the open-source, fully-local ElevenLabs alternative — voice cloning, voice design, video dubbing, dictation, transcription & audiobook creation in 646 languages.项目地址: https://gitcode.com/GitHub_Trending/om/VoiceStudio
导读
Voice Gallery 是 VoiceStudio 内置的"设计声音原型(designed voice archetype)"库:不克隆任何真实人物,完全由 VoiceStudio 自身的语音设计引擎(voice-design engine)按instruct指令词汇表组合出数百个可直接使用的声音,并以 ElevenLabs 式的"精选卡片 + 多维筛选"方式浏览,同时提供一个中立的 URL/文件导入器让用户带入自己的源音频。本文以 docs/superpowers/specs/2026-05-31-voice-gallery-design.md 设计文档为主线,结合 backend/core/archetypes.py、backend/api/routers/archetypes.py、frontend/src/api/archetypes.ts 等仓库源码,完整还原该功能的设计决策、组合规模计算、后端引擎与 API、前端数据层与 UI、预览缓存体系、契约测试以及分阶段实施路径。读完你将掌握:instruct词汇表为何是"唯一合法调色板"、数百个声音如何由组合生成且保证可合成、预览如何做到"预渲染 + 按需渲染 + 磁盘缓存"三级兜底,以及"Use voice"如何把一个原型物化成可在配音/生成/克隆中复用的 voice profile。
1. 目标与核心定位
Voice Gallery 要交付的是一个可浏览的设计声音库:数百个开箱即用的声音,全部由 VoiceStudio 自己的语音设计引擎生成,组织方式借鉴 ElevenLabs——顶部是精选卡片,其余通过 facet 筛选器探索。同时提供一个中立的 URL/文件导入器(复用既有 yt-dlp 与AudioTrimmer流程)让用户带入自己的源音频。
设计文档开篇即明确了一个红线(decision record):项目不收录任何名人 / 具名真人目录。每个原型的"气质(vibe)"只来自指令 token 组合 + 示例脚本 + 策展命名,绝不来自克隆某个可辨识的个人。这条红线背后的推理链条是:
- 用户粘贴 URL 的导入器是中立基础设施(类似 yt-dlp/ffmpeg)——用户自备来源、自担许可责任;
- 但项目自己发布一份"具名真人目录"(名人 / 政客 / 迪士尼 / 漫威)是一种编辑行为,会让项目从中立工具变成"教唆 / 帮助侵权"(MGM v. Grokster 一系判例),把维护者置于形象权(right-of-publicity)、ELVIS-Act、NO-FAKES 等法律风险之下,也是当前 AI 语音诈骗浪潮的主要载体。
因此最终方案是:保留中立导入器,砍掉策展式名人分类法,以合成原型为主打。
2. 引擎约束:instruct 词汇表是唯一的"声音调色板"
Voice Gallery 全部工作的地基是omnivoice/utils/voice_design.py中定义的完整且经过验证的 instruct 词汇表。model.generate(instruct=...)会调用_resolve_instruct,任何词汇表之外的 token 都会触发ValueError——这正是 issue #89 的崩溃模式(一个 personality 携带了散文而非合法 token,直接让合成崩溃)。因此原型引擎生成的一切instruct字符串必须"保证能通过验证器"。
完整的表达调色板如下(与文档表格一致,可在 omnivoice/utils/voice_design.py 的_INSTRUCT_CATEGORIES中核对):
| 轴 | 合法 token | 互斥性 |
|---|---|---|
| 性别 Gender | male,female | one-of(二选一) |
| 年龄 Age | child,teenager,young adult,middle-aged,elderly | one-of |
| 音高 Pitch | very low pitch,low pitch,moderate pitch,high pitch,very high pitch | one-of |
| 风格 Style | whisper(唯一的风格 token) | 可选 |
| 口音 Accent(仅英文) | american, british, australian, chinese, canadian, indian, korean, portuguese, russian, japanese | one-of |
| 方言 Dialect(仅中文) | 河南话, 陕西话, 四川话, 贵州话, 云南话, 桂林话, 济南话, 石家庄话, 甘肃话, 宁夏话, 青岛话, 东北话 | one-of |
两个关键事实:
- 没有情感 / 描述性风格轴——不存在 ElevenLabs
descriptive式的 "calm"、"raspy"、"warm"。因此无法 1:1 移植 ElevenLabs 的声音。设计上只借用其结构(用例分类 + facet 筛选)和人口学维度(age/gender/accent 可直接映射),不借用其风格词汇。 - 口音(EN-only)与方言(ZH-only)互斥——一条 instruct 里永远不同时出现二者。这也被 backend/tests/test_archetypes.py 以测试契约强制锁定。
2.1 规模如何达到"数百"
合法英文空间 ≈ 性别(2) × 年龄(5) × 音高(5) × 口音(11 含 neutral) ≈550,再被whisper修饰符约翻倍。剪掉不合理的组合后得到约 300~500 个英文原型;中文方言空间(性别 × 年龄 × 音高 × 12 方言)再追加数百个。这就在不引入情感维度的前提下,用人口学 / 嗓音多样性达到了 ElevenLabs 量级的广度。
实现层面,backend/core/archetypes.py 的generate_archetypes()正是按此组合逻辑执行:
- 英文:
gender × age × pitch × {neutral + 10 口音},对满足_whisper_ok的(age ∈ {young adult, middle-aged, elderly} 且 pitch ∈ {low, moderate})再追加 whisper 变体; - 中文:
gender × age × pitch × 12 方言; - 过程中以
_pruned(age, pitch)跳过不合理组合(见下),并以_FEATURED_KEYS去重避免与精选集重复。
3. 分类法:七类用例 + 六维筛选(取代名人分类)
设计文档规定用七类**用例(use-case)**分类(对标 ElevenLabs 结构、与真人无关),实现于 backend/core/archetypes.py 的USE_CASES:
narration Narration & Story · 叙事与故事 conversational Conversational · 对话 characters Characters & Animation · 角色与动画 social Social Media · 社交媒体 entertainment Entertainment & TV · 娱乐与电视 advertisement Advertisement · 广告 informative Informative & Educational · 信息与教育每个用例带 lucide-react 图标组件名(BookOpen、MessagesSquare、Drama、Smartphone、Tv、Megaphone、GraduationCap),前端映射为 SVG 图标;刻意不用 emoji(跨 OS 渲染不一致)。
Facet 筛选器:Gender · Age · Pitch · Accent · Whisper · Language(EN / ZH)。
一个值得注意的细节是use_case 的两级来源:
- 精选原型(Featured)携带人工策展的
use_case; - 浏览全部(Browse all)的原型没有人工标注,而是由 backend/core/archetypes.py 的
_use_case()启发式推导(文档中明确标注为近似值):whisper → narration;child/teenager → characters;very high pitch → characters;低沉中年/老年 → narration;高音青年 → social;无口音中年中音 → informative;青年 → conversational;老年 → entertainment;中年 → advertisement;兜底 conversational。
这样即使全量集合没有人工标注,按用例过滤依然全库可用。
4. 架构设计
4.1 信息架构:两个区域 + 顶部切换
Gallery 标签页有两个区域(顶层切换):
- Archetypes(原型)
- Featured(精选)——约 24 个策展原型、预渲染预览 WAV、按用例分组(实现中实际扩充为 24 个英文 + 27 个多语言 = 51 个,见 4.4);
- Browse all(浏览全部)——生成的数百个集合;可 facet 过滤;预览按需渲染 + 缓存。
- My Imports(我的导入)——中立的 URL/文件导入器(复用既有 yt-dlp +
AudioTrimmer流程),无策展分类。
前端实现于 frontend/src/pages/VoiceGallery.jsx,由galleryZone状态驱动;实际 UI 还扩展了第三个community区域(社区市场),但核心的"原型 + 我的导入"二元结构不变。
4.2 原型数据模型:值对象,不是数据库行
每个原型是一个值对象(value object),不落数据库。完整结构(文档 4.2 与 backend/core/archetypes.py_build()返回值一致):
{ "id": str, # 稳定:short hash of (instruct + language),如 "a_" + sha256[:10] "name": str, # "British · Middle-aged · Low — Narrator"(自动生成)或策展命名 "icon": str, # lucide-react 图标组件名 "use_case": str, # 七类用例之一 "instruct": str, # 逗号连接的合法 token——保证通过验证器 "attrs": {Gender, Age, Pitch, Style, EnglishAccent, ChineseDialect}, # 驱动设计滑杆 "facets": {gender, age, pitch, accent, whisper, lang}, # 驱动筛选器 "sample_script": str, # 示例脚本(中文方言原型用 _ZH_SAMPLE,多语言原型用本地化脚本) "preview_url": str | None, # 精选集设置(预渲染);None => 按需渲染 "is_featured": bool, "language": "English" | "Chinese" | "Spanish" | ..., }ID 的稳定性是硬性契约:id = "a_" + sha256(f"{instruct}|{language}")[:10](精选集用feat_XX_<slug>/ml_<lang>_<role>前缀)。测试 backend/tests/test_archetypes.py 明确断言两次调用generate_archetypes()产生完全相同的 ID 序列。
4.3 后端:archetypes 引擎(core.archetypes)
backend/core/archetypes.py 是全新模块,对外暴露:
USE_CASES/categories()—— 七个用例;generate_archetypes()—— 遍历验证器自身的集合、按规则表剪枝不合理组合、自动命名、启发式分配用例、构建保证合法的 instruct 字符串;确定性顺序 + 稳定 ID;list_archetypes(filters)/get_archetype(id)/count()。
三个实现层面的关键设计:
- 单一事实来源(single source of truth):模块按文件路径加载
omnivoice/utils/voice_design.py(importlib.util.spec_from_file_location),而不是import omnivoice...。原因是omnivoice包__init__会拉起 torch/torchaudio 等重型模型依赖,在测试/CI 环境不可用;而voice_design.py本身只依赖标准库。这样"从词汇表本身构建 instruct"从机制上杜绝了_resolve_instruct拒绝 token 的 issue-#89 崩溃。 - 位置守卫断言:加载后立即断言六个类别的位置与内容(
assert "male" in _CAT[0] ...),上游词汇表一旦重排会在此处大声失败,而不是静默产出垃圾 instruct。 - 合理性剪枝规则表(
_PRUNE):child不可配very low pitch/low pitch;teenager不可配very low pitch;elderly不可配very high pitch;- whisper 变体仅允许
young adult / middle-aged / elderly×low / moderate pitch。
4.4 精选集:从 24 到 51 的实现演进
设计文档的精选集是"~24 个",实现中扩展为两层:
- 24 个英文精选(
_FEATURED_SPEC,覆盖七个用例):如叙事类的 "The Librarian"(female · middle-aged · low pitch · british accent)、"The Storyteller"、"The Calm Guide"(whisper);角色类的 "Captain Crusty"、"The Pixie"、"The Ogre";社交类的 "The Hype Host";广告类的 "The Luxe"、"The Upbeat" 等——全部是虚构角色命名,无真实人物; - 27 个多语言精选(
_ML_SAMPLES×_ML_ROLES):在 Spanish、French、German、Italian、Portuguese、Russian、Hindi、Japanese、Korean 九种语言中各提供 Narrator / Explainer / Companion 三个"中性音色角色"。
多语言精选的关键设计:设计声音的"说话语言"由预览文本决定,而不是由 instruct 决定——音色轴(gender/age/pitch)是语言无关的,同一条中性 instruct 可在 VoiceStudio 支持的任意语言下通过model.generate(text=…, language=…, instruct=…)渲染。因此这些原型不携带任何口音/方言 token("spanish accent" 在词汇表里根本不存在,写了就会触发 issue-#89 崩溃),只用通用音色轴。每个language标签必须与 frontend/src/languages.json 中的条目逐字匹配,因为该字符串会无归一化地直接流入model.generate(language=…)("Arabic" 因不在该列表中而被有意排除)。
4.5 后端:archetypes API
backend/api/routers/archetypes.py 定义路由并在 backend/main.py 注册。纯读端点不触碰模型——所有重型依赖(TTS 模型、torch)都被延迟到渲染函数内部导入,保证模块在无权重环境下可干净导入。
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /archetypes/categories | 七个用例分类(须声明在/{id}之前,避免被路径参数路由吞掉) |
| GET | /archetypes | 列表 + 全部筛选 + 分页:?q=&use_case=&gender=&age=&pitch=&accent=&whisper=&lang=&featured=&limit=&offset=,返回{total, limit, offset, items};limit默认 60、范围 1–500,offset≥ 0 |
| GET | /archetypes/{id} | 单个原型,404 处理 |
| GET | /archetypes/{id}/preview/state | 预览来源状态(不碰模型与网络):gallery/cached/no_model/rendering,并附用户可读消息 |
| GET | /archetypes/{id}/preview | 预览音频:预渲染画廊 → 磁盘缓存 → 本地引擎渲染,三级兜底 |
| POST | /archetypes/{id}/use | 渲染示例 → 创建voice_profile(渲染 WAV 作ref_audio,携带原型的instruct/language)→ 返回 profile id |
筛选参数细节(与 backend/core/archetypes.py 的list_archetypes()对应):q是对 name/instruct 的大小写不敏感子串匹配(可以输入 "british"、"librarian"、"whisper" 直接搜索整个数百声音库,弥补 facet 枚举无法按名字精确检索的缺口);whisper/featured为布尔三态;offset/limit支持分页。
4.6 前端:数据层与状态
数据层遵循既有 react-query 模式:
- frontend/src/api/archetypes.ts ——
listArchetypeCategories()、listArchetypes(filters)、archetypePreviewUrl(id, local)(预览音频 URL,供<audio>使用)、useArchetypeAsProfile(id, name?)(POST /archetypes/{id}/use); - frontend/src/api/hooks.ts ——
useArchetypeCategories()与useArchetypes(filters, enabled)。目录规模大且静态,staleTime: 5 * 60_000强力缓存;分页时用keepPreviousData保留上一页;enabled参数让共享消费者(如 VoiceSelector 下拉)在真正打开前不发起请求——配音演员列表可以挂载多个选择器而互不打扰网络。
状态层 frontend/src/store/gallerySlice.ts(zustand slice,注册于 frontend/src/store/index.ts)持有:galleryZone(当前区域)、archetypeFilters(七项筛选状态)、favoriteArchetypeIds(收藏 ID 数组)、galleryViewMode(grid/list)。由于原型不是数据库行,收藏与筛选天然是客户端状态;收藏 + 视图模式被持久化(partialize),会话偏好的区域/筛选也持久化以便画廊重开时恢复原位。
4.7 前端:卡片动作
原型卡片(frontend/src/components/gallery/ArchetypeCard.jsx,区域组件 frontend/src/components/gallery/ArchetypesZone.jsx)提供四个动作:
- Preview(预览)——播放 WAV,主链路走
archetypePreviewUrl; - Use voice(使用声音)——主动作 →
POST /archetypes/{id}/use物化成 profile,之后在配音 / 生成 / 克隆所有选声处可用; - Open in Designer(在设计器中打开)——次动作 →
setInstruct+setVdStates+ 切换到 Design 标签页,把原型加载回语音设计器继续微调; - Favorite(收藏)——写入
gallerySlice的客户端收藏。
VoiceGallery 页面(frontend/src/pages/VoiceGallery.jsx)还实现了"stale-async guards":预览拉取、物化保存等异步操作可能比触发它的动作活得更久(页面卸载、用户切换声音、已离开工作区),每个异步操作捕获当前代号并在播放/导航/setState 前复查,卸载与每次新操作都会使旧代号失效。
5. 预览体系:三级兜底 + 可选预渲染画廊
预览是 Voice Gallery 体验的核心,实现上分成三层:
5.1 按需渲染 + 磁盘缓存
GET /archetypes/{id}/preview在本地无缓存时调用_render_wav_atomic()(backend/api/routers/archetypes.py):先渲染到临时文件、用is_playable_wav校验、再os.replace原子替换到OUTPUTS_DIR/archetype_previews/<hash>.wav,缓存键为sha256(instruct|language)[:16]——两条原型若解析到同一声音则共享同一缓存文件,冷渲染每个不同声音只发生一次。
渲染参数与质量防护值得一提:
- seed 固定为 42(可复现,与 scripts/render_demos_omnivoice.py 对齐);
- num_step 用 32 而非 16:16 步欠收敛会让特定 (脚本, seed) 组合(尤其 seed 42 下的 "social" 示例脚本)坍缩成退化的调性嗡嗡声(The Hype Host / Podcaster / Vlogger);
- 双重退化检测:
_is_blank_audio()(峰值 < 0.02,沉默/空/非有限)之外,还有_spectral_flatness()均值帧谱平坦度检测——纯音嗡嗡声虽响(归一化后峰值约 -2 dBFS)但谱平坦度极低,阈值1e-7对最低语音(约 7.7e-6)与最坏嗡嗡声(约 3.3e-9)两侧都留有 10 倍以上余量;检测到退化即用 seed+1 重试一次,仍失败则响亮报错——空/静音/退化预览绝不会被缓存或保存; - 合成水印:渲染成功后调用
mark_synthetic_async(AudioSeal 嵌入,跑在专用 watermark 池,不占 GPU worker)打上不可见溯源标记——该站点同时覆盖预览音频与物化 profile 的参考 WAV;用户上传/录制的真人参考音频从不打标。
5.2 预渲染画廊(可选、本地优先)
由于每次预览都要在 GPU 上按需合成,全新安装的用户在 2.4 GB TTS 检查点(见 config/models.yaml)下载完成前什么也听不到。为此 backend/services/gallery.py 实现了"预渲染预览下载客户端":
- OPT-IN(默认关闭):下载预览是新的出站调用,而 CLAUDE.md 的 local-first 承诺是"没有明确同意,任何数据不得离开机器"。因此没有安装时后台抓取——
is_enabled在用户在 Settings 开启前恒为 false,模块内所有网络入口在关闭时都是 no-op;"开启"本身即同意,并触发精选集下载。画廊关闭或不可达时,预览照旧本地渲染,整个应用在全部拒绝的情况下依然完整可用。 - 信任模型:
manifest.json用既有 Tauri 发布密钥(minisign)签名,公钥UPDATER_PUBKEY与 frontend/src-tauri/tauri.conf.json 中 updater 携带的密钥逐字节一致(由 tests/test_gallery_previews.py 的 ratchet 测试锁死,冻结的后端不带 tauri.conf.json 所以必须复制)。签名校验是每个文件 SHA-256 摘要唯一有意义的保证——校验失败的 manifest 整体丢弃,且磁盘上已有的 manifest 每次加载都重新校验,不因"曾经信任"而豁免。无新密钥、无新基础设施、无第二个信任根。 - 硬字节上限:manifest ≤ 8 MiB、签名 ≤ 4 KiB、单预览 ≤ 4 MiB、featured 压缩包 ≤ 64 MiB,防止恶意/损坏端点填满用户磁盘;manifest 的 1126 个条目 ≈ 300 kB,64 kbps 单声道示例 ≈ 100 kB。
- 刷新节流:24 小时更新一次(非每次启动);"check now"(
POST /archetypes/previews/check)绕过节流但永不绕过签名校验;ON_DEMAND_TIMEOUT_S = 8.0——按需抓取在等待用户点播放,几秒内没结果不如本地渲染。 - 优先级规则:画廊音频只在
/preview胜出本地渲染(这是可证明来源的固定参考渲染,引擎版本记录在 manifest 中并在 Settings 展示);/use永远本地渲染——该 WAV 会落入VOICES_DIR成为克隆声音的参考音频,下载的有损 MP3 绝不能成为参考。
预览来源查询接口GET /archetypes/{id}/preview/state让 UI 在发起可能耗时 40 秒或必然失败的请求之前就标注好声音状态("需等待片刻"/"先下载模型"),替代了旧版"去看日志文件"的糟糕体验。PUT /archetypes/previews开启画廊时同步拉取精选集,让"同意"产生立即可见的效果;失败默认静默(fetch_featured吞掉异常),预览退回本地渲染。
6. "Use voice":原型 → 可复用 profile 的物化
POST /archetypes/{id}/use是整个画廊的"主动作"出口,实现上有四个要点:
- 先渲染、后入库:约束是
POST /profiles必须携带ref_audio,所以物化必须先把原型的示例脚本渲染成 WAV,再以该 WAV 为ref_audio写入voice_profiles行(kind='design'、seed=42、personality="archetype:{id}"、vd_states携带完整选择器状态)。profile 随后出现在所有选声处(配音 / 生成 / 克隆)。 - 幂等去重:一个原型只物化为恰好一个profile。用命名空间化的
personality身份(archetype:{id})保证:导入的 persona 无法与原型 ID 冲突并被改写;同一画廊声音被任何选择器反复选中时复用那一行,而非每次重新渲染 + 插入重复。渲染期间还处理了并发竞态——写入连接上二次检查、BEGIN IMMEDIATE串行化。 - 陈旧行治愈:识别并修复旧版物化器产生的行(
_heal_materialized_profile补上kind='design'、instruct、vd_states 等字段);_legacy_archetype_profile/_is_materialized_archetype_row不信任身份文本本身,而是逐字段核对音频文件名、instruct、language、ref_text、seed、vd_states、锁状态。 - 失败分级:无模型时提示"去 Model Catalogue 的 Weights 列表下载语音模型";有模型但渲染失败时给出引擎原始错误;两者都是 503 而非 500,且错误消息对 CodeQL 日志注入做了防护(不插请求派生值)。
物化后的 profile 可用GET /profiles系列接口复用,事件总线(event_bus.emit("profiles", ...))向 UI 广播created/updated。
7. 契约测试:保证"每条 instruct 都能合成"
backend/tests/test_archetypes.py 是 archetypes 引擎的 TDD 契约测试,它独立加载词汇表(同样按文件路径,绕过重型包导入),对着真正的单一事实来源验证:
- (a) 合法性:全目录每条 instruct 的每个 token 都在
_INSTRUCT_ALL_VALID中("否则会崩溃合成"); - (a2) 互斥性:每个互斥类别最多取一个 token;
- (b) 分离性:英文口音与中文方言绝不同现;
- (c) 规模:
generate_archetypes()至少 250 个; - (d) 剪枝:不存在
child + very low pitch、elderly + very high pitch; - (e) 稳定性:ID 唯一且跨调用确定;
- (f) 精选完整性:featured ≥ 12、use_case 合法、脚本非空、token 合法;
- (g) 分类法:七个用例 ID 精确匹配;
- (h) 筛选器:gender / use_case / lang=Chinese(且无英文口音)/ accent 过滤正确;
- (h2) 多语言:九种语言精选齐全、instruct 非空且只含通用音色轴 token;
- (i) 查询:
get_archetype往返一致、缺失返回None。
配套的还有 tests/test_gallery_previews.py(画廊签名公钥与 Tauri 更新器密钥 lockstep)、预览质量测试test_archetype_preview_quality.py(校准谱平坦度阈值)以及test_no_hardcoded_cjk.py的 allowlist(中文方言 token 是功能性的模型词汇,动态从词汇表加载,绝不内联硬编码;仅_ZH_SAMPLE与多语言示例脚本作为功能演示文本登记在 allowlist 中)。
8. 跨平台与约束合规(CLAUDE.md)
设计文档对实现的硬约束:
- 默认功能对等(严格):原型浏览 + 按需预览 + "use voice" 在 macOS/Windows/Linux 行为完全一致(纯 Python 合成 + 静态资源,无 OS 专属代码)。唯一平台可变面是 yt-dlp 导入器——以状态形式呈现,yt-dlp/ffmpeg 缺失时优雅降级。任何默认行为不因平台而异。
- 数据向后兼容:
voice_profiles无 schema 变更,voice_gallery表原样复用,无需 alembic 迁移;既有 profile/导入不受影响。 - 本地优先:除用户主动触发的导入器下载(及可选的预渲染画廊下载)外无网络调用。
- 版本纪律:随 v0.3.0 发布,无版本噪音(per CLAUDE.md versioning rule)。
9. 分阶段实施计划
设计文档给出的八阶段路径(实现已基本落地):
- Phase 1 — 原型引擎(TDD):
backend/core/archetypes.py+ 契约测试(上述 a–f); - Phase 2 — 原型 API:
backend/api/routers/archetypes.py、注册进main.py、预览缓存目录;测试覆盖 categories、各筛选、分页、404、预渲染 preview、/usehappy path(无权重时跳过); - Phase 3 — 去名人化导入器:从
services/gallery.py移除名人CATEGORIES常量、移除前端'celebs'/'famous voice'默认值,保留上传/裁剪/存为 profile; - Phase 4 — 前端数据层:
api/archetypes.ts、hooks、store/gallerySlice.ts注册; - Phase 5 — 前端 UI:重写
VoiceGallery.jsx:区域切换、facet 栏、精选 + 浏览网格、懒加载预览、卡片动作、My Imports 导入器; - Phase 6 — i18n:
archetypes.*键写入 frontend/src/i18n/locales/en.json(权威),其余 20 个 locale 翻译前回退英文;验证无 allowlist 之外的硬编码 CJK; - Phase 7 — 精选预览资产:扩展 scripts/render_demos_omnivoice.py 渲染 ~24 个精选 WAV(dev-box 步骤、seed 固定);WAV 缺失时精选回退按需渲染;
- Phase 8 — 验证:后端 pytest、前端 typecheck/test/lint、
test_no_hardcoded_cjk.py、Gallery 标签页手工冒烟。
10. 明确不在范围内
- 项目自产的名人/角色目录;
- 抓取用的自动年龄门 / cookie 绕过;
- 情感风格 instruct token(引擎不支持);
- GitHub-App 自动提交 bug 报告的路径(与本功能无关)。
延伸阅读:设计文档 docs/superpowers/specs/2026-05-31-voice-gallery-design.md、引擎实现 backend/core/archetypes.py、API 实现 backend/api/routers/archetypes.py、词汇表单一事实来源 omnivoice/utils/voice_design.py、前端数据层 frontend/src/api/archetypes.ts 与 frontend/src/store/gallerySlice.ts、画廊 UI frontend/src/pages/VoiceGallery.jsx、契约测试 backend/tests/test_archetypes.py、预渲染画廊客户端 backend/services/gallery.py。
【免费下载链接】VoiceStudioVoiceStudio is the open-source, fully-local ElevenLabs alternative — voice cloning, voice design, video dubbing, dictation, transcription & audiobook creation in 646 languages.项目地址: https://gitcode.com/GitHub_Trending/om/VoiceStudio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考