🎙️ Gipformer - Efficient Vietnamese Speech Recognition
2
15 commits
1 linked in READMEs
updated Sep 17, 2026
A handcrafted demo for the gipformer family of efficient Vietnamese ASR models (Zipformer Transducer, 68M params). Everything fits one screen — no scrolling.
| Control | Options | Effect |
|---|---|---|
| Model (dropdown) | g-group-ai-lab/gipformer1.5-68M-rnnt (default) · g-group-ai-lab/gipformer-68M-rnnt | 1.5 is the newer, more accurate release |
| Quantization | FP32 · INT8 | INT8 weights are ~4× smaller and faster on CPU |
| Decoding | Beam search · Greedy | Modified beam search trades speed for a lower WER |
Load a file once, then switch any control and press Chạy lại to re-run the same audio — that is the quickest way to compare configurations.
The first request for a configuration has to build its recognizer. That happens
behind POST /api/warm, which the UI calls after GET /api/ready reports the
configuration is cold, so the wait is labelled "Đang nạp mô hình…" rather than
looking like a slow model — and the load never lands inside the reported
inference time.
ffmpeg resamples any audio format (mp3, wav, m4a, flac, ogg, …) at any
sample rate to 16 kHz mono, up to 100 MB — video files are turned awaysherpa-onnx — no GPU requiredAudio up to 20 s is transcribed in one pass. Anything longer goes through
chunking.py, which follows the same policy as the gipformer ASR skill:
| Step | Behaviour |
|---|---|
| VAD | Silero (via sherpa-onnx), min_silence=0.2s, min_speech=0.2s |
| Merge | Adjacent speech segments are merged into chunks of up to 20 s |
| Padding | 100 ms kept around each speech boundary |
| Hard cut | A segment still longer than 30 s is cut into 30 s pieces |
| Drop | Chunks shorter than 0.5 s are discarded |
Chunks are decoded in batches (GIPFORMER_BATCH_SIZE, default 8) and the
transcripts are stitched back together. The response carries the merged text
plus each segment's text and start/end offsets.
The VAD also reports where each long silence sits inside a chunk. A period is placed before the first token emitted at or after a silence starts — the VAD marks speech onset late while the decoder emits early, so anchoring on the end of the silence lands a word or two past the break. Measured against a file built from clips with known boundaries, the silence start put 55/65 periods within a second of a real boundary versus 45/65 for the silence end.
Gaps between token timestamps are deliberately not used: the decoder can stall
mid-phrase, which punctuates inside a word group (ĐẦU. CƠ, TỨC. LÀ).
A small FastAPI app serves a static, custom frontend (static/) and two
endpoints for configuration (GET /api/config, GET /api/ready,
POST /api/warm) and one for work (POST /api/transcribe). Model files are pulled
from the Hub on first boot and cached; recognizers are built lazily per
configuration and kept in a small LRU. Runs as a Docker Space.
static/index.html → UI shell (fixed viewport, two panes)
static/style.css → warm/amber theme
static/app.js → model dropdown / controls / upload / record / fetch
chunking.py → Silero VAD segmentation for long audio
app.py → FastAPI + sherpa-onnx
Dockerfile → python:3.11-slim + ffmpeg
| Variable | Default | Purpose |
|---|---|---|
GIPFORMER_THREADS | 4 | ONNX Runtime threads |
GIPFORMER_BATCH_SIZE | 8 | Segments decoded per batch |
GIPFORMER_MAX_UPLOAD_MB | 100 | Upload cap, enforced while the request streams in |
GIPFORMER_MAX_ACTIVE_PATHS | 4 | Beam width for modified beam search |
GIPFORMER_CACHE_SIZE | 4 | Recognizers kept resident (of 8 combinations) |
HF_TOKEN | — | Only needed if a model repo is made private again |
Both models are public, so no token is required.
Static assets are served with a
?v=stamp and the shell withCache-Control: no-store. Bump the stamp inindex.htmlwheneverapp.jsorstyle.csschanges, otherwise browsers keep serving the old bundle.
Built by G-Group AI Lab · See DEPLOY.md for push instructions.
🎙️ Gipformer - Efficient Vietnamese Speech Recognition
2
15 commits
1 linked in READMEs
updated Sep 17, 2026
A handcrafted demo for the gipformer family of efficient Vietnamese ASR models (Zipformer Transducer, 68M params). Everything fits one screen — no scrolling.
| Control | Options | Effect |
|---|---|---|
| Model (dropdown) | g-group-ai-lab/gipformer1.5-68M-rnnt (default) · g-group-ai-lab/gipformer-68M-rnnt | 1.5 is the newer, more accurate release |
| Quantization | FP32 · INT8 | INT8 weights are ~4× smaller and faster on CPU |
| Decoding | Beam search · Greedy | Modified beam search trades speed for a lower WER |
Load a file once, then switch any control and press Chạy lại to re-run the same audio — that is the quickest way to compare configurations.
The first request for a configuration has to build its recognizer. That happens
behind POST /api/warm, which the UI calls after GET /api/ready reports the
configuration is cold, so the wait is labelled "Đang nạp mô hình…" rather than
looking like a slow model — and the load never lands inside the reported
inference time.
ffmpeg resamples any audio format (mp3, wav, m4a, flac, ogg, …) at any
sample rate to 16 kHz mono, up to 100 MB — video files are turned awaysherpa-onnx — no GPU requiredAudio up to 20 s is transcribed in one pass. Anything longer goes through
chunking.py, which follows the same policy as the gipformer ASR skill:
| Step | Behaviour |
|---|---|
| VAD | Silero (via sherpa-onnx), min_silence=0.2s, min_speech=0.2s |
| Merge | Adjacent speech segments are merged into chunks of up to 20 s |
| Padding | 100 ms kept around each speech boundary |
| Hard cut | A segment still longer than 30 s is cut into 30 s pieces |
| Drop | Chunks shorter than 0.5 s are discarded |
Chunks are decoded in batches (GIPFORMER_BATCH_SIZE, default 8) and the
transcripts are stitched back together. The response carries the merged text
plus each segment's text and start/end offsets.
The VAD also reports where each long silence sits inside a chunk. A period is placed before the first token emitted at or after a silence starts — the VAD marks speech onset late while the decoder emits early, so anchoring on the end of the silence lands a word or two past the break. Measured against a file built from clips with known boundaries, the silence start put 55/65 periods within a second of a real boundary versus 45/65 for the silence end.
Gaps between token timestamps are deliberately not used: the decoder can stall
mid-phrase, which punctuates inside a word group (ĐẦU. CƠ, TỨC. LÀ).
A small FastAPI app serves a static, custom frontend (static/) and two
endpoints for configuration (GET /api/config, GET /api/ready,
POST /api/warm) and one for work (POST /api/transcribe). Model files are pulled
from the Hub on first boot and cached; recognizers are built lazily per
configuration and kept in a small LRU. Runs as a Docker Space.
static/index.html → UI shell (fixed viewport, two panes)
static/style.css → warm/amber theme
static/app.js → model dropdown / controls / upload / record / fetch
chunking.py → Silero VAD segmentation for long audio
app.py → FastAPI + sherpa-onnx
Dockerfile → python:3.11-slim + ffmpeg
| Variable | Default | Purpose |
|---|---|---|
GIPFORMER_THREADS | 4 | ONNX Runtime threads |
GIPFORMER_BATCH_SIZE | 8 | Segments decoded per batch |
GIPFORMER_MAX_UPLOAD_MB | 100 | Upload cap, enforced while the request streams in |
GIPFORMER_MAX_ACTIVE_PATHS | 4 | Beam width for modified beam search |
GIPFORMER_CACHE_SIZE | 4 | Recognizers kept resident (of 8 combinations) |
HF_TOKEN | — | Only needed if a model repo is made private again |
Both models are public, so no token is required.
Static assets are served with a
?v=stamp and the shell withCache-Control: no-store. Bump the stamp inindex.htmlwheneverapp.jsorstyle.csschanges, otherwise browsers keep serving the old bundle.
Built by G-Group AI Lab · See DEPLOY.md for push instructions.