Files
storyteller-ml/tts/text/pipeline/espeak_pipeline.py
T

81 lines
3.6 KiB
Python

from typing import List
from text.pipeline.base_pipeline import BasePipeline
from text.pipeline_components.input_parsing.parser import ArpabetSequence, GraphemeSequence, ParsedSequence, parse_grapheme_and_arpabet_sequence
from text.pipeline_components.normalization.espeak_normalization import normalize
from text.pipeline_components.phonetization.espeak_phonemization import EspeakPhonetization
from text.pipeline_components.sequencing.espeak_symbols import Symbols
class EspeakPipeline(BasePipeline):
"""
This is a new text pipeline for FakeYou that will be introduced in July 2022.
It introduces Arpabet and individually upgradable components.
The code is not 1:1 with our notebooks, but we'll go to efforts to make sure that
the model input expectations on both sides match one another.
"""
def __init__(self, lang='en'):
self.lang = lang
symbols = Symbols(lang)
self.symbols_to_sequence = symbols.symbols_to_sequence
self.arpabet_to_sequence = symbols.arpabet_to_sequence
self.sequence_to_text = symbols.sequence_to_text
self.SPACE_INTEGER_ENCODING = symbols.SPACE_INTEGER_ENCODING
self.phonetization = EspeakPhonetization(lang)
def user_input_to_sequence(self, input_text: str) -> List[int]:
"""Convert raw user input into a numerical sequence for ML inference."""
parsed_sequence = parse_grapheme_and_arpabet_sequence(input_text)
self._normalize_graphemes(parsed_sequence)
parsed_sequence = self._convert_phonemes(parsed_sequence)
return self._convert_to_integer_sequence(parsed_sequence)
def sequence_to_text(self, input_sequence: List[int]) -> str:
return self.sequence_to_text(input_sequence)
def _normalize_graphemes(self, parsed_sequence: ParsedSequence):
for i in range(len(parsed_sequence)):
subsequence = parsed_sequence[i]
if isinstance(subsequence, GraphemeSequence):
normalized = normalize(subsequence.sequence, self.lang)
parsed_sequence[i] = GraphemeSequence(normalized)
def _convert_phonemes(self, parsed_sequence: ParsedSequence) -> ParsedSequence:
# NB: We will likely break grapheme runs into multiple arpabet sequences, extending the
# output list length.
updated_sequence = []
for subsequence in parsed_sequence:
if isinstance(subsequence, ArpabetSequence):
updated_sequence.append(subsequence)
elif isinstance(subsequence, GraphemeSequence):
converted_sequence = self.phonetization.try_convert_to_phonemes(subsequence.sequence)
updated_sequence.extend(converted_sequence)
return updated_sequence
def _convert_to_integer_sequence(self, parsed_sequence: ParsedSequence) -> List[int]:
integer_sequence = []
last_index = len(parsed_sequence) - 1
for i, subsequence in enumerate(parsed_sequence):
integer_subsequence = []
if isinstance(subsequence, ArpabetSequence):
integer_subsequence = self.arpabet_to_sequence(subsequence.sequence)
elif isinstance(subsequence, GraphemeSequence):
integer_subsequence = self.symbols_to_sequence(subsequence.sequence)
if integer_subsequence:
integer_sequence.extend(integer_subsequence)
if i < last_index and integer_sequence[-1] != self.SPACE_INTEGER_ENCODING:
# Separate words with single spaces if not already present.
integer_sequence.append(self.SPACE_INTEGER_ENCODING)
return integer_sequence