Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ from pythaitts import TTS
tts = TTS(pretrained="fastthaig2p")
file = tts.tts("สวัสดีครับ", speaker_idx="thai_som", filename="output.wav")

# Use MakHamTTS Paradee (standalone, single-voice 8MB quantized INT8 ONNX model, offline without download)
# MakHamTTS Paradee Sample Rate is 24000 Hz
tts = TTS(pretrained="makham_paradee")
file = tts.tts("สวัสดีค่ะ", filename="output.wav")

# Use MakHamTTS (Kokoro-82M Thai base model, voices: newvoice_female, newvoice_male)
# MakHamTTS Sample Rate is 24000 Hz
tts = TTS(pretrained="makham")
file = tts.tts("สวัสดีค่ะ", speaker_idx="newvoice_female", filename="output.wav")

# Use Lunarlist ONNX
# Sample Rate is 22050 Hz
tts = TTS(pretrained="lunarlist_onnx")
Expand Down
2 changes: 1 addition & 1 deletion demo_realtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def main():
# 1. Initialize TTS model
print("Initializing FastThaiG2P TTS model...")
t_start = time.time()
tts = TTS(pretrained="fastthaig2p")
tts = TTS(pretrained="makham_paradee")
print(f"✓ Model loaded in {time.time() - t_start:.2f}s")
print()

Expand Down
10 changes: 10 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ PyThaiTTS provides English-to-Thai-IPA Grapheme-to-Phoneme (G2P) conversion for

.. autofunction:: en_ipa_to_thai_ipa

MakHamTTS Models
----------------
MakHamTTS models powered by Kokoro-82M Thai and Paradee 1.1 distillation.

.. autoclass:: MakHamTTS
:members:

.. autoclass:: MakHamTTSParadee
:members:

FastThaiG2P Components
----------------------

Expand Down
2 changes: 1 addition & 1 deletion example_realtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def main():
print("-" * 50)

# Initialize FastThaiG2P TTS
tts = TTS(pretrained="fastthaig2p")
tts = TTS(pretrained="makham_paradee")

