@leiboss/dsh-voiceover 0.0.0-stage → 0.3.0

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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +187 -2
  3. package/client/client.js +985 -0
  4. package/cordis.patch.yml +13 -0
  5. package/dist/api.d.ts +52 -0
  6. package/dist/api.d.ts.map +1 -0
  7. package/dist/api.js +301 -0
  8. package/dist/api.js.map +1 -0
  9. package/dist/cli.d.ts +40 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +303 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/client.js +985 -0
  14. package/dist/http-types.d.ts +26 -0
  15. package/dist/http-types.d.ts.map +1 -0
  16. package/dist/http-types.js +2 -0
  17. package/dist/http-types.js.map +1 -0
  18. package/dist/index.d.ts +60 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +410 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/llm.d.ts +60 -0
  23. package/dist/llm.d.ts.map +1 -0
  24. package/dist/llm.js +113 -0
  25. package/dist/llm.js.map +1 -0
  26. package/dist/operations.d.ts +41 -0
  27. package/dist/operations.d.ts.map +1 -0
  28. package/dist/operations.js +77 -0
  29. package/dist/operations.js.map +1 -0
  30. package/dist/panel.d.ts +42 -0
  31. package/dist/panel.d.ts.map +1 -0
  32. package/dist/panel.js +212 -0
  33. package/dist/panel.js.map +1 -0
  34. package/dist/pipeline.d.ts +141 -0
  35. package/dist/pipeline.d.ts.map +1 -0
  36. package/dist/pipeline.js +519 -0
  37. package/dist/pipeline.js.map +1 -0
  38. package/dist/prompts.d.ts +58 -0
  39. package/dist/prompts.d.ts.map +1 -0
  40. package/dist/prompts.js +169 -0
  41. package/dist/prompts.js.map +1 -0
  42. package/dist/serve-entry.d.ts +3 -0
  43. package/dist/serve-entry.d.ts.map +1 -0
  44. package/dist/serve-entry.js +11 -0
  45. package/dist/serve-entry.js.map +1 -0
  46. package/dist/snapshot.d.ts +48 -0
  47. package/dist/snapshot.d.ts.map +1 -0
  48. package/dist/snapshot.js +82 -0
  49. package/dist/snapshot.js.map +1 -0
  50. package/dist/subtitle.d.ts +49 -0
  51. package/dist/subtitle.d.ts.map +1 -0
  52. package/dist/subtitle.js +163 -0
  53. package/dist/subtitle.js.map +1 -0
  54. package/dist/types.d.ts +148 -0
  55. package/dist/types.d.ts.map +1 -0
  56. package/dist/types.js +10 -0
  57. package/dist/types.js.map +1 -0
  58. package/dist/util.d.ts +16 -0
  59. package/dist/util.d.ts.map +1 -0
  60. package/dist/util.js +47 -0
  61. package/dist/util.js.map +1 -0
  62. package/dist/validate.d.ts +15 -0
  63. package/dist/validate.d.ts.map +1 -0
  64. package/dist/validate.js +186 -0
  65. package/dist/validate.js.map +1 -0
  66. package/dist/version.d.ts +3 -0
  67. package/dist/version.d.ts.map +1 -0
  68. package/dist/version.js +3 -0
  69. package/dist/version.js.map +1 -0
  70. package/package.json +83 -3
  71. package/schemas/manifest.schema.json +132 -0
  72. package/schemas/outline.schema.json +40 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 leiboss
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,188 @@
1
- # Temporary Holding Version
1
+ # @leiboss/dsh-voiceover
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 把一篇长文变成一套可发布的有声内容:分章、口播化改写、逐章合成、字幕、manifest,可中断可续跑。
4
+
5
+ 不是「把一句话读出来」——那是 `@leiboss/dsh-tts` 的 `tts_generate`。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ dsh plugin --profile <profile> add @leiboss/dsh-voiceover
11
+ ```
12
+
13
+ 会连带挂载引擎 `@leiboss/dsh-tts`(见 `cordis.patch.yml`)。
14
+
15
+ 配置(DSH 配置层):
16
+
17
+ | 项 | 默认 | 说明 |
18
+ |---|---|---|
19
+ | `outputDir` | `$DSH_HOME/voiceover` | 项目根目录 |
20
+ | `defaultVoice` | `zh-CN-XiaoxiaoNeural` | 默认音色 |
21
+ | `defaultRate` | `+0%` | 默认语速 |
22
+ | `style` | `news` | `lecture` / `news` / `story` / `docs` |
23
+ | `auditSample` | `2` | 前 N 章必检;长章(>3000 字)也必检 |
24
+ | `llmBaseUrl` | 空 | OpenAI 兼容端点;为空则按原文朗读 |
25
+ | `llmApiKey` | 空 | 端点密钥 |
26
+ | `llmModel` | `deepseek-chat` | 记录进 manifest |
27
+
28
+ ## 用法
29
+
30
+ ```text
31
+ 把 D:\docs\ai-engineering.md 做成有声书,女声,每章带字幕
32
+ ```
33
+
34
+ 1. `voiceover_create` — 立即返回 `projectId`,后台开始跑
35
+ 2. `voiceover_status` — 轮询逐章进度
36
+ 3. `voiceover_export` — 拿到音频、字幕、manifest 的绝对路径
37
+
38
+ ## 产物
39
+
40
+ ```
41
+ <outputDir>/<projectId>/
42
+ source/normalized.md
43
+ script/ch-01.md
44
+ audio/ch-01.mp3
45
+ audio/ch-01.est.srt # estimated 时带 .est
46
+ state/state.json # 断点续跑依据
47
+ manifest.json # 契约,schema 见 schemas/
48
+ ```
49
+
50
+ ## 降级矩阵
51
+
52
+ | 模型 | 网络 | 行为 | 产物 |
53
+ |---|---|---|---|
54
+ | ✅ | ✅ | 完整流水线 | 口播稿 + 精确/估算字幕 |
55
+ | ✅ | ❌ | 改写照做,合成走本地引擎 | 文稿好、音色机械 |
56
+ | ❌ | ✅ | 按原文直读 | 书面语,字幕估算 |
57
+ | ❌ | ❌ | 最简模式 | 可听、无改写 |
58
+
59
+ 降级都会写进 `manifest.warnings` 与 `capability`,不静默。
60
+
61
+ ## 已知限制
62
+
63
+ - 只支持 `.md` / `.txt` 输入(PDF/DOCX 待做)
64
+ - 运行跟随宿主进程;宿主要求「创建即返回」,所以长任务在后台,进程退出即中断(可用 `voiceover_status` 续跑)
65
+ - 字幕质量为 `estimated` 时文件名带 `.est`,不要当帧级精确使用
66
+ - 暂无 UI 面板 / daemon / zip 导出
67
+ ## 对话内进度面板
68
+
69
+ `voiceover_create` / `voiceover_status` 的结果下方会渲染一个进度面板(仅 DSH Web 宿主):
70
+
71
+ - 标题 + `完成/总章数` + 进度条
72
+ - 能力条:`模型 改写`/`按原文朗读`、`Edge 可达`/`本地引擎`、`字幕 精确`/`估算`
73
+ - 逐章状态(排队/改写/合成/完成/失败)、时长、是否带字幕
74
+ - 降级与失败原因(warnings)
75
+ - 多语言:面板文案注册在客户端 locale 命名空间 `voiceover`(`zh` / `en` 两套字典),跟随宿主语言切换实时重渲染;
76
+ 宿主没有 locale 服务时回退中文
77
+ - 无障碍:进度条是 `role="progressbar"`(带 `aria-valuetext`),状态词是 `aria-live="polite"` 播报区,
78
+ 按钮为原生 `<button>` 且带可见焦点环,纯装饰的计数对屏幕阅读器隐藏
79
+
80
+ 面板从工具结果里取 `projectId`,随后轮询宿主只读路由 `GET /voiceover/panel/<projectId>.json`
81
+ (同一会话围栏,只返回进度,不返回稿件正文与文件路径)。首章规划期间显示「准备中」,
82
+ 不再误报接口不可用。
83
+
84
+ **试听**:面板顶部有一个播放器,每章行尾的 `▶` 切换到该章;URL 是宿主签发的同源链接
85
+ (`/voiceover/audio/...`,有效期 6 小时、与浏览器会话绑定),刷新进度不会打断播放。
86
+ 无 Web 宿主时不显示播放控件,用 `voiceover_export` 拿文件路径。要续跑失败的章节,
87
+ 对同一份源文再执行一次 `voiceover_create` 即可(项目 ID 由内容哈希决定,已完成的章节会跳过)。
88
+ ## 续跑
89
+
90
+ 失败章节不必重建整个项目,可以整项目续跑,也可以只重跑一章:
91
+
92
+ - 整项目:对 agent 说「续跑这个项目」→ `voiceover_rerun`(只传 `projectId`),或点面板底部的「重跑 N 章」
93
+ - 单章:`voiceover_rerun` 传 `chapter: "ch-03"`,或点该章行尾的「重试」
94
+ - 未指定的章节保持原状(文件与状态都不动),id 写错会直接报错而不是静默什么也不做
95
+
96
+ 两条路径调用的是同一个宿主实现(`src/operations.ts` 的 `rerunProject`),面板按钮只是 POST
97
+ `/voiceover/panel/<projectId>/rerun`。已完成的章节按内容哈希跳过,失败或缺失的重新跑;
98
+ `style` 会随 state 持久化,所以重算出的 projectId 与原来一致——不一致时操作会报错拒绝,
99
+ 而不是悄悄写进另一个目录。
100
+
101
+ ## 工具
102
+
103
+ | 工具 | 作用 |
104
+ |---|---|
105
+ | `voiceover_create` | 建项目,立即返回 `projectId` |
106
+ | `voiceover_status` | 查看逐章进度 |
107
+ | `voiceover_export` | 返回音频、字幕、manifest 的绝对路径 |
108
+ | `voiceover_rerun` | 续跑:跳过已完成章节;传 `chapter` 时只重跑该章 |
109
+ ## 本地 daemon
110
+
111
+ ```powershell
112
+ $env:DSH_VOICEOVER_TOKEN = "<random>"
113
+ node dist/serve-entry.js serve --port 7801 [--host 127.0.0.1] [--output <dir>]
114
+ ```
115
+
116
+ 只绑回环地址;无 token 拒绝启动。除 `/healthz` 外每个请求都要
117
+ `Authorization: Bearer <token>`。
118
+
119
+ | 方法 | 路径 | 作用 |
120
+ |---|---|---|
121
+ | GET | `/healthz` | 存活与版本(免 token) |
122
+ | GET | `/v1/doctor` | 引擎自检 + 端点探测 |
123
+ | POST | `/v1/tts` | 短句合成 → `{ filePath, durationMs, timingQuality, engine }` |
124
+ | POST | `/v1/voiceover` | 建项目 → `202 { projectId, statusUrl }`(`sourcePath` 或 `sourceText` 二选一) |
125
+ | GET | `/v1/projects/:id` | 与面板同源的进度快照 |
126
+ | GET | `/v1/projects/:id/manifest` | 完整 manifest |
127
+ | POST | `/v1/projects/:id/rerun` | 续跑 → `202`;body 可选 `{"chapter":"ch-03"}` |
128
+ | GET | `/v1/projects/:id/audio/:chapter.mp3` | 音频,支持 `Range`(206) |
129
+ | GET | `/v1/projects/:id/subtitles/:chapter(.est).srt` | 字幕 |
130
+
131
+ ```powershell
132
+ curl -H "Authorization: Bearer $env:DSH_VOICEOVER_TOKEN" `
133
+ -H "content-type: application/json" `
134
+ -d '{"sourcePath":"D:\\docs\\a.md","style":"news"}' `
135
+ http://127.0.0.1:7801/v1/voiceover
136
+ ```
137
+
138
+ 建项目和续跑都是异步的:立即返回 202,进度靠 `/v1/projects/:id` 轮询。
139
+ 上游限流时 `/v1/tts` 返回 `429` + `Retry-After: 30`(引擎自身会先按 2s/6s/18s
140
+ 退避重试同一引擎,预算耗尽才降级),调用方照 `Retry-After` 重试即可。
141
+ ## 字幕怎么看(重要)
142
+
143
+ `.srt` 是旁挂文件,**Windows 自带播放器和浏览器都不会自动加载它**。三种能真正看到字幕的方式:
144
+
145
+ | 方式 | 需要什么 | 适用 |
146
+ |---|---|---|
147
+ | 面板内播放 | 无 | 在 DSH 里试听:播放器下方按时间轴显示当前这一句 |
148
+ | VLC 等支持旁挂字幕的播放器 | 把 `ch-01.srt` 与 `ch-01.mp3` 放同目录同名 | 本机任意系统 |
149
+ | 浏览器 `<track>` | 用 `.vtt`(面板路由已提供转换) | 自建网页播放器 |
150
+ | 封装成 MP4 / 烧录进画面 | ffmpeg | Windows 自带播放器、发给别人 |
151
+
152
+ ### 面板内
153
+
154
+ 播放某章时,进度条下方的文本会跟着朗读实时切换——字幕面板只从
155
+ `GET /voiceover/panel/<id>/subtitles/<chapter>` 取,不额外落盘。
156
+
157
+ ### VLC
158
+
159
+ ```
160
+ ch-01.mp3
161
+ ch-01.srt ← 同名同目录
162
+ ```
163
+
164
+ VLC 打开 mp3 会自动加载同名字幕;Windows 的「电影和电视」「Media Player」不会。
165
+
166
+ ### 浏览器
167
+
168
+ `<audio>` 元素不渲染字幕,必须用 `<video>` 承载(音频轨也能放在 video 里):
169
+
170
+ ```html
171
+ <video controls src="/voiceover/audio/...">
172
+ <track kind="subtitles" srclang="zh" label="中文" default
173
+ src="/voiceover/panel/<id>/subtitles/ch-01.vtt">
174
+ </video>
175
+ ```
176
+
177
+ ### 封装或烧录(让 Windows 自带播放器也能看)
178
+
179
+ ```bash
180
+ # 封装:MP4 + mov_text 字幕轨(VLC / 部分播放器可切换)
181
+ ffmpeg -i ch-01.mp3 -i ch-01.srt -map 0:a -map 1:0 -c:a copy -c:s mov_text ch-01.mp4
182
+
183
+ # 烧录:字幕画在画面里,任何播放器都能看(需要先造一路视频画面)
184
+ ffmpeg -f lavfi -i color=c=black:s=1280x720:r=1 -i ch-01.mp3 -vf "subtitles=ch-01.srt" \
185
+ -shortest -c:a aac -c:v libx264 ch-01-burned.mp4
186
+ ```
187
+
188
+ 这两条命令需要 ffmpeg;插件不内置它,也不会因为缺它而失败。