@storyteller-platform/ghost-story 0.0.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/LICENSE.md +611 -0
- package/README.md +18 -0
- package/dist/api/APIOptions.cjs +16 -0
- package/dist/api/APIOptions.d.cts +18 -0
- package/dist/api/APIOptions.d.ts +18 -0
- package/dist/api/APIOptions.js +0 -0
- package/dist/api/Recognition.cjs +263 -0
- package/dist/api/Recognition.d.cts +77 -0
- package/dist/api/Recognition.d.ts +77 -0
- package/dist/api/Recognition.js +233 -0
- package/dist/api/VoiceActivityDetection.cjs +77 -0
- package/dist/api/VoiceActivityDetection.d.cts +24 -0
- package/dist/api/VoiceActivityDetection.d.ts +24 -0
- package/dist/api/VoiceActivityDetection.js +43 -0
- package/dist/audio/AudioConverter.cjs +331 -0
- package/dist/audio/AudioConverter.d.cts +53 -0
- package/dist/audio/AudioConverter.d.ts +53 -0
- package/dist/audio/AudioConverter.js +310 -0
- package/dist/audio/AudioFormat.cjs +151 -0
- package/dist/audio/AudioFormat.d.cts +25 -0
- package/dist/audio/AudioFormat.d.ts +25 -0
- package/dist/audio/AudioFormat.js +123 -0
- package/dist/audio/AudioSource.cjs +119 -0
- package/dist/audio/AudioSource.d.cts +33 -0
- package/dist/audio/AudioSource.d.ts +33 -0
- package/dist/audio/AudioSource.js +88 -0
- package/dist/audio/index.cjs +74 -0
- package/dist/audio/index.d.cts +6 -0
- package/dist/audio/index.d.ts +6 -0
- package/dist/audio/index.js +54 -0
- package/dist/cli/bin.cjs +277 -0
- package/dist/cli/bin.d.cts +1 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +275 -0
- package/dist/cli/config.cjs +347 -0
- package/dist/cli/config.d.cts +33 -0
- package/dist/cli/config.d.ts +33 -0
- package/dist/cli/config.js +285 -0
- package/dist/cli/install.cjs +334 -0
- package/dist/cli/install.d.cts +62 -0
- package/dist/cli/install.d.ts +62 -0
- package/dist/cli/install.js +316 -0
- package/dist/cli/whisper-server.cjs +172 -0
- package/dist/cli/whisper-server.d.cts +24 -0
- package/dist/cli/whisper-server.d.ts +24 -0
- package/dist/cli/whisper-server.js +152 -0
- package/dist/config.cjs +60 -0
- package/dist/config.d.cts +12 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.js +32 -0
- package/dist/convert.cjs +88 -0
- package/dist/convert.d.cts +12 -0
- package/dist/convert.d.ts +12 -0
- package/dist/convert.js +63 -0
- package/dist/encodings/Ascii.cjs +75 -0
- package/dist/encodings/Ascii.d.cts +13 -0
- package/dist/encodings/Ascii.d.ts +13 -0
- package/dist/encodings/Ascii.js +48 -0
- package/dist/encodings/Base64.cjs +155 -0
- package/dist/encodings/Base64.d.cts +5 -0
- package/dist/encodings/Base64.d.ts +5 -0
- package/dist/encodings/Base64.js +129 -0
- package/dist/encodings/TextEncodingsCommon.cjs +16 -0
- package/dist/encodings/TextEncodingsCommon.d.cts +6 -0
- package/dist/encodings/TextEncodingsCommon.d.ts +6 -0
- package/dist/encodings/TextEncodingsCommon.js +0 -0
- package/dist/index.cjs +153 -0
- package/dist/index.d.cts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +140 -0
- package/dist/recognition/AmazonTranscribeSTT.cjs +188 -0
- package/dist/recognition/AmazonTranscribeSTT.d.cts +21 -0
- package/dist/recognition/AmazonTranscribeSTT.d.ts +21 -0
- package/dist/recognition/AmazonTranscribeSTT.js +160 -0
- package/dist/recognition/AzureCognitiveServicesSTT.cjs +124 -0
- package/dist/recognition/AzureCognitiveServicesSTT.d.cts +21 -0
- package/dist/recognition/AzureCognitiveServicesSTT.d.ts +21 -0
- package/dist/recognition/AzureCognitiveServicesSTT.js +95 -0
- package/dist/recognition/DeepgramSTT.cjs +172 -0
- package/dist/recognition/DeepgramSTT.d.cts +23 -0
- package/dist/recognition/DeepgramSTT.d.ts +23 -0
- package/dist/recognition/DeepgramSTT.js +153 -0
- package/dist/recognition/GoogleCloudSTT.cjs +125 -0
- package/dist/recognition/GoogleCloudSTT.d.cts +35 -0
- package/dist/recognition/GoogleCloudSTT.d.ts +35 -0
- package/dist/recognition/GoogleCloudSTT.js +107 -0
- package/dist/recognition/OpenAICloudSTT.cjs +180 -0
- package/dist/recognition/OpenAICloudSTT.d.cts +29 -0
- package/dist/recognition/OpenAICloudSTT.d.ts +29 -0
- package/dist/recognition/OpenAICloudSTT.js +150 -0
- package/dist/recognition/WhisperCppSTT.cjs +296 -0
- package/dist/recognition/WhisperCppSTT.d.cts +40 -0
- package/dist/recognition/WhisperCppSTT.d.ts +40 -0
- package/dist/recognition/WhisperCppSTT.js +275 -0
- package/dist/recognition/WhisperServerSTT.cjs +119 -0
- package/dist/recognition/WhisperServerSTT.d.cts +24 -0
- package/dist/recognition/WhisperServerSTT.d.ts +24 -0
- package/dist/recognition/WhisperServerSTT.js +105 -0
- package/dist/utilities/FileSystem.cjs +54 -0
- package/dist/utilities/FileSystem.d.cts +3 -0
- package/dist/utilities/FileSystem.d.ts +3 -0
- package/dist/utilities/FileSystem.js +20 -0
- package/dist/utilities/Locale.cjs +46 -0
- package/dist/utilities/Locale.d.cts +9 -0
- package/dist/utilities/Locale.d.ts +9 -0
- package/dist/utilities/Locale.js +20 -0
- package/dist/utilities/ObjectUtilities.cjs +41 -0
- package/dist/utilities/ObjectUtilities.d.cts +3 -0
- package/dist/utilities/ObjectUtilities.d.ts +3 -0
- package/dist/utilities/ObjectUtilities.js +7 -0
- package/dist/utilities/Timeline.cjs +120 -0
- package/dist/utilities/Timeline.d.cts +23 -0
- package/dist/utilities/Timeline.d.ts +23 -0
- package/dist/utilities/Timeline.js +94 -0
- package/dist/utilities/Timing.cjs +287 -0
- package/dist/utilities/Timing.d.cts +64 -0
- package/dist/utilities/Timing.d.ts +64 -0
- package/dist/utilities/Timing.js +256 -0
- package/dist/utilities/WhisperTimeline.cjs +344 -0
- package/dist/utilities/WhisperTimeline.d.cts +86 -0
- package/dist/utilities/WhisperTimeline.d.ts +86 -0
- package/dist/utilities/WhisperTimeline.js +313 -0
- package/dist/vad/ActiveGate.cjs +357 -0
- package/dist/vad/ActiveGate.d.cts +53 -0
- package/dist/vad/ActiveGate.d.ts +53 -0
- package/dist/vad/ActiveGate.js +329 -0
- package/dist/vad/ActiveGateOg.cjs +1366 -0
- package/dist/vad/ActiveGateOg.d.cts +33 -0
- package/dist/vad/ActiveGateOg.d.ts +33 -0
- package/dist/vad/ActiveGateOg.js +1341 -0
- package/dist/vad/Silero.cjs +174 -0
- package/dist/vad/Silero.d.cts +25 -0
- package/dist/vad/Silero.d.ts +25 -0
- package/dist/vad/Silero.js +153 -0
- package/package.json +125 -0
package/dist/cli/bin.cjs
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
var import_zli = require("@robingenz/zli");
|
|
26
|
+
var import_zod = require("zod");
|
|
27
|
+
var import_config = require("./config.cjs");
|
|
28
|
+
var import_install = require("./install.cjs");
|
|
29
|
+
var import_whisper_server = require("./whisper-server.cjs");
|
|
30
|
+
const whisperModelSchema = import_zod.z.enum(import_config.WHISPER_MODELS);
|
|
31
|
+
const buildVariantSchema = import_zod.z.enum(import_config.BUILD_VARIANTS);
|
|
32
|
+
function isInstallTarget(value) {
|
|
33
|
+
return ["binary", "model", "vad", "all"].includes(value);
|
|
34
|
+
}
|
|
35
|
+
const installCommand = (0, import_zli.defineCommand)({
|
|
36
|
+
description: `Install whisper.cpp binary and models.
|
|
37
|
+
|
|
38
|
+
Usage:
|
|
39
|
+
storywhisper install binary [variant] - Install binary (auto-detects platform if variant not specified)
|
|
40
|
+
storywhisper install model <model> - Install a whisper model
|
|
41
|
+
storywhisper install vad - Install Silero VAD model
|
|
42
|
+
storywhisper install all - Install binary, all models, and VAD`,
|
|
43
|
+
args: import_zod.z.union([
|
|
44
|
+
import_zod.z.tuple([
|
|
45
|
+
import_zod.z.enum(["binary", "model", "vad", "all"]).describe("What to install: binary, model, vad, or all")
|
|
46
|
+
]),
|
|
47
|
+
import_zod.z.tuple([
|
|
48
|
+
import_zod.z.enum(["binary", "model", "vad", "all"]).describe("What to install: binary, model, vad, or all"),
|
|
49
|
+
import_zod.z.string().optional().describe("Variant (for binary) or model name (for model)")
|
|
50
|
+
])
|
|
51
|
+
]),
|
|
52
|
+
options: (0, import_zli.defineOptions)(
|
|
53
|
+
import_zod.z.object({
|
|
54
|
+
force: import_zod.z.boolean().default(false).describe("Force installation even if platform doesn't match"),
|
|
55
|
+
list: import_zod.z.boolean().default(false).describe("List available variants or models")
|
|
56
|
+
}),
|
|
57
|
+
{ f: "force", l: "list" }
|
|
58
|
+
),
|
|
59
|
+
action: async (options, args) => {
|
|
60
|
+
const [target, argument] = args;
|
|
61
|
+
const force = options.force;
|
|
62
|
+
const list = options.list;
|
|
63
|
+
if (list) {
|
|
64
|
+
if (target === "binary") {
|
|
65
|
+
console.log("Available binary variants:");
|
|
66
|
+
const compatible = (0, import_config.getCompatibleVariants)();
|
|
67
|
+
for (const variant of import_config.BUILD_VARIANTS) {
|
|
68
|
+
const isCompatible = compatible.includes(variant);
|
|
69
|
+
const marker = isCompatible ? "(compatible)" : "";
|
|
70
|
+
console.log(` ${variant} ${marker}`);
|
|
71
|
+
}
|
|
72
|
+
console.log("\nCompatible variants for this platform:");
|
|
73
|
+
for (const variant of compatible) {
|
|
74
|
+
console.log(` ${variant}`);
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (target === "model") {
|
|
79
|
+
console.log("Available whisper models:");
|
|
80
|
+
for (const model of import_config.WHISPER_MODELS) {
|
|
81
|
+
console.log(` ${model}`);
|
|
82
|
+
}
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
console.error("Use --list with 'binary' or 'model'");
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
if (!isInstallTarget(target)) {
|
|
89
|
+
console.error(`Unknown install target: ${target}`);
|
|
90
|
+
console.error("Valid targets: binary, model, vad, all");
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
if (target === "binary" || target === "all") {
|
|
95
|
+
const variant = argument && (0, import_config.isValidVariant)(argument) ? argument : void 0;
|
|
96
|
+
await (0, import_install.installBinary)({ variant, force, printOutput: true });
|
|
97
|
+
}
|
|
98
|
+
if (target === "model") {
|
|
99
|
+
if (!argument) {
|
|
100
|
+
console.error(
|
|
101
|
+
"Model name required. Usage: storywhisper install model <model>"
|
|
102
|
+
);
|
|
103
|
+
console.error("\nAvailable models:");
|
|
104
|
+
for (const m of import_config.WHISPER_MODELS) {
|
|
105
|
+
console.log(` ${m}`);
|
|
106
|
+
}
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
if (!(0, import_config.isValidModel)(argument)) {
|
|
110
|
+
console.error(`Unknown model: ${argument}`);
|
|
111
|
+
console.error("\nAvailable models:");
|
|
112
|
+
for (const m of import_config.WHISPER_MODELS) {
|
|
113
|
+
console.log(` ${m}`);
|
|
114
|
+
}
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
await (0, import_install.installModel)({ model: argument, force, printOutput: true });
|
|
118
|
+
}
|
|
119
|
+
if (target === "all") {
|
|
120
|
+
console.log("\nInstalling all whisper models...");
|
|
121
|
+
for (const m of import_config.WHISPER_MODELS) {
|
|
122
|
+
await (0, import_install.installModel)({ model: m, force, printOutput: true });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (target === "vad" || target === "all") {
|
|
126
|
+
await (0, import_install.installVadModel)({ force, printOutput: true });
|
|
127
|
+
}
|
|
128
|
+
console.log("\nInstallation complete!");
|
|
129
|
+
} catch (error) {
|
|
130
|
+
if (error instanceof import_install.PlatformMismatchError) {
|
|
131
|
+
console.error(`Error: ${error.message}`);
|
|
132
|
+
console.error("\nCompatible variants for this platform:");
|
|
133
|
+
for (const v of error.compatibleVariants) {
|
|
134
|
+
console.log(` ${v}`);
|
|
135
|
+
}
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
const statusCommand = (0, import_zli.defineCommand)({
|
|
143
|
+
description: "Show installation status",
|
|
144
|
+
action: () => {
|
|
145
|
+
const installed = (0, import_config.getInstalledVariant)();
|
|
146
|
+
if (installed) {
|
|
147
|
+
console.log(`Installed variant: ${installed}`);
|
|
148
|
+
} else {
|
|
149
|
+
console.log("No binary installed");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
const serverCommand = (0, import_zli.defineCommand)({
|
|
154
|
+
description: "Start a whisper.cpp transcription server",
|
|
155
|
+
options: (0, import_zli.defineOptions)(
|
|
156
|
+
import_zod.z.object({
|
|
157
|
+
model: whisperModelSchema.default("tiny.en").describe("Whisper model"),
|
|
158
|
+
port: import_zod.z.coerce.number().default(8080).describe("Port to listen on"),
|
|
159
|
+
host: import_zod.z.string().default("0.0.0.0").describe("Host to bind to"),
|
|
160
|
+
threads: import_zod.z.coerce.number().default(4).describe("Number of threads"),
|
|
161
|
+
processors: import_zod.z.coerce.number().default(4).describe("Number of processors"),
|
|
162
|
+
noConvert: import_zod.z.boolean().default(false).describe("Disable automatic audio conversion"),
|
|
163
|
+
noAutoInstall: import_zod.z.boolean().default(false).describe("Don't auto-install missing binary/model"),
|
|
164
|
+
variant: buildVariantSchema.optional().describe("Use specific binary variant"),
|
|
165
|
+
force: import_zod.z.boolean().default(false).describe("Force running even if platform doesn't match"),
|
|
166
|
+
vadModel: import_zod.z.string().optional().describe("Path to VAD model for voice activity detection"),
|
|
167
|
+
vadThreshold: import_zod.z.coerce.number().optional().describe("VAD threshold probability (0.0-1.0)")
|
|
168
|
+
}),
|
|
169
|
+
{ m: "model", p: "port", t: "threads", f: "force" }
|
|
170
|
+
),
|
|
171
|
+
action: async (options) => {
|
|
172
|
+
try {
|
|
173
|
+
await (0, import_whisper_server.spawnWhisperServer)({
|
|
174
|
+
model: options.model,
|
|
175
|
+
port: options.port,
|
|
176
|
+
host: options.host,
|
|
177
|
+
threads: options.threads,
|
|
178
|
+
processors: options.processors,
|
|
179
|
+
convert: !options.noConvert,
|
|
180
|
+
autoInstall: !options.noAutoInstall,
|
|
181
|
+
variant: options.variant,
|
|
182
|
+
force: options.force,
|
|
183
|
+
vadModelPath: options.vadModel,
|
|
184
|
+
vadThreshold: options.vadThreshold
|
|
185
|
+
});
|
|
186
|
+
} catch (error) {
|
|
187
|
+
if (error instanceof import_whisper_server.IncompatibleBinaryError) {
|
|
188
|
+
console.error(`Error: ${error.message}`);
|
|
189
|
+
console.error("\nCompatible variants for this platform:");
|
|
190
|
+
for (const v of (0, import_config.getCompatibleVariants)()) {
|
|
191
|
+
console.log(` ${v}`);
|
|
192
|
+
}
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
const vadCommand = (0, import_zli.defineCommand)({
|
|
200
|
+
description: "Run voice activity detection on an audio file",
|
|
201
|
+
args: import_zod.z.tuple([import_zod.z.string().describe("Input audio file path")], {
|
|
202
|
+
errorMap: (issue) => {
|
|
203
|
+
if (issue.code === "too_small") {
|
|
204
|
+
return {
|
|
205
|
+
message: "Input audio file path is required"
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
message: "Input audio file path is required"
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}),
|
|
213
|
+
options: (0, import_zli.defineOptions)(
|
|
214
|
+
import_zod.z.object({
|
|
215
|
+
output: import_zod.z.string().optional().describe("Output file path for VAD segments (JSON)"),
|
|
216
|
+
threshold: import_zod.z.coerce.number().default(0.5).describe("Speech detection threshold (0.0-1.0)"),
|
|
217
|
+
minSpeechDuration: import_zod.z.coerce.number().default(250).describe("Minimum speech duration in ms"),
|
|
218
|
+
minSilenceDuration: import_zod.z.coerce.number().default(100).describe("Minimum silence duration in ms"),
|
|
219
|
+
speechPad: import_zod.z.coerce.number().default(30).describe("Speech padding in ms")
|
|
220
|
+
}),
|
|
221
|
+
{ o: "output" }
|
|
222
|
+
),
|
|
223
|
+
action: async (options, args) => {
|
|
224
|
+
const [inputPath] = args;
|
|
225
|
+
const { detectVoiceActivity } = await import("../vad/Silero.cjs");
|
|
226
|
+
console.log(`Running VAD on ${inputPath}...`);
|
|
227
|
+
console.log(` Threshold: ${options.threshold}`);
|
|
228
|
+
console.log(` Min speech duration: ${options.minSpeechDuration}ms`);
|
|
229
|
+
console.log(` Min silence duration: ${options.minSilenceDuration}ms`);
|
|
230
|
+
console.log(` Speech padding: ${options.speechPad}ms`);
|
|
231
|
+
await (0, import_install.installVadModel)({ force: true, printOutput: true });
|
|
232
|
+
const segments = await detectVoiceActivity(inputPath, {
|
|
233
|
+
threshold: options.threshold,
|
|
234
|
+
minSpeechDurationMs: options.minSpeechDuration,
|
|
235
|
+
minSilenceDurationMs: options.minSilenceDuration,
|
|
236
|
+
speechPadMs: options.speechPad,
|
|
237
|
+
printOutput: true
|
|
238
|
+
});
|
|
239
|
+
if (options.output !== void 0) {
|
|
240
|
+
const { writeFile } = await import("node:fs/promises");
|
|
241
|
+
await writeFile(options.output, JSON.stringify(segments, null, 2));
|
|
242
|
+
console.log(`
|
|
243
|
+
VAD segments written to ${options.output}`);
|
|
244
|
+
} else {
|
|
245
|
+
console.log("\nVAD segments:");
|
|
246
|
+
console.log(JSON.stringify(segments, null, 2));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
const config = (0, import_zli.defineConfig)({
|
|
251
|
+
meta: {
|
|
252
|
+
name: "storywhisper",
|
|
253
|
+
version: import_config.WHISPER_CPP_VERSION,
|
|
254
|
+
description: `Whisper.cpp management CLI (v${import_config.WHISPER_CPP_VERSION})`
|
|
255
|
+
},
|
|
256
|
+
commands: {
|
|
257
|
+
install: installCommand,
|
|
258
|
+
status: statusCommand,
|
|
259
|
+
server: serverCommand,
|
|
260
|
+
vad: vadCommand
|
|
261
|
+
},
|
|
262
|
+
defaultCommand: statusCommand
|
|
263
|
+
});
|
|
264
|
+
async function main() {
|
|
265
|
+
try {
|
|
266
|
+
const result = (0, import_zli.processConfig)(config, process.argv.slice(2));
|
|
267
|
+
await result.command.action(result.options, result.args);
|
|
268
|
+
} catch (err) {
|
|
269
|
+
if (err instanceof Error) {
|
|
270
|
+
console.error("Error:", err.message);
|
|
271
|
+
} else {
|
|
272
|
+
console.error("Error:", err);
|
|
273
|
+
}
|
|
274
|
+
process.exit(1);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
void main();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli/bin.js
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
defineCommand,
|
|
4
|
+
defineConfig,
|
|
5
|
+
defineOptions,
|
|
6
|
+
processConfig
|
|
7
|
+
} from "@robingenz/zli";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import {
|
|
10
|
+
BUILD_VARIANTS,
|
|
11
|
+
WHISPER_CPP_VERSION,
|
|
12
|
+
WHISPER_MODELS,
|
|
13
|
+
getCompatibleVariants,
|
|
14
|
+
getInstalledVariant,
|
|
15
|
+
isValidModel,
|
|
16
|
+
isValidVariant
|
|
17
|
+
} from "./config.js";
|
|
18
|
+
import {
|
|
19
|
+
PlatformMismatchError,
|
|
20
|
+
installBinary,
|
|
21
|
+
installModel,
|
|
22
|
+
installVadModel
|
|
23
|
+
} from "./install.js";
|
|
24
|
+
import {
|
|
25
|
+
IncompatibleBinaryError,
|
|
26
|
+
spawnWhisperServer
|
|
27
|
+
} from "./whisper-server.js";
|
|
28
|
+
const whisperModelSchema = z.enum(WHISPER_MODELS);
|
|
29
|
+
const buildVariantSchema = z.enum(BUILD_VARIANTS);
|
|
30
|
+
function isInstallTarget(value) {
|
|
31
|
+
return ["binary", "model", "vad", "all"].includes(value);
|
|
32
|
+
}
|
|
33
|
+
const installCommand = defineCommand({
|
|
34
|
+
description: `Install whisper.cpp binary and models.
|
|
35
|
+
|
|
36
|
+
Usage:
|
|
37
|
+
storywhisper install binary [variant] - Install binary (auto-detects platform if variant not specified)
|
|
38
|
+
storywhisper install model <model> - Install a whisper model
|
|
39
|
+
storywhisper install vad - Install Silero VAD model
|
|
40
|
+
storywhisper install all - Install binary, all models, and VAD`,
|
|
41
|
+
args: z.union([
|
|
42
|
+
z.tuple([
|
|
43
|
+
z.enum(["binary", "model", "vad", "all"]).describe("What to install: binary, model, vad, or all")
|
|
44
|
+
]),
|
|
45
|
+
z.tuple([
|
|
46
|
+
z.enum(["binary", "model", "vad", "all"]).describe("What to install: binary, model, vad, or all"),
|
|
47
|
+
z.string().optional().describe("Variant (for binary) or model name (for model)")
|
|
48
|
+
])
|
|
49
|
+
]),
|
|
50
|
+
options: defineOptions(
|
|
51
|
+
z.object({
|
|
52
|
+
force: z.boolean().default(false).describe("Force installation even if platform doesn't match"),
|
|
53
|
+
list: z.boolean().default(false).describe("List available variants or models")
|
|
54
|
+
}),
|
|
55
|
+
{ f: "force", l: "list" }
|
|
56
|
+
),
|
|
57
|
+
action: async (options, args) => {
|
|
58
|
+
const [target, argument] = args;
|
|
59
|
+
const force = options.force;
|
|
60
|
+
const list = options.list;
|
|
61
|
+
if (list) {
|
|
62
|
+
if (target === "binary") {
|
|
63
|
+
console.log("Available binary variants:");
|
|
64
|
+
const compatible = getCompatibleVariants();
|
|
65
|
+
for (const variant of BUILD_VARIANTS) {
|
|
66
|
+
const isCompatible = compatible.includes(variant);
|
|
67
|
+
const marker = isCompatible ? "(compatible)" : "";
|
|
68
|
+
console.log(` ${variant} ${marker}`);
|
|
69
|
+
}
|
|
70
|
+
console.log("\nCompatible variants for this platform:");
|
|
71
|
+
for (const variant of compatible) {
|
|
72
|
+
console.log(` ${variant}`);
|
|
73
|
+
}
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (target === "model") {
|
|
77
|
+
console.log("Available whisper models:");
|
|
78
|
+
for (const model of WHISPER_MODELS) {
|
|
79
|
+
console.log(` ${model}`);
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
console.error("Use --list with 'binary' or 'model'");
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
if (!isInstallTarget(target)) {
|
|
87
|
+
console.error(`Unknown install target: ${target}`);
|
|
88
|
+
console.error("Valid targets: binary, model, vad, all");
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
if (target === "binary" || target === "all") {
|
|
93
|
+
const variant = argument && isValidVariant(argument) ? argument : void 0;
|
|
94
|
+
await installBinary({ variant, force, printOutput: true });
|
|
95
|
+
}
|
|
96
|
+
if (target === "model") {
|
|
97
|
+
if (!argument) {
|
|
98
|
+
console.error(
|
|
99
|
+
"Model name required. Usage: storywhisper install model <model>"
|
|
100
|
+
);
|
|
101
|
+
console.error("\nAvailable models:");
|
|
102
|
+
for (const m of WHISPER_MODELS) {
|
|
103
|
+
console.log(` ${m}`);
|
|
104
|
+
}
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
if (!isValidModel(argument)) {
|
|
108
|
+
console.error(`Unknown model: ${argument}`);
|
|
109
|
+
console.error("\nAvailable models:");
|
|
110
|
+
for (const m of WHISPER_MODELS) {
|
|
111
|
+
console.log(` ${m}`);
|
|
112
|
+
}
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
await installModel({ model: argument, force, printOutput: true });
|
|
116
|
+
}
|
|
117
|
+
if (target === "all") {
|
|
118
|
+
console.log("\nInstalling all whisper models...");
|
|
119
|
+
for (const m of WHISPER_MODELS) {
|
|
120
|
+
await installModel({ model: m, force, printOutput: true });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (target === "vad" || target === "all") {
|
|
124
|
+
await installVadModel({ force, printOutput: true });
|
|
125
|
+
}
|
|
126
|
+
console.log("\nInstallation complete!");
|
|
127
|
+
} catch (error) {
|
|
128
|
+
if (error instanceof PlatformMismatchError) {
|
|
129
|
+
console.error(`Error: ${error.message}`);
|
|
130
|
+
console.error("\nCompatible variants for this platform:");
|
|
131
|
+
for (const v of error.compatibleVariants) {
|
|
132
|
+
console.log(` ${v}`);
|
|
133
|
+
}
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
const statusCommand = defineCommand({
|
|
141
|
+
description: "Show installation status",
|
|
142
|
+
action: () => {
|
|
143
|
+
const installed = getInstalledVariant();
|
|
144
|
+
if (installed) {
|
|
145
|
+
console.log(`Installed variant: ${installed}`);
|
|
146
|
+
} else {
|
|
147
|
+
console.log("No binary installed");
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
const serverCommand = defineCommand({
|
|
152
|
+
description: "Start a whisper.cpp transcription server",
|
|
153
|
+
options: defineOptions(
|
|
154
|
+
z.object({
|
|
155
|
+
model: whisperModelSchema.default("tiny.en").describe("Whisper model"),
|
|
156
|
+
port: z.coerce.number().default(8080).describe("Port to listen on"),
|
|
157
|
+
host: z.string().default("0.0.0.0").describe("Host to bind to"),
|
|
158
|
+
threads: z.coerce.number().default(4).describe("Number of threads"),
|
|
159
|
+
processors: z.coerce.number().default(4).describe("Number of processors"),
|
|
160
|
+
noConvert: z.boolean().default(false).describe("Disable automatic audio conversion"),
|
|
161
|
+
noAutoInstall: z.boolean().default(false).describe("Don't auto-install missing binary/model"),
|
|
162
|
+
variant: buildVariantSchema.optional().describe("Use specific binary variant"),
|
|
163
|
+
force: z.boolean().default(false).describe("Force running even if platform doesn't match"),
|
|
164
|
+
vadModel: z.string().optional().describe("Path to VAD model for voice activity detection"),
|
|
165
|
+
vadThreshold: z.coerce.number().optional().describe("VAD threshold probability (0.0-1.0)")
|
|
166
|
+
}),
|
|
167
|
+
{ m: "model", p: "port", t: "threads", f: "force" }
|
|
168
|
+
),
|
|
169
|
+
action: async (options) => {
|
|
170
|
+
try {
|
|
171
|
+
await spawnWhisperServer({
|
|
172
|
+
model: options.model,
|
|
173
|
+
port: options.port,
|
|
174
|
+
host: options.host,
|
|
175
|
+
threads: options.threads,
|
|
176
|
+
processors: options.processors,
|
|
177
|
+
convert: !options.noConvert,
|
|
178
|
+
autoInstall: !options.noAutoInstall,
|
|
179
|
+
variant: options.variant,
|
|
180
|
+
force: options.force,
|
|
181
|
+
vadModelPath: options.vadModel,
|
|
182
|
+
vadThreshold: options.vadThreshold
|
|
183
|
+
});
|
|
184
|
+
} catch (error) {
|
|
185
|
+
if (error instanceof IncompatibleBinaryError) {
|
|
186
|
+
console.error(`Error: ${error.message}`);
|
|
187
|
+
console.error("\nCompatible variants for this platform:");
|
|
188
|
+
for (const v of getCompatibleVariants()) {
|
|
189
|
+
console.log(` ${v}`);
|
|
190
|
+
}
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
throw error;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
const vadCommand = defineCommand({
|
|
198
|
+
description: "Run voice activity detection on an audio file",
|
|
199
|
+
args: z.tuple([z.string().describe("Input audio file path")], {
|
|
200
|
+
errorMap: (issue) => {
|
|
201
|
+
if (issue.code === "too_small") {
|
|
202
|
+
return {
|
|
203
|
+
message: "Input audio file path is required"
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
message: "Input audio file path is required"
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}),
|
|
211
|
+
options: defineOptions(
|
|
212
|
+
z.object({
|
|
213
|
+
output: z.string().optional().describe("Output file path for VAD segments (JSON)"),
|
|
214
|
+
threshold: z.coerce.number().default(0.5).describe("Speech detection threshold (0.0-1.0)"),
|
|
215
|
+
minSpeechDuration: z.coerce.number().default(250).describe("Minimum speech duration in ms"),
|
|
216
|
+
minSilenceDuration: z.coerce.number().default(100).describe("Minimum silence duration in ms"),
|
|
217
|
+
speechPad: z.coerce.number().default(30).describe("Speech padding in ms")
|
|
218
|
+
}),
|
|
219
|
+
{ o: "output" }
|
|
220
|
+
),
|
|
221
|
+
action: async (options, args) => {
|
|
222
|
+
const [inputPath] = args;
|
|
223
|
+
const { detectVoiceActivity } = await import("../vad/Silero.js");
|
|
224
|
+
console.log(`Running VAD on ${inputPath}...`);
|
|
225
|
+
console.log(` Threshold: ${options.threshold}`);
|
|
226
|
+
console.log(` Min speech duration: ${options.minSpeechDuration}ms`);
|
|
227
|
+
console.log(` Min silence duration: ${options.minSilenceDuration}ms`);
|
|
228
|
+
console.log(` Speech padding: ${options.speechPad}ms`);
|
|
229
|
+
await installVadModel({ force: true, printOutput: true });
|
|
230
|
+
const segments = await detectVoiceActivity(inputPath, {
|
|
231
|
+
threshold: options.threshold,
|
|
232
|
+
minSpeechDurationMs: options.minSpeechDuration,
|
|
233
|
+
minSilenceDurationMs: options.minSilenceDuration,
|
|
234
|
+
speechPadMs: options.speechPad,
|
|
235
|
+
printOutput: true
|
|
236
|
+
});
|
|
237
|
+
if (options.output !== void 0) {
|
|
238
|
+
const { writeFile } = await import("node:fs/promises");
|
|
239
|
+
await writeFile(options.output, JSON.stringify(segments, null, 2));
|
|
240
|
+
console.log(`
|
|
241
|
+
VAD segments written to ${options.output}`);
|
|
242
|
+
} else {
|
|
243
|
+
console.log("\nVAD segments:");
|
|
244
|
+
console.log(JSON.stringify(segments, null, 2));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
const config = defineConfig({
|
|
249
|
+
meta: {
|
|
250
|
+
name: "storywhisper",
|
|
251
|
+
version: WHISPER_CPP_VERSION,
|
|
252
|
+
description: `Whisper.cpp management CLI (v${WHISPER_CPP_VERSION})`
|
|
253
|
+
},
|
|
254
|
+
commands: {
|
|
255
|
+
install: installCommand,
|
|
256
|
+
status: statusCommand,
|
|
257
|
+
server: serverCommand,
|
|
258
|
+
vad: vadCommand
|
|
259
|
+
},
|
|
260
|
+
defaultCommand: statusCommand
|
|
261
|
+
});
|
|
262
|
+
async function main() {
|
|
263
|
+
try {
|
|
264
|
+
const result = processConfig(config, process.argv.slice(2));
|
|
265
|
+
await result.command.action(result.options, result.args);
|
|
266
|
+
} catch (err) {
|
|
267
|
+
if (err instanceof Error) {
|
|
268
|
+
console.error("Error:", err.message);
|
|
269
|
+
} else {
|
|
270
|
+
console.error("Error:", err);
|
|
271
|
+
}
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
void main();
|