| import os |
| import sys |
| |
| |
| sys.path.insert(0, "./hifi-gan") |
| sys.path.insert(0, "./weights") |
|
|
| |
| import collections |
| import collections.abc |
| for type_name in collections.abc.__all__: |
| setattr(collections, type_name, getattr(collections.abc, type_name)) |
| |
|
|
| import nltk |
| from nltk.tokenize import word_tokenize |
| import re |
| import librosa |
| import yaml |
| import gradio as gr |
| import torch |
| import glob |
| from attrdict import AttrDict |
| import phonemizer |
| import json |
| from vocoder import Generator |
| from models import * |
| from utils import * |
| from ipa_uk.ipa_uk import ipa |
| import unicodedata |
| from ukrainian_word_stress import Stressifier, StressSymbol |
|
|
| nltk.download('punkt') |
| nltk.download('punkt_tab') |
| |
| device = 'cuda' if torch.cuda.is_available() else 'cpu' |
|
|
|
|
| |
| _pad = "$" |
| _punctuation = ';:,.!?¡¿—…"«»“” ' |
| _letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' |
| _letters_ipa = "ɑɐɒæɓʙβɔɕçɗɖðʤəɘɚɛɜɝɞɟʄɡɠɢʛɦɧħɥʜɨɪʝɭɬɫɮʟɱɯɰŋɳɲɴøɵɸθœɶʘɹɺɾɻʀʁɽʂʃʈʧʉʊʋⱱʌɣɤʍχʎʏʑʐʒʔʡʕʢǀǁǂǃˈˌːˑʼʴʰʱʲʷˠˤ˞↓↑→'̩'ᵻ" |
|
|
|
|
| |
| symbols = [_pad] + list(_punctuation) + list(_letters) + list(_letters_ipa) |
|
|
| dicts = {} |
| for i in range(len((symbols))): |
| dicts[symbols[i]] = i |
|
|
| class TextCleaner: |
| def __init__(self, dummy=None): |
| self.word_index_dictionary = dicts |
| def __call__(self, text): |
| indexes = [] |
| for char in text: |
| try: |
| indexes.append(self.word_index_dictionary[char]) |
| except KeyError: |
| print(char) |
| return indexes |
|
|
| textclenaer = TextCleaner() |
| |
|
|
| def load_checkpoint(filepath, device): |
| assert os.path.isfile(filepath) |
| print("Loading '{}'".format(filepath)) |
| checkpoint_dict = torch.load(filepath, map_location=device) |
| print("Complete.") |
| return checkpoint_dict |
|
|
| def scan_checkpoint(cp_dir, prefix): |
| pattern = os.path.join(cp_dir, prefix + '*') |
| cp_list = glob.glob(pattern) |
| if len(cp_list) == 0: |
| return '' |
| return sorted(cp_list)[-1] |
| |
|
|
| def greet(name): |
| return "Hello " + name + "!!" |
|
|
| |
| cp_g = scan_checkpoint("Vocoder/", 'g_') |
| config_file = os.path.join(os.path.split(cp_g)[0], 'config.json') |
| with open(config_file) as f: |
| data = f.read() |
| json_config = json.loads(data) |
| h = AttrDict(json_config) |
|
|
| device = torch.device(device) |
| generator = Generator(h).to(device) |
|
|
| state_dict_g = load_checkpoint(cp_g, device) |
| generator.load_state_dict(state_dict_g['generator']) |
| generator.eval() |
| generator.remove_weight_norm() |
| |
|
|
| |
| model_path = "./Models/UK/second_stage.pth" |
| model_config_path = "./Models/UK/config_uk.yml" |
| config = yaml.safe_load(open(model_config_path)) |
|
|
| |
| ASR_config = config.get('ASR_config', False) |
| ASR_path = config.get('ASR_path', False) |
| text_aligner = load_ASR_models(ASR_path, ASR_config) |
|
|
| |
| F0_path = config.get('F0_path', False) |
| pitch_extractor = load_F0_models(F0_path) |
|
|
| model = build_model(Munch(config['model_params']), text_aligner, pitch_extractor) |
| params = torch.load(model_path, map_location=device) |
| params = params['net'] |
| for key in model: |
| if key in params: |
| if not "discriminator" in key: |
| print('%s loaded' % key) |
| model[key].load_state_dict(params[key]) |
| _ = [model[key].eval() for key in model] |
| _ = [model[key].to(device) for key in model] |
| |
|
|
| |
| reference_embeddings = np.load("reference_embeddings.npy", allow_pickle=True).item() |
| |
|
|
| def remove_combining_diacritics(input_str): |
| return ''.join(char for char in unicodedata.normalize('NFD', input_str) if unicodedata.category(char) != 'Mn') |
|
|
| def tts(text: str): |
| stressify = Stressifier(stress_symbol = '\u02C8') |
|
|
| |
| text = text.strip() |
| text = text.replace('"', '') |
| text = text.replace('+', 'ˈ') |
| |
| text = re.sub(r'[{}()_*]', '', text) |
| text = re.sub(r'([!?.])[\./]+', r'\1', text) |
| text = text.replace('-', '') |
| |
| text = re.sub(r'[᠆‐‑‒–—―⁻₋−⸺⸻]', '—', text) |
| text = re.sub(r' - ', ': ', text) |
| |
| |
| |
|
|
| ps = [ipa(stressify(text), check_accent=False)] |
| ps = [remove_combining_diacritics(''.join(ps))] |
| |
| |
| |
| ipa2uk_phonemes = ps[0] |
| print(ps) |
| |
| ps = word_tokenize(ps[0]) |
| ps = ' '.join(ps) |
| tokens = textclenaer(ps) |
| tokens.insert(0, 0) |
| tokens.append(0) |
| tokens = torch.LongTensor(tokens).to(device).unsqueeze(0) |
| |
|
|
| |
| converted_samples = {} |
| |
| with torch.no_grad(): |
| input_lengths = torch.LongTensor([tokens.shape[-1]]).to(device) |
| m = length_to_mask(input_lengths).to(device) |
| t_en = model.text_encoder(tokens, input_lengths, m) |
| |
| for key, (ref, _) in reference_embeddings.items(): |
| |
| s = ref.squeeze(1) |
| style = s |
| |
| d = model.predictor.text_encoder(t_en, style, input_lengths, m) |
| |
| x, _ = model.predictor.lstm(d) |
| duration = model.predictor.duration_proj(x) / 0.98 |
| pred_dur = torch.round(duration.squeeze()).clamp(min=1) |
| |
| pred_aln_trg = torch.zeros(input_lengths, int(pred_dur.sum().data)) |
| c_frame = 0 |
| for i in range(pred_aln_trg.size(0)): |
| pred_aln_trg[i, c_frame:c_frame + int(pred_dur[i].data)] = 1 |
| c_frame += int(pred_dur[i].data) |
| |
| |
| en = (d.transpose(-1, -2) @ pred_aln_trg.unsqueeze(0).to(device)) |
| style = s.expand(en.shape[0], en.shape[1], -1) |
| |
| F0_pred, N_pred = model.predictor.F0Ntrain(en, s) |
| |
| out = model.decoder((t_en @ pred_aln_trg.unsqueeze(0).to(device)), |
| F0_pred, N_pred, ref.squeeze().unsqueeze(0)) |
| |
| c = out.squeeze() |
| y_g_hat = generator(c.unsqueeze(0)) |
| y_out = y_g_hat.squeeze() |
| |
| converted_samples[key] = y_out.cpu().numpy() |
| |
| |
| |
| key = list(converted_samples.keys())[0] |
| audio_output = converted_samples[key] |
| audio_output = (audio_output * 32767).astype(np.int16) |
| |
| return (24000, audio_output), ipa2uk_phonemes |
|
|
|
|
| with open("README.md") as file: |
| article = file.read() |
| article = article[article.find("---\n", 4) + 5 : :] |
|
|
| iface = gr.Interface( |
| fn=tts, |
| inputs=[ |
| |
| gr.Text( |
| label="Input", |
| value='''ми кр+апельки ртуті на рівному полі, на сірій безмірній пустій площині. |
| – рухливі, прудкі, досконалі і голі, котитись навчились, а жити, ще ні, |
| – щенячі забави щоночі, щоднини, тваринна захланність звірячий запал, |
| – хоч крапелька кожна це майже людина, і світло тремтливе відлите в метал. |
| – але проступають пророцтва забуті, і стеляться світом зневіра і страх. |
| – а ми розтік+аємось краплями ртуті, по мінних, - по мінних, по мінних полях. ''', |
| ), |
| ], |
| outputs=[ |
| gr.components.Audio(label="Output"), |
| gr.components.Textbox(label="IPA Phonems"), |
| ], |
| title="Ukrainian StyleTTS Alexis", |
| description= f'''Ukrainian StyleTTS. If the stress is incorrect, use the + symbol before the stressed letter.''', |
| cache_examples=False, |
| examples=[["""Але щоб ви зрозуміли, звідки виник+ає це хибне уявлення людей, цуратись насолоди і вихваляти страждання, я розкрию перед вами всю картину і роз’ясн+ю, що саме говорив цей чоловік, який відкрив істину, якого я б назвав зодчим щасливого життя."""], |
| ["""Ми кр+апельки ртуті на рівному полі, на сірій безмірній пустій площині. |
| – рухливі, прудкі, досконалі і голі, котитись навчились, а жити, ще ні, |
| – щенячі забави щоночі, щоднини, тваринна захланність звірячий запал, |
| – хоч крапелька кожна це майже людина, і світло тремтливе відлите в метал. |
| – але проступають пророцтва забуті, і стеляться світом зневіра і страх. |
| – а ми розтік+аємось краплями ртуті, по мінних, - по мінних, по мінних полях. """], |
| ["""спини мене, отямся і отям, така любов буває раз в нік+оли. |
| – вона ж промчить над зламаним життям за нею ж будуть бігти видноколи. |
| – вона ж порве нам спокій до струни, вона ж слова поспалює вустами. |
| – спини мене, спини і схамени, ще поки можу думати востаннє. |
| – ще поки можу, – але вже не можу. – настала черга й на мою зорю. |
| – чи біля тебе душу відморожу чи біля тебе полум'ям згорю..."""] |
| ], |
| article=article, |
| ) |
| iface.launch() |