MiniWeb-demo / src /miniweb /scripts /fetch_translation_model.py
sparklabuofu's picture
Update the demo
22de727 verified
Raw History Blame Contribute Delete
2.45 kB
"""Fetch + convert the LinguaBridge many-to-many translation model (one-time setup).
Downloads facebook/nllb-200-distilled-600M from Hugging Face and converts it to
an int8 CTranslate2 model at models/nllb200-600M-ct2 (~600MB on disk, ~1GB RAM
at inference, ~100-300ms/sentence on CPU). The site's translator uses it for
all 110 language directions natively (no English pivot, no API key), with the
persistent translation_cache still freezing every output for determinism.
Setup step, like src/miniweb/scripts/fetch_brand_fonts.py — run once per machine/deploy:
~/.conda/envs/miniweb/bin/python src/miniweb/scripts/fetch_translation_model.py
The model directory is gitignored; on Railway either bake this into the image
build or put models/ on the persistent volume. Without the model the site
falls back to the LLM (if keyed) and then the built-in dictionaries.
"""
import pathlib
import shutil
import subprocess
import sys
ROOT = pathlib.Path(__file__).resolve().parents[3] # the repository
MODEL_DIR = ROOT / "models" / "nllb200-600M-ct2"
HF_REPO = "facebook/nllb-200-distilled-600M"
# the weights every cached translation came from; with transformers 4.57.6 and ctranslate2 4.8.1 the conversion
# gives the same model.bin byte for byte (deploy/space/Dockerfile pins those)
HF_REVISION = "f8d333a098d19b4fd9a8b18f94170487ad3f821d"
def main():
if (MODEL_DIR / "model.bin").exists() and (MODEL_DIR / "sentencepiece.model").exists():
print(f"model already present at {MODEL_DIR}")
return
from huggingface_hub import snapshot_download
print(f"downloading {HF_REPO} ...")
src = snapshot_download(HF_REPO, revision=HF_REVISION, allow_patterns=[
"*.json", "*.model", "pytorch_model.bin", "*.safetensors", "*.txt"])
print("converting to CTranslate2 int8 ...")
MODEL_DIR.parent.mkdir(exist_ok=True)
tmp = str(MODEL_DIR) + ".tmp"
subprocess.run([
sys.executable, "-m", "ctranslate2.converters.transformers",
"--model", src, "--output_dir", tmp,
"--quantization", "int8", "--force",
], check=True)
# keep the sentencepiece tokenizer next to the model
sp = pathlib.Path(src) / "sentencepiece.bpe.model"
shutil.copy2(sp, pathlib.Path(tmp) / "sentencepiece.model")
shutil.move(tmp, MODEL_DIR)
size = sum(f.stat().st_size for f in MODEL_DIR.rglob("*")) / 1e6
print(f"done: {MODEL_DIR} ({size:.0f} MB)")
if __name__ == "__main__":
main()