22 from requests_futures.sessions
import FuturesSession
23 from requests.exceptions
import (
24 ReadTimeout, ConnectionError, ConnectTimeout, HTTPError
26 from urllib
import parse
27 from .mimic_tts
import VISIMES
37 _max_sentence_size = 170
41 """ Yield successive n-sized chunks 44 l (list): text (str) to split 45 chunk_size (int): chunk size 47 for i
in range(0, len(l), n):
48 yield " ".join(l[i:i + n])
52 """ Split text into word chunks by chunk_size size 55 text (str): text to split 56 chunk_size (int): chunk size 59 list: list of text chunks 61 text_list = text.split()
63 if len(text_list) <= chunk_size:
66 if chunk_size < len(text_list) < (chunk_size * 2):
69 int(math.ceil(len(text_list) / 2))
71 elif (chunk_size * 2) < len(text_list) < (chunk_size * 3):
74 int(math.ceil(len(text_list) / 3))
76 elif (chunk_size * 3) < len(text_list) < (chunk_size * 4):
79 int(math.ceil(len(text_list) / 4))
84 int(math.ceil(len(text_list) / 5))
89 """splits text by various punctionations 90 e.g. hello, world => [hello, world] 93 chunks (list or str): text (str) to split 94 puncs (list): list of punctuations used to split text 97 list: list with split text 99 if isinstance(chunks, str):
110 splits += re.split(
r'(?<!\.\S)' + punc +
r'\s', t)
112 return [t.strip()
for t
in out]
116 """ Add punctuation at the end of each chunk. 118 Mimic2 expects some form of punctuation at the end of a sentence. 120 punctuation = [
'.',
'?',
'!',
';']
121 if len(text) >= 1
and text[-1]
not in punctuation:
128 """ Split text into smaller chunks for TTS generation. 130 NOTE: The smaller chunks are needed due to current Mimic2 TTS limitations. 131 This stage can be removed once Mimic2 can generate longer sentences. 134 text (str): text to split 135 chunk_size (int): size of each chunk 136 split_by_punc (bool, optional): Defaults to True. 139 list: list of text chunks 141 if len(text) <= _max_sentence_size:
147 puncs=[
r'\.',
r'\!',
r'\?',
r'\:',
r'\;']
152 for chunk
in first_splits:
153 if len(chunk) > _max_sentence_size:
155 puncs=[
r'\,',
'--',
'-'])
157 second_splits.append(chunk)
161 for chunk
in second_splits:
162 if len(chunk) > _max_sentence_size:
165 third_splits.append(chunk)
177 LOG.info(
"Getting Pre-loaded cache")
178 cache_handler.main(config[
'preloaded_cache'])
179 LOG.info(
"Successfully downloaded Pre-loaded cache")
180 except Exception
as e:
181 LOG.error(
"Could not get the pre-loaded cache ({})" 187 """ Save WAV files in tmp 190 data (byes): WAV data 192 with open(self.
filename,
'wb')
as f:
196 """ Play WAV file after saving to tmp 199 req (object): requests object 201 if req.status_code == 200:
202 self.
_save(req.content)
206 '%s Http Error: %s for url: %s' %
207 (req.status_code, req.reason, req.url))
210 """create asynchronous request list 213 chunks (list): list of text to synthesize 216 list: list of FutureSession objects 218 url = self.
url + parse.quote(sentence)
219 req_route = url +
"&visimes=True" 220 return self.session.get(req_route, timeout=5)
223 """ Maps phonemes to appropriate viseme encoding 226 phonemes (list): list of tuples (phoneme, time_start) 229 list: list of tuples (viseme_encoding, time_start) 232 for pair
in phonemes:
234 phone = pair[0].lower()
240 vis = VISIMES.get(phone)
241 vis_dur = float(pair[1])
242 visemes.append((vis, vis_dur))
246 """ Split sentence in chunks better suited for mimic2. """ 250 """ Generate (remotely) and play mimic2 WAV audio 253 sentence (str): Phrase to synthesize to audio with mimic2 254 wav_file (str): Location to write audio output 256 LOG.debug(
"Generating Mimic2 TSS for: " + str(sentence))
259 results = req.result().json()
260 audio = base64.b64decode(results[
'audio_base64'])
261 vis = results[
'visimes']
262 with open(wav_file,
'wb')
as f:
264 except (ReadTimeout, ConnectionError, ConnectTimeout, HTTPError):
266 "Mimic 2 server request timed out. Falling back to mimic")
267 return (wav_file, vis)
274 key: Hash key for the sentence 275 phonemes: phoneme string to save 278 pho_file = os.path.join(cache_dir, key +
".pho")
280 with open(pho_file,
"w")
as cachefile:
281 cachefile.write(json.dumps(phonemes))
283 LOG.exception(
"Failed to write {} to cache".format(pho_file))
287 Load phonemes from cache file. 290 Key: Key identifying phoneme cache 294 if os.path.exists(pho_file):
296 with open(pho_file,
"r") as cachefile: 297 phonemes = json.load(cachefile) 299 except Exception
as e:
300 LOG.error(
"Failed to read .PHO from cache ({})".format(e))
307 super(Mimic2Validator, self).
__init__(tts)
def save_phonemes(self, key, phonemes)
def validate_connection(self)
def _requests(self, sentence)
def _split_by_chunk_size(text, chunk_size)
def viseme(self, phonemes)
def load_phonemes(self, key)
def _split_by_punctuation(chunks, puncs)
def get_tts(self, sentence, wav_file)
def _prepocess_sentence(sentence)
def _add_punctuation(text)
def __init__(self, lang, config)
def get_cache_directory(domain=None)
def _sentence_chunker(text)