Skip to content

Commit f3ce6a2

Browse files
committed
Added tts api
1 parent 6cb631f commit f3ce6a2

File tree

2 files changed

+179
-2
lines changed

2 files changed

+179
-2
lines changed

scratchattach/other/other_apis.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from ..utils import commons
77
from ..utils.exceptions import BadRequest
88
from ..utils.requests import Requests as requests
9-
from ..utils.supportedlangs import SUPPORTED_CODES, SUPPORTED_NAMES
9+
from ..utils.supportedlangs import SUPPORTED_CODES, SUPPORTED_NAMES, tts_lang
1010

1111

1212
# --- Front page ---
@@ -163,3 +163,41 @@ def translate(language: str, text: str = "hello"):
163163
return response_json["result"]
164164
else:
165165
raise BadRequest(f"Language '{language}' does not seem to be valid.\nResponse: {response_json}")
166+
167+
168+
def text2speech(text: str = "hello", gender: str = "female", language: str = "en-US"):
169+
"""
170+
Sends a request to Scratch's TTS synthesis service.
171+
Returns:
172+
- The TTS audio (mp3) as bytes
173+
- The playback rate (e.g. for giant it would be 0.84)
174+
"""
175+
if gender == "female" or gender == "alto":
176+
gender = ("female", 1)
177+
elif gender == "male" or gender == "tenor":
178+
gender = ("male", 1)
179+
elif gender == "squeak":
180+
gender = ("female", 1.19)
181+
elif gender == "giant":
182+
gender = ("male", .84)
183+
elif gender == "kitten":
184+
gender = ("female", 1.41)
185+
else:
186+
gender = ("female", 1)
187+
188+
if language not in SUPPORTED_NAMES:
189+
if language.lower() in SUPPORTED_NAMES:
190+
language = language.lower()
191+
192+
elif language.title() in SUPPORTED_CODES:
193+
language = SUPPORTED_NAMES[SUPPORTED_CODES.index(language.title())]
194+
195+
lang = tts_lang(language.title())
196+
if lang is None:
197+
warnings.warn(f"Language '{language}' is probably not a supported language")
198+
else:
199+
language = lang["speechSynthLocale"]
200+
201+
response = requests.get(f"https://synthesis-service.scratch.mit.edu/synth"
202+
f"?locale={language}&gender={gender[0]}&text={text}")
203+
return response.content, gender[1]

scratchattach/utils/supportedlangs.py

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"""
2-
List of supported languages of scratch's translate extension.
2+
List of supported languages of scratch's translate and text2speech extensions.
33
Adapted from https://translate-service.scratch.mit.edu/supported?language=en
44
"""
55

6+
# Supported langs for translate
67
SUPPORTED_LANGS = {'sq': 'Albanian', 'am': 'Amharic', 'ar': 'Arabic', 'hy': 'Armenian', 'az': 'Azerbaijani',
78
'eu': 'Basque', 'be': 'Belarusian', 'bg': 'Bulgarian', 'ca': 'Catalan',
89
'zh-tw': 'Chinese (Traditional)', 'hr': 'Croatian', 'cs': 'Czech', 'da': 'Danish', 'nl': 'Dutch',
@@ -27,3 +28,141 @@
2728
# for lang in raw:
2829
# SUPPORTED_LANGS[lang["code"]] = lang["name"]
2930
# print(SUPPORTED_LANGS)
31+
32+
# Language info for tts
33+
TTS_LANGUAGE_INFO = [
34+
{
35+
"name": 'Arabic',
36+
"locales": ['ar'],
37+
"speechSynthLocale": 'arb',
38+
"singleGender": True
39+
},
40+
{
41+
"name": 'Chinese (Mandarin)',
42+
"locales": ['zh-cn', 'zh-tw'],
43+
"speechSynthLocale": 'cmn-CN',
44+
"singleGender": True
45+
},
46+
{
47+
"name": 'Danish',
48+
"locales": ['da'],
49+
"speechSynthLocale": 'da-DK'
50+
},
51+
{
52+
"name": 'Dutch',
53+
"locales": ['nl'],
54+
"speechSynthLocale": 'nl-NL'
55+
},
56+
{
57+
"name": 'English',
58+
"locales": ['en'],
59+
"speechSynthLocale": 'en-US'
60+
},
61+
{
62+
"name": 'French',
63+
"locales": ['fr'],
64+
"speechSynthLocale": 'fr-FR'
65+
},
66+
{
67+
"name": 'German',
68+
"locales": ['de'],
69+
"speechSynthLocale": 'de-DE'
70+
},
71+
{
72+
"name": 'Hindi',
73+
"locales": ['hi'],
74+
"speechSynthLocale": 'hi-IN',
75+
"singleGender": True
76+
},
77+
{
78+
"name": 'Icelandic',
79+
"locales": ['is'],
80+
"speechSynthLocale": 'is-IS'
81+
},
82+
{
83+
"name": 'Italian',
84+
"locales": ['it'],
85+
"speechSynthLocale": 'it-IT'
86+
},
87+
{
88+
"name": 'Japanese',
89+
"locales": ['ja', 'ja-hira'],
90+
"speechSynthLocale": 'ja-JP'
91+
},
92+
{
93+
"name": 'Korean',
94+
"locales": ['ko'],
95+
"speechSynthLocale": 'ko-KR',
96+
"singleGender": True
97+
},
98+
{
99+
"name": 'Norwegian',
100+
"locales": ['nb', 'nn'],
101+
"speechSynthLocale": 'nb-NO',
102+
"singleGender": True
103+
},
104+
{
105+
"name": 'Polish',
106+
"locales": ['pl'],
107+
"speechSynthLocale": 'pl-PL'
108+
},
109+
{
110+
"name": 'Portuguese (Brazilian)',
111+
"locales": ['pt-br'],
112+
"speechSynthLocale": 'pt-BR'
113+
},
114+
{
115+
"name": 'Portuguese (European)',
116+
"locales": ['pt'],
117+
"speechSynthLocale": 'pt-PT'
118+
},
119+
{
120+
"name": 'Romanian',
121+
"locales": ['ro'],
122+
"speechSynthLocale": 'ro-RO',
123+
"singleGender": True
124+
},
125+
{
126+
"name": 'Russian',
127+
"locales": ['ru'],
128+
"speechSynthLocale": 'ru-RU'
129+
},
130+
{
131+
"name": 'Spanish (European)',
132+
"locales": ['es'],
133+
"speechSynthLocale": 'es-ES'
134+
},
135+
{
136+
"name": 'Spanish (Latin American)',
137+
"locales": ['es-419'],
138+
"speechSynthLocale": 'es-US'
139+
},
140+
{
141+
"name": 'Swedish',
142+
"locales": ['sv'],
143+
"speechSynthLocale": 'sv-SE',
144+
"singleGender": True
145+
},
146+
{
147+
"name": 'Turkish',
148+
"locales": ['tr'],
149+
"speechSynthLocale": 'tr-TR',
150+
"singleGender": True
151+
},
152+
{
153+
"name": 'Welsh',
154+
"locales": ['cy'],
155+
"speechSynthLocale": 'cy-GB',
156+
"singleGender": True
157+
}]
158+
159+
160+
def tts_lang(attribute: str, by: str = None):
161+
for lang in TTS_LANGUAGE_INFO:
162+
if by is None:
163+
if attribute in lang.values():
164+
return lang
165+
continue
166+
167+
if lang.get(by) == attribute:
168+
return lang

0 commit comments

Comments
 (0)