# 1. Stream speech from text string chunk-by-chunk
text = "สวัสดีครับ ยินดีต้อนรับสู่ระบบสังเคราะห์เสียงภาษาไทยแบบเรียลไทม์"
Expand Down
Binary file added output.wav
Binary file not shown.
77 changes: 70 additions & 7 deletions pythaitts/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
expand_maiyamok,
load_custom_dict,
)
from pythaitts.pretrained.makham import (
MakHamTTS,
MakHamTTSParadee,
)
from pythaitts.pretrained.fastthaig2p.en_g2p import (
EnglishG2P,
en_g2p,
Expand Down Expand Up @@ -40,10 +44,10 @@ def __init__(
**kwargs,
) -> None:
"""
:param str pretrained: TTS pretrained (fastthaig2p, lunarlist_onnx, khanomtan, lunarlist, vachana)
:param str mode: pretrained mode (fastthaig2p, lunarlist_onnx, and vachana don't support)
:param str pretrained: TTS pretrained (fastthaig2p, makham, makham_paradee, lunarlist_onnx, khanomtan, lunarlist, vachana)
:param str mode: pretrained mode (fastthaig2p, makham, makham_paradee, lunarlist_onnx, and vachana don't support)
:param str version: model version (default is 1.0 or 1.1)
:param str device: device for running model. (fastthaig2p, lunarlist_onnx, and vachana support CPU only.)
:param str device: device for running model. (fastthaig2p, makham, makham_paradee, lunarlist_onnx, and vachana support CPU only.)
:param custom_dict: Optional custom word dictionary for custom Thai pronunciation in words

**Options for mode**
Expand All @@ -65,6 +69,9 @@ def __init__(

For fastthaig2p tts model, \
You can see more about fastthaig2p at `https://github.com/awslabs/FastThaiG2P <https://github.com/awslabs/FastThaiG2P>`_

For makham and makham_paradee tts models, \
You can see more about MakHamTTS at `https://huggingface.co/pythainlp/MakHamTTS <https://huggingface.co/pythainlp/MakHamTTS>`_
"""
self.pretrained = pretrained
self.mode = mode
Expand Down Expand Up @@ -93,6 +100,12 @@ def load_pretrained(self, version="1.0", **kwargs):
elif self.pretrained in ("fastthaig2p", "FastThaiG2P"):
from pythaitts.pretrained.fastthaig2p import FastThaiG2P
self.model = FastThaiG2P(device=self.device, **kwargs)
elif self.pretrained in ("makham", "MakHamTTS"):
from pythaitts.pretrained.makham import MakHamTTS
self.model = MakHamTTS(**kwargs)
elif self.pretrained in ("makham_paradee", "MakHamTTS_paradee"):
from pythaitts.pretrained.makham import MakHamTTSParadee
self.model = MakHamTTSParadee(**kwargs)
else:
raise NotImplementedError(
"PyThaiTTS doesn't support %s pretrained." % self.pretrained
Expand Down Expand Up @@ -169,7 +182,7 @@ def tts(
if self.pretrained == "lunarlist" or self.pretrained == "lunarlist_onnx":
return self.model(text=text, return_type=return_type, filename=filename)
elif self.pretrained == "vachana":
if speaker_idx in ("thai_som", "Linda", None):
if speaker_idx in ("thai_som", "Linda", "newvoice_female", None):
speaker_idx = "th_f_1"
return self.model(
text=text,
Expand All @@ -179,7 +192,7 @@ def tts(
**kwargs,
)
elif self.pretrained in ("fastthaig2p", "FastThaiG2P"):
if speaker_idx in ("Linda", None):
if speaker_idx in ("Linda", "newvoice_female", None):
speaker_idx = "thai_som"
call_kwargs = dict(kwargs)
if effective_custom_dict is not None:
Expand All @@ -191,7 +204,31 @@ def tts(
filename=filename,
**call_kwargs,
)
if speaker_idx in ("thai_som", None):
elif self.pretrained in ("makham", "MakHamTTS"):
if speaker_idx in ("Linda", "thai_som", None):
speaker_idx = "newvoice_female"
call_kwargs = dict(kwargs)
if effective_custom_dict is not None:
call_kwargs["custom_dict"] = effective_custom_dict
return self.model(
text=text,
speaker_idx=speaker_idx,
return_type=return_type,
filename=filename,
**call_kwargs,
)
elif self.pretrained in ("makham_paradee", "MakHamTTS_paradee"):
call_kwargs = dict(kwargs)
if effective_custom_dict is not None:
call_kwargs["custom_dict"] = effective_custom_dict
return self.model(
text=text,
speaker_idx=speaker_idx,
return_type=return_type,
filename=filename,
**call_kwargs,
)
if speaker_idx in ("thai_som", "newvoice_female", None):
speaker_idx = "Linda"
return self.model(
text=text,
Expand Down Expand Up @@ -230,7 +267,7 @@ def stream(
)

if self.pretrained in ("fastthaig2p", "FastThaiG2P"):
if speaker_idx in ("Linda", None):
if speaker_idx in ("Linda", "newvoice_female", None):
speaker_idx = "thai_som"
return self.model.stream(
text=text,
Expand All @@ -242,6 +279,30 @@ def stream(
custom_dict=effective_custom_dict,
**kwargs,
)
elif self.pretrained in ("makham", "MakHamTTS"):
if speaker_idx in ("Linda", "thai_som", None):
speaker_idx = "newvoice_female"
return self.model.stream(
text=text,
speaker_idx=speaker_idx,
return_type=return_type,
play=play,
preprocess=preprocess,
max_phonemes=max_phonemes,
custom_dict=effective_custom_dict,
**kwargs,
)
elif self.pretrained in ("makham_paradee", "MakHamTTS_paradee"):
return self.model.stream(
text=text,
speaker_idx=speaker_idx,
return_type=return_type,
play=play,
preprocess=preprocess,
max_phonemes=max_phonemes,
custom_dict=effective_custom_dict,
**kwargs,
)
else:
from pythaitts.realtime import stream_text_to_chunks

Expand Down Expand Up @@ -276,6 +337,8 @@ def _gen():
"en_g2p",
"en_to_ipa",
"en_ipa_to_thai_ipa",
"MakHamTTS",
"MakHamTTSParadee",
"preprocess_text",
"load_custom_dict",
"num_to_thai",
Expand Down
8 changes: 8 additions & 0 deletions pythaitts/pretrained/makham/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
"""
MakHamTTS Models
"""
from pythaitts.pretrained.makham.makham_tts import MakHamTTS
from pythaitts.pretrained.makham.paradee_tts import MakHamTTSParadee

__all__ = ["MakHamTTS", "MakHamTTSParadee"]
177 changes: 177 additions & 0 deletions pythaitts/pretrained/makham/data/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
{
"istftnet": {
"upsample_kernel_sizes": [
20,
12
],
"upsample_rates": [
10,
6
],
"gen_istft_hop_size": 5,
"gen_istft_n_fft": 20,
"resblock_dilation_sizes": [
[
1,
3,
5
],
[
1,
3,
5
],
[
1,
3,
5
]
],
"resblock_kernel_sizes": [
3,
7,
11
],
"upsample_initial_channel": 512
},
"dim_in": 64,
"dropout": 0.2,
"hidden_dim": 512,
"max_conv_dim": 512,
"max_dur": 50,
"multispeaker": true,
"n_layer": 3,
"n_mels": 80,
"n_token": 178,
"style_dim": 128,
"text_encoder_kernel_size": 5,
"plbert": {
"hidden_size": 768,
"num_attention_heads": 12,
"intermediate_size": 2048,
"max_position_embeddings": 512,
"num_hidden_layers": 12,
"dropout": 0.1
},
"vocab": {
";": 1,
":": 2,
",": 3,
".": 4,
"!": 5,
"?": 6,
"—": 9,
"…": 10,
"\"": 11,
"(": 12,
")": 13,
"“": 14,
"”": 15,
" ": 16,
"̃": 17,
"ʣ": 18,
"ʥ": 19,
"ʦ": 20,
"ʨ": 21,
"ᵝ": 22,
"ꭧ": 23,
"A": 24,
"I": 25,
"O": 31,
"Q": 33,
"S": 35,
"T": 36,
"W": 39,
"Y": 41,
"ᵊ": 42,
"a": 43,
"b": 44,
"c": 45,
"d": 46,
"e": 47,
"f": 48,
"h": 50,
"i": 51,
"j": 52,
"k": 53,
"l": 54,
"m": 55,
"n": 56,
"o": 57,
"p": 58,
"q": 59,
"r": 60,
"s": 61,
"t": 62,
"u": 63,
"v": 64,
"w": 65,
"x": 66,
"y": 67,
"z": 68,
"ɑ": 69,
"ɐ": 70,
"ɒ": 71,
"æ": 72,
"β": 75,
"ɔ": 76,
"ɕ": 77,
"ç": 78,
"ɖ": 80,
"ð": 81,
"ʤ": 82,
"ə": 83,
"ɚ": 85,
"ɛ": 86,
"ɜ": 87,
"ɟ": 90,
"ɡ": 92,
"ɥ": 99,
"ɨ": 101,
"ɪ": 102,
"ʝ": 103,
"ɯ": 110,
"ɰ": 111,
"ŋ": 112,
"ɳ": 113,
"ɲ": 114,
"ɴ": 115,
"ø": 116,
"ɸ": 118,
"θ": 119,
"œ": 120,
"ɹ": 123,
"ɾ": 125,
"ɻ": 126,
"ʁ": 128,
"ɽ": 129,
"ʂ": 130,
"ʃ": 131,
"ʈ": 132,
"ʧ": 133,
"ʊ": 135,
"ʋ": 136,
"ʌ": 138,
"ɣ": 139,
"ɤ": 140,
"χ": 142,
"ʎ": 143,
"ʒ": 147,
"ʔ": 148,
"ˈ": 156,
"ˌ": 157,
"ː": 158,
"ʰ": 162,
"ʲ": 164,
"↓": 169,
"→": 171,
"↗": 172,
"↘": 173,
"ᵻ": 177,
"↑": 170
},
"language": "th",
"model_type": "paradee-1.1",
"num_parameters": 7877918,
"architecture": "Paradee 1.1 (TextStudent s+mlp + VDecoder vhead v2)"
}
Binary file not shown.
Loading
Loading