@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.
Files changed (135) hide show
  1. package/LICENSE.md +611 -0
  2. package/README.md +18 -0
  3. package/dist/api/APIOptions.cjs +16 -0
  4. package/dist/api/APIOptions.d.cts +18 -0
  5. package/dist/api/APIOptions.d.ts +18 -0
  6. package/dist/api/APIOptions.js +0 -0
  7. package/dist/api/Recognition.cjs +263 -0
  8. package/dist/api/Recognition.d.cts +77 -0
  9. package/dist/api/Recognition.d.ts +77 -0
  10. package/dist/api/Recognition.js +233 -0
  11. package/dist/api/VoiceActivityDetection.cjs +77 -0
  12. package/dist/api/VoiceActivityDetection.d.cts +24 -0
  13. package/dist/api/VoiceActivityDetection.d.ts +24 -0
  14. package/dist/api/VoiceActivityDetection.js +43 -0
  15. package/dist/audio/AudioConverter.cjs +331 -0
  16. package/dist/audio/AudioConverter.d.cts +53 -0
  17. package/dist/audio/AudioConverter.d.ts +53 -0
  18. package/dist/audio/AudioConverter.js +310 -0
  19. package/dist/audio/AudioFormat.cjs +151 -0
  20. package/dist/audio/AudioFormat.d.cts +25 -0
  21. package/dist/audio/AudioFormat.d.ts +25 -0
  22. package/dist/audio/AudioFormat.js +123 -0
  23. package/dist/audio/AudioSource.cjs +119 -0
  24. package/dist/audio/AudioSource.d.cts +33 -0
  25. package/dist/audio/AudioSource.d.ts +33 -0
  26. package/dist/audio/AudioSource.js +88 -0
  27. package/dist/audio/index.cjs +74 -0
  28. package/dist/audio/index.d.cts +6 -0
  29. package/dist/audio/index.d.ts +6 -0
  30. package/dist/audio/index.js +54 -0
  31. package/dist/cli/bin.cjs +277 -0
  32. package/dist/cli/bin.d.cts +1 -0
  33. package/dist/cli/bin.d.ts +1 -0
  34. package/dist/cli/bin.js +275 -0
  35. package/dist/cli/config.cjs +347 -0
  36. package/dist/cli/config.d.cts +33 -0
  37. package/dist/cli/config.d.ts +33 -0
  38. package/dist/cli/config.js +285 -0
  39. package/dist/cli/install.cjs +334 -0
  40. package/dist/cli/install.d.cts +62 -0
  41. package/dist/cli/install.d.ts +62 -0
  42. package/dist/cli/install.js +316 -0
  43. package/dist/cli/whisper-server.cjs +172 -0
  44. package/dist/cli/whisper-server.d.cts +24 -0
  45. package/dist/cli/whisper-server.d.ts +24 -0
  46. package/dist/cli/whisper-server.js +152 -0
  47. package/dist/config.cjs +60 -0
  48. package/dist/config.d.cts +12 -0
  49. package/dist/config.d.ts +12 -0
  50. package/dist/config.js +32 -0
  51. package/dist/convert.cjs +88 -0
  52. package/dist/convert.d.cts +12 -0
  53. package/dist/convert.d.ts +12 -0
  54. package/dist/convert.js +63 -0
  55. package/dist/encodings/Ascii.cjs +75 -0
  56. package/dist/encodings/Ascii.d.cts +13 -0
  57. package/dist/encodings/Ascii.d.ts +13 -0
  58. package/dist/encodings/Ascii.js +48 -0
  59. package/dist/encodings/Base64.cjs +155 -0
  60. package/dist/encodings/Base64.d.cts +5 -0
  61. package/dist/encodings/Base64.d.ts +5 -0
  62. package/dist/encodings/Base64.js +129 -0
  63. package/dist/encodings/TextEncodingsCommon.cjs +16 -0
  64. package/dist/encodings/TextEncodingsCommon.d.cts +6 -0
  65. package/dist/encodings/TextEncodingsCommon.d.ts +6 -0
  66. package/dist/encodings/TextEncodingsCommon.js +0 -0
  67. package/dist/index.cjs +153 -0
  68. package/dist/index.d.cts +15 -0
  69. package/dist/index.d.ts +15 -0
  70. package/dist/index.js +140 -0
  71. package/dist/recognition/AmazonTranscribeSTT.cjs +188 -0
  72. package/dist/recognition/AmazonTranscribeSTT.d.cts +21 -0
  73. package/dist/recognition/AmazonTranscribeSTT.d.ts +21 -0
  74. package/dist/recognition/AmazonTranscribeSTT.js +160 -0
  75. package/dist/recognition/AzureCognitiveServicesSTT.cjs +124 -0
  76. package/dist/recognition/AzureCognitiveServicesSTT.d.cts +21 -0
  77. package/dist/recognition/AzureCognitiveServicesSTT.d.ts +21 -0
  78. package/dist/recognition/AzureCognitiveServicesSTT.js +95 -0
  79. package/dist/recognition/DeepgramSTT.cjs +172 -0
  80. package/dist/recognition/DeepgramSTT.d.cts +23 -0
  81. package/dist/recognition/DeepgramSTT.d.ts +23 -0
  82. package/dist/recognition/DeepgramSTT.js +153 -0
  83. package/dist/recognition/GoogleCloudSTT.cjs +125 -0
  84. package/dist/recognition/GoogleCloudSTT.d.cts +35 -0
  85. package/dist/recognition/GoogleCloudSTT.d.ts +35 -0
  86. package/dist/recognition/GoogleCloudSTT.js +107 -0
  87. package/dist/recognition/OpenAICloudSTT.cjs +180 -0
  88. package/dist/recognition/OpenAICloudSTT.d.cts +29 -0
  89. package/dist/recognition/OpenAICloudSTT.d.ts +29 -0
  90. package/dist/recognition/OpenAICloudSTT.js +150 -0
  91. package/dist/recognition/WhisperCppSTT.cjs +296 -0
  92. package/dist/recognition/WhisperCppSTT.d.cts +40 -0
  93. package/dist/recognition/WhisperCppSTT.d.ts +40 -0
  94. package/dist/recognition/WhisperCppSTT.js +275 -0
  95. package/dist/recognition/WhisperServerSTT.cjs +119 -0
  96. package/dist/recognition/WhisperServerSTT.d.cts +24 -0
  97. package/dist/recognition/WhisperServerSTT.d.ts +24 -0
  98. package/dist/recognition/WhisperServerSTT.js +105 -0
  99. package/dist/utilities/FileSystem.cjs +54 -0
  100. package/dist/utilities/FileSystem.d.cts +3 -0
  101. package/dist/utilities/FileSystem.d.ts +3 -0
  102. package/dist/utilities/FileSystem.js +20 -0
  103. package/dist/utilities/Locale.cjs +46 -0
  104. package/dist/utilities/Locale.d.cts +9 -0
  105. package/dist/utilities/Locale.d.ts +9 -0
  106. package/dist/utilities/Locale.js +20 -0
  107. package/dist/utilities/ObjectUtilities.cjs +41 -0
  108. package/dist/utilities/ObjectUtilities.d.cts +3 -0
  109. package/dist/utilities/ObjectUtilities.d.ts +3 -0
  110. package/dist/utilities/ObjectUtilities.js +7 -0
  111. package/dist/utilities/Timeline.cjs +120 -0
  112. package/dist/utilities/Timeline.d.cts +23 -0
  113. package/dist/utilities/Timeline.d.ts +23 -0
  114. package/dist/utilities/Timeline.js +94 -0
  115. package/dist/utilities/Timing.cjs +287 -0
  116. package/dist/utilities/Timing.d.cts +64 -0
  117. package/dist/utilities/Timing.d.ts +64 -0
  118. package/dist/utilities/Timing.js +256 -0
  119. package/dist/utilities/WhisperTimeline.cjs +344 -0
  120. package/dist/utilities/WhisperTimeline.d.cts +86 -0
  121. package/dist/utilities/WhisperTimeline.d.ts +86 -0
  122. package/dist/utilities/WhisperTimeline.js +313 -0
  123. package/dist/vad/ActiveGate.cjs +357 -0
  124. package/dist/vad/ActiveGate.d.cts +53 -0
  125. package/dist/vad/ActiveGate.d.ts +53 -0
  126. package/dist/vad/ActiveGate.js +329 -0
  127. package/dist/vad/ActiveGateOg.cjs +1366 -0
  128. package/dist/vad/ActiveGateOg.d.cts +33 -0
  129. package/dist/vad/ActiveGateOg.d.ts +33 -0
  130. package/dist/vad/ActiveGateOg.js +1341 -0
  131. package/dist/vad/Silero.cjs +174 -0
  132. package/dist/vad/Silero.d.cts +25 -0
  133. package/dist/vad/Silero.d.ts +25 -0
  134. package/dist/vad/Silero.js +153 -0
  135. package/package.json +125 -0
@@ -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
@@ -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();