Send text, get natural Thai speech back — powered by Google's Chirp3-HD voices.
A small, production-minded Telegram bot that turns Thai text into high-quality audio. Built for long text — paste an article, a chapter, or a wall of messages, and the bot splits it cleanly, narrates it, and streams the audio files back with live progress.
- Natural Thai voices — Google Cloud
Chirp3-HD(defaultth-TH-Chirp3-HD-Achernar), switchable via env. - Handles long text — up to 20,000 characters per request, auto-split into multiple audio files on sentence boundaries (falls back to soft punctuation, then hard cuts).
- Smart message batching — collects rapid-fire messages within a short window and narrates them as one job, so multi-paragraph pastes stay together.
- Job queue with live progress — every request is queued; the bot reports its queue position and updates
file x/y · chunk m/nas it works. - Monthly usage metering — bot-wide character quota tracking (optional Supabase backend), with a
/statuscommand and per-job usage summary. - Access control — optional
ALLOWED_CHAT_IDSallowlist; unknown chats are silently ignored so strangers can't spend your TTS quota. - Resilient by design — explicit connect/read/send timeouts, graceful error messages per file, no silent failures.
- Deploy anywhere — single
Dockerfile, configured entirely through environment variables.
| Command | What it does |
|---|---|
| (send any text) | Converts it to Thai speech and returns the audio file(s) |
/start |
Quick hint on how to use the bot |
/status |
Shows this month's character usage, remaining quota and the current reader |
/settings |
Pick the Gemini reader (4 personas or 🎲 random). Saved as a pinned message in the chat |
Send a long article and you'll see something like:
รับข้อความแล้ว 14,230 ตัวอักษร
จะแบ่งเป็น 3 ไฟล์ / ประมาณ 58 TTS requests
เข้าคิวลำดับที่ 1
...
กำลังสร้างเสียงไฟล์ 2/3 · ท่อน 9/20...
เสร็จแล้ว
git clone https://github.com/peeraseepat-cell/tts-bot.git
cd tts-bot
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # then fill in your keys
python bot.pydocker build -t tts-bot .
docker run --env-file .env -p 8443:8443 tts-botAll configuration is via environment variables. Only the first two are required.
| Variable | Required | Default | Description |
|---|---|---|---|
TELEGRAM_BOT_TOKEN |
✅ | — | Bot token from @BotFather |
GOOGLE_API_KEY |
✅ | — | Google Cloud API key with Text-to-Speech enabled |
ALLOWED_CHAT_IDS |
— (everyone) | Comma-separated chat IDs allowed to use the bot; others are silently ignored. Get yours from @userinfobot | |
GEMINI_API_KEY |
— | Google AI Studio key. When set, narration uses Gemini TTS and Chirp becomes the fallback for when the Gemini daily quota runs out | |
GEMINI_TTS_MODEL |
gemini-3.8-flash-tts |
Gemini TTS model (Thai needs Flash TTS; Flash-Lite TTS has no Thai) | |
TTS_PERSONA |
jan |
Default Gemini reader (jan tom leng dak) until /settings picks one. The choice is saved in a message the bot pins in the chat, so it survives restarts without a database |
|
GEMINI_PART_SIZE |
14000 |
Characters per Gemini request / audio file. The free tier counts ~2× prompt tokens against 10K input tokens/min; 14k Thai chars ≈ 9.2K | |
TTS_VOICE |
th-TH-Chirp3-HD-Achernar |
Any Google Cloud TTS voice name (Chirp) | |
SUPABASE_URL / SUPABASE_KEY |
— | Enables persistent per-user usage metering | |
TTS_MONTHLY_FREE_CHARS |
1000000 |
Monthly character quota per user | |
COLLECT_WINDOW_SECONDS |
5 |
How long to wait for follow-up messages before narrating | |
TTS_PART_SIZE |
1950 |
Target characters per audio file | |
PORT |
8443 |
Webhook port |
🔒
GOOGLE_API_KEYandSUPABASE_KEYare read server-side only and never logged. Keep them out of version control —.envis gitignored.
Telegram message
│
▼
collect window ──► batch messages into one job
│
▼
split text ──► sentence-aware chunks ──► grouped into parts (~1950 chars)
│
▼
job queue ──► Google Cloud TTS (per chunk) ──► concat ──► MP3
│
▼
stream files back + update usage meter (Supabase)
The core lives in a single, readable bot.py (~600 lines). Text splitting and queue/usage logic are covered by unit tests in tests/.
pip install -r requirements.txt
python -m pytestMIT — © Peerasee