voxx 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. voxx-0.1.0/.gitignore +5 -0
  2. voxx-0.1.0/AGENTS.md +17 -0
  3. voxx-0.1.0/GLOSSARY.md +51 -0
  4. voxx-0.1.0/LICENSE +73 -0
  5. voxx-0.1.0/NOTICE +25 -0
  6. voxx-0.1.0/PKG-INFO +109 -0
  7. voxx-0.1.0/README.md +83 -0
  8. voxx-0.1.0/docs/DESIGN.md +137 -0
  9. voxx-0.1.0/docs/adr/0001-narration-file-is-the-contract.md +15 -0
  10. voxx-0.1.0/docs/adr/0002-synthesis-runs-in-a-worker-process.md +8 -0
  11. voxx-0.1.0/docs/adr/0003-models-are-installed-only-by-an-explicit-command.md +13 -0
  12. voxx-0.1.0/docs/adr/0004-cloning-does-not-check-consent.md +8 -0
  13. voxx-0.1.0/docs/adr/0005-narration-language-is-a-bcp-47-tag.md +13 -0
  14. voxx-0.1.0/docs/adr/0006-only-the-model-that-reads-must-be-installed.md +13 -0
  15. voxx-0.1.0/docs/agents/domain.md +51 -0
  16. voxx-0.1.0/docs/agents/issue-tracker.md +46 -0
  17. voxx-0.1.0/docs/agents/triage-labels.md +15 -0
  18. voxx-0.1.0/docs/releasing.md +45 -0
  19. voxx-0.1.0/docs/research/tts-models-2026-10.md +328 -0
  20. voxx-0.1.0/examples/invite/narration.json +9 -0
  21. voxx-0.1.0/examples/invite/out/email.wav +0 -0
  22. voxx-0.1.0/examples/invite/out/intro.wav +0 -0
  23. voxx-0.1.0/examples/invite/out/narration.json +249 -0
  24. voxx-0.1.0/examples/invite/out/send.wav +0 -0
  25. voxx-0.1.0/pyproject.toml +58 -0
  26. voxx-0.1.0/skills/voxx/SKILL.md +61 -0
  27. voxx-0.1.0/skills/voxx/cloning.md +24 -0
  28. voxx-0.1.0/skills/voxx/scripts/voxx +4 -0
  29. voxx-0.1.0/skills/voxx/setup.md +35 -0
  30. voxx-0.1.0/src/voxx/__init__.py +1 -0
  31. voxx-0.1.0/src/voxx/__main__.py +5 -0
  32. voxx-0.1.0/src/voxx/audio.py +102 -0
  33. voxx-0.1.0/src/voxx/cli.py +89 -0
  34. voxx-0.1.0/src/voxx/doctor.py +49 -0
  35. voxx-0.1.0/src/voxx/engines/__init__.py +47 -0
  36. voxx-0.1.0/src/voxx/engines/fake.py +122 -0
  37. voxx-0.1.0/src/voxx/engines/mlx_audio.py +57 -0
  38. voxx-0.1.0/src/voxx/files.py +34 -0
  39. voxx-0.1.0/src/voxx/install.py +176 -0
  40. voxx-0.1.0/src/voxx/models.py +277 -0
  41. voxx-0.1.0/src/voxx/narrate.py +200 -0
  42. voxx-0.1.0/src/voxx/narration.py +116 -0
  43. voxx-0.1.0/src/voxx/output.py +45 -0
  44. voxx-0.1.0/src/voxx/schema.py +448 -0
  45. voxx-0.1.0/src/voxx/self_check.py +49 -0
  46. voxx-0.1.0/src/voxx/voices.py +190 -0
  47. voxx-0.1.0/src/voxx/words.py +26 -0
  48. voxx-0.1.0/src/voxx/worker/__init__.py +1 -0
  49. voxx-0.1.0/src/voxx/worker/__main__.py +86 -0
  50. voxx-0.1.0/src/voxx/worker/client.py +93 -0
  51. voxx-0.1.0/tests/conftest.py +104 -0
  52. voxx-0.1.0/tests/fake_hub.py +101 -0
  53. voxx-0.1.0/tests/test_clone.py +261 -0
  54. voxx-0.1.0/tests/test_doctor.py +57 -0
  55. voxx-0.1.0/tests/test_example.py +35 -0
  56. voxx-0.1.0/tests/test_install.py +147 -0
  57. voxx-0.1.0/tests/test_line.py +272 -0
  58. voxx-0.1.0/tests/test_line_audio.py +85 -0
  59. voxx-0.1.0/tests/test_models.py +64 -0
  60. voxx-0.1.0/tests/test_narrate.py +320 -0
  61. voxx-0.1.0/tests/test_real_models.py +153 -0
  62. voxx-0.1.0/tests/test_release.py +61 -0
  63. voxx-0.1.0/tests/test_schema.py +109 -0
  64. voxx-0.1.0/tests/test_self_check.py +129 -0
  65. voxx-0.1.0/tests/test_voices.py +29 -0
  66. voxx-0.1.0/tests/test_words.py +122 -0
