Getting started
Scenario
You have never run gigastt and want a working local transcription in about five minutes: install the binary, download the GigaAM v3 model, transcribe a first audio file — on macOS, Linux, or in Docker. This chapter is the whole path; you should not need any other document to get here.
Prerequisites
- Disk: ~1.5 GB free (model + tools). The lean
--prequantizedpath needs only ~250 MB during setup. - RAM: ~800 MB free at the default
--pool-size 2(~400 MB per session). - Network (unless you follow the air-gapped recipe): reach either
huggingface.co(full model) orgithub.com(pre-quantized bundle). - An audio file to transcribe — WAV, M4A, MP3, OGG, or FLAC. Any short recording of Russian speech works.
- Only for
cargo install(build from source): Rust 1.88+ andprotoconPATH(brew install protobuf/apt install protobuf-compiler).
Pick one recipe below — macOS, Linux, Windows, Docker, or air-gapped — then read Choosing the recognition head and The expensive first run once.
Recipe: macOS (Homebrew)
Homebrew is the fastest path on Apple Silicon (the tap ships a CoreML-enabled
binary). On an Intel Mac use cargo install gigastt instead — see the Linux
recipe for the protoc prerequisite.
brew tap ekhodzitsky/gigastt https://github.com/ekhodzitsky/gigastt
brew install gigastt
# Fetch the model (~850 MB FP32 from HuggingFace, then a one-time ~2 min
# INT8 quantization pass — see "The expensive first run" below):
gigastt download
# Transcribe your first file:
gigastt transcribe recording.wav
Verify: the last command prints the recognized text on stdout, e.g.
$ gigastt transcribe recording.wav
Привет, как дела?
and ls ~/.gigastt/models/ shows v3_rnnt_encoder_int8.onnx,
v3_rnnt_decoder.onnx, v3_rnnt_joint.onnx, and v3_vocab.txt.
Recipe: Linux (prebuilt binary or cargo)
Option A — prebuilt binary (no Rust toolchain, no protoc). Each release
publishes tarballs for x86_64-unknown-linux-gnu and
aarch64-unknown-linux-gnu:
# Resolve the latest release tag (or set TAG=v2.14.1 by hand):
TAG=$(curl -fsSL https://api.github.com/repos/ekhodzitsky/gigastt/releases/latest \
| sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p')
VER=${TAG#v}
curl -fLO "https://github.com/ekhodzitsky/gigastt/releases/download/${TAG}/gigastt-${VER}-x86_64-unknown-linux-gnu.tar.gz"
curl -fLO "https://github.com/ekhodzitsky/gigastt/releases/download/${TAG}/gigastt-${VER}-x86_64-unknown-linux-gnu.tar.gz.sha256"
sha256sum -c "gigastt-${VER}-x86_64-unknown-linux-gnu.tar.gz.sha256"
tar xf "gigastt-${VER}-x86_64-unknown-linux-gnu.tar.gz"
sudo install -m 0755 gigastt /usr/local/bin/gigastt
(On ARM64 replace x86_64-unknown-linux-gnu with
aarch64-unknown-linux-gnu. Homebrew on Linux x86_64 — brew install gigastt after the tap from the macOS recipe — works too.)
Option B — cargo (any platform, needs Rust 1.88+ and protoc):
sudo apt install protobuf-compiler # Debian/Ubuntu; skip if protoc exists
cargo install gigastt
Then fetch the model — the lean way, a ~225 MB pre-quantized INT8 bundle from the pinned GitHub Release (no ~850 MB FP32 download, no ~2-minute on-device quantization; also handy when HuggingFace is unreachable but GitHub is not):
gigastt download --prequantized
gigastt transcribe recording.wav
Verify: gigastt transcribe recording.wav prints the recognized text on
stdout, and ls ~/.gigastt/models/ shows the v3_rnnt_* model files.
Recipe: Windows (prebuilt binary)
Every release publishes x86_64-pc-windows-msvc tarballs (CPU). PowerShell
5.1+ / Windows 10+ includes tar and curl:
$rel = Invoke-RestMethod https://api.github.com/repos/ekhodzitsky/gigastt/releases/latest
$TAG = $rel.tag_name # e.g. v2.14.1
$VER = $TAG.TrimStart('v')
$asset = "gigastt-$VER-x86_64-pc-windows-msvc.tar.gz"
$base = "https://github.com/ekhodzitsky/gigastt/releases/download/$TAG"
Invoke-WebRequest "$base/$asset" -OutFile $asset
Invoke-WebRequest "$base/$asset.sha256" -OutFile "$asset.sha256"
# Optional integrity check (hash file is "HASH filename"):
$expected = (Get-Content "$asset.sha256").Split()[0]
$actual = (Get-FileHash $asset -Algorithm SHA256).Hash.ToLower()
if ($actual -ne $expected.ToLower()) { throw "SHA-256 mismatch" }
tar xf $asset
# Put gigastt.exe on PATH, or call it by full path:
.\gigastt.exe download --prequantized
.\gigastt.exe transcribe recording.wav
Model directory on Windows defaults under the user profile
(%USERPROFILE%\.gigastt\models\). First serve still binds loopback only
(127.0.0.1:9876) until you pass --bind-all.
Verify: .\gigastt.exe transcribe recording.wav prints text; health after
.\gigastt.exe serve answers at http://127.0.0.1:9876/health.
Recipe: Docker
Prebuilt multi-arch images (amd64 + arm64) are published to GHCR for every
release; -cuda tags carry the CUDA variant:
docker pull ghcr.io/ekhodzitsky/gigastt:latest # pin :<version> in production
docker run -d --name gigastt \
-p 127.0.0.1:9876:9876 \
-v gigastt-models:/home/gigastt/.gigastt/models \
ghcr.io/ekhodzitsky/gigastt:latest
The named volume keeps the model across container restarts; without it the
container re-downloads ~850 MB on every recreation. On first start the
container downloads the model and quantizes it — the port binds immediately,
but inference is only up when /ready turns green:
# Wait until the model is loaded (503 while initializing):
until curl -sf http://127.0.0.1:9876/ready > /dev/null; do sleep 5; done
curl http://127.0.0.1:9876/health
Then transcribe a file from the host (the file path is on the host — curl
reads it, not the container):
curl -F file=@recording.wav http://127.0.0.1:9876/v1/transcribe
Verify: /health returns
{"status":"ok","model":"gigaam-v3-rnnt","variant":"rnnt","version":"2.14.1","punctuation":true,"itn":true}
(the version field reflects the image you pulled), and the POST returns a
JSON transcript:
{"text":"Привет, как дела?","words":[{"word":"привет","start":0.0,"end":0.4,"confidence":0.99}],"duration":1.2}
Recipe: air-gapped (offline bundle)
For hosts with no internet access, every release publishes a self-contained
offline bundle per Linux target — binary + pre-quantized INT8 rnnt model +
punctuation model + systemd unit + installer — plus two Debian packages with
the same content. Download them on a connected machine, carry them over,
install.
Tarball flow (any distro):
# On a connected machine (see the Linux recipe for resolving TAG/VER):
curl -fLO "https://github.com/ekhodzitsky/gigastt/releases/download/${TAG}/gigastt-${VER}-offline-x86_64-unknown-linux-gnu.tar.gz"
curl -fLO "https://github.com/ekhodzitsky/gigastt/releases/download/${TAG}/gigastt-${VER}-offline-x86_64-unknown-linux-gnu.tar.gz.sha256"
sha256sum -c "gigastt-${VER}-offline-x86_64-unknown-linux-gnu.tar.gz.sha256"
# On the target machine:
tar xf "gigastt-${VER}-offline-x86_64-unknown-linux-gnu.tar.gz"
cd "gigastt-${VER}-offline-x86_64-unknown-linux-gnu"
sudo ./install.sh # verifies SHA256SUMS, installs binary + model + unit
sudo systemctl enable --now gigastt
Debian flow: install gigastt_<ver>_amd64.deb (binary + unit) together with
gigastt-model-int8_<ver>_all.deb (the same model set), then
sudo systemctl enable --now gigastt.
The bundle deliberately omits optional pieces — speaker diarization and the
e2e_rnnt / ml_ctc heads. The installed unit runs with GIGASTT_OFFLINE=1,
so a missing optional model is a fast, instructive error naming the exact path
to fill (fetch it on a connected machine with gigastt download and copy the
file over), never a network timeout. The full contents list and signature
verification are in
packaging/offline/README-OFFLINE.md.
Verify: curl http://127.0.0.1:9876/health returns {"status":"ok",...}
with "model":"gigaam-v3-rnnt", and
gigastt transcribe sample.wav --model-dir /usr/share/gigastt/models prints
text (the flag is only needed when running uninstalled — the systemd unit
already points at the installed model).
Choosing the recognition head
gigastt ships four recognition heads; --model-variant picks one at
download / serve / transcribe time. When you omit the flag, an existing
model directory is used as-is (auto-detect), and a fresh install defaults to
rnnt.
| Head | Languages | Output style | Pick it when |
|---|---|---|---|
rnnt (default) | Russian | Bare lowercase from the acoustic model; casing + punctuation restored by an auto-downloaded RuPunct pass, digits by ITN | Default: lowest WER on Russian speech |
e2e_rnnt | Russian | Punctuation / casing / ITN baked into the acoustic model | You want one self-contained model with no post-processing passes |
ml_ctc | ru/en/kk/ky/uz | Bare lowercase, no restoration passes | Mixed Russian/English (or kk/ky/uz) speech; lighter 220M encoder |
ml_ctc_large | ru/en/kk/ky/uz | Bare lowercase, no restoration passes | Multilingual speech where accuracy matters more than footprint (600M encoder) |
The ml_ctc* heads download pre-quantized INT8 directly, so there is no
quantization step for them. Switching heads after install:
gigastt download --model-variant e2e_rnnt # fetch another head
gigastt serve --model-variant e2e_rnnt # and serve it explicitly
WER/RTF numbers per head are in docs/benchmarks.md; the deeper model/backend tour is in Models and backends.
The expensive first run
The very first gigastt download (or first gigastt serve, which
auto-downloads a missing model) does two one-time things:
- Downloads ~850 MB of FP32 ONNX files from HuggingFace
(SHA-256-verified, staged to
.partial, atomically renamed). - Quantizes the encoder to INT8 (~2 minutes, one-time), producing the ~225 MB encoder the engine actually loads. Later runs reuse it.
Three levers change what you pay:
gigastt download --prequantized— the recommended shortcut: fetch the ~225 MB pre-quantized INT8 bundle from the pinned GitHub Release. No FP32 download, no local quantization, noprotoc. Note it pulls fromgithub.com, nothuggingface.co— useful when one of the two is blocked.gigastt download --skip-quantize(orGIGASTT_SKIP_QUANTIZE=1onserve) — keep the FP32 encoder and skip quantization. The engine then loads FP32: slower inference and ~4× the model RAM. Only for debugging.- Nothing — just let the first
servedo it. The port binds immediately;/healthanswers200with"model":"loading"and/readyreturns503 {"reason":"initializing"}until the model is usable, so clients should gate on/ready, never on the process being alive.
Verifying the result
End-to-end checklist that works after any of the recipes above:
# 1. Model files are in place:
ls ~/.gigastt/models/
# v3_rnnt_encoder_int8.onnx v3_rnnt_decoder.onnx v3_rnnt_joint.onnx v3_vocab.txt ...
# 2. Offline transcription works (no server needed):
gigastt transcribe recording.wav
# → prints the recognized text on stdout
# 3. The server comes up and reports the loaded head:
gigastt serve & # Ctrl-C to stop; default http://127.0.0.1:9876
curl http://127.0.0.1:9876/ready # 200 once the model is loaded
curl http://127.0.0.1:9876/health
# {"status":"ok","model":"gigaam-v3-rnnt","variant":"rnnt","version":"...","punctuation":true,"itn":true}
# 4. REST transcription works:
curl -F file=@recording.wav http://127.0.0.1:9876/v1/transcribe
# → {"text":"...","words":[...],"duration":N}
Common pitfalls
protocnot found duringcargo installor a source build — install the Protocol Buffers compiler (brew install protobuf/apt install protobuf-compiler), or skip the toolchain entirely with the prebuilt binary / Homebrew.- First
servesits there for minutes — that is the one-time model download + INT8 quantization, not a hang:/healthreturns{"model":"loading"}meanwhile. Pre-seed withgigastt download --prequantizedand gate clients on/ready. Address already in useon port 9876 — find the holder withlsof -nP -tiTCP:9876 -sTCP:LISTEN; confirm it is gigastt (ps -p <pid> -o command=), thenkill <pid>(SIGTERM drains cleanly), or start on another port with--port.- Model download fails or hangs (proxy, firewall, HuggingFace
unreachable) — retry
gigastt download; the resume-safe staging file makes it idempotent, and exit codes distinguish causes (65 = checksum, 69 = network, 74 = disk). Ifhuggingface.cois blocked butgithub.comis not, usegigastt download --prequantized; in a fully closed contour use the air-gapped bundle. Check~/.gigastt/models/permissions on disk errors. - OOM or heavy swap on startup — each pool session loads its own encoder
copy (~400 MB resident with INT8); the default
--pool-size 2peaks around 790 MB. On small machines run with--pool-size 1.
The full symptom → cause → fix table lives in docs/troubleshooting.md.
Links
- docs/cli.md — canonical CLI reference (every flag and env var)
- docs/api.md — REST / SSE / WebSocket API reference
- docs/benchmarks.md — per-head WER / RTF numbers
- docs/troubleshooting.md — symptom → cause → fix
- docs/deployment.md — Docker details, reverse proxy, systemd, offline installs
- docs/verifying-releases.md — checksums, minisign, SLSA provenance for release artifacts
- packaging/offline/README-OFFLINE.md — offline bundle contents and installer options
- CLI and batch processing — the next chapter: batch, watch mode, export formats
- Models and backends — heads, quantization, execution providers in depth