Deployment
Contents
- Option A — Pre-built image (GHCR)
- Option B — Build from source
- Environment variables
- Selecting models at runtime
Option A — Pre-built image (GHCR)
Published images are available at ghcr.io/lopatnov/translate. Model files are not bundled — they must be downloaded separately and mounted as a volume.
Step 1 — install system dependencies:
Piper TTS requires espeak-ng installed on the host or in the container:
# Debian / Ubuntu / Docker image based on debian
apt-get install -y espeak-ng
# Windows — download MSI from https://github.com/espeak-ng/espeak-ng/releases and add to PATH
# macOS
brew install espeak-ng
Step 2 — download models (one-time):
# Translation model (Apache 2.0)
hf download lopatnov/m2m100_418M-onnx `
--local-dir ./models/translate/m2m100_418M
# Language detection — required for source_language:"auto" and DetectLanguage RPC (CC-BY-SA 3.0)
hf download lopatnov/fasttext-language-id lid.176.bin `
--local-dir ./models/detect-lang/fasttext-language-id
# Speech-to-text model (MIT)
hf download lopatnov/whisper.cpp ggml-small.bin `
--local-dir ./models/audio-to-text/whisper.cpp
# Text-to-speech voices (MIT) — download the languages you need
hf download lopatnov/piper-voices `
en_US/en_US-joe-medium.onnx en_US/en_US-joe-medium.onnx.json `
--local-dir ./models/text-to-audio/piper-voices
Step 3 — run with Docker Compose (recommended):
Create a docker-compose.yml next to your models/ directory:
services:
translate:
image: ghcr.io/lopatnov/translate:latest
ports:
- "5100:5100"
volumes:
- ./models:/app/models:ro
environment:
- Translation__DefaultModel=m2m100_1.2B
- Translation__AllowedModels__0=m2m100_1.2B
- Translation__AudioToText=whisper-medium
- Models__m2m100_1.2B__Path=/app/models/translate/m2m100_1.2B
- Models__whisper-medium__Path=/app/models/audio-to-text/whisper.cpp/ggml-medium.bin
docker compose up
Or run directly with docker run (Step 4 alternative):
docker run -p 5100:5100 \
-v ./models:/app/models:ro \
-e Translation__DefaultModel=m2m100_1.2B \
-e Translation__AllowedModels__0=m2m100_1.2B \
-e Translation__AudioToText=whisper-medium \
-e Models__m2m100_1.2B__Path=/app/models/translate/m2m100_1.2B \
-e Models__whisper-medium__Path=/app/models/audio-to-text/whisper.cpp/ggml-medium.bin \
ghcr.io/lopatnov/translate:latest
Available tags: latest, semver (e.g. 1.2.3, 1.2), and short SHA (e.g. abc1234).
Option B — Build from source
docker compose -f docker/docker-compose.yml up --build
Builds the image from the local docker/Dockerfile and mounts models/ from the repository root.
docker build -f docker/Dockerfile -t lopatnov/translate .
Environment variables
Override any appsettings.json setting via environment variable (double underscore = section nesting).
| Variable | Default | Description |
|---|---|---|
Translation__DefaultModel |
m2m100_418M |
Translation model used when model field is empty in the request |
Translation__AudioToText |
whisper-small |
STT model key; set to "" to disable TranscribeAudio |
Translation__AutoDetect |
lid-176-bin |
Language detection model key |
Translation__AllowedModels__0 |
m2m100_418M |
First allowed translation model; must include DefaultModel or requests will be rejected |
Translation__ModelTtlMinutes |
30 |
Minutes idle before a loaded model is evicted from memory |
Translation__TextToAudio__en |
piper-en-US |
TTS voice key for English (ISO 639-1 code → model key) |
Translation__TextToAudio__ru |
piper-ru-Ruslan |
TTS voice key for Russian |
Translation__TextToAudio__uk |
piper-uk-Oleksa |
TTS voice key for Ukrainian |
Models__<key>__Path |
(see appsettings.json) | Path override for any model entry |
Models__<key>__ExecutionProvider |
"" (auto) |
ONNX provider: auto, cpu, directml, cuda; Whisper: also vulkan, coreml |
ASPNETCORE_HTTP_PORTS |
5100 |
gRPC server port |
TRANSLATE_TIMEOUT_MS |
(none) | Server-side inference timeout per translation call (ms). Unset = no limit. Set the same value as in translate-angular to keep client and server in sync |
Common path overrides:
| Variable | Docker default |
|---|---|
Models__m2m100_418M__Path |
/app/models/translate/m2m100_418M |
Models__whisper-small__Path |
/app/models/audio-to-text/whisper.cpp/ggml-small.bin |
Models__whisper-medium__Path |
/app/models/audio-to-text/whisper.cpp/ggml-medium.bin |
Models__lid-176-bin__Path |
/app/models/detect-lang/fasttext-language-id/lid.176.bin |
Models__piper-en-US__Path |
/app/models/text-to-audio/piper-voices/en_US/en_US-joe-medium.onnx |
Selecting models at runtime
Models are identified by name. Switching models requires only a configuration change — no rebuild.
Switch to a higher-quality translation model:
environment:
- Translation__DefaultModel=m2m100_1.2B
- Models__m2m100_1.2B__Path=/app/models/translate/m2m100_1.2B
Switch to Whisper medium for better transcription:
environment:
- Translation__AudioToText=whisper-medium
- Models__whisper-medium__Path=/app/models/audio-to-text/whisper.cpp/ggml-medium.bin
Disable STT entirely:
environment:
- Translation__AudioToText=
Expose multiple translation models (clients can choose via the model field):
environment:
- Translation__DefaultModel=m2m100_418M
- Translation__AllowedModels__0=m2m100_418M
- Translation__AllowedModels__1=m2m100_1.2B
- Models__m2m100_418M__Path=/app/models/translate/m2m100_418M
- Models__m2m100_1.2B__Path=/app/models/translate/m2m100_1.2B
Enable text-to-speech (English + Ukrainian):
environment:
- Translation__TextToAudio__en=piper-en-US
- Translation__TextToAudio__uk=piper-uk-Oleksa
- Models__piper-en-US__Path=/app/models/text-to-audio/piper-voices/en_US/en_US-joe-medium.onnx
- Models__piper-uk-Oleksa__Path=/app/models/text-to-audio/piper-voices/uk_Oleksa/uk_UA-oleksa-high.onnx
Enable GPU acceleration (DirectML on Windows, CUDA on Linux):
environment:
# Force DirectML for ONNX models (Windows only):
- Models__m2m100_418M__ExecutionProvider=directml
# Force CUDA for ONNX models (Linux with NVIDIA GPU):
- Models__m2m100_418M__ExecutionProvider=cuda
# Whisper auto-selects GPU at runtime; force a backend:
- Models__whisper-small__ExecutionProvider=cuda
Disable TTS entirely:
environment:
- Translation__TextToAudio= # empty value clears the map