voxx-0.1.0/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.egg-info/
4
+ dist/
5
+ .pytest_cache/
voxx-0.1.0/AGENTS.md ADDED
@@ -0,0 +1,17 @@
1
+ ## Agent skills
2
+
3
+ ### Issue tracker
4
+
5
+ Issue 和 spec 都放在 GitHub Issues(levyxdev/voxx),用 `gh` 操作。See `docs/agents/issue-tracker.md`.
6
+
7
+ ### Triage labels
8
+
9
+ 使用五个默认标签:needs-triage、needs-info、ready-for-agent、ready-for-human、wontfix。See `docs/agents/triage-labels.md`.
10
+
11
+ ### Domain docs
12
+
13
+ Single-context:根目录放 `GLOSSARY.md`,ADR 放 `docs/adr/`。See `docs/agents/domain.md`.
14
+
15
+ ## 检查
16
+
17
+ 改完代码跑 `uv run basedpyright`(零错误)和 `uv run pytest`(全部通过)。改动碰到 Engine 或真实模型时,再用 `VOXX_TEST_REAL=1 uv run pytest tests/test_real_models.py` 跑慢测试,它用的是本机已安装的模型。
voxx-0.1.0/GLOSSARY.md ADDED
@@ -0,0 +1,51 @@
1
+ # voxx
2
+
3
+ voxx 是只给 agent 用的本地语音工具:把 agent 写好的旁白逐句念出来,交回音频和词级时间戳。术语与 CueTake 共用的部分保持同名。
4
+
5
+ ## Language
6
+
7
+ ### 旁白
8
+
9
+ **Narration(旁白)**:
10
+ 一组同一种语言、按顺序排列的 Line,是 voxx 一次合成的输入,也是它交回的清单。
11
+ _Avoid_: script, 文案文件, 口播稿
12
+
13
+ **Line(句子)**:
14
+ 旁白中有唯一 id 的一段文字,一次连续念完,对应一个音频文件。
15
+ _Avoid_: segment, 段落, sentence
16
+
17
+ **Word Timing(词级时间戳)**:
18
+ Line 的音频里每个词(中文为字)开始和结束的时刻,相对该 Line 音频的起点。
19
+ _Avoid_: alignment, 时间轴, 时间
20
+
21
+ ### 音色
22
+
23
+ **Voice(音色)**:
24
+ 念一个 Line 时用的声音身份,要么是 Preset Voice,要么是 Cloned Voice。
25
+ _Avoid_: speaker, 声音, 角色
26
+
27
+ **Preset Voice(预设音色)**:
28
+ 模型自带、按名字选用的音色。
29
+ _Avoid_: built-in speaker, 内置声音
30
+
31
+ **Cloned Voice(克隆音色)**:
32
+ 从一段参考录音得到的音色。
33
+ _Avoid_: custom voice, 声音档案
34
+
35
+ **Reference Recording(参考录音)**:
36
+ 用来得到 Cloned Voice 的那段真人录音。
37
+ _Avoid_: prompt audio, ref, 样本
38
+
39
+ ### 模型
40
+
41
+ **Model(模型)**:
42
+ voxx 注册表里登记的一个可下载的 TTS、对齐或听写模型,固定到一个上游版本,带有已核实的权重许可证。
43
+ _Avoid_: checkpoint, 权重
44
+
45
+ **Capability(能力)**:
46
+ 一个 Model 能做的事:念 Preset Voice(preset_voice)、克隆(clone)、对齐(align)或听写(transcribe)。
47
+ _Avoid_: feature, task, 功能
48
+
49
+ **Engine(引擎)**:
50
+ 实际加载并运行 Model 的推理库,一个 Engine 可以运行多个 Model。
51
+ _Avoid_: backend, runtime, 框架
voxx-0.1.0/LICENSE ADDED
@@ -0,0 +1,73 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
10
+
11
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
12
+
13
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
14
+
15
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
16
+
17
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
18
+
19
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
20
+
21
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
22
+
23
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
24
+
25
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
26
+
27
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
28
+
29
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
30
+
31
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
32
+
33
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
34
+
35
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
36
+
37
+ (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
38
+
39
+ (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
40
+
41
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
42
+
43
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
44
+
45
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
46
+
47
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
48
+
49
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
50
+
51
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
52
+
53
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
54
+
55
+ END OF TERMS AND CONDITIONS
56
+
57
+ APPENDIX: How to apply the Apache License to your work.
58
+
59
+ To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
60
+
61
+ Copyright [yyyy] [name of copyright owner]
62
+
63
+ Licensed under the Apache License, Version 2.0 (the "License");
64
+ you may not use this file except in compliance with the License.
65
+ You may obtain a copy of the License at
66
+
67
+ http://www.apache.org/licenses/LICENSE-2.0
68
+
69
+ Unless required by applicable law or agreed to in writing, software
70
+ distributed under the License is distributed on an "AS IS" BASIS,
71
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
72
+ See the License for the specific language governing permissions and
73
+ limitations under the License.
voxx-0.1.0/NOTICE ADDED
@@ -0,0 +1,25 @@
1
+ voxx
2
+ Copyright 2026 yaobusuan and voxx contributors
3
+
4
+ This product is licensed under the Apache License, Version 2.0 (see LICENSE).
5
+
6
+ voxx does not bundle or redistribute any model weights. Weights are
7
+ downloaded from their original publishers only after the user consents,
8
+ and each remains under its own license, which voxx shows before download.
9
+
10
+ voxx builds on the following third-party projects:
11
+
12
+ - mlx-audio (MIT License)
13
+ https://github.com/Blaizzy/mlx-audio
14
+
15
+ - pyloudnorm (MIT License)
16
+ https://github.com/csteinmetz1/pyloudnorm
17
+
18
+ - Qwen3-TTS, Qwen3-ASR, Qwen3-ForcedAligner (Apache License 2.0)
19
+ Copyright Alibaba Cloud
20
+ https://github.com/QwenLM/Qwen3-TTS
21
+ https://github.com/QwenLM/Qwen3-ASR
22
+
23
+ - VoxCPM (Apache License 2.0)
24
+ Copyright OpenBMB
25
+ https://github.com/OpenBMB/VoxCPM
voxx-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,109 @@
1
+ Metadata-Version: 2.5
2
+ Name: voxx
3
+ Version: 0.1.0
4
+ Summary: Local text-to-speech CLI for agents: narrate each Line to a WAV with word timings
5
+ Project-URL: Homepage, https://github.com/levyxdev/voxx
6
+ Project-URL: Issues, https://github.com/levyxdev/voxx/issues
7
+ Author: levyxdev
8
+ License-Expression: Apache-2.0
9
+ License-File: LICENSE
10
+ License-File: NOTICE
11
+ Keywords: agents,mlx,narration,text-to-speech,tts,voice-cloning
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
20
+ Requires-Python: <3.15,>=3.12
21
+ Requires-Dist: mlx-audio==0.6.3; platform_machine == 'arm64' and sys_platform == 'darwin'
22
+ Requires-Dist: numpy>=2
23
+ Requires-Dist: pyloudnorm==0.2.0
24
+ Requires-Dist: scipy>=1.10
25
+ Description-Content-Type: text/markdown
26
+
27
+ # voxx
28
+
29
+ **Local narration for AI agents.**
30
+
31
+ voxx is a text-to-speech CLI built only for agents. An agent writes a Narration, a list of Lines in one language, and `voxx narrate` reads each Line in one breath with a local speech Model, then hands back one WAV per Line with word timings and a self-check. The completed Narration file goes straight to [CueTake](https://github.com/levyxdev/cuetake) (`cuetake record --narration`), so a product demo can be recorded to fit its voice-over.
32
+
33
+ - Every Line is read whole by the Model, never stitched, then trimmed to 50 ms of silence at each end and normalized to -18 LUFS, as a mono WAV at the Model's native sample rate.
34
+ - Word timings for each Line (per character in Chinese), for Subtitles.
35
+ - A self-check: every Line is transcribed back and compared with its text, so the agent knows which Lines to read again with a new seed, leaving the others byte for byte as they were.
36
+ - Preset Voices, or a Cloned Voice made from a short Reference Recording.
37
+ - Only Models whose weights allow commercial use, run locally through [mlx-audio](https://github.com/Blaizzy/mlx-audio). Nothing is downloaded until the user agrees.
38
+ - Every command prints one JSON object, and `voxx schema` describes them all, so an agent never guesses.
39
+
40
+ voxx 0.1 runs on Apple Silicon Macs only.
41
+
42
+ ## For AI agents
43
+
44
+ If a user hands you this repository to set up voxx:
45
+
46
+ 1. Install the skill with `npx skills add levyxdev/voxx`. In Claude Code you can instead run `/plugin marketplace add levyxdev/voxx`, then `/plugin install voxx`.
47
+ 2. The skill's `scripts/voxx` runs the pinned [`voxx`](https://pypi.org/project/voxx/) package with `uvx`, so nothing else needs installing besides [uv](https://docs.astral.sh/uv/). To run a source checkout instead, export `VOXX_BIN="uv run --project /absolute/path/to/voxx voxx"`.
48
+ 3. Follow the [skill](skills/voxx/SKILL.md): run `scripts/voxx doctor`, and install uv or a Model only after the user agrees ([setup](skills/voxx/setup.md)).
49
+
50
+ ## Example
51
+
52
+ [`examples/invite/narration.json`](examples/invite/narration.json) is a Narration as an agent writes it:
53
+
54
+ ```json
55
+ {
56
+ "language": "zh",
57
+ "style": "语气亲切自然,语速适中,像在给同事演示一个新功能",
58
+ "lines": [
59
+ { "id": "intro", "text": "这是新的邀请流程,只要三步。" },
60
+ { "id": "email", "text": "先填上同事的邮箱,再选好对方的角色。" },
61
+ { "id": "send", "text": "点一下发送,邀请就发出去了!", "style": "语气轻快,带一点兴奋" }
62
+ ]
63
+ }
64
+ ```
65
+
66
+ `voxx narrate examples/invite/narration.json --out examples/invite/out` read it with the default Models into [`examples/invite/out/`](examples/invite/out/): a WAV per Line, and a `narration.json` that keeps every field above and adds each Line's `audio`, `words`, `model`, `voice`, `seed`, `sample_rate`, `transcript`, `error_rate` and `warnings`.
67
+
68
+ ## Models
69
+
70
+ `voxx models` lists the registry. Each Model is pinned to one upstream revision, and its weights license was checked against the upstream model card on 2026-10-30. Only Models whose weights allow commercial use are registered.
71
+
72
+ | Model | Used for | Download | Weights license |
73
+ | --- | --- | --- | --- |
74
+ | `qwen3-tts-1.7b-customvoice` | Preset Voices (default) | 3.1 GB | [Apache-2.0](https://huggingface.co/Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice) |
75
+ | `qwen3-tts-0.6b-customvoice` | Preset Voices, fast drafts | 2.0 GB | [Apache-2.0](https://huggingface.co/Qwen/Qwen3-TTS-12Hz-0.6B-CustomVoice) |
76
+ | `voxcpm2` | Cloned Voices (default) | 3.2 GB | [Apache-2.0](https://huggingface.co/openbmb/VoxCPM2) |
77
+ | `qwen3-tts-1.7b-base` | Cloned Voices | 3.1 GB | [Apache-2.0](https://huggingface.co/Qwen/Qwen3-TTS-12Hz-1.7B-Base) |
78
+ | `qwen3-forcedaligner-0.6b` | Word timings | 1.3 GB | [Apache-2.0](https://huggingface.co/Qwen/Qwen3-ForcedAligner-0.6B) |
79
+ | `qwen3-asr-0.6b` | Self-check, Reference Recording text | 1.0 GB | [Apache-2.0](https://huggingface.co/Qwen/Qwen3-ASR-0.6B) |
80
+
81
+ Only the Model that reads must be installed; without the aligner or the transcriber, Lines are read without word timings or the self-check. `voxx install <model>` is the only command that downloads anything ([ADR 0003](docs/adr/0003-models-are-installed-only-by-an-explicit-command.md)). It fetches the 8-bit MLX conversions from Hugging Face into `~/.voxx/models` (or `$VOXX_HOME/models`), and honors `HF_ENDPOINT` for a mirror.
82
+
83
+ ## Disclaimer
84
+
85
+ - **You are responsible for the voices you clone.** voxx cannot tell whose voice a Reference Recording is, and does not check consent or add a watermark ([ADR 0004](docs/adr/0004-cloning-does-not-check-consent.md)). Clone only your own voice, or a voice whose owner has agreed to it, and follow the laws where you publish.
86
+ - **voxx distributes no model weights.** `voxx install` downloads them from their publishers' Hugging Face repositories only when you run it. Each Model stays under its own license, which voxx shows before you install it. The licenses in the registry were checked on the date shown; check the license yourself before you rely on it.
87
+ - **Label AI-generated speech.** Many platforms and jurisdictions require content with synthetic speech to be labeled as AI-generated when it is published. voxx records the Model, Voice and seed of every Line in its output.
88
+ - voxx is provided as is, without warranty of any kind, under the [Apache License 2.0](LICENSE). The third-party projects it builds on are listed in [NOTICE](NOTICE).
89
+
90
+ ## Run from source
91
+
92
+ Requirements: an Apple Silicon Mac and [uv](https://docs.astral.sh/uv/).
93
+
94
+ ```sh
95
+ uv sync
96
+ uv run voxx doctor
97
+ uv run voxx schema
98
+ ```
99
+
100
+ ## Development
101
+
102
+ ```sh
103
+ uv run basedpyright
104
+ uv run pytest
105
+ # With the Models installed:
106
+ VOXX_TEST_REAL=1 uv run pytest tests/test_real_models.py
107
+ ```
108
+
109
+ The tests run `voxx` as a process, the way an agent does, against a fake Engine and a local stand-in for Hugging Face, so they need no Model and never reach Hugging Face. The design is in [docs/DESIGN.md](docs/DESIGN.md), the terms in [GLOSSARY.md](GLOSSARY.md), the decisions in [docs/adr/](docs/adr/), and the release steps in [docs/releasing.md](docs/releasing.md).
voxx-0.1.0/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # voxx
2
+
3
+ **Local narration for AI agents.**
4
+
5
+ voxx is a text-to-speech CLI built only for agents. An agent writes a Narration, a list of Lines in one language, and `voxx narrate` reads each Line in one breath with a local speech Model, then hands back one WAV per Line with word timings and a self-check. The completed Narration file goes straight to [CueTake](https://github.com/levyxdev/cuetake) (`cuetake record --narration`), so a product demo can be recorded to fit its voice-over.
6
+
7
+ - Every Line is read whole by the Model, never stitched, then trimmed to 50 ms of silence at each end and normalized to -18 LUFS, as a mono WAV at the Model's native sample rate.
8
+ - Word timings for each Line (per character in Chinese), for Subtitles.
9
+ - A self-check: every Line is transcribed back and compared with its text, so the agent knows which Lines to read again with a new seed, leaving the others byte for byte as they were.
10
+ - Preset Voices, or a Cloned Voice made from a short Reference Recording.
11
+ - Only Models whose weights allow commercial use, run locally through [mlx-audio](https://github.com/Blaizzy/mlx-audio). Nothing is downloaded until the user agrees.
12
+ - Every command prints one JSON object, and `voxx schema` describes them all, so an agent never guesses.
13
+
14
+ voxx 0.1 runs on Apple Silicon Macs only.
15
+
16
+ ## For AI agents
17
+
18
+ If a user hands you this repository to set up voxx:
19
+
20
+ 1. Install the skill with `npx skills add levyxdev/voxx`. In Claude Code you can instead run `/plugin marketplace add levyxdev/voxx`, then `/plugin install voxx`.
21
+ 2. The skill's `scripts/voxx` runs the pinned [`voxx`](https://pypi.org/project/voxx/) package with `uvx`, so nothing else needs installing besides [uv](https://docs.astral.sh/uv/). To run a source checkout instead, export `VOXX_BIN="uv run --project /absolute/path/to/voxx voxx"`.
22
+ 3. Follow the [skill](skills/voxx/SKILL.md): run `scripts/voxx doctor`, and install uv or a Model only after the user agrees ([setup](skills/voxx/setup.md)).
23
+
24
+ ## Example
25
+
26
+ [`examples/invite/narration.json`](examples/invite/narration.json) is a Narration as an agent writes it:
27
+
28
+ ```json
29
+ {
30
+ "language": "zh",
31
+ "style": "语气亲切自然,语速适中,像在给同事演示一个新功能",
32
+ "lines": [
33
+ { "id": "intro", "text": "这是新的邀请流程,只要三步。" },
34
+ { "id": "email", "text": "先填上同事的邮箱,再选好对方的角色。" },
35
+ { "id": "send", "text": "点一下发送,邀请就发出去了!", "style": "语气轻快,带一点兴奋" }
36
+ ]
37
+ }
38
+ ```
39
+
40
+ `voxx narrate examples/invite/narration.json --out examples/invite/out` read it with the default Models into [`examples/invite/out/`](examples/invite/out/): a WAV per Line, and a `narration.json` that keeps every field above and adds each Line's `audio`, `words`, `model`, `voice`, `seed`, `sample_rate`, `transcript`, `error_rate` and `warnings`.
41
+
42
+ ## Models
43
+
44
+ `voxx models` lists the registry. Each Model is pinned to one upstream revision, and its weights license was checked against the upstream model card on 2026-10-30. Only Models whose weights allow commercial use are registered.
45
+
46
+ | Model | Used for | Download | Weights license |
47
+ | --- | --- | --- | --- |
48
+ | `qwen3-tts-1.7b-customvoice` | Preset Voices (default) | 3.1 GB | [Apache-2.0](https://huggingface.co/Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice) |
49
+ | `qwen3-tts-0.6b-customvoice` | Preset Voices, fast drafts | 2.0 GB | [Apache-2.0](https://huggingface.co/Qwen/Qwen3-TTS-12Hz-0.6B-CustomVoice) |
50
+ | `voxcpm2` | Cloned Voices (default) | 3.2 GB | [Apache-2.0](https://huggingface.co/openbmb/VoxCPM2) |
51
+ | `qwen3-tts-1.7b-base` | Cloned Voices | 3.1 GB | [Apache-2.0](https://huggingface.co/Qwen/Qwen3-TTS-12Hz-1.7B-Base) |
52
+ | `qwen3-forcedaligner-0.6b` | Word timings | 1.3 GB | [Apache-2.0](https://huggingface.co/Qwen/Qwen3-ForcedAligner-0.6B) |
53
+ | `qwen3-asr-0.6b` | Self-check, Reference Recording text | 1.0 GB | [Apache-2.0](https://huggingface.co/Qwen/Qwen3-ASR-0.6B) |
54
+
55
+ Only the Model that reads must be installed; without the aligner or the transcriber, Lines are read without word timings or the self-check. `voxx install <model>` is the only command that downloads anything ([ADR 0003](docs/adr/0003-models-are-installed-only-by-an-explicit-command.md)). It fetches the 8-bit MLX conversions from Hugging Face into `~/.voxx/models` (or `$VOXX_HOME/models`), and honors `HF_ENDPOINT` for a mirror.
56
+
57
+ ## Disclaimer
58
+
59
+ - **You are responsible for the voices you clone.** voxx cannot tell whose voice a Reference Recording is, and does not check consent or add a watermark ([ADR 0004](docs/adr/0004-cloning-does-not-check-consent.md)). Clone only your own voice, or a voice whose owner has agreed to it, and follow the laws where you publish.
60
+ - **voxx distributes no model weights.** `voxx install` downloads them from their publishers' Hugging Face repositories only when you run it. Each Model stays under its own license, which voxx shows before you install it. The licenses in the registry were checked on the date shown; check the license yourself before you rely on it.
61
+ - **Label AI-generated speech.** Many platforms and jurisdictions require content with synthetic speech to be labeled as AI-generated when it is published. voxx records the Model, Voice and seed of every Line in its output.
62
+ - voxx is provided as is, without warranty of any kind, under the [Apache License 2.0](LICENSE). The third-party projects it builds on are listed in [NOTICE](NOTICE).
63
+
64
+ ## Run from source
65
+
66
+ Requirements: an Apple Silicon Mac and [uv](https://docs.astral.sh/uv/).
67
+
68
+ ```sh
69
+ uv sync
70
+ uv run voxx doctor
71
+ uv run voxx schema
72
+ ```
73
+
74
+ ## Development
75
+
76
+ ```sh
77
+ uv run basedpyright
78
+ uv run pytest
79
+ # With the Models installed:
80
+ VOXX_TEST_REAL=1 uv run pytest tests/test_real_models.py
81
+ ```
82
+
83
+ The tests run `voxx` as a process, the way an agent does, against a fake Engine and a local stand-in for Hugging Face, so they need no Model and never reach Hugging Face. The design is in [docs/DESIGN.md](docs/DESIGN.md), the terms in [GLOSSARY.md](GLOSSARY.md), the decisions in [docs/adr/](docs/adr/), and the release steps in [docs/releasing.md](docs/releasing.md).
@@ -0,0 +1,137 @@
1
+ # voxx v0.1 设计
2
+
3
+ > 状态:已拷问定稿(2026-10-30)。术语见 [GLOSSARY.md](../GLOSSARY.md),关键决策见 [docs/adr/](adr/),模型调研见 [research/tts-models-2026-10.md](research/tts-models-2026-10.md)。下一步:`/to-spec` → `/to-tickets`。
4
+
5
+ ## 一句话
6
+
7
+ voxx 是**只给 agent 用**的本地语音 CLI 加一个 skill:agent 给它一份旁白(Narration),它把每个 Line 一次连续念完,交回每句一个音频文件和词级时间戳。主要用途是给 CueTake 录屏配音:先有口播,再按口播录屏,画面跟着声音走。
8
+
9
+ ## 核心原则:确定的写死在 CLI,判断交给 agent
10
+
11
+ | 写死在 CLI(同样输入总得到同样结果) | 交给 agent(skill 指导) |
12
+ |---|---|
13
+ | 模型注册表、许可证、任务到 checkpoint 的映射 | 选模型、选音色、写 `style` |
14
+ | 合成、响度归一、静音裁剪、强制对齐、自检打分 | 看错字率决定要不要换 seed 重配 |
15
+ | 旁白文件格式、JSON 输出、退出码 | 下载前把大小和许可证告诉用户、等用户同意 |
16
+ | 不隐式下载、不在 Line 内拼接音频 | 克隆前提醒用户确认有权使用这段声音;发布时提醒声明 AI 生成 |
17
+ | | 句子之间停多久(在 CueTake 的 Scenario 里定) |
18
+
19
+ ## 和 CueTake 的关系
20
+
21
+ ```
22
+ agent 写旁白 ──► voxx narrate ──► 旁白文件(补全 audio + words)+ 每句 WAV
23
+ │
24
+ ▼
25
+ cuetake record --narration <文件>
26
+ ```
27
+
28
+ 两个工具只靠文件交接,不互相调用([ADR 0001](adr/0001-narration-file-is-the-contract.md))。旁白格式与 levyxdev/cuetake#7 一致,但由 voxx 自己定义,代码里不依赖 CueTake。
29
+
30
+ ## 旁白文件
31
+
32
+ 输入:
33
+
34
+ ```json
35
+ {
36
+ "language": "zh",
37
+ "voice": "my-voice",
38
+ "style": "语气轻松,语速稍慢",
39
+ "lines": [
40
+ { "id": "intro", "text": "这是一个新的发送流程。" },
41
+ { "id": "send", "text": "点一下发送就完成了。", "style": "语气兴奋" }
42
+ ]
43
+ }
44
+ ```
45
+
46
+ - `language`:BCP 47 标签(规范大小写,如 zh、yue、en-US),一份旁白一种语言,必须和 Model 登记的语言完全一致(ADR 0005)。能用哪些语言跟随念它的 Model(Qwen3-TTS 支持 zh、en、ja、ko、fr、de、it、pt、ru、es),voxx 不另设限制;Model 不念这种语言时退出码 4。
47
+ - `voice`、`style`、`seed` 在顶层设默认值,单个 Line 可以覆盖。`style` 是自然语言,直接作为 instruct 传给模型;没有数值语速。不支持 `style` 的 Model(0.6B 快速档)照样念这个 Line,只在它的 `warnings` 里说明忽略了 `style`。
48
+ - 没写 `voice` 时,用 Model 里第一个以这种语言为母语的音色(中文 vivian、英文 ryan),没有就用它的第一个音色。
49
+ - 没写 `seed` 时由 voxx 随机生成。每个 Line 合成前都重新设 seed,所以同一个 Model、音色、`style`、文字和 seed 在同一台机器上念出逐字节相同的 WAV(真实模型测试验证过),也和 Line 的先后无关。输出的旁白文件原样当输入、带上同样的 `--model`,就能复现上一次(输入不读 Line 上的 `model`)。
50
+
51
+ 输出在每个 Line 上补上:`audio`、`words`(`[{ text, start, end }]`,相对该 Line 音频起点;中文按字)、`model`、`voice`、`seed`、`sample_rate`、自检错字率、`warnings`。
52
+
53
+ ## 命令
54
+
55
+ ```
56
+ voxx narrate <narration.json> --out <dir> [--model <id>] [--line <id>...] [--voices-dir <dir>] # 合成整份旁白;--model 选念它的 Model;--line 只重配指定 Line
57
+ voxx voice add <name> --ref <录音> [--ref-text <文字>] [--model <id>] [--voices-dir <dir>] [--overwrite] # 存一个 Cloned Voice
58
+ voxx voices [--voices-dir <dir>] # 列出 Preset Voice 和 Cloned Voice
59
+ voxx models # 注册表(只含可商用模型)
60
+ voxx install <model> # 唯一会下载的命令
61
+ voxx doctor # 平台、已装模型、磁盘
62
+ voxx schema # 所有命令的参数和返回结构
63
+ ```
64
+
65
+ 不对外提供 `align`、`transcribe`、`batch`:它们都只是 `narrate` 的内部步骤。
66
+
67
+ ## 一份旁白的处理流程
68
+
69
+ 1. CLI 校验旁白文件、确认所需模型已安装,然后启动 worker。
70
+ 2. worker 加载一次模型。
71
+ 3. 逐个 Line:整句一次合成 → 首尾静音裁到 50 ms → 响度归一到 -18 LUFS,峰值超过 -1 dBFS 的瞬间用限幅器压下去(压完仍差 0.5 LU 以上时加警告)→ 强制对齐得到 `words`(失败则不带 `words`,只加警告)→ ASR 听写回来算错字率 → 写单声道 WAV(保留模型原生采样率)。
72
+ 4. worker 退出,CLI 写出补全的旁白文件,在 stdout 打印一个 JSON 结果。
73
+
74
+ ## CLI 和 worker
75
+
76
+ agent 只运行 `voxx` 这个 CLI,永远看不到 worker。
77
+
78
+ - CLI 是轻的:解析参数、读注册表和旁白文件、管理音色、输出 JSON。它不 import mlx,所以 `models`、`schema` 这类命令立刻返回。
79
+ - 需要合成时,CLI 把 `python -m voxx.worker` 作为**子进程**启动,通过它的 stdin/stdout 收发 JSON-RPC 消息(「加载模型」「合成这一句」「对齐这一句」……),stderr 用来转发进度。
80
+ - 旁白念完,worker 退出,模型占用的内存随之释放。worker 崩溃(比如显存不够)时,CLI 仍然能给 agent 返回一个结构化的 JSON 错误。
81
+
82
+ JSON-RPC over stdio 和 MCP、LSP 用的是同一种传输方式,但这里它只是 voxx 内部两半之间的私有管道,不是给 agent 的接口。对 agent 的接口只有 CLI,和 CueTake 一样不做 MCP。决策见 [ADR 0002](adr/0002-synthesis-runs-in-a-worker-process.md)。
83
+
84
+ v0.1 的 worker 和 CLI 在同一个 Python 环境里。等第一个依赖冲突的引擎(比如 PyTorch 系的 CosyVoice 官方包)进来时,再给它单独建一个 venv,协议不变。
85
+
86
+ ## 模型
87
+
88
+ 只登记权重许可证允许商用的模型([ADR 0003](adr/0003-models-are-installed-only-by-an-explicit-command.md)),全部用 mlx 8bit,通过 mlx-audio 运行:
89
+
90
+ | 用途 | 模型 |
91
+ |---|---|
92
+ | Preset Voice(默认) | Qwen3-TTS-12Hz-1.7B-CustomVoice;0.6B 为快速档 |
93
+ | Cloned Voice(默认) | VoxCPM2 |
94
+ | Cloned Voice(对比项) | Qwen3-TTS-12Hz-1.7B-Base |
95
+ | 强制对齐 | Qwen3-ForcedAligner-0.6B |
96
+ | 自检听写、补参考录音文字 | Qwen3-ASR-0.6B |
97
+
98
+ 中文听感没有任何第三方评测,默认值等实际试听后再调整。理由和数据见调研报告。
99
+
100
+ ## 音色
101
+
102
+ - Preset Voice 按名字选,来自模型自带的音色。`voxx voices` 列出每个音色的母语、上游给的一句描述和能念它的 Model,agent 据此让用户挑。Qwen3-TTS CustomVoice 的 9 个音色全部登记,1.7B 和 0.6B 共用;不指定 `--model` 时由默认的 1.7B 念。
103
+ - Cloned Voice 先存再用:`voice add` 把参考录音规范化(单声道、24 kHz、-18 LUFS、首尾静音 50 ms)、补好文字(没给 `--ref-text` 时用 Qwen3-ASR 听写,这时它必须已安装),存成有名字的音色;旁白里用 `voice: "<名字>"` 引用。默认存在 `~/.voxx/voices/`,也可以用 `--voices-dir` 指向项目目录,`narrate` 和 `voices` 传同一个目录。`voice.json` 记下 `voice add --model` 选的克隆 Model(默认 VoxCPM2),`narrate` 默认用它念,`narrate --model` 可以换成另一个克隆 Model。两个克隆 Model 都不跟随 `style`。
104
+ - 代码不做授权校验,使用者对所克隆的声音负责,README 写免责声明([ADR 0004](adr/0004-cloning-does-not-check-consent.md))。不加水印。
105
+
106
+ ## CLI 契约
107
+
108
+ - stdout 永远是一个 JSON 对象:`{"ok": true, "data": {...}}` 或 `{"ok": false, "error": {"code", "message", "hint", "details"}}`。
109
+ - stderr 输出 NDJSON 进度。没有彩色、表格和交互式提示。
110
+
111
+ | 退出码 | 含义 | agent 该做什么 |
112
+ |---|---|---|
113
+ | 0 | 成功 | — |
114
+ | 1 | 内部错误 | 报告 |
115
+ | 2 | 参数错误 | 改参数 |
116
+ | 3 | 模型未安装 | 把大小和许可证告诉用户,同意后 `voxx install` |
117
+ | 4 | 模型不支持该能力 | 换模型 |
118
+
119
+ ## 存储
120
+
121
+ ```
122
+ $VOXX_HOME(默认 ~/.voxx)
123
+ models/ # 模型文件
124
+ voices/<name>/ # voice.json(来源、参考文字、念它的克隆 Model、听写它的 Model、创建时间)+ reference.wav(规范化后的参考录音)
125
+ ```
126
+
127
+ ## 平台与分发
128
+
129
+ - v0.1 只支持 Apple Silicon Mac。
130
+ - Python 实现,发布为 PyPI 上的 `voxx`。skill 里一行启动脚本运行 `uvx voxx@<固定版本>`,skill 和 CLI 从同一个 tag 发布。
131
+ - 本项目 Apache-2.0;不分发任何权重,依赖的上游项目见 `NOTICE`。
132
+
133
+ ## 待定 / 以后
134
+
135
+ - **发音处理**:模型念错产品名、缩写时怎么办。候选方案是发音词典加句内 `{原文|读法}` 标注,在合成前替换文字(整句仍一次念完),词级时间戳映射回原文。先试实际效果再决定。
136
+ - **Ming-3.0-tts-0.5B**:第三方英文评分最高,有显式语速和情绪参数,等 mlx-audio 移植补完整再加。
137
+ - 数值语速、常驻服务模式、每个引擎独立 venv、Linux/CUDA、CosyVoice3。
@@ -0,0 +1,15 @@
1
+ # 旁白文件是 voxx 唯一的输入输出契约
2
+
3
+ voxx 一次调用合成一整份旁白:读入 `{ language, lines: [{ id, text }] }`,为每个 Line 写出一个音频文件,再写回补全了 `audio` 和 `words` 的同一份旁白文件。这个格式和 CueTake 的 Narration(levyxdev/cuetake#7)一致,agent 可以直接把 voxx 的输出交给 `cuetake record --narration`,两个工具之间只靠文件交接,不互相调用,也没有常驻服务。格式由 voxx 自己定义,代码里不依赖 CueTake。
4
+
5
+ ## Considered options
6
+
7
+ - **每句一次 CLI 调用。** 否决:每次都要重新加载几 GB 的模型,十几句的旁白要多花几分钟。
8
+ - **常驻服务(HTTP 或 `serve --stdio`)。** v0.1 不做:调用方都是 agent,一份旁白一次调用已经只加载一次模型,常驻进程带来的生命周期管理不值得。
9
+ - **对外暴露 `align`、`transcribe`、`batch` 等原子命令。** 否决:强制对齐、语音识别和批量合成都只是合成一份旁白的内部步骤。
10
+
11
+ ## Consequences
12
+
13
+ - 改变旁白文件的字段要同时考虑 CueTake,属于跨仓库的变更。
14
+ - 单句重配也走同一个文件:指定 Line id 后只重新生成这些 Line,其他 Line 的音频不动。
15
+ - 一个 Line 永远由模型一次连续念完,不在 Line 内部拼接音频,保证听起来像人在说话。
@@ -0,0 +1,8 @@
1
+ # 合成在独立的 worker 进程里运行
2
+
3
+ CLI 不在自己的进程里加载模型,而是启动一个 worker 进程,用 JSON-RPC over stdio 通信,一份旁白念完 worker 就退出。这样 mlx 爆显存或崩溃时只会死掉 worker,CLI 仍能给 agent 返回结构化的错误;模型占用的几个 GB 内存随 worker 退出归还;CLI 自己不 import mlx,`voxx models`、`voxx schema` 这类命令能立刻返回。以后接入 PyTorch 系的引擎或加常驻模式,都沿用同一个协议。
4
+
5
+ ## Considered options
6
+
7
+ - **单进程、延迟 import。** 否决:代码最少,但崩溃时 agent 拿不到 JSON 错误,协议也要到以后再补。
8
+ - **每个引擎一个独立 venv。** 推迟:只有当两个引擎要求同一个依赖的不同版本时才需要(例如官方 CosyVoice 和 Qwen3-TTS 包各自锁定的 `transformers` 版本冲突)。v0.1 的模型都通过 mlx-audio 运行,worker 就是同一个包里的 `python -m voxx.worker`。
@@ -0,0 +1,13 @@
1
+ # 模型只通过显式的 install 命令下载
2
+
3
+ 任何命令都不会自己下载模型。缺模型时,命令以「未安装」失败,并说明需要安装哪个模型、多大、什么许可证;agent 按 skill 的要求把这些告诉用户,用户同意后才运行 `voxx install <model>`。这和 CueTake 的 `install-browser` 是同一套规矩,agent 只需要学一次。
4
+
5
+ 缺哪些模型才算失败,见 [ADR 0006](0006-only-the-model-that-reads-must-be-installed.md):只有念所必需的模型,辅助模型缺失降级为警告。
6
+
7
+ ## Considered options
8
+
9
+ - **consent token 加专门的退出码(DESIGN.md 草案)。** 否决:CLI 验证不了真的有人同意,token 只是多了一层复杂度,起不到额外的保护作用。
10
+
11
+ ## Consequences
12
+
13
+ - 注册表只登记权重许可证允许商用的模型,因为 voxx 的主要用途是给要发布的产品演示配音。
@@ -0,0 +1,8 @@
1
+ # 克隆不做授权校验,责任在使用者
2
+
3
+ voxx 无法判断参考录音是谁的声音,任何授权声明参数都能被一句话绕过,所以代码里不设授权门槛,也不要求授权声明。使用者对所克隆声音的权利负责,这一点写进 README 的免责声明;skill 要求 agent 在克隆前提醒用户确认自己有权使用这段声音,并在发布时按平台要求声明内容由 AI 生成。voxx 也不嵌入音频水印,只在输出里记录每个 Line 用的模型、音色和 seed。
4
+
5
+ ## Considered options
6
+
7
+ - **`voice add` 必须带授权声明(DESIGN.md 草案)。** 否决:声明无法核实,只增加了使用摩擦。
8
+ - **只允许克隆用户本人的声音。** 否决:同样无法在技术上区分是谁的声音,还会妨碍请配音员这样的正当用途。
@@ -0,0 +1,13 @@
1
+ # 旁白的 language 是 BCP 47 标签,按原样和 Model 的语言比对
2
+
3
+ v0.1 的 spec 原来规定 `language` 用 ISO 639-1 两字母代码,但 Qwen3-ASR 支持的粤语(`yue`)和菲律宾语(`fil`)没有两字母代码,所以改用 BCP 47。BCP 47 包含 ISO 639-1,原来的 `zh`、`en` 照样有效,CueTake 也本来就把 `language` 当作语言标签处理(如 `zh-CN`)。标签只接受规范大小写(`zh-Hant-HK`,不接受 `zh-hant-hk`),并且必须和 Model 登记的某个语言完全一致,voxx 不做 `en-US` → `en` 这样的逐级回退。
4
+
5
+ ## Considered options
6
+
7
+ - **按 RFC 4647 lookup 逐级回退。** 否决:`zh-HK` 会悄悄退成 `zh`,被当作普通话念出来;完全一致时 agent 会拿到 `unsupported_language` 和 Model 实际登记的语言列表,自己改成正确的标签。
8
+ - **不区分大小写。** 否决:只有一种写法时,比对和输出都不会出现歧义;大小写写错时,报错会给出规范写法。
9
+
10
+ ## Consequences
11
+
12
+ - 一个 Model 能念 `en`,不代表它能念 `en-US`:注册表登记什么,旁白就得写什么。
13
+ - 自检也按完全一致来找能听写这种语言的 Model,所以 `en-GB` 的旁白不会交给只登记了 `en` 的 Model 听写,而是带 `not_checked` 警告。
@@ -0,0 +1,13 @@
1
+ # 只有念所必需的 Model 没装才失败,辅助 Model 没装降级为警告
2
+
3
+ ADR 0003 说缺模型时命令以「未安装」失败。`narrate` 原先把它用到一个 Line 用到的每个 Model 上:念的 Model、对齐 Model 和听写 Model 缺一个,整次运行就以退出码 3 失败。但三者地位不同:念的 Model 产出音频,没有它什么都做不了;对齐 Model 只产出 `words`,听写 Model 只产出 `transcript` 和 `error_rate` 这份质量报告,缺了它们音频照样能用。所以现在只有念的 Model 没装才以 `model_not_installed` 失败;对齐或听写 Model 没装时,每个 Line 照常念,只是不带相应字段,各带一条 `aligner_not_installed` 或 `checker_not_installed` 警告,details 给出那个 Model 的 id、大小、许可证和安装命令。这样用户只装一个 TTS Model 也能用 voxx,agent 仍然拿到足够的信息去问用户要不要补装。
4
+
5
+ ## Considered options
6
+
7
+ - **维持全部必需。** 否决:第一次用 voxx 要先下三个 Model,其中两个对很多用途(不需要字幕、自己会听)只是锦上添花。
8
+ - **辅助 Model 缺失时只在结果顶层报一次。** 否决:警告和缺的字段都在 Line 上,agent 逐个 Line 判断时不必再回头看别处;`--line` 重念的 Line 也自然带上自己的警告。
9
+
10
+ ## Consequences
11
+
12
+ - 警告 code 和「这种语言没有 Model」的 `not_aligned`/`not_checked` 分开:后者装什么都补不上,前者装一个 Model 再 `--line` 重念就能补上。
13
+ - 规则只看这一步能不能做下去。`voice add` 没给参考录音文字时要靠听写 Model 补文字,那一步没有它做不下去,所以那里听写 Model 仍是必需的。