Spaces:
Runtime error
Runtime error
global character_name | |
import os, json, sys | |
now_dir = os.getcwd() | |
sys.path.append(now_dir) | |
sys.path.append(os.path.join(now_dir, "GPT_SoVITS")) | |
from inference_core import inference, tts_pipline, get_streaming_tts_wav | |
def load_infer_config(character_path): | |
config_path = os.path.join(character_path, "infer_config.json") | |
"""加载环境配置文件""" | |
with open(config_path, 'r', encoding='utf-8') as f: | |
config = json.load(f) | |
if config.get("ref_wav_path") is not None: | |
return update_config_version(character_path) | |
return config | |
import os | |
import json | |
# 取得模型文件夹路径 | |
global models_path | |
models_path = "trained" | |
config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "config.json") | |
if os.path.exists(config_path): | |
with open(config_path, 'r', encoding='utf-8') as f: | |
config = json.load(f) | |
models_path = config.get("models_path", "trained") | |
def remove_character_path(full_path,character_path): | |
# 从full_path中移除character_path部分 | |
relative_path = full_path.replace(character_path, '') | |
# 如果relative_path以路径分隔符开头,去除它 | |
if relative_path.startswith(os.path.sep): | |
relative_path = relative_path[len(os.path.sep):] | |
return relative_path | |
def update_config_version(character_path): | |
config_path = os.path.join(character_path, "infer_config.json") | |
try: | |
with open(config_path, 'r', encoding='utf-8') as f: | |
config = json.load(f) | |
print("正在更新文件") | |
if config.get("ref_wav_path") is not None: | |
config["emotion_list"] = { | |
"default": { | |
"ref_wav_path": remove_character_path(config["ref_wav_path"],character_path), | |
"prompt_text": config["prompt_text"], | |
"prompt_language": config["prompt_language"] | |
} | |
} | |
config.pop("ref_wav_path", None) | |
config.pop("prompt_text", None) | |
config.pop("prompt_language", None) | |
config["sovits_path"] = remove_character_path(config["sovits_path"],character_path) | |
config["gpt_path"] = remove_character_path(config["gpt_path"],character_path) | |
with open(config_path, 'w', encoding='utf-8') as f: | |
json.dump(config, f, ensure_ascii=False, indent=4) | |
return config | |
except: | |
raise Exception("更新失败!请手动删除infer_config.json文件,让系统自动生成") | |
def auto_generate_infer_config(character_path): | |
## TODO: Auto-generate wav-list and prompt-list from character_path | |
## | |
# Initialize variables for file detection | |
print(f"正在自动生成配置文件: {character_path}") | |
ckpt_file_found = None | |
pth_file_found = None | |
wav_file_found = None | |
# Iterate through files in character_path to find matching file types | |
for dirpath, dirnames, filenames in os.walk(character_path): | |
for file in filenames: | |
# 构建文件的完整路径 | |
full_path = os.path.join(dirpath, file) | |
# 从full_path中移除character_path部分 | |
relative_path = remove_character_path(full_path,character_path) | |
# 根据文件扩展名和变量是否已赋值来更新变量 | |
if file.lower().endswith(".ckpt") and ckpt_file_found is None: | |
ckpt_file_found = relative_path | |
elif file.lower().endswith(".pth") and pth_file_found is None: | |
pth_file_found = relative_path | |
elif file.lower().endswith(".wav") and wav_file_found is None: | |
wav_file_found = relative_path | |
elif file.lower().endswith(".mp3"): | |
import pydub | |
# Convert mp3 to wav | |
wav_file_path = os.path.join(dirpath,os.path.splitext(file)[0] + ".wav") | |
pydub.AudioSegment.from_mp3(full_path).export(wav_file_path, format="wav") | |
if wav_file_found is None: | |
wav_file_found = remove_character_path(os.path.join(dirpath,os.path.splitext(file)[0] + ".wav"),character_path) | |
# Initialize infer_config with gpt_path and sovits_path regardless of wav_file_found | |
infer_config = { | |
"gpt_path": ckpt_file_found, | |
"sovits_path": pth_file_found, | |
"software_version": "1.1", | |
r"简介": r"这是一个配置文件适用于https://github.com/X-T-E-R/TTS-for-GPT-soVITS,是一个简单好用的前后端项目" | |
} | |
# If wav file is also found, update infer_config to include ref_wav_path, prompt_text, and prompt_language | |
if wav_file_found: | |
wav_file_name = os.path.splitext(os.path.basename(wav_file_found))[0] # Extract the filename without extension | |
infer_config["emotion_list"] = { | |
"default": { | |
"ref_wav_path": wav_file_found, | |
"prompt_text": wav_file_name, | |
"prompt_language": "多语种混合" | |
} | |
} | |
else: | |
raise Exception("找不到wav参考文件!请把有效wav文件放置在模型文件夹下。否则效果可能会非常怪") | |
pass | |
# Check if the essential model files were found | |
if ckpt_file_found and pth_file_found: | |
infer_config_path = os.path.join(character_path, "infer_config.json") | |
try: | |
with open(infer_config_path , 'w', encoding='utf-8') as f: | |
json.dump(infer_config, f, ensure_ascii=False, indent=4) | |
except IOError as e: | |
print(f"无法写入文件: {infer_config_path}. 错误: {e}") | |
return infer_config_path | |
else: | |
return "Required model files (.ckpt or .pth) not found in character_path directory." | |
def load_character(cha_name): | |
global character_name | |
character_path=os.path.join(models_path,cha_name) | |
try: | |
# 加载配置 | |
config = load_infer_config(character_path) | |
# 尝试从环境变量获取gpt_path,如果未设置,则从配置文件读取 | |
gpt_path = os.path.join(character_path,config.get("gpt_path")) | |
# 尝试从环境变量获取sovits_path,如果未设置,则从配置文件读取 | |
sovits_path = os.path.join(character_path,config.get("sovits_path")) | |
except: | |
try: | |
# 尝试调用auto_get_infer_config | |
auto_generate_infer_config(character_path) | |
load_character(cha_name) | |
return | |
except: | |
# 报错 | |
raise Exception("找不到模型文件!请把有效模型放置在模型文件夹下,确保其中至少有pth、ckpt和wav三种文件。") | |
# 修改权重 | |
character_name = cha_name | |
tts_pipline.init_t2s_weights(gpt_path) | |
tts_pipline.init_vits_weights(sovits_path) | |
print(f"加载角色成功: {cha_name}") | |
def get_deflaut_character_name(): | |
import os | |
import json | |
character_info_path = os.path.join(models_path, "character_info.json") | |
default_character = None | |
if os.path.exists(character_info_path): | |
with open(character_info_path, "r", encoding='utf-8') as f: | |
try: | |
character_info = json.load(f) | |
default_character = character_info.get("deflaut_character") | |
except: | |
pass | |
if default_character in ["", None, "default"]: | |
default_character=None | |
if default_character is None or not os.path.exists(os.path.join(models_path, default_character)): | |
# List all items in models_path | |
all_items = os.listdir(models_path) | |
# Filter out only directories (folders) from all_items | |
trained_folders = [item for item in all_items if os.path.isdir(os.path.join(models_path, item))] | |
# If there are any directories found, set the first one as the default character | |
if trained_folders: | |
default_character = trained_folders[0] | |
return default_character | |
character_name = get_deflaut_character_name() | |
load_character(character_name) | |
def match_character_emotion(character_path): | |
if not os.path.exists(os.path.join(character_path, "reference_audio")): | |
# 如果没有reference_audio文件夹,就返回None | |
return None, None, None | |
def get_wav_from_text_api( | |
text, | |
text_language, | |
batch_size=1, | |
speed_factor=1.0, | |
top_k=12, | |
top_p=0.6, | |
temperature=0.6, | |
character_emotion="default", | |
cut_method="auto_cut", | |
seed=-1, | |
stream=False, | |
): | |
text = text.replace("\r", "\n").replace("<br>", "\n").replace("\t", " ") | |
# 加载环境配置 | |
config = load_infer_config(os.path.join(models_path, character_name)) | |
# 尝试从配置中提取参数,如果找不到则设置为None | |
ref_wav_path = None | |
prompt_text = None | |
prompt_language = None | |
if character_emotion == "auto": | |
# 如果是auto模式,那么就自动决定情感 | |
ref_wav_path, prompt_text, prompt_language = match_character_emotion(os.path.join(models_path, character_name)) | |
if ref_wav_path is None: | |
# 未能通过auto匹配到情感,就尝试使用指定的情绪列表 | |
emotion_list=config.get('emotion_list', None)# 这是新版的infer_config文件,如果出现错误请删除infer_config.json文件,让系统自动生成 | |
now_emotion="default" | |
for emotion, details in emotion_list.items(): | |
print(emotion) | |
if emotion==character_emotion: | |
now_emotion=character_emotion | |
break | |
for emotion, details in emotion_list.items(): | |
if emotion==now_emotion: | |
ref_wav_path = os.path.join(os.path.join(models_path,character_name), details['ref_wav_path']) | |
prompt_text = details['prompt_text'] | |
prompt_language = details['prompt_language'] | |
break | |
if ref_wav_path is None: | |
print("找不到ref_wav_path!请删除infer_config.json文件,让系统自动生成") | |
print(prompt_text) | |
# 根据是否找到ref_wav_path和prompt_text、prompt_language来决定ref_free的值 | |
if ref_wav_path is not None and prompt_text is not None and prompt_language is not None: | |
ref_free = False | |
else: | |
ref_free = True | |
top_k = 3 | |
top_p = 0.3 | |
temperature = 0.3 | |
params = { | |
"text": text, | |
"text_lang": text_language, | |
"ref_audio_path": ref_wav_path, | |
"prompt_text": prompt_text, | |
"prompt_lang": prompt_language, | |
"top_k": top_k, | |
"top_p": top_p, | |
"temperature": temperature, | |
"text_split_method": cut_method, | |
"batch_size": batch_size, | |
"speed_factor": speed_factor, | |
"ref_text_free": ref_free, | |
"split_bucket":True, | |
"return_fragment":stream, | |
"seed": seed, | |
} | |
# 调用原始的get_tts_wav函数 | |
# 注意:这里假设get_tts_wav函数及其所需的其它依赖已经定义并可用 | |
if stream == False: | |
return inference(**params) | |
else: | |
return get_streaming_tts_wav(params) | |
def update_character_info(): | |
try: | |
with open(os.path.join(models_path, "character_info.json"), "r", encoding='utf-8') as f: | |
default_character = json.load(f).get("deflaut_character", None) | |
except: | |
default_character = "" | |
characters_and_emotions = {} | |
for character_subdir in [f for f in os.listdir(models_path) if os.path.isdir(os.path.join(models_path, f))]: | |
if os.path.exists(os.path.join(models_path, character_subdir, "infer_config.json")): | |
try: | |
with open(os.path.join(models_path, character_subdir, "infer_config.json"), "r", encoding='utf-8') as f: | |
config = json.load(f) | |
emotion_list=[emotion for emotion in config.get('emotion_list', None)] | |
if emotion_list is not None: | |
characters_and_emotions[character_subdir] = emotion_list | |
else: | |
characters_and_emotions[character_subdir] = ["default"] | |
except: | |
characters_and_emotions[character_subdir] = ["default"] | |
else: | |
characters_and_emotions[character_subdir] = ["default"] | |
with open(os.path.join(models_path, "character_info.json"), "w", encoding='utf-8') as f: | |
json.dump({"deflaut_character": default_character, "characters_and_emotions": characters_and_emotions}, f, ensure_ascii=False, indent=4) | |
return {"deflaut_character": default_character, "characters_and_emotions": characters_and_emotions} | |
# def test_audio_save(): | |
# fs, audio_to_save=get_wav_from_text_api("""这是一段音频测试""",'多语种混合') | |
# file_path = "example_audio.wav" | |
# from scipy.io.wavfile import write | |
# write(file_path, fs, audio_to_save) | |
# test_audio_save() | |
update_character_info() | |