mirror of
https://github.com/RVC-Boss/GPT-SoVITS.git
synced 2025-10-07 15:19:59 +08:00
Merge branch 'main' into main
This commit is contained in:
commit
b66b5332e7
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,2 +1,6 @@
|
|||||||
|
.DS_Store
|
||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
env
|
env
|
||||||
runtime
|
runtime
|
||||||
|
.idea
|
||||||
|
@ -12,6 +12,8 @@ bert_path = os.environ.get(
|
|||||||
)
|
)
|
||||||
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=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"))
|
||||||
@ -115,7 +117,6 @@ 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))
|
||||||
hz = 50
|
hz = 50
|
||||||
max_sec = config["data"]["max_sec"]
|
max_sec = config["data"]["max_sec"]
|
||||||
# t2s_model = Text2SemanticLightningModule.load_from_checkpoint(checkpoint_path=gpt_path, config=config, map_location="cpu")#########todo
|
|
||||||
t2s_model = Text2SemanticLightningModule(config, "ojbk", is_train=False)
|
t2s_model = Text2SemanticLightningModule(config, "ojbk", is_train=False)
|
||||||
t2s_model.load_state_dict(dict_s1["weight"])
|
t2s_model.load_state_dict(dict_s1["weight"])
|
||||||
if is_half == True:
|
if is_half == True:
|
||||||
@ -149,13 +150,21 @@ def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language)
|
|||||||
t0 = ttime()
|
t0 = ttime()
|
||||||
prompt_text = prompt_text.strip("\n")
|
prompt_text = prompt_text.strip("\n")
|
||||||
prompt_language, text = prompt_language, text.strip("\n")
|
prompt_language, text = prompt_language, text.strip("\n")
|
||||||
|
zero_wav = np.zeros(
|
||||||
|
int(hps.data.sampling_rate * 0.3),
|
||||||
|
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)
|
||||||
wav16k = torch.from_numpy(wav16k)
|
wav16k = torch.from_numpy(wav16k)
|
||||||
|
zero_wav_torch = torch.from_numpy(zero_wav)
|
||||||
if is_half == True:
|
if is_half == True:
|
||||||
wav16k = wav16k.half().to(device)
|
wav16k = wav16k.half().to(device)
|
||||||
|
zero_wav_torch = zero_wav_torch.half().to(device)
|
||||||
else:
|
else:
|
||||||
wav16k = wav16k.to(device)
|
wav16k = wav16k.to(device)
|
||||||
|
zero_wav_torch = zero_wav_torch.to(device)
|
||||||
|
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(
|
||||||
@ -170,11 +179,10 @@ def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language)
|
|||||||
phones1 = cleaned_text_to_sequence(phones1)
|
phones1 = cleaned_text_to_sequence(phones1)
|
||||||
texts = text.split("\n")
|
texts = text.split("\n")
|
||||||
audio_opt = []
|
audio_opt = []
|
||||||
zero_wav = np.zeros(
|
|
||||||
int(hps.data.sampling_rate * 0.3),
|
|
||||||
dtype=np.float16 if is_half == True else np.float32,
|
|
||||||
)
|
|
||||||
for text in texts:
|
for text in texts:
|
||||||
|
# 解决输入目标文本的空行导致报错的问题
|
||||||
|
if (len(text.strip()) == 0):
|
||||||
|
continue
|
||||||
phones2, word2ph2, norm_text2 = clean_text(text, text_language)
|
phones2, word2ph2, norm_text2 = clean_text(text, text_language)
|
||||||
phones2 = cleaned_text_to_sequence(phones2)
|
phones2 = cleaned_text_to_sequence(phones2)
|
||||||
if prompt_language == "zh":
|
if prompt_language == "zh":
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import time, logging
|
import time
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import random, traceback
|
import random
|
||||||
|
import traceback
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import torch
|
import torch
|
||||||
import torch.utils.data
|
import torch.utils.data
|
||||||
@ -12,15 +14,12 @@ from text import cleaned_text_to_sequence
|
|||||||
from utils import load_wav_to_torch, load_filepaths_and_text
|
from utils import load_wav_to_torch, load_filepaths_and_text
|
||||||
import torch.nn.functional as F
|
import torch.nn.functional as F
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
import torch
|
|
||||||
import requests
|
import requests
|
||||||
from scipy.io import wavfile
|
from scipy.io import wavfile
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
# from config import exp_dir
|
|
||||||
from my_utils import load_audio
|
from my_utils import load_audio
|
||||||
|
|
||||||
|
# ZeroDivisionError fixed by Tybost (https://github.com/RVC-Boss/GPT-SoVITS/issues/79)
|
||||||
class TextAudioSpeakerLoader(torch.utils.data.Dataset):
|
class TextAudioSpeakerLoader(torch.utils.data.Dataset):
|
||||||
"""
|
"""
|
||||||
1) loads audio, speaker_id, text pairs
|
1) loads audio, speaker_id, text pairs
|
||||||
@ -44,7 +43,7 @@ class TextAudioSpeakerLoader(torch.utils.data.Dataset):
|
|||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
tmp = line.split("\t")
|
tmp = line.split("\t")
|
||||||
if len(tmp) != 4:
|
if (len(tmp) != 4):
|
||||||
continue
|
continue
|
||||||
self.phoneme_data[tmp[0]] = [tmp[1]]
|
self.phoneme_data[tmp[0]] = [tmp[1]]
|
||||||
|
|
||||||
@ -52,7 +51,7 @@ class TextAudioSpeakerLoader(torch.utils.data.Dataset):
|
|||||||
tmp = self.audiopaths_sid_text
|
tmp = self.audiopaths_sid_text
|
||||||
leng = len(tmp)
|
leng = len(tmp)
|
||||||
min_num = 100
|
min_num = 100
|
||||||
if leng < min_num:
|
if (leng < min_num):
|
||||||
self.audiopaths_sid_text = []
|
self.audiopaths_sid_text = []
|
||||||
for _ in range(max(2, int(min_num / leng))):
|
for _ in range(max(2, int(min_num / leng))):
|
||||||
self.audiopaths_sid_text += tmp
|
self.audiopaths_sid_text += tmp
|
||||||
@ -77,20 +76,28 @@ class TextAudioSpeakerLoader(torch.utils.data.Dataset):
|
|||||||
for audiopath in tqdm(self.audiopaths_sid_text):
|
for audiopath in tqdm(self.audiopaths_sid_text):
|
||||||
try:
|
try:
|
||||||
phoneme = self.phoneme_data[audiopath][0]
|
phoneme = self.phoneme_data[audiopath][0]
|
||||||
phoneme = phoneme.split(" ")
|
phoneme = phoneme.split(' ')
|
||||||
phoneme_ids = cleaned_text_to_sequence(phoneme)
|
phoneme_ids = cleaned_text_to_sequence(phoneme)
|
||||||
except Exception:
|
except Exception:
|
||||||
print(f"{audiopath} not in self.phoneme_data !")
|
print(f"{audiopath} not in self.phoneme_data !")
|
||||||
skipped_phone += 1
|
skipped_phone += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
size = os.path.getsize("%s/%s" % (self.path5, audiopath))
|
size = os.path.getsize("%s/%s" % (self.path5, audiopath))
|
||||||
duration = size / self.sampling_rate / 2
|
duration = size / self.sampling_rate / 2
|
||||||
|
|
||||||
|
if duration == 0:
|
||||||
|
print(f"Zero duration for {audiopath}, skipping...")
|
||||||
|
skipped_dur += 1
|
||||||
|
continue
|
||||||
|
|
||||||
if 54 > duration > 0.6 or self.val:
|
if 54 > duration > 0.6 or self.val:
|
||||||
audiopaths_sid_text_new.append([audiopath, phoneme_ids])
|
audiopaths_sid_text_new.append([audiopath, phoneme_ids])
|
||||||
lengths.append(size // (2 * self.hop_length))
|
lengths.append(size // (2 * self.hop_length))
|
||||||
else:
|
else:
|
||||||
skipped_dur += 1
|
skipped_dur += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
print("skipped_phone: ", skipped_phone, ", skipped_dur: ", skipped_dur)
|
print("skipped_phone: ", skipped_phone, ", skipped_dur: ", skipped_dur)
|
||||||
print("total left: ", len(audiopaths_sid_text_new))
|
print("total left: ", len(audiopaths_sid_text_new))
|
||||||
assert len(audiopaths_sid_text_new) > 1 # 至少能凑够batch size,这里todo
|
assert len(audiopaths_sid_text_new) > 1 # 至少能凑够batch size,这里todo
|
||||||
@ -103,10 +110,8 @@ class TextAudioSpeakerLoader(torch.utils.data.Dataset):
|
|||||||
try:
|
try:
|
||||||
spec, wav = self.get_audio("%s/%s" % (self.path5, audiopath))
|
spec, wav = self.get_audio("%s/%s" % (self.path5, audiopath))
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
ssl = torch.load(
|
ssl = torch.load("%s/%s.pt" % (self.path4, audiopath), map_location="cpu")
|
||||||
"%s/%s.pt" % (self.path4, audiopath), map_location="cpu"
|
if (ssl.shape[-1] != spec.shape[-1]):
|
||||||
)
|
|
||||||
if ssl.shape[-1] != spec.shape[-1]:
|
|
||||||
typee = ssl.dtype
|
typee = ssl.dtype
|
||||||
ssl = F.pad(ssl.float(), (0, 1), mode="replicate").to(typee)
|
ssl = F.pad(ssl.float(), (0, 1), mode="replicate").to(typee)
|
||||||
ssl.requires_grad = False
|
ssl.requires_grad = False
|
||||||
@ -117,25 +122,15 @@ class TextAudioSpeakerLoader(torch.utils.data.Dataset):
|
|||||||
ssl = torch.zeros(1, 768, 100)
|
ssl = torch.zeros(1, 768, 100)
|
||||||
text = text[-1:]
|
text = text[-1:]
|
||||||
print("load audio or ssl error!!!!!!", audiopath)
|
print("load audio or ssl error!!!!!!", audiopath)
|
||||||
# print(ssl.requires_grad,spec.requires_grad,wav.requires_grad,text.requires_grad)
|
|
||||||
return (ssl, spec, wav, text)
|
return (ssl, spec, wav, text)
|
||||||
|
|
||||||
def get_audio(self, filename):
|
def get_audio(self, filename):
|
||||||
audio_array = load_audio(
|
audio_array = load_audio(filename, self.sampling_rate) # load_audio的方法是已经归一化到-1~1之间的,不用再/32768
|
||||||
filename, self.sampling_rate
|
|
||||||
) # load_audio的方法是已经归一化到-1~1之间的,不用再/32768
|
|
||||||
# print(filename,audio_array.max(),audio_array.min(),audio_array.mean())
|
|
||||||
audio = torch.FloatTensor(audio_array) # /32768
|
audio = torch.FloatTensor(audio_array) # /32768
|
||||||
audio_norm = audio
|
audio_norm = audio
|
||||||
audio_norm = audio_norm.unsqueeze(0)
|
audio_norm = audio_norm.unsqueeze(0)
|
||||||
spec = spectrogram_torch(
|
spec = spectrogram_torch(audio_norm, self.filter_length, self.sampling_rate, self.hop_length, self.win_length,
|
||||||
audio_norm,
|
center=False)
|
||||||
self.filter_length,
|
|
||||||
self.sampling_rate,
|
|
||||||
self.hop_length,
|
|
||||||
self.win_length,
|
|
||||||
center=False,
|
|
||||||
)
|
|
||||||
spec = torch.squeeze(spec, 0)
|
spec = torch.squeeze(spec, 0)
|
||||||
return spec, audio_norm
|
return spec, audio_norm
|
||||||
|
|
||||||
@ -152,14 +147,11 @@ class TextAudioSpeakerLoader(torch.utils.data.Dataset):
|
|||||||
|
|
||||||
def random_slice(self, ssl, wav, mel):
|
def random_slice(self, ssl, wav, mel):
|
||||||
assert abs(ssl.shape[-1] - wav.shape[-1] // self.hop_length) < 3, (
|
assert abs(ssl.shape[-1] - wav.shape[-1] // self.hop_length) < 3, (
|
||||||
"first",
|
"first", ssl.shape, wav.shape)
|
||||||
ssl.shape,
|
|
||||||
wav.shape,
|
|
||||||
)
|
|
||||||
|
|
||||||
len_mel = mel.shape[1]
|
len_mel = mel.shape[1]
|
||||||
if self.val:
|
if self.val:
|
||||||
reference_mel = mel[:, : len_mel // 3]
|
reference_mel = mel[:, :len_mel // 3]
|
||||||
return reference_mel, ssl, wav, mel
|
return reference_mel, ssl, wav, mel
|
||||||
dir = random.randint(0, 1)
|
dir = random.randint(0, 1)
|
||||||
sep_point = random.randint(int(len_mel // 3), int(len_mel // 3 * 2))
|
sep_point = random.randint(int(len_mel // 3), int(len_mel // 3 * 2))
|
||||||
@ -167,29 +159,22 @@ class TextAudioSpeakerLoader(torch.utils.data.Dataset):
|
|||||||
if dir == 0:
|
if dir == 0:
|
||||||
reference_mel = mel[:, :sep_point]
|
reference_mel = mel[:, :sep_point]
|
||||||
ssl = ssl[:, :, sep_point:]
|
ssl = ssl[:, :, sep_point:]
|
||||||
wav2 = wav[:, sep_point * self.hop_length :]
|
wav2 = wav[:, sep_point * self.hop_length:]
|
||||||
mel = mel[:, sep_point:]
|
mel = mel[:, sep_point:]
|
||||||
else:
|
else:
|
||||||
reference_mel = mel[:, sep_point:]
|
reference_mel = mel[:, sep_point:]
|
||||||
ssl = ssl[:, :, :sep_point]
|
ssl = ssl[:, :, :sep_point]
|
||||||
wav2 = wav[:, : sep_point * self.hop_length]
|
wav2 = wav[:, :sep_point * self.hop_length]
|
||||||
mel = mel[:, :sep_point]
|
mel = mel[:, :sep_point]
|
||||||
|
|
||||||
assert abs(ssl.shape[-1] - wav2.shape[-1] // self.hop_length) < 3, (
|
assert abs(ssl.shape[-1] - wav2.shape[-1] // self.hop_length) < 3, (
|
||||||
ssl.shape,
|
ssl.shape, wav.shape, wav2.shape, mel.shape, sep_point, self.hop_length, sep_point * self.hop_length, dir)
|
||||||
wav.shape,
|
|
||||||
wav2.shape,
|
|
||||||
mel.shape,
|
|
||||||
sep_point,
|
|
||||||
self.hop_length,
|
|
||||||
sep_point * self.hop_length,
|
|
||||||
dir,
|
|
||||||
)
|
|
||||||
return reference_mel, ssl, wav2, mel
|
return reference_mel, ssl, wav2, mel
|
||||||
|
|
||||||
|
|
||||||
class TextAudioSpeakerCollate:
|
class TextAudioSpeakerCollate():
|
||||||
"""Zero-pads model inputs and targets"""
|
""" Zero-pads model inputs and targets
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, return_ids=False):
|
def __init__(self, return_ids=False):
|
||||||
self.return_ids = return_ids
|
self.return_ids = return_ids
|
||||||
@ -202,8 +187,8 @@ class TextAudioSpeakerCollate:
|
|||||||
"""
|
"""
|
||||||
# Right zero-pad all one-hot text sequences to max input length
|
# Right zero-pad all one-hot text sequences to max input length
|
||||||
_, ids_sorted_decreasing = torch.sort(
|
_, ids_sorted_decreasing = torch.sort(
|
||||||
torch.LongTensor([x[1].size(1) for x in batch]), dim=0, descending=True
|
torch.LongTensor([x[1].size(1) for x in batch]),
|
||||||
)
|
dim=0, descending=True)
|
||||||
|
|
||||||
max_ssl_len = max([x[0].size(2) for x in batch])
|
max_ssl_len = max([x[0].size(2) for x in batch])
|
||||||
max_ssl_len = int(2 * ((max_ssl_len // 2) + 1))
|
max_ssl_len = int(2 * ((max_ssl_len // 2) + 1))
|
||||||
@ -231,31 +216,22 @@ class TextAudioSpeakerCollate:
|
|||||||
row = batch[ids_sorted_decreasing[i]]
|
row = batch[ids_sorted_decreasing[i]]
|
||||||
|
|
||||||
ssl = row[0]
|
ssl = row[0]
|
||||||
ssl_padded[i, :, : ssl.size(2)] = ssl[0, :, :]
|
ssl_padded[i, :, :ssl.size(2)] = ssl[0, :, :]
|
||||||
ssl_lengths[i] = ssl.size(2)
|
ssl_lengths[i] = ssl.size(2)
|
||||||
|
|
||||||
spec = row[1]
|
spec = row[1]
|
||||||
spec_padded[i, :, : spec.size(1)] = spec
|
spec_padded[i, :, :spec.size(1)] = spec
|
||||||
spec_lengths[i] = spec.size(1)
|
spec_lengths[i] = spec.size(1)
|
||||||
|
|
||||||
wav = row[2]
|
wav = row[2]
|
||||||
wav_padded[i, :, : wav.size(1)] = wav
|
wav_padded[i, :, :wav.size(1)] = wav
|
||||||
wav_lengths[i] = wav.size(1)
|
wav_lengths[i] = wav.size(1)
|
||||||
|
|
||||||
text = row[3]
|
text = row[3]
|
||||||
text_padded[i, : text.size(0)] = text
|
text_padded[i, :text.size(0)] = text
|
||||||
text_lengths[i] = text.size(0)
|
text_lengths[i] = text.size(0)
|
||||||
|
|
||||||
return (
|
return ssl_padded, ssl_lengths, spec_padded, spec_lengths, wav_padded, wav_lengths, text_padded, text_lengths
|
||||||
ssl_padded,
|
|
||||||
ssl_lengths,
|
|
||||||
spec_padded,
|
|
||||||
spec_lengths,
|
|
||||||
wav_padded,
|
|
||||||
wav_lengths,
|
|
||||||
text_padded,
|
|
||||||
text_lengths,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class DistributedBucketSampler(torch.utils.data.distributed.DistributedSampler):
|
class DistributedBucketSampler(torch.utils.data.distributed.DistributedSampler):
|
||||||
@ -268,18 +244,9 @@ class DistributedBucketSampler(torch.utils.data.distributed.DistributedSampler):
|
|||||||
Ex) boundaries = [b1, b2, b3] -> any x s.t. length(x) <= b1 or length(x) > b3 are discarded.
|
Ex) boundaries = [b1, b2, b3] -> any x s.t. length(x) <= b1 or length(x) > b3 are discarded.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, dataset, batch_size, boundaries, num_replicas=None, rank=None, shuffle=True):
|
||||||
self,
|
|
||||||
dataset,
|
|
||||||
batch_size,
|
|
||||||
boundaries,
|
|
||||||
num_replicas=None,
|
|
||||||
rank=None,
|
|
||||||
shuffle=True,
|
|
||||||
):
|
|
||||||
super().__init__(dataset, num_replicas=num_replicas, rank=rank, shuffle=shuffle)
|
super().__init__(dataset, num_replicas=num_replicas, rank=rank, shuffle=shuffle)
|
||||||
self.lengths = dataset.lengths
|
self.lengths = dataset.lengths
|
||||||
# print(233333333333333,self.lengths,dir(dataset))
|
|
||||||
self.batch_size = batch_size
|
self.batch_size = batch_size
|
||||||
self.boundaries = boundaries
|
self.boundaries = boundaries
|
||||||
|
|
||||||
@ -295,24 +262,22 @@ class DistributedBucketSampler(torch.utils.data.distributed.DistributedSampler):
|
|||||||
if idx_bucket != -1:
|
if idx_bucket != -1:
|
||||||
buckets[idx_bucket].append(i)
|
buckets[idx_bucket].append(i)
|
||||||
|
|
||||||
for i in range(len(buckets) - 1, 0, -1):
|
i = len(buckets) - 1
|
||||||
# for i in range(len(buckets) - 1, -1, -1):
|
while i >= 0:
|
||||||
if len(buckets[i]) == 0:
|
if len(buckets[i]) == 0:
|
||||||
buckets.pop(i)
|
buckets.pop(i)
|
||||||
self.boundaries.pop(i + 1)
|
self.boundaries.pop(i + 1)
|
||||||
|
i -= 1
|
||||||
|
|
||||||
num_samples_per_bucket = []
|
num_samples_per_bucket = []
|
||||||
for i in range(len(buckets)):
|
for i in range(len(buckets)):
|
||||||
len_bucket = len(buckets[i])
|
len_bucket = len(buckets[i])
|
||||||
total_batch_size = self.num_replicas * self.batch_size
|
total_batch_size = self.num_replicas * self.batch_size
|
||||||
rem = (
|
rem = (total_batch_size - (len_bucket % total_batch_size)) % total_batch_size
|
||||||
total_batch_size - (len_bucket % total_batch_size)
|
|
||||||
) % total_batch_size
|
|
||||||
num_samples_per_bucket.append(len_bucket + rem)
|
num_samples_per_bucket.append(len_bucket + rem)
|
||||||
return buckets, num_samples_per_bucket
|
return buckets, num_samples_per_bucket
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
# deterministically shuffle based on epoch
|
|
||||||
g = torch.Generator()
|
g = torch.Generator()
|
||||||
g.manual_seed(self.epoch)
|
g.manual_seed(self.epoch)
|
||||||
|
|
||||||
@ -331,25 +296,13 @@ class DistributedBucketSampler(torch.utils.data.distributed.DistributedSampler):
|
|||||||
ids_bucket = indices[i]
|
ids_bucket = indices[i]
|
||||||
num_samples_bucket = self.num_samples_per_bucket[i]
|
num_samples_bucket = self.num_samples_per_bucket[i]
|
||||||
|
|
||||||
# add extra samples to make it evenly divisible
|
|
||||||
rem = num_samples_bucket - len_bucket
|
rem = num_samples_bucket - len_bucket
|
||||||
ids_bucket = (
|
ids_bucket = ids_bucket + ids_bucket * (rem // len_bucket) + ids_bucket[:(rem % len_bucket)]
|
||||||
ids_bucket
|
|
||||||
+ ids_bucket * (rem // len_bucket)
|
|
||||||
+ ids_bucket[: (rem % len_bucket)]
|
|
||||||
)
|
|
||||||
|
|
||||||
# subsample
|
ids_bucket = ids_bucket[self.rank::self.num_replicas]
|
||||||
ids_bucket = ids_bucket[self.rank :: self.num_replicas]
|
|
||||||
|
|
||||||
# batching
|
|
||||||
for j in range(len(ids_bucket) // self.batch_size):
|
for j in range(len(ids_bucket) // self.batch_size):
|
||||||
batch = [
|
batch = [bucket[idx] for idx in ids_bucket[j * self.batch_size:(j + 1) * self.batch_size]]
|
||||||
bucket[idx]
|
|
||||||
for idx in ids_bucket[
|
|
||||||
j * self.batch_size : (j + 1) * self.batch_size
|
|
||||||
]
|
|
||||||
]
|
|
||||||
batches.append(batch)
|
batches.append(batch)
|
||||||
|
|
||||||
if self.shuffle:
|
if self.shuffle:
|
||||||
|
@ -1,23 +1,20 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import sys, os
|
import sys,os
|
||||||
|
inp_text= os.environ.get("inp_text")
|
||||||
inp_text = os.environ.get("inp_text")
|
inp_wav_dir= os.environ.get("inp_wav_dir")
|
||||||
inp_wav_dir = os.environ.get("inp_wav_dir")
|
exp_name= os.environ.get("exp_name")
|
||||||
exp_name = os.environ.get("exp_name")
|
i_part= os.environ.get("i_part")
|
||||||
i_part = os.environ.get("i_part")
|
all_parts= os.environ.get("all_parts")
|
||||||
all_parts = os.environ.get("all_parts")
|
os.environ["CUDA_VISIBLE_DEVICES"]= os.environ.get("_CUDA_VISIBLE_DEVICES")
|
||||||
os.environ["CUDA_VISIBLE_DEVICES"] = os.environ.get("_CUDA_VISIBLE_DEVICES")
|
|
||||||
from feature_extractor import cnhubert
|
from feature_extractor import cnhubert
|
||||||
|
opt_dir= os.environ.get("opt_dir")
|
||||||
|
cnhubert.cnhubert_base_path= os.environ.get("cnhubert_base_dir")
|
||||||
|
is_half=eval(os.environ.get("is_half","True"))
|
||||||
|
|
||||||
opt_dir = os.environ.get("opt_dir")
|
import pdb,traceback,numpy as np,logging
|
||||||
cnhubert.cnhubert_base_path = os.environ.get("cnhubert_base_dir")
|
|
||||||
is_half = eval(os.environ.get("is_half", "True"))
|
|
||||||
|
|
||||||
import pdb, traceback, numpy as np, logging
|
|
||||||
from scipy.io import wavfile
|
from scipy.io import wavfile
|
||||||
import librosa, torch
|
import librosa,torch
|
||||||
|
|
||||||
now_dir = os.getcwd()
|
now_dir = os.getcwd()
|
||||||
sys.path.append(now_dir)
|
sys.path.append(now_dir)
|
||||||
from my_utils import load_audio
|
from my_utils import load_audio
|
||||||
@ -35,75 +32,63 @@ from my_utils import load_audio
|
|||||||
|
|
||||||
from time import time as ttime
|
from time import time as ttime
|
||||||
import shutil
|
import shutil
|
||||||
|
def my_save(fea,path):#####fix issue: torch.save doesn't support chinese path
|
||||||
|
dir=os.path.dirname(path)
|
||||||
|
name=os.path.basename(path)
|
||||||
|
tmp_path="%s/%s%s.pth"%(dir,ttime(),i_part)
|
||||||
|
torch.save(fea,tmp_path)
|
||||||
|
shutil.move(tmp_path,"%s/%s"%(dir,name))
|
||||||
|
|
||||||
|
hubert_dir="%s/4-cnhubert"%(opt_dir)
|
||||||
|
wav32dir="%s/5-wav32k"%(opt_dir)
|
||||||
|
os.makedirs(opt_dir,exist_ok=True)
|
||||||
|
os.makedirs(hubert_dir,exist_ok=True)
|
||||||
|
os.makedirs(wav32dir,exist_ok=True)
|
||||||
|
|
||||||
def my_save(fea, path): #####fix issue: torch.save doesn't support chinese path
|
maxx=0.95
|
||||||
dir = os.path.dirname(path)
|
alpha=0.5
|
||||||
name = os.path.basename(path)
|
device="cuda:0"
|
||||||
tmp_path = "%s/%s%s.pth" % (dir, ttime(), i_part)
|
model=cnhubert.get_model()
|
||||||
torch.save(fea, tmp_path)
|
if(is_half==True):
|
||||||
shutil.move(tmp_path, "%s/%s" % (dir, name))
|
model=model.half().to(device)
|
||||||
|
|
||||||
|
|
||||||
hubert_dir = "%s/4-cnhubert" % (opt_dir)
|
|
||||||
wav32dir = "%s/5-wav32k" % (opt_dir)
|
|
||||||
os.makedirs(opt_dir, exist_ok=True)
|
|
||||||
os.makedirs(hubert_dir, exist_ok=True)
|
|
||||||
os.makedirs(wav32dir, exist_ok=True)
|
|
||||||
|
|
||||||
maxx = 0.95
|
|
||||||
alpha = 0.5
|
|
||||||
device = "cuda:0"
|
|
||||||
model = cnhubert.get_model()
|
|
||||||
if is_half == True:
|
|
||||||
model = model.half().to(device)
|
|
||||||
else:
|
else:
|
||||||
model = model.to(device)
|
model = model.to(device)
|
||||||
|
|
||||||
|
|
||||||
def name2go(wav_name):
|
def name2go(wav_name):
|
||||||
hubert_path = "%s/%s.pt" % (hubert_dir, wav_name)
|
hubert_path="%s/%s.pt"%(hubert_dir,wav_name)
|
||||||
if os.path.exists(hubert_path):
|
if(os.path.exists(hubert_path)):return
|
||||||
return
|
wav_path="%s/%s"%(inp_wav_dir,wav_name)
|
||||||
wav_path = "%s/%s" % (inp_wav_dir, wav_name)
|
|
||||||
tmp_audio = load_audio(wav_path, 32000)
|
tmp_audio = load_audio(wav_path, 32000)
|
||||||
tmp_max = np.abs(tmp_audio).max()
|
tmp_max = np.abs(tmp_audio).max()
|
||||||
if tmp_max > 2.2:
|
if tmp_max > 2.2:
|
||||||
print("%s-%s-%s-filtered" % (idx0, idx1, tmp_max))
|
print("%s-%s-%s-filtered" % (idx0, idx1, tmp_max))
|
||||||
return
|
return
|
||||||
tmp_audio32 = (tmp_audio / tmp_max * (maxx * alpha * 32768)) + (
|
tmp_audio32 = (tmp_audio / tmp_max * (maxx * alpha*32768)) + ((1 - alpha)*32768) * tmp_audio
|
||||||
(1 - alpha) * 32768
|
tmp_audio = librosa.resample(
|
||||||
) * tmp_audio
|
tmp_audio32, orig_sr=32000, target_sr=16000
|
||||||
tmp_audio = librosa.resample(tmp_audio32, orig_sr=32000, target_sr=16000)
|
)
|
||||||
tensor_wav16 = torch.from_numpy(tmp_audio)
|
tensor_wav16 = torch.from_numpy(tmp_audio)
|
||||||
if is_half == True:
|
if (is_half == True):
|
||||||
tensor_wav16 = tensor_wav16.half().to(device)
|
tensor_wav16=tensor_wav16.half().to(device)
|
||||||
else:
|
else:
|
||||||
tensor_wav16 = tensor_wav16.to(device)
|
tensor_wav16 = tensor_wav16.to(device)
|
||||||
ssl = (
|
ssl=model.model(tensor_wav16.unsqueeze(0))["last_hidden_state"].transpose(1,2).cpu()#torch.Size([1, 768, 215])
|
||||||
model.model(tensor_wav16.unsqueeze(0))["last_hidden_state"]
|
if np.isnan(ssl.detach().numpy()).sum()!= 0:return
|
||||||
.transpose(1, 2)
|
|
||||||
.cpu()
|
|
||||||
) # torch.Size([1, 768, 215])
|
|
||||||
if np.isnan(ssl.detach().numpy()).sum() != 0:
|
|
||||||
return
|
|
||||||
wavfile.write(
|
wavfile.write(
|
||||||
"%s/%s" % (wav32dir, wav_name),
|
"%s/%s"%(wav32dir,wav_name),
|
||||||
32000,
|
32000,
|
||||||
tmp_audio32.astype("int16"),
|
tmp_audio32.astype("int16"),
|
||||||
)
|
)
|
||||||
# torch.save(ssl,hubert_path )
|
# torch.save(ssl,hubert_path )
|
||||||
my_save(ssl, hubert_path)
|
my_save(ssl,hubert_path )
|
||||||
|
|
||||||
|
with open(inp_text,"r",encoding="utf8")as f:
|
||||||
|
lines=f.read().strip("\n").split("\n")
|
||||||
|
|
||||||
with open(inp_text, "r", encoding="utf8") as f:
|
for line in lines[int(i_part)::int(all_parts)]:
|
||||||
lines = f.read().strip("\n").split("\n")
|
|
||||||
|
|
||||||
for line in lines[int(i_part) :: int(all_parts)]:
|
|
||||||
try:
|
try:
|
||||||
# wav_name,text=line.split("\t")
|
# wav_name,text=line.split("\t")
|
||||||
wav_name, spk_name, language, text = line.split("|")
|
wav_name, spk_name, language, text = line.split("|")
|
||||||
wav_name = os.path.basename(wav_name)
|
wav_name=os.path.basename(wav_name)
|
||||||
name2go(wav_name)
|
name2go(wav_name)
|
||||||
except:
|
except:
|
||||||
print(line, traceback.format_exc())
|
print(line,traceback.format_exc())
|
||||||
|
2
GPT_SoVITS/pretrained_models/.gitignore
vendored
Normal file
2
GPT_SoVITS/pretrained_models/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
@ -18,7 +18,7 @@ logging.getLogger("matplotlib").setLevel(logging.ERROR)
|
|||||||
|
|
||||||
MATPLOTLIB_FLAG = False
|
MATPLOTLIB_FLAG = False
|
||||||
|
|
||||||
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
|
logging.basicConfig(stream=sys.stdout, level=logging.WARNING)
|
||||||
logger = logging
|
logger = logging
|
||||||
|
|
||||||
|
|
||||||
@ -310,13 +310,13 @@ def check_git_hash(model_dir):
|
|||||||
def get_logger(model_dir, filename="train.log"):
|
def get_logger(model_dir, filename="train.log"):
|
||||||
global logger
|
global logger
|
||||||
logger = logging.getLogger(os.path.basename(model_dir))
|
logger = logging.getLogger(os.path.basename(model_dir))
|
||||||
logger.setLevel(logging.DEBUG)
|
logger.setLevel(logging.WARNING)
|
||||||
|
|
||||||
formatter = logging.Formatter("%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s")
|
formatter = logging.Formatter("%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s")
|
||||||
if not os.path.exists(model_dir):
|
if not os.path.exists(model_dir):
|
||||||
os.makedirs(model_dir)
|
os.makedirs(model_dir)
|
||||||
h = logging.FileHandler(os.path.join(model_dir, filename))
|
h = logging.FileHandler(os.path.join(model_dir, filename))
|
||||||
h.setLevel(logging.DEBUG)
|
h.setLevel(logging.WARNING)
|
||||||
h.setFormatter(formatter)
|
h.setFormatter(formatter)
|
||||||
logger.addHandler(h)
|
logger.addHandler(h)
|
||||||
return logger
|
return logger
|
||||||
|
23
README.md
23
README.md
@ -11,7 +11,8 @@ A Powerful Few-shot Voice Conversion and Text-to-Speech WebUI.<br><br>
|
|||||||
[](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/LICENSE)
|
[](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/LICENSE)
|
||||||
[](https://huggingface.co/lj1995/GPT-SoVITS/tree/main)
|
[](https://huggingface.co/lj1995/GPT-SoVITS/tree/main)
|
||||||
|
|
||||||
[**English**](./README.md) | [**中文简体**](./docs/cn/README.md)
|
|
||||||
|
[**English**](./README.md) | [**中文简体**](./docs/cn/README.md) | [**日本語**](./docs/ja/README.md)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -36,9 +37,12 @@ https://github.com/RVC-Boss/GPT-SoVITS/assets/129054828/05bee1fa-bdd8-4d85-9350-
|
|||||||
|
|
||||||
If you are a Windows user (tested with win>=10) you can install directly via the prezip. Just download the [prezip](https://huggingface.co/lj1995/GPT-SoVITS-windows-package/resolve/main/GPT-SoVITS-beta.7z?download=true), unzip it and double-click go-webui.bat to start GPT-SoVITS-WebUI.
|
If you are a Windows user (tested with win>=10) you can install directly via the prezip. Just download the [prezip](https://huggingface.co/lj1995/GPT-SoVITS-windows-package/resolve/main/GPT-SoVITS-beta.7z?download=true), unzip it and double-click go-webui.bat to start GPT-SoVITS-WebUI.
|
||||||
|
|
||||||
### Python and PyTorch Version
|
### Tested Environments
|
||||||
|
|
||||||
Tested with Python 3.9, PyTorch 2.0.1, and CUDA 11.
|
- Python 3.9, PyTorch 2.0.1, CUDA 11
|
||||||
|
- Python 3.10.13, PyTorch 2.1.2, CUDA 12.3
|
||||||
|
|
||||||
|
_Note: numba==0.56.4 require py<3.11_
|
||||||
|
|
||||||
### Quick Install with Conda
|
### Quick Install with Conda
|
||||||
|
|
||||||
@ -48,6 +52,12 @@ conda activate GPTSoVits
|
|||||||
bash install.sh
|
bash install.sh
|
||||||
```
|
```
|
||||||
### Install Manually
|
### Install Manually
|
||||||
|
#### Make sure you have the distutils for python3.9 installed
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt-get install python3.9-distutils
|
||||||
|
```
|
||||||
|
|
||||||
#### Pip Packages
|
#### Pip Packages
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@ -90,7 +100,7 @@ Download and place [ffmpeg.exe](https://huggingface.co/lj1995/VoiceConversionWeb
|
|||||||
### Pretrained Models
|
### Pretrained Models
|
||||||
|
|
||||||
|
|
||||||
Download pretrained models from [GPT-SoVITS Models](https://huggingface.co/lj1995/GPT-SoVITS) and place them in `GPT_SoVITS\pretrained_models`.
|
Download pretrained models from [GPT-SoVITS Models](https://huggingface.co/lj1995/GPT-SoVITS) and place them in `GPT_SoVITS/pretrained_models`.
|
||||||
|
|
||||||
For Chinese ASR (additionally), download models from [Damo ASR Model](https://modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/files), [Damo VAD Model](https://modelscope.cn/models/damo/speech_fsmn_vad_zh-cn-16k-common-pytorch/files), and [Damo Punc Model](https://modelscope.cn/models/damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/files) and place them in `tools/damo_asr/models`.
|
For Chinese ASR (additionally), download models from [Damo ASR Model](https://modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/files), [Damo VAD Model](https://modelscope.cn/models/damo/speech_fsmn_vad_zh-cn-16k-common-pytorch/files), and [Damo Punc Model](https://modelscope.cn/models/damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/files) and place them in `tools/damo_asr/models`.
|
||||||
|
|
||||||
@ -121,6 +131,7 @@ D:\GPT-SoVITS\xxx/xxx.wav|xxx|en|I like playing Genshin.
|
|||||||
- [ ] **High Priority:**
|
- [ ] **High Priority:**
|
||||||
- [ ] Localization in Japanese and English.
|
- [ ] Localization in Japanese and English.
|
||||||
- [ ] User guide.
|
- [ ] User guide.
|
||||||
|
- [ ] Japanese and English dataset fine tune training.
|
||||||
|
|
||||||
- [ ] **Features:**
|
- [ ] **Features:**
|
||||||
- [ ] Zero-shot voice conversion (5s) / few-shot voice conversion (1min).
|
- [ ] Zero-shot voice conversion (5s) / few-shot voice conversion (1min).
|
||||||
@ -130,7 +141,9 @@ D:\GPT-SoVITS\xxx/xxx.wav|xxx|en|I like playing Genshin.
|
|||||||
- [ ] Improve English and Japanese text frontend.
|
- [ ] Improve English and Japanese text frontend.
|
||||||
- [ ] Develop tiny and larger-sized TTS models.
|
- [ ] Develop tiny and larger-sized TTS models.
|
||||||
- [ ] Colab scripts.
|
- [ ] Colab scripts.
|
||||||
- [ ] Expand training dataset (2k -> 10k).
|
- [ ] Try expand training dataset (2k hours -> 10k hours).
|
||||||
|
- [ ] better sovits base model (enhanced audio quality)
|
||||||
|
- [ ] model mix
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
|
325
api.py
Normal file
325
api.py
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import sys
|
||||||
|
from time import time as ttime
|
||||||
|
import torch
|
||||||
|
import librosa
|
||||||
|
import soundfile as sf
|
||||||
|
from fastapi import FastAPI, Request, HTTPException
|
||||||
|
from fastapi.responses import StreamingResponse
|
||||||
|
import uvicorn
|
||||||
|
from transformers import AutoModelForMaskedLM, AutoTokenizer
|
||||||
|
import numpy as np
|
||||||
|
from feature_extractor import cnhubert
|
||||||
|
from io import BytesIO
|
||||||
|
from module.models import SynthesizerTrn
|
||||||
|
from AR.models.t2s_lightning_module import Text2SemanticLightningModule
|
||||||
|
from text import cleaned_text_to_sequence
|
||||||
|
from text.cleaner import clean_text
|
||||||
|
from module.mel_processing import spectrogram_torch
|
||||||
|
from my_utils import load_audio
|
||||||
|
import config as global_config
|
||||||
|
|
||||||
|
g_config = global_config.Config()
|
||||||
|
|
||||||
|
# AVAILABLE_COMPUTE = "cuda" if torch.cuda.is_available() else "cpu"
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="GPT-SoVITS api")
|
||||||
|
|
||||||
|
parser.add_argument("-s", "--sovits_path", type=str, default=g_config.sovits_path, help="SoVITS模型路径")
|
||||||
|
parser.add_argument("-g", "--gpt_path", type=str, default=g_config.gpt_path, help="GPT模型路径")
|
||||||
|
|
||||||
|
parser.add_argument("-dr", "--default_refer_path", type=str, default="",
|
||||||
|
help="默认参考音频路径, 请求缺少参考音频时调用")
|
||||||
|
parser.add_argument("-dt", "--default_refer_text", type=str, default="", help="默认参考音频文本")
|
||||||
|
parser.add_argument("-dl", "--default_refer_language", type=str, default="", help="默认参考音频语种")
|
||||||
|
|
||||||
|
parser.add_argument("-d", "--device", type=str, default=g_config.infer_device, help="cuda / cpu")
|
||||||
|
parser.add_argument("-p", "--port", type=int, default=g_config.api_port, help="default: 9880")
|
||||||
|
parser.add_argument("-a", "--bind_addr", type=str, default="127.0.0.1", help="default: 127.0.0.1")
|
||||||
|
parser.add_argument("-fp", "--full_precision", action="store_true", default=False, help="覆盖config.is_half为False, 使用全精度")
|
||||||
|
parser.add_argument("-hp", "--half_precision", action="store_true", default=False, help="覆盖config.is_half为True, 使用半精度")
|
||||||
|
# bool值的用法为 `python ./api.py -fp ...`
|
||||||
|
# 此时 full_precision==True, half_precision==False
|
||||||
|
|
||||||
|
parser.add_argument("-hb", "--hubert_path", type=str, default=g_config.cnhubert_path, help="覆盖config.cnhubert_path")
|
||||||
|
parser.add_argument("-b", "--bert_path", type=str, default=g_config.bert_path, help="覆盖config.bert_path")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
sovits_path = args.sovits_path
|
||||||
|
gpt_path = args.gpt_path
|
||||||
|
|
||||||
|
default_refer_path = args.default_refer_path
|
||||||
|
default_refer_text = args.default_refer_text
|
||||||
|
default_refer_language = args.default_refer_language
|
||||||
|
has_preset = False
|
||||||
|
|
||||||
|
device = args.device
|
||||||
|
port = args.port
|
||||||
|
host = args.bind_addr
|
||||||
|
|
||||||
|
if sovits_path == "":
|
||||||
|
sovits_path = g_config.pretrained_sovits_path
|
||||||
|
print(f"[WARN] 未指定SoVITS模型路径, fallback后当前值: {sovits_path}")
|
||||||
|
if gpt_path == "":
|
||||||
|
gpt_path = g_config.pretrained_gpt_path
|
||||||
|
print(f"[WARN] 未指定GPT模型路径, fallback后当前值: {gpt_path}")
|
||||||
|
|
||||||
|
# 指定默认参考音频, 调用方 未提供/未给全 参考音频参数时使用
|
||||||
|
if default_refer_path == "" or default_refer_text == "" or default_refer_language == "":
|
||||||
|
default_refer_path, default_refer_text, default_refer_language = "", "", ""
|
||||||
|
print("[INFO] 未指定默认参考音频")
|
||||||
|
has_preset = False
|
||||||
|
else:
|
||||||
|
print(f"[INFO] 默认参考音频路径: {default_refer_path}")
|
||||||
|
print(f"[INFO] 默认参考音频文本: {default_refer_text}")
|
||||||
|
print(f"[INFO] 默认参考音频语种: {default_refer_language}")
|
||||||
|
has_preset = True
|
||||||
|
|
||||||
|
is_half = g_config.is_half
|
||||||
|
if args.full_precision:
|
||||||
|
is_half = False
|
||||||
|
if args.half_precision:
|
||||||
|
is_half = True
|
||||||
|
if args.full_precision and args.half_precision:
|
||||||
|
is_half = g_config.is_half # 炒饭fallback
|
||||||
|
|
||||||
|
print(f"[INFO] 半精: {is_half}")
|
||||||
|
|
||||||
|
cnhubert_base_path = args.hubert_path
|
||||||
|
bert_path = args.bert_path
|
||||||
|
|
||||||
|
cnhubert.cnhubert_base_path = cnhubert_base_path
|
||||||
|
tokenizer = AutoTokenizer.from_pretrained(bert_path)
|
||||||
|
bert_model = AutoModelForMaskedLM.from_pretrained(bert_path)
|
||||||
|
if is_half:
|
||||||
|
bert_model = bert_model.half().to(device)
|
||||||
|
else:
|
||||||
|
bert_model = bert_model.to(device)
|
||||||
|
|
||||||
|
|
||||||
|
def get_bert_feature(text, word2ph):
|
||||||
|
with torch.no_grad():
|
||||||
|
inputs = tokenizer(text, return_tensors="pt")
|
||||||
|
for i in inputs:
|
||||||
|
inputs[i] = inputs[i].to(device) #####输入是long不用管精度问题,精度随bert_model
|
||||||
|
res = bert_model(**inputs, output_hidden_states=True)
|
||||||
|
res = torch.cat(res["hidden_states"][-3:-2], -1)[0].cpu()[1:-1]
|
||||||
|
assert len(word2ph) == len(text)
|
||||||
|
phone_level_feature = []
|
||||||
|
for i in range(len(word2ph)):
|
||||||
|
repeat_feature = res[i].repeat(word2ph[i], 1)
|
||||||
|
phone_level_feature.append(repeat_feature)
|
||||||
|
phone_level_feature = torch.cat(phone_level_feature, dim=0)
|
||||||
|
# if(is_half==True):phone_level_feature=phone_level_feature.half()
|
||||||
|
return phone_level_feature.T
|
||||||
|
|
||||||
|
|
||||||
|
n_semantic = 1024
|
||||||
|
dict_s2 = torch.load(sovits_path, map_location="cpu")
|
||||||
|
hps = dict_s2["config"]
|
||||||
|
|
||||||
|
|
||||||
|
class DictToAttrRecursive:
|
||||||
|
def __init__(self, input_dict):
|
||||||
|
for key, value in input_dict.items():
|
||||||
|
if isinstance(value, dict):
|
||||||
|
# 如果值是字典,递归调用构造函数
|
||||||
|
setattr(self, key, DictToAttrRecursive(value))
|
||||||
|
else:
|
||||||
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
|
||||||
|
hps = DictToAttrRecursive(hps)
|
||||||
|
hps.model.semantic_frame_rate = "25hz"
|
||||||
|
dict_s1 = torch.load(gpt_path, map_location="cpu")
|
||||||
|
config = dict_s1["config"]
|
||||||
|
ssl_model = cnhubert.get_model()
|
||||||
|
if is_half:
|
||||||
|
ssl_model = ssl_model.half().to(device)
|
||||||
|
else:
|
||||||
|
ssl_model = ssl_model.to(device)
|
||||||
|
|
||||||
|
vq_model = SynthesizerTrn(
|
||||||
|
hps.data.filter_length // 2 + 1,
|
||||||
|
hps.train.segment_size // hps.data.hop_length,
|
||||||
|
n_speakers=hps.data.n_speakers,
|
||||||
|
**hps.model)
|
||||||
|
if is_half:
|
||||||
|
vq_model = vq_model.half().to(device)
|
||||||
|
else:
|
||||||
|
vq_model = vq_model.to(device)
|
||||||
|
vq_model.eval()
|
||||||
|
print(vq_model.load_state_dict(dict_s2["weight"], strict=False))
|
||||||
|
hz = 50
|
||||||
|
max_sec = config['data']['max_sec']
|
||||||
|
t2s_model = Text2SemanticLightningModule(config, "ojbk", is_train=False)
|
||||||
|
t2s_model.load_state_dict(dict_s1["weight"])
|
||||||
|
if is_half:
|
||||||
|
t2s_model = t2s_model.half()
|
||||||
|
t2s_model = t2s_model.to(device)
|
||||||
|
t2s_model.eval()
|
||||||
|
total = sum([param.nelement() for param in t2s_model.parameters()])
|
||||||
|
print("Number of parameter: %.2fM" % (total / 1e6))
|
||||||
|
|
||||||
|
|
||||||
|
def get_spepc(hps, filename):
|
||||||
|
audio = load_audio(filename, int(hps.data.sampling_rate))
|
||||||
|
audio = torch.FloatTensor(audio)
|
||||||
|
audio_norm = audio
|
||||||
|
audio_norm = audio_norm.unsqueeze(0)
|
||||||
|
spec = spectrogram_torch(audio_norm, hps.data.filter_length, hps.data.sampling_rate, hps.data.hop_length,
|
||||||
|
hps.data.win_length, center=False)
|
||||||
|
return spec
|
||||||
|
|
||||||
|
|
||||||
|
dict_language = {
|
||||||
|
"中文": "zh",
|
||||||
|
"英文": "en",
|
||||||
|
"日文": "ja",
|
||||||
|
"ZH": "zh",
|
||||||
|
"EN": "en",
|
||||||
|
"JA": "ja",
|
||||||
|
"zh": "zh",
|
||||||
|
"en": "en",
|
||||||
|
"ja": "ja"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language):
|
||||||
|
t0 = ttime()
|
||||||
|
prompt_text = prompt_text.strip("\n")
|
||||||
|
prompt_language, text = prompt_language, text.strip("\n")
|
||||||
|
with torch.no_grad():
|
||||||
|
wav16k, sr = librosa.load(ref_wav_path, sr=16000) # 派蒙
|
||||||
|
wav16k = torch.from_numpy(wav16k)
|
||||||
|
if (is_half == True):
|
||||||
|
wav16k = wav16k.half().to(device)
|
||||||
|
else:
|
||||||
|
wav16k = wav16k.to(device)
|
||||||
|
ssl_content = ssl_model.model(wav16k.unsqueeze(0))["last_hidden_state"].transpose(1, 2) # .float()
|
||||||
|
codes = vq_model.extract_latent(ssl_content)
|
||||||
|
prompt_semantic = codes[0, 0]
|
||||||
|
t1 = ttime()
|
||||||
|
prompt_language = dict_language[prompt_language]
|
||||||
|
text_language = dict_language[text_language]
|
||||||
|
phones1, word2ph1, norm_text1 = clean_text(prompt_text, prompt_language)
|
||||||
|
phones1 = cleaned_text_to_sequence(phones1)
|
||||||
|
texts = text.split("\n")
|
||||||
|
audio_opt = []
|
||||||
|
zero_wav = np.zeros(int(hps.data.sampling_rate * 0.3), dtype=np.float16 if is_half == True else np.float32)
|
||||||
|
for text in texts:
|
||||||
|
phones2, word2ph2, norm_text2 = clean_text(text, text_language)
|
||||||
|
phones2 = cleaned_text_to_sequence(phones2)
|
||||||
|
if (prompt_language == "zh"):
|
||||||
|
bert1 = get_bert_feature(norm_text1, word2ph1).to(device)
|
||||||
|
else:
|
||||||
|
bert1 = torch.zeros((1024, len(phones1)), dtype=torch.float16 if is_half == True else torch.float32).to(
|
||||||
|
device)
|
||||||
|
if (text_language == "zh"):
|
||||||
|
bert2 = get_bert_feature(norm_text2, word2ph2).to(device)
|
||||||
|
else:
|
||||||
|
bert2 = torch.zeros((1024, len(phones2))).to(bert1)
|
||||||
|
bert = torch.cat([bert1, bert2], 1)
|
||||||
|
|
||||||
|
all_phoneme_ids = torch.LongTensor(phones1 + phones2).to(device).unsqueeze(0)
|
||||||
|
bert = bert.to(device).unsqueeze(0)
|
||||||
|
all_phoneme_len = torch.tensor([all_phoneme_ids.shape[-1]]).to(device)
|
||||||
|
prompt = prompt_semantic.unsqueeze(0).to(device)
|
||||||
|
t2 = ttime()
|
||||||
|
with torch.no_grad():
|
||||||
|
# pred_semantic = t2s_model.model.infer(
|
||||||
|
pred_semantic, idx = t2s_model.model.infer_panel(
|
||||||
|
all_phoneme_ids,
|
||||||
|
all_phoneme_len,
|
||||||
|
prompt,
|
||||||
|
bert,
|
||||||
|
# prompt_phone_len=ph_offset,
|
||||||
|
top_k=config['inference']['top_k'],
|
||||||
|
early_stop_num=hz * max_sec)
|
||||||
|
t3 = ttime()
|
||||||
|
# print(pred_semantic.shape,idx)
|
||||||
|
pred_semantic = pred_semantic[:, -idx:].unsqueeze(0) # .unsqueeze(0)#mq要多unsqueeze一次
|
||||||
|
refer = get_spepc(hps, ref_wav_path) # .to(device)
|
||||||
|
if (is_half == True):
|
||||||
|
refer = refer.half().to(device)
|
||||||
|
else:
|
||||||
|
refer = refer.to(device)
|
||||||
|
# audio = vq_model.decode(pred_semantic, all_phoneme_ids, refer).detach().cpu().numpy()[0, 0]
|
||||||
|
audio = \
|
||||||
|
vq_model.decode(pred_semantic, torch.LongTensor(phones2).to(device).unsqueeze(0),
|
||||||
|
refer).detach().cpu().numpy()[
|
||||||
|
0, 0] ###试试重建不带上prompt部分
|
||||||
|
audio_opt.append(audio)
|
||||||
|
audio_opt.append(zero_wav)
|
||||||
|
t4 = ttime()
|
||||||
|
print("%.3f\t%.3f\t%.3f\t%.3f" % (t1 - t0, t2 - t1, t3 - t2, t4 - t3))
|
||||||
|
yield hps.data.sampling_rate, (np.concatenate(audio_opt, 0) * 32768).astype(np.int16)
|
||||||
|
|
||||||
|
|
||||||
|
def handle(command, refer_wav_path, prompt_text, prompt_language, text, text_language):
|
||||||
|
if command == "/restart":
|
||||||
|
os.execl(g_config.python_exec, g_config.python_exec, *sys.argv)
|
||||||
|
elif command == "/exit":
|
||||||
|
os.kill(os.getpid(), signal.SIGTERM)
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
if (
|
||||||
|
refer_wav_path == "" or refer_wav_path is None
|
||||||
|
or prompt_text == "" or prompt_text is None
|
||||||
|
or prompt_language == "" or prompt_language is None
|
||||||
|
):
|
||||||
|
refer_wav_path, prompt_text, prompt_language = (
|
||||||
|
default_refer_path,
|
||||||
|
default_refer_text,
|
||||||
|
default_refer_language,
|
||||||
|
)
|
||||||
|
if not has_preset:
|
||||||
|
raise HTTPException(status_code=400, detail="未指定参考音频且接口无预设")
|
||||||
|
|
||||||
|
with torch.no_grad():
|
||||||
|
gen = get_tts_wav(
|
||||||
|
refer_wav_path, prompt_text, prompt_language, text, text_language
|
||||||
|
)
|
||||||
|
sampling_rate, audio_data = next(gen)
|
||||||
|
|
||||||
|
wav = BytesIO()
|
||||||
|
sf.write(wav, audio_data, sampling_rate, format="wav")
|
||||||
|
wav.seek(0)
|
||||||
|
|
||||||
|
torch.cuda.empty_cache()
|
||||||
|
return StreamingResponse(wav, media_type="audio/wav")
|
||||||
|
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/")
|
||||||
|
async def tts_endpoint(request: Request):
|
||||||
|
json_post_raw = await request.json()
|
||||||
|
return handle(
|
||||||
|
json_post_raw.get("command"),
|
||||||
|
json_post_raw.get("refer_wav_path"),
|
||||||
|
json_post_raw.get("prompt_text"),
|
||||||
|
json_post_raw.get("prompt_language"),
|
||||||
|
json_post_raw.get("text"),
|
||||||
|
json_post_raw.get("text_language"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def tts_endpoint(
|
||||||
|
command: str = None,
|
||||||
|
refer_wav_path: str = None,
|
||||||
|
prompt_text: str = None,
|
||||||
|
prompt_language: str = None,
|
||||||
|
text: str = None,
|
||||||
|
text_language: str = None,
|
||||||
|
):
|
||||||
|
return handle(command, refer_wav_path, prompt_text, prompt_language, text, text_language)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
uvicorn.run(app, host=host, port=port, workers=1)
|
53
config.py
53
config.py
@ -1,10 +1,47 @@
|
|||||||
import sys
|
import sys
|
||||||
is_half=True
|
|
||||||
exp_root="logs"
|
|
||||||
python_exec=sys.executable or "python"
|
|
||||||
infer_device="cuda"
|
|
||||||
|
|
||||||
webui_port_main=9874
|
|
||||||
webui_port_uvr5=9873
|
# 推理用的指定模型
|
||||||
webui_port_infer_tts=9872
|
sovits_path = ""
|
||||||
webui_port_subfix=9871
|
gpt_path = ""
|
||||||
|
is_half = True
|
||||||
|
is_share=False
|
||||||
|
|
||||||
|
cnhubert_path = "GPT_SoVITS/pretrained_models/chinese-hubert-base"
|
||||||
|
bert_path = "GPT_SoVITS/pretrained_models/chinese-roberta-wwm-ext-large"
|
||||||
|
pretrained_sovits_path = "GPT_SoVITS/pretrained_models/s2G488k.pth"
|
||||||
|
pretrained_gpt_path = "GPT_SoVITS/pretrained_models/s1bert25hz-2kh-longer-epoch=68e-step=50232.ckpt"
|
||||||
|
|
||||||
|
exp_root = "logs"
|
||||||
|
python_exec = sys.executable or "python"
|
||||||
|
infer_device = "cuda"
|
||||||
|
|
||||||
|
webui_port_main = 9874
|
||||||
|
webui_port_uvr5 = 9873
|
||||||
|
webui_port_infer_tts = 9872
|
||||||
|
webui_port_subfix = 9871
|
||||||
|
|
||||||
|
api_port = 9880
|
||||||
|
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
def __init__(self):
|
||||||
|
self.sovits_path = sovits_path
|
||||||
|
self.gpt_path = gpt_path
|
||||||
|
self.is_half = is_half
|
||||||
|
|
||||||
|
self.cnhubert_path = cnhubert_path
|
||||||
|
self.bert_path = bert_path
|
||||||
|
self.pretrained_sovits_path = pretrained_sovits_path
|
||||||
|
self.pretrained_gpt_path = pretrained_gpt_path
|
||||||
|
|
||||||
|
self.exp_root = exp_root
|
||||||
|
self.python_exec = python_exec
|
||||||
|
self.infer_device = infer_device
|
||||||
|
|
||||||
|
self.webui_port_main = webui_port_main
|
||||||
|
self.webui_port_uvr5 = webui_port_uvr5
|
||||||
|
self.webui_port_infer_tts = webui_port_infer_tts
|
||||||
|
self.webui_port_subfix = webui_port_subfix
|
||||||
|
|
||||||
|
self.api_port = api_port
|
||||||
|
160
docs/cn/README.md
Normal file
160
docs/cn/README.md
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<h1>GPT-SoVITS-WebUI</h1>
|
||||||
|
少样本强大的声音转换与文本到语音网络界面。<br><br>
|
||||||
|
|
||||||
|
[](https://github.com/RVC-Boss/GPT-SoVITS)
|
||||||
|
|
||||||
|
<img src="https://counter.seku.su/cmoe?name=gptsovits&theme=r34" /><br>
|
||||||
|
|
||||||
|
[](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/LICENSE)
|
||||||
|
[](https://huggingface.co/lj1995/GPT-SoVITS/tree/main)
|
||||||
|
|
||||||
|
[**English**](./README.md) | [**中文简体**](./README_ZH.md)
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
> 查看我们的介绍视频 [demo video](https://www.bilibili.com/video/BV12g4y1m7Uw)
|
||||||
|
|
||||||
|
https://github.com/RVC-Boss/GPT-SoVITS/assets/129054828/05bee1fa-bdd8-4d85-9350-80c060ab47fb
|
||||||
|
|
||||||
|
## 功能:
|
||||||
|
1. **零样本文本到语音(TTS):** 输入5秒的声音样本,即刻体验文本到语音转换。
|
||||||
|
|
||||||
|
2. **少样本TTS:** 仅需1分钟的训练数据即可微调模型,提升声音相似度和真实感。
|
||||||
|
|
||||||
|
3. **跨语言支持:** 支持与训练数据集不同语言的推理,目前支持英语、日语和中文。
|
||||||
|
|
||||||
|
4. **WebUI工具:** 集成工具包括声音伴奏分离、自动训练集分割、中文自动语音识别(ASR)和文本标注,协助初学者创建训练数据集和GPT/SoVITS模型。
|
||||||
|
|
||||||
|
## 环境准备
|
||||||
|
|
||||||
|
如果你是Windows用户(已在win>=10上测试),可以直接通过预打包文件安装。只需下载[预打包文件](https://huggingface.co/lj1995/GPT-SoVITS-windows-package/resolve/main/GPT-SoVITS-beta.7z?download=true),解压后双击go-webui.bat即可启动GPT-SoVITS-WebUI。
|
||||||
|
|
||||||
|
### Python和PyTorch版本
|
||||||
|
|
||||||
|
已在Python 3.9、PyTorch 2.0.1和CUDA 11上测试。
|
||||||
|
|
||||||
|
### 使用Conda快速安装
|
||||||
|
|
||||||
|
```bash
|
||||||
|
conda create -n GPTSoVits python=3.9
|
||||||
|
conda activate GPTSoVits
|
||||||
|
bash install.sh
|
||||||
|
```
|
||||||
|
### 手动安装包
|
||||||
|
#### Pip包
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install torch numpy scipy tensorboard librosa==0.9.2 numba==0.56.4 pytorch-lightning gradio==3.14.0 ffmpeg-python onnxruntime tqdm cn2an pypinyin pyopenjtalk g2p_en chardet
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 额外要求
|
||||||
|
|
||||||
|
如果你需要中文自动语音识别(由FunASR支持),请安装:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install modelscope torchaudio sentencepiece funasr
|
||||||
|
```
|
||||||
|
|
||||||
|
#### FFmpeg
|
||||||
|
|
||||||
|
##### Conda 使用者
|
||||||
|
```bash
|
||||||
|
conda install ffmpeg
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Ubuntu/Debian 使用者
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install ffmpeg
|
||||||
|
sudo apt install libsox-dev
|
||||||
|
conda install -c conda-forge 'ffmpeg<7'
|
||||||
|
```
|
||||||
|
|
||||||
|
##### MacOS 使用者
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install ffmpeg
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Windows 使用者
|
||||||
|
|
||||||
|
下载并将 [ffmpeg.exe](https://huggingface.co/lj1995/VoiceConversionWebUI/blob/main/ffmpeg.exe) 和 [ffprobe.exe](https://huggingface.co/lj1995/VoiceConversionWebUI/blob/main/ffprobe.exe) 放置在 GPT-SoVITS 根目录下。
|
||||||
|
|
||||||
|
### 预训练模型
|
||||||
|
|
||||||
|
|
||||||
|
从 [GPT-SoVITS Models](https://huggingface.co/lj1995/GPT-SoVITS) 下载预训练模型,并将它们放置在 `GPT_SoVITS\pretrained_models` 中。
|
||||||
|
|
||||||
|
对于中文自动语音识别(另外),从 [Damo ASR Model](https://modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/files), [Damo VAD Model](https://modelscope.cn/models/damo/speech_fsmn_vad_zh-cn-16k-common-pytorch/files), 和 [Damo Punc Model](https://modelscope.cn/models/damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/files) 下载模型,并将它们放置在 `tools/damo_asr/models` 中。
|
||||||
|
|
||||||
|
对于UVR5(人声/伴奏分离和混响移除,另外),从 [UVR5 Weights](https://huggingface.co/lj1995/VoiceConversionWebUI/tree/main/uvr5_weights) 下载模型,并将它们放置在 `tools/uvr5/uvr5_weights` 中。
|
||||||
|
|
||||||
|
|
||||||
|
## 数据集格式
|
||||||
|
|
||||||
|
文本到语音(TTS)注释 .list 文件格式:
|
||||||
|
|
||||||
|
```
|
||||||
|
vocal_path|speaker_name|language|text
|
||||||
|
```
|
||||||
|
|
||||||
|
语言字典:
|
||||||
|
|
||||||
|
- 'zh': Chinese
|
||||||
|
- 'ja': Japanese
|
||||||
|
- 'en': English
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
```
|
||||||
|
D:\GPT-SoVITS\xxx/xxx.wav|xxx|en|I like playing Genshin.
|
||||||
|
```
|
||||||
|
## 待办事项清单
|
||||||
|
|
||||||
|
- [ ] **高优先级:**
|
||||||
|
- [ ] 日语和英语的本地化。
|
||||||
|
- [ ] 用户指南。
|
||||||
|
- [ ] 日语和英语数据集微调训练。
|
||||||
|
|
||||||
|
- [ ] **Features:**
|
||||||
|
- [ ] 零样本声音转换(5秒)/ 少样本声音转换(1分钟)。
|
||||||
|
- [ ] TTS语速控制。
|
||||||
|
- [ ] 增强的TTS情感控制。
|
||||||
|
- [ ] 尝试将SoVITS令牌输入更改为词汇的概率分布。
|
||||||
|
- [ ] 改进英语和日语文本前端。
|
||||||
|
- [ ] 开发体积小和更大的TTS模型。
|
||||||
|
- [ ] Colab脚本。
|
||||||
|
- [ ] 扩展训练数据集(从2k小时到10k小时)。
|
||||||
|
- [ ] 更好的sovits基础模型(增强的音频质量)。
|
||||||
|
- [ ] 模型混合。
|
||||||
|
|
||||||
|
## 致谢
|
||||||
|
|
||||||
|
特别感谢以下项目和贡献者:
|
||||||
|
|
||||||
|
- [ar-vits](https://github.com/innnky/ar-vits)
|
||||||
|
- [SoundStorm](https://github.com/yangdongchao/SoundStorm/tree/master/soundstorm/s1/AR)
|
||||||
|
- [vits](https://github.com/jaywalnut310/vits)
|
||||||
|
- [TransferTTS](https://github.com/hcy71o/TransferTTS/blob/master/models.py#L556)
|
||||||
|
- [Chinese Speech Pretrain](https://github.com/TencentGameMate/chinese_speech_pretrain)
|
||||||
|
- [contentvec](https://github.com/auspicious3000/contentvec/)
|
||||||
|
- [hifi-gan](https://github.com/jik876/hifi-gan)
|
||||||
|
- [Chinese-Roberta-WWM-Ext-Large](https://huggingface.co/hfl/chinese-roberta-wwm-ext-large)
|
||||||
|
- [fish-speech](https://github.com/fishaudio/fish-speech/blob/main/tools/llama/generate.py#L41)
|
||||||
|
- [ultimatevocalremovergui](https://github.com/Anjok07/ultimatevocalremovergui)
|
||||||
|
- [audio-slicer](https://github.com/openvpi/audio-slicer)
|
||||||
|
- [SubFix](https://github.com/cronrpc/SubFix)
|
||||||
|
- [FFmpeg](https://github.com/FFmpeg/FFmpeg)
|
||||||
|
- [gradio](https://github.com/gradio-app/gradio)
|
||||||
|
|
||||||
|
## 感谢所有贡献者的努力
|
||||||
|
<a href="https://github.com/RVC-Boss/GPT-SoVITS/graphs/contributors" target="_blank">
|
||||||
|
<img src="https://contrib.rocks/image?repo=RVC-Boss/GPT-SoVITS" />
|
||||||
|
</a>
|
166
docs/ja/README.md
Normal file
166
docs/ja/README.md
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<h1>GPT-SoVITS-WebUI</h1>
|
||||||
|
パワフルな数発音声変換・音声合成 WebUI。<br><br>
|
||||||
|
|
||||||
|
[](https://github.com/RVC-Boss/GPT-SoVITS)
|
||||||
|
|
||||||
|
<img src="https://counter.seku.su/cmoe?name=gptsovits&theme=r34" /><br>
|
||||||
|
|
||||||
|
[](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/LICENSE)
|
||||||
|
[](https://huggingface.co/lj1995/GPT-SoVITS/tree/main)
|
||||||
|
|
||||||
|
[**English**](../../README.md) | [**中文简体**](../cn/README.md) | [**日本語**](./README.md)
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
> [デモ動画](https://www.bilibili.com/video/BV12g4y1m7Uw)をチェック!
|
||||||
|
|
||||||
|
https://github.com/RVC-Boss/GPT-SoVITS/assets/129054828/05bee1fa-bdd8-4d85-9350-80c060ab47fb
|
||||||
|
|
||||||
|
## 機能:
|
||||||
|
1. **セロショット TTS:** 5秒間のボーカルサンプルを入力すると、即座にテキストから音声に変換されます。
|
||||||
|
|
||||||
|
2. **数ショット TTS:** わずか1分間のトレーニングデータでモデルを微調整し、音声の類似性とリアリズムを向上。
|
||||||
|
|
||||||
|
3. **多言語サポート:** 現在、英語、日本語、中国語をサポートしています。
|
||||||
|
|
||||||
|
4. **WebUI ツール:** 統合されたツールには、音声伴奏の分離、トレーニングセットの自動セグメンテーション、中国語 ASR、テキストラベリングが含まれ、初心者がトレーニングデータセットと GPT/SoVITS モデルを作成するのを支援します。
|
||||||
|
|
||||||
|
## 環境の準備
|
||||||
|
|
||||||
|
Windows ユーザーであれば(win>=10 にてテスト済み)、prezip 経由で直接インストールできます。[prezip](https://huggingface.co/lj1995/GPT-SoVITS-windows-package/resolve/main/GPT-SoVITS-beta.7z?download=true) をダウンロードして解凍し、go-webui.bat をダブルクリックするだけで GPT-SoVITS-WebUI が起動します。
|
||||||
|
|
||||||
|
### Python と PyTorch のバージョン
|
||||||
|
|
||||||
|
Python 3.9、PyTorch 2.0.1、CUDA 11でテスト済。
|
||||||
|
|
||||||
|
### Conda によるクイックインストール
|
||||||
|
|
||||||
|
```bash
|
||||||
|
conda create -n GPTSoVits python=3.9
|
||||||
|
conda activate GPTSoVits
|
||||||
|
bash install.sh
|
||||||
|
```
|
||||||
|
### 手動インストール
|
||||||
|
#### python3.9 用の distutils がインストールされていることを確認する
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt-get install python3.9-distutils
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Pip パッケージ
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install torch numpy scipy tensorboard librosa==0.9.2 numba==0.56.4 pytorch-lightning gradio==3.14.0 ffmpeg-python onnxruntime tqdm cn2an pypinyin pyopenjtalk g2p_en chardet
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 追加要件
|
||||||
|
|
||||||
|
中国語の ASR(FunASR がサポート)が必要な場合は、以下をインストールしてください:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install modelscope torchaudio sentencepiece funasr
|
||||||
|
```
|
||||||
|
|
||||||
|
#### FFmpeg
|
||||||
|
|
||||||
|
##### Conda ユーザー
|
||||||
|
```bash
|
||||||
|
conda install ffmpeg
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Ubuntu/Debian ユーザー
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install ffmpeg
|
||||||
|
sudo apt install libsox-dev
|
||||||
|
conda install -c conda-forge 'ffmpeg<7'
|
||||||
|
```
|
||||||
|
|
||||||
|
##### MacOS ユーザー
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install ffmpeg
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Windows ユーザー
|
||||||
|
|
||||||
|
[ffmpeg.exe](https://huggingface.co/lj1995/VoiceConversionWebUI/blob/main/ffmpeg.exe) と [ffprobe.exe](https://huggingface.co/lj1995/VoiceConversionWebUI/blob/main/ffprobe.exe) をダウンロードし、GPT-SoVITS のルートディレクトリに置きます。
|
||||||
|
|
||||||
|
### 事前訓練済みモデル
|
||||||
|
|
||||||
|
|
||||||
|
[GPT-SoVITS Models](https://huggingface.co/lj1995/GPT-SoVITS) から事前訓練済みモデルをダウンロードし、`GPT_SoVITSpretrained_models` に置きます。
|
||||||
|
|
||||||
|
中国語 ASR(追加)については、[Damo ASR Model](https://modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/files)、[Damo VAD Model](https://modelscope.cn/models/damo/speech_fsmn_vad_zh-cn-16k-common-pytorch/files)、[Damo Punc Model](https://modelscope.cn/models/damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch/files) からモデルをダウンロードし、`tools/damo_asr/models` に置いてください。
|
||||||
|
|
||||||
|
UVR5 (Vocals/Accompaniment Separation & Reverberation Removal, additionally) の場合は、[UVR5 Weights](https://huggingface.co/lj1995/VoiceConversionWebUI/tree/main/uvr5_weights) からモデルをダウンロードして `tools/uvr5/uvr5_weights` に置きます。
|
||||||
|
|
||||||
|
|
||||||
|
## データセット形式
|
||||||
|
|
||||||
|
TTS アノテーション .list ファイル形式:
|
||||||
|
|
||||||
|
```
|
||||||
|
vocal_path|speaker_name|language|text
|
||||||
|
```
|
||||||
|
|
||||||
|
言語辞書:
|
||||||
|
|
||||||
|
- 'zh': 中国語
|
||||||
|
- 'ja': 日本語
|
||||||
|
- 'en': 英語
|
||||||
|
|
||||||
|
例:
|
||||||
|
|
||||||
|
```
|
||||||
|
D:\GPT-SoVITS\xxx/xxx.wav|xxx|en|I like playing Genshin.
|
||||||
|
```
|
||||||
|
## Todo リスト
|
||||||
|
|
||||||
|
- [ ] **優先度 高:**
|
||||||
|
- [ ] 日本語と英語でのローカライズ。
|
||||||
|
- [ ] ユーザーガイド。
|
||||||
|
- [ ] 日本語データセットと英語データセットのファインチューニングトレーニング。
|
||||||
|
|
||||||
|
- [ ] **機能:**
|
||||||
|
- [ ] ゼロショット音声変換(5秒)/数ショット音声変換(1分)。
|
||||||
|
- [ ] TTS スピーキングスピードコントロール。
|
||||||
|
- [ ] TTS の感情コントロールの強化。
|
||||||
|
- [ ] SoVITS トークン入力を語彙の確率分布に変更する実験。
|
||||||
|
- [ ] 英語と日本語のテキストフロントエンドを改善。
|
||||||
|
- [ ] 小型と大型の TTS モデルを開発する。
|
||||||
|
- [ ] Colab のスクリプト。
|
||||||
|
- [ ] トレーニングデータセットを拡張する(2k→10k)。
|
||||||
|
- [ ] より良い sovits ベースモデル(音質向上)
|
||||||
|
- [ ] モデルミックス
|
||||||
|
|
||||||
|
## クレジット
|
||||||
|
|
||||||
|
以下のプロジェクトとコントリビューターに感謝します:
|
||||||
|
|
||||||
|
- [ar-vits](https://github.com/innnky/ar-vits)
|
||||||
|
- [SoundStorm](https://github.com/yangdongchao/SoundStorm/tree/master/soundstorm/s1/AR)
|
||||||
|
- [vits](https://github.com/jaywalnut310/vits)
|
||||||
|
- [TransferTTS](https://github.com/hcy71o/TransferTTS/blob/master/models.py#L556)
|
||||||
|
- [Chinese Speech Pretrain](https://github.com/TencentGameMate/chinese_speech_pretrain)
|
||||||
|
- [contentvec](https://github.com/auspicious3000/contentvec/)
|
||||||
|
- [hifi-gan](https://github.com/jik876/hifi-gan)
|
||||||
|
- [Chinese-Roberta-WWM-Ext-Large](https://huggingface.co/hfl/chinese-roberta-wwm-ext-large)
|
||||||
|
- [fish-speech](https://github.com/fishaudio/fish-speech/blob/main/tools/llama/generate.py#L41)
|
||||||
|
- [ultimatevocalremovergui](https://github.com/Anjok07/ultimatevocalremovergui)
|
||||||
|
- [audio-slicer](https://github.com/openvpi/audio-slicer)
|
||||||
|
- [SubFix](https://github.com/cronrpc/SubFix)
|
||||||
|
- [FFmpeg](https://github.com/FFmpeg/FFmpeg)
|
||||||
|
- [gradio](https://github.com/gradio-app/gradio)
|
||||||
|
|
||||||
|
## すべてのコントリビューターに感謝します
|
||||||
|
<a href="https://github.com/RVC-Boss/GPT-SoVITS/graphs/contributors" target="_blank">
|
||||||
|
<img src="https://contrib.rocks/image?repo=RVC-Boss/GPT-SoVITS" />
|
||||||
|
</a>
|
@ -1,4 +1,154 @@
|
|||||||
{
|
{
|
||||||
|
"很遗憾您这没有能用的显卡来支持您训练": "Unfortunately, there is no compatible GPU available to support your training.",
|
||||||
|
"UVR5已开启": "UVR5 opened ",
|
||||||
|
"UVR5已关闭": "UVR5 closed",
|
||||||
|
"本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责. <br>如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录<b>LICENSE</b>.": "This software is open source under the MIT license. The author does not have any control over the software. Users who use the software and distribute the sounds exported by the software are solely responsible. <br>If you do not agree with this clause, you cannot use or reference any codes and files within the software package. See the root directory <b>Agreement-LICENSE.txt</b> for details.",
|
||||||
|
"0-前置数据集获取工具": "0-Fech dataset",
|
||||||
|
"0a-UVR5人声伴奏分离&去混响去延迟工具": "0a-UVR5 webui (for vocal separation, deecho, dereverb and denoise)",
|
||||||
|
"是否开启UVR5-WebUI": "Open UVR5-WebUI",
|
||||||
|
"UVR5进程输出信息": "UVR5 process output log",
|
||||||
|
"0b-语音切分工具": "0b-Audio slicer",
|
||||||
|
"音频自动切分输入路径,可文件可文件夹": "Audio slicer input (file or folder)",
|
||||||
|
"切分后的子音频的输出根目录": "Audio slicer output folder",
|
||||||
|
"threshold:音量小于这个值视作静音的备选切割点": "Noise gate threshold (loudness below this value will be treated as noise",
|
||||||
|
"min_length:每段最小多长,如果第一段太短一直和后面段连起来直到超过这个值": "Minimum length",
|
||||||
|
"min_interval:最短切割间隔": "Minumum interval for audio cutting",
|
||||||
|
"hop_size:怎么算音量曲线,越小精度越大计算量越高(不是精度越大效果越好)": "hop_size: FO hop size, the smaller the value, the higher the accuracy)",
|
||||||
|
"max_sil_kept:切完后静音最多留多长": "Maximum length for silence to be kept",
|
||||||
|
"开启语音切割": "Start audio slicer",
|
||||||
|
"终止语音切割": "Stop audio cutting",
|
||||||
|
"max:归一化后最大值多少": "Loudness multiplier after normalized",
|
||||||
|
"alpha_mix:混多少比例归一化后音频进来": "alpha_mix: proportion of normalized audio merged into dataset",
|
||||||
|
"切割使用的进程数": "CPU threads used for audio slicing",
|
||||||
|
"语音切割进程输出信息": "Audio slicer output log",
|
||||||
|
"0c-中文批量离线ASR工具": "0c-Chinese ASR tool",
|
||||||
|
"开启离线批量ASR": "Start batch ASR",
|
||||||
|
"终止ASR进程": "Stop ASR task",
|
||||||
|
"批量ASR(中文only)输入文件夹路径": "Batch ASR (Chinese only) input folder",
|
||||||
|
"ASR进程输出信息": "ASR output log",
|
||||||
|
"0d-语音文本校对标注工具": "0d-Speech to text proofreading tool",
|
||||||
|
"是否开启打标WebUI": "Open labelling WebUI",
|
||||||
|
"打标数据标注文件路径": "path to proofreading text file",
|
||||||
|
"打标工具进程输出信息": "Proofreading tool output log",
|
||||||
|
"1-GPT-SoVITS-TTS": "1-GPT-SOVITS-TTS",
|
||||||
|
"*实验/模型名": "*Experiment/model name",
|
||||||
|
"显卡信息": "GPU Information",
|
||||||
|
"预训练的SoVITS-G模型路径": "Pretrained SoVITS-G model path",
|
||||||
|
"预训练的SoVITS-D模型路径": "Pretrained SoVITS-D model path",
|
||||||
|
"预训练的GPT模型路径": "Pretrained GPT model path",
|
||||||
|
"1A-训练集格式化工具": "1A-Dataset formatting",
|
||||||
|
"输出logs/实验名目录下应有23456开头的文件和文件夹": "output folder (logs/{experiment name}) should have files and folders starts with 23456.",
|
||||||
|
"*文本标注文件": "*Text labelling file",
|
||||||
|
"*训练集音频文件目录": "*Audio dataset folder",
|
||||||
|
"训练集音频文件目录 拼接 list文件里波形对应的文件名。": "Training the file name corresponding to the waveform of the waveform in the List file of the audio file",
|
||||||
|
"1Aa-文本内容": "1Aa-Text",
|
||||||
|
"GPU卡号以-分割,每个卡号一个进程": "GPU number is separated by -, each GPU will run one process ",
|
||||||
|
"预训练的中文BERT模型路径": " Pretrained BERT model path",
|
||||||
|
"开启文本获取": "Start speech-to-text",
|
||||||
|
"终止文本获取进程": "Stop speech-to-text",
|
||||||
|
"文本进程输出信息": "Text processing output",
|
||||||
|
"1Ab-SSL自监督特征提取": "1Ab-SSL self-supervised feature extraction",
|
||||||
|
"预训练的SSL模型路径": "Pretrained SSL model path",
|
||||||
|
"开启SSL提取": "Start SSL extracting",
|
||||||
|
"终止SSL提取进程": "Stop SSL extraction",
|
||||||
|
"SSL进程输出信息": "SSL output log",
|
||||||
|
"1Ac-语义token提取": "1Ac-semantics token extraction",
|
||||||
|
"开启语义token提取": "Start semantics token extraction",
|
||||||
|
"终止语义token提取进程": "Stop semantics token extraction",
|
||||||
|
"语义token提取进程输出信息": "Sematics token extraction output log",
|
||||||
|
"1Aabc-训练集格式化一键三连": "1Aabc-One-click formatting",
|
||||||
|
"开启一键三连": "Start one-click formatting",
|
||||||
|
"终止一键三连": "Stop one-click formatting",
|
||||||
|
"一键三连进程输出信息": "One-click formatting output",
|
||||||
|
"1B-微调训练": "1B-Fine-tuned training",
|
||||||
|
"1Ba-SoVITS训练。用于分享的模型文件输出在SoVITS_weights下。": "1Ba-SoVITS training. The model is located in SoVITS_weights.",
|
||||||
|
"每张显卡的batch_size": "Batch size per GPU:",
|
||||||
|
"总训练轮数total_epoch,不建议太高": "Total epochs, do not increase to a value that is too high",
|
||||||
|
"文本模块学习率权重": "Text model learning rate weighting",
|
||||||
|
"保存频率save_every_epoch": "Save frequency (save_every_epoch):",
|
||||||
|
"是否仅保存最新的ckpt文件以节省硬盘空间": "Save only the latest '.ckpt' file to save disk space:",
|
||||||
|
"是否在每次保存时间点将最终小模型保存至weights文件夹": "Save a small final model to the 'weights' folder at each save point:",
|
||||||
|
"开启SoVITS训练": "Start SoVITS training",
|
||||||
|
"终止SoVITS训练": "Stop SoVITS training",
|
||||||
|
"SoVITS训练进程输出信息": "SoVITS training output log",
|
||||||
|
"1Bb-GPT训练。用于分享的模型文件输出在GPT_weights下。": "1Bb-GPT training. The model is located in GPT_weights.",
|
||||||
|
"总训练轮数total_epoch": "Total training epochs (total_epoch):",
|
||||||
|
"开启GPT训练": "Start GPT training",
|
||||||
|
"终止GPT训练": "Stop GPT training",
|
||||||
|
"GPT训练进程输出信息": "GPT training output log",
|
||||||
|
"1C-推理": "1C-inference",
|
||||||
|
"选择训练完存放在SoVITS_weights和GPT_weights下的模型。默认的一个是底模,体验5秒Zero Shot TTS用。": "Choose the models from SoVITS_weights and GPT_weights. The default one is a pretrain, so you can experience zero shot TTS.",
|
||||||
|
"*GPT模型列表": "*GPT models list",
|
||||||
|
"*SoVITS模型列表": "*SoVITS models list",
|
||||||
|
"GPU卡号,只能填1个整数": "GPU number, can only input ONE integer",
|
||||||
|
"刷新模型路径": "refreshing model paths",
|
||||||
|
"是否开启TTS推理WebUI": "Open TTS inference WEBUI",
|
||||||
|
"TTS推理WebUI进程输出信息": "TTS inference webui output log",
|
||||||
|
"2-GPT-SoVITS-变声": "2-GPT-SoVITS-Voice Changer",
|
||||||
|
"施工中,请静候佳音": "In construction, please wait",
|
||||||
|
"TTS推理进程已开启": "TTS inference process is opened",
|
||||||
|
"TTS推理进程已关闭": "TTS inference process closed",
|
||||||
|
"打标工具WebUI已开启": "proofreading tool webui is opened",
|
||||||
|
"打标工具WebUI已关闭": "proofreading tool webui is closed",
|
||||||
|
"本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责. 如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "This software is under MIT licence. The author does not have any control for this software. Users are solely reponsible for all voices thats being converted and/or distributed. If you disagree with this Terms and Conditions, you cannot use or cite any files or code in this file. Please check LICENSE. for more info.",
|
||||||
|
"*请上传并填写参考信息": "*Please upload and fill reference information",
|
||||||
|
"*请填写需要合成的目标文本": "*Please fill the text that needs inference",
|
||||||
|
"ASR任务开启:%s": "ASR training started: %s",
|
||||||
|
"GPT训练完成": "Finished GPT training",
|
||||||
|
"GPT训练开始:%s": "GPT training started: %s",
|
||||||
|
"SSL提取进程执行中": "SSL extracting",
|
||||||
|
"SSL提取进程结束": "SSL extraction finished",
|
||||||
|
"SoVITS训练完成": "SoVITS training finished",
|
||||||
|
"SoVITS训练开始:%s": "SoVITS training started:%s",
|
||||||
|
"一键三连中途报错": "An error has occured during One-click formatting",
|
||||||
|
"一键三连进程结束": "Finished one-click formatting",
|
||||||
|
"中文": "Chinese",
|
||||||
|
"凑50字一切": "Cut per 50 characters",
|
||||||
|
"凑五句一切": "Cut per 5 sentences",
|
||||||
|
"切分后文本": "Text after sliced",
|
||||||
|
"切割执行中": "Slicing audio",
|
||||||
|
"切割结束": "finished audio slicing",
|
||||||
|
"参考音频的文本": "Text for reference audio",
|
||||||
|
"参考音频的语种": "Language for reference audio",
|
||||||
|
"合成语音": "Start inference",
|
||||||
|
"后续将支持混合语种编码文本输入。": "Mixed languages input will be supported soon.",
|
||||||
|
"已有正在进行的ASR任务,需先终止才能开启下一次任务": " An ASR task is already in progress, please stop before starting the next task",
|
||||||
|
"已有正在进行的GPT训练任务,需先终止才能开启下一次任务": "A GPT training task is already in progress, please stop before starting the next task",
|
||||||
|
"已有正在进行的SSL提取任务,需先终止才能开启下一次任务": "A SSL extraction task is already in progress, please stop before starting the next task",
|
||||||
|
"已有正在进行的SoVITS训练任务,需先终止才能开启下一次任务": "A SoVITS training task is already in progress, please stop before starting the next task",
|
||||||
|
"已有正在进行的一键三连任务,需先终止才能开启下一次任务": "An ASR task is already in progress, please stop before starting the next task",
|
||||||
|
"已有正在进行的切割任务,需先终止才能开启下一次任务": "An audio slicing task is already in progress, please stop before starting the next task",
|
||||||
|
"已有正在进行的文本任务,需先终止才能开启下一次任务": "A TTS proofreading task is already in progress, please stop before starting the next task",
|
||||||
|
"已有正在进行的语义token提取任务,需先终止才能开启下一次任务": "A semantics token extraction task is already in progress, please stop before starting the next task",
|
||||||
|
"已终止ASR进程": "ASR task has been stopped",
|
||||||
|
"已终止GPT训练": "GPT training has been stopped",
|
||||||
|
"已终止SoVITS训练": "SoVITS training has been stopped",
|
||||||
|
"已终止所有1a进程": "All 1a tasks has been stopped",
|
||||||
|
"已终止所有1b进程": "All 1b tasks has been stopped",
|
||||||
|
"已终止所有一键三连进程": "All one-clicking formatting tasks has been stopped",
|
||||||
|
"已终止所有切割进程": "All audio slicing tasks has been stopped",
|
||||||
|
"已终止所有语义token进程": "All semantics token tasks has been stopped",
|
||||||
|
"按中文句号。切": "按中文句号。切",
|
||||||
|
"文本切分工具。太长的文本合成出来效果不一定好,所以太长建议先切。合成会根据文本的换行分开合成再拼起来。": "Text slicer tool, since there will be issues when infering long texts, so it is advised to cut first. When infering, it will infer respectively then combined together.",
|
||||||
|
"文本进程执行中": "Text processing",
|
||||||
|
"文本进程结束": "Finished text processing",
|
||||||
|
"日文": "Japanese",
|
||||||
|
"英文": "English",
|
||||||
|
"语义token提取进程执行中": "Semantics token extracting",
|
||||||
|
"语义token提取进程结束": "Finished semantics token extraction",
|
||||||
|
"请上传参考音频": "Please upload reference audio",
|
||||||
|
"输入路径不存在": "No input file or directory",
|
||||||
|
"输入路径存在但既不是文件也不是文件夹": "Input directory exists, but it is not a file or a folder",
|
||||||
|
"输出的语音": "Inference Result",
|
||||||
|
"进度:1a-done": "Progress:1a-done",
|
||||||
|
"进度:1a-done, 1b-ing": "Progress:1a-done, 1b-ing",
|
||||||
|
"进度:1a-ing": "Progress:1a-ing",
|
||||||
|
"进度:1a1b-done": "Progress:1a1b-done",
|
||||||
|
"进度:1a1b-done, 1cing": "Progress:1a1b-done, 1cing",
|
||||||
|
"进度:all-done": "Progress:all-done",
|
||||||
|
"需要合成的切分前文本": "Inference text that needs to be sliced",
|
||||||
|
"需要合成的文本": "Inference text",
|
||||||
|
"需要合成的语种": "Inference text language",
|
||||||
">=3则使用对harvest音高识别的结果使用中值滤波,数值为滤波半径,使用可以削弱哑音": "If >=3: apply median filtering to the harvested pitch results. The value represents the filter radius and can reduce breathiness.",
|
">=3则使用对harvest音高识别的结果使用中值滤波,数值为滤波半径,使用可以削弱哑音": "If >=3: apply median filtering to the harvested pitch results. The value represents the filter radius and can reduce breathiness.",
|
||||||
"A模型权重": "Weight (w) for Model A:",
|
"A模型权重": "Weight (w) for Model A:",
|
||||||
"A模型路径": "Path to Model A:",
|
"A模型路径": "Path to Model A:",
|
||||||
@ -23,7 +173,7 @@
|
|||||||
"step3a:正在训练模型": "Step 3a: Model training started",
|
"step3a:正在训练模型": "Step 3a: Model training started",
|
||||||
"一键训练": "One-click training",
|
"一键训练": "One-click training",
|
||||||
"也可批量输入音频文件, 二选一, 优先读文件夹": "Multiple audio files can also be imported. If a folder path exists, this input is ignored.",
|
"也可批量输入音频文件, 二选一, 优先读文件夹": "Multiple audio files can also be imported. If a folder path exists, this input is ignored.",
|
||||||
"人声伴奏分离批量处理, 使用UVR5模型。 <br>合格的文件夹路径格式举例: E:\\codes\\py39\\vits_vc_gpu\\白鹭霜华测试样例(去文件管理器地址栏拷就行了)。 <br>模型分为三类: <br>1、保留人声:不带和声的音频选这个,对主人声保留比HP5更好。内置HP2和HP3两个模型,HP3可能轻微漏伴奏但对主人声保留比HP2稍微好一丁点; <br>2、仅保留主人声:带和声的音频选这个,对主人声可能有削弱。内置HP5一个模型; <br> 3、去混响、去延迟模型(by FoxJoy):<br> (1)MDX-Net(onnx_dereverb):对于双通道混响是最好的选择,不能去除单通道混响;<br> (234)DeEcho:去除延迟效果。Aggressive比Normal去除得更彻底,DeReverb额外去除混响,可去除单声道混响,但是对高频重的板式混响去不干净。<br>去混响/去延迟,附:<br>1、DeEcho-DeReverb模型的耗时是另外2个DeEcho模型的接近2倍;<br>2、MDX-Net-Dereverb模型挺慢的;<br>3、个人推荐的最干净的配置是先MDX-Net再DeEcho-Aggressive。": "Batch processing for vocal accompaniment separation using the UVR5 model.<br>Example of a valid folder path format: D:\\path\\to\\input\\folder (copy it from the file manager address bar).<br>The model is divided into three categories:<br>1. Preserve vocals: Choose this option for audio without harmonies. It preserves vocals better than HP5. It includes two built-in models: HP2 and HP3. HP3 may slightly leak accompaniment but preserves vocals slightly better than HP2.<br>2. Preserve main vocals only: Choose this option for audio with harmonies. It may weaken the main vocals. It includes one built-in model: HP5.<br>3. De-reverb and de-delay models (by FoxJoy):<br> (1) MDX-Net: The best choice for stereo reverb removal but cannot remove mono reverb;<br> (234) DeEcho: Removes delay effects. Aggressive mode removes more thoroughly than Normal mode. DeReverb additionally removes reverb and can remove mono reverb, but not very effectively for heavily reverberated high-frequency content.<br>De-reverb/de-delay notes:<br>1. The processing time for the DeEcho-DeReverb model is approximately twice as long as the other two DeEcho models.<br>2. The MDX-Net-Dereverb model is quite slow.<br>3. The recommended cleanest configuration is to apply MDX-Net first and then DeEcho-Aggressive.",
|
"人声伴奏分离批量处理, 使用UVR5模型。 <br>合格的文件夹路径格式举例: E:\\codes\\py39\\vits_vc_gpu\\白鹭霜华测试样例(去文件管理器地址栏拷就行了)。 <br>模型分为三类: <br>1、保留人声:不带和声的音频选这个,对主人声保留比HP5更好。内置HP2和HP3两个模型,HP3可能轻微漏伴奏但对主人声保留比HP2稍微好一丁点; <br>2、仅保留主人声:带和声的音频选这个,对主人声可能有削弱。内置HP5一个模型; <br> 3、去混响、去延迟模型(by FoxJoy):<br>\u2003\u2003(1)MDX-Net(onnx_dereverb):对于双通道混响是最好的选择,不能去除单通道混响;<br> (234)DeEcho:去除延迟效果。Aggressive比Normal去除得更彻底,DeReverb额外去除混响,可去除单声道混响,但是对高频重的板式混响去不干净。<br>去混响/去延迟,附:<br>1、DeEcho-DeReverb模型的耗时是另外2个DeEcho模型的接近2倍;<br>2、MDX-Net-Dereverb模型挺慢的;<br>3、个人推荐的最干净的配置是先MDX-Net再DeEcho-Aggressive。": "Batch processing for vocal accompaniment separation using the UVR5 model.<br>Example of a valid folder path format: D:\\path\\to\\input\\folder (copy it from the file manager address bar).<br>The model is divided into three categories:<br>1. Preserve vocals: Choose this option for audio without harmonies. It preserves vocals better than HP5. It includes two built-in models: HP2 and HP3. HP3 may slightly leak accompaniment but preserves vocals slightly better than HP2.<br>2. Preserve main vocals only: Choose this option for audio with harmonies. It may weaken the main vocals. It includes one built-in model: HP5.<br>3. De-reverb and de-delay models (by FoxJoy):<br>\u2003\u2003(1) MDX-Net: The best choice for stereo reverb removal but cannot remove mono reverb;<br> (234) DeEcho: Removes delay effects. Aggressive mode removes more thoroughly than Normal mode. DeReverb additionally removes reverb and can remove mono reverb, but not very effectively for heavily reverberated high-frequency content.<br>De-reverb/de-delay notes:<br>1. The processing time for the DeEcho-DeReverb model is approximately twice as long as the other two DeEcho models.<br>2. The MDX-Net-Dereverb model is quite slow.<br>3. The recommended cleanest configuration is to apply MDX-Net first and then DeEcho-Aggressive.",
|
||||||
"以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "Enter the GPU index(es) separated by '-', e.g., 0-1-2 to use GPU 0, 1, and 2:",
|
"以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "Enter the GPU index(es) separated by '-', e.g., 0-1-2 to use GPU 0, 1, and 2:",
|
||||||
"伴奏人声分离&去混响&去回声": "Vocals/Accompaniment Separation & Reverberation Removal",
|
"伴奏人声分离&去混响&去回声": "Vocals/Accompaniment Separation & Reverberation Removal",
|
||||||
"使用模型采样率": "使用模型采样率",
|
"使用模型采样率": "使用模型采样率",
|
||||||
@ -31,7 +181,6 @@
|
|||||||
"保存名": "Save name:",
|
"保存名": "Save name:",
|
||||||
"保存的文件名, 默认空为和源文件同名": "Save file name (default: same as the source file):",
|
"保存的文件名, 默认空为和源文件同名": "Save file name (default: same as the source file):",
|
||||||
"保存的模型名不带后缀": "Saved model name (without extension):",
|
"保存的模型名不带后缀": "Saved model name (without extension):",
|
||||||
"保存频率save_every_epoch": "Save frequency (save_every_epoch):",
|
|
||||||
"保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "Protect voiceless consonants and breath sounds to prevent artifacts such as tearing in electronic music. Set to 0.5 to disable. Decrease the value to increase protection, but it may reduce indexing accuracy:",
|
"保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "Protect voiceless consonants and breath sounds to prevent artifacts such as tearing in electronic music. Set to 0.5 to disable. Decrease the value to increase protection, but it may reduce indexing accuracy:",
|
||||||
"修改": "Modify",
|
"修改": "Modify",
|
||||||
"修改模型信息(仅支持weights文件夹下提取的小模型文件)": "Modify model information (only supported for small model files extracted from the 'weights' folder)",
|
"修改模型信息(仅支持weights文件夹下提取的小模型文件)": "Modify model information (only supported for small model files extracted from the 'weights' folder)",
|
||||||
@ -55,9 +204,7 @@
|
|||||||
"常见问题解答": "FAQ (Frequently Asked Questions)",
|
"常见问题解答": "FAQ (Frequently Asked Questions)",
|
||||||
"常规设置": "General settings",
|
"常规设置": "General settings",
|
||||||
"开始音频转换": "Start audio conversion",
|
"开始音频转换": "Start audio conversion",
|
||||||
"很遗憾您这没有能用的显卡来支持您训练": "Unfortunately, there is no compatible GPU available to support your training.",
|
|
||||||
"性能设置": "Performance settings",
|
"性能设置": "Performance settings",
|
||||||
"总训练轮数total_epoch": "Total training epochs (total_epoch):",
|
|
||||||
"批量推理": "Batch Inference",
|
"批量推理": "Batch Inference",
|
||||||
"批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "Batch conversion. Enter the folder containing the audio files to be converted or upload multiple audio files. The converted audio will be output in the specified folder (default: 'opt').",
|
"批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "Batch conversion. Enter the folder containing the audio files to be converted or upload multiple audio files. The converted audio will be output in the specified folder (default: 'opt').",
|
||||||
"指定输出主人声文件夹": "Specify the output folder for vocals:",
|
"指定输出主人声文件夹": "Specify the output folder for vocals:",
|
||||||
@ -68,11 +215,7 @@
|
|||||||
"提取": "Extract",
|
"提取": "Extract",
|
||||||
"提取音高和处理数据使用的CPU进程数": "Number of CPU processes used for pitch extraction and data processing:",
|
"提取音高和处理数据使用的CPU进程数": "Number of CPU processes used for pitch extraction and data processing:",
|
||||||
"是": "Yes",
|
"是": "Yes",
|
||||||
"是否仅保存最新的ckpt文件以节省硬盘空间": "Save only the latest '.ckpt' file to save disk space:",
|
|
||||||
"是否在每次保存时间点将最终小模型保存至weights文件夹": "Save a small final model to the 'weights' folder at each save point:",
|
|
||||||
"是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "Cache all training sets to GPU memory. Caching small datasets (less than 10 minutes) can speed up training, but caching large datasets will consume a lot of GPU memory and may not provide much speed improvement:",
|
"是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "Cache all training sets to GPU memory. Caching small datasets (less than 10 minutes) can speed up training, but caching large datasets will consume a lot of GPU memory and may not provide much speed improvement:",
|
||||||
"显卡信息": "GPU Information",
|
|
||||||
"本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责. <br>如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录<b>LICENSE</b>.": "This software is open source under the MIT license. The author does not have any control over the software. Users who use the software and distribute the sounds exported by the software are solely responsible. <br>If you do not agree with this clause, you cannot use or reference any codes and files within the software package. See the root directory <b>Agreement-LICENSE.txt</b> for details.",
|
|
||||||
"查看": "View",
|
"查看": "View",
|
||||||
"查看模型信息(仅支持weights文件夹下提取的小模型文件)": "View model information (only supported for small model files extracted from the 'weights' folder)",
|
"查看模型信息(仅支持weights文件夹下提取的小模型文件)": "View model information (only supported for small model files extracted from the 'weights' folder)",
|
||||||
"检索特征占比": "Search feature ratio (controls accent strength, too high has artifacting):",
|
"检索特征占比": "Search feature ratio (controls accent strength, too high has artifacting):",
|
||||||
@ -85,7 +228,6 @@
|
|||||||
"模型版本型号": "Model architecture version:",
|
"模型版本型号": "Model architecture version:",
|
||||||
"模型融合, 可用于测试音色融合": "Model fusion, can be used to test timbre fusion",
|
"模型融合, 可用于测试音色融合": "Model fusion, can be used to test timbre fusion",
|
||||||
"模型路径": "Path to Model:",
|
"模型路径": "Path to Model:",
|
||||||
"每张显卡的batch_size": "Batch size per GPU:",
|
|
||||||
"淡入淡出长度": "Fade length",
|
"淡入淡出长度": "Fade length",
|
||||||
"版本": "Version",
|
"版本": "Version",
|
||||||
"特征提取": "Feature extraction",
|
"特征提取": "Feature extraction",
|
||||||
|
93
i18n/locale/pt_BR.json
Normal file
93
i18n/locale/pt_BR.json
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
{
|
||||||
|
"很遗憾您这没有能用的显卡来支持您训练": "Infelizmente, você não possui uma placa de vídeo funcional para suportar seu treinamento",
|
||||||
|
"UVR5已开启": "UVR5 está ativado",
|
||||||
|
"UVR5已关闭": "UVR5 está desativado",
|
||||||
|
"本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责. <br>如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录<b>LICENSE</b>.": "Este software é de código aberto sob a licença MIT. O autor não tem controle sobre o software. Aqueles que usam o software e difundem os sons exportados pelo software são totalmente responsáveis. <br>Se você não concorda com esta cláusula, não pode usar ou citar nenhum código e arquivo dentro do pacote de software. Consulte o diretório raiz <b>LICENSE</b> para mais detalhes.<br><br> Traduzido por Rafael Godoy Ebert",
|
||||||
|
"0-前置数据集获取工具": "0- Ferramenta de aquisição de conjunto de dados pré-frontal",
|
||||||
|
"0a-UVR5人声伴奏分离&去混响去延迟工具": "0A-UVR5 separação de voz e acompanhamento instrumental & ferramenta para remover reverberação e atraso",
|
||||||
|
"是否开启UVR5-WebUI": "Se deseja ativar a UVR5-WEBUI",
|
||||||
|
"UVR5进程输出信息": "Informações de saída do processo UVR5",
|
||||||
|
"0b-语音切分工具": "0b- Ferramenta de corte de voz",
|
||||||
|
"音频自动切分输入路径,可文件可文件夹": "Caminho de entrada automático de corte de áudio, pode ser um arquivo ou uma pasta",
|
||||||
|
"切分后的子音频的输出根目录": "Diretório raiz de saída do sub-áudio após o corte",
|
||||||
|
"threshold:音量小于这个值视作静音的备选切割点": "Limiar: O volume menor que este valor é considerado como um ponto de corte mudo alternativo",
|
||||||
|
"min_length:每段最小多长,如果第一段太短一直和后面段连起来直到超过这个值": "min_length: O comprimento mínimo de cada parágrafo, se o primeiro for muito curto, conecte-o continuamente aos próximos até ultrapassar este valor",
|
||||||
|
"min_interval:最短切割间隔": "min_interval: O intervalo de corte mínimo",
|
||||||
|
"hop_size:怎么算音量曲线,越小精度越大计算量越高(不是精度越大效果越好)": "HOP_SIZE: Como calcular a curva de volume, quanto menor a precisão, maior a quantidade de cálculos (não significa que quanto maior a precisão, melhor o efeito)",
|
||||||
|
"max_sil_kept:切完后静音最多留多长": "max_sil_kept: Depois de cortar, por quanto tempo no máximo o silêncio é mantido",
|
||||||
|
"开启语音切割": "Ativar corte de voz",
|
||||||
|
"终止语音切割": "Encerrar corte de voz",
|
||||||
|
"max:归一化后最大值多少": "MAX: Qual é o valor máximo após a normalização?",
|
||||||
|
"alpha_mix:混多少比例归一化后音频进来": "alpha_mix: Em que proporção o áudio normalizado é misturado de volta",
|
||||||
|
"切割使用的进程数": "Número de processos para corte",
|
||||||
|
"语音切割进程输出信息": "Informações de saída do processo de corte de voz",
|
||||||
|
"0c-中文批量离线ASR工具": "0c- Ferramenta chinesa de ASR offline em lote",
|
||||||
|
"开启离线批量ASR": "Ativar ASR offline em lote",
|
||||||
|
"终止ASR进程": "Encerrar processo ASR",
|
||||||
|
"批量ASR(中文only)输入文件夹路径": "Caminho da pasta de entrada para ASR em lote (apenas chinês)",
|
||||||
|
"ASR进程输出信息": "Informações de saída do processo ASR",
|
||||||
|
"0d-语音文本校对标注工具": "0d- Ferramenta de correção e marcação de texto de voz",
|
||||||
|
"是否开启打标WebUI": "Se deseja abrir o webui de marcação",
|
||||||
|
"打标数据标注文件路径": "Caminho do arquivo de marcação de dados de marcação",
|
||||||
|
"打标工具进程输出信息": "Informações de saída do processo da ferramenta de marcação",
|
||||||
|
"1-GPT-SoVITS-TTS": "1-GPT-SOVITS-TTS",
|
||||||
|
"*实验/模型名": "*Nome do experimento/modelo",
|
||||||
|
"显卡信息": "Informações da placa de vídeo",
|
||||||
|
"预训练的SoVITS-G模型路径": "Caminho do modelo SoVITS-G pre-train",
|
||||||
|
"预训练的SoVITS-D模型路径": "Caminho do modelo SoVITS-D pre-train",
|
||||||
|
"预训练的GPT模型路径": "Caminho do modelo GPT pre-train",
|
||||||
|
"1A-训练集格式化工具": "1A-Ferramenta de formatação de conjunto de dados de treinamento",
|
||||||
|
"输出logs/实验名目录下应有23456开头的文件和文件夹": "Logs de saída/deve haver arquivos e pastas começando com 23456 no diretório do nome do experimento",
|
||||||
|
"*文本标注文件": "*Arquivo de marcação de texto",
|
||||||
|
"*训练集音频文件目录": "*Diretório de arquivos de áudio do conjunto de treinamento",
|
||||||
|
"训练集音频文件目录 拼接 list文件里波形对应的文件名。": "Diretório de arquivos de áudio do conjunto de treinamento. Concatene o nome do arquivo correspondente à forma de onda no arquivo de lista",
|
||||||
|
"1Aa-文本内容": "1AA-Conteúdo do texto",
|
||||||
|
"GPU卡号以-分割,每个卡号一个进程": "Número da placa de vídeo dividido por-, cada número de placa é um processo",
|
||||||
|
"预训练的中文BERT模型路径": "Caminho do modelo BERT chinês pre-train",
|
||||||
|
"开启文本获取": "Ativar obtenção de texto",
|
||||||
|
"终止文本获取进程": "Encerrar processo de obtenção de texto",
|
||||||
|
"文本进程输出信息": "Informações de saída do processo de texto",
|
||||||
|
"1Ab-SSL自监督特征提取": "1AB-Extração de características auto-supervisionadas SSL",
|
||||||
|
"预训练的SSL模型路径": "Caminho do modelo SSL pre-train",
|
||||||
|
"开启SSL提取": "Ativar extração SSL",
|
||||||
|
"终止SSL提取进程": "Encerrar processo de extração SSL",
|
||||||
|
"SSL进程输出信息": "Informações de saída do processo SSL",
|
||||||
|
"1Ac-语义token提取": "1AC-Extração de token semântico",
|
||||||
|
"开启语义token提取": "Ativar extração de token semântico",
|
||||||
|
"终止语义token提取进程": "Encerrar processo de extração de token semântico",
|
||||||
|
"语义token提取进程输出信息": "Informações de saída do processo de extração de token semântico",
|
||||||
|
"1Aabc-训练集格式化一键三连": "1AABC-Formatação de conjunto de treinamento em um clique",
|
||||||
|
"开启一键三连": "Ativar um clique",
|
||||||
|
"终止一键三连": "Encerrar um clique",
|
||||||
|
"一键三连进程输出信息": "Informações de saída do processo de um clique",
|
||||||
|
"1B-微调训练": "1B-Treinamento de ajuste fino",
|
||||||
|
"1Ba-SoVITS训练。用于分享的模型文件输出在SoVITS_weights下。": "1ba-Treinamento SoVITS. O arquivo de modelo para compartilhamento é gerado em SOVITS_WEIGHTS",
|
||||||
|
"每张显卡的batch_size": "Tamanho do lote de cada placa de vídeo",
|
||||||
|
"总训练轮数total_epoch,不建议太高": "Total de epoch de treinamento, não é recomendável um valor muito alto",
|
||||||
|
"文本模块学习率权重": "Weight da taxa de aprendizado do módulo de texto",
|
||||||
|
"保存频率save_every_epoch": "Frequência de salvamento save_every_epoch",
|
||||||
|
"是否仅保存最新的ckpt文件以节省硬盘空间": "Se deve salvar apenas o último arquivo CKPT para economizar espaço em disco",
|
||||||
|
"是否在每次保存时间点将最终小模型保存至weights文件夹": "Se deve salvar o modelo pequeno final na pasta Weights em cada ponto de salvamento de tempo",
|
||||||
|
"开启SoVITS训练": "Ativar treinamento SoVITS",
|
||||||
|
"终止SoVITS训练": "Encerrar treinamento SoVITS",
|
||||||
|
"SoVITS训练进程输出信息": "Informações de saída do processo de treinamento SoVITS",
|
||||||
|
"1Bb-GPT训练。用于分享的模型文件输出在GPT_weights下。": "1BB-Treinamento GPT. O arquivo de modelo para compartilhamento é gerado em GPT_WEIGHTS",
|
||||||
|
"总训练轮数total_epoch": "Total de epoch de treinamento",
|
||||||
|
"开启GPT训练": "Ativar treinamento GPT",
|
||||||
|
"终止GPT训练": "Encerrar treinamento GPT",
|
||||||
|
"GPT训练进程输出信息": "Informações de saída do processo de treinamento GPT",
|
||||||
|
"1C-推理": "1C-raciocínio",
|
||||||
|
"选择训练完存放在SoVITS_weights和GPT_weights下的模型。默认的一个是底模,体验5秒Zero Shot TTS用。": "Selecione os modelos armazenados em Sovits_weights e GPT_WEIGHTS. O padrão é o modelo inferior, experiência para 5 segundos de Zero Shot TTS",
|
||||||
|
"*GPT模型列表": "*Lista de modelos GPT",
|
||||||
|
"*SoVITS模型列表": "*Lista de modelos Sovits",
|
||||||
|
"GPU卡号,只能填1个整数": "Número da placa de vídeo, só é possível preencher com um número inteiro",
|
||||||
|
"刷新模型路径": "Atualizar caminho do modelo",
|
||||||
|
"是否开启TTS推理WebUI": "Se deseja ativar o webui de raciocínio TTS",
|
||||||
|
"TTS推理WebUI进程输出信息": "Informações de saída do processo webui de raciocínio TTS",
|
||||||
|
"2-GPT-SoVITS-变声": "2-gpt-sovits-mudança de voz",
|
||||||
|
"施工中,请静候佳音": "Em construção, por favor, aguarde por um bom som",
|
||||||
|
"TTS推理进程已开启": "O processo de inferência TTS foi iniciado",
|
||||||
|
"TTS推理进程已关闭": "O processo de inferência TTS foi desativado",
|
||||||
|
"打标工具WebUI已开启": "A ferramenta de marcação WebUI está ativada",
|
||||||
|
"打标工具WebUI已关闭": "A ferramenta de marcação WebUI foi desativado"
|
||||||
|
}
|
@ -19,3 +19,4 @@ sentencepiece
|
|||||||
transformers
|
transformers
|
||||||
chardet
|
chardet
|
||||||
PyYAML
|
PyYAML
|
||||||
|
psutil
|
||||||
|
@ -30,17 +30,19 @@ inference_pipeline = pipeline(
|
|||||||
punc_model='tools/damo_asr/models/punc_ct-transformer_zh-cn-common-vocab272727-pytorch',
|
punc_model='tools/damo_asr/models/punc_ct-transformer_zh-cn-common-vocab272727-pytorch',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def process_audio_file(dir,filename,name,opt_name):
|
def process_audio_file(dir,filename,name,opt_name):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
text = inference_pipeline(audio_in="%s/%s" % (dir, name))["text"]
|
text = inference_pipeline(audio_in="%s/%s" % (dir, name))["text"]
|
||||||
|
|
||||||
with lock:
|
with lock:
|
||||||
with open(filename,"a",encoding="utf-8")as f:f.write("%s/%s|%s|ZH|%s\n" % (dir, name, opt_name, text))
|
with open(filename,"a",encoding="utf-8")as f:f.write("%s/%s|%s|ZH|%s\n" % (dir, name, opt_name, text.strip()))
|
||||||
|
|
||||||
except:
|
except:
|
||||||
print(traceback.format_exc())
|
print(traceback.format_exc())
|
||||||
|
|
||||||
|
|
||||||
def run__process(): # 主进程
|
def run__process(): # 主进程
|
||||||
|
|
||||||
opt_dir="output/asr_opt"
|
opt_dir="output/asr_opt"
|
||||||
@ -52,6 +54,8 @@ def run__process(): # 主进程
|
|||||||
with multiprocessing.Pool(processes=processes) as pool:
|
with multiprocessing.Pool(processes=processes) as pool:
|
||||||
pool.starmap(process_audio_file, [(dir,filename,name ,opt_name) for name in os.listdir(dir)])
|
pool.starmap(process_audio_file, [(dir,filename,name ,opt_name) for name in os.listdir(dir)])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
run__process()
|
run__process()
|
||||||
|
|
||||||
|
2
tools/damo_asr/models/.gitignore
vendored
Normal file
2
tools/damo_asr/models/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
@ -79,6 +79,7 @@ def b_change_index(index, batch):
|
|||||||
|
|
||||||
|
|
||||||
def b_next_index(index, batch):
|
def b_next_index(index, batch):
|
||||||
|
b_save_file()
|
||||||
if (index + batch) <= g_max_json_index:
|
if (index + batch) <= g_max_json_index:
|
||||||
return index + batch , *b_change_index(index + batch, batch)
|
return index + batch , *b_change_index(index + batch, batch)
|
||||||
else:
|
else:
|
||||||
@ -86,6 +87,7 @@ def b_next_index(index, batch):
|
|||||||
|
|
||||||
|
|
||||||
def b_previous_index(index, batch):
|
def b_previous_index(index, batch):
|
||||||
|
b_save_file()
|
||||||
if (index - batch) >= 0:
|
if (index - batch) >= 0:
|
||||||
return index - batch , *b_change_index(index - batch, batch)
|
return index - batch , *b_change_index(index - batch, batch)
|
||||||
else:
|
else:
|
||||||
@ -294,6 +296,7 @@ def set_global(load_json, load_list, json_key_text, json_key_path, batch):
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description='Process some integers.')
|
parser = argparse.ArgumentParser(description='Process some integers.')
|
||||||
parser.add_argument('--load_json', default="None", help='source file, like demo.json')
|
parser.add_argument('--load_json', default="None", help='source file, like demo.json')
|
||||||
|
parser.add_argument('--is_share', default="False", help='whether webui is_share=True')
|
||||||
parser.add_argument('--load_list', default="None", help='source file, like demo.list')
|
parser.add_argument('--load_list', default="None", help='source file, like demo.list')
|
||||||
parser.add_argument('--webui_port_subfix', default=9871, help='source file, like demo.list')
|
parser.add_argument('--webui_port_subfix', default=9871, help='source file, like demo.list')
|
||||||
parser.add_argument('--json_key_text', default="text", help='the text key name in json, Default: text')
|
parser.add_argument('--json_key_text', default="text", help='the text key name in json, Default: text')
|
||||||
@ -488,5 +491,6 @@ if __name__ == "__main__":
|
|||||||
server_name="0.0.0.0",
|
server_name="0.0.0.0",
|
||||||
inbrowser=True,
|
inbrowser=True,
|
||||||
quiet=True,
|
quiet=True,
|
||||||
|
share=eval(args.is_share),
|
||||||
server_port=int(args.webui_port_subfix)
|
server_port=int(args.webui_port_subfix)
|
||||||
)
|
)
|
@ -24,7 +24,7 @@ def make_padding(width, cropsize, offset):
|
|||||||
|
|
||||||
def inference(X_spec, device, model, aggressiveness, data):
|
def inference(X_spec, device, model, aggressiveness, data):
|
||||||
"""
|
"""
|
||||||
data : dic configs
|
data : dic configs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _execute(
|
def _execute(
|
||||||
|
@ -19,7 +19,8 @@ for name in os.listdir(weight_uvr5_root):
|
|||||||
|
|
||||||
device=sys.argv[1]
|
device=sys.argv[1]
|
||||||
is_half=sys.argv[2]
|
is_half=sys.argv[2]
|
||||||
|
webui_port_uvr5=int(sys.argv[3])
|
||||||
|
is_share=eval(sys.argv[4])
|
||||||
|
|
||||||
def uvr(model_name, inp_root, save_root_vocal, paths, save_root_ins, agg, format0):
|
def uvr(model_name, inp_root, save_root_vocal, paths, save_root_ins, agg, format0):
|
||||||
infos = []
|
infos = []
|
||||||
@ -179,6 +180,7 @@ with gr.Blocks(title="RVC WebUI") as app:
|
|||||||
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",
|
||||||
inbrowser=True,
|
inbrowser=True,
|
||||||
server_port=9873,
|
share=is_share,
|
||||||
|
server_port=webui_port_uvr5,
|
||||||
quiet=True,
|
quiet=True,
|
||||||
)
|
)
|
Loading…
x
Reference in New Issue
Block a user