@leiboss/dsh-tts 0.0.0-stage → 0.2.1
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.
- package/CHANGELOG.md +74 -0
- package/LICENSE +21 -0
- package/README.md +352 -2
- package/cordis.patch.yml +4 -0
- package/dist/audio-route.d.ts +116 -0
- package/dist/audio-route.d.ts.map +1 -0
- package/dist/audio-route.js +406 -0
- package/dist/audio-route.js.map +1 -0
- package/dist/cache.d.ts +41 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +105 -0
- package/dist/cache.js.map +1 -0
- package/dist/chunked-tts.d.ts +34 -0
- package/dist/chunked-tts.d.ts.map +1 -0
- package/dist/chunked-tts.js +121 -0
- package/dist/chunked-tts.js.map +1 -0
- package/dist/chunker.d.ts +19 -0
- package/dist/chunker.d.ts.map +1 -0
- package/dist/chunker.js +98 -0
- package/dist/chunker.js.map +1 -0
- package/dist/client.js +90 -0
- package/dist/concurrency.d.ts +33 -0
- package/dist/concurrency.d.ts.map +1 -0
- package/dist/concurrency.js +95 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/config.d.ts +133 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +143 -0
- package/dist/config.js.map +1 -0
- package/dist/edge-tts.d.ts +74 -0
- package/dist/edge-tts.d.ts.map +1 -0
- package/dist/edge-tts.js +154 -0
- package/dist/edge-tts.js.map +1 -0
- package/dist/errors.d.ts +47 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +68 -0
- package/dist/errors.js.map +1 -0
- package/dist/fallback.d.ts +55 -0
- package/dist/fallback.d.ts.map +1 -0
- package/dist/fallback.js +79 -0
- package/dist/fallback.js.map +1 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +617 -0
- package/dist/index.js.map +1 -0
- package/dist/probe.d.ts +42 -0
- package/dist/probe.d.ts.map +1 -0
- package/dist/probe.js +63 -0
- package/dist/probe.js.map +1 -0
- package/dist/provider.d.ts +33 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +7 -0
- package/dist/provider.js.map +1 -0
- package/dist/sapi-tts.d.ts +29 -0
- package/dist/sapi-tts.d.ts.map +1 -0
- package/dist/sapi-tts.js +131 -0
- package/dist/sapi-tts.js.map +1 -0
- package/dist/self-check.d.ts +24 -0
- package/dist/self-check.d.ts.map +1 -0
- package/dist/self-check.js +72 -0
- package/dist/self-check.js.map +1 -0
- package/dist/voices.d.ts +21 -0
- package/dist/voices.d.ts.map +1 -0
- package/dist/voices.js +74 -0
- package/dist/voices.js.map +1 -0
- package/icon.svg +6 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +88 -4
package/dist/fallback.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ErrorCode, TtsError } from "./errors.js";
|
|
2
|
+
import { isSapiSupported, synthesizeSapi, } from "./sapi-tts.js";
|
|
3
|
+
/** Codes that mean "the engine failed", not "the request is invalid". */
|
|
4
|
+
const FALLBACK_ELIGIBLE = new Set([
|
|
5
|
+
ErrorCode.EdgeTtsNotFound,
|
|
6
|
+
ErrorCode.SpawnEperm,
|
|
7
|
+
ErrorCode.SpawnFailed,
|
|
8
|
+
ErrorCode.EdgeTtsFailed,
|
|
9
|
+
ErrorCode.SynthesisTimeout,
|
|
10
|
+
ErrorCode.EmptyAudio,
|
|
11
|
+
]);
|
|
12
|
+
/** Whether a failed Edge-TTS attempt is worth retrying with another engine. */
|
|
13
|
+
export function isFallbackEligible(error) {
|
|
14
|
+
return error instanceof TtsError && FALLBACK_ELIGIBLE.has(error.code);
|
|
15
|
+
}
|
|
16
|
+
function describe(error) {
|
|
17
|
+
if (error instanceof TtsError)
|
|
18
|
+
return `${error.code}: ${error.detail}`;
|
|
19
|
+
return error instanceof Error ? error.message : String(error);
|
|
20
|
+
}
|
|
21
|
+
function allFailed(order, attempts, primaryError) {
|
|
22
|
+
const reasons = attempts
|
|
23
|
+
.map((attempt) => `${attempt.engine} (${attempt.reason})`)
|
|
24
|
+
.join('; ');
|
|
25
|
+
return new TtsError(ErrorCode.AllFallbacksFailed, `All configured TTS fallbacks failed. Chain: ${order.join(' -> ')}. Tried: ${reasons}. Engines: ${JSON.stringify(order)}.`, 'Install edge-tts and restore network access, or include `speechSynthesis` in `fallbackOrder`.', { cause: primaryError });
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Run the configured engines after Edge-TTS already failed. `edge-tts` in
|
|
29
|
+
* `fallbackOrder` marks the primary attempt rather than a retry.
|
|
30
|
+
*/
|
|
31
|
+
export async function runFallback(options, deps = {}) {
|
|
32
|
+
const platform = deps.platform ?? process.platform;
|
|
33
|
+
const sapiImpl = deps.synthesizeSapiImpl ?? synthesizeSapi;
|
|
34
|
+
const attempts = [
|
|
35
|
+
{
|
|
36
|
+
engine: 'edge-tts',
|
|
37
|
+
reason: `primary engine failed: ${describe(options.primaryError)}`,
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
// Local array narrowing keeps the literal union readable in the loop.
|
|
41
|
+
const order = options.fallbackOrder;
|
|
42
|
+
for (const engine of order) {
|
|
43
|
+
if (engine === 'edge-tts')
|
|
44
|
+
continue;
|
|
45
|
+
if (engine === 'sapi') {
|
|
46
|
+
if (!isSapiSupported(platform)) {
|
|
47
|
+
attempts.push({ engine, reason: `skipped: SAPI is Windows-only (${platform})` });
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const audio = await sapiImpl(options.text, {
|
|
52
|
+
rate: options.rate,
|
|
53
|
+
outputDir: options.outputDir,
|
|
54
|
+
hash: options.hash,
|
|
55
|
+
timeoutMs: options.timeoutMs,
|
|
56
|
+
signal: options.signal,
|
|
57
|
+
spawnImpl: deps.spawnImpl,
|
|
58
|
+
now: options.now,
|
|
59
|
+
platform,
|
|
60
|
+
powershellBinary: deps.powershellBinary,
|
|
61
|
+
ffmpegBinary: deps.ffmpegBinary,
|
|
62
|
+
});
|
|
63
|
+
attempts.push({ engine, reason: 'succeeded' });
|
|
64
|
+
return { kind: 'audio', audio, engine, attempts };
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (error instanceof TtsError && error.code === ErrorCode.Aborted)
|
|
68
|
+
throw error;
|
|
69
|
+
attempts.push({ engine, reason: describe(error) });
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (engine === 'speechSynthesis') {
|
|
74
|
+
return { kind: 'speechSynthesis', engine: 'speechSynthesis', attempts };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
throw allFailed(order, attempts, options.primaryError);
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=fallback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fallback.js","sourceRoot":"","sources":["../src/fallback.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DSH tool plugin: text in, a durable audio file out.
|
|
3
|
+
*
|
|
4
|
+
* The plugin owns exactly one capability — Edge-TTS synthesis into
|
|
5
|
+
* `$DSH_HOME/tts-output` — and exposes it through `tts_generate` plus a
|
|
6
|
+
* side-effect-free `tts_self_check`. It deliberately implements no playback,
|
|
7
|
+
* transcription, voice cloning, or multi-provider routing.
|
|
8
|
+
*/
|
|
9
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
10
|
+
import { type ToolDefinition } from '@deepseek-ai/dsh-tools';
|
|
11
|
+
import { type AudioUrlProvider } from './audio-route.ts';
|
|
12
|
+
import { ConcurrencyLimiter } from './concurrency.ts';
|
|
13
|
+
import { type ResolvedConfig, type TtsConfig } from './config.ts';
|
|
14
|
+
import { type SpawnFunction, type SynthesizedAudio } from './edge-tts.ts';
|
|
15
|
+
import type { SapiOptions } from './sapi-tts.ts';
|
|
16
|
+
import { type ProbeConnector } from './probe.ts';
|
|
17
|
+
export { Config } from './config.ts';
|
|
18
|
+
export type { TtsConfig } from './config.ts';
|
|
19
|
+
export type { TTSProvider, SynthesizeOptions, SynthesizeResult, } from './provider.ts';
|
|
20
|
+
export { ErrorCode, TtsError } from './errors.ts';
|
|
21
|
+
export { cacheKey, findCachedFile } from './cache.ts';
|
|
22
|
+
export { runProcess, synthesize } from './edge-tts.ts';
|
|
23
|
+
export { selfCheck } from './self-check.ts';
|
|
24
|
+
export { AUDIO_ROUTE_PREFIX, AudioRoute } from './audio-route.ts';
|
|
25
|
+
export { DEFAULT_CHUNK_SIZE, splitText } from './chunker.ts';
|
|
26
|
+
export { synthesizeChunked } from './chunked-tts.ts';
|
|
27
|
+
export { ConcurrencyLimiter, type ConcurrencyLimits } from './concurrency.ts';
|
|
28
|
+
export { isFallbackEligible, runFallback } from './fallback.ts';
|
|
29
|
+
export { isSapiSupported, sapiRate, synthesizeSapi } from './sapi-tts.ts';
|
|
30
|
+
export { AVAILABLE_VOICES, VOICES, type VoiceInfo } from './voices.ts';
|
|
31
|
+
export declare const name = "dsh-tts";
|
|
32
|
+
/** The registry must exist before `apply` runs. */
|
|
33
|
+
export declare const inject: string[];
|
|
34
|
+
/** Pitch Edge-TTS uses when the call omits one. */
|
|
35
|
+
export declare const DEFAULT_PITCH = "+0Hz";
|
|
36
|
+
/** Volume Edge-TTS uses when the call omits one. */
|
|
37
|
+
export declare const DEFAULT_VOLUME = "+0%";
|
|
38
|
+
/** Injection points used by tests; production always uses the defaults. */
|
|
39
|
+
export interface TtsDependencies {
|
|
40
|
+
spawnImpl?: SpawnFunction;
|
|
41
|
+
now?: () => Date;
|
|
42
|
+
/** Present when a web route was registered; enables `browserUrl`. */
|
|
43
|
+
audioRoute?: AudioUrlProvider;
|
|
44
|
+
/** Override the pause between chunk subprocesses (tests use 0). */
|
|
45
|
+
chunkDelayMs?: number;
|
|
46
|
+
/** Platform override, so non-Windows tests can exercise the SAPI branch. */
|
|
47
|
+
platform?: NodeJS.Platform;
|
|
48
|
+
/** Injected SAPI implementation; defaults to the real PowerShell path. */
|
|
49
|
+
sapiSynthesize?: (text: string, options: SapiOptions) => Promise<SynthesizedAudio>;
|
|
50
|
+
powershellBinary?: string;
|
|
51
|
+
ffmpegBinary?: string;
|
|
52
|
+
/** Inject a limiter to share one capacity pool across tool instances. */
|
|
53
|
+
limiter?: ConcurrencyLimiter;
|
|
54
|
+
/** Debug sink for fallback timing; never receives call arguments. */
|
|
55
|
+
log?: (message: string) => void;
|
|
56
|
+
/** Injected TCP connector for `tts_probe_network`; tests use a local server. */
|
|
57
|
+
probeConnect?: ProbeConnector;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Build both tool definitions from one resolved config. Exported so tests can
|
|
61
|
+
* exercise the real `execute` bodies with an injected spawn implementation.
|
|
62
|
+
*/
|
|
63
|
+
export declare function createTtsTools(config: ResolvedConfig, deps?: TtsDependencies): ToolDefinition[];
|
|
64
|
+
/**
|
|
65
|
+
* Mount both tools. Registration is fiber-owned, so unloading the plugin
|
|
66
|
+
* unregisters them without explicit cleanup.
|
|
67
|
+
*/
|
|
68
|
+
export declare function apply(ctx: Context, config?: Partial<TtsConfig>): void;
|
|
69
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|