gowhisper

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2026 License: MIT Imports: 11 Imported by: 0

README

go-whisper

A small Go library for on-device speech-to-text: record from the microphone and transcribe with whisper.cpp. No audio leaves the machine and there is no API key.

Recording and transcription are separate interfaces (Recorder, Transcriber) so they can run in different processes — for example, capture in a foreground app that holds the microphone permission, transcribe in a long-lived daemon that keeps the model loaded.

The current backends shell out to ffmpeg and whisper-cli. A CGO-linked whisper backend can be added behind the Transcriber interface without changing callers.

Requirements

  • macOS (the recorder uses ffmpeg's avfoundation input)
  • ffmpegbrew install ffmpeg
  • whisper.cppbrew install whisper-cpp (provides whisper-cli)
  • A ggml model, e.g. ggml-base.bin from huggingface.co/ggerganov/whisper.cpp

Install

go get github.com/diegosalasmartinez/go-whisper

Usage

recorder := gowhisper.NewFFmpegRecorder()
transcriber := gowhisper.NewCLITranscriber("/path/to/ggml-base.bin")

// Record until ctx is cancelled (or the recorder's cap is hit).
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

wav, err := recorder.Record(ctx)
if err != nil {
	log.Fatal(err)
}
defer os.Remove(wav)

text, err := transcriber.Transcribe(context.Background(), wav)
if err != nil {
	log.Fatal(err)
}
fmt.Println(text)

Both types expose their configuration as fields (binary path, audio device, sample rate, language, threads) with sensible defaults from the constructors.

Recording stops when the context is cancelled, so an interactive caller can start recording on one keypress and stop on the next by cancelling the context.

Native backend (CGO)

The default CLITranscriber shells out to whisper-cli. An optional in-process backend links whisper.cpp directly, loading the model once and reusing it across calls. It is behind the whisper_cgo build tag, so the default build stays CGO-free.

tr, err := gowhisper.NewNativeTranscriber("/path/to/ggml-base.bin")
if err != nil {
	log.Fatal(err)
}
defer tr.Close()
text, err := tr.Transcribe(ctx, wav)

Build and test it with the tag:

go build -tags whisper_cgo ./...
go test  -tags whisper_cgo ./...

Requirements: whisper-cpp installed with its headers and libraries (Homebrew provides them under /opt/homebrew), and CGO enabled. The #cgo directives in transcriber_native.go point at the Homebrew paths; adjust them for other prefixes. On Apple Silicon this requires a native arm64 Go toolchain — an amd64 (Rosetta) toolchain cannot link the arm64 whisper libraries.

Example

go run ./example --model /path/to/ggml-base.bin --seconds 5

Records for five seconds and prints the transcript. Use it to confirm ffmpeg and whisper.cpp are installed and the microphone works.

Finding the audio device

List avfoundation inputs and set FFmpegRecorder.Device accordingly:

ffmpeg -f avfoundation -list_devices true -i ""

The default is :0 (first audio input).

License

MIT. See LICENSE.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CLITranscriber

type CLITranscriber struct {
	Binary   string // whisper.cpp CLI; defaults to "whisper-cli"
	Model    string // path to a ggml model; required
	Language string // language code or "auto"; defaults to "auto"
	Threads  int    // worker threads; 0 leaves the whisper.cpp default
}

CLITranscriber shells out to the whisper.cpp command-line tool. It is the quick-to-run backend; a CGO-linked backend can replace it behind this same interface without changing callers.

func NewCLITranscriber

func NewCLITranscriber(model string) *CLITranscriber

func (*CLITranscriber) Transcribe

func (t *CLITranscriber) Transcribe(ctx context.Context, wavPath string) (string, error)

type FFmpegRecorder

type FFmpegRecorder struct {
	Binary     string // ffmpeg executable; defaults to "ffmpeg"
	Device     string // avfoundation audio device; defaults to ":0"
	SampleRate int    // output sample rate in Hz; defaults to 16000
	MaxSeconds int    // hard cap on recording length; defaults to 60
}

FFmpegRecorder records from a macOS avfoundation input device using ffmpeg.

func NewFFmpegRecorder

func NewFFmpegRecorder() *FFmpegRecorder

func (*FFmpegRecorder) Record

func (r *FFmpegRecorder) Record(ctx context.Context) (string, error)

type FakeRecorder

type FakeRecorder struct {
	Path string
	Err  error
}

FakeRecorder returns a fixed path, for tests that don't touch a microphone.

func (FakeRecorder) Record

func (f FakeRecorder) Record(context.Context) (string, error)

type FakeTranscriber

type FakeTranscriber struct {
	Text string
	Err  error
	Seen []string
}

FakeTranscriber returns fixed text and records the WAV paths it was given.

func (*FakeTranscriber) Transcribe

func (f *FakeTranscriber) Transcribe(_ context.Context, wavPath string) (string, error)

type Recorder

type Recorder interface {
	// Record captures audio until ctx is cancelled (or an internal cap is
	// reached), then returns the path to a 16 kHz mono WAV file. The caller owns
	// the file and is responsible for removing it.
	Record(ctx context.Context) (string, error)
}

Recorder captures microphone audio to a WAV file.

type Transcriber

type Transcriber interface {
	Transcribe(ctx context.Context, wavPath string) (string, error)
}

Transcriber converts a WAV file into text.

Directories

Path Synopsis
Command example records a few seconds of microphone audio and prints the transcript.
Command example records a few seconds of microphone audio and prints the transcript.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL