Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
fd98dcb
Merge pull request #7 from PyThaiNLP/dev
wannaphong Jan 24, 2024
0db6709
Merge pull request #15 from PyThaiNLP/dev
wannaphong Jan 28, 2026
089cf42
Merge pull request #18 from PyThaiNLP/dev
wannaphong Jan 28, 2026
fffe138
Initial plan
Copilot Jan 28, 2026
f33e574
Fix deploy_docs.yml: Change GITHUB_TOKEN to github_token
Copilot Jan 28, 2026
bdd3233
Merge pull request #19 from PyThaiNLP/copilot/fix-deploy-docs-workflow
wannaphong Jan 28, 2026
8d44a50
Add missing 'soundfile' requirement to requirements.txt
kittinan Jan 30, 2026
8212962
make it easy to copy pip install pythaitts
kittinan Jan 30, 2026
284d246
Merge pull request #20 from kittinan/fix-missing-requirement
wannaphong Jan 30, 2026
d75cb36
Bump version from 0.4.0 to 0.4.1
wannaphong Jan 30, 2026
fdc1f00
Initial plan
Copilot Jan 31, 2026
ced57de
Add TTS repository reference to khanomtan_tts.py
Copilot Jan 31, 2026
f65d69b
Refactor Synthesizer initialization parameters
wannaphong Jan 31, 2026
7ce813d
Refactor save_wav method calls for clarity
wannaphong Jan 31, 2026
a180e52
Bump version to 0.4.2
wannaphong Jan 31, 2026
182ff6e
Bump version from 0.4.1 to 0.4.2
wannaphong Jan 31, 2026
3ae5e31
Merge pull request #21 from PyThaiNLP/copilot/update-coqui-ai-tts-ref…
wannaphong Jan 31, 2026
73fd33e
Add tts from FastThaiG2P
wannaphong Sep 11, 2026
6a74f4a
Add FastThaiG2P License
wannaphong Sep 11, 2026
f8798e6
Merge pull request #28 from PyThaiNLP/add-FastThaiG2P
wannaphong Sep 11, 2026
b567591
Update Python version matrix in test workflow
wannaphong Sep 11, 2026
cf7ab76
Update README with TTS examples and sample rates
wannaphong Sep 11, 2026
6c0afca
Update README.md
wannaphong Sep 11, 2026
c75f66a
Bump version from 0.4.2 to 0.5.0
wannaphong Sep 11, 2026
e484d43
Update __init__.py
wannaphong Sep 11, 2026
4cc31d4
PyThaiTTS v0.6.0
wannaphong Sep 12, 2026
fd71d5f
Add realtime TTS
wannaphong Oct 3, 2026
6915bec
Fix tests
wannaphong Oct 3, 2026
0838442
Merge pull request #29 from PyThaiNLP/example-realtime
wannaphong Oct 4, 2026
7183e69
PyThaiTTS v0.7.0
wannaphong Oct 4, 2026
5062d73
Add English to IPA
wannaphong Oct 11, 2026
29193ba
Fix "สวน" in FastThaiG2P
wannaphong Oct 11, 2026
78e884e
Merge pull request #30 from PyThaiNLP/add-english
wannaphong Oct 11, 2026
b7cc619
PyThaiTTS v0.8.0
wannaphong Oct 11, 2026
107607b
Update README
wannaphong Oct 11, 2026
5e3f1c1
Update docs
wannaphong Oct 11, 2026
32e75cc
Update docs
wannaphong Oct 11, 2026
ac06fa8
Fix build docs
wannaphong Oct 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/deploy_docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,25 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.8
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: 3.8
python-version: '3.11'
- name: Install dependencies
run: |
sudo apt install pandoc
sudo apt-get update && sudo apt-get install -y pandoc
python -m pip install --upgrade pip
pip install boto smart_open sphinx sphinx-rtd-theme pythainlp
pip install -e .
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install -e .
- name: Build sphinx documentation
run: |
cd docs && make html
cd ..
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs/_build/html
user_name: 'github-actions[bot]'
user_email: 'github-actions[bot]@users.noreply.github.com'
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: ['3.8', '3.9', '3.10', '3.11']
python-version: ['3.9', '3.10', '3.11']

steps:
- uses: actions/checkout@v4
Expand Down
8 changes: 5 additions & 3 deletions DOCKER.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ docker run --rm pythaitts:latest
```

The demo will:
1. Initialize the PyThaiTTS model (default: lunarlist_onnx)
1. Initialize the PyThaiTTS model (default: fastthaig2p)
2. Generate speech from Thai text
3. Save the output to a WAV file
4. Display the waveform information
Expand Down Expand Up @@ -81,7 +81,9 @@ print(f"Waveform shape: {waveform.shape}")

PyThaiTTS supports multiple models:

- **lunarlist_onnx** (default): ONNX-optimized model, CPU-only
- **fastthaig2p** (default): FastThaiG2P model (voice: thai_som)
- **lunarlist_onnx**: ONNX-optimized model, CPU-only
- **vachana**: VachanaTTS model
- **khanomtan**: KhanomTan TTS model
- **lunarlist**: Original Lunarlist model

Expand Down Expand Up @@ -111,4 +113,4 @@ If you encounter issues with model downloads, ensure:

- The first run will download model files from Hugging Face Hub, which may take some time depending on your internet connection
- Generated audio files are in WAV format
- The default model (lunarlist_onnx) runs on CPU and doesn't require GPU support
- The default model (fastthaig2p) runs on CPU and doesn't require GPU support
110 changes: 104 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# PyThaiTTS
Open Source Thai Text-to-speech library in Python

[Google Colab](https://colab.research.google.com/github/PyThaiNLP/PyThaiTTS/blob/dev/notebook/use_lunarlist_model.ipynb) | [Docs](https://pythainlp.github.io/PyThaiTTS/) | [Notebooks](https://github.com/PyThaiNLP/PyThaiTTS/tree/dev/notebook)
[Google Colab](https://colab.research.google.com/github/PyThaiNLP/PyThaiTTS/blob/main/notebook/use_fastthaig2p.ipynb) | [Docs](https://pythainlp.github.io/PyThaiTTS/) | [Notebooks](https://github.com/PyThaiNLP/PyThaiTTS/tree/main/notebook)
<a href="https://pepy.tech/project/pythaitts"><img alt="Download" src="https://pepy.tech/badge/pythaitts/month"/></a>

License: [Apache-2.0 License](https://github.com/PyThaiNLP/pythaitts/blob/main/LICENSE)
Expand All @@ -10,7 +10,9 @@ License: [Apache-2.0 License](https://github.com/PyThaiNLP/pythaitts/blob/main/L

Install by pip:

> pip install pythaitts
```sh
pip install pythaitts
```

## Usage

Expand All @@ -31,19 +33,115 @@ PyThaiTTS supports multiple TTS models. You can specify which model to use:
```python
from pythaitts import TTS

# Use VachanaTTS (default voices: th_f_1, th_m_1, th_f_2, th_m_2)
tts = TTS(pretrained="vachana")
file = tts.tts("สวัสดีครับ", speaker_idx="th_f_1", filename="output.wav")
# Use FastThaiG2P (default) (default voice: thai_som)
# FastThaiG2P Sample Rate is 24000 Hz
tts = TTS(pretrained="fastthaig2p")
file = tts.tts("สวัสดีครับ", speaker_idx="thai_som", filename="output.wav")

# Use Lunarlist ONNX (default)
# Use Lunarlist ONNX
# Sample Rate is 22050 Hz
tts = TTS(pretrained="lunarlist_onnx")
file = tts.tts("ภาษาไทย ง่าย มาก", filename="output.wav")

# Use VachanaTTS (default voices: th_f_1, th_m_1, th_f_2, th_m_2)
# Sample Rate is 22050 Hz
tts = TTS(pretrained="vachana")
file = tts.tts("สวัสดีครับ", speaker_idx="th_f_1", filename="output.wav")

# Use KhanomTan
# Sample Rate is 16000 Hz
tts = TTS(pretrained="khanomtan")
file = tts.tts("ภาษาไทย", speaker_idx="Linda", filename="output.wav")
```

### Real-time / Streaming TTS (FastThaiG2P)

PyThaiTTS supports low-latency, real-time streaming speech synthesis with FastThaiG2P, making it ideal for conversational voice agents and LLM streaming:

#### 1. Streaming Audio from Text

Synthesize chunk-by-chunk in real time:

```python
from pythaitts import TTS

tts = TTS(pretrained="fastthaig2p")

# Stream audio chunks as 24kHz float32 NumPy arrays
for audio_chunk in tts.stream("สวัสดีครับ ยินดีต้อนรับสู่ระบบเรียลไทม์ทีทีเอส"):
print(f"Audio chunk shape: {audio_chunk.shape}")

# Stream raw 16-bit PCM bytes (for WebSockets or PyAudio)
for pcm_bytes in tts.stream("สวัสดีครับ", return_type="bytes"):
# send over websocket or write to audio stream
pass
```

#### 2. Streaming from an LLM Token Stream

Feed tokens directly from an LLM or generator into `tts.stream()`:

```python
from pythaitts import TTS

tts = TTS()

def token_stream():
tokens = ["สวัสดี", "ครับ", " ", "นี่", "คือ", "การ", "สตรีม", "มิ่ง"]
for tok in tokens:
yield tok

for audio_chunk in tts.stream(token_stream()):
# Process or play chunk with low latency
pass
```

#### 3. Integration with the RealtimeTTS Library

You can use FastThaiG2P as an engine with [KoljaB/RealtimeTTS](https://github.com/KoljaB/RealtimeTTS):

```sh
pip install pythaitts[realtime]
```

```python
from RealtimeTTS import TextToAudioStream
from pythaitts.realtime import FastThaiG2PEngine

engine = FastThaiG2PEngine()
stream = TextToAudioStream(engine)
stream.feed("สวัสดีครับ วันนี้อากาศดีมาก")
stream.play()
```


### Thai-English Code-Switching (FastThaiG2P)

`FastThaiG2P` automatically supports Thai-English code-switching text by converting English words into English IPA and adapting them into Thai IPA phonemes (Thai-style English pronunciation), while spelling out English acronyms and single letters in Thai (e.g., `SMS` -> `เอสเอ็มเอส`, `แผน A` -> `แผน เอ`):

```python
from pythaitts import TTS

tts = TTS(pretrained="fastthaig2p")
file = tts.tts("วันนี้เรามี meeting เรื่อง project ใหม่", filename="code_switch.wav")
```

You can also use the English-to-Thai-IPA G2P utilities directly:

```python
from pythaitts import EnglishG2P, en_g2p, en_to_ipa, en_ipa_to_thai_ipa

# Convert English word -> English IPA -> Thai IPA
print(en_to_ipa("computer")) # Output: /kəmˈpjuː.tɚ/
print(en_ipa_to_thai_ipa("/kəmˈpjuː.tɚ/")) # Output: /kʰɔm˧.pʰiw˧.tɤː˥˩/
print(en_g2p("computer")) # Output: /kʰɔm˧.pʰiw˧.tɤː˥˩/

# Or use the EnglishG2P class
eng = EnglishG2P()
print(eng("project")) # Output: /proː˧.t͡ɕek̚˨˩/
```


### Text Preprocessing

PyThaiTTS includes automatic text preprocessing to improve TTS quality:
Expand Down
6 changes: 3 additions & 3 deletions demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ def main():
print("=" * 60)
print()

# Initialize TTS with default model (lunarlist_onnx)
print("Initializing TTS model (lunarlist_onnx)...")
# Initialize TTS with default model (fastthaig2p)
print("Initializing TTS model (fastthaig2p)...")
try:
tts = TTS()
print("✓ TTS model loaded successfully!")
print()

# Sample Thai text
text = "สวัสดีครับ ยินดีต้อนรับสู่ PyThaiTTS"
text = "สวัสดีครับ ยินดีต้อนรับสู่ พายไทยทีทีเอส"
print(f"Input text: {text}")
print()

Expand Down
139 changes: 139 additions & 0 deletions demo_realtime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Real-time Text-to-Speech Demo for FastThaiG2P in PyThaiTTS.

Demonstrates:
1. Low-latency streaming TTS from text string (chunk by chunk).
2. Streaming TTS from an LLM-like token generator.
3. Streaming 16-bit PCM bytes for audio pipelines/WebSockets.
4. FastThaiG2PEngine integration with KoljaB/RealtimeTTS.
"""

import time
from pythaitts import TTS, RealtimeTTS, FastThaiG2PEngine


def main():
print("=" * 65)
print("PyThaiTTS - Real-time TTS Demo (FastThaiG2P)")
print("=" * 65)
print()

# 1. Initialize TTS model
print("Initializing FastThaiG2P TTS model...")
t_start = time.time()
tts = TTS(pretrained="fastthaig2p")
print(f"✓ Model loaded in {time.time() - t_start:.2f}s")
print()

# 2. Streaming from a full text string
sample_text = (
"สวัสดีครับ ยินดีต้อนรับสู่ระบบสังเคราะห์เสียงภาษาไทยแบบเรียลไทม์ "
"ระบบนี้ช่วยให้สร้างเสียงพูดได้อย่างรวดเร็วและต่อเนื่อง "
"โดยเริ่มส่งสัญญาณเสียงได้ทันทีตั้งแต่ข้อความส่วนแรกประมวลผลเสร็จ"
)
print("-----------------------------------------------------------------")
print("Demo 1: Real-time Streaming from Full Text")
print("-----------------------------------------------------------------")
print(f"Input text:\n{sample_text}\n")

t0 = time.time()
total_audio_samples = 0
chunk_count = 0
ttfa = None # Time to First Audio

for audio_chunk in tts.stream(sample_text, return_type="waveform"):
chunk_count += 1
elapsed = time.time() - t0
if ttfa is None:
ttfa = elapsed
print(f"⚡ Time to First Audio (TTFA): {ttfa * 1000:.1f} ms!")

duration = len(audio_chunk) / 24000.0
total_audio_samples += len(audio_chunk)
print(
f" [Chunk {chunk_count}] Received {len(audio_chunk)} samples "
f"({duration:.2f}s of audio) at +{elapsed:.2f}s"
)

total_time = time.time() - t0
total_audio_sec = total_audio_samples / 24000.0
rtf = total_time / total_audio_sec if total_audio_sec > 0 else 0
print(f"\n✓ Generated {total_audio_sec:.2f}s of audio across {chunk_count} chunks in {total_time:.2f}s")
print(f" Real-Time Factor (RTF): {rtf:.3f} (< 1.0 means faster than real-time)")
print()

# 3. Streaming from simulated LLM token stream
print("-----------------------------------------------------------------")
print("Demo 2: Real-time Streaming from LLM Token Stream")
print("-----------------------------------------------------------------")

def simulate_llm_stream():
tokens = [
"สวัสดี", "ครับ", " ", "นี่", "คือ", "การ", "ทดสอบ", " ",
"การ", "สตรีม", "มิ่ง", " ", "ข้อความ", "จาก", " ", "โมเดล",
"ภาษา", "ขนาด", "ใหญ่", " ", "แบบ", "เรียล", "ไทม์", "ครับ"
]
print("Streaming tokens from LLM: ", end="", flush=True)
for tok in tokens:
print(tok, end="", flush=True)
time.sleep(0.04) # simulate LLM generation delay
yield tok
print("\n")

t0 = time.time()
stream_chunks = 0
for audio_chunk in tts.stream(simulate_llm_stream(), return_type="waveform"):
stream_chunks += 1
elapsed = time.time() - t0
dur = len(audio_chunk) / 24000.0
print(f" [Audio Chunk {stream_chunks}] Duration: {dur:.2f}s at +{elapsed:.2f}s")

print(f"✓ LLM streaming synthesis complete in {time.time() - t0:.2f}s\n")

# 4. Streaming 16-bit PCM bytes
print("-----------------------------------------------------------------")
print("Demo 3: Streaming 16-bit PCM Bytes (for WebSockets / PyAudio)")
print("-----------------------------------------------------------------")
byte_chunks = 0
total_bytes = 0
for pcm in tts.stream("ระบบเสียงภาษาไทย คุณภาพสูง", return_type="bytes"):
byte_chunks += 1
total_bytes += len(pcm)
print(f" [PCM Chunk {byte_chunks}] Received {len(pcm)} bytes of raw 16-bit PCM")

print(f"✓ Total raw PCM data: {total_bytes} bytes (24 kHz, 16-bit, mono)\n")

# 5. RealtimeTTS Library compatibility
print("-----------------------------------------------------------------")
print("Demo 4: RealtimeTTS Engine (KoljaB/RealtimeTTS compatibility)")
print("-----------------------------------------------------------------")
try:
from RealtimeTTS import TextToAudioStream
print("RealtimeTTS library detected. Initializing FastThaiG2PEngine...")
engine = FastThaiG2PEngine()
stream = TextToAudioStream(engine)
print("✓ FastThaiG2PEngine ready with RealtimeTTS TextToAudioStream!")
except ImportError:
print("KoljaB/RealtimeTTS library is not installed.")
print("To use with RealtimeTTS:")
print(" pip install pythaitts[realtime]")
print(" or: pip install RealtimeTTS")
print("\nFastThaiG2PEngine can then be used directly:")
print(" from RealtimeTTS import TextToAudioStream")
print(" from pythaitts.realtime import FastThaiG2PEngine")
print(" engine = FastThaiG2PEngine()")
print(" stream = TextToAudioStream(engine)")
print(" stream.feed('สวัสดีครับ')")
print(" stream.play()")

print()
print("=" * 65)
print("Real-time TTS Demo completed successfully!")
print("=" * 65)
return 0


if __name__ == "__main__":
exit(main())
Loading
Loading