whisper-api 0.1.0 → 0.1.2
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/README.md +26 -1
- package/dist/whisper-api.js +53 -21
- package/dist/whisper-api.js.map +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -50,6 +50,31 @@ curl http://YOUR_SERVER:8080/v1/audio/transcriptions \
|
|
|
50
50
|
-F model=whisper-1
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
### Personal use — one fixed token (no setup)
|
|
54
|
+
|
|
55
|
+
For a single-user endpoint you don't even need `init` or the keystore. Just pick a
|
|
56
|
+
secret and pass it inline — the server accepts it as a bearer key:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# choose your own token; clients send it as "Authorization: Bearer <token>"
|
|
60
|
+
npx whisper-api start --api-key "my-secret-token" --model base.en
|
|
61
|
+
|
|
62
|
+
# or via environment (e.g. systemd / Docker):
|
|
63
|
+
WHISPER_API_KEY="my-secret-token" npx whisper-api start
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Then from anywhere:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
curl http://YOUR_SERVER:8080/v1/audio/transcriptions \
|
|
70
|
+
-H "Authorization: Bearer my-secret-token" \
|
|
71
|
+
-F file=@audio.m4a -F model=whisper-1
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The fixed token is accepted **in addition** to any keys created with
|
|
75
|
+
`whisper-api key generate`, so you can start simple and add managed keys later.
|
|
76
|
+
Auth is always required — there is no unauthenticated mode.
|
|
77
|
+
|
|
53
78
|
## Using it from a third-party app
|
|
54
79
|
|
|
55
80
|
Anything that supports the OpenAI API works — just change the base URL and key.
|
|
@@ -85,7 +110,7 @@ console.log(out.text);
|
|
|
85
110
|
| Command | Description |
|
|
86
111
|
| --- | --- |
|
|
87
112
|
| `whisper-api init` | Interactive setup: engine, models, first API key. |
|
|
88
|
-
| `whisper-api start [-p 8080] [--host 0.0.0.0] [-m base.en] [-e auto]` | Start the API server. |
|
|
113
|
+
| `whisper-api start [-p 8080] [--host 0.0.0.0] [-m base.en] [-e auto] [-k <token>]` | Start the API server. `-k/--api-key` sets a fixed personal key. |
|
|
89
114
|
| `whisper-api models list` | List available and installed models. |
|
|
90
115
|
| `whisper-api models pull <name>` | Download a model (e.g. `large-v3`). |
|
|
91
116
|
| `whisper-api models rm <name>` | Remove a downloaded GGML model. |
|
package/dist/whisper-api.js
CHANGED
|
@@ -591,6 +591,9 @@ import multipart from "@fastify/multipart";
|
|
|
591
591
|
import rateLimit from "@fastify/rate-limit";
|
|
592
592
|
import fastifyStatic from "@fastify/static";
|
|
593
593
|
|
|
594
|
+
// src/server/auth.ts
|
|
595
|
+
import crypto4 from "crypto";
|
|
596
|
+
|
|
594
597
|
// src/server/formats.ts
|
|
595
598
|
var RESPONSE_FORMATS = ["json", "verbose_json", "text", "srt", "vtt"];
|
|
596
599
|
function isResponseFormat(v) {
|
|
@@ -670,25 +673,48 @@ function extractBearer(header) {
|
|
|
670
673
|
const m = /^Bearer\s+(.+)$/i.exec(header.trim());
|
|
671
674
|
return m ? m[1].trim() : null;
|
|
672
675
|
}
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
return;
|
|
676
|
+
function matchesStatic(token, staticKeys) {
|
|
677
|
+
const t = crypto4.createHash("sha256").update(token).digest();
|
|
678
|
+
for (const k of staticKeys) {
|
|
679
|
+
if (!k) continue;
|
|
680
|
+
const h = crypto4.createHash("sha256").update(k).digest();
|
|
681
|
+
if (h.length === t.length && crypto4.timingSafeEqual(h, t)) return true;
|
|
679
682
|
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
function makeAuthHook(ctx) {
|
|
686
|
+
return async function authHook(req, reply) {
|
|
687
|
+
if (isPublic(req.url)) return;
|
|
688
|
+
const token = extractBearer(req.headers.authorization);
|
|
689
|
+
if (!token) {
|
|
690
|
+
await reply.code(401).send(errorBody("Missing bearer token. Pass `Authorization: Bearer <key>`.", "invalid_request_error", "missing_api_key"));
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
if (ctx.staticApiKeys.length && matchesStatic(token, ctx.staticApiKeys)) {
|
|
694
|
+
req.apiKey = {
|
|
695
|
+
id: "static",
|
|
696
|
+
name: "static",
|
|
697
|
+
prefix: token.slice(0, 8),
|
|
698
|
+
hash: "",
|
|
699
|
+
createdAt: "",
|
|
700
|
+
lastUsedAt: null,
|
|
701
|
+
revoked: false
|
|
702
|
+
};
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
const record = await verifyKey(token);
|
|
706
|
+
if (!record) {
|
|
707
|
+
await reply.code(401).send(errorBody("Invalid or revoked API key.", "invalid_request_error", "invalid_api_key"));
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
req.apiKey = record;
|
|
711
|
+
};
|
|
686
712
|
}
|
|
687
713
|
|
|
688
714
|
// src/server/routes/transcriptions.ts
|
|
689
715
|
import fs7 from "fs";
|
|
690
716
|
import path6 from "path";
|
|
691
|
-
import
|
|
717
|
+
import crypto5 from "crypto";
|
|
692
718
|
import { pipeline } from "stream/promises";
|
|
693
719
|
async function parseMultipart(req) {
|
|
694
720
|
ensureDirs();
|
|
@@ -697,7 +723,7 @@ async function parseMultipart(req) {
|
|
|
697
723
|
if (part.type === "file") {
|
|
698
724
|
if (part.fieldname === "file") {
|
|
699
725
|
const ext = path6.extname(part.filename || "") || ".bin";
|
|
700
|
-
const dest = path6.join(paths.tmp(), `up-${
|
|
726
|
+
const dest = path6.join(paths.tmp(), `up-${crypto5.randomBytes(8).toString("hex")}${ext}`);
|
|
701
727
|
await pipeline(part.file, fs7.createWriteStream(dest));
|
|
702
728
|
result.filePath = dest;
|
|
703
729
|
result.filename = part.filename;
|
|
@@ -806,7 +832,7 @@ async function buildServer(ctx) {
|
|
|
806
832
|
keyGenerator: (req) => extractBearer(req.headers.authorization) ?? req.ip,
|
|
807
833
|
errorResponseBuilder: () => errorBody("Rate limit exceeded. Slow down or request a higher limit.", "rate_limit_error", "rate_limit_exceeded")
|
|
808
834
|
});
|
|
809
|
-
app.addHook("onRequest",
|
|
835
|
+
app.addHook("onRequest", makeAuthHook({ staticApiKeys: ctx.staticApiKeys }));
|
|
810
836
|
app.setErrorHandler((err, req, reply) => {
|
|
811
837
|
const status = err.statusCode && err.statusCode >= 400 ? err.statusCode : 500;
|
|
812
838
|
req.log.error({ err }, "request error");
|
|
@@ -831,7 +857,7 @@ async function startServer(ctx) {
|
|
|
831
857
|
}
|
|
832
858
|
|
|
833
859
|
// src/version.ts
|
|
834
|
-
var VERSION = "0.1.
|
|
860
|
+
var VERSION = "0.1.2";
|
|
835
861
|
|
|
836
862
|
// src/cli/ui.ts
|
|
837
863
|
import cliProgress from "cli-progress";
|
|
@@ -969,6 +995,7 @@ async function runStart(opts) {
|
|
|
969
995
|
if (opts.port) config.port = Number(opts.port);
|
|
970
996
|
if (opts.host) config.host = opts.host;
|
|
971
997
|
if (opts.engine) config.engine = opts.engine;
|
|
998
|
+
const staticApiKeys = [opts.apiKey, process.env.WHISPER_API_KEY].map((k) => (k ?? "").trim()).filter((k) => k.length > 0);
|
|
972
999
|
const model = resolveModel(opts.model || config.defaultModel, config.defaultModel);
|
|
973
1000
|
const allowBuild = config.engine === "whispercpp" || process.env.WHISPER_API_AUTOBUILD === "1";
|
|
974
1001
|
console.log(pc.dim(` Selecting engine (${config.engine})\u2026`));
|
|
@@ -999,7 +1026,8 @@ async function runStart(opts) {
|
|
|
999
1026
|
defaultEngine: selection.engine,
|
|
1000
1027
|
engineLabel: selection.engine.describe(),
|
|
1001
1028
|
version: VERSION,
|
|
1002
|
-
getEngine
|
|
1029
|
+
getEngine,
|
|
1030
|
+
staticApiKeys
|
|
1003
1031
|
};
|
|
1004
1032
|
const { url } = await startServer(ctx);
|
|
1005
1033
|
console.log();
|
|
@@ -1008,10 +1036,14 @@ async function runStart(opts) {
|
|
|
1008
1036
|
selection.engine.describe()
|
|
1009
1037
|
)} ${pc.dim("\xB7")} model ${pc.bold(model.name)}`
|
|
1010
1038
|
);
|
|
1011
|
-
if (
|
|
1012
|
-
console.log(` ${pc.
|
|
1039
|
+
if (staticApiKeys.length) {
|
|
1040
|
+
console.log(` ${pc.green("\u2713")} Accepting a fixed API key from ${pc.bold("--api-key / WHISPER_API_KEY")}`);
|
|
1041
|
+
} else if (await countActiveKeys() === 0) {
|
|
1042
|
+
console.log(
|
|
1043
|
+
` ${pc.yellow("!")} No API keys yet \u2014 run ${pc.bold("whisper-api key generate")} or start with ${pc.bold("--api-key <token>")}`
|
|
1044
|
+
);
|
|
1013
1045
|
}
|
|
1014
|
-
printAccessExample(url);
|
|
1046
|
+
printAccessExample(url, staticApiKeys[0]);
|
|
1015
1047
|
}
|
|
1016
1048
|
async function runModelsList() {
|
|
1017
1049
|
const config = await loadConfig();
|
|
@@ -1100,7 +1132,7 @@ function buildProgram() {
|
|
|
1100
1132
|
const program2 = new Command();
|
|
1101
1133
|
program2.name("whisper-api").description("Self-hostable, OpenAI-compatible Whisper speech-to-text API server.").version(VERSION, "-v, --version").showHelpAfterError();
|
|
1102
1134
|
program2.command("init").description("Interactive setup: choose engine, download models, create an API key").action(runInit);
|
|
1103
|
-
program2.command("start").description("Start the API server").option("-p, --port <port>", "port to listen on").option("--host <host>", "host to bind").option("-m, --model <name>", "default model (overrides config)").option("-e, --engine <engine>", "auto | whispercpp | onnx").action(runStart);
|
|
1135
|
+
program2.command("start").description("Start the API server").option("-p, --port <port>", "port to listen on").option("--host <host>", "host to bind").option("-m, --model <name>", "default model (overrides config)").option("-e, --engine <engine>", "auto | whispercpp | onnx").option("-k, --api-key <token>", "fixed API key to accept (personal use); also via WHISPER_API_KEY").action(runStart);
|
|
1104
1136
|
const models = program2.command("models").description("Manage local transcription models");
|
|
1105
1137
|
models.command("list").description("List available and installed models").action(runModelsList);
|
|
1106
1138
|
models.command("pull <name>").description("Download a model (e.g. base.en, large-v3)").action(runModelsPull);
|
package/dist/whisper-api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/index.ts","../src/config/index.ts","../src/models/registry.ts","../src/keys/store.ts","../src/audio.ts","../src/engine/onnx.ts","../src/engine/whispercpp.ts","../src/engine/probe.ts","../src/engine/detect.ts","../src/server/app.ts","../src/server/formats.ts","../src/server/auth.ts","../src/server/routes/transcriptions.ts","../src/server/routes/models.ts","../src/server/routes/health.ts","../src/version.ts","../src/cli/ui.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport dotenv from \"dotenv\";\nimport { Command } from \"commander\";\nimport { intro, outro, select, multiselect, isCancel, cancel, note } from \"@clack/prompts\";\nimport {\n DEFAULT_CONFIG,\n applyEnvOverrides,\n ensureDirs,\n homeDir,\n loadConfig,\n paths,\n saveConfig,\n type EngineChoice,\n type WhisperApiConfig,\n} from \"../config\";\nimport {\n MODELS,\n downloadGgml,\n findModel,\n ggmlPath,\n isGgmlInstalled,\n resolveModel,\n type ModelInfo,\n} from \"../models/registry\";\nimport { countActiveKeys, createKey, listKeys, revokeKey } from \"../keys/store\";\nimport { createEngine } from \"../engine/detect\";\nimport { OnnxEngine } from \"../engine/onnx\";\nimport { buildWhisperCpp, locateWhisperBinary } from \"../engine/probe\";\nimport type { TranscriptionEngine } from \"../engine/types\";\nimport { startServer, type ServerContext } from \"../server/app\";\nimport { VERSION } from \"../version\";\nimport { modelProgress, pc, printAccessExample, printNewKey } from \"./ui\";\n\n// Load env from CWD and from the whisper-api home dir (quiet: no promo banners).\ndotenv.config({ quiet: true });\ndotenv.config({ path: path.join(homeDir(), \".env\"), quiet: true });\n\n/** Download (whisper.cpp GGML) or warm (ONNX weights) a model's assets. */\nasync function provision(engineChoice: EngineChoice, model: ModelInfo, label: string): Promise<void> {\n const ui = modelProgress(label.padEnd(16));\n try {\n if (engineChoice === \"onnx\") {\n await new OnnxEngine(model).ensureModel(ui.onProgress);\n } else {\n await downloadGgml(model, ui.onProgress);\n }\n } finally {\n ui.done();\n }\n}\n\nasync function runInit(): Promise<void> {\n ensureDirs();\n const existing = await loadConfig();\n intro(pc.bold(\" whisper-api setup \"));\n\n const engine = await select({\n message: \"Transcription engine\",\n initialValue: existing.engine,\n options: [\n { value: \"auto\", label: \"auto\", hint: \"whisper.cpp if available, else portable ONNX\" },\n { value: \"whispercpp\", label: \"whisper.cpp\", hint: \"fastest, GPU; needs build tools or a prebuilt binary\" },\n { value: \"onnx\", label: \"onnx\", hint: \"pure-JS, no compiler, runs anywhere\" },\n ],\n });\n if (isCancel(engine)) return cancel(\"Setup cancelled.\");\n\n const chosen = await multiselect({\n message: \"Models to download (space to toggle)\",\n required: true,\n initialValues: [existing.defaultModel],\n options: MODELS.map((m) => ({ value: m.name, label: `${m.name} ${pc.dim(`(${m.sizeMB} MB)`)}`, hint: m.description })),\n });\n if (isCancel(chosen)) return cancel(\"Setup cancelled.\");\n const selected = chosen as string[];\n\n let defaultModel = selected[0]!;\n if (selected.length > 1) {\n const d = await select({\n message: \"Default model (served for the `whisper-1` alias)\",\n initialValue: selected.includes(existing.defaultModel) ? existing.defaultModel : selected[0],\n options: selected.map((n) => ({ value: n, label: n })),\n });\n if (isCancel(d)) return cancel(\"Setup cancelled.\");\n defaultModel = d as string;\n }\n\n const config: WhisperApiConfig = { ...DEFAULT_CONFIG, ...existing, engine: engine as EngineChoice, defaultModel };\n await saveConfig(config);\n\n const { raw, record } = await createKey(\"default\");\n note(`${pc.cyan(raw)}\\n${pc.dim(`id ${record.id}`)}`, \"API key — copy now, shown once\");\n\n console.log();\n console.log(pc.bold(` Downloading ${selected.length} model(s) for ${engine === \"onnx\" ? \"ONNX\" : \"whisper.cpp\"}…`));\n for (const name of selected) {\n await provision(config.engine, findModel(name)!, name);\n }\n\n outro(pc.green(\"Setup complete.\"));\n console.log(` Config: ${paths.config()}`);\n console.log(` Start: ${pc.bold(\"whisper-api start\")}`);\n printAccessExample(`http://localhost:${config.port}`, raw);\n}\n\nasync function runStart(opts: { port?: string; host?: string; model?: string; engine?: string }): Promise<void> {\n ensureDirs();\n const config = applyEnvOverrides(await loadConfig());\n if (opts.port) config.port = Number(opts.port);\n if (opts.host) config.host = opts.host;\n if (opts.engine) config.engine = opts.engine as EngineChoice;\n\n const model = resolveModel(opts.model || config.defaultModel, config.defaultModel);\n const allowBuild = config.engine === \"whispercpp\" || process.env.WHISPER_API_AUTOBUILD === \"1\";\n\n console.log(pc.dim(` Selecting engine (${config.engine})…`));\n const selection = await createEngine({\n engine: config.engine,\n model,\n allowBuild,\n onLog: (l) => console.log(pc.dim(\" \" + l)),\n });\n console.log(pc.dim(` ${selection.reason}`));\n\n const ui = modelProgress(`model ${model.name}`.padEnd(16));\n try {\n await selection.engine.ensureModel(ui.onProgress);\n } finally {\n ui.done();\n }\n\n const cache = new Map<string, TranscriptionEngine>([[model.name, selection.engine]]);\n const getEngine = async (name: string): Promise<TranscriptionEngine> => {\n const cached = cache.get(name);\n if (cached) return cached;\n const info = findModel(name) ?? model;\n const eng = selection.engine.forModel(info);\n cache.set(name, eng);\n return eng;\n };\n\n const ctx: ServerContext = {\n config,\n defaultEngine: selection.engine,\n engineLabel: selection.engine.describe(),\n version: VERSION,\n getEngine,\n };\n const { url } = await startServer(ctx);\n\n console.log();\n console.log(\n ` ${pc.green(\"▶\")} ${pc.bold(\"whisper-api\")} on ${pc.cyan(url)} ${pc.dim(\"·\")} engine ${pc.bold(\n selection.engine.describe(),\n )} ${pc.dim(\"·\")} model ${pc.bold(model.name)}`,\n );\n if ((await countActiveKeys()) === 0) {\n console.log(` ${pc.yellow(\"!\")} No API keys yet — run ${pc.bold(\"whisper-api key generate\")}`);\n }\n printAccessExample(url);\n}\n\nasync function runModelsList(): Promise<void> {\n const config = await loadConfig();\n console.log(pc.bold(\" Models \") + pc.dim(\"(✓ = GGML present locally)\"));\n for (const m of MODELS) {\n const mark = isGgmlInstalled(m) ? pc.green(\"✓\") : pc.dim(\"·\");\n const def = m.name === config.defaultModel ? pc.cyan(\" (default)\") : \"\";\n console.log(` ${mark} ${m.name.padEnd(16)} ${String(m.sizeMB).padStart(5)} MB ${pc.dim(m.description)}${def}`);\n }\n}\n\nasync function runModelsPull(name: string): Promise<void> {\n const model = findModel(name);\n if (!model) {\n console.error(pc.red(`Unknown model '${name}'. Run \\`whisper-api models list\\`.`));\n process.exitCode = 1;\n return;\n }\n const config = await loadConfig();\n await provision(config.engine, model, name);\n console.log(pc.green(` ✓ ${name} ready`));\n}\n\nasync function runModelsRm(name: string): Promise<void> {\n const model = findModel(name);\n if (!model) {\n console.error(pc.red(`Unknown model '${name}'.`));\n process.exitCode = 1;\n return;\n }\n const p = ggmlPath(model);\n if (fs.existsSync(p)) {\n fs.rmSync(p);\n console.log(pc.green(` ✓ removed ${model.ggmlFile}`));\n } else {\n console.log(pc.dim(` nothing to remove for ${name} (ONNX weights live under ${paths.cache()})`));\n }\n}\n\nasync function runKeyGenerate(opts: { name?: string }): Promise<void> {\n ensureDirs();\n const { raw, record } = await createKey(opts.name || \"default\");\n printNewKey(raw, record.name, record.id);\n const config = await loadConfig();\n printAccessExample(`http://localhost:${config.port}`, raw);\n}\n\nasync function runKeyList(): Promise<void> {\n const keys = await listKeys();\n if (!keys.length) {\n console.log(pc.dim(\" No keys yet. Create one: whisper-api key generate\"));\n return;\n }\n for (const k of keys) {\n const state = k.revoked ? pc.red(\"revoked\") : pc.green(\"active\");\n console.log(\n ` ${k.prefix}… ${state} ${pc.dim(k.id)} name=${k.name} created=${k.createdAt.slice(0, 10)} lastUsed=${\n k.lastUsedAt ? k.lastUsedAt.slice(0, 10) : \"never\"\n }`,\n );\n }\n}\n\nasync function runKeyRevoke(idOrPrefix: string): Promise<void> {\n const ok = await revokeKey(idOrPrefix);\n console.log(ok ? pc.green(` ✓ revoked ${idOrPrefix}`) : pc.yellow(` no active key matched ${idOrPrefix}`));\n}\n\nasync function runStatus(): Promise<void> {\n const config = applyEnvOverrides(await loadConfig());\n const installed = MODELS.filter(isGgmlInstalled).map((m) => m.name);\n const bin = locateWhisperBinary();\n console.log(pc.bold(\" whisper-api status\"));\n console.log(` home ${homeDir()}`);\n console.log(` engine ${config.engine}`);\n console.log(` default ${config.defaultModel}`);\n console.log(` listen ${config.host}:${config.port}`);\n console.log(` rate limit ${config.rateLimit.max} / ${config.rateLimit.timeWindow} per key`);\n console.log(` ggml models ${installed.length ? installed.join(\", \") : pc.dim(\"(none downloaded)\")}`);\n console.log(` api keys ${await countActiveKeys()} active`);\n console.log(` whisper.cpp ${bin ? pc.green(bin) : pc.dim(\"not built (run: whisper-api build-engine)\")}`);\n}\n\nasync function runBuildEngine(): Promise<void> {\n console.log(pc.bold(\" Building whisper.cpp from source…\"));\n try {\n const bin = await buildWhisperCpp((l) => console.log(pc.dim(\" \" + l)));\n console.log(pc.green(` ✓ built: ${bin}`));\n } catch (e) {\n console.error(pc.red(` build failed: ${(e as Error).message}`));\n process.exitCode = 1;\n }\n}\n\nfunction buildProgram(): Command {\n const program = new Command();\n program\n .name(\"whisper-api\")\n .description(\"Self-hostable, OpenAI-compatible Whisper speech-to-text API server.\")\n .version(VERSION, \"-v, --version\")\n .showHelpAfterError();\n\n program.command(\"init\").description(\"Interactive setup: choose engine, download models, create an API key\").action(runInit);\n\n program\n .command(\"start\")\n .description(\"Start the API server\")\n .option(\"-p, --port <port>\", \"port to listen on\")\n .option(\"--host <host>\", \"host to bind\")\n .option(\"-m, --model <name>\", \"default model (overrides config)\")\n .option(\"-e, --engine <engine>\", \"auto | whispercpp | onnx\")\n .action(runStart);\n\n const models = program.command(\"models\").description(\"Manage local transcription models\");\n models.command(\"list\").description(\"List available and installed models\").action(runModelsList);\n models.command(\"pull <name>\").description(\"Download a model (e.g. base.en, large-v3)\").action(runModelsPull);\n models.command(\"rm <name>\").description(\"Remove a downloaded GGML model\").action(runModelsRm);\n\n const key = program.command(\"key\").description(\"Manage API access keys\");\n key.command(\"generate\").description(\"Generate a new API key\").option(\"-n, --name <name>\", \"label for the key\").action(runKeyGenerate);\n key.command(\"list\").description(\"List API keys\").action(runKeyList);\n key.command(\"revoke <idOrPrefix>\").description(\"Revoke a key by id or prefix\").action(runKeyRevoke);\n\n program.command(\"status\").description(\"Show configuration and local state\").action(runStatus);\n program.command(\"build-engine\").description(\"Build whisper.cpp from source for native speed\").action(runBuildEngine);\n\n return program;\n}\n\nconst program = buildProgram();\nif (process.argv.slice(2).length === 0) {\n program.outputHelp();\n process.exit(0);\n}\nprogram.parseAsync(process.argv).catch((err: Error) => {\n console.error(pc.red(err.message));\n process.exit(1);\n});\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport fs from \"node:fs\";\nimport fsp from \"node:fs/promises\";\n\nexport type EngineChoice = \"auto\" | \"whispercpp\" | \"onnx\";\n\nexport interface RateLimitConfig {\n /** Max requests per window, per API key. */\n max: number;\n /** Window, e.g. \"1 minute\" (parsed by @fastify/rate-limit). */\n timeWindow: string;\n}\n\nexport interface WhisperApiConfig {\n engine: EngineChoice;\n /** Friendly model name, e.g. \"base.en\". Also the default for the `whisper-1` alias. */\n defaultModel: string;\n host: string;\n port: number;\n /** Max upload size in bytes (OpenAI parity default: 25 MB). */\n maxUploadBytes: number;\n rateLimit: RateLimitConfig;\n}\n\nexport const DEFAULT_CONFIG: WhisperApiConfig = {\n engine: \"auto\",\n defaultModel: \"base.en\",\n host: \"0.0.0.0\",\n port: 8080,\n maxUploadBytes: 25 * 1024 * 1024,\n rateLimit: { max: 120, timeWindow: \"1 minute\" },\n};\n\n/** Root dir for config, keys, models and caches. Overridable for tests/containers. */\nexport function homeDir(): string {\n return process.env.WHISPER_API_HOME || path.join(os.homedir(), \".whisper-api\");\n}\n\nexport const paths = {\n home: homeDir,\n config: () => path.join(homeDir(), \"config.json\"),\n keys: () => path.join(homeDir(), \"keys.json\"),\n /** GGML model files for whisper.cpp. */\n models: () => path.join(homeDir(), \"models\"),\n /** transformers.js / ONNX model cache. */\n cache: () => path.join(homeDir(), \"cache\"),\n /** Built/downloaded whisper.cpp binaries. */\n bin: () => path.join(homeDir(), \"bin\"),\n /** Scratch space for uploads and converted audio. */\n tmp: () => path.join(homeDir(), \"tmp\"),\n};\n\nexport function ensureDirs(): void {\n for (const p of [homeDir(), paths.models(), paths.cache(), paths.bin(), paths.tmp()]) {\n fs.mkdirSync(p, { recursive: true });\n }\n}\n\nexport function configExists(): boolean {\n return fs.existsSync(paths.config());\n}\n\nexport async function loadConfig(): Promise<WhisperApiConfig> {\n try {\n const raw = await fsp.readFile(paths.config(), \"utf8\");\n const parsed = JSON.parse(raw) as Partial<WhisperApiConfig>;\n return {\n ...DEFAULT_CONFIG,\n ...parsed,\n rateLimit: { ...DEFAULT_CONFIG.rateLimit, ...(parsed.rateLimit ?? {}) },\n };\n } catch {\n return { ...DEFAULT_CONFIG };\n }\n}\n\nexport async function saveConfig(cfg: WhisperApiConfig): Promise<void> {\n ensureDirs();\n await fsp.writeFile(paths.config(), JSON.stringify(cfg, null, 2) + \"\\n\", \"utf8\");\n}\n\n/**\n * Apply environment-variable overrides on top of a loaded config.\n * Useful in containers/systemd where mutating config.json is awkward.\n */\nexport function applyEnvOverrides(cfg: WhisperApiConfig): WhisperApiConfig {\n const out = { ...cfg, rateLimit: { ...cfg.rateLimit } };\n if (process.env.WHISPER_API_PORT) out.port = Number(process.env.WHISPER_API_PORT);\n if (process.env.WHISPER_API_HOST) out.host = process.env.WHISPER_API_HOST;\n if (process.env.WHISPER_API_ENGINE) out.engine = process.env.WHISPER_API_ENGINE as EngineChoice;\n if (process.env.WHISPER_API_MODEL) out.defaultModel = process.env.WHISPER_API_MODEL;\n if (process.env.WHISPER_API_MAX_UPLOAD_MB) {\n out.maxUploadBytes = Number(process.env.WHISPER_API_MAX_UPLOAD_MB) * 1024 * 1024;\n }\n if (process.env.WHISPER_API_RATE_MAX) out.rateLimit.max = Number(process.env.WHISPER_API_RATE_MAX);\n return out;\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { paths } from \"../config\";\n\nexport interface ModelInfo {\n /** Friendly name, e.g. \"base.en\". */\n name: string;\n /** GGML filename used by whisper.cpp. */\n ggmlFile: string;\n /** transformers.js / ONNX model repo id. */\n onnxRepo: string;\n /** Approximate GGML download size in MB (for UX). */\n sizeMB: number;\n englishOnly: boolean;\n description: string;\n}\n\nconst HF_GGML_BASE = \"https://huggingface.co/ggerganov/whisper.cpp/resolve/main\";\n\nfunction ggml(name: string): string {\n return `ggml-${name}.bin`;\n}\n\n/** Supported models, smallest → largest. */\nexport const MODELS: ModelInfo[] = [\n { name: \"tiny.en\", ggmlFile: ggml(\"tiny.en\"), onnxRepo: \"Xenova/whisper-tiny.en\", sizeMB: 75, englishOnly: true, description: \"Fastest, English-only\" },\n { name: \"tiny\", ggmlFile: ggml(\"tiny\"), onnxRepo: \"Xenova/whisper-tiny\", sizeMB: 75, englishOnly: false, description: \"Fastest, multilingual\" },\n { name: \"base.en\", ggmlFile: ggml(\"base.en\"), onnxRepo: \"Xenova/whisper-base.en\", sizeMB: 142, englishOnly: true, description: \"Good speed/quality, English-only\" },\n { name: \"base\", ggmlFile: ggml(\"base\"), onnxRepo: \"Xenova/whisper-base\", sizeMB: 142, englishOnly: false, description: \"Good speed/quality, multilingual\" },\n { name: \"small.en\", ggmlFile: ggml(\"small.en\"), onnxRepo: \"Xenova/whisper-small.en\", sizeMB: 466, englishOnly: true, description: \"Higher quality, English-only\" },\n { name: \"small\", ggmlFile: ggml(\"small\"), onnxRepo: \"Xenova/whisper-small\", sizeMB: 466, englishOnly: false, description: \"Higher quality, multilingual\" },\n { name: \"medium.en\", ggmlFile: ggml(\"medium.en\"), onnxRepo: \"Xenova/whisper-medium.en\", sizeMB: 1500, englishOnly: true, description: \"High quality, English-only\" },\n { name: \"medium\", ggmlFile: ggml(\"medium\"), onnxRepo: \"Xenova/whisper-medium\", sizeMB: 1500, englishOnly: false, description: \"High quality, multilingual\" },\n { name: \"large-v3-turbo\", ggmlFile: ggml(\"large-v3-turbo\"), onnxRepo: \"onnx-community/whisper-large-v3-turbo\", sizeMB: 1600, englishOnly: false, description: \"Near large-v3 quality, much faster\" },\n { name: \"large-v3\", ggmlFile: ggml(\"large-v3\"), onnxRepo: \"onnx-community/whisper-large-v3\", sizeMB: 3100, englishOnly: false, description: \"Best quality, multilingual\" },\n];\n\n/** OpenAI clients commonly send model=\"whisper-1\"; alias it to the configured default. */\nexport const OPENAI_ALIASES = new Set([\"whisper-1\", \"whisper-large-v3\", \"gpt-4o-transcribe\", \"gpt-4o-mini-transcribe\"]);\n\nexport function isAlias(model: string): boolean {\n return OPENAI_ALIASES.has(model);\n}\n\nexport function findModel(name: string): ModelInfo | undefined {\n return MODELS.find((m) => m.name === name);\n}\n\n/**\n * Resolve a requested model id (possibly an OpenAI alias) to a known model,\n * falling back to the configured default.\n */\nexport function resolveModel(requested: string | undefined, defaultModel: string): ModelInfo {\n if (requested && !isAlias(requested)) {\n const found = findModel(requested);\n if (found) return found;\n }\n return findModel(defaultModel) ?? MODELS.find((m) => m.name === \"base.en\")!;\n}\n\nexport function ggmlPath(model: ModelInfo): string {\n return path.join(paths.models(), model.ggmlFile);\n}\n\nexport function ggmlUrl(model: ModelInfo): string {\n return `${HF_GGML_BASE}/${model.ggmlFile}`;\n}\n\nexport function isGgmlInstalled(model: ModelInfo): boolean {\n return fs.existsSync(ggmlPath(model));\n}\n\nexport type ProgressFn = (received: number, total: number) => void;\n\n/**\n * Stream a GGML model file from Hugging Face to the models dir, reporting\n * progress. Downloads to a .part file and renames on success (atomic-ish).\n */\nexport async function downloadGgml(model: ModelInfo, onProgress?: ProgressFn): Promise<string> {\n const dest = ggmlPath(model);\n if (fs.existsSync(dest)) return dest;\n fs.mkdirSync(paths.models(), { recursive: true });\n\n const url = ggmlUrl(model);\n const res = await fetch(url, { redirect: \"follow\" });\n if (!res.ok || !res.body) {\n throw new Error(`Failed to download ${model.name} (${res.status} ${res.statusText}) from ${url}`);\n }\n const total = Number(res.headers.get(\"content-length\") || 0);\n const tmp = dest + \".part\";\n const out = fs.createWriteStream(tmp);\n let received = 0;\n\n const reader = res.body.getReader();\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) {\n received += value.length;\n if (!out.write(value)) {\n await new Promise<void>((resolve) => out.once(\"drain\", resolve));\n }\n onProgress?.(received, total);\n }\n }\n } finally {\n out.end();\n await new Promise<void>((resolve, reject) => {\n out.on(\"finish\", () => resolve());\n out.on(\"error\", reject);\n });\n }\n fs.renameSync(tmp, dest);\n return dest;\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport { paths, ensureDirs } from \"../config\";\n\nexport const KEY_PREFIX = \"sk-wapi-\";\n\nexport interface KeyRecord {\n id: string;\n name: string;\n /** Human-recognizable leading slice of the raw key (safe to store/display). */\n prefix: string;\n /** SHA-256 hex of the raw key. The raw key itself is never stored. */\n hash: string;\n createdAt: string;\n lastUsedAt: string | null;\n revoked: boolean;\n}\n\nexport function generateRawKey(): string {\n return KEY_PREFIX + crypto.randomBytes(32).toString(\"base64url\");\n}\n\nexport function hashKey(raw: string): string {\n return crypto.createHash(\"sha256\").update(raw).digest(\"hex\");\n}\n\nfunction newId(): string {\n return \"key_\" + crypto.randomBytes(10).toString(\"hex\");\n}\n\nasync function load(): Promise<KeyRecord[]> {\n try {\n const raw = await fsp.readFile(paths.keys(), \"utf8\");\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? (parsed as KeyRecord[]) : [];\n } catch {\n return [];\n }\n}\n\nasync function persist(list: KeyRecord[]): Promise<void> {\n ensureDirs();\n // Restrictive perms — this file effectively holds the access list.\n await fsp.writeFile(paths.keys(), JSON.stringify(list, null, 2) + \"\\n\", { encoding: \"utf8\", mode: 0o600 });\n try {\n fs.chmodSync(paths.keys(), 0o600);\n } catch {\n /* best effort on platforms without POSIX perms */\n }\n}\n\n/** Create a new key. Returns the raw secret (shown once) plus its stored record. */\nexport async function createKey(name: string): Promise<{ raw: string; record: KeyRecord }> {\n const raw = generateRawKey();\n const record: KeyRecord = {\n id: newId(),\n name: name || \"default\",\n prefix: raw.slice(0, KEY_PREFIX.length + 6),\n hash: hashKey(raw),\n createdAt: new Date().toISOString(),\n lastUsedAt: null,\n revoked: false,\n };\n const list = await load();\n list.push(record);\n await persist(list);\n return { raw, record };\n}\n\nexport async function listKeys(): Promise<KeyRecord[]> {\n return load();\n}\n\nexport async function countActiveKeys(): Promise<number> {\n return (await load()).filter((k) => !k.revoked).length;\n}\n\n/** Revoke by id or prefix. Returns true if a matching active key was revoked. */\nexport async function revokeKey(idOrPrefix: string): Promise<boolean> {\n const list = await load();\n let changed = false;\n for (const rec of list) {\n if (!rec.revoked && (rec.id === idOrPrefix || rec.prefix === idOrPrefix)) {\n rec.revoked = true;\n changed = true;\n }\n }\n if (changed) await persist(list);\n return changed;\n}\n\n/**\n * Verify a raw bearer token against stored hashes using a constant-time compare.\n * Updates lastUsedAt on success. Returns the matching record or null.\n */\nexport async function verifyKey(raw: string): Promise<KeyRecord | null> {\n if (!raw || !raw.startsWith(KEY_PREFIX)) return null;\n const candidate = Buffer.from(hashKey(raw), \"hex\");\n const list = await load();\n let match: KeyRecord | null = null;\n for (const rec of list) {\n if (rec.revoked) continue;\n const stored = Buffer.from(rec.hash, \"hex\");\n if (stored.length === candidate.length && crypto.timingSafeEqual(stored, candidate)) {\n match = rec;\n break;\n }\n }\n if (match) {\n match.lastUsedAt = new Date().toISOString();\n await persist(list);\n }\n return match;\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport ffmpegStatic from \"ffmpeg-static\";\nimport { paths, ensureDirs } from \"./config\";\n\nconst SAMPLE_RATE = 16000;\n\nfunction ffmpegBin(): string {\n // ffmpeg-static exports the bundled binary path; allow override.\n return process.env.FFMPEG_PATH || (ffmpegStatic as unknown as string) || \"ffmpeg\";\n}\n\nfunction run(args: string[]): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const proc = spawn(ffmpegBin(), args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n const out: Buffer[] = [];\n const err: Buffer[] = [];\n proc.stdout.on(\"data\", (d: Buffer) => out.push(d));\n proc.stderr.on(\"data\", (d: Buffer) => err.push(d));\n proc.on(\"error\", reject);\n proc.on(\"close\", (code) => {\n if (code === 0) resolve(Buffer.concat(out));\n else reject(new Error(`ffmpeg exited with code ${code}: ${Buffer.concat(err).toString(\"utf8\").slice(-800)}`));\n });\n });\n}\n\n/** Convert any input audio/video into a 16 kHz mono 16-bit WAV file (for whisper.cpp). */\nexport async function toWav16k(inputPath: string): Promise<string> {\n ensureDirs();\n const outPath = path.join(paths.tmp(), `wav-${crypto.randomBytes(8).toString(\"hex\")}.wav`);\n await run([\"-nostdin\", \"-i\", inputPath, \"-ar\", String(SAMPLE_RATE), \"-ac\", \"1\", \"-c:a\", \"pcm_s16le\", \"-f\", \"wav\", outPath, \"-y\"]);\n return outPath;\n}\n\nexport interface DecodedAudio {\n samples: Float32Array;\n sampleRate: number;\n duration: number;\n}\n\n/** Decode any input into mono 16 kHz Float32 PCM samples (for the ONNX engine). */\nexport async function toFloat32(inputPath: string): Promise<DecodedAudio> {\n const raw = await run([\"-nostdin\", \"-i\", inputPath, \"-ar\", String(SAMPLE_RATE), \"-ac\", \"1\", \"-f\", \"f32le\", \"-\"]);\n // Copy into a correctly-aligned buffer before viewing as Float32.\n const aligned = new Uint8Array(raw.byteLength);\n aligned.set(raw);\n const samples = new Float32Array(aligned.buffer, 0, Math.floor(aligned.byteLength / 4));\n return { samples, sampleRate: SAMPLE_RATE, duration: samples.length / SAMPLE_RATE };\n}\n\nexport function cleanup(file: string | undefined): void {\n if (!file) return;\n try {\n fs.rmSync(file, { force: true });\n } catch {\n /* ignore */\n }\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport { toFloat32 } from \"../audio\";\nimport { paths } from \"../config\";\nimport type { ModelInfo, ProgressFn } from \"../models/registry\";\nimport type { Segment, TranscribeOptions, TranscriptionEngine, TranscriptionResult } from \"./types\";\n\n// transformers.js is heavy; import lazily so unrelated CLI commands stay fast.\ntype Pipeline = (input: Float32Array, opts: Record<string, unknown>) => Promise<OnnxOutput>;\ninterface OnnxChunk {\n timestamp: [number, number | null];\n text: string;\n}\ninterface OnnxOutput {\n text: string;\n chunks?: OnnxChunk[];\n}\n\nconst ISO_TO_NAME: Record<string, string> = {\n en: \"english\", es: \"spanish\", fr: \"french\", de: \"german\", it: \"italian\",\n pt: \"portuguese\", nl: \"dutch\", ru: \"russian\", zh: \"chinese\", ja: \"japanese\",\n ko: \"korean\", ar: \"arabic\", hi: \"hindi\", tr: \"turkish\", pl: \"polish\",\n uk: \"ukrainian\", sv: \"swedish\", cs: \"czech\", da: \"danish\", fi: \"finnish\",\n};\n\n/** Pure-JS engine via @huggingface/transformers (onnxruntime-node). No compiler needed. */\nexport class OnnxEngine implements TranscriptionEngine {\n readonly kind = \"onnx\" as const;\n readonly model: ModelInfo;\n private device: string;\n private pipe: Pipeline | null = null;\n\n constructor(model: ModelInfo) {\n this.model = model;\n this.device = process.env.WHISPER_API_ONNX_DEVICE || \"cpu\";\n }\n\n describe(): string {\n return `onnx (${this.device})`;\n }\n\n forModel(model: ModelInfo): TranscriptionEngine {\n return new OnnxEngine(model);\n }\n\n private async getPipe(onProgress?: ProgressFn): Promise<Pipeline> {\n if (this.pipe) return this.pipe;\n const { pipeline, env } = await import(\"@huggingface/transformers\");\n env.cacheDir = paths.cache();\n env.allowLocalModels = true;\n\n const dtype = process.env.WHISPER_API_ONNX_DTYPE || (this.model.sizeMB > 1000 ? \"q8\" : \"fp32\");\n const pipe = (await pipeline(\"automatic-speech-recognition\", this.model.onnxRepo, {\n device: this.device as never,\n dtype: dtype as never,\n progress_callback: onProgress\n ? (p: { status?: string; loaded?: number; total?: number }) => {\n if (p.status === \"progress\" && typeof p.loaded === \"number\" && typeof p.total === \"number\") {\n onProgress(p.loaded, p.total);\n }\n }\n : undefined,\n })) as unknown as Pipeline;\n this.pipe = pipe;\n return pipe;\n }\n\n async ensureModel(onProgress?: ProgressFn): Promise<void> {\n // Instantiating the pipeline downloads & caches the ONNX weights.\n await this.getPipe(onProgress);\n }\n\n async transcribe(inputPath: string, opts: TranscribeOptions): Promise<TranscriptionResult> {\n const pipe = await this.getPipe();\n const { samples, duration } = await toFloat32(inputPath);\n\n const runOpts: Record<string, unknown> = {\n return_timestamps: true,\n chunk_length_s: 30,\n stride_length_s: 5,\n };\n if (!this.model.englishOnly) {\n runOpts[\"task\"] = opts.translate ? \"translate\" : \"transcribe\";\n if (opts.language) runOpts[\"language\"] = ISO_TO_NAME[opts.language] ?? opts.language;\n }\n if (typeof opts.temperature === \"number\") runOpts[\"temperature\"] = opts.temperature;\n\n const out = await pipe(samples, runOpts);\n const segments: Segment[] = (out.chunks ?? []).map((c, i) => ({\n id: i,\n start: c.timestamp[0] ?? 0,\n end: c.timestamp[1] ?? duration,\n text: c.text.trim(),\n }));\n\n return {\n text: (out.text ?? \"\").trim(),\n language: opts.language,\n duration,\n segments,\n };\n }\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport { paths } from \"../config\";\nimport { toWav16k, cleanup } from \"../audio\";\nimport { downloadGgml, ggmlPath, type ModelInfo, type ProgressFn } from \"../models/registry\";\nimport type { Gpu } from \"./probe\";\nimport type { Segment, TranscribeOptions, TranscriptionEngine, TranscriptionResult } from \"./types\";\n\ninterface WhisperCppJson {\n result?: { language?: string };\n params?: { language?: string };\n transcription?: Array<{\n timestamps?: { from?: string; to?: string };\n offsets?: { from?: number; to?: number }; // milliseconds\n text?: string;\n }>;\n}\n\n/** Engine backed by a native whisper.cpp `whisper-cli` binary (CPU + CUDA/Metal). */\nexport class WhisperCppEngine implements TranscriptionEngine {\n readonly kind = \"whispercpp\" as const;\n readonly model: ModelInfo;\n private bin: string;\n private gpu: Gpu;\n\n constructor(model: ModelInfo, bin: string, gpu: Gpu) {\n this.model = model;\n this.bin = bin;\n this.gpu = gpu;\n }\n\n describe(): string {\n return `whisper.cpp (${this.gpu ?? \"cpu\"})`;\n }\n\n forModel(model: ModelInfo): TranscriptionEngine {\n return new WhisperCppEngine(model, this.bin, this.gpu);\n }\n\n async ensureModel(onProgress?: ProgressFn): Promise<void> {\n await downloadGgml(this.model, onProgress);\n }\n\n async transcribe(inputPath: string, opts: TranscribeOptions): Promise<TranscriptionResult> {\n await this.ensureModel();\n const wav = await toWav16k(inputPath);\n const outPrefix = path.join(paths.tmp(), `wcpp-${crypto.randomBytes(8).toString(\"hex\")}`);\n const jsonPath = outPrefix + \".json\";\n\n const args = [\n \"-m\", ggmlPath(this.model),\n \"-f\", wav,\n \"-oj\",\n \"-of\", outPrefix,\n \"-np\",\n \"-t\", String(Math.max(1, os.cpus().length)),\n ];\n if (this.model.englishOnly) {\n args.push(\"-l\", \"en\");\n } else {\n args.push(\"-l\", opts.language ?? \"auto\");\n }\n if (opts.translate) args.push(\"--translate\");\n if (typeof opts.temperature === \"number\") args.push(\"-tp\", String(opts.temperature));\n if (opts.prompt) args.push(\"--prompt\", opts.prompt);\n\n try {\n await this.run(args);\n const raw = await fsp.readFile(jsonPath, \"utf8\");\n return this.parse(JSON.parse(raw) as WhisperCppJson, opts);\n } finally {\n cleanup(wav);\n cleanup(jsonPath);\n }\n }\n\n private run(args: string[]): Promise<void> {\n return new Promise((resolve, reject) => {\n const proc = spawn(this.bin, args, { stdio: [\"ignore\", \"ignore\", \"pipe\"] });\n const err: Buffer[] = [];\n proc.stderr.on(\"data\", (d: Buffer) => err.push(d));\n proc.on(\"error\", reject);\n proc.on(\"close\", (code) =>\n code === 0\n ? resolve()\n : reject(new Error(`whisper-cli exited with code ${code}: ${Buffer.concat(err).toString(\"utf8\").slice(-800)}`)),\n );\n });\n }\n\n private parse(data: WhisperCppJson, opts: TranscribeOptions): TranscriptionResult {\n const items = data.transcription ?? [];\n const segments: Segment[] = items.map((it, i) => ({\n id: i,\n start: (it.offsets?.from ?? 0) / 1000,\n end: (it.offsets?.to ?? 0) / 1000,\n text: (it.text ?? \"\").trim(),\n }));\n const last = items[items.length - 1];\n return {\n text: items.map((it) => it.text ?? \"\").join(\"\").trim(),\n language: data.result?.language ?? data.params?.language ?? opts.language,\n duration: last?.offsets?.to ? last.offsets.to / 1000 : undefined,\n segments,\n };\n }\n}\n\n/** True if a GGML file for this model is already on disk. */\nexport function ggmlInstalled(model: ModelInfo): boolean {\n return fs.existsSync(ggmlPath(model));\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport { spawn, spawnSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { paths, ensureDirs } from \"../config\";\n\nexport type Gpu = \"cuda\" | \"metal\" | null;\n\nconst WHISPER_CPP_REPO = \"https://github.com/ggml-org/whisper.cpp\";\n\n/** Is an executable resolvable on PATH? */\nexport function which(cmd: string): boolean {\n const finder = process.platform === \"win32\" ? \"where\" : \"which\";\n const r = spawnSync(finder, [cmd], { stdio: \"ignore\" });\n return r.status === 0;\n}\n\nexport function hasBuildTools(): boolean {\n const compiler = which(\"cc\") || which(\"clang\") || which(\"gcc\") || which(\"c++\");\n return which(\"git\") && which(\"cmake\") && compiler;\n}\n\nexport function detectGpu(): Gpu {\n if (which(\"nvidia-smi\")) return \"cuda\";\n if (process.platform === \"darwin\" && os.arch() === \"arm64\") return \"metal\";\n return null;\n}\n\nfunction binCandidates(): string[] {\n const exe = process.platform === \"win32\" ? \".exe\" : \"\";\n const names = [`whisper-cli${exe}`, `main${exe}`];\n const out: string[] = [];\n if (process.env.WHISPER_CPP_BIN) out.push(process.env.WHISPER_CPP_BIN);\n for (const n of names) out.push(path.join(paths.bin(), n));\n return out;\n}\n\n/** Locate a usable whisper.cpp binary: env → cached build → PATH. */\nexport function locateWhisperBinary(): string | null {\n for (const c of binCandidates()) {\n if (fs.existsSync(c)) return c;\n }\n if (which(\"whisper-cli\")) return \"whisper-cli\";\n return null;\n}\n\ntype LogFn = (line: string) => void;\n\nfunction step(cmd: string, args: string[], cwd: string, onLog?: LogFn): Promise<void> {\n return new Promise((resolve, reject) => {\n onLog?.(`$ ${cmd} ${args.join(\" \")}`);\n const proc = spawn(cmd, args, { cwd, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n const relay = (d: Buffer) => onLog?.(d.toString(\"utf8\").trimEnd());\n proc.stdout.on(\"data\", relay);\n proc.stderr.on(\"data\", relay);\n proc.on(\"error\", reject);\n proc.on(\"close\", (code) =>\n code === 0 ? resolve() : reject(new Error(`${cmd} exited with code ${code}`)),\n );\n });\n}\n\n/**\n * Clone and build whisper.cpp, then install the `whisper-cli` binary into the\n * whisper-api bin dir. Best-effort: throws if the toolchain is missing or the\n * build fails, so callers can fall back to the ONNX engine.\n */\nexport async function buildWhisperCpp(onLog?: LogFn): Promise<string> {\n if (!hasBuildTools()) {\n throw new Error(\"Build tools missing (need git, cmake and a C/C++ compiler).\");\n }\n ensureDirs();\n const srcDir = path.join(paths.cache(), \"whisper.cpp-src\");\n const buildDir = path.join(srcDir, \"build\");\n const gpu = detectGpu();\n\n if (!fs.existsSync(path.join(srcDir, \"CMakeLists.txt\"))) {\n fs.rmSync(srcDir, { recursive: true, force: true });\n await step(\"git\", [\"clone\", \"--depth\", \"1\", WHISPER_CPP_REPO, srcDir], paths.cache(), onLog);\n }\n\n const cmakeArgs = [\n \"-S\", srcDir,\n \"-B\", buildDir,\n \"-DCMAKE_BUILD_TYPE=Release\",\n \"-DWHISPER_BUILD_TESTS=OFF\",\n \"-DWHISPER_BUILD_SERVER=OFF\",\n \"-DWHISPER_BUILD_EXAMPLES=ON\",\n ];\n if (gpu === \"cuda\") cmakeArgs.push(\"-DGGML_CUDA=ON\");\n // Metal is enabled by default on Apple Silicon with shaders embedded in the binary.\n\n await step(\"cmake\", cmakeArgs, srcDir, onLog);\n await step(\"cmake\", [\"--build\", buildDir, \"-j\", String(Math.max(1, os.cpus().length)), \"--config\", \"Release\"], srcDir, onLog);\n\n const exe = process.platform === \"win32\" ? \".exe\" : \"\";\n const built = [\n path.join(buildDir, \"bin\", `whisper-cli${exe}`),\n path.join(buildDir, \"bin\", \"Release\", `whisper-cli${exe}`),\n ].find((p) => fs.existsSync(p));\n if (!built) throw new Error(\"Build finished but whisper-cli binary was not found.\");\n\n const dest = path.join(paths.bin(), `whisper-cli${exe}`);\n fs.copyFileSync(built, dest);\n fs.chmodSync(dest, 0o755);\n onLog?.(`Installed whisper.cpp → ${dest}`);\n return dest;\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport type { EngineChoice } from \"../config\";\nimport type { ModelInfo } from \"../models/registry\";\nimport { OnnxEngine } from \"./onnx\";\nimport { WhisperCppEngine } from \"./whispercpp\";\nimport { buildWhisperCpp, detectGpu, hasBuildTools, locateWhisperBinary } from \"./probe\";\nimport type { TranscriptionEngine } from \"./types\";\n\nexport interface EngineSelection {\n engine: TranscriptionEngine;\n reason: string;\n}\n\nexport interface CreateEngineOpts {\n engine: EngineChoice;\n model: ModelInfo;\n /** Permit building whisper.cpp from source if no binary is found. */\n allowBuild?: boolean;\n onLog?: (line: string) => void;\n}\n\n/**\n * Resolve which transcription engine to use.\n *\n * - `onnx` → always the portable ONNX engine.\n * - `whispercpp` → require/obtain a native binary (build if allowed), else error.\n * - `auto` → prefer an existing whisper.cpp binary; optionally build one;\n * otherwise fall back to the portable ONNX engine.\n */\nexport async function createEngine(opts: CreateEngineOpts): Promise<EngineSelection> {\n const { engine, model, model: m } = opts;\n const allowBuild = opts.allowBuild ?? process.env.WHISPER_API_AUTOBUILD === \"1\";\n\n if (engine === \"onnx\") {\n return { engine: new OnnxEngine(m), reason: \"engine=onnx (portable, no compiler)\" };\n }\n\n if (engine === \"whispercpp\") {\n const bin = locateWhisperBinary() ?? (await tryBuild(opts.onLog));\n if (!bin) {\n throw new Error(\n \"engine=whispercpp requested but no binary is available and it could not be built. \" +\n \"Install build tools (git, cmake, a C/C++ compiler) and run `whisper-api build-engine`, \" +\n \"set WHISPER_CPP_BIN, or use --engine onnx.\",\n );\n }\n return { engine: new WhisperCppEngine(model, bin, detectGpu()), reason: \"engine=whispercpp\" };\n }\n\n // auto\n const existing = locateWhisperBinary();\n if (existing) {\n return { engine: new WhisperCppEngine(model, existing, detectGpu()), reason: \"auto → whisper.cpp (binary found)\" };\n }\n if (allowBuild && hasBuildTools()) {\n const built = await tryBuild(opts.onLog);\n if (built) {\n return { engine: new WhisperCppEngine(model, built, detectGpu()), reason: \"auto → whisper.cpp (built from source)\" };\n }\n }\n return {\n engine: new OnnxEngine(m),\n reason: hasBuildTools()\n ? \"auto → onnx (no whisper.cpp binary; run `whisper-api build-engine` for native speed)\"\n : \"auto → onnx (no whisper.cpp binary and no build toolchain)\",\n };\n}\n\nasync function tryBuild(onLog?: (l: string) => void): Promise<string | null> {\n try {\n return await buildWhisperCpp(onLog);\n } catch (err) {\n onLog?.(`whisper.cpp build failed: ${(err as Error).message}`);\n return null;\n }\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport { fileURLToPath } from \"node:url\";\nimport fs from \"node:fs\";\nimport Fastify, { type FastifyError, type FastifyInstance } from \"fastify\";\nimport multipart from \"@fastify/multipart\";\nimport rateLimit from \"@fastify/rate-limit\";\nimport fastifyStatic from \"@fastify/static\";\nimport type { WhisperApiConfig } from \"../config\";\nimport type { ModelInfo } from \"../models/registry\";\nimport type { TranscriptionEngine } from \"../engine/types\";\nimport { authHook, extractBearer } from \"./auth\";\nimport { errorBody } from \"./formats\";\nimport { registerTranscriptions } from \"./routes/transcriptions\";\nimport { registerModels } from \"./routes/models\";\nimport { registerHealth } from \"./routes/health\";\n\nexport interface ServerContext {\n config: WhisperApiConfig;\n /** Engine for the configured default model. */\n defaultEngine: TranscriptionEngine;\n /** Human label, e.g. \"whisper.cpp (metal)\". */\n engineLabel: string;\n version: string;\n /** Resolve (and cache) an engine for a specific model name. */\n getEngine(modelName: string): Promise<TranscriptionEngine>;\n}\n\nfunction findWebDir(): string | null {\n for (const rel of [\"../web\", \"../../web\", \"../../../web\"]) {\n const dir = fileURLToPath(new URL(rel, import.meta.url));\n if (fs.existsSync(dir)) return dir;\n }\n return null;\n}\n\nexport async function buildServer(ctx: ServerContext): Promise<FastifyInstance> {\n const app = Fastify({\n logger: process.env.WHISPER_API_LOG === \"silent\" ? false : { level: process.env.WHISPER_API_LOG || \"info\" },\n bodyLimit: ctx.config.maxUploadBytes + 1024 * 1024,\n });\n\n await app.register(multipart, {\n limits: { fileSize: ctx.config.maxUploadBytes, files: 1, fields: 25 },\n });\n\n await app.register(rateLimit, {\n global: false,\n keyGenerator: (req) => extractBearer(req.headers.authorization) ?? req.ip,\n errorResponseBuilder: () =>\n errorBody(\"Rate limit exceeded. Slow down or request a higher limit.\", \"rate_limit_error\", \"rate_limit_exceeded\"),\n });\n\n app.addHook(\"onRequest\", authHook);\n\n app.setErrorHandler((err: FastifyError, req, reply) => {\n const status = (err.statusCode && err.statusCode >= 400 ? err.statusCode : 500) as number;\n req.log.error({ err }, \"request error\");\n reply.code(status).send(errorBody(err.message || \"Internal server error.\", status >= 500 ? \"server_error\" : \"invalid_request_error\"));\n });\n\n // Routes\n registerHealth(app, ctx);\n registerModels(app, ctx);\n registerTranscriptions(app, ctx);\n\n // Static web status page (served at \"/\").\n const webDir = findWebDir();\n if (webDir) {\n await app.register(fastifyStatic, { root: webDir, prefix: \"/\", index: [\"index.html\"] });\n } else {\n app.get(\"/\", async () => ({ name: \"whisper-api\", status: \"ok\", docs: \"/health\" }));\n }\n\n return app;\n}\n\nexport async function startServer(ctx: ServerContext): Promise<{ app: FastifyInstance; url: string }> {\n const app = await buildServer(ctx);\n await app.listen({ host: ctx.config.host, port: ctx.config.port });\n const shown = ctx.config.host === \"0.0.0.0\" ? \"localhost\" : ctx.config.host;\n return { app, url: `http://${shown}:${ctx.config.port}` };\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport type { TranscriptionResult } from \"../engine/types\";\n\nexport type ResponseFormat = \"json\" | \"verbose_json\" | \"text\" | \"srt\" | \"vtt\";\n\nexport const RESPONSE_FORMATS: ResponseFormat[] = [\"json\", \"verbose_json\", \"text\", \"srt\", \"vtt\"];\n\nexport function isResponseFormat(v: string): v is ResponseFormat {\n return (RESPONSE_FORMATS as string[]).includes(v);\n}\n\nfunction pad(n: number, width: number): string {\n return Math.floor(n).toString().padStart(width, \"0\");\n}\n\n/** Seconds → \"HH:MM:SS,mmm\" (SRT) or \"HH:MM:SS.mmm\" (VTT). */\nfunction timestamp(seconds: number, sep: \",\" | \".\"): string {\n const ms = Math.round((seconds - Math.floor(seconds)) * 1000);\n const s = Math.floor(seconds) % 60;\n const m = Math.floor(seconds / 60) % 60;\n const h = Math.floor(seconds / 3600);\n return `${pad(h, 2)}:${pad(m, 2)}:${pad(s, 2)}${sep}${pad(ms, 3)}`;\n}\n\nfunction toSrt(r: TranscriptionResult): string {\n return (\n r.segments\n .map((seg, i) => `${i + 1}\\n${timestamp(seg.start, \",\")} --> ${timestamp(seg.end, \",\")}\\n${seg.text}\\n`)\n .join(\"\\n\") + \"\\n\"\n );\n}\n\nfunction toVtt(r: TranscriptionResult): string {\n const cues = r.segments\n .map((seg) => `${timestamp(seg.start, \".\")} --> ${timestamp(seg.end, \".\")}\\n${seg.text}`)\n .join(\"\\n\\n\");\n return `WEBVTT\\n\\n${cues}\\n`;\n}\n\nexport interface SerializedResponse {\n contentType: string;\n body: string;\n}\n\n/** Render a transcription result in the requested OpenAI-compatible format. */\nexport function serialize(result: TranscriptionResult, format: ResponseFormat): SerializedResponse {\n switch (format) {\n case \"text\":\n return { contentType: \"text/plain; charset=utf-8\", body: result.text + \"\\n\" };\n case \"srt\":\n return { contentType: \"text/plain; charset=utf-8\", body: toSrt(result) };\n case \"vtt\":\n return { contentType: \"text/vtt; charset=utf-8\", body: toVtt(result) };\n case \"verbose_json\":\n return {\n contentType: \"application/json; charset=utf-8\",\n body: JSON.stringify({\n task: \"transcribe\",\n language: result.language ?? \"unknown\",\n duration: result.duration ?? 0,\n text: result.text,\n segments: result.segments.map((seg) => ({\n id: seg.id,\n seek: 0,\n start: seg.start,\n end: seg.end,\n text: seg.text,\n tokens: [],\n temperature: 0,\n avg_logprob: 0,\n compression_ratio: 0,\n no_speech_prob: 0,\n })),\n }),\n };\n case \"json\":\n default:\n return { contentType: \"application/json; charset=utf-8\", body: JSON.stringify({ text: result.text }) };\n }\n}\n\n/** OpenAI-shaped error body. */\nexport function errorBody(message: string, type = \"invalid_request_error\", code: string | null = null) {\n return { error: { message, type, param: null, code } };\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport type { FastifyReply, FastifyRequest } from \"fastify\";\nimport { verifyKey, type KeyRecord } from \"../keys/store\";\nimport { errorBody } from \"./formats\";\n\ndeclare module \"fastify\" {\n interface FastifyRequest {\n apiKey?: KeyRecord;\n }\n}\n\n/** Paths that never require authentication. */\nconst PUBLIC_PATHS = new Set([\"/health\", \"/\", \"/favicon.ico\"]);\n\nfunction isPublic(url: string): boolean {\n const pathname = url.split(\"?\")[0] ?? url;\n return PUBLIC_PATHS.has(pathname) || (!pathname.startsWith(\"/v1/\") && !pathname.startsWith(\"/v1\"));\n}\n\nexport function extractBearer(header: string | undefined): string | null {\n if (!header) return null;\n const m = /^Bearer\\s+(.+)$/i.exec(header.trim());\n return m ? m[1]!.trim() : null;\n}\n\n/** Fastify onRequest hook enforcing bearer-token auth on /v1/* routes. */\nexport async function authHook(req: FastifyRequest, reply: FastifyReply): Promise<void> {\n if (isPublic(req.url)) return;\n\n const token = extractBearer(req.headers.authorization);\n if (!token) {\n await reply\n .code(401)\n .send(errorBody(\"Missing bearer token. Pass `Authorization: Bearer <key>`.\", \"invalid_request_error\", \"missing_api_key\"));\n return;\n }\n const record = await verifyKey(token);\n if (!record) {\n await reply.code(401).send(errorBody(\"Invalid or revoked API key.\", \"invalid_request_error\", \"invalid_api_key\"));\n return;\n }\n req.apiKey = record;\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport { pipeline } from \"node:stream/promises\";\nimport type { FastifyInstance } from \"fastify\";\nimport { paths, ensureDirs } from \"../../config\";\nimport { cleanup } from \"../../audio\";\nimport { resolveModel } from \"../../models/registry\";\nimport { errorBody, isResponseFormat, serialize, type ResponseFormat } from \"../formats\";\nimport type { ServerContext } from \"../app\";\n\ninterface ParsedRequest {\n filePath?: string;\n filename?: string;\n fields: Record<string, string>;\n}\n\nasync function parseMultipart(req: import(\"fastify\").FastifyRequest): Promise<ParsedRequest> {\n ensureDirs();\n const result: ParsedRequest = { fields: {} };\n for await (const part of req.parts()) {\n if (part.type === \"file\") {\n if (part.fieldname === \"file\") {\n const ext = path.extname(part.filename || \"\") || \".bin\";\n const dest = path.join(paths.tmp(), `up-${crypto.randomBytes(8).toString(\"hex\")}${ext}`);\n await pipeline(part.file, fs.createWriteStream(dest));\n result.filePath = dest;\n result.filename = part.filename;\n if (part.file.truncated) {\n cleanup(dest);\n throw Object.assign(new Error(\"Uploaded file exceeds the configured size limit.\"), { statusCode: 413 });\n }\n } else {\n part.file.resume(); // drain unexpected file fields\n }\n } else {\n result.fields[part.fieldname] = String(part.value);\n }\n }\n return result;\n}\n\nexport function registerTranscriptions(app: FastifyInstance, ctx: ServerContext): void {\n const handler = (translate: boolean) => async (req: import(\"fastify\").FastifyRequest, reply: import(\"fastify\").FastifyReply) => {\n let parsed: ParsedRequest | undefined;\n try {\n parsed = await parseMultipart(req);\n if (!parsed.filePath) {\n return reply.code(400).send(errorBody(\"Missing required `file` field.\", \"invalid_request_error\", \"missing_file\"));\n }\n\n const fmtRaw = parsed.fields[\"response_format\"] || \"json\";\n if (!isResponseFormat(fmtRaw)) {\n return reply.code(400).send(errorBody(`Unsupported response_format '${fmtRaw}'.`, \"invalid_request_error\"));\n }\n const format = fmtRaw as ResponseFormat;\n\n const model = resolveModel(parsed.fields[\"model\"], ctx.config.defaultModel);\n const temperature = parsed.fields[\"temperature\"] !== undefined ? Number(parsed.fields[\"temperature\"]) : undefined;\n const task = parsed.fields[\"task\"];\n\n const engine = await ctx.getEngine(model.name);\n const result = await engine.transcribe(parsed.filePath, {\n language: parsed.fields[\"language\"] || undefined,\n translate: translate || task === \"translate\",\n temperature: typeof temperature === \"number\" && !Number.isNaN(temperature) ? temperature : undefined,\n prompt: parsed.fields[\"prompt\"] || undefined,\n });\n\n const { contentType, body } = serialize(result, format);\n return reply.header(\"content-type\", contentType).send(body);\n } catch (err) {\n const e = err as Error & { statusCode?: number };\n const status = e.statusCode ?? 500;\n req.log.error({ err: e }, \"transcription failed\");\n return reply\n .code(status)\n .send(errorBody(e.message || \"Transcription failed.\", status === 413 ? \"invalid_request_error\" : \"server_error\"));\n } finally {\n cleanup(parsed?.filePath);\n }\n };\n\n const routeOpts = {\n config: { rateLimit: { max: ctx.config.rateLimit.max, timeWindow: ctx.config.rateLimit.timeWindow } },\n };\n app.post(\"/v1/audio/transcriptions\", routeOpts, handler(false));\n app.post(\"/v1/audio/translations\", routeOpts, handler(true));\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport type { FastifyInstance } from \"fastify\";\nimport { MODELS } from \"../../models/registry\";\nimport type { ServerContext } from \"../app\";\n\n/** OpenAI-compatible model listing. Advertises `whisper-1` plus all known models. */\nexport function registerModels(app: FastifyInstance, ctx: ServerContext): void {\n const created = 1700000000; // stable placeholder timestamp\n const entry = (id: string) => ({ id, object: \"model\", created, owned_by: \"whisper-api\" });\n\n app.get(\"/v1/models\", async () => ({\n object: \"list\",\n data: [entry(\"whisper-1\"), ...MODELS.map((m) => entry(m.name))],\n }));\n\n app.get(\"/v1/models/:id\", async (req, reply) => {\n const id = (req.params as { id: string }).id;\n if (id === \"whisper-1\" || MODELS.some((m) => m.name === id)) {\n return entry(id);\n }\n return reply.code(404).send({ error: { message: `Model '${id}' not found.`, type: \"invalid_request_error\" } });\n });\n\n // Expose which model is actively loaded (handy for `status`).\n app.get(\"/v1/models/active\", async () => entry(ctx.defaultEngine.model.name));\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport type { FastifyInstance } from \"fastify\";\nimport { countActiveKeys } from \"../../keys/store\";\nimport type { ServerContext } from \"../app\";\n\n/** Unauthenticated liveness/readiness endpoint. */\nexport function registerHealth(app: FastifyInstance, ctx: ServerContext): void {\n app.get(\"/health\", async () => ({\n status: \"ok\",\n engine: ctx.engineLabel,\n model: ctx.defaultEngine.model.name,\n activeKeys: await countActiveKeys(),\n uptime: Math.round(process.uptime()),\n version: ctx.version,\n }));\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\n// Keep in sync with package.json \"version\" (checked by test/registry.test.ts).\nexport const VERSION = \"0.1.0\";\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport cliProgress from \"cli-progress\";\nimport pc from \"picocolors\";\n\nexport { pc };\n\nexport function mb(bytes: number): number {\n return Math.round(bytes / (1024 * 1024));\n}\n\n/** A reusable byte-progress bar for a single model download. */\nexport function modelProgress(label: string) {\n const bar = new cliProgress.SingleBar(\n { clearOnComplete: false, hideCursor: true, format: ` ${label} [{bar}] {percentage}% | {info}` },\n cliProgress.Presets.shades_classic,\n );\n let started = false;\n return {\n onProgress(received: number, total: number) {\n if (!started) {\n bar.start(total || 1, 0, { info: \"\" });\n started = true;\n }\n if (total) bar.setTotal(total);\n bar.update(received, { info: total ? `${mb(received)}/${mb(total)} MB` : `${mb(received)} MB` });\n },\n done() {\n if (started) {\n bar.update(bar.getTotal());\n bar.stop();\n } else {\n console.log(` ${label} ${pc.green(\"✓\")} ${pc.dim(\"(already present)\")}`);\n }\n },\n };\n}\n\n/**\n * Print copy-paste examples showing how a third-party app connects to the\n * endpoint. When `key` is omitted, a placeholder is shown with a hint.\n */\nexport function printAccessExample(baseUrl: string, key?: string): void {\n const k = key ?? \"sk-wapi-…\";\n const note = key ? \"\" : pc.dim(\" (generate one with: whisper-api key generate)\\n\");\n console.log();\n console.log(pc.bold(\" Connect a third-party app to this endpoint:\"));\n console.log();\n if (note) console.log(note.trimEnd());\n console.log(pc.dim(\" # curl\"));\n console.log(` curl ${baseUrl}/v1/audio/transcriptions \\\\`);\n console.log(` -H ${pc.cyan(`\"Authorization: Bearer ${k}\"`)} \\\\`);\n console.log(` -F file=@audio.m4a -F model=whisper-1`);\n console.log();\n console.log(pc.dim(\" # Python — official OpenAI SDK, just repoint base_url\"));\n console.log(` from openai import OpenAI`);\n console.log(` client = OpenAI(base_url=${pc.cyan(`\"${baseUrl}/v1\"`)}, api_key=${pc.cyan(`\"${k}\"`)})`);\n console.log(` print(client.audio.transcriptions.create(`);\n console.log(` model=\"whisper-1\", file=open(\"audio.m4a\", \"rb\")).text)`);\n console.log();\n console.log(pc.dim(\" # Node — official OpenAI SDK\"));\n console.log(` import OpenAI from \"openai\";`);\n console.log(` const client = new OpenAI({ baseURL: ${pc.cyan(`\"${baseUrl}/v1\"`)}, apiKey: ${pc.cyan(`\"${k}\"`)} });`);\n console.log();\n console.log(pc.dim(` # Any OpenAI-compatible app (Open WebUI, n8n, Raycast, LibreChat…):`));\n console.log(` Base URL ${pc.cyan(`${baseUrl}/v1`)}`);\n console.log(` API key ${pc.cyan(k)}`);\n console.log();\n}\n\n/** Reveal a freshly-minted secret once, with a copy warning. */\nexport function printNewKey(raw: string, name: string, id: string): void {\n console.log();\n console.log(pc.green(\" ✔ New API key — store it now, it is not recoverable:\"));\n console.log();\n console.log(` ${pc.bold(pc.cyan(raw))}`);\n console.log();\n console.log(pc.dim(` id ${id} name ${name}`));\n console.log();\n}\n"],"mappings":"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","names":["fs","path","fs","path","path","fs","fs","fsp","fsp","fs","fs","path","crypto","path","crypto","fs","pipeline","spawn","fs","fsp","os","path","crypto","path","crypto","os","fsp","spawn","spawn","fs","os","path","os","path","fs","spawn","fs","fs","path","crypto","path","crypto","fs","fs","note","path","fs","program"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/index.ts","../src/config/index.ts","../src/models/registry.ts","../src/keys/store.ts","../src/audio.ts","../src/engine/onnx.ts","../src/engine/whispercpp.ts","../src/engine/probe.ts","../src/engine/detect.ts","../src/server/app.ts","../src/server/auth.ts","../src/server/formats.ts","../src/server/routes/transcriptions.ts","../src/server/routes/models.ts","../src/server/routes/health.ts","../src/version.ts","../src/cli/ui.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport dotenv from \"dotenv\";\nimport { Command } from \"commander\";\nimport { intro, outro, select, multiselect, isCancel, cancel, note } from \"@clack/prompts\";\nimport {\n DEFAULT_CONFIG,\n applyEnvOverrides,\n ensureDirs,\n homeDir,\n loadConfig,\n paths,\n saveConfig,\n type EngineChoice,\n type WhisperApiConfig,\n} from \"../config\";\nimport {\n MODELS,\n downloadGgml,\n findModel,\n ggmlPath,\n isGgmlInstalled,\n resolveModel,\n type ModelInfo,\n} from \"../models/registry\";\nimport { countActiveKeys, createKey, listKeys, revokeKey } from \"../keys/store\";\nimport { createEngine } from \"../engine/detect\";\nimport { OnnxEngine } from \"../engine/onnx\";\nimport { buildWhisperCpp, locateWhisperBinary } from \"../engine/probe\";\nimport type { TranscriptionEngine } from \"../engine/types\";\nimport { startServer, type ServerContext } from \"../server/app\";\nimport { VERSION } from \"../version\";\nimport { modelProgress, pc, printAccessExample, printNewKey } from \"./ui\";\n\n// Load env from CWD and from the whisper-api home dir (quiet: no promo banners).\ndotenv.config({ quiet: true });\ndotenv.config({ path: path.join(homeDir(), \".env\"), quiet: true });\n\n/** Download (whisper.cpp GGML) or warm (ONNX weights) a model's assets. */\nasync function provision(engineChoice: EngineChoice, model: ModelInfo, label: string): Promise<void> {\n const ui = modelProgress(label.padEnd(16));\n try {\n if (engineChoice === \"onnx\") {\n await new OnnxEngine(model).ensureModel(ui.onProgress);\n } else {\n await downloadGgml(model, ui.onProgress);\n }\n } finally {\n ui.done();\n }\n}\n\nasync function runInit(): Promise<void> {\n ensureDirs();\n const existing = await loadConfig();\n intro(pc.bold(\" whisper-api setup \"));\n\n const engine = await select({\n message: \"Transcription engine\",\n initialValue: existing.engine,\n options: [\n { value: \"auto\", label: \"auto\", hint: \"whisper.cpp if available, else portable ONNX\" },\n { value: \"whispercpp\", label: \"whisper.cpp\", hint: \"fastest, GPU; needs build tools or a prebuilt binary\" },\n { value: \"onnx\", label: \"onnx\", hint: \"pure-JS, no compiler, runs anywhere\" },\n ],\n });\n if (isCancel(engine)) return cancel(\"Setup cancelled.\");\n\n const chosen = await multiselect({\n message: \"Models to download (space to toggle)\",\n required: true,\n initialValues: [existing.defaultModel],\n options: MODELS.map((m) => ({ value: m.name, label: `${m.name} ${pc.dim(`(${m.sizeMB} MB)`)}`, hint: m.description })),\n });\n if (isCancel(chosen)) return cancel(\"Setup cancelled.\");\n const selected = chosen as string[];\n\n let defaultModel = selected[0]!;\n if (selected.length > 1) {\n const d = await select({\n message: \"Default model (served for the `whisper-1` alias)\",\n initialValue: selected.includes(existing.defaultModel) ? existing.defaultModel : selected[0],\n options: selected.map((n) => ({ value: n, label: n })),\n });\n if (isCancel(d)) return cancel(\"Setup cancelled.\");\n defaultModel = d as string;\n }\n\n const config: WhisperApiConfig = { ...DEFAULT_CONFIG, ...existing, engine: engine as EngineChoice, defaultModel };\n await saveConfig(config);\n\n const { raw, record } = await createKey(\"default\");\n note(`${pc.cyan(raw)}\\n${pc.dim(`id ${record.id}`)}`, \"API key — copy now, shown once\");\n\n console.log();\n console.log(pc.bold(` Downloading ${selected.length} model(s) for ${engine === \"onnx\" ? \"ONNX\" : \"whisper.cpp\"}…`));\n for (const name of selected) {\n await provision(config.engine, findModel(name)!, name);\n }\n\n outro(pc.green(\"Setup complete.\"));\n console.log(` Config: ${paths.config()}`);\n console.log(` Start: ${pc.bold(\"whisper-api start\")}`);\n printAccessExample(`http://localhost:${config.port}`, raw);\n}\n\nasync function runStart(opts: {\n port?: string;\n host?: string;\n model?: string;\n engine?: string;\n apiKey?: string;\n}): Promise<void> {\n ensureDirs();\n const config = applyEnvOverrides(await loadConfig());\n if (opts.port) config.port = Number(opts.port);\n if (opts.host) config.host = opts.host;\n if (opts.engine) config.engine = opts.engine as EngineChoice;\n\n // Fixed personal token(s) from --api-key and/or WHISPER_API_KEY, accepted\n // alongside any keys created with `whisper-api key generate`.\n const staticApiKeys = [opts.apiKey, process.env.WHISPER_API_KEY]\n .map((k) => (k ?? \"\").trim())\n .filter((k) => k.length > 0);\n\n const model = resolveModel(opts.model || config.defaultModel, config.defaultModel);\n const allowBuild = config.engine === \"whispercpp\" || process.env.WHISPER_API_AUTOBUILD === \"1\";\n\n console.log(pc.dim(` Selecting engine (${config.engine})…`));\n const selection = await createEngine({\n engine: config.engine,\n model,\n allowBuild,\n onLog: (l) => console.log(pc.dim(\" \" + l)),\n });\n console.log(pc.dim(` ${selection.reason}`));\n\n const ui = modelProgress(`model ${model.name}`.padEnd(16));\n try {\n await selection.engine.ensureModel(ui.onProgress);\n } finally {\n ui.done();\n }\n\n const cache = new Map<string, TranscriptionEngine>([[model.name, selection.engine]]);\n const getEngine = async (name: string): Promise<TranscriptionEngine> => {\n const cached = cache.get(name);\n if (cached) return cached;\n const info = findModel(name) ?? model;\n const eng = selection.engine.forModel(info);\n cache.set(name, eng);\n return eng;\n };\n\n const ctx: ServerContext = {\n config,\n defaultEngine: selection.engine,\n engineLabel: selection.engine.describe(),\n version: VERSION,\n getEngine,\n staticApiKeys,\n };\n const { url } = await startServer(ctx);\n\n console.log();\n console.log(\n ` ${pc.green(\"▶\")} ${pc.bold(\"whisper-api\")} on ${pc.cyan(url)} ${pc.dim(\"·\")} engine ${pc.bold(\n selection.engine.describe(),\n )} ${pc.dim(\"·\")} model ${pc.bold(model.name)}`,\n );\n if (staticApiKeys.length) {\n console.log(` ${pc.green(\"✓\")} Accepting a fixed API key from ${pc.bold(\"--api-key / WHISPER_API_KEY\")}`);\n } else if ((await countActiveKeys()) === 0) {\n console.log(\n ` ${pc.yellow(\"!\")} No API keys yet — run ${pc.bold(\"whisper-api key generate\")} or start with ${pc.bold(\"--api-key <token>\")}`,\n );\n }\n // Show the example with the real personal token when one was supplied.\n printAccessExample(url, staticApiKeys[0]);\n}\n\nasync function runModelsList(): Promise<void> {\n const config = await loadConfig();\n console.log(pc.bold(\" Models \") + pc.dim(\"(✓ = GGML present locally)\"));\n for (const m of MODELS) {\n const mark = isGgmlInstalled(m) ? pc.green(\"✓\") : pc.dim(\"·\");\n const def = m.name === config.defaultModel ? pc.cyan(\" (default)\") : \"\";\n console.log(` ${mark} ${m.name.padEnd(16)} ${String(m.sizeMB).padStart(5)} MB ${pc.dim(m.description)}${def}`);\n }\n}\n\nasync function runModelsPull(name: string): Promise<void> {\n const model = findModel(name);\n if (!model) {\n console.error(pc.red(`Unknown model '${name}'. Run \\`whisper-api models list\\`.`));\n process.exitCode = 1;\n return;\n }\n const config = await loadConfig();\n await provision(config.engine, model, name);\n console.log(pc.green(` ✓ ${name} ready`));\n}\n\nasync function runModelsRm(name: string): Promise<void> {\n const model = findModel(name);\n if (!model) {\n console.error(pc.red(`Unknown model '${name}'.`));\n process.exitCode = 1;\n return;\n }\n const p = ggmlPath(model);\n if (fs.existsSync(p)) {\n fs.rmSync(p);\n console.log(pc.green(` ✓ removed ${model.ggmlFile}`));\n } else {\n console.log(pc.dim(` nothing to remove for ${name} (ONNX weights live under ${paths.cache()})`));\n }\n}\n\nasync function runKeyGenerate(opts: { name?: string }): Promise<void> {\n ensureDirs();\n const { raw, record } = await createKey(opts.name || \"default\");\n printNewKey(raw, record.name, record.id);\n const config = await loadConfig();\n printAccessExample(`http://localhost:${config.port}`, raw);\n}\n\nasync function runKeyList(): Promise<void> {\n const keys = await listKeys();\n if (!keys.length) {\n console.log(pc.dim(\" No keys yet. Create one: whisper-api key generate\"));\n return;\n }\n for (const k of keys) {\n const state = k.revoked ? pc.red(\"revoked\") : pc.green(\"active\");\n console.log(\n ` ${k.prefix}… ${state} ${pc.dim(k.id)} name=${k.name} created=${k.createdAt.slice(0, 10)} lastUsed=${\n k.lastUsedAt ? k.lastUsedAt.slice(0, 10) : \"never\"\n }`,\n );\n }\n}\n\nasync function runKeyRevoke(idOrPrefix: string): Promise<void> {\n const ok = await revokeKey(idOrPrefix);\n console.log(ok ? pc.green(` ✓ revoked ${idOrPrefix}`) : pc.yellow(` no active key matched ${idOrPrefix}`));\n}\n\nasync function runStatus(): Promise<void> {\n const config = applyEnvOverrides(await loadConfig());\n const installed = MODELS.filter(isGgmlInstalled).map((m) => m.name);\n const bin = locateWhisperBinary();\n console.log(pc.bold(\" whisper-api status\"));\n console.log(` home ${homeDir()}`);\n console.log(` engine ${config.engine}`);\n console.log(` default ${config.defaultModel}`);\n console.log(` listen ${config.host}:${config.port}`);\n console.log(` rate limit ${config.rateLimit.max} / ${config.rateLimit.timeWindow} per key`);\n console.log(` ggml models ${installed.length ? installed.join(\", \") : pc.dim(\"(none downloaded)\")}`);\n console.log(` api keys ${await countActiveKeys()} active`);\n console.log(` whisper.cpp ${bin ? pc.green(bin) : pc.dim(\"not built (run: whisper-api build-engine)\")}`);\n}\n\nasync function runBuildEngine(): Promise<void> {\n console.log(pc.bold(\" Building whisper.cpp from source…\"));\n try {\n const bin = await buildWhisperCpp((l) => console.log(pc.dim(\" \" + l)));\n console.log(pc.green(` ✓ built: ${bin}`));\n } catch (e) {\n console.error(pc.red(` build failed: ${(e as Error).message}`));\n process.exitCode = 1;\n }\n}\n\nfunction buildProgram(): Command {\n const program = new Command();\n program\n .name(\"whisper-api\")\n .description(\"Self-hostable, OpenAI-compatible Whisper speech-to-text API server.\")\n .version(VERSION, \"-v, --version\")\n .showHelpAfterError();\n\n program.command(\"init\").description(\"Interactive setup: choose engine, download models, create an API key\").action(runInit);\n\n program\n .command(\"start\")\n .description(\"Start the API server\")\n .option(\"-p, --port <port>\", \"port to listen on\")\n .option(\"--host <host>\", \"host to bind\")\n .option(\"-m, --model <name>\", \"default model (overrides config)\")\n .option(\"-e, --engine <engine>\", \"auto | whispercpp | onnx\")\n .option(\"-k, --api-key <token>\", \"fixed API key to accept (personal use); also via WHISPER_API_KEY\")\n .action(runStart);\n\n const models = program.command(\"models\").description(\"Manage local transcription models\");\n models.command(\"list\").description(\"List available and installed models\").action(runModelsList);\n models.command(\"pull <name>\").description(\"Download a model (e.g. base.en, large-v3)\").action(runModelsPull);\n models.command(\"rm <name>\").description(\"Remove a downloaded GGML model\").action(runModelsRm);\n\n const key = program.command(\"key\").description(\"Manage API access keys\");\n key.command(\"generate\").description(\"Generate a new API key\").option(\"-n, --name <name>\", \"label for the key\").action(runKeyGenerate);\n key.command(\"list\").description(\"List API keys\").action(runKeyList);\n key.command(\"revoke <idOrPrefix>\").description(\"Revoke a key by id or prefix\").action(runKeyRevoke);\n\n program.command(\"status\").description(\"Show configuration and local state\").action(runStatus);\n program.command(\"build-engine\").description(\"Build whisper.cpp from source for native speed\").action(runBuildEngine);\n\n return program;\n}\n\nconst program = buildProgram();\nif (process.argv.slice(2).length === 0) {\n program.outputHelp();\n process.exit(0);\n}\nprogram.parseAsync(process.argv).catch((err: Error) => {\n console.error(pc.red(err.message));\n process.exit(1);\n});\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport fs from \"node:fs\";\nimport fsp from \"node:fs/promises\";\n\nexport type EngineChoice = \"auto\" | \"whispercpp\" | \"onnx\";\n\nexport interface RateLimitConfig {\n /** Max requests per window, per API key. */\n max: number;\n /** Window, e.g. \"1 minute\" (parsed by @fastify/rate-limit). */\n timeWindow: string;\n}\n\nexport interface WhisperApiConfig {\n engine: EngineChoice;\n /** Friendly model name, e.g. \"base.en\". Also the default for the `whisper-1` alias. */\n defaultModel: string;\n host: string;\n port: number;\n /** Max upload size in bytes (OpenAI parity default: 25 MB). */\n maxUploadBytes: number;\n rateLimit: RateLimitConfig;\n}\n\nexport const DEFAULT_CONFIG: WhisperApiConfig = {\n engine: \"auto\",\n defaultModel: \"base.en\",\n host: \"0.0.0.0\",\n port: 8080,\n maxUploadBytes: 25 * 1024 * 1024,\n rateLimit: { max: 120, timeWindow: \"1 minute\" },\n};\n\n/** Root dir for config, keys, models and caches. Overridable for tests/containers. */\nexport function homeDir(): string {\n return process.env.WHISPER_API_HOME || path.join(os.homedir(), \".whisper-api\");\n}\n\nexport const paths = {\n home: homeDir,\n config: () => path.join(homeDir(), \"config.json\"),\n keys: () => path.join(homeDir(), \"keys.json\"),\n /** GGML model files for whisper.cpp. */\n models: () => path.join(homeDir(), \"models\"),\n /** transformers.js / ONNX model cache. */\n cache: () => path.join(homeDir(), \"cache\"),\n /** Built/downloaded whisper.cpp binaries. */\n bin: () => path.join(homeDir(), \"bin\"),\n /** Scratch space for uploads and converted audio. */\n tmp: () => path.join(homeDir(), \"tmp\"),\n};\n\nexport function ensureDirs(): void {\n for (const p of [homeDir(), paths.models(), paths.cache(), paths.bin(), paths.tmp()]) {\n fs.mkdirSync(p, { recursive: true });\n }\n}\n\nexport function configExists(): boolean {\n return fs.existsSync(paths.config());\n}\n\nexport async function loadConfig(): Promise<WhisperApiConfig> {\n try {\n const raw = await fsp.readFile(paths.config(), \"utf8\");\n const parsed = JSON.parse(raw) as Partial<WhisperApiConfig>;\n return {\n ...DEFAULT_CONFIG,\n ...parsed,\n rateLimit: { ...DEFAULT_CONFIG.rateLimit, ...(parsed.rateLimit ?? {}) },\n };\n } catch {\n return { ...DEFAULT_CONFIG };\n }\n}\n\nexport async function saveConfig(cfg: WhisperApiConfig): Promise<void> {\n ensureDirs();\n await fsp.writeFile(paths.config(), JSON.stringify(cfg, null, 2) + \"\\n\", \"utf8\");\n}\n\n/**\n * Apply environment-variable overrides on top of a loaded config.\n * Useful in containers/systemd where mutating config.json is awkward.\n */\nexport function applyEnvOverrides(cfg: WhisperApiConfig): WhisperApiConfig {\n const out = { ...cfg, rateLimit: { ...cfg.rateLimit } };\n if (process.env.WHISPER_API_PORT) out.port = Number(process.env.WHISPER_API_PORT);\n if (process.env.WHISPER_API_HOST) out.host = process.env.WHISPER_API_HOST;\n if (process.env.WHISPER_API_ENGINE) out.engine = process.env.WHISPER_API_ENGINE as EngineChoice;\n if (process.env.WHISPER_API_MODEL) out.defaultModel = process.env.WHISPER_API_MODEL;\n if (process.env.WHISPER_API_MAX_UPLOAD_MB) {\n out.maxUploadBytes = Number(process.env.WHISPER_API_MAX_UPLOAD_MB) * 1024 * 1024;\n }\n if (process.env.WHISPER_API_RATE_MAX) out.rateLimit.max = Number(process.env.WHISPER_API_RATE_MAX);\n return out;\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { paths } from \"../config\";\n\nexport interface ModelInfo {\n /** Friendly name, e.g. \"base.en\". */\n name: string;\n /** GGML filename used by whisper.cpp. */\n ggmlFile: string;\n /** transformers.js / ONNX model repo id. */\n onnxRepo: string;\n /** Approximate GGML download size in MB (for UX). */\n sizeMB: number;\n englishOnly: boolean;\n description: string;\n}\n\nconst HF_GGML_BASE = \"https://huggingface.co/ggerganov/whisper.cpp/resolve/main\";\n\nfunction ggml(name: string): string {\n return `ggml-${name}.bin`;\n}\n\n/** Supported models, smallest → largest. */\nexport const MODELS: ModelInfo[] = [\n { name: \"tiny.en\", ggmlFile: ggml(\"tiny.en\"), onnxRepo: \"Xenova/whisper-tiny.en\", sizeMB: 75, englishOnly: true, description: \"Fastest, English-only\" },\n { name: \"tiny\", ggmlFile: ggml(\"tiny\"), onnxRepo: \"Xenova/whisper-tiny\", sizeMB: 75, englishOnly: false, description: \"Fastest, multilingual\" },\n { name: \"base.en\", ggmlFile: ggml(\"base.en\"), onnxRepo: \"Xenova/whisper-base.en\", sizeMB: 142, englishOnly: true, description: \"Good speed/quality, English-only\" },\n { name: \"base\", ggmlFile: ggml(\"base\"), onnxRepo: \"Xenova/whisper-base\", sizeMB: 142, englishOnly: false, description: \"Good speed/quality, multilingual\" },\n { name: \"small.en\", ggmlFile: ggml(\"small.en\"), onnxRepo: \"Xenova/whisper-small.en\", sizeMB: 466, englishOnly: true, description: \"Higher quality, English-only\" },\n { name: \"small\", ggmlFile: ggml(\"small\"), onnxRepo: \"Xenova/whisper-small\", sizeMB: 466, englishOnly: false, description: \"Higher quality, multilingual\" },\n { name: \"medium.en\", ggmlFile: ggml(\"medium.en\"), onnxRepo: \"Xenova/whisper-medium.en\", sizeMB: 1500, englishOnly: true, description: \"High quality, English-only\" },\n { name: \"medium\", ggmlFile: ggml(\"medium\"), onnxRepo: \"Xenova/whisper-medium\", sizeMB: 1500, englishOnly: false, description: \"High quality, multilingual\" },\n { name: \"large-v3-turbo\", ggmlFile: ggml(\"large-v3-turbo\"), onnxRepo: \"onnx-community/whisper-large-v3-turbo\", sizeMB: 1600, englishOnly: false, description: \"Near large-v3 quality, much faster\" },\n { name: \"large-v3\", ggmlFile: ggml(\"large-v3\"), onnxRepo: \"onnx-community/whisper-large-v3\", sizeMB: 3100, englishOnly: false, description: \"Best quality, multilingual\" },\n];\n\n/** OpenAI clients commonly send model=\"whisper-1\"; alias it to the configured default. */\nexport const OPENAI_ALIASES = new Set([\"whisper-1\", \"whisper-large-v3\", \"gpt-4o-transcribe\", \"gpt-4o-mini-transcribe\"]);\n\nexport function isAlias(model: string): boolean {\n return OPENAI_ALIASES.has(model);\n}\n\nexport function findModel(name: string): ModelInfo | undefined {\n return MODELS.find((m) => m.name === name);\n}\n\n/**\n * Resolve a requested model id (possibly an OpenAI alias) to a known model,\n * falling back to the configured default.\n */\nexport function resolveModel(requested: string | undefined, defaultModel: string): ModelInfo {\n if (requested && !isAlias(requested)) {\n const found = findModel(requested);\n if (found) return found;\n }\n return findModel(defaultModel) ?? MODELS.find((m) => m.name === \"base.en\")!;\n}\n\nexport function ggmlPath(model: ModelInfo): string {\n return path.join(paths.models(), model.ggmlFile);\n}\n\nexport function ggmlUrl(model: ModelInfo): string {\n return `${HF_GGML_BASE}/${model.ggmlFile}`;\n}\n\nexport function isGgmlInstalled(model: ModelInfo): boolean {\n return fs.existsSync(ggmlPath(model));\n}\n\nexport type ProgressFn = (received: number, total: number) => void;\n\n/**\n * Stream a GGML model file from Hugging Face to the models dir, reporting\n * progress. Downloads to a .part file and renames on success (atomic-ish).\n */\nexport async function downloadGgml(model: ModelInfo, onProgress?: ProgressFn): Promise<string> {\n const dest = ggmlPath(model);\n if (fs.existsSync(dest)) return dest;\n fs.mkdirSync(paths.models(), { recursive: true });\n\n const url = ggmlUrl(model);\n const res = await fetch(url, { redirect: \"follow\" });\n if (!res.ok || !res.body) {\n throw new Error(`Failed to download ${model.name} (${res.status} ${res.statusText}) from ${url}`);\n }\n const total = Number(res.headers.get(\"content-length\") || 0);\n const tmp = dest + \".part\";\n const out = fs.createWriteStream(tmp);\n let received = 0;\n\n const reader = res.body.getReader();\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) {\n received += value.length;\n if (!out.write(value)) {\n await new Promise<void>((resolve) => out.once(\"drain\", resolve));\n }\n onProgress?.(received, total);\n }\n }\n } finally {\n out.end();\n await new Promise<void>((resolve, reject) => {\n out.on(\"finish\", () => resolve());\n out.on(\"error\", reject);\n });\n }\n fs.renameSync(tmp, dest);\n return dest;\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport { paths, ensureDirs } from \"../config\";\n\nexport const KEY_PREFIX = \"sk-wapi-\";\n\nexport interface KeyRecord {\n id: string;\n name: string;\n /** Human-recognizable leading slice of the raw key (safe to store/display). */\n prefix: string;\n /** SHA-256 hex of the raw key. The raw key itself is never stored. */\n hash: string;\n createdAt: string;\n lastUsedAt: string | null;\n revoked: boolean;\n}\n\nexport function generateRawKey(): string {\n return KEY_PREFIX + crypto.randomBytes(32).toString(\"base64url\");\n}\n\nexport function hashKey(raw: string): string {\n return crypto.createHash(\"sha256\").update(raw).digest(\"hex\");\n}\n\nfunction newId(): string {\n return \"key_\" + crypto.randomBytes(10).toString(\"hex\");\n}\n\nasync function load(): Promise<KeyRecord[]> {\n try {\n const raw = await fsp.readFile(paths.keys(), \"utf8\");\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? (parsed as KeyRecord[]) : [];\n } catch {\n return [];\n }\n}\n\nasync function persist(list: KeyRecord[]): Promise<void> {\n ensureDirs();\n // Restrictive perms — this file effectively holds the access list.\n await fsp.writeFile(paths.keys(), JSON.stringify(list, null, 2) + \"\\n\", { encoding: \"utf8\", mode: 0o600 });\n try {\n fs.chmodSync(paths.keys(), 0o600);\n } catch {\n /* best effort on platforms without POSIX perms */\n }\n}\n\n/** Create a new key. Returns the raw secret (shown once) plus its stored record. */\nexport async function createKey(name: string): Promise<{ raw: string; record: KeyRecord }> {\n const raw = generateRawKey();\n const record: KeyRecord = {\n id: newId(),\n name: name || \"default\",\n prefix: raw.slice(0, KEY_PREFIX.length + 6),\n hash: hashKey(raw),\n createdAt: new Date().toISOString(),\n lastUsedAt: null,\n revoked: false,\n };\n const list = await load();\n list.push(record);\n await persist(list);\n return { raw, record };\n}\n\nexport async function listKeys(): Promise<KeyRecord[]> {\n return load();\n}\n\nexport async function countActiveKeys(): Promise<number> {\n return (await load()).filter((k) => !k.revoked).length;\n}\n\n/** Revoke by id or prefix. Returns true if a matching active key was revoked. */\nexport async function revokeKey(idOrPrefix: string): Promise<boolean> {\n const list = await load();\n let changed = false;\n for (const rec of list) {\n if (!rec.revoked && (rec.id === idOrPrefix || rec.prefix === idOrPrefix)) {\n rec.revoked = true;\n changed = true;\n }\n }\n if (changed) await persist(list);\n return changed;\n}\n\n/**\n * Verify a raw bearer token against stored hashes using a constant-time compare.\n * Updates lastUsedAt on success. Returns the matching record or null.\n */\nexport async function verifyKey(raw: string): Promise<KeyRecord | null> {\n if (!raw || !raw.startsWith(KEY_PREFIX)) return null;\n const candidate = Buffer.from(hashKey(raw), \"hex\");\n const list = await load();\n let match: KeyRecord | null = null;\n for (const rec of list) {\n if (rec.revoked) continue;\n const stored = Buffer.from(rec.hash, \"hex\");\n if (stored.length === candidate.length && crypto.timingSafeEqual(stored, candidate)) {\n match = rec;\n break;\n }\n }\n if (match) {\n match.lastUsedAt = new Date().toISOString();\n await persist(list);\n }\n return match;\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport ffmpegStatic from \"ffmpeg-static\";\nimport { paths, ensureDirs } from \"./config\";\n\nconst SAMPLE_RATE = 16000;\n\nfunction ffmpegBin(): string {\n // ffmpeg-static exports the bundled binary path; allow override.\n return process.env.FFMPEG_PATH || (ffmpegStatic as unknown as string) || \"ffmpeg\";\n}\n\nfunction run(args: string[]): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const proc = spawn(ffmpegBin(), args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n const out: Buffer[] = [];\n const err: Buffer[] = [];\n proc.stdout.on(\"data\", (d: Buffer) => out.push(d));\n proc.stderr.on(\"data\", (d: Buffer) => err.push(d));\n proc.on(\"error\", reject);\n proc.on(\"close\", (code) => {\n if (code === 0) resolve(Buffer.concat(out));\n else reject(new Error(`ffmpeg exited with code ${code}: ${Buffer.concat(err).toString(\"utf8\").slice(-800)}`));\n });\n });\n}\n\n/** Convert any input audio/video into a 16 kHz mono 16-bit WAV file (for whisper.cpp). */\nexport async function toWav16k(inputPath: string): Promise<string> {\n ensureDirs();\n const outPath = path.join(paths.tmp(), `wav-${crypto.randomBytes(8).toString(\"hex\")}.wav`);\n await run([\"-nostdin\", \"-i\", inputPath, \"-ar\", String(SAMPLE_RATE), \"-ac\", \"1\", \"-c:a\", \"pcm_s16le\", \"-f\", \"wav\", outPath, \"-y\"]);\n return outPath;\n}\n\nexport interface DecodedAudio {\n samples: Float32Array;\n sampleRate: number;\n duration: number;\n}\n\n/** Decode any input into mono 16 kHz Float32 PCM samples (for the ONNX engine). */\nexport async function toFloat32(inputPath: string): Promise<DecodedAudio> {\n const raw = await run([\"-nostdin\", \"-i\", inputPath, \"-ar\", String(SAMPLE_RATE), \"-ac\", \"1\", \"-f\", \"f32le\", \"-\"]);\n // Copy into a correctly-aligned buffer before viewing as Float32.\n const aligned = new Uint8Array(raw.byteLength);\n aligned.set(raw);\n const samples = new Float32Array(aligned.buffer, 0, Math.floor(aligned.byteLength / 4));\n return { samples, sampleRate: SAMPLE_RATE, duration: samples.length / SAMPLE_RATE };\n}\n\nexport function cleanup(file: string | undefined): void {\n if (!file) return;\n try {\n fs.rmSync(file, { force: true });\n } catch {\n /* ignore */\n }\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport { toFloat32 } from \"../audio\";\nimport { paths } from \"../config\";\nimport type { ModelInfo, ProgressFn } from \"../models/registry\";\nimport type { Segment, TranscribeOptions, TranscriptionEngine, TranscriptionResult } from \"./types\";\n\n// transformers.js is heavy; import lazily so unrelated CLI commands stay fast.\ntype Pipeline = (input: Float32Array, opts: Record<string, unknown>) => Promise<OnnxOutput>;\ninterface OnnxChunk {\n timestamp: [number, number | null];\n text: string;\n}\ninterface OnnxOutput {\n text: string;\n chunks?: OnnxChunk[];\n}\n\nconst ISO_TO_NAME: Record<string, string> = {\n en: \"english\", es: \"spanish\", fr: \"french\", de: \"german\", it: \"italian\",\n pt: \"portuguese\", nl: \"dutch\", ru: \"russian\", zh: \"chinese\", ja: \"japanese\",\n ko: \"korean\", ar: \"arabic\", hi: \"hindi\", tr: \"turkish\", pl: \"polish\",\n uk: \"ukrainian\", sv: \"swedish\", cs: \"czech\", da: \"danish\", fi: \"finnish\",\n};\n\n/** Pure-JS engine via @huggingface/transformers (onnxruntime-node). No compiler needed. */\nexport class OnnxEngine implements TranscriptionEngine {\n readonly kind = \"onnx\" as const;\n readonly model: ModelInfo;\n private device: string;\n private pipe: Pipeline | null = null;\n\n constructor(model: ModelInfo) {\n this.model = model;\n this.device = process.env.WHISPER_API_ONNX_DEVICE || \"cpu\";\n }\n\n describe(): string {\n return `onnx (${this.device})`;\n }\n\n forModel(model: ModelInfo): TranscriptionEngine {\n return new OnnxEngine(model);\n }\n\n private async getPipe(onProgress?: ProgressFn): Promise<Pipeline> {\n if (this.pipe) return this.pipe;\n const { pipeline, env } = await import(\"@huggingface/transformers\");\n env.cacheDir = paths.cache();\n env.allowLocalModels = true;\n\n const dtype = process.env.WHISPER_API_ONNX_DTYPE || (this.model.sizeMB > 1000 ? \"q8\" : \"fp32\");\n const pipe = (await pipeline(\"automatic-speech-recognition\", this.model.onnxRepo, {\n device: this.device as never,\n dtype: dtype as never,\n progress_callback: onProgress\n ? (p: { status?: string; loaded?: number; total?: number }) => {\n if (p.status === \"progress\" && typeof p.loaded === \"number\" && typeof p.total === \"number\") {\n onProgress(p.loaded, p.total);\n }\n }\n : undefined,\n })) as unknown as Pipeline;\n this.pipe = pipe;\n return pipe;\n }\n\n async ensureModel(onProgress?: ProgressFn): Promise<void> {\n // Instantiating the pipeline downloads & caches the ONNX weights.\n await this.getPipe(onProgress);\n }\n\n async transcribe(inputPath: string, opts: TranscribeOptions): Promise<TranscriptionResult> {\n const pipe = await this.getPipe();\n const { samples, duration } = await toFloat32(inputPath);\n\n const runOpts: Record<string, unknown> = {\n return_timestamps: true,\n chunk_length_s: 30,\n stride_length_s: 5,\n };\n if (!this.model.englishOnly) {\n runOpts[\"task\"] = opts.translate ? \"translate\" : \"transcribe\";\n if (opts.language) runOpts[\"language\"] = ISO_TO_NAME[opts.language] ?? opts.language;\n }\n if (typeof opts.temperature === \"number\") runOpts[\"temperature\"] = opts.temperature;\n\n const out = await pipe(samples, runOpts);\n const segments: Segment[] = (out.chunks ?? []).map((c, i) => ({\n id: i,\n start: c.timestamp[0] ?? 0,\n end: c.timestamp[1] ?? duration,\n text: c.text.trim(),\n }));\n\n return {\n text: (out.text ?? \"\").trim(),\n language: opts.language,\n duration,\n segments,\n };\n }\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport { paths } from \"../config\";\nimport { toWav16k, cleanup } from \"../audio\";\nimport { downloadGgml, ggmlPath, type ModelInfo, type ProgressFn } from \"../models/registry\";\nimport type { Gpu } from \"./probe\";\nimport type { Segment, TranscribeOptions, TranscriptionEngine, TranscriptionResult } from \"./types\";\n\ninterface WhisperCppJson {\n result?: { language?: string };\n params?: { language?: string };\n transcription?: Array<{\n timestamps?: { from?: string; to?: string };\n offsets?: { from?: number; to?: number }; // milliseconds\n text?: string;\n }>;\n}\n\n/** Engine backed by a native whisper.cpp `whisper-cli` binary (CPU + CUDA/Metal). */\nexport class WhisperCppEngine implements TranscriptionEngine {\n readonly kind = \"whispercpp\" as const;\n readonly model: ModelInfo;\n private bin: string;\n private gpu: Gpu;\n\n constructor(model: ModelInfo, bin: string, gpu: Gpu) {\n this.model = model;\n this.bin = bin;\n this.gpu = gpu;\n }\n\n describe(): string {\n return `whisper.cpp (${this.gpu ?? \"cpu\"})`;\n }\n\n forModel(model: ModelInfo): TranscriptionEngine {\n return new WhisperCppEngine(model, this.bin, this.gpu);\n }\n\n async ensureModel(onProgress?: ProgressFn): Promise<void> {\n await downloadGgml(this.model, onProgress);\n }\n\n async transcribe(inputPath: string, opts: TranscribeOptions): Promise<TranscriptionResult> {\n await this.ensureModel();\n const wav = await toWav16k(inputPath);\n const outPrefix = path.join(paths.tmp(), `wcpp-${crypto.randomBytes(8).toString(\"hex\")}`);\n const jsonPath = outPrefix + \".json\";\n\n const args = [\n \"-m\", ggmlPath(this.model),\n \"-f\", wav,\n \"-oj\",\n \"-of\", outPrefix,\n \"-np\",\n \"-t\", String(Math.max(1, os.cpus().length)),\n ];\n if (this.model.englishOnly) {\n args.push(\"-l\", \"en\");\n } else {\n args.push(\"-l\", opts.language ?? \"auto\");\n }\n if (opts.translate) args.push(\"--translate\");\n if (typeof opts.temperature === \"number\") args.push(\"-tp\", String(opts.temperature));\n if (opts.prompt) args.push(\"--prompt\", opts.prompt);\n\n try {\n await this.run(args);\n const raw = await fsp.readFile(jsonPath, \"utf8\");\n return this.parse(JSON.parse(raw) as WhisperCppJson, opts);\n } finally {\n cleanup(wav);\n cleanup(jsonPath);\n }\n }\n\n private run(args: string[]): Promise<void> {\n return new Promise((resolve, reject) => {\n const proc = spawn(this.bin, args, { stdio: [\"ignore\", \"ignore\", \"pipe\"] });\n const err: Buffer[] = [];\n proc.stderr.on(\"data\", (d: Buffer) => err.push(d));\n proc.on(\"error\", reject);\n proc.on(\"close\", (code) =>\n code === 0\n ? resolve()\n : reject(new Error(`whisper-cli exited with code ${code}: ${Buffer.concat(err).toString(\"utf8\").slice(-800)}`)),\n );\n });\n }\n\n private parse(data: WhisperCppJson, opts: TranscribeOptions): TranscriptionResult {\n const items = data.transcription ?? [];\n const segments: Segment[] = items.map((it, i) => ({\n id: i,\n start: (it.offsets?.from ?? 0) / 1000,\n end: (it.offsets?.to ?? 0) / 1000,\n text: (it.text ?? \"\").trim(),\n }));\n const last = items[items.length - 1];\n return {\n text: items.map((it) => it.text ?? \"\").join(\"\").trim(),\n language: data.result?.language ?? data.params?.language ?? opts.language,\n duration: last?.offsets?.to ? last.offsets.to / 1000 : undefined,\n segments,\n };\n }\n}\n\n/** True if a GGML file for this model is already on disk. */\nexport function ggmlInstalled(model: ModelInfo): boolean {\n return fs.existsSync(ggmlPath(model));\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport { spawn, spawnSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { paths, ensureDirs } from \"../config\";\n\nexport type Gpu = \"cuda\" | \"metal\" | null;\n\nconst WHISPER_CPP_REPO = \"https://github.com/ggml-org/whisper.cpp\";\n\n/** Is an executable resolvable on PATH? */\nexport function which(cmd: string): boolean {\n const finder = process.platform === \"win32\" ? \"where\" : \"which\";\n const r = spawnSync(finder, [cmd], { stdio: \"ignore\" });\n return r.status === 0;\n}\n\nexport function hasBuildTools(): boolean {\n const compiler = which(\"cc\") || which(\"clang\") || which(\"gcc\") || which(\"c++\");\n return which(\"git\") && which(\"cmake\") && compiler;\n}\n\nexport function detectGpu(): Gpu {\n if (which(\"nvidia-smi\")) return \"cuda\";\n if (process.platform === \"darwin\" && os.arch() === \"arm64\") return \"metal\";\n return null;\n}\n\nfunction binCandidates(): string[] {\n const exe = process.platform === \"win32\" ? \".exe\" : \"\";\n const names = [`whisper-cli${exe}`, `main${exe}`];\n const out: string[] = [];\n if (process.env.WHISPER_CPP_BIN) out.push(process.env.WHISPER_CPP_BIN);\n for (const n of names) out.push(path.join(paths.bin(), n));\n return out;\n}\n\n/** Locate a usable whisper.cpp binary: env → cached build → PATH. */\nexport function locateWhisperBinary(): string | null {\n for (const c of binCandidates()) {\n if (fs.existsSync(c)) return c;\n }\n if (which(\"whisper-cli\")) return \"whisper-cli\";\n return null;\n}\n\ntype LogFn = (line: string) => void;\n\nfunction step(cmd: string, args: string[], cwd: string, onLog?: LogFn): Promise<void> {\n return new Promise((resolve, reject) => {\n onLog?.(`$ ${cmd} ${args.join(\" \")}`);\n const proc = spawn(cmd, args, { cwd, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n const relay = (d: Buffer) => onLog?.(d.toString(\"utf8\").trimEnd());\n proc.stdout.on(\"data\", relay);\n proc.stderr.on(\"data\", relay);\n proc.on(\"error\", reject);\n proc.on(\"close\", (code) =>\n code === 0 ? resolve() : reject(new Error(`${cmd} exited with code ${code}`)),\n );\n });\n}\n\n/**\n * Clone and build whisper.cpp, then install the `whisper-cli` binary into the\n * whisper-api bin dir. Best-effort: throws if the toolchain is missing or the\n * build fails, so callers can fall back to the ONNX engine.\n */\nexport async function buildWhisperCpp(onLog?: LogFn): Promise<string> {\n if (!hasBuildTools()) {\n throw new Error(\"Build tools missing (need git, cmake and a C/C++ compiler).\");\n }\n ensureDirs();\n const srcDir = path.join(paths.cache(), \"whisper.cpp-src\");\n const buildDir = path.join(srcDir, \"build\");\n const gpu = detectGpu();\n\n if (!fs.existsSync(path.join(srcDir, \"CMakeLists.txt\"))) {\n fs.rmSync(srcDir, { recursive: true, force: true });\n await step(\"git\", [\"clone\", \"--depth\", \"1\", WHISPER_CPP_REPO, srcDir], paths.cache(), onLog);\n }\n\n const cmakeArgs = [\n \"-S\", srcDir,\n \"-B\", buildDir,\n \"-DCMAKE_BUILD_TYPE=Release\",\n \"-DWHISPER_BUILD_TESTS=OFF\",\n \"-DWHISPER_BUILD_SERVER=OFF\",\n \"-DWHISPER_BUILD_EXAMPLES=ON\",\n ];\n if (gpu === \"cuda\") cmakeArgs.push(\"-DGGML_CUDA=ON\");\n // Metal is enabled by default on Apple Silicon with shaders embedded in the binary.\n\n await step(\"cmake\", cmakeArgs, srcDir, onLog);\n await step(\"cmake\", [\"--build\", buildDir, \"-j\", String(Math.max(1, os.cpus().length)), \"--config\", \"Release\"], srcDir, onLog);\n\n const exe = process.platform === \"win32\" ? \".exe\" : \"\";\n const built = [\n path.join(buildDir, \"bin\", `whisper-cli${exe}`),\n path.join(buildDir, \"bin\", \"Release\", `whisper-cli${exe}`),\n ].find((p) => fs.existsSync(p));\n if (!built) throw new Error(\"Build finished but whisper-cli binary was not found.\");\n\n const dest = path.join(paths.bin(), `whisper-cli${exe}`);\n fs.copyFileSync(built, dest);\n fs.chmodSync(dest, 0o755);\n onLog?.(`Installed whisper.cpp → ${dest}`);\n return dest;\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport type { EngineChoice } from \"../config\";\nimport type { ModelInfo } from \"../models/registry\";\nimport { OnnxEngine } from \"./onnx\";\nimport { WhisperCppEngine } from \"./whispercpp\";\nimport { buildWhisperCpp, detectGpu, hasBuildTools, locateWhisperBinary } from \"./probe\";\nimport type { TranscriptionEngine } from \"./types\";\n\nexport interface EngineSelection {\n engine: TranscriptionEngine;\n reason: string;\n}\n\nexport interface CreateEngineOpts {\n engine: EngineChoice;\n model: ModelInfo;\n /** Permit building whisper.cpp from source if no binary is found. */\n allowBuild?: boolean;\n onLog?: (line: string) => void;\n}\n\n/**\n * Resolve which transcription engine to use.\n *\n * - `onnx` → always the portable ONNX engine.\n * - `whispercpp` → require/obtain a native binary (build if allowed), else error.\n * - `auto` → prefer an existing whisper.cpp binary; optionally build one;\n * otherwise fall back to the portable ONNX engine.\n */\nexport async function createEngine(opts: CreateEngineOpts): Promise<EngineSelection> {\n const { engine, model, model: m } = opts;\n const allowBuild = opts.allowBuild ?? process.env.WHISPER_API_AUTOBUILD === \"1\";\n\n if (engine === \"onnx\") {\n return { engine: new OnnxEngine(m), reason: \"engine=onnx (portable, no compiler)\" };\n }\n\n if (engine === \"whispercpp\") {\n const bin = locateWhisperBinary() ?? (await tryBuild(opts.onLog));\n if (!bin) {\n throw new Error(\n \"engine=whispercpp requested but no binary is available and it could not be built. \" +\n \"Install build tools (git, cmake, a C/C++ compiler) and run `whisper-api build-engine`, \" +\n \"set WHISPER_CPP_BIN, or use --engine onnx.\",\n );\n }\n return { engine: new WhisperCppEngine(model, bin, detectGpu()), reason: \"engine=whispercpp\" };\n }\n\n // auto\n const existing = locateWhisperBinary();\n if (existing) {\n return { engine: new WhisperCppEngine(model, existing, detectGpu()), reason: \"auto → whisper.cpp (binary found)\" };\n }\n if (allowBuild && hasBuildTools()) {\n const built = await tryBuild(opts.onLog);\n if (built) {\n return { engine: new WhisperCppEngine(model, built, detectGpu()), reason: \"auto → whisper.cpp (built from source)\" };\n }\n }\n return {\n engine: new OnnxEngine(m),\n reason: hasBuildTools()\n ? \"auto → onnx (no whisper.cpp binary; run `whisper-api build-engine` for native speed)\"\n : \"auto → onnx (no whisper.cpp binary and no build toolchain)\",\n };\n}\n\nasync function tryBuild(onLog?: (l: string) => void): Promise<string | null> {\n try {\n return await buildWhisperCpp(onLog);\n } catch (err) {\n onLog?.(`whisper.cpp build failed: ${(err as Error).message}`);\n return null;\n }\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport { fileURLToPath } from \"node:url\";\nimport fs from \"node:fs\";\nimport Fastify, { type FastifyError, type FastifyInstance } from \"fastify\";\nimport multipart from \"@fastify/multipart\";\nimport rateLimit from \"@fastify/rate-limit\";\nimport fastifyStatic from \"@fastify/static\";\nimport type { WhisperApiConfig } from \"../config\";\nimport type { ModelInfo } from \"../models/registry\";\nimport type { TranscriptionEngine } from \"../engine/types\";\nimport { makeAuthHook, extractBearer } from \"./auth\";\nimport { errorBody } from \"./formats\";\nimport { registerTranscriptions } from \"./routes/transcriptions\";\nimport { registerModels } from \"./routes/models\";\nimport { registerHealth } from \"./routes/health\";\n\nexport interface ServerContext {\n config: WhisperApiConfig;\n /** Engine for the configured default model. */\n defaultEngine: TranscriptionEngine;\n /** Human label, e.g. \"whisper.cpp (metal)\". */\n engineLabel: string;\n version: string;\n /** Resolve (and cache) an engine for a specific model name. */\n getEngine(modelName: string): Promise<TranscriptionEngine>;\n /** Fixed tokens accepted in addition to generated keys (personal/simple setups). */\n staticApiKeys: string[];\n}\n\nfunction findWebDir(): string | null {\n for (const rel of [\"../web\", \"../../web\", \"../../../web\"]) {\n const dir = fileURLToPath(new URL(rel, import.meta.url));\n if (fs.existsSync(dir)) return dir;\n }\n return null;\n}\n\nexport async function buildServer(ctx: ServerContext): Promise<FastifyInstance> {\n const app = Fastify({\n logger: process.env.WHISPER_API_LOG === \"silent\" ? false : { level: process.env.WHISPER_API_LOG || \"info\" },\n bodyLimit: ctx.config.maxUploadBytes + 1024 * 1024,\n });\n\n await app.register(multipart, {\n limits: { fileSize: ctx.config.maxUploadBytes, files: 1, fields: 25 },\n });\n\n await app.register(rateLimit, {\n global: false,\n keyGenerator: (req) => extractBearer(req.headers.authorization) ?? req.ip,\n errorResponseBuilder: () =>\n errorBody(\"Rate limit exceeded. Slow down or request a higher limit.\", \"rate_limit_error\", \"rate_limit_exceeded\"),\n });\n\n app.addHook(\"onRequest\", makeAuthHook({ staticApiKeys: ctx.staticApiKeys }));\n\n app.setErrorHandler((err: FastifyError, req, reply) => {\n const status = (err.statusCode && err.statusCode >= 400 ? err.statusCode : 500) as number;\n req.log.error({ err }, \"request error\");\n reply.code(status).send(errorBody(err.message || \"Internal server error.\", status >= 500 ? \"server_error\" : \"invalid_request_error\"));\n });\n\n // Routes\n registerHealth(app, ctx);\n registerModels(app, ctx);\n registerTranscriptions(app, ctx);\n\n // Static web status page (served at \"/\").\n const webDir = findWebDir();\n if (webDir) {\n await app.register(fastifyStatic, { root: webDir, prefix: \"/\", index: [\"index.html\"] });\n } else {\n app.get(\"/\", async () => ({ name: \"whisper-api\", status: \"ok\", docs: \"/health\" }));\n }\n\n return app;\n}\n\nexport async function startServer(ctx: ServerContext): Promise<{ app: FastifyInstance; url: string }> {\n const app = await buildServer(ctx);\n await app.listen({ host: ctx.config.host, port: ctx.config.port });\n const shown = ctx.config.host === \"0.0.0.0\" ? \"localhost\" : ctx.config.host;\n return { app, url: `http://${shown}:${ctx.config.port}` };\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport crypto from \"node:crypto\";\nimport type { FastifyReply, FastifyRequest } from \"fastify\";\nimport { verifyKey, type KeyRecord } from \"../keys/store\";\nimport { errorBody } from \"./formats\";\n\ndeclare module \"fastify\" {\n interface FastifyRequest {\n apiKey?: KeyRecord;\n }\n}\n\n/** Paths that never require authentication. */\nconst PUBLIC_PATHS = new Set([\"/health\", \"/\", \"/favicon.ico\"]);\n\nfunction isPublic(url: string): boolean {\n const pathname = url.split(\"?\")[0] ?? url;\n return PUBLIC_PATHS.has(pathname) || (!pathname.startsWith(\"/v1/\") && !pathname.startsWith(\"/v1\"));\n}\n\nexport function extractBearer(header: string | undefined): string | null {\n if (!header) return null;\n const m = /^Bearer\\s+(.+)$/i.exec(header.trim());\n return m ? m[1]!.trim() : null;\n}\n\n/** Constant-time check of a token against a set of static keys (compares hashes). */\nfunction matchesStatic(token: string, staticKeys: string[]): boolean {\n const t = crypto.createHash(\"sha256\").update(token).digest();\n for (const k of staticKeys) {\n if (!k) continue;\n const h = crypto.createHash(\"sha256\").update(k).digest();\n if (h.length === t.length && crypto.timingSafeEqual(h, t)) return true;\n }\n return false;\n}\n\nexport interface AuthContext {\n /** Fixed tokens accepted in addition to generated keys (personal/simple setups). */\n staticApiKeys: string[];\n}\n\n/**\n * Build a Fastify onRequest hook enforcing bearer-token auth on /v1/* routes.\n * Accepts either a configured static key (env/flag) or a generated keystore key.\n */\nexport function makeAuthHook(ctx: AuthContext) {\n return async function authHook(req: FastifyRequest, reply: FastifyReply): Promise<void> {\n if (isPublic(req.url)) return;\n\n const token = extractBearer(req.headers.authorization);\n if (!token) {\n await reply\n .code(401)\n .send(errorBody(\"Missing bearer token. Pass `Authorization: Bearer <key>`.\", \"invalid_request_error\", \"missing_api_key\"));\n return;\n }\n\n if (ctx.staticApiKeys.length && matchesStatic(token, ctx.staticApiKeys)) {\n req.apiKey = {\n id: \"static\",\n name: \"static\",\n prefix: token.slice(0, 8),\n hash: \"\",\n createdAt: \"\",\n lastUsedAt: null,\n revoked: false,\n };\n return;\n }\n\n const record = await verifyKey(token);\n if (!record) {\n await reply.code(401).send(errorBody(\"Invalid or revoked API key.\", \"invalid_request_error\", \"invalid_api_key\"));\n return;\n }\n req.apiKey = record;\n };\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport type { TranscriptionResult } from \"../engine/types\";\n\nexport type ResponseFormat = \"json\" | \"verbose_json\" | \"text\" | \"srt\" | \"vtt\";\n\nexport const RESPONSE_FORMATS: ResponseFormat[] = [\"json\", \"verbose_json\", \"text\", \"srt\", \"vtt\"];\n\nexport function isResponseFormat(v: string): v is ResponseFormat {\n return (RESPONSE_FORMATS as string[]).includes(v);\n}\n\nfunction pad(n: number, width: number): string {\n return Math.floor(n).toString().padStart(width, \"0\");\n}\n\n/** Seconds → \"HH:MM:SS,mmm\" (SRT) or \"HH:MM:SS.mmm\" (VTT). */\nfunction timestamp(seconds: number, sep: \",\" | \".\"): string {\n const ms = Math.round((seconds - Math.floor(seconds)) * 1000);\n const s = Math.floor(seconds) % 60;\n const m = Math.floor(seconds / 60) % 60;\n const h = Math.floor(seconds / 3600);\n return `${pad(h, 2)}:${pad(m, 2)}:${pad(s, 2)}${sep}${pad(ms, 3)}`;\n}\n\nfunction toSrt(r: TranscriptionResult): string {\n return (\n r.segments\n .map((seg, i) => `${i + 1}\\n${timestamp(seg.start, \",\")} --> ${timestamp(seg.end, \",\")}\\n${seg.text}\\n`)\n .join(\"\\n\") + \"\\n\"\n );\n}\n\nfunction toVtt(r: TranscriptionResult): string {\n const cues = r.segments\n .map((seg) => `${timestamp(seg.start, \".\")} --> ${timestamp(seg.end, \".\")}\\n${seg.text}`)\n .join(\"\\n\\n\");\n return `WEBVTT\\n\\n${cues}\\n`;\n}\n\nexport interface SerializedResponse {\n contentType: string;\n body: string;\n}\n\n/** Render a transcription result in the requested OpenAI-compatible format. */\nexport function serialize(result: TranscriptionResult, format: ResponseFormat): SerializedResponse {\n switch (format) {\n case \"text\":\n return { contentType: \"text/plain; charset=utf-8\", body: result.text + \"\\n\" };\n case \"srt\":\n return { contentType: \"text/plain; charset=utf-8\", body: toSrt(result) };\n case \"vtt\":\n return { contentType: \"text/vtt; charset=utf-8\", body: toVtt(result) };\n case \"verbose_json\":\n return {\n contentType: \"application/json; charset=utf-8\",\n body: JSON.stringify({\n task: \"transcribe\",\n language: result.language ?? \"unknown\",\n duration: result.duration ?? 0,\n text: result.text,\n segments: result.segments.map((seg) => ({\n id: seg.id,\n seek: 0,\n start: seg.start,\n end: seg.end,\n text: seg.text,\n tokens: [],\n temperature: 0,\n avg_logprob: 0,\n compression_ratio: 0,\n no_speech_prob: 0,\n })),\n }),\n };\n case \"json\":\n default:\n return { contentType: \"application/json; charset=utf-8\", body: JSON.stringify({ text: result.text }) };\n }\n}\n\n/** OpenAI-shaped error body. */\nexport function errorBody(message: string, type = \"invalid_request_error\", code: string | null = null) {\n return { error: { message, type, param: null, code } };\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport { pipeline } from \"node:stream/promises\";\nimport type { FastifyInstance } from \"fastify\";\nimport { paths, ensureDirs } from \"../../config\";\nimport { cleanup } from \"../../audio\";\nimport { resolveModel } from \"../../models/registry\";\nimport { errorBody, isResponseFormat, serialize, type ResponseFormat } from \"../formats\";\nimport type { ServerContext } from \"../app\";\n\ninterface ParsedRequest {\n filePath?: string;\n filename?: string;\n fields: Record<string, string>;\n}\n\nasync function parseMultipart(req: import(\"fastify\").FastifyRequest): Promise<ParsedRequest> {\n ensureDirs();\n const result: ParsedRequest = { fields: {} };\n for await (const part of req.parts()) {\n if (part.type === \"file\") {\n if (part.fieldname === \"file\") {\n const ext = path.extname(part.filename || \"\") || \".bin\";\n const dest = path.join(paths.tmp(), `up-${crypto.randomBytes(8).toString(\"hex\")}${ext}`);\n await pipeline(part.file, fs.createWriteStream(dest));\n result.filePath = dest;\n result.filename = part.filename;\n if (part.file.truncated) {\n cleanup(dest);\n throw Object.assign(new Error(\"Uploaded file exceeds the configured size limit.\"), { statusCode: 413 });\n }\n } else {\n part.file.resume(); // drain unexpected file fields\n }\n } else {\n result.fields[part.fieldname] = String(part.value);\n }\n }\n return result;\n}\n\nexport function registerTranscriptions(app: FastifyInstance, ctx: ServerContext): void {\n const handler = (translate: boolean) => async (req: import(\"fastify\").FastifyRequest, reply: import(\"fastify\").FastifyReply) => {\n let parsed: ParsedRequest | undefined;\n try {\n parsed = await parseMultipart(req);\n if (!parsed.filePath) {\n return reply.code(400).send(errorBody(\"Missing required `file` field.\", \"invalid_request_error\", \"missing_file\"));\n }\n\n const fmtRaw = parsed.fields[\"response_format\"] || \"json\";\n if (!isResponseFormat(fmtRaw)) {\n return reply.code(400).send(errorBody(`Unsupported response_format '${fmtRaw}'.`, \"invalid_request_error\"));\n }\n const format = fmtRaw as ResponseFormat;\n\n const model = resolveModel(parsed.fields[\"model\"], ctx.config.defaultModel);\n const temperature = parsed.fields[\"temperature\"] !== undefined ? Number(parsed.fields[\"temperature\"]) : undefined;\n const task = parsed.fields[\"task\"];\n\n const engine = await ctx.getEngine(model.name);\n const result = await engine.transcribe(parsed.filePath, {\n language: parsed.fields[\"language\"] || undefined,\n translate: translate || task === \"translate\",\n temperature: typeof temperature === \"number\" && !Number.isNaN(temperature) ? temperature : undefined,\n prompt: parsed.fields[\"prompt\"] || undefined,\n });\n\n const { contentType, body } = serialize(result, format);\n return reply.header(\"content-type\", contentType).send(body);\n } catch (err) {\n const e = err as Error & { statusCode?: number };\n const status = e.statusCode ?? 500;\n req.log.error({ err: e }, \"transcription failed\");\n return reply\n .code(status)\n .send(errorBody(e.message || \"Transcription failed.\", status === 413 ? \"invalid_request_error\" : \"server_error\"));\n } finally {\n cleanup(parsed?.filePath);\n }\n };\n\n const routeOpts = {\n config: { rateLimit: { max: ctx.config.rateLimit.max, timeWindow: ctx.config.rateLimit.timeWindow } },\n };\n app.post(\"/v1/audio/transcriptions\", routeOpts, handler(false));\n app.post(\"/v1/audio/translations\", routeOpts, handler(true));\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport type { FastifyInstance } from \"fastify\";\nimport { MODELS } from \"../../models/registry\";\nimport type { ServerContext } from \"../app\";\n\n/** OpenAI-compatible model listing. Advertises `whisper-1` plus all known models. */\nexport function registerModels(app: FastifyInstance, ctx: ServerContext): void {\n const created = 1700000000; // stable placeholder timestamp\n const entry = (id: string) => ({ id, object: \"model\", created, owned_by: \"whisper-api\" });\n\n app.get(\"/v1/models\", async () => ({\n object: \"list\",\n data: [entry(\"whisper-1\"), ...MODELS.map((m) => entry(m.name))],\n }));\n\n app.get(\"/v1/models/:id\", async (req, reply) => {\n const id = (req.params as { id: string }).id;\n if (id === \"whisper-1\" || MODELS.some((m) => m.name === id)) {\n return entry(id);\n }\n return reply.code(404).send({ error: { message: `Model '${id}' not found.`, type: \"invalid_request_error\" } });\n });\n\n // Expose which model is actively loaded (handy for `status`).\n app.get(\"/v1/models/active\", async () => entry(ctx.defaultEngine.model.name));\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport type { FastifyInstance } from \"fastify\";\nimport { countActiveKeys } from \"../../keys/store\";\nimport type { ServerContext } from \"../app\";\n\n/** Unauthenticated liveness/readiness endpoint. */\nexport function registerHealth(app: FastifyInstance, ctx: ServerContext): void {\n app.get(\"/health\", async () => ({\n status: \"ok\",\n engine: ctx.engineLabel,\n model: ctx.defaultEngine.model.name,\n activeKeys: await countActiveKeys(),\n uptime: Math.round(process.uptime()),\n version: ctx.version,\n }));\n}\n","// SPDX-License-Identifier: AGPL-3.0-or-later\n// Auto-generated from package.json by scripts/sync-version.mjs (npm \"version\"). Do not edit by hand.\nexport const VERSION = \"0.1.2\";\n","// SPDX-License-Identifier: AGPL-3.0-or-later\nimport cliProgress from \"cli-progress\";\nimport pc from \"picocolors\";\n\nexport { pc };\n\nexport function mb(bytes: number): number {\n return Math.round(bytes / (1024 * 1024));\n}\n\n/** A reusable byte-progress bar for a single model download. */\nexport function modelProgress(label: string) {\n const bar = new cliProgress.SingleBar(\n { clearOnComplete: false, hideCursor: true, format: ` ${label} [{bar}] {percentage}% | {info}` },\n cliProgress.Presets.shades_classic,\n );\n let started = false;\n return {\n onProgress(received: number, total: number) {\n if (!started) {\n bar.start(total || 1, 0, { info: \"\" });\n started = true;\n }\n if (total) bar.setTotal(total);\n bar.update(received, { info: total ? `${mb(received)}/${mb(total)} MB` : `${mb(received)} MB` });\n },\n done() {\n if (started) {\n bar.update(bar.getTotal());\n bar.stop();\n } else {\n console.log(` ${label} ${pc.green(\"✓\")} ${pc.dim(\"(already present)\")}`);\n }\n },\n };\n}\n\n/**\n * Print copy-paste examples showing how a third-party app connects to the\n * endpoint. When `key` is omitted, a placeholder is shown with a hint.\n */\nexport function printAccessExample(baseUrl: string, key?: string): void {\n const k = key ?? \"sk-wapi-…\";\n const note = key ? \"\" : pc.dim(\" (generate one with: whisper-api key generate)\\n\");\n console.log();\n console.log(pc.bold(\" Connect a third-party app to this endpoint:\"));\n console.log();\n if (note) console.log(note.trimEnd());\n console.log(pc.dim(\" # curl\"));\n console.log(` curl ${baseUrl}/v1/audio/transcriptions \\\\`);\n console.log(` -H ${pc.cyan(`\"Authorization: Bearer ${k}\"`)} \\\\`);\n console.log(` -F file=@audio.m4a -F model=whisper-1`);\n console.log();\n console.log(pc.dim(\" # Python — official OpenAI SDK, just repoint base_url\"));\n console.log(` from openai import OpenAI`);\n console.log(` client = OpenAI(base_url=${pc.cyan(`\"${baseUrl}/v1\"`)}, api_key=${pc.cyan(`\"${k}\"`)})`);\n console.log(` print(client.audio.transcriptions.create(`);\n console.log(` model=\"whisper-1\", file=open(\"audio.m4a\", \"rb\")).text)`);\n console.log();\n console.log(pc.dim(\" # Node — official OpenAI SDK\"));\n console.log(` import OpenAI from \"openai\";`);\n console.log(` const client = new OpenAI({ baseURL: ${pc.cyan(`\"${baseUrl}/v1\"`)}, apiKey: ${pc.cyan(`\"${k}\"`)} });`);\n console.log();\n console.log(pc.dim(` # Any OpenAI-compatible app (Open WebUI, n8n, Raycast, LibreChat…):`));\n console.log(` Base URL ${pc.cyan(`${baseUrl}/v1`)}`);\n console.log(` API key ${pc.cyan(k)}`);\n console.log();\n}\n\n/** Reveal a freshly-minted secret once, with a copy warning. */\nexport function printNewKey(raw: string, name: string, id: string): void {\n console.log();\n console.log(pc.green(\" ✔ New API key — store it now, it is not recoverable:\"));\n console.log();\n console.log(` ${pc.bold(pc.cyan(raw))}`);\n console.log();\n console.log(pc.dim(` id ${id} name ${name}`));\n console.log();\n}\n"],"mappings":";AACA,OAAOA,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAO,YAAY;AACnB,SAAS,eAAe;AACxB,SAAS,OAAO,OAAO,QAAQ,aAAa,UAAU,QAAQ,YAAY;;;ACJ1E,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,OAAO,SAAS;AAsBT,IAAM,iBAAmC;AAAA,EAC9C,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,MAAM;AAAA,EACN,MAAM;AAAA,EACN,gBAAgB,KAAK,OAAO;AAAA,EAC5B,WAAW,EAAE,KAAK,KAAK,YAAY,WAAW;AAChD;AAGO,SAAS,UAAkB;AAChC,SAAO,QAAQ,IAAI,oBAAoB,KAAK,KAAK,GAAG,QAAQ,GAAG,cAAc;AAC/E;AAEO,IAAM,QAAQ;AAAA,EACnB,MAAM;AAAA,EACN,QAAQ,MAAM,KAAK,KAAK,QAAQ,GAAG,aAAa;AAAA,EAChD,MAAM,MAAM,KAAK,KAAK,QAAQ,GAAG,WAAW;AAAA;AAAA,EAE5C,QAAQ,MAAM,KAAK,KAAK,QAAQ,GAAG,QAAQ;AAAA;AAAA,EAE3C,OAAO,MAAM,KAAK,KAAK,QAAQ,GAAG,OAAO;AAAA;AAAA,EAEzC,KAAK,MAAM,KAAK,KAAK,QAAQ,GAAG,KAAK;AAAA;AAAA,EAErC,KAAK,MAAM,KAAK,KAAK,QAAQ,GAAG,KAAK;AACvC;AAEO,SAAS,aAAmB;AACjC,aAAW,KAAK,CAAC,QAAQ,GAAG,MAAM,OAAO,GAAG,MAAM,MAAM,GAAG,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG;AACpF,OAAG,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAAA,EACrC;AACF;AAMA,eAAsB,aAAwC;AAC5D,MAAI;AACF,UAAM,MAAM,MAAM,IAAI,SAAS,MAAM,OAAO,GAAG,MAAM;AACrD,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,WAAO;AAAA,MACL,GAAG;AAAA,MACH,GAAG;AAAA,MACH,WAAW,EAAE,GAAG,eAAe,WAAW,GAAI,OAAO,aAAa,CAAC,EAAG;AAAA,IACxE;AAAA,EACF,QAAQ;AACN,WAAO,EAAE,GAAG,eAAe;AAAA,EAC7B;AACF;AAEA,eAAsB,WAAW,KAAsC;AACrE,aAAW;AACX,QAAM,IAAI,UAAU,MAAM,OAAO,GAAG,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI,MAAM,MAAM;AACjF;AAMO,SAAS,kBAAkB,KAAyC;AACzE,QAAM,MAAM,EAAE,GAAG,KAAK,WAAW,EAAE,GAAG,IAAI,UAAU,EAAE;AACtD,MAAI,QAAQ,IAAI,iBAAkB,KAAI,OAAO,OAAO,QAAQ,IAAI,gBAAgB;AAChF,MAAI,QAAQ,IAAI,iBAAkB,KAAI,OAAO,QAAQ,IAAI;AACzD,MAAI,QAAQ,IAAI,mBAAoB,KAAI,SAAS,QAAQ,IAAI;AAC7D,MAAI,QAAQ,IAAI,kBAAmB,KAAI,eAAe,QAAQ,IAAI;AAClE,MAAI,QAAQ,IAAI,2BAA2B;AACzC,QAAI,iBAAiB,OAAO,QAAQ,IAAI,yBAAyB,IAAI,OAAO;AAAA,EAC9E;AACA,MAAI,QAAQ,IAAI,qBAAsB,KAAI,UAAU,MAAM,OAAO,QAAQ,IAAI,oBAAoB;AACjG,SAAO;AACT;;;ACjGA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAgBjB,IAAM,eAAe;AAErB,SAAS,KAAK,MAAsB;AAClC,SAAO,QAAQ,IAAI;AACrB;AAGO,IAAM,SAAsB;AAAA,EACjC,EAAE,MAAM,WAAW,UAAU,KAAK,SAAS,GAAG,UAAU,0BAA0B,QAAQ,IAAI,aAAa,MAAM,aAAa,wBAAwB;AAAA,EACtJ,EAAE,MAAM,QAAQ,UAAU,KAAK,MAAM,GAAG,UAAU,uBAAuB,QAAQ,IAAI,aAAa,OAAO,aAAa,wBAAwB;AAAA,EAC9I,EAAE,MAAM,WAAW,UAAU,KAAK,SAAS,GAAG,UAAU,0BAA0B,QAAQ,KAAK,aAAa,MAAM,aAAa,mCAAmC;AAAA,EAClK,EAAE,MAAM,QAAQ,UAAU,KAAK,MAAM,GAAG,UAAU,uBAAuB,QAAQ,KAAK,aAAa,OAAO,aAAa,mCAAmC;AAAA,EAC1J,EAAE,MAAM,YAAY,UAAU,KAAK,UAAU,GAAG,UAAU,2BAA2B,QAAQ,KAAK,aAAa,MAAM,aAAa,+BAA+B;AAAA,EACjK,EAAE,MAAM,SAAS,UAAU,KAAK,OAAO,GAAG,UAAU,wBAAwB,QAAQ,KAAK,aAAa,OAAO,aAAa,+BAA+B;AAAA,EACzJ,EAAE,MAAM,aAAa,UAAU,KAAK,WAAW,GAAG,UAAU,4BAA4B,QAAQ,MAAM,aAAa,MAAM,aAAa,6BAA6B;AAAA,EACnK,EAAE,MAAM,UAAU,UAAU,KAAK,QAAQ,GAAG,UAAU,yBAAyB,QAAQ,MAAM,aAAa,OAAO,aAAa,6BAA6B;AAAA,EAC3J,EAAE,MAAM,kBAAkB,UAAU,KAAK,gBAAgB,GAAG,UAAU,yCAAyC,QAAQ,MAAM,aAAa,OAAO,aAAa,qCAAqC;AAAA,EACnM,EAAE,MAAM,YAAY,UAAU,KAAK,UAAU,GAAG,UAAU,mCAAmC,QAAQ,MAAM,aAAa,OAAO,aAAa,6BAA6B;AAC3K;AAGO,IAAM,iBAAiB,oBAAI,IAAI,CAAC,aAAa,oBAAoB,qBAAqB,wBAAwB,CAAC;AAE/G,SAAS,QAAQ,OAAwB;AAC9C,SAAO,eAAe,IAAI,KAAK;AACjC;AAEO,SAAS,UAAU,MAAqC;AAC7D,SAAO,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAC3C;AAMO,SAAS,aAAa,WAA+B,cAAiC;AAC3F,MAAI,aAAa,CAAC,QAAQ,SAAS,GAAG;AACpC,UAAM,QAAQ,UAAU,SAAS;AACjC,QAAI,MAAO,QAAO;AAAA,EACpB;AACA,SAAO,UAAU,YAAY,KAAK,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS;AAC3E;AAEO,SAAS,SAAS,OAA0B;AACjD,SAAOC,MAAK,KAAK,MAAM,OAAO,GAAG,MAAM,QAAQ;AACjD;AAEO,SAAS,QAAQ,OAA0B;AAChD,SAAO,GAAG,YAAY,IAAI,MAAM,QAAQ;AAC1C;AAEO,SAAS,gBAAgB,OAA2B;AACzD,SAAOC,IAAG,WAAW,SAAS,KAAK,CAAC;AACtC;AAQA,eAAsB,aAAa,OAAkB,YAA0C;AAC7F,QAAM,OAAO,SAAS,KAAK;AAC3B,MAAIA,IAAG,WAAW,IAAI,EAAG,QAAO;AAChC,EAAAA,IAAG,UAAU,MAAM,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AAEhD,QAAM,MAAM,QAAQ,KAAK;AACzB,QAAM,MAAM,MAAM,MAAM,KAAK,EAAE,UAAU,SAAS,CAAC;AACnD,MAAI,CAAC,IAAI,MAAM,CAAC,IAAI,MAAM;AACxB,UAAM,IAAI,MAAM,sBAAsB,MAAM,IAAI,KAAK,IAAI,MAAM,IAAI,IAAI,UAAU,UAAU,GAAG,EAAE;AAAA,EAClG;AACA,QAAM,QAAQ,OAAO,IAAI,QAAQ,IAAI,gBAAgB,KAAK,CAAC;AAC3D,QAAM,MAAM,OAAO;AACnB,QAAM,MAAMA,IAAG,kBAAkB,GAAG;AACpC,MAAI,WAAW;AAEf,QAAM,SAAS,IAAI,KAAK,UAAU;AAClC,MAAI;AACF,eAAS;AACP,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AACV,UAAI,OAAO;AACT,oBAAY,MAAM;AAClB,YAAI,CAAC,IAAI,MAAM,KAAK,GAAG;AACrB,gBAAM,IAAI,QAAc,CAAC,YAAY,IAAI,KAAK,SAAS,OAAO,CAAC;AAAA,QACjE;AACA,qBAAa,UAAU,KAAK;AAAA,MAC9B;AAAA,IACF;AAAA,EACF,UAAE;AACA,QAAI,IAAI;AACR,UAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,UAAI,GAAG,UAAU,MAAM,QAAQ,CAAC;AAChC,UAAI,GAAG,SAAS,MAAM;AAAA,IACxB,CAAC;AAAA,EACH;AACA,EAAAA,IAAG,WAAW,KAAK,IAAI;AACvB,SAAO;AACT;;;ACnHA,OAAO,YAAY;AACnB,OAAOC,SAAQ;AACf,OAAOC,UAAS;AAGT,IAAM,aAAa;AAcnB,SAAS,iBAAyB;AACvC,SAAO,aAAa,OAAO,YAAY,EAAE,EAAE,SAAS,WAAW;AACjE;AAEO,SAAS,QAAQ,KAAqB;AAC3C,SAAO,OAAO,WAAW,QAAQ,EAAE,OAAO,GAAG,EAAE,OAAO,KAAK;AAC7D;AAEA,SAAS,QAAgB;AACvB,SAAO,SAAS,OAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AACvD;AAEA,eAAe,OAA6B;AAC1C,MAAI;AACF,UAAM,MAAM,MAAMC,KAAI,SAAS,MAAM,KAAK,GAAG,MAAM;AACnD,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,WAAO,MAAM,QAAQ,MAAM,IAAK,SAAyB,CAAC;AAAA,EAC5D,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAe,QAAQ,MAAkC;AACvD,aAAW;AAEX,QAAMA,KAAI,UAAU,MAAM,KAAK,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,MAAM,EAAE,UAAU,QAAQ,MAAM,IAAM,CAAC;AACzG,MAAI;AACF,IAAAC,IAAG,UAAU,MAAM,KAAK,GAAG,GAAK;AAAA,EAClC,QAAQ;AAAA,EAER;AACF;AAGA,eAAsB,UAAU,MAA2D;AACzF,QAAM,MAAM,eAAe;AAC3B,QAAM,SAAoB;AAAA,IACxB,IAAI,MAAM;AAAA,IACV,MAAM,QAAQ;AAAA,IACd,QAAQ,IAAI,MAAM,GAAG,WAAW,SAAS,CAAC;AAAA,IAC1C,MAAM,QAAQ,GAAG;AAAA,IACjB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,YAAY;AAAA,IACZ,SAAS;AAAA,EACX;AACA,QAAM,OAAO,MAAM,KAAK;AACxB,OAAK,KAAK,MAAM;AAChB,QAAM,QAAQ,IAAI;AAClB,SAAO,EAAE,KAAK,OAAO;AACvB;AAEA,eAAsB,WAAiC;AACrD,SAAO,KAAK;AACd;AAEA,eAAsB,kBAAmC;AACvD,UAAQ,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE;AAClD;AAGA,eAAsB,UAAU,YAAsC;AACpE,QAAM,OAAO,MAAM,KAAK;AACxB,MAAI,UAAU;AACd,aAAW,OAAO,MAAM;AACtB,QAAI,CAAC,IAAI,YAAY,IAAI,OAAO,cAAc,IAAI,WAAW,aAAa;AACxE,UAAI,UAAU;AACd,gBAAU;AAAA,IACZ;AAAA,EACF;AACA,MAAI,QAAS,OAAM,QAAQ,IAAI;AAC/B,SAAO;AACT;AAMA,eAAsB,UAAU,KAAwC;AACtE,MAAI,CAAC,OAAO,CAAC,IAAI,WAAW,UAAU,EAAG,QAAO;AAChD,QAAM,YAAY,OAAO,KAAK,QAAQ,GAAG,GAAG,KAAK;AACjD,QAAM,OAAO,MAAM,KAAK;AACxB,MAAI,QAA0B;AAC9B,aAAW,OAAO,MAAM;AACtB,QAAI,IAAI,QAAS;AACjB,UAAM,SAAS,OAAO,KAAK,IAAI,MAAM,KAAK;AAC1C,QAAI,OAAO,WAAW,UAAU,UAAU,OAAO,gBAAgB,QAAQ,SAAS,GAAG;AACnF,cAAQ;AACR;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO;AACT,UAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC1C,UAAM,QAAQ,IAAI;AAAA,EACpB;AACA,SAAO;AACT;;;AClHA,SAAS,aAAa;AACtB,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAOC,aAAY;AACnB,OAAO,kBAAkB;AAGzB,IAAM,cAAc;AAEpB,SAAS,YAAoB;AAE3B,SAAO,QAAQ,IAAI,eAAgB,gBAAsC;AAC3E;AAEA,SAAS,IAAI,MAAiC;AAC5C,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,OAAO,MAAM,UAAU,GAAG,MAAM,EAAE,OAAO,CAAC,UAAU,QAAQ,MAAM,EAAE,CAAC;AAC3E,UAAM,MAAgB,CAAC;AACvB,UAAM,MAAgB,CAAC;AACvB,SAAK,OAAO,GAAG,QAAQ,CAAC,MAAc,IAAI,KAAK,CAAC,CAAC;AACjD,SAAK,OAAO,GAAG,QAAQ,CAAC,MAAc,IAAI,KAAK,CAAC,CAAC;AACjD,SAAK,GAAG,SAAS,MAAM;AACvB,SAAK,GAAG,SAAS,CAAC,SAAS;AACzB,UAAI,SAAS,EAAG,SAAQ,OAAO,OAAO,GAAG,CAAC;AAAA,UACrC,QAAO,IAAI,MAAM,2BAA2B,IAAI,KAAK,OAAO,OAAO,GAAG,EAAE,SAAS,MAAM,EAAE,MAAM,IAAI,CAAC,EAAE,CAAC;AAAA,IAC9G,CAAC;AAAA,EACH,CAAC;AACH;AAGA,eAAsB,SAAS,WAAoC;AACjE,aAAW;AACX,QAAM,UAAUC,MAAK,KAAK,MAAM,IAAI,GAAG,OAAOC,QAAO,YAAY,CAAC,EAAE,SAAS,KAAK,CAAC,MAAM;AACzF,QAAM,IAAI,CAAC,YAAY,MAAM,WAAW,OAAO,OAAO,WAAW,GAAG,OAAO,KAAK,QAAQ,aAAa,MAAM,OAAO,SAAS,IAAI,CAAC;AAChI,SAAO;AACT;AASA,eAAsB,UAAU,WAA0C;AACxE,QAAM,MAAM,MAAM,IAAI,CAAC,YAAY,MAAM,WAAW,OAAO,OAAO,WAAW,GAAG,OAAO,KAAK,MAAM,SAAS,GAAG,CAAC;AAE/G,QAAM,UAAU,IAAI,WAAW,IAAI,UAAU;AAC7C,UAAQ,IAAI,GAAG;AACf,QAAM,UAAU,IAAI,aAAa,QAAQ,QAAQ,GAAG,KAAK,MAAM,QAAQ,aAAa,CAAC,CAAC;AACtF,SAAO,EAAE,SAAS,YAAY,aAAa,UAAU,QAAQ,SAAS,YAAY;AACpF;AAEO,SAAS,QAAQ,MAAgC;AACtD,MAAI,CAAC,KAAM;AACX,MAAI;AACF,IAAAC,IAAG,OAAO,MAAM,EAAE,OAAO,KAAK,CAAC;AAAA,EACjC,QAAQ;AAAA,EAER;AACF;;;AC5CA,IAAM,cAAsC;AAAA,EAC1C,IAAI;AAAA,EAAW,IAAI;AAAA,EAAW,IAAI;AAAA,EAAU,IAAI;AAAA,EAAU,IAAI;AAAA,EAC9D,IAAI;AAAA,EAAc,IAAI;AAAA,EAAS,IAAI;AAAA,EAAW,IAAI;AAAA,EAAW,IAAI;AAAA,EACjE,IAAI;AAAA,EAAU,IAAI;AAAA,EAAU,IAAI;AAAA,EAAS,IAAI;AAAA,EAAW,IAAI;AAAA,EAC5D,IAAI;AAAA,EAAa,IAAI;AAAA,EAAW,IAAI;AAAA,EAAS,IAAI;AAAA,EAAU,IAAI;AACjE;AAGO,IAAM,aAAN,MAAM,YAA0C;AAAA,EAC5C,OAAO;AAAA,EACP;AAAA,EACD;AAAA,EACA,OAAwB;AAAA,EAEhC,YAAY,OAAkB;AAC5B,SAAK,QAAQ;AACb,SAAK,SAAS,QAAQ,IAAI,2BAA2B;AAAA,EACvD;AAAA,EAEA,WAAmB;AACjB,WAAO,SAAS,KAAK,MAAM;AAAA,EAC7B;AAAA,EAEA,SAAS,OAAuC;AAC9C,WAAO,IAAI,YAAW,KAAK;AAAA,EAC7B;AAAA,EAEA,MAAc,QAAQ,YAA4C;AAChE,QAAI,KAAK,KAAM,QAAO,KAAK;AAC3B,UAAM,EAAE,UAAAC,WAAU,IAAI,IAAI,MAAM,OAAO,2BAA2B;AAClE,QAAI,WAAW,MAAM,MAAM;AAC3B,QAAI,mBAAmB;AAEvB,UAAM,QAAQ,QAAQ,IAAI,2BAA2B,KAAK,MAAM,SAAS,MAAO,OAAO;AACvF,UAAM,OAAQ,MAAMA,UAAS,gCAAgC,KAAK,MAAM,UAAU;AAAA,MAChF,QAAQ,KAAK;AAAA,MACb;AAAA,MACA,mBAAmB,aACf,CAAC,MAA4D;AAC3D,YAAI,EAAE,WAAW,cAAc,OAAO,EAAE,WAAW,YAAY,OAAO,EAAE,UAAU,UAAU;AAC1F,qBAAW,EAAE,QAAQ,EAAE,KAAK;AAAA,QAC9B;AAAA,MACF,IACA;AAAA,IACN,CAAC;AACD,SAAK,OAAO;AACZ,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,YAAY,YAAwC;AAExD,UAAM,KAAK,QAAQ,UAAU;AAAA,EAC/B;AAAA,EAEA,MAAM,WAAW,WAAmB,MAAuD;AACzF,UAAM,OAAO,MAAM,KAAK,QAAQ;AAChC,UAAM,EAAE,SAAS,SAAS,IAAI,MAAM,UAAU,SAAS;AAEvD,UAAM,UAAmC;AAAA,MACvC,mBAAmB;AAAA,MACnB,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,IACnB;AACA,QAAI,CAAC,KAAK,MAAM,aAAa;AAC3B,cAAQ,MAAM,IAAI,KAAK,YAAY,cAAc;AACjD,UAAI,KAAK,SAAU,SAAQ,UAAU,IAAI,YAAY,KAAK,QAAQ,KAAK,KAAK;AAAA,IAC9E;AACA,QAAI,OAAO,KAAK,gBAAgB,SAAU,SAAQ,aAAa,IAAI,KAAK;AAExE,UAAM,MAAM,MAAM,KAAK,SAAS,OAAO;AACvC,UAAM,YAAuB,IAAI,UAAU,CAAC,GAAG,IAAI,CAAC,GAAG,OAAO;AAAA,MAC5D,IAAI;AAAA,MACJ,OAAO,EAAE,UAAU,CAAC,KAAK;AAAA,MACzB,KAAK,EAAE,UAAU,CAAC,KAAK;AAAA,MACvB,MAAM,EAAE,KAAK,KAAK;AAAA,IACpB,EAAE;AAEF,WAAO;AAAA,MACL,OAAO,IAAI,QAAQ,IAAI,KAAK;AAAA,MAC5B,UAAU,KAAK;AAAA,MACf;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;;;ACpGA,SAAS,SAAAC,cAAa;AACtB,OAAOC,SAAQ;AACf,OAAOC,UAAS;AAChB,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAOC,aAAY;AAkBZ,IAAM,mBAAN,MAAM,kBAAgD;AAAA,EAClD,OAAO;AAAA,EACP;AAAA,EACD;AAAA,EACA;AAAA,EAER,YAAY,OAAkB,KAAa,KAAU;AACnD,SAAK,QAAQ;AACb,SAAK,MAAM;AACX,SAAK,MAAM;AAAA,EACb;AAAA,EAEA,WAAmB;AACjB,WAAO,gBAAgB,KAAK,OAAO,KAAK;AAAA,EAC1C;AAAA,EAEA,SAAS,OAAuC;AAC9C,WAAO,IAAI,kBAAiB,OAAO,KAAK,KAAK,KAAK,GAAG;AAAA,EACvD;AAAA,EAEA,MAAM,YAAY,YAAwC;AACxD,UAAM,aAAa,KAAK,OAAO,UAAU;AAAA,EAC3C;AAAA,EAEA,MAAM,WAAW,WAAmB,MAAuD;AACzF,UAAM,KAAK,YAAY;AACvB,UAAM,MAAM,MAAM,SAAS,SAAS;AACpC,UAAM,YAAYC,MAAK,KAAK,MAAM,IAAI,GAAG,QAAQC,QAAO,YAAY,CAAC,EAAE,SAAS,KAAK,CAAC,EAAE;AACxF,UAAM,WAAW,YAAY;AAE7B,UAAM,OAAO;AAAA,MACX;AAAA,MAAM,SAAS,KAAK,KAAK;AAAA,MACzB;AAAA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MAAO;AAAA,MACP;AAAA,MACA;AAAA,MAAM,OAAO,KAAK,IAAI,GAAGC,IAAG,KAAK,EAAE,MAAM,CAAC;AAAA,IAC5C;AACA,QAAI,KAAK,MAAM,aAAa;AAC1B,WAAK,KAAK,MAAM,IAAI;AAAA,IACtB,OAAO;AACL,WAAK,KAAK,MAAM,KAAK,YAAY,MAAM;AAAA,IACzC;AACA,QAAI,KAAK,UAAW,MAAK,KAAK,aAAa;AAC3C,QAAI,OAAO,KAAK,gBAAgB,SAAU,MAAK,KAAK,OAAO,OAAO,KAAK,WAAW,CAAC;AACnF,QAAI,KAAK,OAAQ,MAAK,KAAK,YAAY,KAAK,MAAM;AAElD,QAAI;AACF,YAAM,KAAK,IAAI,IAAI;AACnB,YAAM,MAAM,MAAMC,KAAI,SAAS,UAAU,MAAM;AAC/C,aAAO,KAAK,MAAM,KAAK,MAAM,GAAG,GAAqB,IAAI;AAAA,IAC3D,UAAE;AACA,cAAQ,GAAG;AACX,cAAQ,QAAQ;AAAA,IAClB;AAAA,EACF;AAAA,EAEQ,IAAI,MAA+B;AACzC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,OAAOC,OAAM,KAAK,KAAK,MAAM,EAAE,OAAO,CAAC,UAAU,UAAU,MAAM,EAAE,CAAC;AAC1E,YAAM,MAAgB,CAAC;AACvB,WAAK,OAAO,GAAG,QAAQ,CAAC,MAAc,IAAI,KAAK,CAAC,CAAC;AACjD,WAAK,GAAG,SAAS,MAAM;AACvB,WAAK;AAAA,QAAG;AAAA,QAAS,CAAC,SAChB,SAAS,IACL,QAAQ,IACR,OAAO,IAAI,MAAM,gCAAgC,IAAI,KAAK,OAAO,OAAO,GAAG,EAAE,SAAS,MAAM,EAAE,MAAM,IAAI,CAAC,EAAE,CAAC;AAAA,MAClH;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,MAAM,MAAsB,MAA8C;AAChF,UAAM,QAAQ,KAAK,iBAAiB,CAAC;AACrC,UAAM,WAAsB,MAAM,IAAI,CAAC,IAAI,OAAO;AAAA,MAChD,IAAI;AAAA,MACJ,QAAQ,GAAG,SAAS,QAAQ,KAAK;AAAA,MACjC,MAAM,GAAG,SAAS,MAAM,KAAK;AAAA,MAC7B,OAAO,GAAG,QAAQ,IAAI,KAAK;AAAA,IAC7B,EAAE;AACF,UAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,WAAO;AAAA,MACL,MAAM,MAAM,IAAI,CAAC,OAAO,GAAG,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK;AAAA,MACrD,UAAU,KAAK,QAAQ,YAAY,KAAK,QAAQ,YAAY,KAAK;AAAA,MACjE,UAAU,MAAM,SAAS,KAAK,KAAK,QAAQ,KAAK,MAAO;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AACF;;;AC9GA,SAAS,SAAAC,QAAO,iBAAiB;AACjC,OAAOC,SAAQ;AACf,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAKjB,IAAM,mBAAmB;AAGlB,SAAS,MAAM,KAAsB;AAC1C,QAAM,SAAS,QAAQ,aAAa,UAAU,UAAU;AACxD,QAAM,IAAI,UAAU,QAAQ,CAAC,GAAG,GAAG,EAAE,OAAO,SAAS,CAAC;AACtD,SAAO,EAAE,WAAW;AACtB;AAEO,SAAS,gBAAyB;AACvC,QAAM,WAAW,MAAM,IAAI,KAAK,MAAM,OAAO,KAAK,MAAM,KAAK,KAAK,MAAM,KAAK;AAC7E,SAAO,MAAM,KAAK,KAAK,MAAM,OAAO,KAAK;AAC3C;AAEO,SAAS,YAAiB;AAC/B,MAAI,MAAM,YAAY,EAAG,QAAO;AAChC,MAAI,QAAQ,aAAa,YAAYC,IAAG,KAAK,MAAM,QAAS,QAAO;AACnE,SAAO;AACT;AAEA,SAAS,gBAA0B;AACjC,QAAM,MAAM,QAAQ,aAAa,UAAU,SAAS;AACpD,QAAM,QAAQ,CAAC,cAAc,GAAG,IAAI,OAAO,GAAG,EAAE;AAChD,QAAM,MAAgB,CAAC;AACvB,MAAI,QAAQ,IAAI,gBAAiB,KAAI,KAAK,QAAQ,IAAI,eAAe;AACrE,aAAW,KAAK,MAAO,KAAI,KAAKC,MAAK,KAAK,MAAM,IAAI,GAAG,CAAC,CAAC;AACzD,SAAO;AACT;AAGO,SAAS,sBAAqC;AACnD,aAAW,KAAK,cAAc,GAAG;AAC/B,QAAIC,IAAG,WAAW,CAAC,EAAG,QAAO;AAAA,EAC/B;AACA,MAAI,MAAM,aAAa,EAAG,QAAO;AACjC,SAAO;AACT;AAIA,SAAS,KAAK,KAAa,MAAgB,KAAa,OAA8B;AACpF,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAQ,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,CAAC,EAAE;AACpC,UAAM,OAAOC,OAAM,KAAK,MAAM,EAAE,KAAK,OAAO,CAAC,UAAU,QAAQ,MAAM,EAAE,CAAC;AACxE,UAAM,QAAQ,CAAC,MAAc,QAAQ,EAAE,SAAS,MAAM,EAAE,QAAQ,CAAC;AACjE,SAAK,OAAO,GAAG,QAAQ,KAAK;AAC5B,SAAK,OAAO,GAAG,QAAQ,KAAK;AAC5B,SAAK,GAAG,SAAS,MAAM;AACvB,SAAK;AAAA,MAAG;AAAA,MAAS,CAAC,SAChB,SAAS,IAAI,QAAQ,IAAI,OAAO,IAAI,MAAM,GAAG,GAAG,qBAAqB,IAAI,EAAE,CAAC;AAAA,IAC9E;AAAA,EACF,CAAC;AACH;AAOA,eAAsB,gBAAgB,OAAgC;AACpE,MAAI,CAAC,cAAc,GAAG;AACpB,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACA,aAAW;AACX,QAAM,SAASF,MAAK,KAAK,MAAM,MAAM,GAAG,iBAAiB;AACzD,QAAM,WAAWA,MAAK,KAAK,QAAQ,OAAO;AAC1C,QAAM,MAAM,UAAU;AAEtB,MAAI,CAACC,IAAG,WAAWD,MAAK,KAAK,QAAQ,gBAAgB,CAAC,GAAG;AACvD,IAAAC,IAAG,OAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAClD,UAAM,KAAK,OAAO,CAAC,SAAS,WAAW,KAAK,kBAAkB,MAAM,GAAG,MAAM,MAAM,GAAG,KAAK;AAAA,EAC7F;AAEA,QAAM,YAAY;AAAA,IAChB;AAAA,IAAM;AAAA,IACN;AAAA,IAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,QAAQ,OAAQ,WAAU,KAAK,gBAAgB;AAGnD,QAAM,KAAK,SAAS,WAAW,QAAQ,KAAK;AAC5C,QAAM,KAAK,SAAS,CAAC,WAAW,UAAU,MAAM,OAAO,KAAK,IAAI,GAAGF,IAAG,KAAK,EAAE,MAAM,CAAC,GAAG,YAAY,SAAS,GAAG,QAAQ,KAAK;AAE5H,QAAM,MAAM,QAAQ,aAAa,UAAU,SAAS;AACpD,QAAM,QAAQ;AAAA,IACZC,MAAK,KAAK,UAAU,OAAO,cAAc,GAAG,EAAE;AAAA,IAC9CA,MAAK,KAAK,UAAU,OAAO,WAAW,cAAc,GAAG,EAAE;AAAA,EAC3D,EAAE,KAAK,CAAC,MAAMC,IAAG,WAAW,CAAC,CAAC;AAC9B,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,sDAAsD;AAElF,QAAM,OAAOD,MAAK,KAAK,MAAM,IAAI,GAAG,cAAc,GAAG,EAAE;AACvD,EAAAC,IAAG,aAAa,OAAO,IAAI;AAC3B,EAAAA,IAAG,UAAU,MAAM,GAAK;AACxB,UAAQ,gCAA2B,IAAI,EAAE;AACzC,SAAO;AACT;;;AC/EA,eAAsB,aAAa,MAAkD;AACnF,QAAM,EAAE,QAAQ,OAAO,OAAO,EAAE,IAAI;AACpC,QAAM,aAAa,KAAK,cAAc,QAAQ,IAAI,0BAA0B;AAE5E,MAAI,WAAW,QAAQ;AACrB,WAAO,EAAE,QAAQ,IAAI,WAAW,CAAC,GAAG,QAAQ,sCAAsC;AAAA,EACpF;AAEA,MAAI,WAAW,cAAc;AAC3B,UAAM,MAAM,oBAAoB,KAAM,MAAM,SAAS,KAAK,KAAK;AAC/D,QAAI,CAAC,KAAK;AACR,YAAM,IAAI;AAAA,QACR;AAAA,MAGF;AAAA,IACF;AACA,WAAO,EAAE,QAAQ,IAAI,iBAAiB,OAAO,KAAK,UAAU,CAAC,GAAG,QAAQ,oBAAoB;AAAA,EAC9F;AAGA,QAAM,WAAW,oBAAoB;AACrC,MAAI,UAAU;AACZ,WAAO,EAAE,QAAQ,IAAI,iBAAiB,OAAO,UAAU,UAAU,CAAC,GAAG,QAAQ,yCAAoC;AAAA,EACnH;AACA,MAAI,cAAc,cAAc,GAAG;AACjC,UAAM,QAAQ,MAAM,SAAS,KAAK,KAAK;AACvC,QAAI,OAAO;AACT,aAAO,EAAE,QAAQ,IAAI,iBAAiB,OAAO,OAAO,UAAU,CAAC,GAAG,QAAQ,8CAAyC;AAAA,IACrH;AAAA,EACF;AACA,SAAO;AAAA,IACL,QAAQ,IAAI,WAAW,CAAC;AAAA,IACxB,QAAQ,cAAc,IAClB,8FACA;AAAA,EACN;AACF;AAEA,eAAe,SAAS,OAAqD;AAC3E,MAAI;AACF,WAAO,MAAM,gBAAgB,KAAK;AAAA,EACpC,SAAS,KAAK;AACZ,YAAQ,6BAA8B,IAAc,OAAO,EAAE;AAC7D,WAAO;AAAA,EACT;AACF;;;AC1EA,SAAS,qBAAqB;AAC9B,OAAOE,SAAQ;AACf,OAAO,aAA0D;AACjE,OAAO,eAAe;AACtB,OAAO,eAAe;AACtB,OAAO,mBAAmB;;;ACL1B,OAAOC,aAAY;;;ACIZ,IAAM,mBAAqC,CAAC,QAAQ,gBAAgB,QAAQ,OAAO,KAAK;AAExF,SAAS,iBAAiB,GAAgC;AAC/D,SAAQ,iBAA8B,SAAS,CAAC;AAClD;AAEA,SAAS,IAAI,GAAW,OAAuB;AAC7C,SAAO,KAAK,MAAM,CAAC,EAAE,SAAS,EAAE,SAAS,OAAO,GAAG;AACrD;AAGA,SAAS,UAAU,SAAiB,KAAwB;AAC1D,QAAM,KAAK,KAAK,OAAO,UAAU,KAAK,MAAM,OAAO,KAAK,GAAI;AAC5D,QAAM,IAAI,KAAK,MAAM,OAAO,IAAI;AAChC,QAAM,IAAI,KAAK,MAAM,UAAU,EAAE,IAAI;AACrC,QAAM,IAAI,KAAK,MAAM,UAAU,IAAI;AACnC,SAAO,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,IAAI,IAAI,CAAC,CAAC;AAClE;AAEA,SAAS,MAAM,GAAgC;AAC7C,SACE,EAAE,SACC,IAAI,CAAC,KAAK,MAAM,GAAG,IAAI,CAAC;AAAA,EAAK,UAAU,IAAI,OAAO,GAAG,CAAC,QAAQ,UAAU,IAAI,KAAK,GAAG,CAAC;AAAA,EAAK,IAAI,IAAI;AAAA,CAAI,EACtG,KAAK,IAAI,IAAI;AAEpB;AAEA,SAAS,MAAM,GAAgC;AAC7C,QAAM,OAAO,EAAE,SACZ,IAAI,CAAC,QAAQ,GAAG,UAAU,IAAI,OAAO,GAAG,CAAC,QAAQ,UAAU,IAAI,KAAK,GAAG,CAAC;AAAA,EAAK,IAAI,IAAI,EAAE,EACvF,KAAK,MAAM;AACd,SAAO;AAAA;AAAA,EAAa,IAAI;AAAA;AAC1B;AAQO,SAAS,UAAU,QAA6B,QAA4C;AACjG,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,EAAE,aAAa,6BAA6B,MAAM,OAAO,OAAO,KAAK;AAAA,IAC9E,KAAK;AACH,aAAO,EAAE,aAAa,6BAA6B,MAAM,MAAM,MAAM,EAAE;AAAA,IACzE,KAAK;AACH,aAAO,EAAE,aAAa,2BAA2B,MAAM,MAAM,MAAM,EAAE;AAAA,IACvE,KAAK;AACH,aAAO;AAAA,QACL,aAAa;AAAA,QACb,MAAM,KAAK,UAAU;AAAA,UACnB,MAAM;AAAA,UACN,UAAU,OAAO,YAAY;AAAA,UAC7B,UAAU,OAAO,YAAY;AAAA,UAC7B,MAAM,OAAO;AAAA,UACb,UAAU,OAAO,SAAS,IAAI,CAAC,SAAS;AAAA,YACtC,IAAI,IAAI;AAAA,YACR,MAAM;AAAA,YACN,OAAO,IAAI;AAAA,YACX,KAAK,IAAI;AAAA,YACT,MAAM,IAAI;AAAA,YACV,QAAQ,CAAC;AAAA,YACT,aAAa;AAAA,YACb,aAAa;AAAA,YACb,mBAAmB;AAAA,YACnB,gBAAgB;AAAA,UAClB,EAAE;AAAA,QACJ,CAAC;AAAA,MACH;AAAA,IACF,KAAK;AAAA,IACL;AACE,aAAO,EAAE,aAAa,mCAAmC,MAAM,KAAK,UAAU,EAAE,MAAM,OAAO,KAAK,CAAC,EAAE;AAAA,EACzG;AACF;AAGO,SAAS,UAAU,SAAiB,OAAO,yBAAyB,OAAsB,MAAM;AACrG,SAAO,EAAE,OAAO,EAAE,SAAS,MAAM,OAAO,MAAM,KAAK,EAAE;AACvD;;;ADvEA,IAAM,eAAe,oBAAI,IAAI,CAAC,WAAW,KAAK,cAAc,CAAC;AAE7D,SAAS,SAAS,KAAsB;AACtC,QAAM,WAAW,IAAI,MAAM,GAAG,EAAE,CAAC,KAAK;AACtC,SAAO,aAAa,IAAI,QAAQ,KAAM,CAAC,SAAS,WAAW,MAAM,KAAK,CAAC,SAAS,WAAW,KAAK;AAClG;AAEO,SAAS,cAAc,QAA2C;AACvE,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,IAAI,mBAAmB,KAAK,OAAO,KAAK,CAAC;AAC/C,SAAO,IAAI,EAAE,CAAC,EAAG,KAAK,IAAI;AAC5B;AAGA,SAAS,cAAc,OAAe,YAA+B;AACnE,QAAM,IAAIC,QAAO,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO;AAC3D,aAAW,KAAK,YAAY;AAC1B,QAAI,CAAC,EAAG;AACR,UAAM,IAAIA,QAAO,WAAW,QAAQ,EAAE,OAAO,CAAC,EAAE,OAAO;AACvD,QAAI,EAAE,WAAW,EAAE,UAAUA,QAAO,gBAAgB,GAAG,CAAC,EAAG,QAAO;AAAA,EACpE;AACA,SAAO;AACT;AAWO,SAAS,aAAa,KAAkB;AAC7C,SAAO,eAAe,SAAS,KAAqB,OAAoC;AACtF,QAAI,SAAS,IAAI,GAAG,EAAG;AAEvB,UAAM,QAAQ,cAAc,IAAI,QAAQ,aAAa;AACrD,QAAI,CAAC,OAAO;AACV,YAAM,MACH,KAAK,GAAG,EACR,KAAK,UAAU,6DAA6D,yBAAyB,iBAAiB,CAAC;AAC1H;AAAA,IACF;AAEA,QAAI,IAAI,cAAc,UAAU,cAAc,OAAO,IAAI,aAAa,GAAG;AACvE,UAAI,SAAS;AAAA,QACX,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ,MAAM,MAAM,GAAG,CAAC;AAAA,QACxB,MAAM;AAAA,QACN,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,SAAS;AAAA,MACX;AACA;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,UAAU,KAAK;AACpC,QAAI,CAAC,QAAQ;AACX,YAAM,MAAM,KAAK,GAAG,EAAE,KAAK,UAAU,+BAA+B,yBAAyB,iBAAiB,CAAC;AAC/G;AAAA,IACF;AACA,QAAI,SAAS;AAAA,EACf;AACF;;;AE7EA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAOC,aAAY;AACnB,SAAS,gBAAgB;AAczB,eAAe,eAAe,KAA+D;AAC3F,aAAW;AACX,QAAM,SAAwB,EAAE,QAAQ,CAAC,EAAE;AAC3C,mBAAiB,QAAQ,IAAI,MAAM,GAAG;AACpC,QAAI,KAAK,SAAS,QAAQ;AACxB,UAAI,KAAK,cAAc,QAAQ;AAC7B,cAAM,MAAMC,MAAK,QAAQ,KAAK,YAAY,EAAE,KAAK;AACjD,cAAM,OAAOA,MAAK,KAAK,MAAM,IAAI,GAAG,MAAMC,QAAO,YAAY,CAAC,EAAE,SAAS,KAAK,CAAC,GAAG,GAAG,EAAE;AACvF,cAAM,SAAS,KAAK,MAAMC,IAAG,kBAAkB,IAAI,CAAC;AACpD,eAAO,WAAW;AAClB,eAAO,WAAW,KAAK;AACvB,YAAI,KAAK,KAAK,WAAW;AACvB,kBAAQ,IAAI;AACZ,gBAAM,OAAO,OAAO,IAAI,MAAM,kDAAkD,GAAG,EAAE,YAAY,IAAI,CAAC;AAAA,QACxG;AAAA,MACF,OAAO;AACL,aAAK,KAAK,OAAO;AAAA,MACnB;AAAA,IACF,OAAO;AACL,aAAO,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK;AAAA,IACnD;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,uBAAuB,KAAsB,KAA0B;AACrF,QAAM,UAAU,CAAC,cAAuB,OAAO,KAAuC,UAA0C;AAC9H,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,eAAe,GAAG;AACjC,UAAI,CAAC,OAAO,UAAU;AACpB,eAAO,MAAM,KAAK,GAAG,EAAE,KAAK,UAAU,kCAAkC,yBAAyB,cAAc,CAAC;AAAA,MAClH;AAEA,YAAM,SAAS,OAAO,OAAO,iBAAiB,KAAK;AACnD,UAAI,CAAC,iBAAiB,MAAM,GAAG;AAC7B,eAAO,MAAM,KAAK,GAAG,EAAE,KAAK,UAAU,gCAAgC,MAAM,MAAM,uBAAuB,CAAC;AAAA,MAC5G;AACA,YAAM,SAAS;AAEf,YAAM,QAAQ,aAAa,OAAO,OAAO,OAAO,GAAG,IAAI,OAAO,YAAY;AAC1E,YAAM,cAAc,OAAO,OAAO,aAAa,MAAM,SAAY,OAAO,OAAO,OAAO,aAAa,CAAC,IAAI;AACxG,YAAM,OAAO,OAAO,OAAO,MAAM;AAEjC,YAAM,SAAS,MAAM,IAAI,UAAU,MAAM,IAAI;AAC7C,YAAM,SAAS,MAAM,OAAO,WAAW,OAAO,UAAU;AAAA,QACtD,UAAU,OAAO,OAAO,UAAU,KAAK;AAAA,QACvC,WAAW,aAAa,SAAS;AAAA,QACjC,aAAa,OAAO,gBAAgB,YAAY,CAAC,OAAO,MAAM,WAAW,IAAI,cAAc;AAAA,QAC3F,QAAQ,OAAO,OAAO,QAAQ,KAAK;AAAA,MACrC,CAAC;AAED,YAAM,EAAE,aAAa,KAAK,IAAI,UAAU,QAAQ,MAAM;AACtD,aAAO,MAAM,OAAO,gBAAgB,WAAW,EAAE,KAAK,IAAI;AAAA,IAC5D,SAAS,KAAK;AACZ,YAAM,IAAI;AACV,YAAM,SAAS,EAAE,cAAc;AAC/B,UAAI,IAAI,MAAM,EAAE,KAAK,EAAE,GAAG,sBAAsB;AAChD,aAAO,MACJ,KAAK,MAAM,EACX,KAAK,UAAU,EAAE,WAAW,yBAAyB,WAAW,MAAM,0BAA0B,cAAc,CAAC;AAAA,IACpH,UAAE;AACA,cAAQ,QAAQ,QAAQ;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,YAAY;AAAA,IAChB,QAAQ,EAAE,WAAW,EAAE,KAAK,IAAI,OAAO,UAAU,KAAK,YAAY,IAAI,OAAO,UAAU,WAAW,EAAE;AAAA,EACtG;AACA,MAAI,KAAK,4BAA4B,WAAW,QAAQ,KAAK,CAAC;AAC9D,MAAI,KAAK,0BAA0B,WAAW,QAAQ,IAAI,CAAC;AAC7D;;;ACnFO,SAAS,eAAe,KAAsB,KAA0B;AAC7E,QAAM,UAAU;AAChB,QAAM,QAAQ,CAAC,QAAgB,EAAE,IAAI,QAAQ,SAAS,SAAS,UAAU,cAAc;AAEvF,MAAI,IAAI,cAAc,aAAa;AAAA,IACjC,QAAQ;AAAA,IACR,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,OAAO,IAAI,CAAC,MAAM,MAAM,EAAE,IAAI,CAAC,CAAC;AAAA,EAChE,EAAE;AAEF,MAAI,IAAI,kBAAkB,OAAO,KAAK,UAAU;AAC9C,UAAM,KAAM,IAAI,OAA0B;AAC1C,QAAI,OAAO,eAAe,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG;AAC3D,aAAO,MAAM,EAAE;AAAA,IACjB;AACA,WAAO,MAAM,KAAK,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,UAAU,EAAE,gBAAgB,MAAM,wBAAwB,EAAE,CAAC;AAAA,EAC/G,CAAC;AAGD,MAAI,IAAI,qBAAqB,YAAY,MAAM,IAAI,cAAc,MAAM,IAAI,CAAC;AAC9E;;;ACnBO,SAAS,eAAe,KAAsB,KAA0B;AAC7E,MAAI,IAAI,WAAW,aAAa;AAAA,IAC9B,QAAQ;AAAA,IACR,QAAQ,IAAI;AAAA,IACZ,OAAO,IAAI,cAAc,MAAM;AAAA,IAC/B,YAAY,MAAM,gBAAgB;AAAA,IAClC,QAAQ,KAAK,MAAM,QAAQ,OAAO,CAAC;AAAA,IACnC,SAAS,IAAI;AAAA,EACf,EAAE;AACJ;;;ALcA,SAAS,aAA4B;AACnC,aAAW,OAAO,CAAC,UAAU,aAAa,cAAc,GAAG;AACzD,UAAM,MAAM,cAAc,IAAI,IAAI,KAAK,YAAY,GAAG,CAAC;AACvD,QAAIC,IAAG,WAAW,GAAG,EAAG,QAAO;AAAA,EACjC;AACA,SAAO;AACT;AAEA,eAAsB,YAAY,KAA8C;AAC9E,QAAM,MAAM,QAAQ;AAAA,IAClB,QAAQ,QAAQ,IAAI,oBAAoB,WAAW,QAAQ,EAAE,OAAO,QAAQ,IAAI,mBAAmB,OAAO;AAAA,IAC1G,WAAW,IAAI,OAAO,iBAAiB,OAAO;AAAA,EAChD,CAAC;AAED,QAAM,IAAI,SAAS,WAAW;AAAA,IAC5B,QAAQ,EAAE,UAAU,IAAI,OAAO,gBAAgB,OAAO,GAAG,QAAQ,GAAG;AAAA,EACtE,CAAC;AAED,QAAM,IAAI,SAAS,WAAW;AAAA,IAC5B,QAAQ;AAAA,IACR,cAAc,CAAC,QAAQ,cAAc,IAAI,QAAQ,aAAa,KAAK,IAAI;AAAA,IACvE,sBAAsB,MACpB,UAAU,6DAA6D,oBAAoB,qBAAqB;AAAA,EACpH,CAAC;AAED,MAAI,QAAQ,aAAa,aAAa,EAAE,eAAe,IAAI,cAAc,CAAC,CAAC;AAE3E,MAAI,gBAAgB,CAAC,KAAmB,KAAK,UAAU;AACrD,UAAM,SAAU,IAAI,cAAc,IAAI,cAAc,MAAM,IAAI,aAAa;AAC3E,QAAI,IAAI,MAAM,EAAE,IAAI,GAAG,eAAe;AACtC,UAAM,KAAK,MAAM,EAAE,KAAK,UAAU,IAAI,WAAW,0BAA0B,UAAU,MAAM,iBAAiB,uBAAuB,CAAC;AAAA,EACtI,CAAC;AAGD,iBAAe,KAAK,GAAG;AACvB,iBAAe,KAAK,GAAG;AACvB,yBAAuB,KAAK,GAAG;AAG/B,QAAM,SAAS,WAAW;AAC1B,MAAI,QAAQ;AACV,UAAM,IAAI,SAAS,eAAe,EAAE,MAAM,QAAQ,QAAQ,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC;AAAA,EACxF,OAAO;AACL,QAAI,IAAI,KAAK,aAAa,EAAE,MAAM,eAAe,QAAQ,MAAM,MAAM,UAAU,EAAE;AAAA,EACnF;AAEA,SAAO;AACT;AAEA,eAAsB,YAAY,KAAoE;AACpG,QAAM,MAAM,MAAM,YAAY,GAAG;AACjC,QAAM,IAAI,OAAO,EAAE,MAAM,IAAI,OAAO,MAAM,MAAM,IAAI,OAAO,KAAK,CAAC;AACjE,QAAM,QAAQ,IAAI,OAAO,SAAS,YAAY,cAAc,IAAI,OAAO;AACvE,SAAO,EAAE,KAAK,KAAK,UAAU,KAAK,IAAI,IAAI,OAAO,IAAI,GAAG;AAC1D;;;AMjFO,IAAM,UAAU;;;ACDvB,OAAO,iBAAiB;AACxB,OAAO,QAAQ;AAIR,SAAS,GAAG,OAAuB;AACxC,SAAO,KAAK,MAAM,SAAS,OAAO,KAAK;AACzC;AAGO,SAAS,cAAc,OAAe;AAC3C,QAAM,MAAM,IAAI,YAAY;AAAA,IAC1B,EAAE,iBAAiB,OAAO,YAAY,MAAM,QAAQ,KAAK,KAAK,kCAAkC;AAAA,IAChG,YAAY,QAAQ;AAAA,EACtB;AACA,MAAI,UAAU;AACd,SAAO;AAAA,IACL,WAAW,UAAkB,OAAe;AAC1C,UAAI,CAAC,SAAS;AACZ,YAAI,MAAM,SAAS,GAAG,GAAG,EAAE,MAAM,GAAG,CAAC;AACrC,kBAAU;AAAA,MACZ;AACA,UAAI,MAAO,KAAI,SAAS,KAAK;AAC7B,UAAI,OAAO,UAAU,EAAE,MAAM,QAAQ,GAAG,GAAG,QAAQ,CAAC,IAAI,GAAG,KAAK,CAAC,QAAQ,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC;AAAA,IACjG;AAAA,IACA,OAAO;AACL,UAAI,SAAS;AACX,YAAI,OAAO,IAAI,SAAS,CAAC;AACzB,YAAI,KAAK;AAAA,MACX,OAAO;AACL,gBAAQ,IAAI,KAAK,KAAK,IAAI,GAAG,MAAM,QAAG,CAAC,IAAI,GAAG,IAAI,mBAAmB,CAAC,EAAE;AAAA,MAC1E;AAAA,IACF;AAAA,EACF;AACF;AAMO,SAAS,mBAAmB,SAAiB,KAAoB;AACtE,QAAM,IAAI,OAAO;AACjB,QAAMC,QAAO,MAAM,KAAK,GAAG,IAAI,mDAAmD;AAClF,UAAQ,IAAI;AACZ,UAAQ,IAAI,GAAG,KAAK,+CAA+C,CAAC;AACpE,UAAQ,IAAI;AACZ,MAAIA,MAAM,SAAQ,IAAIA,MAAK,QAAQ,CAAC;AACpC,UAAQ,IAAI,GAAG,IAAI,UAAU,CAAC;AAC9B,UAAQ,IAAI,UAAU,OAAO,6BAA6B;AAC1D,UAAQ,IAAI,UAAU,GAAG,KAAK,0BAA0B,CAAC,GAAG,CAAC,KAAK;AAClE,UAAQ,IAAI,2CAA2C;AACvD,UAAQ,IAAI;AACZ,UAAQ,IAAI,GAAG,IAAI,8DAAyD,CAAC;AAC7E,UAAQ,IAAI,6BAA6B;AACzC,UAAQ,IAAI,8BAA8B,GAAG,KAAK,IAAI,OAAO,MAAM,CAAC,aAAa,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG;AACrG,UAAQ,IAAI,6CAA6C;AACzD,UAAQ,IAAI,8DAA8D;AAC1E,UAAQ,IAAI;AACZ,UAAQ,IAAI,GAAG,IAAI,qCAAgC,CAAC;AACpD,UAAQ,IAAI,gCAAgC;AAC5C,UAAQ,IAAI,0CAA0C,GAAG,KAAK,IAAI,OAAO,MAAM,CAAC,aAAa,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM;AACpH,UAAQ,IAAI;AACZ,UAAQ,IAAI,GAAG,IAAI,4EAAuE,CAAC;AAC3F,UAAQ,IAAI,eAAe,GAAG,KAAK,GAAG,OAAO,KAAK,CAAC,EAAE;AACrD,UAAQ,IAAI,eAAe,GAAG,KAAK,CAAC,CAAC,EAAE;AACvC,UAAQ,IAAI;AACd;AAGO,SAAS,YAAY,KAAa,MAAc,IAAkB;AACvE,UAAQ,IAAI;AACZ,UAAQ,IAAI,GAAG,MAAM,kEAAwD,CAAC;AAC9E,UAAQ,IAAI;AACZ,UAAQ,IAAI,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC,EAAE;AAC5C,UAAQ,IAAI;AACZ,UAAQ,IAAI,GAAG,IAAI,YAAY,EAAE,WAAW,IAAI,EAAE,CAAC;AACnD,UAAQ,IAAI;AACd;;;AhB1CA,OAAO,OAAO,EAAE,OAAO,KAAK,CAAC;AAC7B,OAAO,OAAO,EAAE,MAAMC,MAAK,KAAK,QAAQ,GAAG,MAAM,GAAG,OAAO,KAAK,CAAC;AAGjE,eAAe,UAAU,cAA4B,OAAkB,OAA8B;AACnG,QAAM,KAAK,cAAc,MAAM,OAAO,EAAE,CAAC;AACzC,MAAI;AACF,QAAI,iBAAiB,QAAQ;AAC3B,YAAM,IAAI,WAAW,KAAK,EAAE,YAAY,GAAG,UAAU;AAAA,IACvD,OAAO;AACL,YAAM,aAAa,OAAO,GAAG,UAAU;AAAA,IACzC;AAAA,EACF,UAAE;AACA,OAAG,KAAK;AAAA,EACV;AACF;AAEA,eAAe,UAAyB;AACtC,aAAW;AACX,QAAM,WAAW,MAAM,WAAW;AAClC,QAAM,GAAG,KAAK,qBAAqB,CAAC;AAEpC,QAAM,SAAS,MAAM,OAAO;AAAA,IAC1B,SAAS;AAAA,IACT,cAAc,SAAS;AAAA,IACvB,SAAS;AAAA,MACP,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,+CAA+C;AAAA,MACrF,EAAE,OAAO,cAAc,OAAO,eAAe,MAAM,uDAAuD;AAAA,MAC1G,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,sCAAsC;AAAA,IAC9E;AAAA,EACF,CAAC;AACD,MAAI,SAAS,MAAM,EAAG,QAAO,OAAO,kBAAkB;AAEtD,QAAM,SAAS,MAAM,YAAY;AAAA,IAC/B,SAAS;AAAA,IACT,UAAU;AAAA,IACV,eAAe,CAAC,SAAS,YAAY;AAAA,IACrC,SAAS,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,GAAG,EAAE,IAAI,KAAK,GAAG,IAAI,IAAI,EAAE,MAAM,MAAM,CAAC,IAAI,MAAM,EAAE,YAAY,EAAE;AAAA,EACxH,CAAC;AACD,MAAI,SAAS,MAAM,EAAG,QAAO,OAAO,kBAAkB;AACtD,QAAM,WAAW;AAEjB,MAAI,eAAe,SAAS,CAAC;AAC7B,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,IAAI,MAAM,OAAO;AAAA,MACrB,SAAS;AAAA,MACT,cAAc,SAAS,SAAS,SAAS,YAAY,IAAI,SAAS,eAAe,SAAS,CAAC;AAAA,MAC3F,SAAS,SAAS,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,EAAE;AAAA,IACvD,CAAC;AACD,QAAI,SAAS,CAAC,EAAG,QAAO,OAAO,kBAAkB;AACjD,mBAAe;AAAA,EACjB;AAEA,QAAM,SAA2B,EAAE,GAAG,gBAAgB,GAAG,UAAU,QAAgC,aAAa;AAChH,QAAM,WAAW,MAAM;AAEvB,QAAM,EAAE,KAAK,OAAO,IAAI,MAAM,UAAU,SAAS;AACjD,OAAK,GAAG,GAAG,KAAK,GAAG,CAAC;AAAA,EAAK,GAAG,IAAI,MAAM,OAAO,EAAE,EAAE,CAAC,IAAI,qCAAgC;AAEtF,UAAQ,IAAI;AACZ,UAAQ,IAAI,GAAG,KAAK,iBAAiB,SAAS,MAAM,iBAAiB,WAAW,SAAS,SAAS,aAAa,QAAG,CAAC;AACnH,aAAW,QAAQ,UAAU;AAC3B,UAAM,UAAU,OAAO,QAAQ,UAAU,IAAI,GAAI,IAAI;AAAA,EACvD;AAEA,QAAM,GAAG,MAAM,iBAAiB,CAAC;AACjC,UAAQ,IAAI,cAAc,MAAM,OAAO,CAAC,EAAE;AAC1C,UAAQ,IAAI,cAAc,GAAG,KAAK,mBAAmB,CAAC,EAAE;AACxD,qBAAmB,oBAAoB,OAAO,IAAI,IAAI,GAAG;AAC3D;AAEA,eAAe,SAAS,MAMN;AAChB,aAAW;AACX,QAAM,SAAS,kBAAkB,MAAM,WAAW,CAAC;AACnD,MAAI,KAAK,KAAM,QAAO,OAAO,OAAO,KAAK,IAAI;AAC7C,MAAI,KAAK,KAAM,QAAO,OAAO,KAAK;AAClC,MAAI,KAAK,OAAQ,QAAO,SAAS,KAAK;AAItC,QAAM,gBAAgB,CAAC,KAAK,QAAQ,QAAQ,IAAI,eAAe,EAC5D,IAAI,CAAC,OAAO,KAAK,IAAI,KAAK,CAAC,EAC3B,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAE7B,QAAM,QAAQ,aAAa,KAAK,SAAS,OAAO,cAAc,OAAO,YAAY;AACjF,QAAM,aAAa,OAAO,WAAW,gBAAgB,QAAQ,IAAI,0BAA0B;AAE3F,UAAQ,IAAI,GAAG,IAAI,uBAAuB,OAAO,MAAM,SAAI,CAAC;AAC5D,QAAM,YAAY,MAAM,aAAa;AAAA,IACnC,QAAQ,OAAO;AAAA,IACf;AAAA,IACA;AAAA,IACA,OAAO,CAAC,MAAM,QAAQ,IAAI,GAAG,IAAI,OAAO,CAAC,CAAC;AAAA,EAC5C,CAAC;AACD,UAAQ,IAAI,GAAG,IAAI,KAAK,UAAU,MAAM,EAAE,CAAC;AAE3C,QAAM,KAAK,cAAc,SAAS,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;AACzD,MAAI;AACF,UAAM,UAAU,OAAO,YAAY,GAAG,UAAU;AAAA,EAClD,UAAE;AACA,OAAG,KAAK;AAAA,EACV;AAEA,QAAM,QAAQ,oBAAI,IAAiC,CAAC,CAAC,MAAM,MAAM,UAAU,MAAM,CAAC,CAAC;AACnF,QAAM,YAAY,OAAO,SAA+C;AACtE,UAAM,SAAS,MAAM,IAAI,IAAI;AAC7B,QAAI,OAAQ,QAAO;AACnB,UAAM,OAAO,UAAU,IAAI,KAAK;AAChC,UAAM,MAAM,UAAU,OAAO,SAAS,IAAI;AAC1C,UAAM,IAAI,MAAM,GAAG;AACnB,WAAO;AAAA,EACT;AAEA,QAAM,MAAqB;AAAA,IACzB;AAAA,IACA,eAAe,UAAU;AAAA,IACzB,aAAa,UAAU,OAAO,SAAS;AAAA,IACvC,SAAS;AAAA,IACT;AAAA,IACA;AAAA,EACF;AACA,QAAM,EAAE,IAAI,IAAI,MAAM,YAAY,GAAG;AAErC,UAAQ,IAAI;AACZ,UAAQ;AAAA,IACN,KAAK,GAAG,MAAM,QAAG,CAAC,IAAI,GAAG,KAAK,aAAa,CAAC,OAAO,GAAG,KAAK,GAAG,CAAC,KAAK,GAAG,IAAI,MAAG,CAAC,WAAW,GAAG;AAAA,MAC3F,UAAU,OAAO,SAAS;AAAA,IAC5B,CAAC,IAAI,GAAG,IAAI,MAAG,CAAC,UAAU,GAAG,KAAK,MAAM,IAAI,CAAC;AAAA,EAC/C;AACA,MAAI,cAAc,QAAQ;AACxB,YAAQ,IAAI,KAAK,GAAG,MAAM,QAAG,CAAC,mCAAmC,GAAG,KAAK,6BAA6B,CAAC,EAAE;AAAA,EAC3G,WAAY,MAAM,gBAAgB,MAAO,GAAG;AAC1C,YAAQ;AAAA,MACN,KAAK,GAAG,OAAO,GAAG,CAAC,+BAA0B,GAAG,KAAK,0BAA0B,CAAC,kBAAkB,GAAG,KAAK,mBAAmB,CAAC;AAAA,IAChI;AAAA,EACF;AAEA,qBAAmB,KAAK,cAAc,CAAC,CAAC;AAC1C;AAEA,eAAe,gBAA+B;AAC5C,QAAM,SAAS,MAAM,WAAW;AAChC,UAAQ,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,IAAI,iCAA4B,CAAC;AACvE,aAAW,KAAK,QAAQ;AACtB,UAAM,OAAO,gBAAgB,CAAC,IAAI,GAAG,MAAM,QAAG,IAAI,GAAG,IAAI,MAAG;AAC5D,UAAM,MAAM,EAAE,SAAS,OAAO,eAAe,GAAG,KAAK,aAAa,IAAI;AACtE,YAAQ,IAAI,KAAK,IAAI,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC,IAAI,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,QAAQ,GAAG,IAAI,EAAE,WAAW,CAAC,GAAG,GAAG,EAAE;AAAA,EACjH;AACF;AAEA,eAAe,cAAc,MAA6B;AACxD,QAAM,QAAQ,UAAU,IAAI;AAC5B,MAAI,CAAC,OAAO;AACV,YAAQ,MAAM,GAAG,IAAI,kBAAkB,IAAI,qCAAqC,CAAC;AACjF,YAAQ,WAAW;AACnB;AAAA,EACF;AACA,QAAM,SAAS,MAAM,WAAW;AAChC,QAAM,UAAU,OAAO,QAAQ,OAAO,IAAI;AAC1C,UAAQ,IAAI,GAAG,MAAM,YAAO,IAAI,QAAQ,CAAC;AAC3C;AAEA,eAAe,YAAY,MAA6B;AACtD,QAAM,QAAQ,UAAU,IAAI;AAC5B,MAAI,CAAC,OAAO;AACV,YAAQ,MAAM,GAAG,IAAI,kBAAkB,IAAI,IAAI,CAAC;AAChD,YAAQ,WAAW;AACnB;AAAA,EACF;AACA,QAAM,IAAI,SAAS,KAAK;AACxB,MAAIC,IAAG,WAAW,CAAC,GAAG;AACpB,IAAAA,IAAG,OAAO,CAAC;AACX,YAAQ,IAAI,GAAG,MAAM,oBAAe,MAAM,QAAQ,EAAE,CAAC;AAAA,EACvD,OAAO;AACL,YAAQ,IAAI,GAAG,IAAI,2BAA2B,IAAI,6BAA6B,MAAM,MAAM,CAAC,GAAG,CAAC;AAAA,EAClG;AACF;AAEA,eAAe,eAAe,MAAwC;AACpE,aAAW;AACX,QAAM,EAAE,KAAK,OAAO,IAAI,MAAM,UAAU,KAAK,QAAQ,SAAS;AAC9D,cAAY,KAAK,OAAO,MAAM,OAAO,EAAE;AACvC,QAAM,SAAS,MAAM,WAAW;AAChC,qBAAmB,oBAAoB,OAAO,IAAI,IAAI,GAAG;AAC3D;AAEA,eAAe,aAA4B;AACzC,QAAM,OAAO,MAAM,SAAS;AAC5B,MAAI,CAAC,KAAK,QAAQ;AAChB,YAAQ,IAAI,GAAG,IAAI,qDAAqD,CAAC;AACzE;AAAA,EACF;AACA,aAAW,KAAK,MAAM;AACpB,UAAM,QAAQ,EAAE,UAAU,GAAG,IAAI,SAAS,IAAI,GAAG,MAAM,QAAQ;AAC/D,YAAQ;AAAA,MACN,KAAK,EAAE,MAAM,WAAM,KAAK,KAAK,GAAG,IAAI,EAAE,EAAE,CAAC,UAAU,EAAE,IAAI,aAAa,EAAE,UAAU,MAAM,GAAG,EAAE,CAAC,cAC5F,EAAE,aAAa,EAAE,WAAW,MAAM,GAAG,EAAE,IAAI,OAC7C;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,aAAa,YAAmC;AAC7D,QAAM,KAAK,MAAM,UAAU,UAAU;AACrC,UAAQ,IAAI,KAAK,GAAG,MAAM,oBAAe,UAAU,EAAE,IAAI,GAAG,OAAO,2BAA2B,UAAU,EAAE,CAAC;AAC7G;AAEA,eAAe,YAA2B;AACxC,QAAM,SAAS,kBAAkB,MAAM,WAAW,CAAC;AACnD,QAAM,YAAY,OAAO,OAAO,eAAe,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAClE,QAAM,MAAM,oBAAoB;AAChC,UAAQ,IAAI,GAAG,KAAK,sBAAsB,CAAC;AAC3C,UAAQ,IAAI,iBAAiB,QAAQ,CAAC,EAAE;AACxC,UAAQ,IAAI,iBAAiB,OAAO,MAAM,EAAE;AAC5C,UAAQ,IAAI,iBAAiB,OAAO,YAAY,EAAE;AAClD,UAAQ,IAAI,iBAAiB,OAAO,IAAI,IAAI,OAAO,IAAI,EAAE;AACzD,UAAQ,IAAI,iBAAiB,OAAO,UAAU,GAAG,MAAM,OAAO,UAAU,UAAU,UAAU;AAC5F,UAAQ,IAAI,iBAAiB,UAAU,SAAS,UAAU,KAAK,IAAI,IAAI,GAAG,IAAI,mBAAmB,CAAC,EAAE;AACpG,UAAQ,IAAI,iBAAiB,MAAM,gBAAgB,CAAC,SAAS;AAC7D,UAAQ,IAAI,iBAAiB,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,2CAA2C,CAAC,EAAE;AAC1G;AAEA,eAAe,iBAAgC;AAC7C,UAAQ,IAAI,GAAG,KAAK,0CAAqC,CAAC;AAC1D,MAAI;AACF,UAAM,MAAM,MAAM,gBAAgB,CAAC,MAAM,QAAQ,IAAI,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC;AACtE,YAAQ,IAAI,GAAG,MAAM,mBAAc,GAAG,EAAE,CAAC;AAAA,EAC3C,SAAS,GAAG;AACV,YAAQ,MAAM,GAAG,IAAI,mBAAoB,EAAY,OAAO,EAAE,CAAC;AAC/D,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,SAAS,eAAwB;AAC/B,QAAMC,WAAU,IAAI,QAAQ;AAC5B,EAAAA,SACG,KAAK,aAAa,EAClB,YAAY,qEAAqE,EACjF,QAAQ,SAAS,eAAe,EAChC,mBAAmB;AAEtB,EAAAA,SAAQ,QAAQ,MAAM,EAAE,YAAY,sEAAsE,EAAE,OAAO,OAAO;AAE1H,EAAAA,SACG,QAAQ,OAAO,EACf,YAAY,sBAAsB,EAClC,OAAO,qBAAqB,mBAAmB,EAC/C,OAAO,iBAAiB,cAAc,EACtC,OAAO,sBAAsB,kCAAkC,EAC/D,OAAO,yBAAyB,0BAA0B,EAC1D,OAAO,yBAAyB,kEAAkE,EAClG,OAAO,QAAQ;AAElB,QAAM,SAASA,SAAQ,QAAQ,QAAQ,EAAE,YAAY,mCAAmC;AACxF,SAAO,QAAQ,MAAM,EAAE,YAAY,qCAAqC,EAAE,OAAO,aAAa;AAC9F,SAAO,QAAQ,aAAa,EAAE,YAAY,2CAA2C,EAAE,OAAO,aAAa;AAC3G,SAAO,QAAQ,WAAW,EAAE,YAAY,gCAAgC,EAAE,OAAO,WAAW;AAE5F,QAAM,MAAMA,SAAQ,QAAQ,KAAK,EAAE,YAAY,wBAAwB;AACvE,MAAI,QAAQ,UAAU,EAAE,YAAY,wBAAwB,EAAE,OAAO,qBAAqB,mBAAmB,EAAE,OAAO,cAAc;AACpI,MAAI,QAAQ,MAAM,EAAE,YAAY,eAAe,EAAE,OAAO,UAAU;AAClE,MAAI,QAAQ,qBAAqB,EAAE,YAAY,8BAA8B,EAAE,OAAO,YAAY;AAElG,EAAAA,SAAQ,QAAQ,QAAQ,EAAE,YAAY,oCAAoC,EAAE,OAAO,SAAS;AAC5F,EAAAA,SAAQ,QAAQ,cAAc,EAAE,YAAY,gDAAgD,EAAE,OAAO,cAAc;AAEnH,SAAOA;AACT;AAEA,IAAM,UAAU,aAAa;AAC7B,IAAI,QAAQ,KAAK,MAAM,CAAC,EAAE,WAAW,GAAG;AACtC,UAAQ,WAAW;AACnB,UAAQ,KAAK,CAAC;AAChB;AACA,QAAQ,WAAW,QAAQ,IAAI,EAAE,MAAM,CAAC,QAAe;AACrD,UAAQ,MAAM,GAAG,IAAI,IAAI,OAAO,CAAC;AACjC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["fs","path","fs","path","path","fs","fs","fsp","fsp","fs","fs","path","crypto","path","crypto","fs","pipeline","spawn","fs","fsp","os","path","crypto","path","crypto","os","fsp","spawn","spawn","fs","os","path","os","path","fs","spawn","fs","crypto","crypto","fs","path","crypto","path","crypto","fs","fs","note","path","fs","program"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "whisper-api",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Self-hostable, OpenAI-compatible Whisper speech-to-text API server you can run anywhere with npx. Local inference via whisper.cpp or ONNX (transformers.js).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0-or-later",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"typecheck": "tsc --noEmit",
|
|
50
50
|
"test": "vitest run",
|
|
51
51
|
"test:watch": "vitest",
|
|
52
|
+
"version": "node scripts/sync-version.mjs && git add src/version.ts",
|
|
52
53
|
"prepublishOnly": "npm run build && npm test"
|
|
53
54
|
},
|
|
54
55
|
"dependencies": {
|
|
@@ -73,6 +74,9 @@
|
|
|
73
74
|
"typescript": "^6.0.3",
|
|
74
75
|
"vitest": "^4.1.9"
|
|
75
76
|
},
|
|
77
|
+
"overrides": {
|
|
78
|
+
"esbuild": "^0.28.1"
|
|
79
|
+
},
|
|
76
80
|
"publishConfig": {
|
|
77
81
|
"access": "public"
|
|
78
82
|
}
|