CoolFace
Apppublic

kwau/sovits-isla

sourceHugging Faceupdated 3y agoView on Hugging Face
0likes
app_old.py1428 linesDownload Raw Back to root
1import ast2import datetime3import glob4import json5import logging6import multiprocessing7import os8import re9import shutil10import subprocess11import traceback12import zipfile13from itertools import chain14from pathlib import Path15 16import gradio as gr17import librosa18import numpy as np19import soundfile as sf20import torch21import yaml22 23import utils24from auto_slicer import AutoSlicer25from compress_model import removeOptimizer26from inference.infer_tool import Svc27from onnxexport.model_onnx import SynthesizerTrn28from tts_voices import SUPPORTED_LANGUAGES29from utils import mix_model30 31os.environ["PATH"] += os.pathsep + os.path.join(os.getcwd(), "ffmpeg", "bin")32 33logging.getLogger('numba').setLevel(logging.WARNING)34logging.getLogger('markdown_it').setLevel(logging.WARNING)35logging.getLogger('urllib3').setLevel(logging.WARNING)36logging.getLogger('matplotlib').setLevel(logging.WARNING)37 38# Some directories39workdir = "logs/44k"40second_dir = "models"41diff_second_dir = "models/diffusion"42diff_workdir = "logs/44k/diffusion"43config_dir = "configs/"44dataset_dir = "dataset/44k"45raw_path = "dataset_raw"46raw_wavs_path = "raw"47models_backup_path = 'models_backup'48root_dir = "checkpoints"49default_settings_file = "settings.yaml"50current_mode = ""51# Some global variables52debug = False53precheck_ok = False54model = None55sovits_params = {}56diff_params = {}57# Some dicts for mapping58MODEL_TYPE = {59    "vec768l12": 768,60    "vec256l9": 256,61    "hubertsoft": 256,62    "whisper-ppg": 1024,63    "cnhubertlarge": 1024,64    "dphubert": 768,65    "wavlmbase+": 768,66    "whisper-ppg-large": 128067}68ENCODER_PRETRAIN = {69    "vec256l9": "pretrain/checkpoint_best_legacy_500.pt",70    "vec768l12": "pretrain/checkpoint_best_legacy_500.pt",71    "hubertsoft": "pretrain/hubert-soft-0d54a1f4.pt",72    "whisper-ppg": "pretrain/medium.pt",73    "cnhubertlarge": "pretrain/chinese-hubert-large-fairseq-ckpt.pt",74    "dphubert": "pretrain/DPHuBERT-sp0.75.pth",75    "wavlmbase+": "pretrain/WavLM-Base+.pt",76    "whisper-ppg-large": "pretrain/large-v2.pt"77}78 79class Config:80    def __init__(self, path, type):81        self.path = path82        self.type = type83    84    def read(self):85        if self.type == "json":86            with open(self.path, 'r') as f:87                return json.load(f)88        if self.type == "yaml":89            with open(self.path, 'r') as f:90                return yaml.safe_load(f)91    92    def save(self, content):93        if self.type == "json":94            with open(self.path, 'w') as f:95                json.dump(content, f, indent=4)96        if self.type == "yaml":97            with open(self.path, 'w') as f:98                yaml.safe_dump(content, f, default_flow_style=False, sort_keys=False)99 100 101class ReleasePacker:102    def __init__(self, speaker, model):103        self.speaker = speaker104        self.model = model105        self.output_path = os.path.join("release_packs", f"{speaker}_release.zip")106        self.file_list = []107 108    def remove_temp(self, path):109        for filename in os.listdir(path):110            file_path = os.path.join(path, filename)111            if os.path.isfile(file_path) and not filename.endswith(".zip"):112                os.remove(file_path)113            elif os.path.isdir(file_path):114                shutil.rmtree(file_path, ignore_errors=True)115 116    def add_file(self, file_paths):117        self.file_list.extend(file_paths)118    119    def spk_to_dict(self):120        spk_string = self.speaker.replace(',', ',')121        spk_string = spk_string.replace(' ', '')122        _spk = spk_string.split(',')123        return {_spk: index for index, _spk in enumerate(_spk)}124 125    def generate_config(self, diff_model, config_origin):126        _config_origin = Config(os.path.join(config_read_dir, config_origin), "json")127        _template = Config("release_packs/config_template.json", "json")128        _d_template = Config("release_packs/diffusion_template.yaml", "yaml")129        orig_config = _config_origin.read()130        config_template = _template.read()131        diff_config_template = _d_template.read()132        spk_dict = self.spk_to_dict()133        _net = torch.load(os.path.join(ckpt_read_dir, self.model), map_location='cpu')134        emb_dim, model_dim = _net['model'].get('emb_g.weight', torch.empty(0, 0)).size()135        vol_emb = _net['model'].get('emb_vol.weight')136        if vol_emb is not None:137            config_template["train"]["vol_aug"] = config_template["model"]["vol_embedding"] = True138        #Keep the spk_dict length same as emb_dim139        if emb_dim > len(spk_dict):140            for i in range(emb_dim - len(spk_dict)):141                spk_dict[f"spk{i}"] = len(spk_dict)142        if emb_dim < len(spk_dict):143            for i in range(len(spk_dict) - emb_dim):144                spk_dict.popitem()145        self.speaker = ','.join(spk_dict.keys())146        config_template['model']['ssl_dim'] = config_template["model"]["filter_channels"] = config_template["model"]["gin_channels"] = model_dim147        config_template['model']['n_speakers'] = diff_config_template['model']['n_spk'] = emb_dim148        config_template['spk'] = diff_config_template['spk'] = spk_dict149        encoder = [k for k, v in MODEL_TYPE.items() if v == model_dim]150        if orig_config['model']['speech_encoder'] in encoder:151            config_template['model']['speech_encoder'] = orig_config['model']['speech_encoder']152        else:153            raise Exception("Config is not compatible with the model")154        155        if diff_model != "no_diff":156            _diff = torch.load(os.path.join(diff_read_dir, diff_model), map_location='cpu')157            _, diff_dim = _diff["model"].get("unit_embed.weight", torch.empty(0, 0)).size()158            if diff_dim == 256:159                diff_config_template['data']['encoder'] = 'hubertsoft'160                diff_config_template['data']['encoder_out_channels'] = 256161            elif diff_dim == 768:162                diff_config_template['data']['encoder'] = 'vec768l12'163                diff_config_template['data']['encoder_out_channels'] = 768164            elif diff_dim == 1024:165                diff_config_template['data']['encoder'] = 'whisper-ppg'166                diff_config_template['data']['encoder_out_channels'] = 1024167 168        with open("release_packs/install.txt", 'w') as f:169            f.write(str(self.file_list) + '#' + str(self.speaker))170 171        _template.save(config_template)172        _d_template.save(diff_config_template)173 174    def unpack(self, zip_file):175        with zipfile.ZipFile(zip_file, 'r') as zipf:176            zipf.extractall("release_packs")177 178    def formatted_install(self, install_txt):179        with open(install_txt, 'r') as f:180            content = f.read()181        file_list, speaker = content.split('#')182        self.speaker = speaker183        file_list = ast.literal_eval(file_list)184        self.file_list = file_list185        for _, target_path in self.file_list:186            if target_path != "install.txt" and target_path != "":187                shutil.move(os.path.join("release_packs", target_path), target_path)188        self.remove_temp("release_packs")189        return self.speaker190 191    def pack(self):192        with zipfile.ZipFile(self.output_path, 'w', zipfile.ZIP_DEFLATED) as zipf:193            for file_path, target_path in self.file_list:194                if os.path.isfile(file_path):195                    zipf.write(file_path, arcname=target_path)196 197 198def debug_change():199    global debug200    debug = debug_button.value201 202def get_default_settings():203    global sovits_params, diff_params, second_dir_enable204    config_file = Config(default_settings_file, "yaml")205    default_settings = config_file.read()206    sovits_params = default_settings['sovits_params']207    diff_params = default_settings['diff_params']208    webui_settings = default_settings['webui_settings']209    second_dir_enable = webui_settings['second_dir']210    return sovits_params, diff_params, second_dir_enable211 212def webui_change(read_second_dir):213    global second_dir_enable214    config_file = Config(default_settings_file, "yaml")215    default_settings = config_file.read()216    second_dir_enable = default_settings['webui_settings']['second_dir'] = read_second_dir217    config_file.save(default_settings)218 219def get_current_mode():220    global current_mode221    current_mode = "当前模式:独立目录模式,将从'./models/'读取模型文件" if second_dir_enable else "当前模式:工作目录模式,将从'./logs/44k'读取模型文件" 222    return current_mode223 224def save_default_settings(log_interval,eval_interval,keep_ckpts,batch_size,learning_rate,amp_dtype,all_in_mem,num_workers,cache_all_data,cache_device,diff_amp_dtype,diff_batch_size,diff_lr,diff_interval_log,diff_interval_val,diff_force_save,diff_k_step_max):225    config_file = Config(default_settings_file, "yaml")226    default_settings = config_file.read()227    default_settings['sovits_params']['log_interval'] = int(log_interval)228    default_settings['sovits_params']['eval_interval'] = int(eval_interval)229    default_settings['sovits_params']['keep_ckpts'] = int(keep_ckpts)230    default_settings['sovits_params']['batch_size'] = int(batch_size)231    default_settings['sovits_params']['learning_rate'] = float(learning_rate)232    default_settings['sovits_params']['amp_dtype'] = str(amp_dtype)233    default_settings['sovits_params']['all_in_mem'] = all_in_mem234    default_settings['diff_params']['num_workers'] = int(num_workers)235    default_settings['diff_params']['cache_all_data'] = cache_all_data236    default_settings['diff_params']['cache_device'] = str(cache_device)237    default_settings['diff_params']['amp_dtype'] = str(diff_amp_dtype)238    default_settings['diff_params']['diff_batch_size'] = int(diff_batch_size)239    default_settings['diff_params']['diff_lr'] = float(diff_lr)240    default_settings['diff_params']['diff_interval_log'] = int(diff_interval_log)241    default_settings['diff_params']['diff_interval_val'] = int(diff_interval_val)242    default_settings['diff_params']['diff_force_save'] = int(diff_force_save)243    default_settings['diff_params']['diff_k_step_max'] = diff_k_step_max244    config_file.save(default_settings)245    return "成功保存默认配置"246 247def get_model_info(choice_ckpt):248    pthfile = os.path.join(ckpt_read_dir, choice_ckpt)249    net = torch.load(pthfile, map_location=torch.device('cpu')) #cpu load to avoid using gpu memory250    spk_emb = net["model"].get("emb_g.weight")251    if spk_emb is None:252        return "所选模型缺少emb_g.weight,你可能选择了一个底模"253    _layer = spk_emb.size(1)254    encoder = [k for k, v in MODEL_TYPE.items() if v == _layer] #通过维度对应编码器255    encoder.sort()256    if encoder == ["hubertsoft", "vec256l9"]:257        encoder = ["vec256l9 / hubertsoft"]258    if encoder == ["cnhubertlarge", "whisper-ppg"]:259        encoder = ["whisper-ppg / cnhubertlarge"]260    if encoder == ["dphubert", "vec768l12", "wavlmbase+"]:261        encoder = ["vec768l12 / dphubert / wavlmbase+"]262    return encoder[0]263    264def load_json_encoder(config_choice, choice_ckpt):265    if config_choice == "no_config":266        return "未启用自动加载,请手动选择配置文件"267    if choice_ckpt == "no_model":268        return "请先选择模型"269    config_file = Config(os.path.join(config_read_dir, config_choice), "json")270    config = config_file.read()271    try:272        #比对配置文件中的模型维度与该encoder的实际维度是否对应,防止古神语273        config_encoder = config["model"].get("speech_encoder", "no_encoder")274        config_dim = config["model"]["ssl_dim"]275        #旧版配置文件自动匹配276        if config_encoder == "no_encoder":277            config_encoder = config["model"]["speech_encoder"] = "vec256l9" if config_dim == 256 else "vec768l12"278            config_file.save(config)279        correct_dim = MODEL_TYPE.get(config_encoder, "unknown")280        if config_dim != correct_dim:281            return "配置文件中的编码器与模型维度不匹配"282        return config_encoder283    except Exception as e:284        return f"出错了: {e}"285        286def auto_load(choice_ckpt):287    global second_dir_enable288    model_output_msg = get_model_info(choice_ckpt)289    json_output_msg = config_choice = ""290    choice_ckpt_name, _ = os.path.splitext(choice_ckpt)291    if second_dir_enable:292        all_config = [json for json in os.listdir(second_dir) if json.endswith(".json")]293        for config in all_config:294            config_fname, _ = os.path.splitext(config)295            if config_fname == choice_ckpt_name:296                config_choice = config297                json_output_msg = load_json_encoder(config, choice_ckpt)298        if json_output_msg != "":299            return model_output_msg, config_choice, json_output_msg300        else:301            return model_output_msg, "no_config", ""302    else:303        return model_output_msg, "no_config", ""304    305def auto_load_diff(diff_model):306    global second_dir_enable307    if second_dir_enable is False:308        return "no_diff_config"309    all_diff_config = [yaml for yaml in os.listdir(second_dir) if yaml.endswith(".yaml")]310    for config in all_diff_config:311        config_fname, _ = os.path.splitext(config)312        diff_fname, _ = os.path.splitext(diff_model)313        if config_fname == diff_fname:314            return config315    return "no_diff_config"316        317def load_model_func(ckpt_name,cluster_name,config_name,enhance,diff_model_name,diff_config_name,only_diffusion,use_spk_mix,using_device,method,speedup):318    global model319    config_path = os.path.join(config_read_dir, config_name) if not only_diffusion else "configs/config.json"320    diff_config_path = os.path.join(config_read_dir, diff_config_name) if diff_config_name != "no_diff_config" else "configs/diffusion.yaml"321    ckpt_path = os.path.join(ckpt_read_dir, ckpt_name)322    cluster_path = os.path.join(ckpt_read_dir, cluster_name)323    diff_model_path = os.path.join(diff_read_dir, diff_model_name)324    k_step_max = 1000325    if not only_diffusion:326        config = Config(config_path, "json").read()327    if diff_model_name != "no_diff":328        _diff = Config(diff_config_path, "yaml")329        _content = _diff.read()330        diff_spk = _content.get('spk', {})331        diff_spk_choice = spk_choice = next(iter(diff_spk), "未检测到音色")332        if not only_diffusion:333            if _content['data'].get('encoder_out_channels') != config["model"].get('ssl_dim'):334                return "扩散模型维度与主模型不匹配,请确保两个模型使用的是同一个编码器", gr.Dropdown.update(choices=[], value=""), 0, None335        _content["infer"]["speedup"] = int(speedup)336        _content["infer"]["method"] = str(method)337        k_step_max = _content["model"].get('k_step_max', 0) if _content["model"].get('k_step_max', 0) != 0 else 1000338        _diff.save(_content)339    if not only_diffusion:340        net = torch.load(ckpt_path, map_location=torch.device('cpu'))341    #读取模型各维度并比对,还有小可爱无视提示硬要加载底模的就返回个未初始张量342        emb_dim, model_dim = net["model"].get("emb_g.weight", torch.empty(0, 0)).size() 343        if emb_dim > config["model"]["n_speakers"]:344            return "模型说话人数量与emb维度不匹配", gr.Dropdown.update(choices=[], value=""), 0, None345        if model_dim != config["model"]["ssl_dim"]: 346            return "配置文件与模型不匹配", gr.Dropdown.update(choices=[], value=""), 0, None347        encoder = config["model"]["speech_encoder"]348        spk_dict = config.get('spk', {})349        spk_choice = next(iter(spk_dict), "未检测到音色")350    else:351        spk_dict = diff_spk352        spk_choice = diff_spk_choice353    fr = cluster_name.endswith(".pkl") #如果是pkl后缀就启用特征检索354    shallow_diffusion = diff_model_name != "no_diff" #加载了扩散模型就启用浅扩散355    device = cuda[using_device] if "CUDA" in using_device else using_device356    model = Svc(ckpt_path,357                    config_path,358                    device=device if device != "Auto" else None,359                    cluster_model_path=cluster_path,360                    nsf_hifigan_enhance=enhance,361                    diffusion_model_path=diff_model_path,362                    diffusion_config_path=diff_config_path,363                    shallow_diffusion=shallow_diffusion,364                    only_diffusion=only_diffusion,365                    spk_mix_enable=use_spk_mix,366                    feature_retrieval=fr)367    spk_list = list(spk_dict.keys())368    if not only_diffusion:369        clip = 25 if encoder == "whisper-ppg" or encoder == "whisper-ppg-large" else 0 #Whisper必须强制切片25秒370        device_name = torch.cuda.get_device_properties(model.dev).name if "cuda" in str(model.dev) else str(model.dev)371        sovits_msg = f"模型被成功加载到了{device_name}上\n"372    else: 373        clip = 0374        sovits_msg = "启用全扩散推理,未加载So-VITS模型\n"375    index_or_kmeans = "特征索引" if fr else "聚类模型"376    clu_load = "未加载" if cluster_name == "no_clu" else cluster_name377    diff_load = "未加载" if diff_model_name == "no_diff" else f"{diff_model_name} | 采样器: {method} | 加速倍数:{int(speedup)} | 最大浅扩散步数:{k_step_max}"378    output_msg = f"{sovits_msg}{index_or_kmeans}:{clu_load}\n扩散模型:{diff_load}"379    return (380        output_msg, 381        gr.Dropdown.update(choices=spk_list, value=spk_choice), 382        clip, 383        gr.Slider.update(value=100 if k_step_max>100 else k_step_max, minimum=speedup, maximum=k_step_max)384    )385 386def model_empty_cache():387    global model388    if model is None:389        return sid.update(choices = [],value=""),"没有模型需要卸载!"390    else:391        model.unload_model()392        model = None393        torch.cuda.empty_cache()394        return sid.update(choices = [],value=""),"模型卸载完毕!"395 396def get_file_options(directory, extension):397    return [file for file in os.listdir(directory) if file.endswith(extension)]398 399def load_options():400    ckpt_list = [file for file in get_file_options(ckpt_read_dir, ".pth") if not file.startswith("D_") or file == "G_0.pth"]401    config_list = get_file_options(config_read_dir, ".json")402    cluster_list = ["no_clu"] + get_file_options(ckpt_read_dir, ".pt") + get_file_options(ckpt_read_dir, ".pkl") # 聚类和特征检索模型403    diff_list = ["no_diff"] + get_file_options(diff_read_dir, ".pt")404    diff_config_list = ["no_diff_config"] + get_file_options(config_read_dir, ".yaml")405    return ckpt_list, config_list, cluster_list, diff_list, diff_config_list406 407def refresh_options():408    global ckpt_read_dir, config_read_dir, diff_read_dir, current_mode409    ckpt_read_dir = second_dir if second_dir_enable else workdir410    config_read_dir = second_dir if second_dir_enable else config_dir411    diff_read_dir = diff_second_dir if second_dir_enable else diff_workdir412    ckpt_list, config_list, cluster_list, diff_list, diff_config_list = load_options()413    current_mode = get_current_mode()414    return (415        choice_ckpt.update(choices=ckpt_list),416        config_choice.update(choices=config_list),417        cluster_choice.update(choices=cluster_list),418        diff_choice.update(choices=diff_list),419        diff_config_choice.update(choices=diff_config_list),420        mode_caption.update(value=f"""{current_mode},可在页面底端切换模式""")421    )422 423def vc_infer(output_format, sid, input_audio, input_audio_path, vc_transform, auto_f0, cluster_ratio, slice_db, noise_scale, pad_seconds, cl_num, lg_num, lgr_num, f0_predictor, enhancer_adaptive_key, cr_threshold, k_step, use_spk_mix, second_encoding, loudness_envelope_adjustment):424    if np.issubdtype(input_audio.dtype, np.integer):425        input_audio = (input_audio / np.iinfo(input_audio.dtype).max).astype(np.float32)426    if len(input_audio.shape) > 1:427        input_audio = librosa.to_mono(input_audio.transpose(1, 0))428    sf.write("temp.wav", input_audio, 44100, format="wav")429    _audio = model.slice_inference(430        "temp.wav",431        sid,432        vc_transform,433        slice_db,434        cluster_ratio,435        auto_f0,436        noise_scale,437        pad_seconds,438        cl_num,439        lg_num,440        lgr_num,441        f0_predictor,442        enhancer_adaptive_key,443        cr_threshold,444        k_step,445        use_spk_mix,446        second_encoding,447        loudness_envelope_adjustment448    )  449    model.clear_empty()450    if not os.path.exists("results"):451        os.makedirs("results")452    key = "auto" if auto_f0 else f"{int(vc_transform)}key"453    cluster = "_" if cluster_ratio == 0 else f"_{cluster_ratio}_"454    isdiffusion = "sovits"455    if model.shallow_diffusion:456        isdiffusion = "sovdiff"457    if model.only_diffusion:458        isdiffusion = "diff"459    #Gradio上传的filepath因为未知原因会有一个无意义的固定后缀,这里去掉460    truncated_basename = Path(input_audio_path).stem[:-6] if Path(input_audio_path).stem[-6:] == "-0-100" else Path(input_audio_path).stem461    output_file_name = f'{truncated_basename}_{sid}_{key}{cluster}{isdiffusion}.{output_format}'462    output_file_path = os.path.join("results", output_file_name)463    if os.path.exists(output_file_path):464        count = 1465        while os.path.exists(output_file_path):466            output_file_name = f'{truncated_basename}_{sid}_{key}{cluster}{isdiffusion}_{str(count)}.{output_format}'467            output_file_path = os.path.join("results", output_file_name)468            count += 1  469    sf.write(output_file_path, _audio, model.target_sample, format=output_format)470    return output_file_path471 472def vc_fn(output_format, sid, input_audio, vc_transform, auto_f0, cluster_ratio, slice_db, noise_scale, pad_seconds, cl_num, lg_num, lgr_num, f0_predictor, enhancer_adaptive_key, cr_threshold, k_step, use_spk_mix, second_encoding, loudness_envelope_adjustment):473    global model474    try:475        if input_audio is None:476            return "你还没有上传音频", None477        if model is None:478            return "你还没有加载模型", None479        if getattr(model, 'cluster_model', None) is None and model.feature_retrieval is False:480            if cluster_ratio != 0:481                return "你还未加载聚类或特征检索模型,无法启用聚类/特征检索混合比例", None482        audio, _ = sf.read(input_audio)483        output_file_path = vc_infer(output_format, sid, audio, input_audio, vc_transform, auto_f0, cluster_ratio, slice_db, noise_scale, pad_seconds, cl_num, lg_num, lgr_num, f0_predictor, enhancer_adaptive_key, cr_threshold, k_step, use_spk_mix, second_encoding, loudness_envelope_adjustment)484        os.remove("temp.wav")485        return "Success", output_file_path486    except Exception as e:487        if debug:488            traceback.print_exc()489        raise gr.Error(e)490 491def vc_batch_fn(output_format, sid, input_audio_files, vc_transform, auto_f0, cluster_ratio, slice_db, noise_scale, pad_seconds, cl_num, lg_num, lgr_num, f0_predictor, enhancer_adaptive_key, cr_threshold, k_step, use_spk_mix, second_encoding, loudness_envelope_adjustment):492    global model493    try:494        if input_audio_files is None or len(input_audio_files) == 0:495            return "你还没有上传音频"496        if model is None:497            return "你还没有加载模型"498        if getattr(model, 'cluster_model', None) is None and model.feature_retrieval is False:499            if cluster_ratio != 0:500                return "你还未加载聚类或特征检索模型,无法启用聚类/特征检索混合比例", None501        _output = []502        for file_obj in input_audio_files:503            print(f"Start processing: {file_obj.name}")504            input_audio_path = file_obj.name505            audio, _ = sf.read(input_audio_path)506            output_file_path = vc_infer(output_format, sid, audio, input_audio_path, vc_transform, auto_f0, cluster_ratio, slice_db, noise_scale, pad_seconds, cl_num, lg_num, lgr_num, f0_predictor, enhancer_adaptive_key, cr_threshold, k_step, use_spk_mix, second_encoding, loudness_envelope_adjustment)507            _output.append(output_file_path)508        return "批量推理完成,音频已经被保存到results文件夹"509    except Exception as e:510        if debug:511            traceback.print_exc()512        raise gr.Error(e)513    514def tts_fn(_text, _gender, _lang, _rate, _volume, output_format, sid, vc_transform, auto_f0,cluster_ratio, slice_db, noise_scale,pad_seconds,cl_num,lg_num,lgr_num,f0_predictor,enhancer_adaptive_key,cr_threshold, k_step,use_spk_mix,second_encoding,loudness_envelope_adjustment):515    global model516    try:517        if model is None:518            return "你还没有加载模型", None519        if getattr(model, 'cluster_model', None) is None and model.feature_retrieval is False:520            if cluster_ratio != 0:521                return "你还未加载聚类或特征检索模型,无法启用聚类/特征检索混合比例", None522        _rate = f"+{int(_rate*100)}%" if _rate >= 0 else f"{int(_rate*100)}%"523        _volume = f"+{int(_volume*100)}%" if _volume >= 0 else f"{int(_volume*100)}%"524        if _lang == "Auto":525            _gender = "Male" if _gender == "男" else "Female"526            subprocess.run([r".\workenv\python.exe", "tts.py", _text, _lang, _rate, _volume, _gender])527        else:528            subprocess.run([r".\workenv\python.exe", "tts.py", _text, _lang, _rate, _volume])529        target_sr = 44100530        y, sr = librosa.load("tts.wav")531        resampled_y = librosa.resample(y, orig_sr=sr, target_sr=target_sr)532        sf.write("tts.wav", resampled_y, target_sr, subtype = "PCM_16")533        input_audio = "tts.wav"534        audio, _ = sf.read(input_audio)535        output_file_path = vc_infer(output_format, sid, audio, input_audio, vc_transform, auto_f0, cluster_ratio, slice_db, noise_scale, pad_seconds, cl_num, lg_num, lgr_num, f0_predictor, enhancer_adaptive_key, cr_threshold, k_step, use_spk_mix, second_encoding, loudness_envelope_adjustment)536        #os.remove("tts.wav")537        return "Success", output_file_path538    except Exception as e:539        if debug:540            traceback.print_exc()541        raise gr.Error(e)542 543def load_raw_dirs():544    global precheck_ok545    precheck_ok = False546    allowed_pattern = re.compile(r'^[a-zA-Z0-9_@#$%^&()_+\-=\s\.]*$')547    illegal_files = illegal_dataset = []548    for root, dirs, files in os.walk(raw_path):549        for dir in dirs:550            if not allowed_pattern.match(dir):551                illegal_dataset.append(dir)552        if illegal_dataset:553            return f"数据集文件夹名只能包含数字、字母、下划线,以下文件夹不符合要求,请改名后再试:\n{illegal_dataset}"554        if root != raw_path:  # 只处理子文件夹内的文件555            for file in files:556                if not allowed_pattern.match(file) and file not in illegal_files:557                    illegal_files.append(file)558                if not file.lower().endswith('.wav') and file not in illegal_files:559                    illegal_files.append(file)560    if illegal_files:561        return f"数据集文件名只能包含数字、字母、下划线,且必须是.wav格式,以下文件不符合要求,请改名后再试:\n{illegal_files}"562    spk_dirs = [entry.name for entry in os.scandir(raw_path) if entry.is_dir()]563    if spk_dirs:564        precheck_ok = True565        return spk_dirs566    else:567        return "未找到数据集,请检查dataset_raw文件夹"568 569def dataset_preprocess(encoder, f0_predictor, use_diff, vol_aug, skip_loudnorm, num_processes):570    if precheck_ok:571        diff_arg = "--use_diff" if use_diff else ""572        vol_aug_arg = "--vol_aug" if vol_aug else ""573        skip_loudnorm_arg = "--skip_loudnorm" if skip_loudnorm else ""574        preprocess_commands = [575            r".\workenv\python.exe resample.py %s" % (skip_loudnorm_arg),576            r".\workenv\python.exe preprocess_flist_config.py --speech_encoder %s %s" % (encoder, vol_aug_arg),577            r".\workenv\python.exe preprocess_hubert_f0.py --num_processes %s --f0_predictor %s %s" % (num_processes ,f0_predictor, diff_arg)578            ]579        accumulated_output = ""580        #清空dataset581        dataset = os.listdir(dataset_dir)582        if len(dataset) != 0:583            for dir in dataset:584                dataset_spk_dir = os.path.join(dataset_dir, str(dir))585                if os.path.isdir(dataset_spk_dir):586                    shutil.rmtree(dataset_spk_dir)587                    accumulated_output += f"Deleting previous dataset: {dir}\n"588        for command in preprocess_commands:589            try:590                result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, text=True)591                accumulated_output += f"Command: {command}, Using Encoder: {encoder}, Using f0 Predictor: {f0_predictor}\n"592                yield accumulated_output, None593                progress_line = None594                for line in result.stdout:595                    if r"it/s" in line or r"s/it" in line: #防止进度条刷屏596                        progress_line = line597                    else:598                        accumulated_output += line599                    if progress_line is None:600                        yield accumulated_output, None601                    else:602                        yield accumulated_output + progress_line, None603                result.communicate()604            except subprocess.CalledProcessError as e:605                result = e.output606                accumulated_output += f"Error: {result}\n"607                yield accumulated_output, None608            if progress_line is not None:609                accumulated_output += progress_line610            accumulated_output += '-' * 50 + '\n'611            yield accumulated_output, None612            config_path = "configs/config.json"613        with open(config_path, 'r') as f:614            config = json.load(f)615        spk_name = config.get('spk', None)616        yield accumulated_output, gr.Textbox.update(value=spk_name)617    else:618        yield "数据集识别未通过,请先识别数据集并确保没有报错信息", None619 620def regenerate_config(encoder, vol_aug):621    if precheck_ok is False:622        return "数据集识别未通过,请检查识别结果的报错信息"623    vol_aug_arg = "--vol_aug" if vol_aug else ""624    cmd = r".\workenv\python.exe preprocess_flist_config.py --speech_encoder %s %s" % (encoder, vol_aug_arg)625    output = ""626    try:627        result = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, text=True)628        for line in result.stdout:629            output += line630        output += "Regenerate config file successfully."631    except subprocess.CalledProcessError as e:632        result = e.output633        output += f"Error: {result}\n"634    return output635 636def clear_output():637    return gr.Textbox.update(value="Cleared!>_<")638 639def get_available_encoder():640    current_pretrain = os.listdir("pretrain")641    current_pretrain = [("pretrain/" + model) for model in current_pretrain]642    encoder_list = []643    for encoder, path in ENCODER_PRETRAIN.items():644        if path in current_pretrain:645            encoder_list.append(encoder)646    return encoder_list647 648def config_fn(log_interval, eval_interval, keep_ckpts, batch_size, lr, amp_dtype, all_in_mem, diff_num_workers, diff_cache_all_data, diff_batch_size, diff_lr, diff_interval_log, diff_interval_val, diff_cache_device, diff_amp_dtype, diff_force_save, diff_k_step_max):649    if amp_dtype == "fp16" or amp_dtype == "bf16":650        fp16_run = True651    else:652        fp16_run = False653        amp_dtype = "fp16"654    config_origin = Config("configs/config.json", "json")655    diff_config = Config("configs/diffusion.yaml", "yaml")656    config_data = config_origin.read()657    config_data['train']['log_interval'] = int(log_interval)658    config_data['train']['eval_interval'] = int(eval_interval)659    config_data['train']['keep_ckpts'] = int(keep_ckpts)660    config_data['train']['batch_size'] = int(batch_size)661    config_data['train']['learning_rate'] = float(lr)662    config_data['train']['fp16_run'] = fp16_run663    config_data['train']['half_type'] = str(amp_dtype)664    config_data['train']['all_in_mem'] = all_in_mem665    config_origin.save(config_data)666    diff_config_data = diff_config.read()667    diff_config_data['train']['num_workers'] = int(diff_num_workers)668    diff_config_data['train']['cache_all_data'] = diff_cache_all_data669    diff_config_data['train']['batch_size'] = int(diff_batch_size)670    diff_config_data['train']['lr'] = float(diff_lr)671    diff_config_data['train']['interval_log'] = int(diff_interval_log)672    diff_config_data['train']['interval_val'] = int(diff_interval_val)673    diff_config_data['train']['cache_device'] = str(diff_cache_device)674    diff_config_data['train']['amp_dtype'] = str(diff_amp_dtype)675    diff_config_data['train']['interval_force_save'] = int(diff_force_save)676    diff_config_data['model']['k_step_max'] = 100 if diff_k_step_max else 0677    diff_config.save(diff_config_data)678    return "配置文件写入完成"679 680def check_dataset(dataset_path):681    if not os.listdir(dataset_path):682        return "数据集不存在,请检查dataset文件夹"683    no_npy_pt_files = True684    for root, dirs, files in os.walk(dataset_path):685        for file in files:686            if file.endswith('.npy') or file.endswith('.pt'):687                no_npy_pt_files = False688                break689    if no_npy_pt_files:690        return "数据集中未检测到f0和hubert文件,可能是预处理未完成"691    return None692 693def training(gpu_selection, encoder):694    config_file = Config("configs/config.json", "json")695    config_data = config_file.read()696    vol_emb = config_data["model"]["vol_embedding"]697    dataset_warn = check_dataset(dataset_dir)698    if dataset_warn is not None:699        return dataset_warn700    PRETRAIN = { 701        "vec256l9": ("D_0.pth", "G_0.pth", "pre_trained_model"),702        "vec768l12": ("D_0.pth", "G_0.pth", "pre_trained_model/768l12/vol_emb" if vol_emb else "pre_trained_model/768l12"),703        "hubertsoft": ("D_0.pth", "G_0.pth", "pre_trained_model/hubertsoft"),704        "whisper-ppg": ("D_0.pth", "G_0.pth", "pre_trained_model/whisper-ppg"),705        "cnhubertlarge": ("D_0.pth", "G_0.pth", "pre_trained_model/cnhubertlarge"),706        "dphubert": ("D_0.pth", "G_0.pth", "pre_trained_model/dphubert"),707        "wavlmbase+": ("D_0.pth", "G_0.pth", "pre_trained_model/wavlmbase+"),708        "whisper-ppg-large": ("D_0.pth", "G_0.pth", "pre_trained_model/whisper-ppg-large")709    }710    if encoder not in PRETRAIN:711        return "未知编码器"712    d_0_file, g_0_file, encoder_model_path = PRETRAIN[encoder]713    d_0_path = os.path.join(encoder_model_path, d_0_file)714    g_0_path = os.path.join(encoder_model_path, g_0_file)715    timestamp = datetime.datetime.now().strftime('%Y_%m_%d_%H_%M')716    new_backup_folder = os.path.join(models_backup_path, str(timestamp))717    output_msg = ""718    if os.listdir(workdir) != ['diffusion']:719        os.makedirs(new_backup_folder, exist_ok=True)720        for file in os.listdir(workdir):721            if file != "diffusion":722                shutil.move(os.path.join(workdir, file), os.path.join(new_backup_folder, file))723    if os.path.isfile(g_0_path) and os.path.isfile(d_0_path):724        shutil.copy(d_0_path, os.path.join(workdir, "D_0.pth"))725        shutil.copy(g_0_path, os.path.join(workdir, "G_0.pth"))726        output_msg += f"成功装载预训练模型,编码器:{encoder}\n"727    else:728        output_msg += f"{encoder}的预训练模型不存在,未装载预训练模型\n"729    cmd = r"set CUDA_VISIBLE_DEVICES=%s && .\workenv\python.exe train.py -c configs/config.json -m 44k" % (gpu_selection)730    subprocess.Popen(["cmd", "/c", "start", "cmd", "/k", cmd])731    output_msg += "已经在新的终端窗口开始训练,请监看终端窗口的训练日志。在终端中按Ctrl+C可暂停训练。"732    return output_msg733 734def continue_training(gpu_selection, encoder):735    dataset_warn = check_dataset(dataset_dir)736    if dataset_warn is not None:737        return dataset_warn738    if encoder == "":739        return "请先选择预处理对应的编码器"740    all_files = os.listdir(workdir)741    model_files = [f for f in all_files if f.startswith('G_') and f.endswith('.pth')]742    if len(model_files) == 0:743        return "你还没有已开始的训练"744    cmd = r"set CUDA_VISIBLE_DEVICES=%s && .\workenv\python.exe train.py -c configs/config.json -m 44k" % (gpu_selection)745    subprocess.Popen(["cmd", "/c", "start", "cmd", "/k", cmd])746    return "已经在新的终端窗口开始训练,请监看终端窗口的训练日志。在终端中按Ctrl+C可暂停训练。"747 748def kmeans_training(kmeans_gpu):749    if not os.listdir(dataset_dir):750        return "数据集不存在,请检查dataset文件夹"751    cmd = r".\workenv\python.exe cluster/train_cluster.py --gpu" if kmeans_gpu else r".\workenv\python.exe cluster/train_cluster.py"752    subprocess.Popen(["cmd", "/c", "start", "cmd", "/k", cmd])753    return "已经在新的终端窗口开始训练,训练聚类模型不会输出日志,CPU训练一般需要5-10分钟左右"754 755def index_training():756    if not os.listdir(dataset_dir):757        return "数据集不存在,请检查dataset文件夹"758    cmd = r".\workenv\python.exe train_index.py -c configs/config.json"759    subprocess.Popen(["cmd", "/c", "start", "cmd", "/k", cmd])760    return "已经在新的终端窗口开始训练"761 762def diff_training(encoder, k_step_max):763    if not os.listdir(dataset_dir):764        return "数据集不存在,请检查dataset文件夹"765    timestamp = datetime.datetime.now().strftime('%Y_%m_%d_%H_%M')766    new_backup_folder = os.path.join(models_backup_path, "diffusion", str(timestamp))767    if len(os.listdir(diff_workdir)) != 0:768        os.makedirs(new_backup_folder, exist_ok=True)769        for file in os.listdir(diff_workdir):770            shutil.move(os.path.join(diff_workdir, file), os.path.join(new_backup_folder, file))771    DIFF_PRETRAIN = {772        "768-kstepmax100": "pre_trained_model/diffusion/768l12/max100/model_0.pt",773        "vec768l12": "pre_trained_model/diffusion/768l12/model_0.pt",774        "hubertsoft": "pre_trained_model/diffusion/hubertsoft/model_0.pt",775        "whisper-ppg": "pre_trained_model/diffusion/whisper-ppg/model_0.pt"776    }777    if encoder not in DIFF_PRETRAIN:778        return "你所选的编码器暂时不支持训练扩散模型"779    if k_step_max:780        encoder = "768-kstepmax100"781    diff_pretrained_model = DIFF_PRETRAIN[encoder]782    shutil.copy(diff_pretrained_model, os.path.join(diff_workdir, "model_0.pt"))783    subprocess.Popen(["cmd", "/c", "start", "cmd", "/k", r".\workenv\python.exe train_diff.py -c configs/diffusion.yaml"])784    output_message = "已经在新的终端窗口开始训练,请监看终端窗口的训练日志。在终端中按Ctrl+C可暂停训练。"785    if encoder == "768-kstepmax100":786        output_message += "\n正在进行100步深度的浅扩散训练,已加载底模"787    else:788        output_message += f"\n正在进行完整深度的扩散训练,编码器{encoder}"789    return output_message790 791def diff_continue_training(encoder):792    if not os.listdir(dataset_dir):793        return "数据集不存在,请检查dataset文件夹"794    if encoder == "":795        return "请先选择预处理对应的编码器"796    all_files = os.listdir(diff_workdir)797    model_files = [f for f in all_files if f.endswith('.pt')]798    if len(model_files) == 0:799        return "你还没有已开始的训练"800    subprocess.Popen(["cmd", "/c", "start", "cmd", "/k", r".\workenv\python.exe train_diff.py -c configs/diffusion.yaml"])801    return "已经在新的终端窗口开始训练,请监看终端窗口的训练日志。在终端中按Ctrl+C可暂停训练。"802 803def upload_mix_append_file(files,sfiles):804    try:805        if(sfiles is None):806            file_paths = [file.name for file in files]807        else:808            file_paths = [file.name for file in chain(files,sfiles)]809        p = {file:100 for file in file_paths}810        return file_paths,mix_model_output1.update(value=json.dumps(p,indent=2))811    except Exception as e:812        if debug:813            traceback.print_exc()814        raise gr.Error(e)815 816def mix_submit_click(js,mode):817    try:818        assert js.lstrip()!=""819        modes = {"凸组合":0, "线性组合":1}820        mode = modes[mode]821        data = json.loads(js)822        data = list(data.items())823        model_path,mix_rate = zip(*data)824        path = mix_model(model_path,mix_rate,mode)825        return f"成功,文件被保存在了{path}"826    except Exception as e:827        if debug:828            traceback.print_exc()829        raise gr.Error(e)830 831def updata_mix_info(files):832    try:833        if files is None:834            return mix_model_output1.update(value="")835        p = {file.name:100 for file in files}836        return mix_model_output1.update(value=json.dumps(p,indent=2))837    except Exception as e:838        if debug:839            traceback.print_exc()840        raise gr.Error(e)841 842def pth_identify():843    if not os.path.exists(root_dir):844        return f"未找到{root_dir}文件夹,请先创建一个{root_dir}文件夹并按第一步流程操作"845    model_dirs = [d for d in os.listdir(root_dir) if os.path.isdir(os.path.join(root_dir, d))]846    if not model_dirs:847        return f"未在{root_dir}文件夹中找到模型文件夹,请确保每个模型和配置文件都被放置在单独的文件夹中"848    valid_model_dirs = []849    for path in model_dirs:850        pth_files = glob.glob(f"{root_dir}/{path}/*.pth")851        json_files = glob.glob(f"{root_dir}/{path}/*.json")852        if len(pth_files) != 1 or len(json_files) != 1:853            return f"错误: 在{root_dir}/{path}中找到了{len(pth_files)}个.pth文件和{len(json_files)}个.json文件。应当确保每个文件夹内有且只有一个.pth文件和.json文件"854        valid_model_dirs.append(path)855        856    return f"成功识别了{len(valid_model_dirs)}个模型:{valid_model_dirs}"857 858def onnx_export():859    model_dirs = [d for d in os.listdir(root_dir) if os.path.isdir(os.path.join(root_dir, d))]860    try:861        for path in model_dirs:862            pth_files = glob.glob(f"{root_dir}/{path}/*.pth")863            json_files = glob.glob(f"{root_dir}/{path}/*.json")864            model_file = pth_files[0]865            json_file = json_files[0]866            device = torch.device("cpu")867            hps = utils.get_hparams_from_file(json_file)868            SVCVITS = SynthesizerTrn(869                hps.data.filter_length // 2 + 1,870                hps.train.segment_size // hps.data.hop_length,871                **hps.model)872            _ = utils.load_checkpoint(model_file, SVCVITS, None)873            _ = SVCVITS.eval().to(device)874            for i in SVCVITS.parameters():875                i.requires_grad = False       876            n_frame = 10877            test_hidden_unit = torch.rand(1, n_frame, 256)878            test_pitch = torch.rand(1, n_frame)879            test_mel2ph = torch.arange(0, n_frame, dtype=torch.int64)[None] # torch.LongTensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]).unsqueeze(0)880            test_uv = torch.ones(1, n_frame, dtype=torch.float32)881            test_noise = torch.randn(1, 192, n_frame)882            test_sid = torch.LongTensor([0])883            input_names = ["c", "f0", "mel2ph", "uv", "noise", "sid"]884            output_names = ["audio", ]885            onnx_file = os.path.splitext(model_file)[0] + ".onnx"886            torch.onnx.export(SVCVITS,887                              (888                                  test_hidden_unit.to(device),889                                  test_pitch.to(device),890                                  test_mel2ph.to(device),891                                  test_uv.to(device),892                                  test_noise.to(device),893                                  test_sid.to(device)894                              ),895                              onnx_file,896                              dynamic_axes={897                                  "c": [0, 1],898                                  "f0": [1],899                                  "mel2ph": [1],900                                  "uv": [1],901                                  "noise": [2],902                              },903                              do_constant_folding=False,904                              opset_version=16,905                              verbose=False,906                              input_names=input_names,907                              output_names=output_names)908        return "转换成功,模型被保存在了checkpoints下的对应目录"909    except Exception as e:910        if debug:911            traceback.print_exc()912        raise gr.Error(e)913 914def load_raw_audio(audio_path):915    if not os.path.isdir(audio_path):916        return "请输入正确的目录", None917    files = os.listdir(audio_path)918    wav_files = [file for file in files if file.lower().endswith('.wav')]919    if not wav_files:920        return "未在目录中找到.wav音频文件", None921    return "成功加载", wav_files922 923def slicer_fn(input_dir, output_dir, process_method, max_sec, min_sec):924    if output_dir == "":925        return "请先选择输出的文件夹"926    if output_dir == input_dir:927        return "输出目录不能和输入目录相同"928    slicer = AutoSlicer()929    if os.path.exists(output_dir) is not True:930        os.makedirs(output_dir)931    for filename in os.listdir(input_dir):932        if filename.lower().endswith(".wav"):933            slicer.auto_slice(filename, input_dir, output_dir, max_sec)934    if process_method == "丢弃":935        for filename in os.listdir(output_dir):936            if filename.endswith(".wav"):937                filepath = os.path.join(output_dir, filename)938                audio, sr = librosa.load(filepath, sr=None, mono=False)939                if librosa.get_duration(y=audio, sr=sr) < min_sec:940                    os.remove(filepath)941    elif process_method == "将过短音频整合为长音频":942        slicer.merge_short(output_dir, max_sec, min_sec)943    file_count, max_duration, min_duration, orig_duration, final_duration = slicer.slice_count(input_dir, output_dir)944    hrs = int(final_duration / 3600)945    mins = int((final_duration % 3600) / 60)946    sec = format(float(final_duration % 60), '.2f')947    rate = format(100 * (final_duration / orig_duration), '.2f') if orig_duration != 0 else 0948    rate_msg = f"为原始音频时长的{rate}%" if rate != 0 else "因未知问题,无法计算切片时长的占比"949    return f"成功将音频切分为{file_count}条片段,其中最长{max_duration}秒,最短{min_duration}秒,切片后的音频总时长{hrs:02d}小时{mins:02d}分{sec}秒,{rate_msg}"950 951def model_compression(_model):952    if _model == "":953        return "请先选择要压缩的模型"954    else:955        model_path = os.path.join(ckpt_read_dir, _model)956        filename, extension = os.path.splitext(_model)957        output_model_name = f"{filename}_compressed{extension}"958        output_path = os.path.join(ckpt_read_dir, output_model_name)959        removeOptimizer(model_path, output_path)960        return f"模型已成功被保存在了{output_path}"961    962def pack_autoload(model_to_pack):963    _, config_name, _ = auto_load(model_to_pack)964    if config_name == "no_config":965        return "未找到对应的配置文件,请手动选择", None966    else:967        _config = Config(os.path.join(config_read_dir, config_name), "json")968        _content = _config.read()969        spk_dict = _content["spk"]970        spk_list = ",".join(spk_dict.keys())971        return config_name, spk_list972    973def release_packing(model_to_pack, model_config, speaker, diff_to_pack, cluster_to_pack):974    model_path = diff_path = cluster_path = ""975    basename = os.path.splitext(model_to_pack)[0]976    diff_basename = os.path.splitext(diff_to_pack)[0]977    if model_to_pack == "" or model_config == "" or speaker == "":978        return "存在必选项为空,请检查后重试"979    released_pack = ReleasePacker(speaker, model_to_pack)980    released_pack.remove_temp("release_packs")981    model_path = os.path.join(ckpt_read_dir, model_to_pack)982    if os.stat(model_path).st_size > 300000000:983        removeOptimizer(model_path, os.path.join("release_packs", model_to_pack))984        model_path = os.path.join("release_packs", model_to_pack)985    if diff_to_pack != "no_diff":986        diff_path = os.path.join(diff_read_dir, diff_to_pack)987    if cluster_to_pack != "no_cluster":988        cluster_path = os.path.join(ckpt_read_dir, cluster_to_pack)989    shutil.copyfile("configs_template/config_template.json", "release_packs/config_template.json")990    shutil.copyfile("configs_template/diffusion_template.yaml", "release_packs/diffusion_template.yaml")991    files_to_pack = [992        (model_path, f"models/{model_to_pack}"),993        (diff_path, f"models/diffusion/{diff_to_pack}") if diff_to_pack != "no_diff" else ("", ""),994        (cluster_path, f"models/{cluster_to_pack}") if cluster_to_pack != "no_cluster" else ("", ""),995        (f"release_packs/{basename}.json", f"models/{basename}.json"),996        (f"release_packs/{diff_basename}.yaml", f"models/{diff_basename}.yaml") if diff_to_pack != "no_diff" else ("", ""),997        ("release_packs/install.txt", "install.txt")998    ]999    released_pack.add_file(files_to_pack)1000    released_pack.generate_config(diff_to_pack, model_config)1001    os.rename("release_packs/config_template.json", f"release_packs/{basename}.json")1002    os.rename("release_packs/diffusion_template.yaml", f"release_packs/{diff_basename}.yaml")1003    released_pack.pack()1004    to_remove = [file for file in os.listdir("release_packs") if not file.endswith(".zip")]1005    for file in to_remove:1006        os.remove(os.path.join("release_packs", file))1007    return "打包成功, 请在release_packs目录下查看"1008 1009def release_install(model_zip_path):1010    model_zip = ReleasePacker("", "")1011    model_zip.unpack(model_zip_path)1012    for file in os.listdir("release_packs"):1013        if file.endswith(".txt"):1014            install_txt = os.path.join("release_packs", file)1015            break1016    else:1017        model_zip.remove_temp("release_packs")1018        return "非格式化安装包,无法安装"1019    _spk = model_zip.formatted_install(install_txt)1020    model_zip.remove_temp("release_packs")1021    return f"安装成功,可用说话人{_spk},请启用独立目录模式加载模型"1022 1023#read default params1024sovits_params, diff_params, second_dir_enable = get_default_settings()1025ckpt_read_dir = second_dir if second_dir_enable else workdir1026config_read_dir = second_dir if second_dir_enable else config_dir1027diff_read_dir = diff_second_dir if second_dir_enable else diff_workdir1028current_mode = get_current_mode()1029 1030# create dirs if they don't exist1031dirs_to_check = [1032    workdir,1033    second_dir,1034    diff_workdir,1035    diff_second_dir,1036    dataset_dir,1037]1038for dir in dirs_to_check:1039    if not os.path.exists(dir):1040        os.makedirs(dir)1041 1042# read ckpt list1043ckpt_list, config_list, cluster_list, diff_list, diff_config_list = load_options()1044 1045# read available encoder list1046encoder_list = get_available_encoder()1047 1048#read GPU info1049ngpu=torch.cuda.device_count()1050gpu_infos=[]1051if(torch.cuda.is_available() is False or ngpu==0):1052    if_gpu_ok=False1053else:1054    if_gpu_ok = False1055    for i in range(ngpu):1056        gpu_name=torch.cuda.get_device_name(i)1057        if("MX"in gpu_name):1058            continue1059        if("RTX" in gpu_name.upper() or "10"in gpu_name or "16"in gpu_name or "20"in gpu_name or "30"in gpu_name or "40"in gpu_name or "A50"in gpu_name.upper() or "70"in gpu_name or "80"in gpu_name or "90"in gpu_name or "M4"in gpu_name or"P4"in gpu_name or "T4"in gpu_name or "TITAN"in gpu_name.upper()):#A10#A100#V100#A40#P40#M40#K801060            if_gpu_ok=True#至少有一张能用的N卡1061            gpu_infos.append("%s\t%s"%(i,gpu_name))1062gpu_info="\n".join(gpu_infos)if if_gpu_ok is True and len(gpu_infos)>0 else "很遗憾您这没有能用的显卡来支持您训练"1063gpus="-".join([i[0]for i in gpu_infos])1064 1065#read cuda info for inference1066cuda = {}1067if torch.cuda.is_available():1068    for i in range(torch.cuda.device_count()):1069        device_name = torch.cuda.get_device_properties(i).name1070        cuda[f"CUDA:{i} {device_name}"] = f"cuda:{i}"1071 1072#Check BF16 support1073amp_options = ["fp32", "fp16", "bf16"] if torch.cuda.is_bf16_supported() else ["fp32", "fp16"]1074 1075#Get F0 Options1076f0_options = ["crepe","pm","dio","harvest","rmvpe"] if os.path.exists("pretrain/rmvpe.pt") else ["crepe","pm","dio","harvest"]1077 1078app = gr.Blocks()1079with app:1080    gr.Markdown(value="""1081        ### So-VITS-SVC 4.1-Stable WebUI 推理&训练 v2.3.81082                1083        制作协力:bilibili@麦哲云1084 1085        仅供个人娱乐和非商业用途,禁止用于血腥、暴力、性相关、政治相关内容1086 1087        [使用文档和常见报错解答](https://www.yuque.com/umoubuton/ueupp5)1088 1089        整合包作者:bilibili@羽毛布団 | 技术交流群:742817595 | 交流二群:168254971 | 交流三群:4166561751090 1091        """)1092    with gr.Tabs():1093        with gr.TabItem("推理") as inference_tab:1094            mode_caption = gr.Markdown(value=f"""1095                {current_mode},可在页面底端切换模式1096            """)1097            with gr.Row():1098                choice_ckpt = gr.Dropdown(label="模型选择", choices=ckpt_list, value="no_model")1099                model_branch = gr.Textbox(label="模型编码器", placeholder="请先选择模型", interactive=False)1100            with gr.Row():1101                config_choice = gr.Dropdown(label="配置文件", choices=config_list, value="no_config")1102                config_info = gr.Textbox(label="配置文件编码器", placeholder="请选择配置文件")1103            gr.Markdown(value="""**请检查模型和配置文件的编码器是否匹配**""")1104            with gr.Row():1105                diff_choice = gr.Dropdown(label="(可选)选择扩散模型", choices=diff_list, value="no_diff", interactive=True)1106                diff_config_choice = gr.Dropdown(label="扩散模型配置文件", choices=diff_config_list, value="no_diff_config", interactive=True)1107            cluster_choice = gr.Dropdown(label="(可选)选择聚类模型/特征检索模型", choices=cluster_list, value="no_clu")1108            refresh = gr.Button("刷新选项")1109            with gr.Row():1110                enhance = gr.Checkbox(label="是否使用NSF_HIFIGAN增强,该选项对部分训练集少的模型有一定的音质增强效果,但是对训练好的模型有反面效果,默认关闭", value=False)1111                only_diffusion = gr.Checkbox(label="是否使用全扩散推理,开启后将不使用So-VITS模型,仅使用扩散模型进行完整扩散推理,不建议使用", value=False)1112            with gr.Row():1113                diffusion_method = gr.Dropdown(label="扩散模型采样器", choices=["dpm-solver++","dpm-solver","pndm","ddim","unipc"], value="dpm-solver")1114                diffusion_speedup = gr.Number(label="扩散加速倍数,默认为10倍", value=10)1115            using_device = gr.Dropdown(label="推理设备,默认为自动选择", choices=["Auto",*cuda.keys(),"cpu"], value="Auto")1116            with gr.Row():1117                loadckpt = gr.Button("加载模型", variant="primary")1118                unload = gr.Button("卸载模型", variant="primary")1119            with gr.Row():1120                model_message = gr.Textbox(label="Output Message")1121                sid = gr.Dropdown(label="So-VITS说话人", value="speaker0")1122            1123            inference_tab.select(refresh_options,[],[choice_ckpt,config_choice,cluster_choice,diff_choice,diff_config_choice])1124            choice_ckpt.change(auto_load, [choice_ckpt], [model_branch, config_choice, config_info])  1125            config_choice.change(load_json_encoder, [config_choice, choice_ckpt], [config_info])1126            diff_choice.change(auto_load_diff, [diff_choice], [diff_config_choice])1127            refresh.click(refresh_options,[],[choice_ckpt,config_choice,cluster_choice,diff_choice,diff_config_choice,mode_caption])1128 1129            gr.Markdown(value="""1130                请稍等片刻,模型加载大约需要10秒。后续操作不需要重新加载模型1131                """)1132            with gr.Tabs():1133                with gr.TabItem("单个音频上传"):1134                    vc_input3 = gr.Audio(label="单个音频上传", type="filepath")1135                with gr.TabItem("批量音频上传"):1136                    vc_batch_files = gr.Files(label="批量音频上传", file_types=["audio"], file_count="multiple")1137                with gr.TabItem("文字转语音"):1138                    gr.Markdown("""1139                        文字转语音(TTS)说明:使用edge_tts服务生成音频,并转换为So-VITS模型音色。1140                    """)1141                    text_input = gr.Textbox(label = "在此输入需要转译的文字(建议打开自动f0预测)",)1142                    with gr.Row():1143                        tts_gender = gr.Radio(label = "说话人性别", choices = ["男","女"], value = "男")1144                        tts_lang = gr.Dropdown(label = "选择语言,Auto为根据输入文字自动识别", choices=SUPPORTED_LANGUAGES, value = "Auto")1145                    with gr.Row():1146                        tts_rate = gr.Slider(label = "TTS语音变速(倍速相对值)", minimum = -1, maximum = 3, value = 0, step = 0.1)1147                        tts_volume = gr.Slider(label = "TTS语音音量(相对值)", minimum = -1, maximum = 1.5, value = 0, step = 0.1)1148 1149            with gr.Row():1150                auto_f0 = gr.Checkbox(label="自动f0预测,配合聚类模型f0预测效果更好,会导致变调功能失效(仅限转换语音,歌声不要勾选此项会跑调)", value=False)1151                f0_predictor = gr.Radio(label="f0预测器选择(如遇哑音可以更换f0预测器解决,crepe为原F0使用均值滤波器)", choices=f0_options, value="pm")1152                cr_threshold = gr.Number(label="F0过滤阈值,只有使用crepe时有效. 数值范围从0-1. 降低该值可减少跑调概率,但会增加哑音", value=0.05)1153            with gr.Row():1154                vc_transform = gr.Number(label="变调(整数,可以正负,半音数量,升高八度就是12)", value=0)1155                cluster_ratio = gr.Number(label="聚类模型/特征检索混合比例,0-1之间,默认为0不启用聚类或特征检索,能提升音色相似度,但会导致咬字下降", value=0)1156                k_step = gr.Slider(label="浅扩散步数,只有使用了扩散模型才有效,步数越大越接近扩散模型的结果", value=100, minimum = 1, maximum = 1000)1157            with gr.Row():1158                output_format = gr.Radio(label="音频输出格式", choices=["wav", "flac", "mp3"], value = "wav")1159                enhancer_adaptive_key = gr.Number(label="使NSF-HIFIGAN增强器适应更高的音域(单位为半音数)|默认为0", value=0)1160                slice_db = gr.Number(label="切片阈值", value=-50)1161                cl_num = gr.Number(label="音频自动切片,0为按默认方式切片,单位为秒/s,爆显存可以设置此处强制切片", value=0)1162            with gr.Accordion("高级设置(一般不需要动)", open=False):1163                noise_scale = gr.Number(label="noise_scale 建议不要动,会影响音质,玄学参数", value=0.4)1164                pad_seconds = gr.Number(label="推理音频pad秒数,由于未知原因开头结尾会有异响,pad一小段静音段后就不会出现", value=0.5)1165                lg_num = gr.Number(label="两端音频切片的交叉淡入长度,如果自动切片后出现人声不连贯可调整该数值,如果连贯建议采用默认值0,注意,该设置会影响推理速度,单位为秒/s", value=1)1166                lgr_num = gr.Number(label="自动音频切片后,需要舍弃每段切片的头尾。该参数设置交叉长度保留的比例,范围0-1,左开右闭", value=0.75)1167                second_encoding = gr.Checkbox(label = "二次编码,浅扩散前会对原始音频进行二次编码,玄学选项,效果时好时差,默认关闭", value=False)1168                loudness_envelope_adjustment = gr.Number(label="输入源响度包络替换输出响度包络融合比例,越靠近1越使用输出响度包络", value = 0)1169                use_spk_mix = gr.Checkbox(label="动态声线融合,需要手动编辑角色混合轨道,没做完暂时不要开启", value=False, interactive=False)1170            with gr.Row():1171                vc_submit = gr.Button("音频转换", variant="primary")1172                vc_batch_submit = gr.Button("批量转换", variant="primary")1173                vc_tts_submit = gr.Button("文本转语音", variant="primary")1174            vc_output1 = gr.Textbox(label="Output Message")1175            vc_output2 = gr.Audio(label="Output Audio")1176        1177        loadckpt.click(load_model_func,[choice_ckpt,cluster_choice,config_choice,enhance,diff_choice,diff_config_choice,only_diffusion,use_spk_mix,using_device,diffusion_method,diffusion_speedup],[model_message, sid, cl_num, k_step])1178        unload.click(model_empty_cache, [], [sid, model_message])1179        vc_submit.click(vc_fn, [output_format, sid, vc_input3, vc_transform,auto_f0,cluster_ratio, slice_db, noise_scale,pad_seconds,cl_num,lg_num,lgr_num,f0_predictor,enhancer_adaptive_key,cr_threshold,k_step,use_spk_mix,second_encoding,loudness_envelope_adjustment], [vc_output1, vc_output2])1180        vc_batch_submit.click(vc_batch_fn, [output_format, sid, vc_batch_files, vc_transform,auto_f0,cluster_ratio, slice_db, noise_scale,pad_seconds,cl_num,lg_num,lgr_num,f0_predictor,enhancer_adaptive_key,cr_threshold,k_step,use_spk_mix,second_encoding,loudness_envelope_adjustment], [vc_output1])1181        vc_tts_submit.click(tts_fn, [text_input, tts_gender, tts_lang, tts_rate, tts_volume, output_format, sid, vc_transform,auto_f0,cluster_ratio, slice_db, noise_scale,pad_seconds,cl_num,lg_num,lgr_num,f0_predictor,enhancer_adaptive_key,cr_threshold,k_step,use_spk_mix,second_encoding,loudness_envelope_adjustment], [vc_output1, vc_output2])1182 1183 1184        with gr.TabItem("训练"):1185            gr.Markdown(value="""请将数据集文件夹放置在dataset_raw文件夹下,确认放置正确后点击下方获取数据集名称""")1186            raw_dirs_list=gr.Textbox(label="Raw dataset directory(s):")1187            get_raw_dirs=gr.Button("识别数据集", variant="primary")1188            gr.Markdown(value="""确认数据集正确识别后请选择训练使用的特征编码器和f0预测器,**如果要训练扩散模型,请选择Vec768l12或hubertsoft或whisper-ppg,并确保So-VITS和扩散模型使用同一个编码器**""")1189            with gr.Row():1190                gr.Markdown(value="""**vec256l9**: ContentVec(256Layer9),旧版本叫v1,So-VITS-SVC 4.0的基础版本,**不推荐使用**1191                                **vec768l12**: 特征输入更换为ContentVec的第12层Transformer输出,模型理论上会更加还原训练集音色1192                                **hubertsoft**: So-VITS-SVC 3.0使用的编码器,咬字更为准确,但可能存在多说话人音色泄露问题1193                                **whisper-ppg**: 来自OpenAI,咬字最为准确,但和Hubertsoft一样存在多说话人音色泄露,且显存占用和训练时间有明显增加。1194                                解锁更多编码器选项,请见[这里](https://www.yuque.com/umoubuton/ueupp5/kmui02dszo5zrqkz)1195                """)1196                gr.Markdown(value="""**crepe**: 抗噪能力最强,但预处理速度慢(不过如果你的显卡很强的话速度会很快)1197                                **pm**: 预处理速度快,但抗噪能力较弱1198                                **dio**: 先前版本预处理默认使用的f0预测器1199                                **harvest**: 有一定抗噪能力,预处理显存占用友好,速度比较慢1200                """)

Showing the first 1,200 of 1428 lines. Download the file for the rest.