import tomli import os import sys import tempfile from fastapi import HTTPException from structlog import get_logger import bark from glob import glob log = get_logger(__name__) def parse_config(): """Parse and validate config on startup Raise errors for invalid config Set defaults for undefined config options """ config = { "rvc": {}, "tts": {}, } config_file = None try: with open("config.toml", mode="rb") as fp: config_file = tomli.load(fp) except FileNotFoundError: log.error("FAILURE TO START. Configuration file \"config.toml\" was not found") sys.exit(1) try: if config_file["rvc"]["model_dir"]: rvc_model_dir = config_file["rvc"]["model_dir"] if not os.path.isdir(rvc_model_dir): log.error(f"FAILURE TO START. Config item \"rvc.model_dir\" was defined but path \"{rvc_model_dir}\" was not found") log.info(f"Remove config item \"rvc.model_dir\" from \"config.toml\" if you don't want to use RVC models") sys.exit(1) else: config["rvc"]["model_dir"] = config_file["rvc"]["model_dir"] except KeyError: config["rvc"]["model_dir"] = False log.warn(f"Config item \"rvc.model_dir\" is missing from config file. RVC features are disabled") try: if config_file["rvc"]["bark_voice_map"]: if not config["rvc"]["model_dir"]: log.error(f"FAILURE TO START. Config item \"rvc.bark_voice_map\" was defined but \"rvc.model_dir\" was not") log.info(f"Config item \"rvc.model_dir\" is required to use RVC models. Either set this value or remove \"rvc.bark_voice_map\"") sys.exit(1) config["rvc"]["bark_voice_map"] = config_file["rvc"]["bark_voice_map"] except KeyError: # Suno Favourite from voice Bark Speaker Library (v2) config["rvc"]["bark_voice_map"] = {"default": "v2/en_speaker_6"} log.warn("Config item \"rvc.bark_voice_map\" is undefined. Setting \"v2/en_speaker_6\" for all RVC models") try: temp = config_file["tts"]["output_dir"] if temp: if not os.path.isdir(temp): log.error(f"FAILURE TO START. Config item \"tts.output_dir\" was defined but path \"{temp}\" was not found") log.info(f"Either remove config item \"tts.output_dir\" from \"config.toml\" to use system default temp dir, or set the value as an existing directory path") sys.exit(1) else: config["tts"]["output_dir"] = config_file["tts"]["output_dir"] except KeyError: temp_dir = tempfile.gettempdir() config["tts"]["output_dir"] = temp_dir log.warn(f"Config item \"tts.output_dir\" is undefined. Using system default: {temp_dir}") log.info(f"STARTUP CONFIG: {config}") return config # Return list of relative paths for input of list of paths and start path def relative_bark_paths(paths, start_path): p = [] for i in paths: p += [os.path.relpath(os.path.splitext(i)[0], start_path)] return p def load_speakers(config): """Load all available speakers on system. Including Bark voices and RVC models """ # Get bark voices from bark package files bark_voice_dir = os.path.join(bark.__path__[0], "assets/prompts") if not os.path.isdir(bark_voice_dir): log.error(f"FAILURE TO START. Bark voice directory was not found at {bark_voice_dir}") sys.exit(1) voices_full_path = glob(os.path.join(bark_voice_dir, "**", f"*.npz"), recursive=True) bark_voices = relative_bark_paths(voices_full_path, bark_voice_dir) if not bark_voices: log.error(f"FAILURE TO START. No Bark speaker npz files were found in a recursive search of existing directory {bark_voice_dir}. Bark speakers are required") sys.exit(1) # Get RVC models rvc_model_dir = config["rvc"]["model_dir"] rvc_speakers = {} if rvc_model_dir: rvc_full_path = glob(os.path.join(rvc_model_dir, f"**", "*.pth"), recursive=True) for s in rvc_full_path: id = os.path.relpath(s, rvc_model_dir) name = os.path.split(id)[0] dir = os.path.dirname(s) index = [os.path.join(dir, f) for f in os.listdir(dir) if f.endswith(".index")] if len(index) != 1: log.error(f"FAILURE TO START. RVC model {name} should have 1 index file. It has {len(index)}") sys.exit(1) index_relative = os.path.relpath( index[0], rvc_model_dir ) try: bv = config["rvc"]["bark_voice_map"][name] except KeyError: bv = config["rvc"]["bark_voice_map"]["default"] rvc_speakers[name] = {"id": id, "bark_voice": bv, "index": index_relative} if not rvc_speakers: log.error(f"FAILURE TO START. No RVC model files were found in a recursive search of the defined and existing {rvc_model_dir}") log.info(f"You must supply any RVC models you wish to use. Either remove or fix the config item \"rvc.model_dir\"") sys.exit(1) return bark_voices, rvc_speakers config = parse_config() bark_voices, rvc_speakers = load_speakers(config)