Sign in

    whisper

    MoonBit native bindings for whisper.cpp speech-to-text inference

    whisper
    speech-to-text
    native
    ffi
    Download zip
    Author
    Version
    0.3.1
    License
    MIT
    Last updated
    8 months ago
    Downloads
    55

    Dependencies

    #whisper

    MoonBit native bindings for whisper.cpp — speech-to-text inference.

    #Prerequisites

    #Quick Start (standalone)

    git clone --recursive https://github.com/mizchi/whisper-mbt.git cd whisper-mbt # Build whisper.cpp and download model just setup # Run WHISPER_MODEL=models/ggml-base.bin \ WHISPER_WAV=vendor/whisper.cpp/samples/jfk.wav \ moon run src/main --target native

    #Use as a dependency

    #1. Add the package

    From mooncakes registry (when published):

    moon add mizchi/whisper

    Or as a local path dependency in moon.mod.json:

    { "name": "your/project", "deps": { "mizchi/whisper": { "path": "/path/to/whisper" } }, "preferred-target": "native" }

    #2. Build whisper.cpp

    Build whisper.cpp somewhere on your system:

    git clone https://github.com/ggml-org/whisper.cpp.git cd whisper.cpp # macOS (Metal) cmake -B build -DCMAKE_BUILD_TYPE=Release \ -DGGML_METAL=ON -DGGML_METAL_EMBED_LIBRARY=ON \ -DBUILD_SHARED_LIBS=OFF \ -DWHISPER_BUILD_EXAMPLES=OFF -DWHISPER_BUILD_TESTS=OFF -DWHISPER_BUILD_SERVER=OFF cmake --build build --config Release -j$(sysctl -n hw.logicalcpu) # Linux (CPU only) cmake -B build -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DWHISPER_BUILD_EXAMPLES=OFF -DWHISPER_BUILD_TESTS=OFF -DWHISPER_BUILD_SERVER=OFF cmake --build build --config Release -j$(nproc)

    #3. Configure your main package

    In your main package's moon.pkg, import the library and add link flags pointing to the whisper.cpp build:

    // cmd/main/moon.pkg import { "mizchi/whisper" @whisper, } options( "is-main": true, link: { "native": { // macOS (Metal + Accelerate) "cc-link-flags": "/path/to/whisper.cpp/build/src/libwhisper.a /path/to/whisper.cpp/build/ggml/src/libggml.a /path/to/whisper.cpp/build/ggml/src/libggml-base.a /path/to/whisper.cpp/build/ggml/src/libggml-cpu.a /path/to/whisper.cpp/build/ggml/src/ggml-metal/libggml-metal.a /path/to/whisper.cpp/build/ggml/src/ggml-blas/libggml-blas.a -lstdc++ -framework Accelerate -framework Metal -framework Foundation -framework MetalKit", }, }, "supported-targets": [ "native" ], )

    For Linux (CPU only):

    "cc-link-flags": "/path/to/whisper.cpp/build/src/libwhisper.a /path/to/whisper.cpp/build/ggml/src/libggml.a /path/to/whisper.cpp/build/ggml/src/libggml-base.a /path/to/whisper.cpp/build/ggml/src/libggml-cpu.a -lstdc++ -lm -lpthread"

    Note: cc-link-flags requires absolute paths or paths relative to the project root where moon build is invoked.

    #4. Download a model

    # ggml-base (147 MB) curl -L -o models/ggml-base.bin \ https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.bin

    See whisper.cpp models for other sizes (tiny, small, medium, large).

    #5. Use

    fn main {
    let ctx = @whisper.WhisperContext::init("models/ggml-base.bin")
    match ctx {
    None => println("Failed to load model")
    Some(ctx) => {
    let segments = ctx.transcribe("audio.wav", language="auto")
    for i = 0; i < segments.length(); i = i + 1 {
    println(segments[i].text)
    }
    ctx.free()
    }
    }
    }

    #API

    #WhisperContext

    WhisperContext::init(model_path : String) -> WhisperContext?
    WhisperContext::transcribe(self, wav_path, language?="en", translate?=false, n_threads?=4, ...) -> Array[Segment]
    WhisperContext::transcribe_parallel(self, wav_path, n_processors?=4, ...) -> Array[Segment]
    WhisperContext::get_tokens(self, segment_index) -> Array[TokenData]
    WhisperContext::token_count(self, text) -> Int
    WhisperContext::tokenize(self, text, max_tokens?=512) -> Array[Int]
    WhisperContext::detect_language(self, wav_path, n_threads?=4) -> String
    WhisperContext::detect_language_with_probs(self, wav_path, n_threads?=4) -> Array[LangProb]
    WhisperContext::model_info(self) -> ModelInfo
    WhisperContext::detected_language(self) -> String // after transcribe()
    WhisperContext::get_timings(self) -> Timings
    WhisperContext::print_timings(self) -> Unit
    WhisperContext::free(self) -> Unit

    #Utility functions

    lang_id(lang : String) -> Int // "en" -> 0
    lang_str(id : Int) -> String // 0 -> "en"
    lang_str_full(id : Int) -> String // 0 -> "english"
    lang_max_id() -> Int // max language id (98)
    system_info() -> String // CPU/GPU feature info

    #Types

    struct Segment { text: String, t0: Int64, t1: Int64, no_speech_prob: Double, speaker_turn_next: Bool }
    struct TokenData { text: String, id: Int, prob: Double, t0: Int64, t1: Int64 }
    struct LangProb { lang: String, lang_full: String, prob: Double }
    struct ModelInfo { model_type: String, is_multilingual: Bool, n_vocab: Int, n_text_ctx: Int, n_audio_ctx: Int }
    struct Timings { sample_ms: Double, encode_ms: Double, decode_ms: Double, batchd_ms: Double, prompt_ms: Double }
    struct VadParams { threshold: Double, min_speech_duration_ms: Int, min_silence_duration_ms: Int, max_speech_duration_s: Double, speech_pad_ms: Int }
    enum Strategy { Greedy; BeamSearch }

    #transcribe options

    ParameterTypeDefaultDescription
    languageString"en"Language code or "auto"
    translateBoolfalseTranslate to English
    n_threadsInt4Number of threads
    offset_msInt0Start offset in ms
    duration_msInt0Duration to process (0 = all)
    no_timestampsBoolfalseDisable timestamps
    single_segmentBoolfalseForce single segment
    token_timestampsBoolfalseToken-level timestamps
    max_lenInt0Max segment length (chars)
    max_tokensInt0Max tokens per segment
    initial_promptString""Initial prompt
    temperatureDouble0.0Decoding temperature
    strategyStrategyGreedyGreedy or BeamSearch
    beam_sizeInt5Beam size (when BeamSearch)
    no_contextBoolfalseDisable past context
    vad_model_pathString""Path to Silero VAD model (enables VAD)
    vad_paramsVadParams?NoneVAD tuning parameters

    #VAD (Voice Activity Detection)

    VAD skips silence and processes only speech segments. Requires a separate Silero VAD model:

    curl -L -o models/ggml-silero-v5.1.2.bin \ https://huggingface.co/ggml-org/whisper-vad/resolve/main/ggml-silero-v5.1.2.bin

    let segments = ctx.transcribe(
    "audio.wav",
    language="auto",
    vad_model_path="models/ggml-silero-v5.1.2.bin",
    )

    #Tokenization

    let count = ctx.token_count("Hello world") // 2
    let ids = ctx.tokenize("Hello world") // [15947, 1002]

    #Language detection

    Auto-detect spoken language from audio without full transcription:

    let lang = ctx.detect_language("audio.wav") // "en"

    // With probabilities for all languages
    let probs = ctx.detect_language_with_probs("audio.wav")
    for i = 0; i < probs.length(); i = i + 1 {
    let p = probs[i]
    println(p.lang + " (" + p.lang_full + "): " + p.prob.to_string())
    }

    #Parallel inference

    Splits audio across multiple processors for faster throughput:

    let segments = ctx.transcribe_parallel(
    "long_audio.wav",
    n_processors=4,
    language="auto",
    )

    #Updating vendored headers

    When upgrading the whisper.cpp submodule:

    just build-whisper just update-headers

    #License

    MIT

    LangProb

    pub struct LangProb {
    lang : String
    lang_full : String
    prob : Double
    }

    impl Show for LangProb

    ModelInfo

    pub struct ModelInfo {
    model_type : String
    is_multilingual : Bool
    n_vocab : Int
    n_text_ctx : Int
    n_audio_ctx : Int
    }

    impl Show for ModelInfo

    Segment

    pub struct Segment {
    text : String
    t0 : Int64
    t1 : Int64
    no_speech_prob : Double
    speaker_turn_next : Bool
    }

    impl Show for Segment

    Strategy

    pub(all) enum Strategy {
    Greedy
    BeamSearch
    }
    Sampling strategy for whisper decoding. Greedy (default) or BeamSearch with configurable beam size.
    impl Show for Strategy

    Timings

    pub struct Timings {
    sample_ms : Double
    encode_ms : Double
    decode_ms : Double
    batchd_ms : Double
    prompt_ms : Double
    }

    impl Show for Timings

    TokenData

    pub struct TokenData {
    text : String
    id : Int
    prob : Double
    t0 : Int64
    t1 : Int64
    }

    impl Show for TokenData

    VadParams

    pub struct VadParams {
    threshold : Double
    min_speech_duration_ms : Int
    min_silence_duration_ms : Int
    max_speech_duration_s : Double
    speech_pad_ms : Int
    }

    impl Show for VadParams

    VadParams::default

    fn VadParams::default() -> VadParams

    WhisperContext

    pub struct WhisperContext {
    // private fields
    }

    WhisperContext::detect_language

    fn WhisperContext::detect_language(self : WhisperContext, wav_path : String, n_threads? : Int) -> String

    WhisperContext::detect_language_with_probs

    fn WhisperContext::detect_language_with_probs(self : WhisperContext, wav_path : String, n_threads? : Int) -> Array[LangProb]

    WhisperContext::detected_language

    fn WhisperContext::detected_language(self : WhisperContext) -> String

    WhisperContext::free

    fn WhisperContext::free(self : WhisperContext) -> Unit

    WhisperContext::get_timings

    fn WhisperContext::get_timings(self : WhisperContext) -> Timings

    WhisperContext::get_tokens

    fn WhisperContext::get_tokens(self : WhisperContext, segment_index : Int) -> Array[TokenData]

    WhisperContext::init

    fn WhisperContext::init(model_path : String) -> WhisperContext?

    WhisperContext::model_info

    fn WhisperContext::model_info(self : WhisperContext) -> ModelInfo

    WhisperContext::print_timings

    fn WhisperContext::print_timings(self : WhisperContext) -> Unit

    WhisperContext::reset_timings

    fn WhisperContext::reset_timings(self : WhisperContext) -> Unit

    WhisperContext::token_count

    fn WhisperContext::token_count(self : WhisperContext, text : String) -> Int

    WhisperContext::tokenize

    fn WhisperContext::tokenize(self : WhisperContext, text : String, max_tokens? : Int) -> Array[Int]

    WhisperContext::transcribe

    fn WhisperContext::transcribe(self : WhisperContext, wav_path : String, language? : String, translate? : Bool, n_threads? : Int, offset_ms? : Int, duration_ms? : Int, no_timestamps? : Bool, single_segment? : Bool, token_timestamps? : Bool, max_len? : Int, max_tokens? : Int, audio_ctx? : Int, initial_prompt? : String, temperature? : Double, print_progress? : Bool, strategy? : Strategy, beam_size? : Int, no_context? : Bool, vad_model_path? : String, vad_params? : VadParams?) -> Array[Segment]

    WhisperContext::transcribe_parallel

    fn WhisperContext::transcribe_parallel(self : WhisperContext, wav_path : String, n_processors? : Int, language? : String, translate? : Bool, n_threads? : Int, offset_ms? : Int, duration_ms? : Int, no_timestamps? : Bool, single_segment? : Bool, token_timestamps? : Bool, max_len? : Int, max_tokens? : Int, audio_ctx? : Int, initial_prompt? : String, temperature? : Double, print_progress? : Bool, strategy? : Strategy, beam_size? : Int, no_context? : Bool, vad_model_path? : String, vad_params? : VadParams?) -> Array[Segment]

    lang_id

    fn lang_id(lang : String) -> Int

    lang_max_id

    fn lang_max_id() -> Int

    lang_str

    fn lang_str(id : Int) -> String

    lang_str_full

    fn lang_str_full(id : Int) -> String

    system_info

    fn system_info() -> String

    Source Files