Update inference_webui.py

This commit is contained in:
KakaruHayate 2024-03-30 21:41:51 +08:00
parent adad163625
commit 158f85c745

View File

@ -1,25 +1,47 @@
import os,re,logging '''
按中英混合识别
按日英混合识别
多语种启动切分识别语种
全部按中文识别
全部按英文识别
全部按日文识别
'''
import os, re, logging
import LangSegment
logging.getLogger("markdown_it").setLevel(logging.ERROR) logging.getLogger("markdown_it").setLevel(logging.ERROR)
logging.getLogger("urllib3").setLevel(logging.ERROR) logging.getLogger("urllib3").setLevel(logging.ERROR)
logging.getLogger("httpcore").setLevel(logging.ERROR) logging.getLogger("httpcore").setLevel(logging.ERROR)
logging.getLogger("httpx").setLevel(logging.ERROR) logging.getLogger("httpx").setLevel(logging.ERROR)
logging.getLogger("asyncio").setLevel(logging.ERROR) logging.getLogger("asyncio").setLevel(logging.ERROR)
logging.getLogger("charset_normalizer").setLevel(logging.ERROR) logging.getLogger("charset_normalizer").setLevel(logging.ERROR)
logging.getLogger("torchaudio._extension").setLevel(logging.ERROR) logging.getLogger("torchaudio._extension").setLevel(logging.ERROR)
import pdb import pdb
import torch
device = "cpu"
try:
import torch_musa
use_torch_musa = True
except ImportError:
use_torch_musa = False
if use_torch_musa:
if "_MUSA_VISIBLE_DEVICES" in os.environ:
os.environ["MUSA_VISIBLE_DEVICES"] = os.environ["_MUSA_VISIBLE_DEVICES"]
if torch.musa.is_available():
device = "musa"
if os.path.exists("./gweight.txt"): if os.path.exists("./gweight.txt"):
with open("./gweight.txt", 'r',encoding="utf-8") as file: with open("./gweight.txt", 'r', encoding="utf-8") as file:
gweight_data = file.read() gweight_data = file.read()
gpt_path = os.environ.get( gpt_path = os.environ.get(
"gpt_path", gweight_data) "gpt_path", gweight_data)
else: else:
gpt_path = os.environ.get( gpt_path = os.environ.get(
"gpt_path", "GPT_SoVITS/pretrained_models/s1bert25hz-2kh-longer-epoch=68e-step=50232.ckpt") "gpt_path", "GPT_SoVITS/pretrained_models/s1bert25hz-2kh-longer-epoch=68e-step=50232.ckpt")
if os.path.exists("./sweight.txt"): if os.path.exists("./sweight.txt"):
with open("./sweight.txt", 'r',encoding="utf-8") as file: with open("./sweight.txt", 'r', encoding="utf-8") as file:
sweight_data = file.read() sweight_data = file.read()
sovits_path = os.environ.get("sovits_path", sweight_data) sovits_path = os.environ.get("sovits_path", sweight_data)
else: else:
@ -29,24 +51,25 @@ else:
# ) # )
# sovits_path = os.environ.get("sovits_path", "pretrained_models/s2G488k.pth") # sovits_path = os.environ.get("sovits_path", "pretrained_models/s2G488k.pth")
cnhubert_base_path = os.environ.get( cnhubert_base_path = os.environ.get(
"cnhubert_base_path", "pretrained_models/chinese-hubert-base" "cnhubert_base_path", "GPT_SoVITS/pretrained_models/chinese-hubert-base"
) )
bert_path = os.environ.get( bert_path = os.environ.get(
"bert_path", "pretrained_models/chinese-roberta-wwm-ext-large" "bert_path", "GPT_SoVITS/pretrained_models/chinese-roberta-wwm-ext-large"
) )
infer_ttswebui = os.environ.get("infer_ttswebui", 9872) infer_ttswebui = os.environ.get("infer_ttswebui", 9872)
infer_ttswebui = int(infer_ttswebui) infer_ttswebui = int(infer_ttswebui)
is_share = os.environ.get("is_share", "False") is_share = os.environ.get("is_share", "False")
is_share=eval(is_share) is_share = eval(is_share)
if "_CUDA_VISIBLE_DEVICES" in os.environ: if "_CUDA_VISIBLE_DEVICES" in os.environ:
os.environ["CUDA_VISIBLE_DEVICES"] = os.environ["_CUDA_VISIBLE_DEVICES"] os.environ["CUDA_VISIBLE_DEVICES"] = os.environ["_CUDA_VISIBLE_DEVICES"]
is_half = eval(os.environ.get("is_half", "True")) is_half = eval(os.environ.get("is_half", "True")) and torch.cuda.is_available()
import gradio as gr import gradio as gr
from transformers import AutoModelForMaskedLM, AutoTokenizer from transformers import AutoModelForMaskedLM, AutoTokenizer
import numpy as np import numpy as np
import librosa,torch import librosa
from feature_extractor import cnhubert from feature_extractor import cnhubert
cnhubert.cnhubert_base_path=cnhubert_base_path
cnhubert.cnhubert_base_path = cnhubert_base_path
from module.models import SynthesizerTrn from module.models import SynthesizerTrn
from AR.models.t2s_lightning_module import Text2SemanticLightningModule from AR.models.t2s_lightning_module import Text2SemanticLightningModule
@ -56,16 +79,13 @@ from time import time as ttime
from module.mel_processing import spectrogram_torch from module.mel_processing import spectrogram_torch
from my_utils import load_audio from my_utils import load_audio
from tools.i18n.i18n import I18nAuto from tools.i18n.i18n import I18nAuto
i18n = I18nAuto() i18n = I18nAuto()
os.environ['PYTORCH_ENABLE_MPS_FALLBACK'] = '1' # 确保直接启动推理UI时也能够设置。 # os.environ['PYTORCH_ENABLE_MPS_FALLBACK'] = '1' # 确保直接启动推理UI时也能够设置。
if torch.cuda.is_available(): if torch.cuda.is_available():
device = "cuda" device = "cuda"
elif torch.backends.mps.is_available():
device = "mps"
else:
device = "cpu"
tokenizer = AutoTokenizer.from_pretrained(bert_path) tokenizer = AutoTokenizer.from_pretrained(bert_path)
bert_model = AutoModelForMaskedLM.from_pretrained(bert_path) bert_model = AutoModelForMaskedLM.from_pretrained(bert_path)
@ -74,6 +94,7 @@ if is_half == True:
else: else:
bert_model = bert_model.to(device) bert_model = bert_model.to(device)
def get_bert_feature(text, word2ph): def get_bert_feature(text, word2ph):
with torch.no_grad(): with torch.no_grad():
inputs = tokenizer(text, return_tensors="pt") inputs = tokenizer(text, return_tensors="pt")
@ -89,6 +110,7 @@ def get_bert_feature(text, word2ph):
phone_level_feature = torch.cat(phone_level_feature, dim=0) phone_level_feature = torch.cat(phone_level_feature, dim=0)
return phone_level_feature.T return phone_level_feature.T
class DictToAttrRecursive(dict): class DictToAttrRecursive(dict):
def __init__(self, input_dict): def __init__(self, input_dict):
super().__init__(input_dict) super().__init__(input_dict)
@ -123,10 +145,11 @@ if is_half == True:
else: else:
ssl_model = ssl_model.to(device) ssl_model = ssl_model.to(device)
def change_sovits_weights(sovits_path): def change_sovits_weights(sovits_path):
global vq_model,hps global vq_model, hps
dict_s2=torch.load(sovits_path,map_location="cpu") dict_s2 = torch.load(sovits_path, map_location="cpu")
hps=dict_s2["config"] hps = dict_s2["config"]
hps = DictToAttrRecursive(hps) hps = DictToAttrRecursive(hps)
hps.model.semantic_frame_rate = "25hz" hps.model.semantic_frame_rate = "25hz"
vq_model = SynthesizerTrn( vq_model = SynthesizerTrn(
@ -135,7 +158,7 @@ def change_sovits_weights(sovits_path):
n_speakers=hps.data.n_speakers, n_speakers=hps.data.n_speakers,
**hps.model **hps.model
) )
if("pretrained"not in sovits_path): if ("pretrained" not in sovits_path):
del vq_model.enc_q del vq_model.enc_q
if is_half == True: if is_half == True:
vq_model = vq_model.half().to(device) vq_model = vq_model.half().to(device)
@ -143,11 +166,15 @@ def change_sovits_weights(sovits_path):
vq_model = vq_model.to(device) vq_model = vq_model.to(device)
vq_model.eval() vq_model.eval()
print(vq_model.load_state_dict(dict_s2["weight"], strict=False)) print(vq_model.load_state_dict(dict_s2["weight"], strict=False))
with open("./sweight.txt","w",encoding="utf-8")as f:f.write(sovits_path) with open("./sweight.txt", "w", encoding="utf-8") as f:
f.write(sovits_path)
change_sovits_weights(sovits_path) change_sovits_weights(sovits_path)
def change_gpt_weights(gpt_path): def change_gpt_weights(gpt_path):
global hz,max_sec,t2s_model,config global hz, max_sec, t2s_model, config
hz = 50 hz = 50
dict_s1 = torch.load(gpt_path, map_location="cpu") dict_s1 = torch.load(gpt_path, map_location="cpu")
config = dict_s1["config"] config = dict_s1["config"]
@ -160,9 +187,12 @@ def change_gpt_weights(gpt_path):
t2s_model.eval() t2s_model.eval()
total = sum([param.nelement() for param in t2s_model.parameters()]) total = sum([param.nelement() for param in t2s_model.parameters()])
print("Number of parameter: %.2fM" % (total / 1e6)) print("Number of parameter: %.2fM" % (total / 1e6))
with open("./gweight.txt","w",encoding="utf-8")as f:f.write(gpt_path) with open("./gweight.txt", "w", encoding="utf-8") as f: f.write(gpt_path)
change_gpt_weights(gpt_path) change_gpt_weights(gpt_path)
def get_spepc(hps, filename): def get_spepc(hps, filename):
audio = load_audio(filename, int(hps.data.sampling_rate)) audio = load_audio(filename, int(hps.data.sampling_rate))
audio = torch.FloatTensor(audio) audio = torch.FloatTensor(audio)
@ -179,43 +209,26 @@ def get_spepc(hps, filename):
return spec return spec
dict_language={ dict_language = {
i18n("中文"):"zh", i18n("中文"): "all_zh",#全部按中文识别
i18n("英文"):"en", i18n("英文"): "en",#全部按英文识别#######不变
i18n("日文"):"ja" i18n("日文"): "all_ja",#全部按日文识别
i18n("中英混合"): "zh",#按中英混合识别####不变
i18n("日英混合"): "ja",#按日英混合识别####不变
i18n("多语种混合"): "auto",#多语种启动切分识别语种
} }
def splite_en_inf(sentence, language):
pattern = re.compile(r'[a-zA-Z. ]+')
textlist = []
langlist = []
pos = 0
for match in pattern.finditer(sentence):
start, end = match.span()
if start > pos:
textlist.append(sentence[pos:start])
langlist.append(language)
textlist.append(sentence[start:end])
langlist.append("en")
pos = end
if pos < len(sentence):
textlist.append(sentence[pos:])
langlist.append(language)
return textlist, langlist
def clean_text_inf(text, language): def clean_text_inf(text, language):
phones, word2ph, norm_text = clean_text(text, language) phones, word2ph, norm_text = clean_text(text, language)
phones = cleaned_text_to_sequence(phones) phones = cleaned_text_to_sequence(phones)
return phones, word2ph, norm_text return phones, word2ph, norm_text
dtype=torch.float16 if is_half == True else torch.float32
def get_bert_inf(phones, word2ph, norm_text, language): def get_bert_inf(phones, word2ph, norm_text, language):
language=language.replace("all_","")
if language == "zh": if language == "zh":
bert = get_bert_feature(norm_text, word2ph).to(device) bert = get_bert_feature(norm_text, word2ph).to(device)#.to(dtype)
else: else:
bert = torch.zeros( bert = torch.zeros(
(1024, len(phones)), (1024, len(phones)),
@ -225,54 +238,112 @@ def get_bert_inf(phones, word2ph, norm_text, language):
return bert return bert
def nonen_clean_text_inf(text, language): splits = {"", "", "", "", ",", ".", "?", "!", "~", ":", "", "", "", }
textlist, langlist = splite_en_inf(text, language)
phones_list = []
word2ph_list = [] def get_first(text):
norm_text_list = [] pattern = "[" + "".join(re.escape(sep) for sep in splits) + "]"
for i in range(len(textlist)): text = re.split(pattern, text)[0].strip()
lang = langlist[i] return text
phones, word2ph, norm_text = clean_text_inf(textlist[i], lang)
phones_list.append(phones)
if lang == "en" or "ja": def get_phones_and_bert(text,language):
pass if language in {"en","all_zh","all_ja"}:
language = language.replace("all_","")
if language == "en":
LangSegment.setfilters(["en"])
formattext = " ".join(tmp["text"] for tmp in LangSegment.getTexts(text))
else: else:
word2ph_list.append(word2ph) # 因无法区别中日文汉字,以用户输入为准
norm_text_list.append(norm_text) formattext = text
print(word2ph_list) while " " in formattext:
phones = sum(phones_list, []) formattext = formattext.replace(" ", " ")
word2ph = sum(word2ph_list, []) phones, word2ph, norm_text = clean_text_inf(formattext, language)
norm_text = ' '.join(norm_text_list) if language == "zh":
bert = get_bert_feature(norm_text, word2ph).to(device)
else:
bert = torch.zeros(
(1024, len(phones)),
dtype=torch.float16 if is_half == True else torch.float32,
).to(device)
elif language in {"zh", "ja","auto"}:
textlist=[]
langlist=[]
LangSegment.setfilters(["zh","ja","en","ko"])
if language == "auto":
for tmp in LangSegment.getTexts(text):
if tmp["lang"] == "ko":
langlist.append("zh")
textlist.append(tmp["text"])
else:
langlist.append(tmp["lang"])
textlist.append(tmp["text"])
else:
for tmp in LangSegment.getTexts(text):
if tmp["lang"] == "en":
langlist.append(tmp["lang"])
else:
# 因无法区别中日文汉字,以用户输入为准
langlist.append(language)
textlist.append(tmp["text"])
print(textlist)
print(langlist)
phones_list = []
bert_list = []
norm_text_list = []
for i in range(len(textlist)):
lang = langlist[i]
phones, word2ph, norm_text = clean_text_inf(textlist[i], lang)
bert = get_bert_inf(phones, word2ph, norm_text, lang)
phones_list.append(phones)
norm_text_list.append(norm_text)
bert_list.append(bert)
bert = torch.cat(bert_list, dim=1)
phones = sum(phones_list, [])
norm_text = ''.join(norm_text_list)
return phones, word2ph, norm_text return phones,bert.to(dtype),norm_text
def nonen_get_bert_inf(text, language): def merge_short_text_in_array(texts, threshold):
textlist, langlist = splite_en_inf(text, language) if (len(texts)) < 2:
print(textlist) return texts
print(langlist) result = []
bert_list = [] text = ""
for i in range(len(textlist)): for ele in texts:
text = textlist[i] text += ele
lang = langlist[i] if len(text) >= threshold:
phones, word2ph, norm_text = clean_text_inf(text, lang) result.append(text)
bert = get_bert_inf(phones, word2ph, norm_text, lang) text = ""
bert_list.append(bert) if (len(text) > 0):
bert = torch.cat(bert_list, dim=1) if len(result) == 0:
result.append(text)
else:
result[len(result) - 1] += text
return result
return bert def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language, how_to_cut=i18n("不切"), top_k=20, top_p=0.6, temperature=0.6, ref_free = False):
if prompt_text is None or len(prompt_text) == 0:
#i18n("不切"),i18n("凑五句一切"),i18n("凑50字一切"),i18n("按中文句号。切"),i18n("按英文句号.切") ref_free = True
def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language,how_to_cut=i18n("不切")):
t0 = ttime() t0 = ttime()
prompt_text = prompt_text.strip("\n") prompt_language = dict_language[prompt_language]
prompt_language, text = prompt_language, text.strip("\n") text_language = dict_language[text_language]
if not ref_free:
prompt_text = prompt_text.strip("\n")
if (prompt_text[-1] not in splits): prompt_text += "" if prompt_language != "en" else "."
print(i18n("实际输入的参考文本:"), prompt_text)
text = text.strip("\n")
if (text[0] not in splits and len(get_first(text)) < 4): text = "" + text if text_language != "en" else "." + text
print(i18n("实际输入的目标文本:"), text)
zero_wav = np.zeros( zero_wav = np.zeros(
int(hps.data.sampling_rate * 0.3), int(hps.data.sampling_rate * 0.3),
dtype=np.float16 if is_half == True else np.float32, dtype=np.float16 if is_half == True else np.float32,
) )
with torch.no_grad(): with torch.no_grad():
wav16k, sr = librosa.load(ref_wav_path, sr=16000) wav16k, sr = librosa.load(ref_wav_path, sr=16000)
if (wav16k.shape[0] > 160000 or wav16k.shape[0] < 48000):
raise OSError(i18n("参考音频在3~10秒范围外请更换"))
wav16k = torch.from_numpy(wav16k) wav16k = torch.from_numpy(wav16k)
zero_wav_torch = torch.from_numpy(zero_wav) zero_wav_torch = torch.from_numpy(zero_wav)
if is_half == True: if is_half == True:
@ -281,52 +352,51 @@ def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language,
else: else:
wav16k = wav16k.to(device) wav16k = wav16k.to(device)
zero_wav_torch = zero_wav_torch.to(device) zero_wav_torch = zero_wav_torch.to(device)
wav16k=torch.cat([wav16k,zero_wav_torch]) wav16k = torch.cat([wav16k, zero_wav_torch])
ssl_content = ssl_model.model(wav16k.unsqueeze(0))[ ssl_content = ssl_model.model(wav16k.unsqueeze(0))[
"last_hidden_state" "last_hidden_state"
].transpose( ].transpose(
1, 2 1, 2
) # .float() ) # .float()
codes = vq_model.extract_latent(ssl_content) codes = vq_model.extract_latent(ssl_content)
prompt_semantic = codes[0, 0] prompt_semantic = codes[0, 0]
t1 = ttime() t1 = ttime()
prompt_language = dict_language[prompt_language]
text_language = dict_language[text_language]
if prompt_language == "en": if (how_to_cut == i18n("凑四句一切")):
phones1, word2ph1, norm_text1 = clean_text_inf(prompt_text, prompt_language) text = cut1(text)
else: elif (how_to_cut == i18n("凑50字一切")):
phones1, word2ph1, norm_text1 = nonen_clean_text_inf(prompt_text, prompt_language) text = cut2(text)
if(how_to_cut==i18n("凑五句一切")):text=cut1(text) elif (how_to_cut == i18n("按中文句号。切")):
elif(how_to_cut==i18n("凑50字一切")):text=cut2(text) text = cut3(text)
elif(how_to_cut==i18n("按中文句号。切")):text=cut3(text) elif (how_to_cut == i18n("按英文句号.切")):
elif(how_to_cut==i18n("按英文句号.切")):text=cut4(text) text = cut4(text)
text = text.replace("\n\n","\n").replace("\n\n","\n").replace("\n\n","\n") elif (how_to_cut == i18n("按标点符号切")):
if(text[-1]not in splits):text+=""if text_language!="en"else "." text = cut5(text)
texts=text.split("\n") while "\n\n" in text:
text = text.replace("\n\n", "\n")
print(i18n("实际输入的目标文本(切句后):"), text)
texts = text.split("\n")
texts = merge_short_text_in_array(texts, 5)
audio_opt = [] audio_opt = []
if prompt_language == "en": if not ref_free:
bert1 = get_bert_inf(phones1, word2ph1, norm_text1, prompt_language) phones1,bert1,norm_text1=get_phones_and_bert(prompt_text, prompt_language)
else:
bert1 = nonen_get_bert_inf(prompt_text, prompt_language)
for text in texts: for text in texts:
# 解决输入目标文本的空行导致报错的问题 # 解决输入目标文本的空行导致报错的问题
if (len(text.strip()) == 0): if (len(text.strip()) == 0):
continue continue
if text_language == "en": if (text[-1] not in splits): text += "" if text_language != "en" else "."
phones2, word2ph2, norm_text2 = clean_text_inf(text, text_language) print(i18n("实际输入的目标文本(每句):"), text)
phones2,bert2,norm_text2=get_phones_and_bert(text, text_language)
print(i18n("前端处理后的文本(每句):"), norm_text2)
if not ref_free:
bert = torch.cat([bert1, bert2], 1)
all_phoneme_ids = torch.LongTensor(phones1+phones2).to(device).unsqueeze(0)
else: else:
phones2, word2ph2, norm_text2 = nonen_clean_text_inf(text, text_language) bert = bert2
all_phoneme_ids = torch.LongTensor(phones2).to(device).unsqueeze(0)
if text_language == "en":
bert2 = get_bert_inf(phones2, word2ph2, norm_text2, text_language)
else:
bert2 = nonen_get_bert_inf(text, text_language)
bert = torch.cat([bert1, bert2], 1)
all_phoneme_ids = torch.LongTensor(phones1 + phones2).to(device).unsqueeze(0)
bert = bert.to(device).unsqueeze(0) bert = bert.to(device).unsqueeze(0)
all_phoneme_len = torch.tensor([all_phoneme_ids.shape[-1]]).to(device) all_phoneme_len = torch.tensor([all_phoneme_ids.shape[-1]]).to(device)
prompt = prompt_semantic.unsqueeze(0).to(device) prompt = prompt_semantic.unsqueeze(0).to(device)
@ -336,10 +406,12 @@ def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language,
pred_semantic, idx = t2s_model.model.infer_panel( pred_semantic, idx = t2s_model.model.infer_panel(
all_phoneme_ids, all_phoneme_ids,
all_phoneme_len, all_phoneme_len,
prompt, None if ref_free else prompt,
bert, bert,
# prompt_phone_len=ph_offset, # prompt_phone_len=ph_offset,
top_k=config["inference"]["top_k"], top_k=top_k,
top_p=top_p,
temperature=temperature,
early_stop_num=hz * max_sec, early_stop_num=hz * max_sec,
) )
t3 = ttime() t3 = ttime()
@ -357,10 +429,12 @@ def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language,
vq_model.decode( vq_model.decode(
pred_semantic, torch.LongTensor(phones2).to(device).unsqueeze(0), refer pred_semantic, torch.LongTensor(phones2).to(device).unsqueeze(0), refer
) )
.detach() .detach()
.cpu() .cpu()
.numpy()[0, 0] .numpy()[0, 0]
) ###试试重建不带上prompt部分 ) ###试试重建不带上prompt部分
max_audio=np.abs(audio).max()#简单防止16bit爆音
if max_audio>1:audio/=max_audio
audio_opt.append(audio) audio_opt.append(audio)
audio_opt.append(zero_wav) audio_opt.append(zero_wav)
t4 = ttime() t4 = ttime()
@ -370,23 +444,6 @@ def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language,
) )
splits = {
"",
"",
"",
"",
",",
".",
"?",
"!",
"~",
":",
"",
"",
"",
} # 不考虑省略号
def split(todo_text): def split(todo_text):
todo_text = todo_text.replace("……", "").replace("——", "") todo_text = todo_text.replace("……", "").replace("——", "")
if todo_text[-1] not in splits: if todo_text[-1] not in splits:
@ -409,12 +466,12 @@ def split(todo_text):
def cut1(inp): def cut1(inp):
inp = inp.strip("\n") inp = inp.strip("\n")
inps = split(inp) inps = split(inp)
split_idx = list(range(0, len(inps), 5)) split_idx = list(range(0, len(inps), 4))
split_idx[-1] = None split_idx[-1] = None
if len(split_idx) > 1: if len(split_idx) > 1:
opts = [] opts = []
for idx in range(len(split_idx) - 1): for idx in range(len(split_idx) - 1):
opts.append("".join(inps[split_idx[idx] : split_idx[idx + 1]])) opts.append("".join(inps[split_idx[idx]: split_idx[idx + 1]]))
else: else:
opts = [inp] opts = [inp]
return "\n".join(opts) return "\n".join(opts)
@ -424,7 +481,7 @@ def cut2(inp):
inp = inp.strip("\n") inp = inp.strip("\n")
inps = split(inp) inps = split(inp)
if len(inps) < 2: if len(inps) < 2:
return [inp] return inp
opts = [] opts = []
summ = 0 summ = 0
tmp_str = "" tmp_str = ""
@ -437,7 +494,8 @@ def cut2(inp):
tmp_str = "" tmp_str = ""
if tmp_str != "": if tmp_str != "":
opts.append(tmp_str) opts.append(tmp_str)
if len(opts[-1]) < 50: ##如果最后一个太短了,和前一个合一起 # print(opts)
if len(opts) > 1 and len(opts[-1]) < 50: ##如果最后一个太短了,和前一个合一起
opts[-2] = opts[-2] + opts[-1] opts[-2] = opts[-2] + opts[-1]
opts = opts[:-1] opts = opts[:-1]
return "\n".join(opts) return "\n".join(opts)
@ -445,10 +503,28 @@ def cut2(inp):
def cut3(inp): def cut3(inp):
inp = inp.strip("\n") inp = inp.strip("\n")
return "\n".join(["%s" % item for item in inp.strip("").split("")]) return "\n".join(["%s" % item for item in inp.strip("").split("")])
def cut4(inp): def cut4(inp):
inp = inp.strip("\n") inp = inp.strip("\n")
return "\n".join(["%s." % item for item in inp.strip(".").split(".")]) return "\n".join(["%s" % item for item in inp.strip(".").split(".")])
# contributed by https://github.com/AI-Hobbyist/GPT-SoVITS/blob/main/GPT_SoVITS/inference_webui.py
def cut5(inp):
# if not re.search(r'[^\w\s]', inp[-1]):
# inp += '。'
inp = inp.strip("\n")
punds = r'[,.;?!、,。?!;:…]'
items = re.split(f'({punds})', inp)
mergeitems = ["".join(group) for group in zip(items[::2], items[1::2])]
# 在句子不存在符号或句尾无符号的时候保证文本完整
if len(items)%2 == 1:
mergeitems.append(items[-1])
opt = "\n".join(mergeitems)
return opt
def custom_sort_key(s): def custom_sort_key(s):
# 使用正则表达式提取字符串中的数字部分和非数字部分 # 使用正则表达式提取字符串中的数字部分和非数字部分
@ -457,25 +533,31 @@ def custom_sort_key(s):
parts = [int(part) if part.isdigit() else part for part in parts] parts = [int(part) if part.isdigit() else part for part in parts]
return parts return parts
def change_choices(): def change_choices():
SoVITS_names, GPT_names = get_weights_names() SoVITS_names, GPT_names = get_weights_names()
return {"choices": sorted(SoVITS_names,key=custom_sort_key), "__type__": "update"}, {"choices": sorted(GPT_names,key=custom_sort_key), "__type__": "update"} return {"choices": sorted(SoVITS_names, key=custom_sort_key), "__type__": "update"}, {"choices": sorted(GPT_names, key=custom_sort_key), "__type__": "update"}
pretrained_sovits_name = "GPT_SoVITS/pretrained_models/s2G488k.pth"
pretrained_gpt_name = "GPT_SoVITS/pretrained_models/s1bert25hz-2kh-longer-epoch=68e-step=50232.ckpt"
SoVITS_weight_root = "SoVITS_weights"
GPT_weight_root = "GPT_weights"
os.makedirs(SoVITS_weight_root, exist_ok=True)
os.makedirs(GPT_weight_root, exist_ok=True)
pretrained_sovits_name="GPT_SoVITS/pretrained_models/s2G488k.pth"
pretrained_gpt_name="GPT_SoVITS/pretrained_models/s1bert25hz-2kh-longer-epoch=68e-step=50232.ckpt"
SoVITS_weight_root="SoVITS_weights"
GPT_weight_root="GPT_weights"
os.makedirs(SoVITS_weight_root,exist_ok=True)
os.makedirs(GPT_weight_root,exist_ok=True)
def get_weights_names(): def get_weights_names():
SoVITS_names = [pretrained_sovits_name] SoVITS_names = [pretrained_sovits_name]
for name in os.listdir(SoVITS_weight_root): for name in os.listdir(SoVITS_weight_root):
if name.endswith(".pth"):SoVITS_names.append("%s/%s"%(SoVITS_weight_root,name)) if name.endswith(".pth"): SoVITS_names.append("%s/%s" % (SoVITS_weight_root, name))
GPT_names = [pretrained_gpt_name] GPT_names = [pretrained_gpt_name]
for name in os.listdir(GPT_weight_root): for name in os.listdir(GPT_weight_root):
if name.endswith(".ckpt"): GPT_names.append("%s/%s"%(GPT_weight_root,name)) if name.endswith(".ckpt"): GPT_names.append("%s/%s" % (GPT_weight_root, name))
return SoVITS_names,GPT_names return SoVITS_names, GPT_names
SoVITS_names,GPT_names = get_weights_names()
SoVITS_names, GPT_names = get_weights_names()
with gr.Blocks(title="GPT-SoVITS WebUI") as app: with gr.Blocks(title="GPT-SoVITS WebUI") as app:
gr.Markdown( gr.Markdown(
@ -484,53 +566,63 @@ with gr.Blocks(title="GPT-SoVITS WebUI") as app:
with gr.Group(): with gr.Group():
gr.Markdown(value=i18n("模型切换")) gr.Markdown(value=i18n("模型切换"))
with gr.Row(): with gr.Row():
GPT_dropdown = gr.Dropdown(label=i18n("GPT模型列表"), choices=sorted(GPT_names, key=custom_sort_key), value=gpt_path,interactive=True) GPT_dropdown = gr.Dropdown(label=i18n("GPT模型列表"), choices=sorted(GPT_names, key=custom_sort_key), value=gpt_path, interactive=True)
SoVITS_dropdown = gr.Dropdown(label=i18n("SoVITS模型列表"), choices=sorted(SoVITS_names, key=custom_sort_key), value=sovits_path,interactive=True) SoVITS_dropdown = gr.Dropdown(label=i18n("SoVITS模型列表"), choices=sorted(SoVITS_names, key=custom_sort_key), value=sovits_path, interactive=True)
refresh_button = gr.Button(i18n("刷新模型路径"), variant="primary") refresh_button = gr.Button(i18n("刷新模型路径"), variant="primary")
refresh_button.click(fn=change_choices, inputs=[], outputs=[SoVITS_dropdown, GPT_dropdown]) refresh_button.click(fn=change_choices, inputs=[], outputs=[SoVITS_dropdown, GPT_dropdown])
SoVITS_dropdown.change(change_sovits_weights,[SoVITS_dropdown],[]) SoVITS_dropdown.change(change_sovits_weights, [SoVITS_dropdown], [])
GPT_dropdown.change(change_gpt_weights,[GPT_dropdown],[]) GPT_dropdown.change(change_gpt_weights, [GPT_dropdown], [])
gr.Markdown(value=i18n("*请上传并填写参考信息")) gr.Markdown(value=i18n("*请上传并填写参考信息"))
with gr.Row(): with gr.Row():
inp_ref = gr.Audio(label=i18n("请上传参考音频"), type="filepath") inp_ref = gr.Audio(label=i18n("请上传3~10秒内参考音频超过会报错"), type="filepath")
prompt_text = gr.Textbox(label=i18n("参考音频的文本"), value="") with gr.Column():
ref_text_free = gr.Checkbox(label=i18n("开启无参考文本模式。不填参考文本亦相当于开启。"), value=False, interactive=True, show_label=True)
gr.Markdown(i18n("使用无参考文本模式时建议使用微调的GPT听不清参考音频说的啥(不晓得写啥)可以开,开启后无视填写的参考文本。"))
prompt_text = gr.Textbox(label=i18n("参考音频的文本"), value="")
prompt_language = gr.Dropdown( prompt_language = gr.Dropdown(
label=i18n("参考音频的语种"),choices=[i18n("中文"),i18n("英文"),i18n("日文")],value=i18n("中文") label=i18n("参考音频的语种"), choices=[i18n("中文"), i18n("英文"), i18n("日文"), i18n("中英混合"), i18n("日英混合"), i18n("多语种混合")], value=i18n("中文")
) )
gr.Markdown(value=i18n("*请填写需要合成的目标文本。中英混合选中文,日英混合选日文,中日混合暂不支持,非目标语言文本自动遗弃。")) gr.Markdown(value=i18n("*请填写需要合成的目标文本和语种模式"))
with gr.Row(): with gr.Row():
text = gr.Textbox(label=i18n("需要合成的文本"), value="") text = gr.Textbox(label=i18n("需要合成的文本"), value="")
text_language = gr.Dropdown( text_language = gr.Dropdown(
label=i18n("需要合成的语种"),choices=[i18n("中文"),i18n("英文"),i18n("日文")],value=i18n("中文") label=i18n("需要合成的语种"), choices=[i18n("中文"), i18n("英文"), i18n("日文"), i18n("中英混合"), i18n("日英混合"), i18n("多语种混合")], value=i18n("中文")
) )
how_to_cut = gr.Radio( how_to_cut = gr.Radio(
label=i18n("怎么切"), label=i18n("怎么切"),
choices=[i18n("不切"),i18n("凑五句一切"),i18n("凑50字一切"),i18n("按中文句号。切"),i18n("按英文句号.切"),], choices=[i18n("不切"), i18n("凑四句一切"), i18n("凑50字一切"), i18n("按中文句号。切"), i18n("按英文句号.切"), i18n("按标点符号切"), ],
value=i18n("50字一切"), value=i18n("四句一切"),
interactive=True, interactive=True,
) )
with gr.Row():
gr.Markdown(value=i18n("gpt采样参数(无参考文本时不要太低)"))
top_k = gr.Slider(minimum=1,maximum=100,step=1,label=i18n("top_k"),value=5,interactive=True)
top_p = gr.Slider(minimum=0,maximum=1,step=0.05,label=i18n("top_p"),value=1,interactive=True)
temperature = gr.Slider(minimum=0,maximum=1,step=0.05,label=i18n("temperature"),value=1,interactive=True)
inference_button = gr.Button(i18n("合成语音"), variant="primary") inference_button = gr.Button(i18n("合成语音"), variant="primary")
output = gr.Audio(label=i18n("输出的语音")) output = gr.Audio(label=i18n("输出的语音"))
inference_button.click( inference_button.click(
get_tts_wav, get_tts_wav,
[inp_ref, prompt_text, prompt_language, text, text_language,how_to_cut], [inp_ref, prompt_text, prompt_language, text, text_language, how_to_cut, top_k, top_p, temperature, ref_text_free],
[output], [output],
) )
gr.Markdown(value=i18n("文本切分工具。太长的文本合成出来效果不一定好,所以太长建议先切。合成会根据文本的换行分开合成再拼起来。")) gr.Markdown(value=i18n("文本切分工具。太长的文本合成出来效果不一定好,所以太长建议先切。合成会根据文本的换行分开合成再拼起来。"))
with gr.Row(): with gr.Row():
text_inp = gr.Textbox(label=i18n("需要合成的切分前文本"),value="") text_inp = gr.Textbox(label=i18n("需要合成的切分前文本"), value="")
button1 = gr.Button(i18n("句一切"), variant="primary") button1 = gr.Button(i18n("句一切"), variant="primary")
button2 = gr.Button(i18n("凑50字一切"), variant="primary") button2 = gr.Button(i18n("凑50字一切"), variant="primary")
button3 = gr.Button(i18n("按中文句号。切"), variant="primary") button3 = gr.Button(i18n("按中文句号。切"), variant="primary")
button4 = gr.Button(i18n("按英文句号.切"), variant="primary") button4 = gr.Button(i18n("按英文句号.切"), variant="primary")
button5 = gr.Button(i18n("按标点符号切"), variant="primary")
text_opt = gr.Textbox(label=i18n("切分后文本"), value="") text_opt = gr.Textbox(label=i18n("切分后文本"), value="")
button1.click(cut1, [text_inp], [text_opt]) button1.click(cut1, [text_inp], [text_opt])
button2.click(cut2, [text_inp], [text_opt]) button2.click(cut2, [text_inp], [text_opt])
button3.click(cut3, [text_inp], [text_opt]) button3.click(cut3, [text_inp], [text_opt])
button4.click(cut4, [text_inp], [text_opt]) button4.click(cut4, [text_inp], [text_opt])
gr.Markdown(value=i18n("后续将支持混合语种编码文本输入。")) button5.click(cut5, [text_inp], [text_opt])
gr.Markdown(value=i18n("后续将支持转音素、手工修改音素、语音合成分步执行。"))
app.queue(concurrency_count=511, max_size=1022).launch( app.queue(concurrency_count=511, max_size=1022).launch(
server_name="0.0.0.0", server_name="0.0.0.0",