Repository navigation
Releases
Laras v0.2.1 — jalan di arm64, dan bisa dicoba tanpa curl
Laras v0.2.1 — jalan di arm64, dan bisa dicoba tanpa curl
Dua celah adopsi yang tersisa di v0.2.0 ditutup: image-nya sekarang multi-arch,
dan server punya halaman depan sehingga orang bisa mendengar suaranya tanpa
membaca README dulu.
Image untuk amd64 dan arm64
Satu manifest, dua arsitektur. Mac M-series, Graviton, dan Ampere menarik varian
yang benar tanpa --platform:
docker run --rm -p 8080:8080 -v "$PWD/data:/data" \
ghcr.io/urdemonlord/laras-tts:0.2.1Keduanya dibangun di runner native masing-masing (ubuntu-latest dan
ubuntu-24.04-arm) lalu manifest-nya digabung dengan buildx imagetools create — bukan QEMU, karena emulasi build Rust sebesar ini 5–10× lebih lambat.
CI memverifikasi manifest benar-benar berisi linux/amd64 dan linux/arm64
sebelum image dinyatakan terbit.
GET / — halaman depan
Satu kotak teks, satu tombol putar, dan perintah curl yang setara. Berkasnya
demo/index.html, di-include_str! ke dalam binary, jadi tetap satu berkas
tanpa direktori aset. Halaman ini bebas token dan bebas batas laju seperti
/health: isinya statis dan tidak memakai CPU. Sintesis tetap butuh token
kalau LARAS_TOKEN diisi.
Demo publik dalam satu perintah
pip install -U "huggingface_hub[cli]"
hf auth login
scripts/terbitkan-space.sh --user <akun-hf>Skrip itu membuat HF Space (SDK docker), menyalin bundel demo/hf-space/,
push, lalu menunggu sampai statusnya RUNNING. Token tidak pernah masuk ke URL
git atau argv — ditulis ke berkas 600 lalu dibaca credential helper.
Isi bundelnya:
- model diunduh saat build, bukan saat start — pengunjung pertama tidak
menunggu 160 MB; - unduhannya memakai
scripts/unduh-model.shyang dipin ke tag rilis, jadi
sha256-nya ikut diverifikasi; - referensinya sampel Common Voice CC0, bukan rekaman pribadi siapa pun;
TAKES=1,RATE_LIMIT=6karena CPU Space dipakai bersama.
Perbaikan lain
scripts/uji-image.sh— smoke test image dipindah dari YAML ke skrip, dipakai
jalur rilis dan jalur PR, jadi yang diuji adalah artefak yang benar-benar
di-push (arch,ldd, glibc, ffmpeg mp3→wav, gagal-muat-model).Dockerfilemenyalindemo/index.htmlke tahap build (tanpa itu
include_str!gagal).- CI menolak skrip yang sintaksnya rusak dan
--cekyang menerima direktori
model kosong. - Versi crate 0.2.1,
/healthikut melaporkan0.2.1.
Yang masih batas model, bukan bug
Artikulasi gugus konsonan ("kloning" → "koning") tidak diperbaiki di rilis ini.
Akarnya kosakata tokenizer 4.000 kata; memperbaikinya butuh latih ulang dengan
kosakata 8–16 ribu dan itu butuh GPU. Rilis ini menutup celah adopsi, bukan
celah kualitas — dan itu disebut apa adanya di README.
Uji
- 40 tes
cargo test --features onnx, 26 tanpa fitur;cargo fmt --checkdanclippy -D warningsbersih di kedua kombinasi. - CI 5/5 hijau pada commit yang di-tag.
- Manifest diverifikasi lewat registry API:
linux/amd64+linux/arm64.
Full Changelog: v0.2.0...v0.2.1
Laras v0.2.0 — pengaman runtime dan tes HTTP
Port Laras sebelumnya terbuka: siapa pun yang bisa menjangkau port-nya boleh
memakai CPU, dan permintaan bisa menumpuk sampai memori habis. Rilis ini
menutup itu — dan menambah tes HTTP yang selama ini tidak ada.
Pengaman runtime
Semuanya opsional dan mati secara default, jadi localhost tetap tanpa gesekan.
| Variabel | Default | Arti |
|---|---|---|
LARAS_TOKEN |
kosong (terbuka) | semua rute kecuali /health butuh Authorization: Bearer <token> |
RATE_LIMIT |
0 (mati) |
permintaan per menit per klien |
MAX_CONCURRENT |
1 |
slot sintesis paralel |
QUEUE_WAIT |
120 |
detik menunggu slot sebelum 429 |
REQUEST_TIMEOUT |
300 |
detik sampai header respons siap sebelum 504 |
MAX_BODY_KB |
64 |
batas body permintaan sebelum 413 |
LARAS_TOKEN=$(openssl rand -hex 24) BIND=0.0.0.0 ./target/release/laras
curl -H "Authorization: Bearer $LARAS_TOKEN" \
-d '{"text":"Halo, apa kabar?"}' localhost:8080/tts -o halo.wavDetail yang disengaja:
/healthbebas token dan bebas batas laju — healthcheck container tidak
boleh ikut terkunci.- Token dibandingkan dengan waktu konstan, jadi panjang dan isinya tidak
bocor lewat timing. - Cache hit tidak ikut mengantre. Permintaan yang hasilnya sudah ada
dijawab langsung; yang mengantre hanya kerja sintesis. - Antrean penuh dijawab
429+Retry-After, bukan digantung sampai klien
menyerah. - Server mencetak peringatan di log kalau
BINDbukan loopback sementara
LARAS_TOKENkosong.
Tes HTTP
39 tes dengan --features onnx (26 tanpa fitur itu). Rute diuji lewat
Service::oneshot: axum sungguhan, tanpa membuka port, dan memakai
bangun_router() yang sama dengan main — jadi urutan layer-nya ikut teruji,
bukan cuma handler-nya.
Yang diuji: /health tetap jalan tanpa token, 401 untuk token salah,
400 untuk teks kosong, 413 untuk body kebesaran, 429 + Retry-After saat
jatah laju habis, 504 saat handler terlalu lambat, dan pemulihan antrean
setelah slot dilepas.
Untuk bisa menguji rute tanpa memuat model 438 MB, ada varian Backend::Uji
yang hanya hidup saat cfg(test).
Diukur, bukan diasumsikan
Dengan MAX_CONCURRENT=1, QUEUE_WAIT=2, RATE_LIMIT=3, satu sintesis
5 kalimat berjalan (7,77 s):
| Permintaan | Hasil |
|---|---|
| Teks yang sudah ada di cache | 200 dalam 0,0008 s, x-cache: hit |
| Teks baru saat slot terpakai | 429 setelah 2,00 s, Retry-After: 5 |
| Sintesis panjang | 200, 439.724 byte |
Batas lain yang terverifikasi: 401 + WWW-Authenticate: Bearer, 413 untuk
body 3 KB saat batas 2 KB, dan 429 dengan Retry-After: 45 saat jatah menit
habis.
Perbaikan kecil
- Versi crate naik ke
0.2.0, jadi/healthakhirnya melaporkan versi yang
sama dengan tag rilis (sebelumnya image0.1.1masih bilang0.1.0). - README: bagian "Pengaman runtime" + tabel jawaban
401/429/413/504,
bagian "Kualitas", dan satu batasan usang ("belum ada streaming") dibuang.
Image: ghcr.io/urdemonlord/laras-tts:0.2.0 (juga 0.2, latest).
Laras v0.1.1 — unduh model sekali jalan, referensi MP3 langsung dipakai
Rilis patch yang menutup dua gesekan yang bikin orang harus menebak-nebak saat
pertama kali mencoba Laras.
1. Model tidak perlu diunduh manual lagi
scripts/unduh-model.sh mengunduh 9 berkas dari Hugging Face dan memverifikasi
sha256 setiap berkas. Hash tidak cocok = berhenti dengan kode keluar 1,
bukan diam-diam memakai berkas rusak atau setengah jadi.
scripts/unduh-model.sh # ±160 MB: model + contoh referensi CC0
scripts/unduh-model.sh --cek # hanya verifikasi yang sudah ada
scripts/unduh-model.sh --dir /data/models --ref-dir /data/refRepo bobotnya publik — tidak perlu huggingface-cli login. (Bobot asli
kyutai/pocket-tts gated; itu hanya relevan kalau kamu mau mengekspor graf
ONNX sendiri.)
2. Referensi MP3 langsung jalan
Sebelumnya REF_WAV hanya menerima WAV, padahal contoh referensi Common Voice
berformat MP3 — jadi permintaan pertama gagal dengan pesan "hanya WAV yang
didukung". Sekarang WAV, MP3, m4a, ogg, flac semuanya diterima: selain WAV
dikonversi otomatis ke WAV 24 kHz mono lewat ffmpeg, dan hasilnya dipakai
ulang selama berkas sumbernya tidak berubah (tidak ada konversi berulang di
setiap permintaan).
Kalau ffmpeg tidak terpasang, galatnya menyebut perintah konversi manual —
bukan menyuruh menebak.
Image rilis sekarang memasang ffmpeg, jadi perilaku ini sama di dalam
container.
Perbaikan lain
- Peringatan saat start kalau
REF_WAVtidak ada, bukan gagal di permintaan pertama. docker compose upmemakai image ghcr (bukanbuild: .), plusmake modelsdanmake cek-model.- README: bagian "Menyiapkan model", format referensi yang didukung, dan diagram arsitektur yang sesuai kenyataan — ONNX native adalah default, Python hanya jalur cadangan.
- Smoke test CI memeriksa
ffmpegdi dalam image dan benar-benar mengonversi satu MP3; CI juga memastikan--cekmenolak direktori kosong dengan kode 1.
Bukti
- Referensi
suara.mp3(180 KB, 15 detik) dipakai langsung: sintesis 2,80 detik
audio berhasil tanpa konversi manual, dan permintaan berikutnya memakai hasil
konversi yang sama (mtime tidak berubah, tidak ada berkas baru). - 28 tes lulus dengan
--features onnx, termasuk 4 tes baru untuk pembacaan
audio dan pemakaian ulang konversi. - CI
mainhijau 5/5; image diuji dari artefak yang benar-benar di-push.
Image: ghcr.io/urdemonlord/laras-tts:0.1.1 (juga 0.1, latest).
Laras v0.1.0 — TTS Bahasa Indonesia, CPU-first
Rilis pertama Laras: engine TTS Bahasa Indonesia yang CPU-first, self-hosted, dengan
kloning suara. Satu binary Rust, ONNX Runtime native (tanpa Python di jalur
permintaan), dan audio yang dikirim per kalimat.
Yang bisa dipakai
POST /tts— WAV utuh dari teks, lengkap dengan normalisasi angka/rupiah/persen
dan pemilihan take adaptif.POST /tts/stream— audio dikirim per kalimat begitu selesai disintesis;
?fmt=pcmuntuk browser dan pemutar yang menolak WAV tanpa panjang pasti.GET /health,GET /normalize— cek status, dan debug normalizer tanpa memuat model.- Kloning suara dari 10–15 detik rekaman referensi (
REF_WAV).
Angka terukur, bukan estimasi
Teks 8 kalimat (22,7 s audio), 4 vCPU, cache kosong:
| Momen | /tts |
/tts/stream |
|---|---|---|
| byte pertama | 3,76 s | 0,26 s |
| 50% audio | – | 2,04 s |
| selesai | 3,76 s | 3,85 s |
Keluaran identik: 1.091.084 byte di kedua jalur, PCM hasil decode sama
bit-per-bit. Latensi dengar turun ±14× dengan tambahan total 0,09 s.
Image Docker
docker run --rm -p 8080:8080 \
-v "$PWD/data:/data" \
ghcr.io/urdemonlord/laras-tts:0.1.0linux/amd64, basis debian:trixie-slim, satu binary, ONNX Runtime ter-link
statis (tidak ada libonnxruntime.so di ldd). Butuh /data/models (graf ONNX)
dan /data/ref/suara.wav; tanpa itu proses berhenti dengan gagal memuat model ONNX.
Image diuji di CI sebelum dipakai: ldd tanpa "not found", binary menuntut
GLIBC_2.38 sementara runtime menyediakan 2.41, dan binary terbukti sampai
tahap memuat model di dalam container.
Batasan yang sudah diukur
- Teks ≤20 kata tidak dapat manfaat streaming: 4 kata tetap 8,83 s di kedua jalur.
- Header WAV memakai ukuran
0xFFFFFFFFkarena total belum diketahui saat header
dikirim; ffmpeg memberi peringatan di EOF, tapi decode tetap identik. - Normalisasi loudness dilakukan per potongan pada jalur streaming (RMS −17,8 dBFS
vs −17,3 dBFS di/tts), dan/tts/streamtidak menulis cache. - MSRV 1.92, dipaksa
ort 2.0.0-rc.15. Image memakai trixie karena binary
menuntut glibc ≥ 2.38 — bookworm tidak bisa dipakai sama sekali.
Catatan teknis
- Pemilihan take adaptif berbasis ASR: rata-rata 10,8 s dari sebelumnya 14,5 s,
kualitas setara (WER 0,168 vs 0,163; 27 dari 28 kalimat identik). - Normalisasi loudness BS.1770 + limiter puncak.
- Image dibangun dan diuji di GitHub Actions; tidak ada build Docker di mesin
produksi.
Lisensi: MIT OR Apache-2.0. Konfigurasi lengkap ada di README.
Laras Desktop v0.1.0 — Windows x86_64
Pratinjau pertama aplikasi desktop Laras untuk Windows.
Isi paket (ekstrak semua ke satu folder):
- laras-desktop.exe
- DirectML.dll
- data/models/ (9 berkas ONNX, 157 MB)
- data/ref/suara.mp3 (contoh Common Voice CC0)
- BACA-DULU.txt
Cara pakai: ekstrak, lalu dobel-klik laras-desktop.exe. Tanpa jaringan, tanpa GPU.
Catatan: exe belum ditandatangani, jadi SmartScreen akan memperingatkan (More info -> Run anyway). Jalur sintesis di Windows belum diuji otomatis; laporan bug sangat membantu.