Quick start: files
import { Alkove } from 'alkove'
const r = await Alkove.process(file, { focus: true, cue: true })r.audio // Float32Array, 16 kHz, the voice onlyr.speech // [{ start, end }] in secondsconst wav = new Blob([r.toWav()], { type: 'audio/wav' })Alkove.process decodes the file, resamples it to 16 kHz and runs the models you ask for, faster than real time. In a browser it runs in the background worker, off your main thread. Focus and Cue follow the same rules as in a live input, so a recording sounds the way it would have sounded live.
What you can pass
Section titled “What you can pass”- a
BloborFile, anArrayBufferor aUint8Array: any format the browser can decode (in Node, WAV only); - an
AudioBuffer; { pcm, rate }: monoFloat32Arraysamples and their sample rate, for audio you decoded yourself.
Stereo is mixed down to mono.
What you can ask for
Section titled “What you can ask for”const r = await Alkove.process(file, { focus: { voiceprint: print }, // or true: keep the closest voice cue: true, // speech segments in r.speech spot: { words: [word] }, // detections in r.wakes})focus:truekeeps the closest voice.{ voiceprint }keeps one person;{ strength }mixes Focus with the original (1 by default). Withoutfocus,r.audiois the input, resampled.cue: speech segments.true, or the speech parameters to tune (SpeechParams). Withfocus, Cue listens to Focus’s output.spot:{ words, context }, the words to find. Withfocus, Spot listens behind Focus.contextis'anywhere'by default here.normalize: level the voice as a call input does. Off by default for files.trace: per-frame values of each model inr.trace, for debugging.signal: anAbortSignalto cancel.
The result holds audio (processed) and raw (the input at 16 kHz), both the same length, plus speech, wakes and diag. r.toWav() encodes a 16 kHz WAV: 'audio' by default, 'raw', or 'both' for a stereo file with the input on the left and the output on the right, handy to compare. All fields: ProcessOptions and ProcessResult.
Long files: Alkove.stream
Section titled “Long files: Alkove.stream”For an hour of audio, do not hold it all in memory. Alkove.stream takes blocks in and gives parts out, with the same result as process on the whole:
for await (const part of Alkove.stream(blocks, { rate: 48000, focus: true, cue: true })) { out.write(part.audio) // 16 kHz for (const s of part.speech) console.log('speech', s.start, s.end)}blocks is an async iterable or a ReadableStream of mono Float32Array blocks at rate (16000 by default). Each part has start (seconds from the stream’s start), its audio, and the speech, wakes and diag found while it went through. The last part flushes what is still inside the models.
In Node
Section titled “In Node”The same WebAssembly engine runs in Node, in your thread. Copy the models once, then read them from disk:
npx alkove models ./modelsimport { readFile, writeFile } from 'node:fs/promises'import { Alkove } from 'alkove'
Alkove.configure({ modelDir: './models' })const r = await Alkove.process(await readFile('call.wav'), { focus: true, cue: true })await writeFile('call.clean.wav', r.toWav())Node decodes WAV only. For MP3, Opus or anything else, decode the file with your own tool and pass { pcm, rate }; outside a browser, other formats reject with AlkoveError code browser.unsupported.
Without modelDir, Node downloads the models from Hugging Face on every run (there is no cache outside the browser).
The CLI
Section titled “The CLI”The package ships one command, to copy what your installed version loads into a folder:
npx alkove models <dir> [focus cue spot timbre lex]It downloads the models at the revision pinned by your version, checks their sha256, and copies alkove-engine.wasm, alkove-worker.js and alkove-worklet.js next to them. Name models to copy only those; with none, it copies all five. Use the folder as modelDir in Node, or serve it and set modelBaseUrl and assetBaseUrl in the browser (see Self-hosting the models).
Voiceprints and words for files
Section titled “Voiceprints and words for files”focus.voiceprint and spot.words take the same values as the live inputs: a Voiceprint or its JSON, a compiled word or its JSON. Make a print from a few seconds of the person’s voice with Timbre:
import { Timbre } from 'alkove'
const timbre = await Timbre.create()const print = await timbre.embed(sample) // Float32Array at 16 kHz, 1.5 s or moreSee Voiceprints and Primitives.