diff --git a/GPT_SoVITS/TTS_infer_pack/TTS.py b/GPT_SoVITS/TTS_infer_pack/TTS.py index a1eeb28c..809601b3 100644 --- a/GPT_SoVITS/TTS_infer_pack/TTS.py +++ b/GPT_SoVITS/TTS_infer_pack/TTS.py @@ -1,60 +1,66 @@ from copy import deepcopy import math import os, sys, gc -import random -import traceback -from tqdm import tqdm + now_dir = os.getcwd() sys.path.append(now_dir) import ffmpeg -import os -from typing import Generator, List, Tuple, Union +import librosa import numpy as np +import random import torch import torch.nn.functional as F +import traceback import yaml -from transformers import AutoModelForMaskedLM, AutoTokenizer + +from huggingface_hub import snapshot_download, hf_hub_download +from importlib.resources import files +from time import time as ttime +from typing import Generator, List, Tuple, Union +from tqdm import tqdm + from AR.models.t2s_lightning_module import Text2SemanticLightningModule from feature_extractor.cnhubert import CNHubert from module.models import SynthesizerTrn -import librosa -from time import time as ttime +from module.mel_processing import spectrogram_torch from tools.i18n.i18n import I18nAuto, scan_language_list from tools.my_utils import load_audio -from module.mel_processing import spectrogram_torch +from transformers import AutoModelForMaskedLM, AutoTokenizer from TTS_infer_pack.text_segmentation_method import splits from TTS_infer_pack.TextPreprocessor import TextPreprocessor + language=os.environ.get("language","Auto") language=sys.argv[-1] if sys.argv[-1] in scan_language_list() else language i18n = I18nAuto(language=language) +LIBRARY_NAME = "GPT_SoVITS" # configs/tts_infer.yaml """ custom: - bert_base_path: GPT_SoVITS/pretrained_models/chinese-roberta-wwm-ext-large - cnhuhbert_base_path: GPT_SoVITS/pretrained_models/chinese-hubert-base + bert_base_path: pretrained_models/chinese-roberta-wwm-ext-large + cnhuhbert_base_path: pretrained_models/chinese-hubert-base device: cpu is_half: false - t2s_weights_path: GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s1bert25hz-5kh-longer-epoch=12-step=369668.ckpt - vits_weights_path: GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s2G2333k.pth + t2s_weights_path: pretrained_models/gsv-v2final-pretrained/s1bert25hz-5kh-longer-epoch=12-step=369668.ckpt + vits_weights_path: pretrained_models/gsv-v2final-pretrained/s2G2333k.pth version: v2 default: - bert_base_path: GPT_SoVITS/pretrained_models/chinese-roberta-wwm-ext-large - cnhuhbert_base_path: GPT_SoVITS/pretrained_models/chinese-hubert-base + bert_base_path: pretrained_models/chinese-roberta-wwm-ext-large + cnhuhbert_base_path: pretrained_models/chinese-hubert-base device: cpu is_half: false - t2s_weights_path: GPT_SoVITS/pretrained_models/s1bert25hz-2kh-longer-epoch=68e-step=50232.ckpt - vits_weights_path: GPT_SoVITS/pretrained_models/s2G488k.pth + t2s_weights_path: pretrained_models/s1bert25hz-2kh-longer-epoch=68e-step=50232.ckpt + vits_weights_path: pretrained_models/s2G488k.pth version: v1 default_v2: - bert_base_path: GPT_SoVITS/pretrained_models/chinese-roberta-wwm-ext-large - cnhuhbert_base_path: GPT_SoVITS/pretrained_models/chinese-hubert-base + bert_base_path: pretrained_models/chinese-roberta-wwm-ext-large + cnhuhbert_base_path: pretrained_models/chinese-hubert-base device: cpu is_half: false - t2s_weights_path: GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s1bert25hz-5kh-longer-epoch=12-step=369668.ckpt - vits_weights_path: GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s2G2333k.pth + t2s_weights_path: pretrained_models/gsv-v2final-pretrained/s1bert25hz-5kh-longer-epoch=12-step=369668.ckpt + vits_weights_path: pretrained_models/gsv-v2final-pretrained/s2G2333k.pth version: v2 """ @@ -86,19 +92,19 @@ class TTS_Config: "device": "cpu", "is_half": False, "version": "v1", - "t2s_weights_path": "GPT_SoVITS/pretrained_models/s1bert25hz-2kh-longer-epoch=68e-step=50232.ckpt", - "vits_weights_path": "GPT_SoVITS/pretrained_models/s2G488k.pth", - "cnhuhbert_base_path": "GPT_SoVITS/pretrained_models/chinese-hubert-base", - "bert_base_path": "GPT_SoVITS/pretrained_models/chinese-roberta-wwm-ext-large", + "t2s_weights_path": "pretrained_models/s1bert25hz-2kh-longer-epoch=68e-step=50232.ckpt", + "vits_weights_path": "pretrained_models/s2G488k.pth", + "cnhuhbert_base_path": "pretrained_models/chinese-hubert-base", + "bert_base_path": "pretrained_models/chinese-roberta-wwm-ext-large", }, "default_v2":{ "device": "cpu", "is_half": False, "version": "v2", - "t2s_weights_path": "GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s1bert25hz-5kh-longer-epoch=12-step=369668.ckpt", - "vits_weights_path": "GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s2G2333k.pth", - "cnhuhbert_base_path": "GPT_SoVITS/pretrained_models/chinese-hubert-base", - "bert_base_path": "GPT_SoVITS/pretrained_models/chinese-roberta-wwm-ext-large", + "t2s_weights_path": "pretrained_models/gsv-v2final-pretrained/s1bert25hz-5kh-longer-epoch=12-step=369668.ckpt", + "vits_weights_path": "pretrained_models/gsv-v2final-pretrained/s2G2333k.pth", + "cnhuhbert_base_path": "pretrained_models/chinese-hubert-base", + "bert_base_path": "pretrained_models/chinese-roberta-wwm-ext-large", }, } configs:dict = None @@ -120,7 +126,7 @@ class TTS_Config: def __init__(self, configs: Union[dict, str]=None): # 设置默认配置文件路径 - configs_base_path:str = "GPT_SoVITS/configs/" + configs_base_path:str = "configs/" os.makedirs(configs_base_path, exist_ok=True) self.configs_path:str = os.path.join(configs_base_path, "tts_infer.yaml") @@ -152,23 +158,24 @@ class TTS_Config: self.bert_base_path = self.configs.get("bert_base_path", None) self.cnhuhbert_base_path = self.configs.get("cnhuhbert_base_path", None) self.languages = self.v2_languages if self.version=="v2" else self.v1_languages - if (self.t2s_weights_path in [None, ""]) or (not os.path.exists(self.t2s_weights_path)): - self.t2s_weights_path = self.default_configs[default_config_key]['t2s_weights_path'] + self.t2s_weights_path = str(files(LIBRARY_NAME).joinpath(self.default_configs[default_config_key]['t2s_weights_path'])) print(f"fall back to default t2s_weights_path: {self.t2s_weights_path}") if (self.vits_weights_path in [None, ""]) or (not os.path.exists(self.vits_weights_path)): - self.vits_weights_path = self.default_configs[default_config_key]['vits_weights_path'] + self.vits_weights_path = str(files(LIBRARY_NAME).joinpath(self.default_configs[default_config_key]['vits_weights_path'])) print(f"fall back to default vits_weights_path: {self.vits_weights_path}") if (self.bert_base_path in [None, ""]) or (not os.path.exists(self.bert_base_path)): - self.bert_base_path = self.default_configs[default_config_key]['bert_base_path'] + self.bert_base_path = str(files(LIBRARY_NAME).joinpath(self.default_configs[default_config_key]['bert_base_path'])) print(f"fall back to default bert_base_path: {self.bert_base_path}") if (self.cnhuhbert_base_path in [None, ""]) or (not os.path.exists(self.cnhuhbert_base_path)): - self.cnhuhbert_base_path = self.default_configs[default_config_key]['cnhuhbert_base_path'] + self.cnhuhbert_base_path = str(files(LIBRARY_NAME).joinpath(self.default_configs[default_config_key]['cnhuhbert_base_path'])) print(f"fall back to default cnhuhbert_base_path: {self.cnhuhbert_base_path}") + + repo_name="lj1995/GPT-SoVITS" + snapshot_download(repo_id=repo_name, local_dir=os.path.dirname(self.bert_base_path)) self.update_configs() - self.max_sec = None self.hz:int = 50 self.semantic_frame_rate:str = "25hz" diff --git a/api_v2.py b/GPT_SoVITS/api_v2.py similarity index 98% rename from api_v2.py rename to GPT_SoVITS/api_v2.py index 92a18f37..5dfbebec 100644 --- a/api_v2.py +++ b/GPT_SoVITS/api_v2.py @@ -114,6 +114,8 @@ from fastapi import FastAPI, Request, HTTPException, Response from fastapi.responses import StreamingResponse, JSONResponse from fastapi import FastAPI, UploadFile, File import uvicorn + +from importlib.resources import files from io import BytesIO from tools.i18n.i18n import I18nAuto from GPT_SoVITS.TTS_infer_pack.TTS import TTS, TTS_Config @@ -125,7 +127,7 @@ i18n = I18nAuto() cut_method_names = get_cut_method_names() parser = argparse.ArgumentParser(description="GPT-SoVITS api") -parser.add_argument("-c", "--tts_config", type=str, default="GPT_SoVITS/configs/tts_infer.yaml", help="tts_infer路径") +parser.add_argument("-c", "--tts_config", type=str, default=None, help="tts_infer路径") parser.add_argument("-a", "--bind_addr", type=str, default="127.0.0.1", help="default: 127.0.0.1") parser.add_argument("-p", "--port", type=int, default="9880", help="default: 9880") args = parser.parse_args() @@ -136,7 +138,7 @@ host = args.bind_addr argv = sys.argv if config_path in [None, ""]: - config_path = "GPT-SoVITS/configs/tts_infer.yaml" + config_path = str(files("GPT_SoVITS").joinpath("configs/tts_infer.yaml")) tts_config = TTS_Config(config_path) print(tts_config) @@ -394,7 +396,7 @@ async def tts_get_endpoint( @APP.post("/tts") async def tts_post_endpoint(request: TTS_Request): - req = request.dict() + req = request.model_dump() return await tts_handle(req) @@ -449,7 +451,8 @@ async def set_sovits_weights(weights_path: str = None): -if __name__ == "__main__": +def main(): + global port, host, argv try: if host == 'None': # 在调用时使用 -a None 参数,可以让api监听双栈 host = None @@ -458,3 +461,6 @@ if __name__ == "__main__": traceback.print_exc() os.kill(os.getpid(), signal.SIGTERM) exit(0) + +if __name__ == "__main__": + main() diff --git a/GPT_SoVITS/configs/tts_infer.yaml b/GPT_SoVITS/configs/tts_infer.yaml index 66f1193d..fe63fa2a 100644 --- a/GPT_SoVITS/configs/tts_infer.yaml +++ b/GPT_SoVITS/configs/tts_infer.yaml @@ -1,24 +1,24 @@ custom: - bert_base_path: GPT_SoVITS/pretrained_models/chinese-roberta-wwm-ext-large - cnhuhbert_base_path: GPT_SoVITS/pretrained_models/chinese-hubert-base + bert_base_path: pretrained_models/chinese-roberta-wwm-ext-large + cnhuhbert_base_path: pretrained_models/chinese-hubert-base device: cuda is_half: true - t2s_weights_path: GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s1bert25hz-5kh-longer-epoch=12-step=369668.ckpt + t2s_weights_path: pretrained_models/gsv-v2final-pretrained/s1bert25hz-5kh-longer-epoch=12-step=369668.ckpt version: v2 - vits_weights_path: GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s2G2333k.pth + vits_weights_path: pretrained_models/gsv-v2final-pretrained/s2G2333k.pth default: - bert_base_path: GPT_SoVITS/pretrained_models/chinese-roberta-wwm-ext-large - cnhuhbert_base_path: GPT_SoVITS/pretrained_models/chinese-hubert-base + bert_base_path: pretrained_models/chinese-roberta-wwm-ext-large + cnhuhbert_base_path: pretrained_models/chinese-hubert-base device: cpu is_half: false - t2s_weights_path: GPT_SoVITS/pretrained_models/s1bert25hz-2kh-longer-epoch=68e-step=50232.ckpt + t2s_weights_path: pretrained_models/s1bert25hz-2kh-longer-epoch=68e-step=50232.ckpt version: v1 - vits_weights_path: GPT_SoVITS/pretrained_models/s2G488k.pth + vits_weights_path: pretrained_models/s2G488k.pth default_v2: - bert_base_path: GPT_SoVITS/pretrained_models/chinese-roberta-wwm-ext-large - cnhuhbert_base_path: GPT_SoVITS/pretrained_models/chinese-hubert-base + bert_base_path: pretrained_models/chinese-roberta-wwm-ext-large + cnhuhbert_base_path: pretrained_models/chinese-hubert-base device: cpu is_half: false - t2s_weights_path: GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s1bert25hz-5kh-longer-epoch=12-step=369668.ckpt + t2s_weights_path: pretrained_models/gsv-v2final-pretrained/s1bert25hz-5kh-longer-epoch=12-step=369668.ckpt version: v2 - vits_weights_path: GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/s2G2333k.pth + vits_weights_path: pretrained_models/gsv-v2final-pretrained/s2G2333k.pth diff --git a/tools/__init__.py b/GPT_SoVITS/tools/__init__.py similarity index 100% rename from tools/__init__.py rename to GPT_SoVITS/tools/__init__.py diff --git a/tools/asr/config.py b/GPT_SoVITS/tools/asr/config.py similarity index 100% rename from tools/asr/config.py rename to GPT_SoVITS/tools/asr/config.py diff --git a/tools/asr/fasterwhisper_asr.py b/GPT_SoVITS/tools/asr/fasterwhisper_asr.py similarity index 100% rename from tools/asr/fasterwhisper_asr.py rename to GPT_SoVITS/tools/asr/fasterwhisper_asr.py diff --git a/tools/asr/funasr_asr.py b/GPT_SoVITS/tools/asr/funasr_asr.py similarity index 100% rename from tools/asr/funasr_asr.py rename to GPT_SoVITS/tools/asr/funasr_asr.py diff --git a/tools/asr/models/.gitignore b/GPT_SoVITS/tools/asr/models/.gitignore similarity index 100% rename from tools/asr/models/.gitignore rename to GPT_SoVITS/tools/asr/models/.gitignore diff --git a/tools/cmd-denoise.py b/GPT_SoVITS/tools/cmd-denoise.py similarity index 97% rename from tools/cmd-denoise.py rename to GPT_SoVITS/tools/cmd-denoise.py index 1fdcab6d..29128966 100644 --- a/tools/cmd-denoise.py +++ b/GPT_SoVITS/tools/cmd-denoise.py @@ -1,33 +1,33 @@ -import os,argparse -import traceback - -from modelscope.pipelines import pipeline -from modelscope.utils.constant import Tasks -from tqdm import tqdm - -path_denoise = 'tools/denoise-model/speech_frcrn_ans_cirm_16k' -path_denoise = path_denoise if os.path.exists(path_denoise) else "damo/speech_frcrn_ans_cirm_16k" -ans = pipeline(Tasks.acoustic_noise_suppression,model=path_denoise) -def execute_denoise(input_folder,output_folder): - os.makedirs(output_folder,exist_ok=True) - # print(input_folder) - # print(list(os.listdir(input_folder).sort())) - for name in tqdm(os.listdir(input_folder)): - try: - ans("%s/%s"%(input_folder,name),output_path='%s/%s'%(output_folder,name)) - except: - traceback.print_exc() - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("-i", "--input_folder", type=str, required=True, - help="Path to the folder containing WAV files.") - parser.add_argument("-o", "--output_folder", type=str, required=True, - help="Output folder to store transcriptions.") - parser.add_argument("-p", "--precision", type=str, default='float16', choices=['float16','float32'], - help="fp16 or fp32")#还没接入 - cmd = parser.parse_args() - execute_denoise( - input_folder = cmd.input_folder, - output_folder = cmd.output_folder, +import os,argparse +import traceback + +from modelscope.pipelines import pipeline +from modelscope.utils.constant import Tasks +from tqdm import tqdm + +path_denoise = 'tools/denoise-model/speech_frcrn_ans_cirm_16k' +path_denoise = path_denoise if os.path.exists(path_denoise) else "damo/speech_frcrn_ans_cirm_16k" +ans = pipeline(Tasks.acoustic_noise_suppression,model=path_denoise) +def execute_denoise(input_folder,output_folder): + os.makedirs(output_folder,exist_ok=True) + # print(input_folder) + # print(list(os.listdir(input_folder).sort())) + for name in tqdm(os.listdir(input_folder)): + try: + ans("%s/%s"%(input_folder,name),output_path='%s/%s'%(output_folder,name)) + except: + traceback.print_exc() + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("-i", "--input_folder", type=str, required=True, + help="Path to the folder containing WAV files.") + parser.add_argument("-o", "--output_folder", type=str, required=True, + help="Output folder to store transcriptions.") + parser.add_argument("-p", "--precision", type=str, default='float16', choices=['float16','float32'], + help="fp16 or fp32")#还没接入 + cmd = parser.parse_args() + execute_denoise( + input_folder = cmd.input_folder, + output_folder = cmd.output_folder, ) \ No newline at end of file diff --git a/tools/denoise-model/.gitignore b/GPT_SoVITS/tools/denoise-model/.gitignore similarity index 100% rename from tools/denoise-model/.gitignore rename to GPT_SoVITS/tools/denoise-model/.gitignore diff --git a/tools/i18n/i18n.py b/GPT_SoVITS/tools/i18n/i18n.py similarity index 100% rename from tools/i18n/i18n.py rename to GPT_SoVITS/tools/i18n/i18n.py diff --git a/tools/i18n/locale/en_US.json b/GPT_SoVITS/tools/i18n/locale/en_US.json similarity index 100% rename from tools/i18n/locale/en_US.json rename to GPT_SoVITS/tools/i18n/locale/en_US.json diff --git a/tools/i18n/locale/es_ES.json b/GPT_SoVITS/tools/i18n/locale/es_ES.json similarity index 100% rename from tools/i18n/locale/es_ES.json rename to GPT_SoVITS/tools/i18n/locale/es_ES.json diff --git a/tools/i18n/locale/fr_FR.json b/GPT_SoVITS/tools/i18n/locale/fr_FR.json similarity index 100% rename from tools/i18n/locale/fr_FR.json rename to GPT_SoVITS/tools/i18n/locale/fr_FR.json diff --git a/tools/i18n/locale/it_IT.json b/GPT_SoVITS/tools/i18n/locale/it_IT.json similarity index 100% rename from tools/i18n/locale/it_IT.json rename to GPT_SoVITS/tools/i18n/locale/it_IT.json diff --git a/tools/i18n/locale/ja_JP.json b/GPT_SoVITS/tools/i18n/locale/ja_JP.json similarity index 100% rename from tools/i18n/locale/ja_JP.json rename to GPT_SoVITS/tools/i18n/locale/ja_JP.json diff --git a/tools/i18n/locale/ko_KR.json b/GPT_SoVITS/tools/i18n/locale/ko_KR.json similarity index 100% rename from tools/i18n/locale/ko_KR.json rename to GPT_SoVITS/tools/i18n/locale/ko_KR.json diff --git a/tools/i18n/locale/pt_BR.json b/GPT_SoVITS/tools/i18n/locale/pt_BR.json similarity index 100% rename from tools/i18n/locale/pt_BR.json rename to GPT_SoVITS/tools/i18n/locale/pt_BR.json diff --git a/tools/i18n/locale/ru_RU.json b/GPT_SoVITS/tools/i18n/locale/ru_RU.json similarity index 100% rename from tools/i18n/locale/ru_RU.json rename to GPT_SoVITS/tools/i18n/locale/ru_RU.json diff --git a/tools/i18n/locale/tr_TR.json b/GPT_SoVITS/tools/i18n/locale/tr_TR.json similarity index 100% rename from tools/i18n/locale/tr_TR.json rename to GPT_SoVITS/tools/i18n/locale/tr_TR.json diff --git a/tools/i18n/locale/zh_CN.json b/GPT_SoVITS/tools/i18n/locale/zh_CN.json similarity index 100% rename from tools/i18n/locale/zh_CN.json rename to GPT_SoVITS/tools/i18n/locale/zh_CN.json diff --git a/tools/i18n/locale/zh_HK.json b/GPT_SoVITS/tools/i18n/locale/zh_HK.json similarity index 100% rename from tools/i18n/locale/zh_HK.json rename to GPT_SoVITS/tools/i18n/locale/zh_HK.json diff --git a/tools/i18n/locale/zh_SG.json b/GPT_SoVITS/tools/i18n/locale/zh_SG.json similarity index 100% rename from tools/i18n/locale/zh_SG.json rename to GPT_SoVITS/tools/i18n/locale/zh_SG.json diff --git a/tools/i18n/locale/zh_TW.json b/GPT_SoVITS/tools/i18n/locale/zh_TW.json similarity index 100% rename from tools/i18n/locale/zh_TW.json rename to GPT_SoVITS/tools/i18n/locale/zh_TW.json diff --git a/tools/i18n/scan_i18n.py b/GPT_SoVITS/tools/i18n/scan_i18n.py similarity index 100% rename from tools/i18n/scan_i18n.py rename to GPT_SoVITS/tools/i18n/scan_i18n.py diff --git a/tools/my_utils.py b/GPT_SoVITS/tools/my_utils.py similarity index 97% rename from tools/my_utils.py rename to GPT_SoVITS/tools/my_utils.py index cdb95e0b..c1469234 100644 --- a/tools/my_utils.py +++ b/GPT_SoVITS/tools/my_utils.py @@ -1,115 +1,115 @@ -import platform,os,traceback -import ffmpeg -import numpy as np -import gradio as gr -from tools.i18n.i18n import I18nAuto -import pandas as pd -i18n = I18nAuto(language=os.environ.get('language','Auto')) - -def load_audio(file, sr): - try: - # https://github.com/openai/whisper/blob/main/whisper/audio.py#L26 - # This launches a subprocess to decode audio while down-mixing and resampling as necessary. - # Requires the ffmpeg CLI and `ffmpeg-python` package to be installed. - file = clean_path(file) # 防止小白拷路径头尾带了空格和"和回车 - if os.path.exists(file) == False: - raise RuntimeError( - "You input a wrong audio path that does not exists, please fix it!" - ) - out, _ = ( - ffmpeg.input(file, threads=0) - .output("-", format="f32le", acodec="pcm_f32le", ac=1, ar=sr) - .run(cmd=["ffmpeg", "-nostdin"], capture_stdout=True, capture_stderr=True) - ) - except Exception as e: - traceback.print_exc() - raise RuntimeError(i18n("音频加载失败")) - - return np.frombuffer(out, np.float32).flatten() - - -def clean_path(path_str:str): - if path_str.endswith(('\\','/')): - return clean_path(path_str[0:-1]) - path_str = path_str.replace('/', os.sep).replace('\\', os.sep) - return path_str.strip(" ").strip('\'').strip("\n").strip('"').strip(" ").strip("\u202a") - - -def check_for_existance(file_list:list=None,is_train=False,is_dataset_processing=False): - files_status=[] - if is_train == True and file_list: - file_list.append(os.path.join(file_list[0],'2-name2text.txt')) - file_list.append(os.path.join(file_list[0],'3-bert')) - file_list.append(os.path.join(file_list[0],'4-cnhubert')) - file_list.append(os.path.join(file_list[0],'5-wav32k')) - file_list.append(os.path.join(file_list[0],'6-name2semantic.tsv')) - for file in file_list: - if os.path.exists(file):files_status.append(True) - else:files_status.append(False) - if sum(files_status)!=len(files_status): - if is_train: - for file,status in zip(file_list,files_status): - if status:pass - else:gr.Warning(file) - gr.Warning(i18n('以下文件或文件夹不存在')) - return False - elif is_dataset_processing: - if files_status[0]: - return True - elif not files_status[0]: - gr.Warning(file_list[0]) - elif not files_status[1] and file_list[1]: - gr.Warning(file_list[1]) - gr.Warning(i18n('以下文件或文件夹不存在')) - return False - else: - if file_list[0]: - gr.Warning(file_list[0]) - gr.Warning(i18n('以下文件或文件夹不存在')) - else: - gr.Warning(i18n('路径不能为空')) - return False - return True - -def check_details(path_list=None,is_train=False,is_dataset_processing=False): - if is_dataset_processing: - list_path, audio_path = path_list - if (not list_path.endswith('.list')): - gr.Warning(i18n('请填入正确的List路径')) - return - if audio_path: - if not os.path.isdir(audio_path): - gr.Warning(i18n('请填入正确的音频文件夹路径')) - return - with open(list_path,"r",encoding="utf8")as f: - line=f.readline().strip("\n").split("\n") - wav_name, _, __, ___ = line[0].split("|") - wav_name=clean_path(wav_name) - if (audio_path != "" and audio_path != None): - wav_name = os.path.basename(wav_name) - wav_path = "%s/%s"%(audio_path, wav_name) - else: - wav_path=wav_name - if os.path.exists(wav_path): - ... - else: - gr.Warning(i18n('路径错误')) - return - if is_train: - path_list.append(os.path.join(path_list[0],'2-name2text.txt')) - path_list.append(os.path.join(path_list[0],'4-cnhubert')) - path_list.append(os.path.join(path_list[0],'5-wav32k')) - path_list.append(os.path.join(path_list[0],'6-name2semantic.tsv')) - phone_path, hubert_path, wav_path, semantic_path = path_list[1:] - with open(phone_path,'r',encoding='utf-8') as f: - if f.read(1):... - else:gr.Warning(i18n('缺少音素数据集')) - if os.listdir(hubert_path):... - else:gr.Warning(i18n('缺少Hubert数据集')) - if os.listdir(wav_path):... - else:gr.Warning(i18n('缺少音频数据集')) - df = pd.read_csv( - semantic_path, delimiter="\t", encoding="utf-8" - ) - if len(df) >= 1:... - else:gr.Warning(i18n('缺少语义数据集')) +import platform,os,traceback +import ffmpeg +import numpy as np +import gradio as gr +from tools.i18n.i18n import I18nAuto +import pandas as pd +i18n = I18nAuto(language=os.environ.get('language','Auto')) + +def load_audio(file, sr): + try: + # https://github.com/openai/whisper/blob/main/whisper/audio.py#L26 + # This launches a subprocess to decode audio while down-mixing and resampling as necessary. + # Requires the ffmpeg CLI and `ffmpeg-python` package to be installed. + file = clean_path(file) # 防止小白拷路径头尾带了空格和"和回车 + if os.path.exists(file) == False: + raise RuntimeError( + "You input a wrong audio path that does not exists, please fix it!" + ) + out, _ = ( + ffmpeg.input(file, threads=0) + .output("-", format="f32le", acodec="pcm_f32le", ac=1, ar=sr) + .run(cmd=["ffmpeg", "-nostdin"], capture_stdout=True, capture_stderr=True) + ) + except Exception as e: + traceback.print_exc() + raise RuntimeError(i18n("音频加载失败")) + + return np.frombuffer(out, np.float32).flatten() + + +def clean_path(path_str:str): + if path_str.endswith(('\\','/')): + return clean_path(path_str[0:-1]) + path_str = path_str.replace('/', os.sep).replace('\\', os.sep) + return path_str.strip(" ").strip('\'').strip("\n").strip('"').strip(" ").strip("\u202a") + + +def check_for_existance(file_list:list=None,is_train=False,is_dataset_processing=False): + files_status=[] + if is_train == True and file_list: + file_list.append(os.path.join(file_list[0],'2-name2text.txt')) + file_list.append(os.path.join(file_list[0],'3-bert')) + file_list.append(os.path.join(file_list[0],'4-cnhubert')) + file_list.append(os.path.join(file_list[0],'5-wav32k')) + file_list.append(os.path.join(file_list[0],'6-name2semantic.tsv')) + for file in file_list: + if os.path.exists(file):files_status.append(True) + else:files_status.append(False) + if sum(files_status)!=len(files_status): + if is_train: + for file,status in zip(file_list,files_status): + if status:pass + else:gr.Warning(file) + gr.Warning(i18n('以下文件或文件夹不存在')) + return False + elif is_dataset_processing: + if files_status[0]: + return True + elif not files_status[0]: + gr.Warning(file_list[0]) + elif not files_status[1] and file_list[1]: + gr.Warning(file_list[1]) + gr.Warning(i18n('以下文件或文件夹不存在')) + return False + else: + if file_list[0]: + gr.Warning(file_list[0]) + gr.Warning(i18n('以下文件或文件夹不存在')) + else: + gr.Warning(i18n('路径不能为空')) + return False + return True + +def check_details(path_list=None,is_train=False,is_dataset_processing=False): + if is_dataset_processing: + list_path, audio_path = path_list + if (not list_path.endswith('.list')): + gr.Warning(i18n('请填入正确的List路径')) + return + if audio_path: + if not os.path.isdir(audio_path): + gr.Warning(i18n('请填入正确的音频文件夹路径')) + return + with open(list_path,"r",encoding="utf8")as f: + line=f.readline().strip("\n").split("\n") + wav_name, _, __, ___ = line[0].split("|") + wav_name=clean_path(wav_name) + if (audio_path != "" and audio_path != None): + wav_name = os.path.basename(wav_name) + wav_path = "%s/%s"%(audio_path, wav_name) + else: + wav_path=wav_name + if os.path.exists(wav_path): + ... + else: + gr.Warning(i18n('路径错误')) + return + if is_train: + path_list.append(os.path.join(path_list[0],'2-name2text.txt')) + path_list.append(os.path.join(path_list[0],'4-cnhubert')) + path_list.append(os.path.join(path_list[0],'5-wav32k')) + path_list.append(os.path.join(path_list[0],'6-name2semantic.tsv')) + phone_path, hubert_path, wav_path, semantic_path = path_list[1:] + with open(phone_path,'r',encoding='utf-8') as f: + if f.read(1):... + else:gr.Warning(i18n('缺少音素数据集')) + if os.listdir(hubert_path):... + else:gr.Warning(i18n('缺少Hubert数据集')) + if os.listdir(wav_path):... + else:gr.Warning(i18n('缺少音频数据集')) + df = pd.read_csv( + semantic_path, delimiter="\t", encoding="utf-8" + ) + if len(df) >= 1:... + else:gr.Warning(i18n('缺少语义数据集')) diff --git a/tools/slice_audio.py b/GPT_SoVITS/tools/slice_audio.py similarity index 97% rename from tools/slice_audio.py rename to GPT_SoVITS/tools/slice_audio.py index 8a06292d..b9912ae0 100644 --- a/tools/slice_audio.py +++ b/GPT_SoVITS/tools/slice_audio.py @@ -1,48 +1,48 @@ -import os,sys,numpy as np -import traceback -from scipy.io import wavfile -# parent_directory = os.path.dirname(os.path.abspath(__file__)) -# sys.path.append(parent_directory) -from tools.my_utils import load_audio -from slicer2 import Slicer - -def slice(inp,opt_root,threshold,min_length,min_interval,hop_size,max_sil_kept,_max,alpha,i_part,all_part): - os.makedirs(opt_root,exist_ok=True) - if os.path.isfile(inp): - input=[inp] - elif os.path.isdir(inp): - input=[os.path.join(inp, name) for name in sorted(list(os.listdir(inp)))] - else: - return "输入路径存在但既不是文件也不是文件夹" - slicer = Slicer( - sr=32000, # 长音频采样率 - threshold= int(threshold), # 音量小于这个值视作静音的备选切割点 - min_length= int(min_length), # 每段最小多长,如果第一段太短一直和后面段连起来直到超过这个值 - min_interval= int(min_interval), # 最短切割间隔 - hop_size= int(hop_size), # 怎么算音量曲线,越小精度越大计算量越高(不是精度越大效果越好) - max_sil_kept= int(max_sil_kept), # 切完后静音最多留多长 - ) - _max=float(_max) - alpha=float(alpha) - for inp_path in input[int(i_part)::int(all_part)]: - # print(inp_path) - try: - name = os.path.basename(inp_path) - audio = load_audio(inp_path, 32000) - # print(audio.shape) - for chunk, start, end in slicer.slice(audio): # start和end是帧数 - tmp_max = np.abs(chunk).max() - if(tmp_max>1):chunk/=tmp_max - chunk = (chunk / tmp_max * (_max * alpha)) + (1 - alpha) * chunk - wavfile.write( - "%s/%s_%010d_%010d.wav" % (opt_root, name, start, end), - 32000, - # chunk.astype(np.float32), - (chunk * 32767).astype(np.int16), - ) - except: - print(inp_path,"->fail->",traceback.format_exc()) - return "执行完毕,请检查输出文件" - -print(slice(*sys.argv[1:])) - +import os,sys,numpy as np +import traceback +from scipy.io import wavfile +# parent_directory = os.path.dirname(os.path.abspath(__file__)) +# sys.path.append(parent_directory) +from tools.my_utils import load_audio +from slicer2 import Slicer + +def slice(inp,opt_root,threshold,min_length,min_interval,hop_size,max_sil_kept,_max,alpha,i_part,all_part): + os.makedirs(opt_root,exist_ok=True) + if os.path.isfile(inp): + input=[inp] + elif os.path.isdir(inp): + input=[os.path.join(inp, name) for name in sorted(list(os.listdir(inp)))] + else: + return "输入路径存在但既不是文件也不是文件夹" + slicer = Slicer( + sr=32000, # 长音频采样率 + threshold= int(threshold), # 音量小于这个值视作静音的备选切割点 + min_length= int(min_length), # 每段最小多长,如果第一段太短一直和后面段连起来直到超过这个值 + min_interval= int(min_interval), # 最短切割间隔 + hop_size= int(hop_size), # 怎么算音量曲线,越小精度越大计算量越高(不是精度越大效果越好) + max_sil_kept= int(max_sil_kept), # 切完后静音最多留多长 + ) + _max=float(_max) + alpha=float(alpha) + for inp_path in input[int(i_part)::int(all_part)]: + # print(inp_path) + try: + name = os.path.basename(inp_path) + audio = load_audio(inp_path, 32000) + # print(audio.shape) + for chunk, start, end in slicer.slice(audio): # start和end是帧数 + tmp_max = np.abs(chunk).max() + if(tmp_max>1):chunk/=tmp_max + chunk = (chunk / tmp_max * (_max * alpha)) + (1 - alpha) * chunk + wavfile.write( + "%s/%s_%010d_%010d.wav" % (opt_root, name, start, end), + 32000, + # chunk.astype(np.float32), + (chunk * 32767).astype(np.int16), + ) + except: + print(inp_path,"->fail->",traceback.format_exc()) + return "执行完毕,请检查输出文件" + +print(slice(*sys.argv[1:])) + diff --git a/tools/slicer2.py b/GPT_SoVITS/tools/slicer2.py similarity index 97% rename from tools/slicer2.py rename to GPT_SoVITS/tools/slicer2.py index ba6794b6..176781af 100644 --- a/tools/slicer2.py +++ b/GPT_SoVITS/tools/slicer2.py @@ -1,261 +1,261 @@ -import numpy as np - - -# This function is obtained from librosa. -def get_rms( - y, - frame_length=2048, - hop_length=512, - pad_mode="constant", -): - padding = (int(frame_length // 2), int(frame_length // 2)) - y = np.pad(y, padding, mode=pad_mode) - - axis = -1 - # put our new within-frame axis at the end for now - out_strides = y.strides + tuple([y.strides[axis]]) - # Reduce the shape on the framing axis - x_shape_trimmed = list(y.shape) - x_shape_trimmed[axis] -= frame_length - 1 - out_shape = tuple(x_shape_trimmed) + tuple([frame_length]) - xw = np.lib.stride_tricks.as_strided(y, shape=out_shape, strides=out_strides) - if axis < 0: - target_axis = axis - 1 - else: - target_axis = axis + 1 - xw = np.moveaxis(xw, -1, target_axis) - # Downsample along the target axis - slices = [slice(None)] * xw.ndim - slices[axis] = slice(0, None, hop_length) - x = xw[tuple(slices)] - - # Calculate power - power = np.mean(np.abs(x) ** 2, axis=-2, keepdims=True) - - return np.sqrt(power) - - -class Slicer: - def __init__( - self, - sr: int, - threshold: float = -40.0, - min_length: int = 5000, - min_interval: int = 300, - hop_size: int = 20, - max_sil_kept: int = 5000, - ): - if not min_length >= min_interval >= hop_size: - raise ValueError( - "The following condition must be satisfied: min_length >= min_interval >= hop_size" - ) - if not max_sil_kept >= hop_size: - raise ValueError( - "The following condition must be satisfied: max_sil_kept >= hop_size" - ) - min_interval = sr * min_interval / 1000 - self.threshold = 10 ** (threshold / 20.0) - self.hop_size = round(sr * hop_size / 1000) - self.win_size = min(round(min_interval), 4 * self.hop_size) - self.min_length = round(sr * min_length / 1000 / self.hop_size) - self.min_interval = round(min_interval / self.hop_size) - self.max_sil_kept = round(sr * max_sil_kept / 1000 / self.hop_size) - - def _apply_slice(self, waveform, begin, end): - if len(waveform.shape) > 1: - return waveform[ - :, begin * self.hop_size : min(waveform.shape[1], end * self.hop_size) - ] - else: - return waveform[ - begin * self.hop_size : min(waveform.shape[0], end * self.hop_size) - ] - - # @timeit - def slice(self, waveform): - if len(waveform.shape) > 1: - samples = waveform.mean(axis=0) - else: - samples = waveform - if samples.shape[0] <= self.min_length: - return [waveform] - rms_list = get_rms( - y=samples, frame_length=self.win_size, hop_length=self.hop_size - ).squeeze(0) - sil_tags = [] - silence_start = None - clip_start = 0 - for i, rms in enumerate(rms_list): - # Keep looping while frame is silent. - if rms < self.threshold: - # Record start of silent frames. - if silence_start is None: - silence_start = i - continue - # Keep looping while frame is not silent and silence start has not been recorded. - if silence_start is None: - continue - # Clear recorded silence start if interval is not enough or clip is too short - is_leading_silence = silence_start == 0 and i > self.max_sil_kept - need_slice_middle = ( - i - silence_start >= self.min_interval - and i - clip_start >= self.min_length - ) - if not is_leading_silence and not need_slice_middle: - silence_start = None - continue - # Need slicing. Record the range of silent frames to be removed. - if i - silence_start <= self.max_sil_kept: - pos = rms_list[silence_start : i + 1].argmin() + silence_start - if silence_start == 0: - sil_tags.append((0, pos)) - else: - sil_tags.append((pos, pos)) - clip_start = pos - elif i - silence_start <= self.max_sil_kept * 2: - pos = rms_list[ - i - self.max_sil_kept : silence_start + self.max_sil_kept + 1 - ].argmin() - pos += i - self.max_sil_kept - pos_l = ( - rms_list[ - silence_start : silence_start + self.max_sil_kept + 1 - ].argmin() - + silence_start - ) - pos_r = ( - rms_list[i - self.max_sil_kept : i + 1].argmin() - + i - - self.max_sil_kept - ) - if silence_start == 0: - sil_tags.append((0, pos_r)) - clip_start = pos_r - else: - sil_tags.append((min(pos_l, pos), max(pos_r, pos))) - clip_start = max(pos_r, pos) - else: - pos_l = ( - rms_list[ - silence_start : silence_start + self.max_sil_kept + 1 - ].argmin() - + silence_start - ) - pos_r = ( - rms_list[i - self.max_sil_kept : i + 1].argmin() - + i - - self.max_sil_kept - ) - if silence_start == 0: - sil_tags.append((0, pos_r)) - else: - sil_tags.append((pos_l, pos_r)) - clip_start = pos_r - silence_start = None - # Deal with trailing silence. - total_frames = rms_list.shape[0] - if ( - silence_start is not None - and total_frames - silence_start >= self.min_interval - ): - silence_end = min(total_frames, silence_start + self.max_sil_kept) - pos = rms_list[silence_start : silence_end + 1].argmin() + silence_start - sil_tags.append((pos, total_frames + 1)) - # Apply and return slices. - ####音频+起始时间+终止时间 - if len(sil_tags) == 0: - return [[waveform,0,int(total_frames*self.hop_size)]] - else: - chunks = [] - if sil_tags[0][0] > 0: - chunks.append([self._apply_slice(waveform, 0, sil_tags[0][0]),0,int(sil_tags[0][0]*self.hop_size)]) - for i in range(len(sil_tags) - 1): - chunks.append( - [self._apply_slice(waveform, sil_tags[i][1], sil_tags[i + 1][0]),int(sil_tags[i][1]*self.hop_size),int(sil_tags[i + 1][0]*self.hop_size)] - ) - if sil_tags[-1][1] < total_frames: - chunks.append( - [self._apply_slice(waveform, sil_tags[-1][1], total_frames),int(sil_tags[-1][1]*self.hop_size),int(total_frames*self.hop_size)] - ) - return chunks - - -def main(): - import os.path - from argparse import ArgumentParser - - import librosa - import soundfile - - parser = ArgumentParser() - parser.add_argument("audio", type=str, help="The audio to be sliced") - parser.add_argument( - "--out", type=str, help="Output directory of the sliced audio clips" - ) - parser.add_argument( - "--db_thresh", - type=float, - required=False, - default=-40, - help="The dB threshold for silence detection", - ) - parser.add_argument( - "--min_length", - type=int, - required=False, - default=5000, - help="The minimum milliseconds required for each sliced audio clip", - ) - parser.add_argument( - "--min_interval", - type=int, - required=False, - default=300, - help="The minimum milliseconds for a silence part to be sliced", - ) - parser.add_argument( - "--hop_size", - type=int, - required=False, - default=10, - help="Frame length in milliseconds", - ) - parser.add_argument( - "--max_sil_kept", - type=int, - required=False, - default=500, - help="The maximum silence length kept around the sliced clip, presented in milliseconds", - ) - args = parser.parse_args() - out = args.out - if out is None: - out = os.path.dirname(os.path.abspath(args.audio)) - audio, sr = librosa.load(args.audio, sr=None, mono=False) - slicer = Slicer( - sr=sr, - threshold=args.db_thresh, - min_length=args.min_length, - min_interval=args.min_interval, - hop_size=args.hop_size, - max_sil_kept=args.max_sil_kept, - ) - chunks = slicer.slice(audio) - if not os.path.exists(out): - os.makedirs(out) - for i, chunk in enumerate(chunks): - if len(chunk.shape) > 1: - chunk = chunk.T - soundfile.write( - os.path.join( - out, - f"%s_%d.wav" - % (os.path.basename(args.audio).rsplit(".", maxsplit=1)[0], i), - ), - chunk, - sr, - ) - - -if __name__ == "__main__": - main() +import numpy as np + + +# This function is obtained from librosa. +def get_rms( + y, + frame_length=2048, + hop_length=512, + pad_mode="constant", +): + padding = (int(frame_length // 2), int(frame_length // 2)) + y = np.pad(y, padding, mode=pad_mode) + + axis = -1 + # put our new within-frame axis at the end for now + out_strides = y.strides + tuple([y.strides[axis]]) + # Reduce the shape on the framing axis + x_shape_trimmed = list(y.shape) + x_shape_trimmed[axis] -= frame_length - 1 + out_shape = tuple(x_shape_trimmed) + tuple([frame_length]) + xw = np.lib.stride_tricks.as_strided(y, shape=out_shape, strides=out_strides) + if axis < 0: + target_axis = axis - 1 + else: + target_axis = axis + 1 + xw = np.moveaxis(xw, -1, target_axis) + # Downsample along the target axis + slices = [slice(None)] * xw.ndim + slices[axis] = slice(0, None, hop_length) + x = xw[tuple(slices)] + + # Calculate power + power = np.mean(np.abs(x) ** 2, axis=-2, keepdims=True) + + return np.sqrt(power) + + +class Slicer: + def __init__( + self, + sr: int, + threshold: float = -40.0, + min_length: int = 5000, + min_interval: int = 300, + hop_size: int = 20, + max_sil_kept: int = 5000, + ): + if not min_length >= min_interval >= hop_size: + raise ValueError( + "The following condition must be satisfied: min_length >= min_interval >= hop_size" + ) + if not max_sil_kept >= hop_size: + raise ValueError( + "The following condition must be satisfied: max_sil_kept >= hop_size" + ) + min_interval = sr * min_interval / 1000 + self.threshold = 10 ** (threshold / 20.0) + self.hop_size = round(sr * hop_size / 1000) + self.win_size = min(round(min_interval), 4 * self.hop_size) + self.min_length = round(sr * min_length / 1000 / self.hop_size) + self.min_interval = round(min_interval / self.hop_size) + self.max_sil_kept = round(sr * max_sil_kept / 1000 / self.hop_size) + + def _apply_slice(self, waveform, begin, end): + if len(waveform.shape) > 1: + return waveform[ + :, begin * self.hop_size : min(waveform.shape[1], end * self.hop_size) + ] + else: + return waveform[ + begin * self.hop_size : min(waveform.shape[0], end * self.hop_size) + ] + + # @timeit + def slice(self, waveform): + if len(waveform.shape) > 1: + samples = waveform.mean(axis=0) + else: + samples = waveform + if samples.shape[0] <= self.min_length: + return [waveform] + rms_list = get_rms( + y=samples, frame_length=self.win_size, hop_length=self.hop_size + ).squeeze(0) + sil_tags = [] + silence_start = None + clip_start = 0 + for i, rms in enumerate(rms_list): + # Keep looping while frame is silent. + if rms < self.threshold: + # Record start of silent frames. + if silence_start is None: + silence_start = i + continue + # Keep looping while frame is not silent and silence start has not been recorded. + if silence_start is None: + continue + # Clear recorded silence start if interval is not enough or clip is too short + is_leading_silence = silence_start == 0 and i > self.max_sil_kept + need_slice_middle = ( + i - silence_start >= self.min_interval + and i - clip_start >= self.min_length + ) + if not is_leading_silence and not need_slice_middle: + silence_start = None + continue + # Need slicing. Record the range of silent frames to be removed. + if i - silence_start <= self.max_sil_kept: + pos = rms_list[silence_start : i + 1].argmin() + silence_start + if silence_start == 0: + sil_tags.append((0, pos)) + else: + sil_tags.append((pos, pos)) + clip_start = pos + elif i - silence_start <= self.max_sil_kept * 2: + pos = rms_list[ + i - self.max_sil_kept : silence_start + self.max_sil_kept + 1 + ].argmin() + pos += i - self.max_sil_kept + pos_l = ( + rms_list[ + silence_start : silence_start + self.max_sil_kept + 1 + ].argmin() + + silence_start + ) + pos_r = ( + rms_list[i - self.max_sil_kept : i + 1].argmin() + + i + - self.max_sil_kept + ) + if silence_start == 0: + sil_tags.append((0, pos_r)) + clip_start = pos_r + else: + sil_tags.append((min(pos_l, pos), max(pos_r, pos))) + clip_start = max(pos_r, pos) + else: + pos_l = ( + rms_list[ + silence_start : silence_start + self.max_sil_kept + 1 + ].argmin() + + silence_start + ) + pos_r = ( + rms_list[i - self.max_sil_kept : i + 1].argmin() + + i + - self.max_sil_kept + ) + if silence_start == 0: + sil_tags.append((0, pos_r)) + else: + sil_tags.append((pos_l, pos_r)) + clip_start = pos_r + silence_start = None + # Deal with trailing silence. + total_frames = rms_list.shape[0] + if ( + silence_start is not None + and total_frames - silence_start >= self.min_interval + ): + silence_end = min(total_frames, silence_start + self.max_sil_kept) + pos = rms_list[silence_start : silence_end + 1].argmin() + silence_start + sil_tags.append((pos, total_frames + 1)) + # Apply and return slices. + ####音频+起始时间+终止时间 + if len(sil_tags) == 0: + return [[waveform,0,int(total_frames*self.hop_size)]] + else: + chunks = [] + if sil_tags[0][0] > 0: + chunks.append([self._apply_slice(waveform, 0, sil_tags[0][0]),0,int(sil_tags[0][0]*self.hop_size)]) + for i in range(len(sil_tags) - 1): + chunks.append( + [self._apply_slice(waveform, sil_tags[i][1], sil_tags[i + 1][0]),int(sil_tags[i][1]*self.hop_size),int(sil_tags[i + 1][0]*self.hop_size)] + ) + if sil_tags[-1][1] < total_frames: + chunks.append( + [self._apply_slice(waveform, sil_tags[-1][1], total_frames),int(sil_tags[-1][1]*self.hop_size),int(total_frames*self.hop_size)] + ) + return chunks + + +def main(): + import os.path + from argparse import ArgumentParser + + import librosa + import soundfile + + parser = ArgumentParser() + parser.add_argument("audio", type=str, help="The audio to be sliced") + parser.add_argument( + "--out", type=str, help="Output directory of the sliced audio clips" + ) + parser.add_argument( + "--db_thresh", + type=float, + required=False, + default=-40, + help="The dB threshold for silence detection", + ) + parser.add_argument( + "--min_length", + type=int, + required=False, + default=5000, + help="The minimum milliseconds required for each sliced audio clip", + ) + parser.add_argument( + "--min_interval", + type=int, + required=False, + default=300, + help="The minimum milliseconds for a silence part to be sliced", + ) + parser.add_argument( + "--hop_size", + type=int, + required=False, + default=10, + help="Frame length in milliseconds", + ) + parser.add_argument( + "--max_sil_kept", + type=int, + required=False, + default=500, + help="The maximum silence length kept around the sliced clip, presented in milliseconds", + ) + args = parser.parse_args() + out = args.out + if out is None: + out = os.path.dirname(os.path.abspath(args.audio)) + audio, sr = librosa.load(args.audio, sr=None, mono=False) + slicer = Slicer( + sr=sr, + threshold=args.db_thresh, + min_length=args.min_length, + min_interval=args.min_interval, + hop_size=args.hop_size, + max_sil_kept=args.max_sil_kept, + ) + chunks = slicer.slice(audio) + if not os.path.exists(out): + os.makedirs(out) + for i, chunk in enumerate(chunks): + if len(chunk.shape) > 1: + chunk = chunk.T + soundfile.write( + os.path.join( + out, + f"%s_%d.wav" + % (os.path.basename(args.audio).rsplit(".", maxsplit=1)[0], i), + ), + chunk, + sr, + ) + + +if __name__ == "__main__": + main() diff --git a/tools/subfix_webui.py b/GPT_SoVITS/tools/subfix_webui.py similarity index 100% rename from tools/subfix_webui.py rename to GPT_SoVITS/tools/subfix_webui.py diff --git a/tools/uvr5/bs_roformer/__init__.py b/GPT_SoVITS/tools/uvr5/bs_roformer/__init__.py similarity index 100% rename from tools/uvr5/bs_roformer/__init__.py rename to GPT_SoVITS/tools/uvr5/bs_roformer/__init__.py diff --git a/tools/uvr5/bs_roformer/attend.py b/GPT_SoVITS/tools/uvr5/bs_roformer/attend.py similarity index 100% rename from tools/uvr5/bs_roformer/attend.py rename to GPT_SoVITS/tools/uvr5/bs_roformer/attend.py diff --git a/tools/uvr5/bs_roformer/bs_roformer.py b/GPT_SoVITS/tools/uvr5/bs_roformer/bs_roformer.py similarity index 100% rename from tools/uvr5/bs_roformer/bs_roformer.py rename to GPT_SoVITS/tools/uvr5/bs_roformer/bs_roformer.py diff --git a/tools/uvr5/bsroformer.py b/GPT_SoVITS/tools/uvr5/bsroformer.py similarity index 100% rename from tools/uvr5/bsroformer.py rename to GPT_SoVITS/tools/uvr5/bsroformer.py diff --git a/tools/uvr5/lib/lib_v5/dataset.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/dataset.py similarity index 100% rename from tools/uvr5/lib/lib_v5/dataset.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/dataset.py diff --git a/tools/uvr5/lib/lib_v5/layers.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/layers.py similarity index 100% rename from tools/uvr5/lib/lib_v5/layers.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/layers.py diff --git a/tools/uvr5/lib/lib_v5/layers_123812KB.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/layers_123812KB.py similarity index 100% rename from tools/uvr5/lib/lib_v5/layers_123812KB.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/layers_123812KB.py diff --git a/tools/uvr5/lib/lib_v5/layers_123821KB.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/layers_123821KB.py similarity index 100% rename from tools/uvr5/lib/lib_v5/layers_123821KB.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/layers_123821KB.py diff --git a/tools/uvr5/lib/lib_v5/layers_33966KB.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/layers_33966KB.py similarity index 100% rename from tools/uvr5/lib/lib_v5/layers_33966KB.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/layers_33966KB.py diff --git a/tools/uvr5/lib/lib_v5/layers_537227KB.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/layers_537227KB.py similarity index 100% rename from tools/uvr5/lib/lib_v5/layers_537227KB.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/layers_537227KB.py diff --git a/tools/uvr5/lib/lib_v5/layers_537238KB.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/layers_537238KB.py similarity index 100% rename from tools/uvr5/lib/lib_v5/layers_537238KB.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/layers_537238KB.py diff --git a/tools/uvr5/lib/lib_v5/layers_new.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/layers_new.py similarity index 100% rename from tools/uvr5/lib/lib_v5/layers_new.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/layers_new.py diff --git a/tools/uvr5/lib/lib_v5/model_param_init.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/model_param_init.py similarity index 100% rename from tools/uvr5/lib/lib_v5/model_param_init.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/model_param_init.py diff --git a/tools/uvr5/lib/lib_v5/modelparams/1band_sr16000_hl512.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr16000_hl512.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/1band_sr16000_hl512.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr16000_hl512.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/1band_sr32000_hl512.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr32000_hl512.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/1band_sr32000_hl512.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr32000_hl512.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/1band_sr33075_hl384.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr33075_hl384.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/1band_sr33075_hl384.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr33075_hl384.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl1024.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl1024.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl1024.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl1024.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl256.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl256.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl256.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl256.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl512.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl512.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl512.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl512.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl512_cut.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl512_cut.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl512_cut.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/1band_sr44100_hl512_cut.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/2band_32000.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/2band_32000.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/2band_32000.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/2band_32000.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/2band_44100_lofi.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/2band_44100_lofi.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/2band_44100_lofi.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/2band_44100_lofi.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/2band_48000.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/2band_48000.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/2band_48000.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/2band_48000.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/3band_44100.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/3band_44100.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/3band_44100.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/3band_44100.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/3band_44100_mid.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/3band_44100_mid.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/3band_44100_mid.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/3band_44100_mid.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/3band_44100_msb2.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/3band_44100_msb2.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/3band_44100_msb2.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/3band_44100_msb2.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/4band_44100.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_44100.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/4band_44100.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_44100.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/4band_44100_mid.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_44100_mid.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/4band_44100_mid.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_44100_mid.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/4band_44100_msb.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_44100_msb.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/4band_44100_msb.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_44100_msb.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/4band_44100_msb2.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_44100_msb2.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/4band_44100_msb2.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_44100_msb2.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/4band_44100_reverse.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_44100_reverse.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/4band_44100_reverse.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_44100_reverse.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/4band_44100_sw.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_44100_sw.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/4band_44100_sw.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_44100_sw.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/4band_v2.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_v2.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/4band_v2.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_v2.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/4band_v2_sn.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_v2_sn.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/4band_v2_sn.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_v2_sn.json diff --git a/tools/uvr5/lib/lib_v5/modelparams/4band_v3.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_v3.json similarity index 94% rename from tools/uvr5/lib/lib_v5/modelparams/4band_v3.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_v3.json index 2a73bc97..edb908b8 100644 --- a/tools/uvr5/lib/lib_v5/modelparams/4band_v3.json +++ b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/4band_v3.json @@ -1,54 +1,54 @@ -{ - "bins": 672, - "unstable_bins": 8, - "reduction_bins": 530, - "band": { - "1": { - "sr": 7350, - "hl": 80, - "n_fft": 640, - "crop_start": 0, - "crop_stop": 85, - "lpf_start": 25, - "lpf_stop": 53, - "res_type": "polyphase" - }, - "2": { - "sr": 7350, - "hl": 80, - "n_fft": 320, - "crop_start": 4, - "crop_stop": 87, - "hpf_start": 25, - "hpf_stop": 12, - "lpf_start": 31, - "lpf_stop": 62, - "res_type": "polyphase" - }, - "3": { - "sr": 14700, - "hl": 160, - "n_fft": 512, - "crop_start": 17, - "crop_stop": 216, - "hpf_start": 48, - "hpf_stop": 24, - "lpf_start": 139, - "lpf_stop": 210, - "res_type": "polyphase" - }, - "4": { - "sr": 44100, - "hl": 480, - "n_fft": 960, - "crop_start": 78, - "crop_stop": 383, - "hpf_start": 130, - "hpf_stop": 86, - "res_type": "kaiser_fast" - } - }, - "sr": 44100, - "pre_filter_start": 668, - "pre_filter_stop": 672 +{ + "bins": 672, + "unstable_bins": 8, + "reduction_bins": 530, + "band": { + "1": { + "sr": 7350, + "hl": 80, + "n_fft": 640, + "crop_start": 0, + "crop_stop": 85, + "lpf_start": 25, + "lpf_stop": 53, + "res_type": "polyphase" + }, + "2": { + "sr": 7350, + "hl": 80, + "n_fft": 320, + "crop_start": 4, + "crop_stop": 87, + "hpf_start": 25, + "hpf_stop": 12, + "lpf_start": 31, + "lpf_stop": 62, + "res_type": "polyphase" + }, + "3": { + "sr": 14700, + "hl": 160, + "n_fft": 512, + "crop_start": 17, + "crop_stop": 216, + "hpf_start": 48, + "hpf_stop": 24, + "lpf_start": 139, + "lpf_stop": 210, + "res_type": "polyphase" + }, + "4": { + "sr": 44100, + "hl": 480, + "n_fft": 960, + "crop_start": 78, + "crop_stop": 383, + "hpf_start": 130, + "hpf_stop": 86, + "res_type": "kaiser_fast" + } + }, + "sr": 44100, + "pre_filter_start": 668, + "pre_filter_stop": 672 } \ No newline at end of file diff --git a/tools/uvr5/lib/lib_v5/modelparams/ensemble.json b/GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/ensemble.json similarity index 100% rename from tools/uvr5/lib/lib_v5/modelparams/ensemble.json rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/modelparams/ensemble.json diff --git a/tools/uvr5/lib/lib_v5/nets.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/nets.py similarity index 100% rename from tools/uvr5/lib/lib_v5/nets.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/nets.py diff --git a/tools/uvr5/lib/lib_v5/nets_123812KB.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_123812KB.py similarity index 100% rename from tools/uvr5/lib/lib_v5/nets_123812KB.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_123812KB.py diff --git a/tools/uvr5/lib/lib_v5/nets_123821KB.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_123821KB.py similarity index 100% rename from tools/uvr5/lib/lib_v5/nets_123821KB.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_123821KB.py diff --git a/tools/uvr5/lib/lib_v5/nets_33966KB.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_33966KB.py similarity index 100% rename from tools/uvr5/lib/lib_v5/nets_33966KB.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_33966KB.py diff --git a/tools/uvr5/lib/lib_v5/nets_537227KB.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_537227KB.py similarity index 100% rename from tools/uvr5/lib/lib_v5/nets_537227KB.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_537227KB.py diff --git a/tools/uvr5/lib/lib_v5/nets_537238KB.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_537238KB.py similarity index 100% rename from tools/uvr5/lib/lib_v5/nets_537238KB.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_537238KB.py diff --git a/tools/uvr5/lib/lib_v5/nets_61968KB.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_61968KB.py similarity index 100% rename from tools/uvr5/lib/lib_v5/nets_61968KB.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_61968KB.py diff --git a/tools/uvr5/lib/lib_v5/nets_new.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_new.py similarity index 100% rename from tools/uvr5/lib/lib_v5/nets_new.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/nets_new.py diff --git a/tools/uvr5/lib/lib_v5/spec_utils.py b/GPT_SoVITS/tools/uvr5/lib/lib_v5/spec_utils.py similarity index 100% rename from tools/uvr5/lib/lib_v5/spec_utils.py rename to GPT_SoVITS/tools/uvr5/lib/lib_v5/spec_utils.py diff --git a/tools/uvr5/lib/name_params.json b/GPT_SoVITS/tools/uvr5/lib/name_params.json similarity index 100% rename from tools/uvr5/lib/name_params.json rename to GPT_SoVITS/tools/uvr5/lib/name_params.json diff --git a/tools/uvr5/lib/utils.py b/GPT_SoVITS/tools/uvr5/lib/utils.py similarity index 100% rename from tools/uvr5/lib/utils.py rename to GPT_SoVITS/tools/uvr5/lib/utils.py diff --git a/tools/uvr5/mdxnet.py b/GPT_SoVITS/tools/uvr5/mdxnet.py similarity index 100% rename from tools/uvr5/mdxnet.py rename to GPT_SoVITS/tools/uvr5/mdxnet.py diff --git a/tools/uvr5/uvr5_weights/.gitignore b/GPT_SoVITS/tools/uvr5/uvr5_weights/.gitignore similarity index 100% rename from tools/uvr5/uvr5_weights/.gitignore rename to GPT_SoVITS/tools/uvr5/uvr5_weights/.gitignore diff --git a/tools/uvr5/vr.py b/GPT_SoVITS/tools/uvr5/vr.py similarity index 100% rename from tools/uvr5/vr.py rename to GPT_SoVITS/tools/uvr5/vr.py diff --git a/tools/uvr5/webui.py b/GPT_SoVITS/tools/uvr5/webui.py similarity index 100% rename from tools/uvr5/webui.py rename to GPT_SoVITS/tools/uvr5/webui.py diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..084bdb35 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include GPT_SoVITS/configs/* \ No newline at end of file diff --git a/README.md b/README.md index 1fa36a79..f6fe3d77 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +# Jarod's NOTE +Working on turning this into a package. Right now, the API *does in fact* work to make requests to and this can be installed. Will get instrucitons out sometime in the future. +
diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..2ee1d234 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,63 @@ +[build-system] +requires = ["setuptools >= 61.0", "setuptools-scm>=8.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "GPT_SoVITS" +dynamic = ["version"] +description = "" +readme = "README.md" +license = {text = "MIT License"} +classifiers = [ + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", +] +dependencies = [ + "numpy==1.26.4", + "scipy", + "tensorboard", + "librosa==0.9.2", + "numba", + "pytorch-lightning", + "gradio>=4.0,<=4.24.0", + "ffmpeg-python", + "onnxruntime; sys_platform == 'darwin'", + "onnxruntime-gpu; sys_platform != 'darwin'", + "tqdm", + "funasr==1.0.27", + "cn2an", + "pypinyin", + "pyopenjtalk>=0.3.4", + "g2p_en", + "torchaudio", + "modelscope==1.10.0", + "sentencepiece", + "transformers", + "chardet", + "PyYAML", + "psutil", + "jieba_fast", + "jieba", + "LangSegment>=0.2.0", + "Faster_Whisper", + "wordsegment", + "rotary_embedding_torch", + "pyjyutping", + "g2pk2", + "ko_pron", + "opencc; sys_platform != 'linux'", + "opencc==1.1.1; sys_platform == 'linux'", + "python_mecab_ko; sys_platform != 'win32'", + "fastapi<0.112.2", +] + + +[project.urls] +Homepage = "https://github.com/RVC-Boss/GPT-SoVITS" + +[project.scripts] +"gpt_sovits_api" = "GPT_SoVITS.api_v2:main" + +[tool.setuptools.packages.find] +include = ["GPT_SoVITS"] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 280d9d99..5230906f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ -numpy==1.23.4 +numpy==1.26.4 scipy tensorboard librosa==0.9.2 -numba==0.56.4 +numba pytorch-lightning gradio>=4.0,<=4.24.0 ffmpeg-python