Spaces:
Running
Running
Yurii Paniv
commited on
Commit
•
2ffc7e7
1
Parent(s):
9ddc3f7
black everything
Browse files- app.py +13 -7
- data_logger.py +11 -11
- pytest.ini +1 -1
- requirements-test.txt +2 -1
- setup.py +17 -16
- tests/test_formatter.py +10 -4
- tests/test_stress.py +38 -14
- tests/test_tts.py +2 -1
- ukrainian_tts/formatter.py +1 -2
- ukrainian_tts/stress.py +2 -2
- ukrainian_tts/tts.py +12 -16
app.py
CHANGED
@@ -12,7 +12,9 @@ from time import sleep
|
|
12 |
|
13 |
|
14 |
def check_thread(logging_queue: Queue):
|
15 |
-
logging_callback = log_data(
|
|
|
|
|
16 |
while True:
|
17 |
sleep(60)
|
18 |
batch = []
|
@@ -23,10 +25,13 @@ def check_thread(logging_queue: Queue):
|
|
23 |
try:
|
24 |
logging_callback(batch)
|
25 |
except:
|
26 |
-
print(
|
|
|
|
|
27 |
for item in batch:
|
28 |
logging_queue.put(item)
|
29 |
|
|
|
30 |
if getenv("HF_API_TOKEN") is not None:
|
31 |
log_queue = Queue()
|
32 |
t = Thread(target=check_thread, args=(log_queue,))
|
@@ -45,6 +50,7 @@ class VoiceOption(Enum):
|
|
45 |
Dmytro = "Дмитро (чоловічий) 👨"
|
46 |
Olga = "Ольга (жіночий) 👩"
|
47 |
|
|
|
48 |
print(f"CUDA available? {is_available()}")
|
49 |
|
50 |
badge = (
|
@@ -70,7 +76,7 @@ def tts(text: str, voice: str, stress: str):
|
|
70 |
}
|
71 |
stress_mapping = {
|
72 |
StressOption.AutomaticStress.value: Stress.Dictionary.value,
|
73 |
-
StressOption.AutomaticStressWithModel.value: Stress.Model.value
|
74 |
}
|
75 |
|
76 |
speaker_name = voice_mapping[voice]
|
@@ -79,7 +85,7 @@ def tts(text: str, voice: str, stress: str):
|
|
79 |
text = (
|
80 |
text if len(text) < text_limit else text[0:text_limit]
|
81 |
) # mitigate crashes on hf space
|
82 |
-
|
83 |
if getenv("HF_API_TOKEN") is not None:
|
84 |
log_queue.put([text, speaker_name, stress_selected, str(datetime.utcnow())])
|
85 |
|
@@ -90,7 +96,7 @@ def tts(text: str, voice: str, stress: str):
|
|
90 |
|
91 |
with open("README.md") as file:
|
92 |
article = file.read()
|
93 |
-
article = article[article.find("---\n", 4) + 5
|
94 |
|
95 |
|
96 |
iface = gr.Interface(
|
@@ -108,7 +114,7 @@ iface = gr.Interface(
|
|
108 |
gr.components.Radio(
|
109 |
label="Наголоси",
|
110 |
choices=[option.value for option in StressOption],
|
111 |
-
value=StressOption.AutomaticStress.value
|
112 |
),
|
113 |
],
|
114 |
outputs=[
|
@@ -144,6 +150,6 @@ iface = gr.Interface(
|
|
144 |
VoiceOption.Lada.value,
|
145 |
StressOption.AutomaticStress.value,
|
146 |
],
|
147 |
-
]
|
148 |
)
|
149 |
iface.launch(enable_queue=True)
|
|
|
12 |
|
13 |
|
14 |
def check_thread(logging_queue: Queue):
|
15 |
+
logging_callback = log_data(
|
16 |
+
hf_token=getenv("HF_API_TOKEN"), dataset_name="uk-tts-output", private=True
|
17 |
+
)
|
18 |
while True:
|
19 |
sleep(60)
|
20 |
batch = []
|
|
|
25 |
try:
|
26 |
logging_callback(batch)
|
27 |
except:
|
28 |
+
print(
|
29 |
+
"Error happened while pushing data to HF. Puttting items back in queue..."
|
30 |
+
)
|
31 |
for item in batch:
|
32 |
logging_queue.put(item)
|
33 |
|
34 |
+
|
35 |
if getenv("HF_API_TOKEN") is not None:
|
36 |
log_queue = Queue()
|
37 |
t = Thread(target=check_thread, args=(log_queue,))
|
|
|
50 |
Dmytro = "Дмитро (чоловічий) 👨"
|
51 |
Olga = "Ольга (жіночий) 👩"
|
52 |
|
53 |
+
|
54 |
print(f"CUDA available? {is_available()}")
|
55 |
|
56 |
badge = (
|
|
|
76 |
}
|
77 |
stress_mapping = {
|
78 |
StressOption.AutomaticStress.value: Stress.Dictionary.value,
|
79 |
+
StressOption.AutomaticStressWithModel.value: Stress.Model.value,
|
80 |
}
|
81 |
|
82 |
speaker_name = voice_mapping[voice]
|
|
|
85 |
text = (
|
86 |
text if len(text) < text_limit else text[0:text_limit]
|
87 |
) # mitigate crashes on hf space
|
88 |
+
|
89 |
if getenv("HF_API_TOKEN") is not None:
|
90 |
log_queue.put([text, speaker_name, stress_selected, str(datetime.utcnow())])
|
91 |
|
|
|
96 |
|
97 |
with open("README.md") as file:
|
98 |
article = file.read()
|
99 |
+
article = article[article.find("---\n", 4) + 5 : :]
|
100 |
|
101 |
|
102 |
iface = gr.Interface(
|
|
|
114 |
gr.components.Radio(
|
115 |
label="Наголоси",
|
116 |
choices=[option.value for option in StressOption],
|
117 |
+
value=StressOption.AutomaticStress.value,
|
118 |
),
|
119 |
],
|
120 |
outputs=[
|
|
|
150 |
VoiceOption.Lada.value,
|
151 |
StressOption.AutomaticStress.value,
|
152 |
],
|
153 |
+
],
|
154 |
)
|
155 |
iface.launch(enable_queue=True)
|
data_logger.py
CHANGED
@@ -3,21 +3,22 @@ import os
|
|
3 |
import csv
|
4 |
import huggingface_hub
|
5 |
|
|
|
6 |
def log_data(hf_token: str, dataset_name: str, private=True):
|
7 |
path_to_dataset_repo = huggingface_hub.create_repo(
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
flagging_dir = "flagged"
|
15 |
dataset_dir = os.path.join(flagging_dir, dataset_name)
|
16 |
repo = huggingface_hub.Repository(
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
repo.git_pull(lfs=True)
|
22 |
log_file = os.path.join(dataset_dir, "data.csv")
|
23 |
|
@@ -38,4 +39,3 @@ def log_data(hf_token: str, dataset_name: str, private=True):
|
|
38 |
return line_count
|
39 |
|
40 |
return log_function
|
41 |
-
|
|
|
3 |
import csv
|
4 |
import huggingface_hub
|
5 |
|
6 |
+
|
7 |
def log_data(hf_token: str, dataset_name: str, private=True):
|
8 |
path_to_dataset_repo = huggingface_hub.create_repo(
|
9 |
+
repo_id=dataset_name,
|
10 |
+
token=hf_token,
|
11 |
+
private=private,
|
12 |
+
repo_type="dataset",
|
13 |
+
exist_ok=True,
|
14 |
+
)
|
15 |
flagging_dir = "flagged"
|
16 |
dataset_dir = os.path.join(flagging_dir, dataset_name)
|
17 |
repo = huggingface_hub.Repository(
|
18 |
+
local_dir=dataset_dir,
|
19 |
+
clone_from=path_to_dataset_repo,
|
20 |
+
use_auth_token=hf_token,
|
21 |
+
)
|
22 |
repo.git_pull(lfs=True)
|
23 |
log_file = os.path.join(dataset_dir, "data.csv")
|
24 |
|
|
|
39 |
return line_count
|
40 |
|
41 |
return log_function
|
|
pytest.ini
CHANGED
@@ -1,2 +1,2 @@
|
|
1 |
[pytest]
|
2 |
-
addopts = --ignore=training --cov=ukrainian_tts
|
|
|
1 |
[pytest]
|
2 |
+
addopts = --ignore=training --cov=ukrainian_tts --cov-branch
|
requirements-test.txt
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
-r requirements.txt
|
2 |
|
3 |
pytest==7.2.0
|
4 |
-
pytest-cov==4.0.0
|
|
|
|
1 |
-r requirements.txt
|
2 |
|
3 |
pytest==7.2.0
|
4 |
+
pytest-cov==4.0.0
|
5 |
+
black
|
setup.py
CHANGED
@@ -1,19 +1,20 @@
|
|
1 |
#!/usr/bin/env python
|
2 |
from setuptools import setup, find_packages
|
3 |
|
4 |
-
setup(
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
|
|
|
1 |
#!/usr/bin/env python
|
2 |
from setuptools import setup, find_packages
|
3 |
|
4 |
+
setup(
|
5 |
+
name="ukrainian-tts",
|
6 |
+
version="3.0",
|
7 |
+
description="Ukrainian TTS using Coqui TTS",
|
8 |
+
author="Yurii Paniv",
|
9 |
+
author_email="mr.robinhad@gmail.com",
|
10 |
+
url="https://github.com/robinhad/ukrainian-tts",
|
11 |
+
license="GPLv3",
|
12 |
+
packages=find_packages(),
|
13 |
+
python_requires=">3.6.0",
|
14 |
+
install_requires=[
|
15 |
+
"torch>=1.9",
|
16 |
+
"TTS==0.9.0",
|
17 |
+
"ukrainian-word-stress==1.0.1",
|
18 |
+
"ukrainian_accentor @ git+https://github.com/egorsmkv/ukrainian-accentor.git@5b7971c4e135e3ff3283336962e63fc0b1c80f4c",
|
19 |
+
],
|
20 |
+
)
|
tests/test_formatter.py
CHANGED
@@ -5,10 +5,16 @@ def test_formatter():
|
|
5 |
examples = [
|
6 |
("Quality of life update", "КВюаліті оф ліфе юпдате"),
|
7 |
("Він украв 20000000 $", "Він украв двадцять мільйонів долар"),
|
8 |
-
(
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
("це 19-річне вино.", "це дев'ятнадцять-річне вино."),
|
11 |
-
("10-30-40-50-5-9-5", "десять-тридцять-сорок-п'ятдесят-п'ять-дев'ять-п'ять")
|
12 |
]
|
13 |
for item in examples:
|
14 |
-
assert preprocess_text(item[0]) == item[1]
|
|
|
5 |
examples = [
|
6 |
("Quality of life update", "КВюаліті оф ліфе юпдате"),
|
7 |
("Він украв 20000000 $", "Він украв двадцять мільйонів долар"),
|
8 |
+
(
|
9 |
+
"111 000 000 000 доларів державного боргу.",
|
10 |
+
"сто одинадцять мільярдів доларів державного боргу.",
|
11 |
+
),
|
12 |
+
(
|
13 |
+
"11100000001 доларів державного боргу.",
|
14 |
+
"одинадцять мільярдів сто мільйонів один доларів державного боргу.",
|
15 |
+
),
|
16 |
("це 19-річне вино.", "це дев'ятнадцять-річне вино."),
|
17 |
+
("10-30-40-50-5-9-5", "десять-тридцять-сорок-п'ятдесят-п'ять-дев'ять-п'ять"),
|
18 |
]
|
19 |
for item in examples:
|
20 |
+
assert preprocess_text(item[0]) == item[1]
|
tests/test_stress.py
CHANGED
@@ -3,36 +3,60 @@ from ukrainian_tts.stress import sentence_to_stress, stress_with_model
|
|
3 |
|
4 |
def test_stress_table():
|
5 |
examples = [
|
6 |
-
("Бабин біб розцвів у дощ — Буде бабі біб у борщ.\n\nБоронила", "Б+абин б+іб розцв+ів +у д+ощ — Б+уде б+абі б+іб +у б+орщ.\n\nБорон+ила"),
|
7 |
-
("Бабин біб розцвів у дощ — Буде бабі біб у борщ.,,Боронила", "Б+абин б+іб розцв+ів +у д+ощ — Б+уде б+абі б+іб +у б+орщ.,,Борон+ила"),
|
8 |
-
("Бабин біб розцвів у дощ — Буде бабі біб у борщ.\n\n", "Б+абин б+іб розцв+ів +у д+ощ — Б+уде б+абі б+іб +у б+орщ.\n\n"),
|
9 |
-
("Бобер на березі з бобренятами бублики пік.","Боб+ер н+а березі з бобрен+ятами б+ублики п+ік."),
|
10 |
(
|
11 |
-
"
|
12 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
("Привіт, як тебе звати?", "Прив+іт, +як теб+е зв+ати?"),
|
14 |
("АННА - український панк-рок гурт", "+АННА - укра+їнський панк-р+ок г+урт"),
|
15 |
-
(
|
16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
("два + два", "дв+а + дв+а"),
|
18 |
("Н тльк в крн тк мж бт.", "Н тльк в крн тк мж бт."),
|
19 |
-
|
20 |
]
|
21 |
for item in examples:
|
22 |
assert sentence_to_stress(item[0]) == item[1]
|
23 |
|
24 |
examples = [
|
25 |
(
|
26 |
-
"Кам'янець-Подільський - місто в Хмельницькій області України, центр Кам'янець-Подільської міської об'єднаної територіальної громади і Кам'янець-Подільського району.",
|
27 |
-
"к+ам'янець-под+ільський - м+істо в хм+ельницькій обл+асті укра+їни, ц+ентр к+ам'янець-под+ільської м+іської об'+єднаної територі+альної гром+ади +і к+ам'янець-под+ільського рай+ону."
|
28 |
),
|
29 |
("Привіт, як тебе звати?", "прив+іт, +як т+ебе зв+ати?"),
|
30 |
("АННА - український панк-рок гурт", "+анна - укра+їнський п+анк-р+ок г+урт"),
|
31 |
-
(
|
32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
("два + два", "дв+а + дв+а"),
|
34 |
("Н тльк в крн тк мж бт.", "н тльк в крн тк мж бт."),
|
35 |
]
|
36 |
|
37 |
for item in examples:
|
38 |
-
assert sentence_to_stress(item[0], stress_function=stress_with_model) == item[1]
|
|
|
3 |
|
4 |
def test_stress_table():
|
5 |
examples = [
|
|
|
|
|
|
|
|
|
6 |
(
|
7 |
+
"Бабин біб розцвів у дощ — Буде бабі біб у борщ.\n\nБоронила",
|
8 |
+
"Б+абин б+іб розцв+ів +у д+ощ — Б+уде б+абі б+іб +у б+орщ.\n\nБорон+ила",
|
9 |
+
),
|
10 |
+
(
|
11 |
+
"Бабин біб розцвів у дощ — Буде бабі біб у борщ.,,Боронила",
|
12 |
+
"Б+абин б+іб розцв+ів +у д+ощ — Б+уде б+абі б+іб +у б+орщ.,,Борон+ила",
|
13 |
+
),
|
14 |
+
(
|
15 |
+
"Бабин біб розцвів у дощ — Буде бабі біб у борщ.\n\n",
|
16 |
+
"Б+абин б+іб розцв+ів +у д+ощ — Б+уде б+абі б+іб +у б+орщ.\n\n",
|
17 |
+
),
|
18 |
+
(
|
19 |
+
"Бобер на березі з бобренятами бублики пік.",
|
20 |
+
"Боб+ер н+а березі з бобрен+ятами б+ублики п+ік.",
|
21 |
+
),
|
22 |
+
(
|
23 |
+
"Кам'янець-Подільський - місто в Хмельницькій області України, центр Кам'янець-Подільської міської об'єднаної територіальної громади і Кам'янець-Подільського району.",
|
24 |
+
"Кам'ян+ець-Под+ільський - м+істо в Хмельн+ицькій +області Укра+їни, ц+ентр Кам'ян+ець-Под+ільської міськ+ої об'+єднаної територі+альної гром+ади +і Кам'ян+ець-Под+ільського рай+ону.",
|
25 |
+
),
|
26 |
("Привіт, як тебе звати?", "Прив+іт, +як теб+е зв+ати?"),
|
27 |
("АННА - український панк-рок гурт", "+АННА - укра+їнський панк-р+ок г+урт"),
|
28 |
+
(
|
29 |
+
"Не тільки в Україні таке може бути.",
|
30 |
+
"Н+е т+ільки в Укра+їні так+е м+оже б+ути.",
|
31 |
+
),
|
32 |
+
(
|
33 |
+
"Не тільки в +Укра+їні т+аке може бути.",
|
34 |
+
"Н+е т+ільки в +Укра+їні т+аке м+оже б+ути.",
|
35 |
+
),
|
36 |
("два + два", "дв+а + дв+а"),
|
37 |
("Н тльк в крн тк мж бт.", "Н тльк в крн тк мж бт."),
|
|
|
38 |
]
|
39 |
for item in examples:
|
40 |
assert sentence_to_stress(item[0]) == item[1]
|
41 |
|
42 |
examples = [
|
43 |
(
|
44 |
+
"Кам'янець-Подільський - місто в Хмельницькій області України, центр Кам'янець-Подільської міської об'єднаної територіальної громади і Кам'янець-Подільського району.",
|
45 |
+
"к+ам'янець-под+ільський - м+істо в хм+ельницькій обл+асті укра+їни, ц+ентр к+ам'янець-под+ільської м+іської об'+єднаної територі+альної гром+ади +і к+ам'янець-под+ільського рай+ону.",
|
46 |
),
|
47 |
("Привіт, як тебе звати?", "прив+іт, +як т+ебе зв+ати?"),
|
48 |
("АННА - український панк-рок гурт", "+анна - укра+їнський п+анк-р+ок г+урт"),
|
49 |
+
(
|
50 |
+
"Не тільки в Україні таке може бути.",
|
51 |
+
"н+е т+ільки в укра+їні т+аке м+оже б+ути.",
|
52 |
+
),
|
53 |
+
(
|
54 |
+
"Не тільки в +Укра+їні т+аке може бути.",
|
55 |
+
"н+е т+ільки в +Укра+їні т+аке м+оже б+ути.",
|
56 |
+
),
|
57 |
("два + два", "дв+а + дв+а"),
|
58 |
("Н тльк в крн тк мж бт.", "н тльк в крн тк мж бт."),
|
59 |
]
|
60 |
|
61 |
for item in examples:
|
62 |
+
assert sentence_to_stress(item[0], stress_function=stress_with_model) == item[1]
|
tests/test_tts.py
CHANGED
@@ -1,10 +1,11 @@
|
|
1 |
from ukrainian_tts.tts import TTS, Voices, Stress
|
2 |
from io import BytesIO
|
3 |
|
|
|
4 |
def test_tts():
|
5 |
tts = TTS(use_cuda=False)
|
6 |
file = BytesIO()
|
7 |
_, text = tts.tts("Привіт", Voices.Dmytro.value, Stress.Dictionary.value, file)
|
8 |
file.seek(0)
|
9 |
assert text == "Прив+іт"
|
10 |
-
assert file.getbuffer().nbytes > 1000
|
|
|
1 |
from ukrainian_tts.tts import TTS, Voices, Stress
|
2 |
from io import BytesIO
|
3 |
|
4 |
+
|
5 |
def test_tts():
|
6 |
tts = TTS(use_cuda=False)
|
7 |
file = BytesIO()
|
8 |
_, text = tts.tts("Привіт", Voices.Dmytro.value, Stress.Dictionary.value, file)
|
9 |
file.seek(0)
|
10 |
assert text == "Прив+іт"
|
11 |
+
assert file.getbuffer().nbytes > 1000 # check that file was generated
|
ukrainian_tts/formatter.py
CHANGED
@@ -76,5 +76,4 @@ def preprocess_text(text, use_autostress_model=False):
|
|
76 |
text = text.replace(english_char.upper(), english[english_char].upper())
|
77 |
text = text.replace(english_char, english[english_char])
|
78 |
|
79 |
-
|
80 |
-
return text
|
|
|
76 |
text = text.replace(english_char.upper(), english[english_char].upper())
|
77 |
text = text.replace(english_char, english[english_char])
|
78 |
|
79 |
+
return text
|
|
ukrainian_tts/stress.py
CHANGED
@@ -69,7 +69,7 @@ def sentence_to_stress(sentence: str, stress_function=stress_dict) -> str:
|
|
69 |
# add remainder
|
70 |
if previous != len(new_stressed):
|
71 |
new_list.append(new_stressed[previous:])
|
72 |
-
|
73 |
# add stress to single-vowel words
|
74 |
for word_index in range(0, len(new_list)):
|
75 |
element = new_list[word_index]
|
@@ -89,4 +89,4 @@ def sentence_to_stress(sentence: str, stress_function=stress_dict) -> str:
|
|
89 |
for stressed in all_stresses:
|
90 |
words[stressed] = orig_words[stressed]
|
91 |
return " ".join(words)
|
92 |
-
return new_stressed
|
|
|
69 |
# add remainder
|
70 |
if previous != len(new_stressed):
|
71 |
new_list.append(new_stressed[previous:])
|
72 |
+
|
73 |
# add stress to single-vowel words
|
74 |
for word_index in range(0, len(new_list)):
|
75 |
element = new_list[word_index]
|
|
|
89 |
for stressed in all_stresses:
|
90 |
words[stressed] = orig_words[stressed]
|
91 |
return " ".join(words)
|
92 |
+
return new_stressed
|
ukrainian_tts/tts.py
CHANGED
@@ -7,8 +7,10 @@ from .formatter import preprocess_text
|
|
7 |
from .stress import sentence_to_stress, stress_dict, stress_with_model
|
8 |
from torch import no_grad
|
9 |
|
|
|
10 |
class Voices(Enum):
|
11 |
"""List of available voices for the model."""
|
|
|
12 |
Olena = "olena"
|
13 |
Mykyta = "mykyta"
|
14 |
Lada = "lada"
|
@@ -20,14 +22,14 @@ class Stress(Enum):
|
|
20 |
"""Options how to stress sentence.
|
21 |
- `dictionary` - performs lookup in dictionary, taking into account grammatical case of a word and its' neighbors
|
22 |
- `model` - stress using transformer model"""
|
|
|
23 |
Dictionary = "dictionary"
|
24 |
Model = "model"
|
25 |
|
26 |
|
27 |
class TTS:
|
28 |
-
"""
|
29 |
-
|
30 |
-
"""
|
31 |
def __init__(self, cache_folder=None, use_cuda=False) -> None:
|
32 |
"""
|
33 |
Class to setup a text-to-speech engine, from download to model creation. \n
|
@@ -35,7 +37,6 @@ class TTS:
|
|
35 |
By default stores in current directory."""
|
36 |
self.__setup_cache(cache_folder, use_cuda=use_cuda)
|
37 |
|
38 |
-
|
39 |
def tts(self, text: str, voice: str, stress: str, output_fp=BytesIO()):
|
40 |
"""
|
41 |
Run a Text-to-Speech engine and output to `output_fp` BytesIO-like object.
|
@@ -46,14 +47,18 @@ class TTS:
|
|
46 |
"""
|
47 |
|
48 |
if stress not in [option.value for option in Stress]:
|
49 |
-
raise ValueError(
|
|
|
|
|
50 |
|
51 |
if stress == Stress.Model.value:
|
52 |
stress = True
|
53 |
else:
|
54 |
stress = False
|
55 |
if voice not in [option.value for option in Voices]:
|
56 |
-
raise ValueError(
|
|
|
|
|
57 |
|
58 |
text = preprocess_text(text, stress)
|
59 |
text = sentence_to_stress(text, stress_with_model if stress else stress_dict)
|
@@ -66,7 +71,6 @@ class TTS:
|
|
66 |
|
67 |
return output_fp, text
|
68 |
|
69 |
-
|
70 |
def __setup_cache(self, cache_folder=None, use_cuda=False):
|
71 |
"""Downloads models and stores them into `cache_folder`. By default stores in current directory."""
|
72 |
print("downloading uk/mykyta/vits-tts")
|
@@ -87,18 +91,12 @@ class TTS:
|
|
87 |
self.__download(speakers_link, speakers_path)
|
88 |
|
89 |
self.synthesizer = Synthesizer(
|
90 |
-
model_path,
|
91 |
-
config_path,
|
92 |
-
speakers_path,
|
93 |
-
None,
|
94 |
-
None,
|
95 |
-
use_cuda=use_cuda
|
96 |
)
|
97 |
|
98 |
if self.synthesizer is None:
|
99 |
raise NameError("Model not found")
|
100 |
|
101 |
-
|
102 |
def __download(self, url, file_name):
|
103 |
"""Downloads file from `url` into local `file_name` file."""
|
104 |
if not exists(file_name):
|
@@ -108,5 +106,3 @@ class TTS:
|
|
108 |
file.write(r.content)
|
109 |
else:
|
110 |
print(f"Found {file_name}. Skipping download...")
|
111 |
-
|
112 |
-
|
|
|
7 |
from .stress import sentence_to_stress, stress_dict, stress_with_model
|
8 |
from torch import no_grad
|
9 |
|
10 |
+
|
11 |
class Voices(Enum):
|
12 |
"""List of available voices for the model."""
|
13 |
+
|
14 |
Olena = "olena"
|
15 |
Mykyta = "mykyta"
|
16 |
Lada = "lada"
|
|
|
22 |
"""Options how to stress sentence.
|
23 |
- `dictionary` - performs lookup in dictionary, taking into account grammatical case of a word and its' neighbors
|
24 |
- `model` - stress using transformer model"""
|
25 |
+
|
26 |
Dictionary = "dictionary"
|
27 |
Model = "model"
|
28 |
|
29 |
|
30 |
class TTS:
|
31 |
+
""" """
|
32 |
+
|
|
|
33 |
def __init__(self, cache_folder=None, use_cuda=False) -> None:
|
34 |
"""
|
35 |
Class to setup a text-to-speech engine, from download to model creation. \n
|
|
|
37 |
By default stores in current directory."""
|
38 |
self.__setup_cache(cache_folder, use_cuda=use_cuda)
|
39 |
|
|
|
40 |
def tts(self, text: str, voice: str, stress: str, output_fp=BytesIO()):
|
41 |
"""
|
42 |
Run a Text-to-Speech engine and output to `output_fp` BytesIO-like object.
|
|
|
47 |
"""
|
48 |
|
49 |
if stress not in [option.value for option in Stress]:
|
50 |
+
raise ValueError(
|
51 |
+
f"Invalid value for stress option selected! Please use one of the following values: {', '.join([option.value for option in Stress])}."
|
52 |
+
)
|
53 |
|
54 |
if stress == Stress.Model.value:
|
55 |
stress = True
|
56 |
else:
|
57 |
stress = False
|
58 |
if voice not in [option.value for option in Voices]:
|
59 |
+
raise ValueError(
|
60 |
+
f"Invalid value for voice selected! Please use one of the following values: {', '.join([option.value for option in Voices])}."
|
61 |
+
)
|
62 |
|
63 |
text = preprocess_text(text, stress)
|
64 |
text = sentence_to_stress(text, stress_with_model if stress else stress_dict)
|
|
|
71 |
|
72 |
return output_fp, text
|
73 |
|
|
|
74 |
def __setup_cache(self, cache_folder=None, use_cuda=False):
|
75 |
"""Downloads models and stores them into `cache_folder`. By default stores in current directory."""
|
76 |
print("downloading uk/mykyta/vits-tts")
|
|
|
91 |
self.__download(speakers_link, speakers_path)
|
92 |
|
93 |
self.synthesizer = Synthesizer(
|
94 |
+
model_path, config_path, speakers_path, None, None, use_cuda=use_cuda
|
|
|
|
|
|
|
|
|
|
|
95 |
)
|
96 |
|
97 |
if self.synthesizer is None:
|
98 |
raise NameError("Model not found")
|
99 |
|
|
|
100 |
def __download(self, url, file_name):
|
101 |
"""Downloads file from `url` into local `file_name` file."""
|
102 |
if not exists(file_name):
|
|
|
106 |
file.write(r.content)
|
107 |
else:
|
108 |
print(f"Found {file_name}. Skipping download...")
|
|
|
|