@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
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Structural views of the host's HTTP seams.
3
+ *
4
+ * Kept in one module so the panel route, the audio route, and the daemon agree
5
+ * on the same shapes instead of each declaring its own near-copy.
6
+ */
7
+ import type { IncomingMessage, ServerResponse } from 'node:http';
8
+ /** One route registration understood by the host router. */
9
+ export interface RegisterableRoute {
10
+ kind: 'exact' | 'prefix';
11
+ path: string;
12
+ handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;
13
+ }
14
+ /** Structural view of the host `webServer` service; only `register` is used. */
15
+ export interface HttpRouteRegistrar {
16
+ register(route: RegisterableRoute): () => void;
17
+ getOrigin?(): string | undefined;
18
+ }
19
+ /** Structural view of the host connection fence. */
20
+ export interface ConnectionFence {
21
+ requestRejection?(input: {
22
+ headers: Record<string, string | string[] | undefined>;
23
+ }): 401 | 403 | undefined;
24
+ allowsRemoteAuthorities?: boolean;
25
+ }
26
+ //# sourceMappingURL=http-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-types.d.ts","sourceRoot":"","sources":["../src/http-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAEhE,4DAA4D;AAC5D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7E;AAED,gFAAgF;AAChF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAAA;IAC9C,SAAS,CAAC,IAAI,MAAM,GAAG,SAAS,CAAA;CACjC;AAED,oDAAoD;AACpD,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;KAAE,GAAG,GAAG,GAAG,GAAG,GAAG,SAAS,CAAA;IAC3G,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAClC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=http-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-types.js","sourceRoot":"","sources":["../src/http-types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * DSH entry point: config, tools, and the two host adapters (model + engine).
3
+ *
4
+ * The heavy lifting lives in `pipeline.ts`, which knows nothing about cordis.
5
+ * This file is the only place that touches the host, so the pipeline stays
6
+ * testable without a running DSH.
7
+ */
8
+ import type { Context } from '@deepseek-ai/cordis';
9
+ import { type ToolDefinition } from '@deepseek-ai/dsh-tools';
10
+ import z from '@deepseek-ai/schemastery';
11
+ import { type StyleProfile } from './pipeline.ts';
12
+ export declare const name = "dsh-voiceover";
13
+ /** The tool registry must exist before `apply` runs. */
14
+ export declare const inject: string[];
15
+ /** Config schema exposed to the DSH settings layer. */
16
+ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
17
+ outputDir: z<string, string, "plain">;
18
+ defaultVoice: z<string, string, "defined">;
19
+ defaultRate: z<string, string, "defined">;
20
+ style: z<"lecture" | "news" | "story" | "docs", "lecture" | "news" | "story" | "docs", "defined">;
21
+ auditSample: z<number, number, "defined">;
22
+ llmBaseUrl: z<string, string, "plain">;
23
+ llmApiKey: z<string, string, "plain">;
24
+ llmModel: z<string, string, "defined">;
25
+ trustedHosts: z<string[], string[], "plain">;
26
+ chapterChars: z<number, number, "defined">;
27
+ }>>, Schemastery.ObjectT<NoInfer<{
28
+ outputDir: z<string, string, "plain">;
29
+ defaultVoice: z<string, string, "defined">;
30
+ defaultRate: z<string, string, "defined">;
31
+ style: z<"lecture" | "news" | "story" | "docs", "lecture" | "news" | "story" | "docs", "defined">;
32
+ auditSample: z<number, number, "defined">;
33
+ llmBaseUrl: z<string, string, "plain">;
34
+ llmApiKey: z<string, string, "plain">;
35
+ llmModel: z<string, string, "defined">;
36
+ trustedHosts: z<string[], string[], "plain">;
37
+ chapterChars: z<number, number, "defined">;
38
+ }>>, "plain">;
39
+ /** Config accepted by {@link apply}. */
40
+ export interface VoiceoverConfig {
41
+ outputDir?: string;
42
+ defaultVoice?: string;
43
+ defaultRate?: string;
44
+ style?: StyleProfile;
45
+ auditSample?: number;
46
+ llmBaseUrl?: string;
47
+ llmApiKey?: string;
48
+ llmModel?: string;
49
+ /** Extra Host names accepted by the audio route (reverse proxies). */
50
+ trustedHosts?: string[];
51
+ /** Target characters per chapter when planning without a model. */
52
+ chapterChars?: number;
53
+ }
54
+ /** Tool definitions; separated so tests can inspect them without a host. */
55
+ export declare function createVoiceoverTools(ctx: Context, config: VoiceoverConfig, env?: NodeJS.ProcessEnv): ToolDefinition[];
56
+ /** Route prefix for per-chapter audio; distinct from the engine's own prefix. */
57
+ export declare const VOICEOVER_AUDIO_PREFIX = "/voiceover/audio";
58
+ /** Mount the tools. Registration is fiber-owned, so unloading cleans up. */
59
+ export declare function apply(ctx: Context, config?: VoiceoverConfig): void;
60
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACxE,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAQxC,OAAO,EAAiF,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAIhI,eAAO,MAAM,IAAI,kBAAkB,CAAA;AAEnC,wDAAwD;AACxD,eAAO,MAAM,MAAM,UAAY,CAAA;AAE/B,uDAAuD;AACvD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;aAcjB,CAAA;AAEF,wCAAwC;AACxC,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,YAAY,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AA0HD,4EAA4E;AAC5E,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,eAAe,EACvB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,cAAc,EAAE,CA+OlB;AAED,iFAAiF;AACjF,eAAO,MAAM,sBAAsB,qBAAqB,CAAA;AA4DxD,4EAA4E;AAC5E,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,eAAoB,GAAG,IAAI,CAKtE"}
package/dist/index.js ADDED
@@ -0,0 +1,410 @@
1
+ import { defineTool } from '@deepseek-ai/dsh-tools';
2
+ import z from '@deepseek-ai/schemastery';
3
+ import { AudioRoute } from '@leiboss/dsh-tts';
4
+ import { readFile, stat } from 'node:fs/promises';
5
+ import { homedir } from 'node:os';
6
+ import { join } from 'node:path';
7
+ import { httpCompleter } from "./llm.js";
8
+ import { PanelRoute } from "./panel.js";
9
+ import { rerunProject } from "./operations.js";
10
+ import { normalizeSource, projectKey, runProject } from "./pipeline.js";
11
+ import { readJson } from "./util.js";
12
+ export const name = 'dsh-voiceover';
13
+ /** The tool registry must exist before `apply` runs. */
14
+ export const inject = ['tools'];
15
+ /** Config schema exposed to the DSH settings layer. */
16
+ export const Config = z.object({
17
+ outputDir: z.string().description('Project root. Defaults to $DSH_HOME/voiceover.'),
18
+ defaultVoice: z.string().default('zh-CN-XiaoxiaoNeural').description('Voice used when a call omits one.'),
19
+ defaultRate: z.string().default('+0%').description('Speech rate used when a call omits one.'),
20
+ style: z
21
+ .union([z.const('lecture'), z.const('news'), z.const('story'), z.const('docs')])
22
+ .default('news')
23
+ .description('Default spoken-script style.'),
24
+ auditSample: z.number().default(2).description('Chapters always audited from the start of the book.'),
25
+ llmBaseUrl: z.string().description('OpenAI-compatible base URL, for example https://api.deepseek.com/v1.'),
26
+ llmApiKey: z.string().description('API key for the model endpoint.'),
27
+ llmModel: z.string().default('deepseek-chat').description('Model name recorded in the manifest.'),
28
+ trustedHosts: z.array(z.string()).description('Extra Host names accepted by the audio route (reverse proxies).'),
29
+ chapterChars: z.number().default(1400).description('Target characters per chapter when planning without a model.'),
30
+ });
31
+ /** Resolve the project root without requiring DSH_HOME. */
32
+ function resolveOutputDir(config, env) {
33
+ if (config.outputDir !== undefined && config.outputDir.length > 0)
34
+ return config.outputDir;
35
+ const home = env.DSH_HOME ?? join(homedir(), '.dsh');
36
+ return join(home, 'voiceover');
37
+ }
38
+ /** Read an optional cordis service without a static dependency. */
39
+ function serviceOf(ctx, key) {
40
+ const getter = ctx.get;
41
+ return typeof getter === 'function' ? getter.call(ctx, key) : undefined;
42
+ }
43
+ /** Adapt `ctx.tts` to the pipeline's narrow synthesizer port. */
44
+ function engineSynthesizer(ctx) {
45
+ return {
46
+ async synthesize(request) {
47
+ const service = serviceOf(ctx, 'tts');
48
+ if (service === undefined) {
49
+ throw new Error('No TTS engine is available: install @leiboss/dsh-tts, or add it to the same profile as @leiboss/dsh-voiceover.');
50
+ }
51
+ const result = await service.synthesize(request);
52
+ if (result.kind === 'speechSynthesis') {
53
+ throw new Error(`No host engine could produce audio (${result.reason}). Voiceover needs a file, so fix the engine first.`);
54
+ }
55
+ // The manifest schema requires a positive byte count, so measure it here
56
+ // rather than trusting the engine to report its own file size.
57
+ const bytes = (await stat(result.filePath)).size;
58
+ return {
59
+ filePath: result.filePath,
60
+ bytes,
61
+ durationMs: result.durationMs,
62
+ timingQuality: result.timingQuality,
63
+ format: result.format === 'wav' ? 'wav' : 'mp3',
64
+ engine: result.engine,
65
+ ...(result.words === undefined ? {} : { words: result.words }),
66
+ };
67
+ },
68
+ };
69
+ }
70
+ /** One in-flight run per project: a second create must not fork the same job. */
71
+ const inFlight = new Map();
72
+ /** Build the model port from config; absent config means "no model". */
73
+ function completer(config) {
74
+ if (config.llmBaseUrl === undefined || config.llmBaseUrl.length === 0)
75
+ return undefined;
76
+ return httpCompleter({
77
+ baseUrl: config.llmBaseUrl,
78
+ model: config.llmModel ?? 'deepseek-chat',
79
+ apiKey: config.llmApiKey,
80
+ label: config.llmModel ?? 'deepseek-chat',
81
+ });
82
+ }
83
+ /** Build the pipeline collaborators for one call site. */
84
+ function pipelineDeps(ctx, config) {
85
+ const model = completer(config);
86
+ return {
87
+ ...(model === undefined ? {} : { completer: model }),
88
+ synth: engineSynthesizer(ctx),
89
+ };
90
+ }
91
+ /**
92
+ * Start a rerun in the background, deduped per project.
93
+ *
94
+ * Both callers (the `voiceover_rerun` Tool and the panel button) land here; the
95
+ * operation itself lives in `operations.ts`, so neither path owns a copy.
96
+ */
97
+ function startRerun(ctx, config, outputDir, projectId, chapters) {
98
+ if (inFlight.has(projectId))
99
+ return;
100
+ const logger = typeof ctx.logger === 'function' ? ctx.logger('@leiboss/dsh-voiceover') : undefined;
101
+ const run = rerunProject(pipelineDeps(ctx, config), {
102
+ outputDir,
103
+ projectId,
104
+ auditSample: config.auditSample ?? 2,
105
+ ...(chapters === undefined ? {} : { chapters }),
106
+ });
107
+ inFlight.set(projectId, run);
108
+ void run
109
+ .catch((error) => {
110
+ logger?.warn?.(`voiceover rerun failed: ${String(error)}`);
111
+ })
112
+ .finally(() => {
113
+ inFlight.delete(projectId);
114
+ });
115
+ }
116
+ /** Tool definitions; separated so tests can inspect them without a host. */
117
+ export function createVoiceoverTools(ctx, config, env = process.env) {
118
+ const outputDir = resolveOutputDir(config, env);
119
+ const deps = pipelineDeps(ctx, config);
120
+ const create = defineTool({
121
+ name: 'voiceover_create',
122
+ description: [
123
+ 'Turn a long document into a set of chapter audio files with subtitles.',
124
+ 'Returns immediately with a projectId; poll `voiceover_status` for progress.',
125
+ 'Prefer `sourcePath` over `sourceText` for anything longer than a few paragraphs.',
126
+ ].join(' '),
127
+ parameters: {
128
+ sourcePath: { type: 'string', description: 'Path to a local .md or .txt file. Preferred for long documents.' },
129
+ sourceText: { type: 'string', description: 'Inline source text, for short documents only.' },
130
+ title: { type: 'string', description: 'Title used for the manifest and chapter planning.' },
131
+ voice: { type: 'string', description: `Edge TTS voice. Defaults to ${config.defaultVoice ?? 'zh-CN-XiaoxiaoNeural'}.` },
132
+ style: { type: 'string', description: 'Spoken style: lecture, news, story, or docs.' },
133
+ },
134
+ output: {
135
+ schema: {
136
+ type: 'object',
137
+ additionalProperties: false,
138
+ properties: {
139
+ projectId: { type: 'string', description: 'Stable identity derived from source + settings.' },
140
+ projectDir: { type: 'string', description: 'Directory holding audio, subtitles, scripts, and the manifest.' },
141
+ status: { type: 'string', description: 'Always `running` for a new project.' },
142
+ },
143
+ },
144
+ render: (_args, value) => [
145
+ {
146
+ type: 'text',
147
+ text: [
148
+ `Voiceover project ${value.projectId ?? ''} started. Directory: ${value.projectDir ?? ''}. Poll voiceover_status for per-chapter progress.`,
149
+ // Stable token the conversation panel parses to poll its JSON route.
150
+ `projectId: ${value.projectId ?? ''}`,
151
+ ].join('\n'),
152
+ },
153
+ ],
154
+ },
155
+ async execute(args) {
156
+ if (args.sourcePath === undefined && args.sourceText === undefined) {
157
+ throw new Error('Provide either sourcePath or sourceText.');
158
+ }
159
+ if (args.sourcePath !== undefined && !/\.(md|markdown|txt)$/i.test(args.sourcePath)) {
160
+ throw new Error('Only .md and .txt sources are supported in this version.');
161
+ }
162
+ const text = args.sourcePath === undefined ? (args.sourceText ?? '') : await readFile(args.sourcePath, 'utf8');
163
+ const title = args.title !== undefined && args.title.length > 0
164
+ ? args.title
165
+ : (args.sourcePath?.replace(/\.[^.]+$/, '').split(/[\\/]/).pop() ?? '未命名');
166
+ const voice = args.voice ?? config.defaultVoice ?? 'zh-CN-XiaoxiaoNeural';
167
+ const style = (args.style ?? config.style ?? 'news');
168
+ const rate = config.defaultRate ?? '+0%';
169
+ // The id must match what the pipeline will compute: it keys projects by
170
+ // the normalised text, so reporting the raw text here would hand the
171
+ // panel an id that never appears on disk (and poll 404 forever).
172
+ const projectId = projectKey({ text: normalizeSource(text), voice, rate, style });
173
+ const logger = typeof ctx.logger === 'function' ? ctx.logger('@leiboss/dsh-voiceover') : undefined;
174
+ if (!inFlight.has(projectId)) {
175
+ const run = runProject(deps, {
176
+ outputDir,
177
+ title,
178
+ text,
179
+ voice,
180
+ rate,
181
+ style,
182
+ network: true,
183
+ auditSample: config.auditSample ?? 2,
184
+ ...(config.chapterChars === undefined ? {} : { chapterChars: config.chapterChars }),
185
+ });
186
+ inFlight.set(projectId, run);
187
+ void run
188
+ .catch((error) => {
189
+ logger?.warn?.(`voiceover run failed: ${String(error)}`);
190
+ })
191
+ .finally(() => {
192
+ inFlight.delete(projectId);
193
+ });
194
+ }
195
+ return { projectId, projectDir: join(outputDir, projectId), status: 'running' };
196
+ },
197
+ });
198
+ const status = defineTool({
199
+ name: 'voiceover_status',
200
+ description: 'Report per-chapter progress for a voiceover project. Reads persisted state; safe to poll.',
201
+ parameters: {
202
+ projectId: { type: 'string', required: true, description: 'Id returned by voiceover_create.' },
203
+ },
204
+ output: {
205
+ schema: {
206
+ type: 'object',
207
+ additionalProperties: false,
208
+ properties: {
209
+ projectId: { type: 'string', description: 'Project identity.' },
210
+ done: { type: 'number', description: 'Chapters finished.' },
211
+ total: { type: 'number', description: 'Chapters planned.' },
212
+ chapters: {
213
+ type: 'array',
214
+ description: 'Per-chapter status rows.',
215
+ items: {
216
+ type: 'object',
217
+ additionalProperties: false,
218
+ properties: {
219
+ id: { type: 'string', description: 'Chapter id such as ch-01.' },
220
+ title: { type: 'string', description: 'Chapter title.' },
221
+ status: { type: 'string', description: 'Lifecycle status.' },
222
+ error: { type: 'string', description: 'Error code when the chapter failed; omitted otherwise.' },
223
+ durationMs: { type: 'number', description: 'Audio duration in milliseconds; omitted before synthesis.' },
224
+ subtitles: { type: 'string', description: 'Subtitle path relative to the project; omitted when absent.' },
225
+ },
226
+ },
227
+ },
228
+ warnings: { type: 'array', items: { type: 'string' }, description: 'Degradations recorded by the pipeline.' },
229
+ },
230
+ },
231
+ render: (_args, value) => [
232
+ {
233
+ type: 'text',
234
+ text: [
235
+ `projectId: ${value.projectId ?? ''}`,
236
+ `${value.done}/${value.total} chapters done.`,
237
+ ...(value.chapters ?? []).map((chapter) => `${chapter.id ?? ''} ${chapter.title ?? ''} - ${chapter.status ?? 'unknown'}${chapter.error === undefined ? '' : ` (${chapter.error})`}`),
238
+ ...((value.warnings ?? []).length === 0 ? [] : ['Warnings:', ...(value.warnings ?? []).map((warning) => `- ${warning}`)]),
239
+ ].join('\n'),
240
+ },
241
+ ],
242
+ },
243
+ async execute(args) {
244
+ const projectId = args.projectId;
245
+ const state = await readJson(join(outputDir, projectId, 'state', 'state.json'));
246
+ if (state === undefined)
247
+ throw new Error(`Unknown project: ${projectId}`);
248
+ const done = state.chapters.filter((chapter) => chapter.status === 'done').length;
249
+ return {
250
+ projectId,
251
+ done,
252
+ total: state.outline.chapters.length,
253
+ chapters: state.chapters.map((chapter) => ({
254
+ id: chapter.id,
255
+ title: chapter.title,
256
+ status: chapter.status,
257
+ ...(chapter.error === undefined ? {} : { error: chapter.error.code }),
258
+ ...(chapter.audio === undefined ? {} : { durationMs: chapter.audio.durationMs }),
259
+ ...(chapter.subtitles === undefined ? {} : { subtitles: chapter.subtitles.path }),
260
+ })),
261
+ warnings: state.warnings,
262
+ };
263
+ },
264
+ });
265
+ const exportTool = defineTool({
266
+ name: 'voiceover_export',
267
+ description: 'List or resolve a finished project’s artifacts (audio, subtitles, manifest).',
268
+ parameters: {
269
+ projectId: { type: 'string', required: true, description: 'Id returned by voiceover_create.' },
270
+ },
271
+ output: {
272
+ schema: {
273
+ type: 'object',
274
+ additionalProperties: false,
275
+ properties: {
276
+ projectDir: { type: 'string', description: 'Project directory.' },
277
+ manifest: { type: 'string', description: 'Absolute path to manifest.json.' },
278
+ audio: { type: 'array', items: { type: 'string' }, description: 'Absolute audio paths.' },
279
+ subtitles: { type: 'array', items: { type: 'string' }, description: 'Absolute subtitle paths.' },
280
+ },
281
+ },
282
+ render: (_args, value) => [
283
+ {
284
+ type: 'text',
285
+ text: [
286
+ `Project: ${value.projectDir}`,
287
+ `Manifest: ${value.manifest}`,
288
+ ...(value.audio ?? []).map((path) => `Audio: ${path}`),
289
+ ...(value.subtitles ?? []).map((path) => `Subtitles: ${path}`),
290
+ ].join('\n'),
291
+ },
292
+ ],
293
+ },
294
+ async execute(args) {
295
+ const projectId = args.projectId;
296
+ const projectDir = join(outputDir, projectId);
297
+ const state = await readJson(join(projectDir, 'state', 'state.json'));
298
+ if (state === undefined)
299
+ throw new Error(`Unknown project: ${projectId}`);
300
+ return {
301
+ projectDir,
302
+ manifest: join(projectDir, 'manifest.json'),
303
+ audio: state.chapters.flatMap((chapter) => (chapter.audio === undefined ? [] : [join(projectDir, chapter.audio.path)])),
304
+ subtitles: state.chapters.flatMap((chapter) => chapter.subtitles === undefined ? [] : [join(projectDir, chapter.subtitles.path)]),
305
+ };
306
+ },
307
+ });
308
+ const rerun = defineTool({
309
+ name: 'voiceover_rerun',
310
+ description: 'Resume a voiceover project: finished chapters are skipped, failed or missing ones run again. Returns immediately; poll voiceover_status.',
311
+ parameters: {
312
+ projectId: { type: 'string', required: true, description: 'Id returned by voiceover_create.' },
313
+ chapter: {
314
+ type: 'string',
315
+ description: 'Only this chapter, for example ch-03. Omit to resume every unfinished chapter.',
316
+ },
317
+ },
318
+ output: {
319
+ schema: {
320
+ type: 'object',
321
+ additionalProperties: false,
322
+ properties: {
323
+ projectId: { type: 'string', description: 'Project identity.' },
324
+ status: { type: 'string', description: 'Always `running`; poll voiceover_status.' },
325
+ },
326
+ },
327
+ render: (_args, value) => [
328
+ {
329
+ type: 'text',
330
+ text: [`Resuming project ${value.projectId ?? ''}.`, `projectId: ${value.projectId ?? ''}`].join('\n'),
331
+ },
332
+ ],
333
+ }, async execute(args) {
334
+ const projectId = args.projectId;
335
+ const chapter = args.chapter;
336
+ if (chapter !== undefined && !/^ch-[0-9]{2,3}$/.test(chapter)) {
337
+ throw new Error('chapter must look like ch-03');
338
+ }
339
+ startRerun(ctx, config, outputDir, projectId, chapter === undefined ? undefined : [chapter]);
340
+ return { projectId, status: 'running' };
341
+ },
342
+ });
343
+ return [create, status, exportTool, rerun];
344
+ }
345
+ /** Route prefix for per-chapter audio; distinct from the engine's own prefix. */
346
+ export const VOICEOVER_AUDIO_PREFIX = '/voiceover/audio';
347
+ /**
348
+ * Mount the progress panel and the audio route behind the host fence.
349
+ *
350
+ * The audio route is the engine's `AudioRoute` with a different prefix: it
351
+ * already mints signed, expiring URLs, serves Range requests for seeking, and
352
+ * checks Host/Origin plus the browser session. Reusing it keeps one
353
+ * implementation of that security surface instead of two.
354
+ */
355
+ function mountWebSurfaces(ctx, config, env = process.env) {
356
+ const outputDir = resolveOutputDir(config, env);
357
+ const connection = serviceOf(ctx, 'connection');
358
+ const logger = typeof ctx.logger === 'function' ? ctx.logger('@leiboss/dsh-voiceover') : undefined;
359
+ const debug = (message) => {
360
+ logger?.debug?.(message);
361
+ };
362
+ const audio = new AudioRoute({
363
+ outputDir,
364
+ prefix: VOICEOVER_AUDIO_PREFIX,
365
+ trustedHosts: config.trustedHosts ?? [],
366
+ ...(connection === undefined ? {} : { connection }),
367
+ debug,
368
+ });
369
+ const panel = new PanelRoute({
370
+ outputDir,
371
+ ...(connection === undefined ? {} : { connection }),
372
+ audioUrlFor: (filePath) => audio.urlFor(filePath),
373
+ onRerun: (projectId, chapter) => startRerun(ctx, config, outputDir, projectId, chapter === undefined ? undefined : [chapter]),
374
+ debug,
375
+ });
376
+ const register = (registrar) => {
377
+ try {
378
+ const origin = registrar.getOrigin?.();
379
+ if (origin !== undefined)
380
+ audio.setOrigin(origin);
381
+ }
382
+ catch {
383
+ // No advertised origin: the panel uses same-origin relative URLs anyway.
384
+ }
385
+ ctx.effect(() => audio.register(registrar));
386
+ ctx.effect(() => panel.register(registrar));
387
+ };
388
+ // The Web host provides `webServer`; older hosts exposed the same router as
389
+ // `httpServer`. Without either (headless, file://), the panel and playback do
390
+ // not render and the tools still work.
391
+ const web = serviceOf(ctx, 'webServer') ?? serviceOf(ctx, 'httpServer');
392
+ if (web !== undefined) {
393
+ register(web);
394
+ return;
395
+ }
396
+ ctx.inject(['webServer'], (webCtx) => {
397
+ const late = webCtx.webServer;
398
+ if (late === undefined)
399
+ return;
400
+ register(late);
401
+ });
402
+ }
403
+ /** Mount the tools. Registration is fiber-owned, so unloading cleans up. */
404
+ export function apply(ctx, config = {}) {
405
+ for (const tool of createVoiceoverTools(ctx, config)) {
406
+ ctx.tools.register(tool);
407
+ }
408
+ mountWebSurfaces(ctx, config);
409
+ }
410
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/llm.d.ts ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * The model boundary. The pipeline depends on this narrow `Completer` port, not
3
+ * on any particular provider, so it runs identically inside DSH (host adapter),
4
+ * against an OpenAI-compatible endpoint, and in tests (a scripted fake).
5
+ */
6
+ import { type Prompt } from './prompts.ts';
7
+ /** One completion request. */
8
+ export interface CompletionRequest {
9
+ system: string;
10
+ user: string;
11
+ temperature?: number;
12
+ signal?: AbortSignal;
13
+ }
14
+ /** Anything that can answer one prompt. */
15
+ export interface Completer {
16
+ complete(request: CompletionRequest): Promise<string>;
17
+ /** Human-facing identity recorded in the manifest, for example `deepseek-chat`. */
18
+ readonly model?: string;
19
+ }
20
+ /** Failure with a routable code; callers distinguish retryable from terminal. */
21
+ export declare class LlmError extends Error {
22
+ readonly code: string;
23
+ readonly retryable: boolean;
24
+ constructor(code: string, message: string, retryable: boolean);
25
+ }
26
+ /**
27
+ * Pull one JSON value out of a model reply. Tolerates fences and leading prose,
28
+ * but never invents structure: a reply without a JSON object is an error.
29
+ */
30
+ export declare function extractJson(text: string): unknown;
31
+ /** Options for {@link callJson}. */
32
+ export interface CallJsonOptions {
33
+ temperature?: number;
34
+ signal?: AbortSignal;
35
+ /** Extra attempts that only repair structure; defaults to 1. */
36
+ repairRounds?: number;
37
+ }
38
+ /**
39
+ * Ask for JSON, validate it, and repair structure once before giving up. The
40
+ * repair pass never re-runs the task, only the shape, so a bad outline cannot
41
+ * silently become a different outline.
42
+ */
43
+ export declare function callJson<T>(completer: Completer, prompt: Prompt, validate: (value: unknown) => T, options?: CallJsonOptions): Promise<T>;
44
+ /** Options for {@link httpCompleter}. */
45
+ export interface HttpCompleterOptions {
46
+ /** Base URL including `/v1`, for example `https://api.deepseek.com/v1`. */
47
+ baseUrl: string;
48
+ model: string;
49
+ apiKey?: string;
50
+ timeoutMs?: number;
51
+ fetchImpl?: typeof fetch;
52
+ /** Recorded in the manifest; defaults to `model`. */
53
+ label?: string;
54
+ }
55
+ /**
56
+ * OpenAI-compatible chat completions. Injecting `fetchImpl` keeps every test
57
+ * offline and lets the same adapter serve a local gateway.
58
+ */
59
+ export declare function httpCompleter(options: HttpCompleterOptions): Completer;
60
+ //# sourceMappingURL=llm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAA;AAGxD,8BAA8B;AAC9B,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,2CAA2C;AAC3C,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACrD,mFAAmF;IACnF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,iFAAiF;AACjF,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;gBAEf,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO;CAM9D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAajD;AAED,oCAAoC;AACpC,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC,EAC/B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,CAAC,CAAC,CA6BZ;AAED,yCAAyC;AACzC,MAAM,WAAW,oBAAoB;IACnC,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACxB,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,SAAS,CA4CtE"}