CTranslate2 INT8 quantized version of
small-100-Singlish-Sinhala-CodeMix2 — a fine-tuned
NLLB-200 small-100 model for translating
Singlish (Romanized Sinhala / English-Sinhala code-mixed text) →
Sinhala script.
Translates informal Sri Lankan code-mixed text written in Roman script into Sinhala Unicode script.
1from huggingface_hub import snapshot_download
2import ctranslate2
3from transformers import AutoTokenizer
4
5model_path = snapshot_download("savinugunarathna/small-100-Singlish-Sinhala-CodeMix2-CT2")
6print(f"✓ Downloaded to: {model_path}")
7
8translator = ctranslate2.Translator(
9 model_path,
10 device="cpu",
11 compute_type="int8",
12 intra_threads=4,
13)
14
15tokenizer = AutoTokenizer.from_pretrained(
16 "savinugunarathna/small-100-Singlish-Sinhala-CodeMix2-CT2"
17)
18
19def translate(text: str) -> str:
20 tokenizer.src_lang = "en"
21 tokens = tokenizer.convert_ids_to_tokens(
22 tokenizer.encode(text, add_special_tokens=True)
23 )
24
25 result = translator.translate_batch(
26 [tokens],
27 target_prefix=[["si"]],
28 beam_size=3,
29 max_decoding_length=128,
30 repetition_penalty=1.2,
31 )
32
33 hyp_ids = tokenizer.convert_tokens_to_ids(result[0].hypotheses[0])
34 return tokenizer.decode(hyp_ids, skip_special_tokens=True).strip("si")
35
36while True:
37 text = input("\nSinglish: ").strip()
38 if text.lower() == "q":
39 break
40 print(f"සිංහල: {translate(text)}")
1from fastapi import FastAPI, HTTPException
2from pydantic import BaseModel
3import ctranslate2
4from transformers import AutoTokenizer
5import uvicorn
6
7MODEL_CT2 = "savinugunarathna/small-100-Singlish-Sinhala-CodeMix2-CT2"
8MODEL_BASE = "savinugunarathna/small-100-Singlish-Sinhala-CodeMix2"
9
10print("Loading model...")
11translator = ctranslate2.Translator(MODEL_CT2, device="cpu", compute_type="int8", intra_threads=4)
12tokenizer = AutoTokenizer.from_pretrained(MODEL_BASE)
13print("Ready!")
14
15app = FastAPI(title="Singlish → Sinhala API", version="1.0")
16
17class TranslateRequest(BaseModel):
18 text: str
19 beam_size: int = 3
20 max_length: int = 128
21
22class TranslateResponse(BaseModel):
23 input: str
24 translation: str
25
26def _translate(text: str, beam_size: int = 3, max_length: int = 128) -> str:
27 tokenizer.src_lang = "en"
28 tokens = tokenizer.convert_ids_to_tokens(
29 tokenizer.encode(text, add_special_tokens=True)
30 )
31 result = translator.translate_batch(
32 [tokens],
33 target_prefix=[["si"]],
34 beam_size=beam_size,
35 max_decoding_length=max_length,
36 repetition_penalty=1.2,
37 )
38 hyp_ids = tokenizer.convert_tokens_to_ids(result[0].hypotheses[0])
39 return tokenizer.decode(hyp_ids, skip_special_tokens=True).strip("si")
40
41@app.get("/health")
42def health():
43 return {"status": "ok", "model": MODEL_CT2}
44
45@app.post("/translate", response_model=TranslateResponse)
46def translate(req: TranslateRequest):
47 if not req.text.strip():
48 raise HTTPException(status_code=400, detail="text cannot be empty")
49 return TranslateResponse(
50 input=req.text,
51 translation=_translate(req.text, req.beam_size, req.max_length)
52 )
53
54@app.post("/translate/batch")
55def translate_batch(texts: list[str]):
56 if not texts:
57 raise HTTPException(status_code=400, detail="texts list cannot be empty")
58 if len(texts) > 32:
59 raise HTTPException(status_code=400, detail="max 32 texts per batch")
60 return {"translations": [_translate(t) for t in texts]}
61
62if __name__ == "__main__":
63 uvicorn.run(app, host="0.0.0.0", port=8000)
1@misc{small100-singlish-sinhala-ct2,
2 author = {Savinu Gunarathna},
3 title = {small-100-Singlish-Sinhala-CodeMix2-CT2},
4 year = {2025},
5 publisher = {HuggingFace},
6 url = {https://huggingface.co/savinugunarathna/small-100-Singlish-Sinhala-CodeMix2-CT2}
7}