Merge pull request #395 from Paladinium/alltalkbeta_config_refactoring
Adding config classes and tests
This commit is contained in:
9 files changed
+949
-579
No files matched your search
@@ -0,0 +1,317 @@
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import inspect
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from filelock import FileLock
|
||||
from types import SimpleNamespace
|
||||
from dataclasses import dataclass
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Callable, Any, MutableSequence
|
||||
|
||||
|
||||
@dataclass
|
||||
class AlltalkConfigTheme:
|
||||
file: str | None = None
|
||||
clazz = ""
|
||||
|
||||
@dataclass
|
||||
class AlltalkConfigRvcSettings:
|
||||
rvc_enabled = False
|
||||
rvc_char_model_file = ""
|
||||
rvc_narr_model_file = ""
|
||||
split_audio = False
|
||||
autotune = False
|
||||
pitch = 0
|
||||
filter_radius = 0
|
||||
index_rate = 0.0
|
||||
rms_mix_rate = 0
|
||||
protect = 0
|
||||
hop_length = 0
|
||||
f0method = ""
|
||||
embedder_model = ""
|
||||
training_data_size = 0
|
||||
|
||||
@dataclass
|
||||
class AlltalkConfigTgwUi:
|
||||
tgwui_activate_tts = False
|
||||
tgwui_autoplay_tts = False
|
||||
tgwui_narrator_enabled = ""
|
||||
tgwui_non_quoted_text_is = ""
|
||||
tgwui_deepspeed_enabled = False
|
||||
tgwui_language = ""
|
||||
tgwui_lowvram_enabled = False
|
||||
tgwui_pitch_set = 0
|
||||
tgwui_temperature_set = 0.0
|
||||
tgwui_repetitionpenalty_set = 0
|
||||
tgwui_generationspeed_set = 0
|
||||
tgwui_narrator_voice = ""
|
||||
tgwui_show_text = False
|
||||
tgwui_character_voice = ""
|
||||
tgwui_rvc_char_voice = ""
|
||||
tgwui_rvc_narr_voice = ""
|
||||
|
||||
@dataclass
|
||||
class AlltalkConfigApiDef:
|
||||
api_port_number = 0
|
||||
api_allowed_filter = ""
|
||||
api_length_stripping = 0
|
||||
api_max_characters = 0
|
||||
api_use_legacy_api = False
|
||||
api_legacy_ip_address = ""
|
||||
api_text_filtering = ""
|
||||
api_narrator_enabled = ""
|
||||
api_text_not_inside = ""
|
||||
api_language = ""
|
||||
api_output_file_name = ""
|
||||
api_output_file_timestamp = False
|
||||
api_autoplay = False
|
||||
api_autoplay_volume = 0.0
|
||||
|
||||
@dataclass
|
||||
class AlltalkConfigDebug:
|
||||
debug_transcode = False
|
||||
debug_tts = False
|
||||
debug_openai = False
|
||||
debug_concat = False
|
||||
debug_tts_variables = False
|
||||
debug_rvc = False
|
||||
|
||||
@dataclass
|
||||
class AlltalkConfigGradioPages:
|
||||
Generate_Help_page = False
|
||||
Voice2RVC_page = False
|
||||
TTS_Generator_page = False
|
||||
TTS_Engines_Settings_page = False
|
||||
alltalk_documentation_page = False
|
||||
api_documentation_page = False
|
||||
|
||||
|
||||
@dataclass
|
||||
class AlltalkAvailableEngine:
|
||||
name = ""
|
||||
selected_model = ""
|
||||
|
||||
|
||||
class AbstractJsonConfig(ABC):
|
||||
|
||||
def __init__(self, config_path: Path | str, file_check_interval: int):
|
||||
self.__config_path = Path(config_path) if type(config_path) is str else config_path
|
||||
self.__last_read_time = 0 # Track when we last read the file
|
||||
self.__file_check_interval = file_check_interval
|
||||
|
||||
def get_config_path(self):
|
||||
return self.__config_path
|
||||
|
||||
def reload(self):
|
||||
self._load_config()
|
||||
return self
|
||||
|
||||
def to_dict(self):
|
||||
# Remove private fields:
|
||||
without_private_fields = {}
|
||||
for attr, value in self.__dict__.items():
|
||||
if not attr.startswith("_"):
|
||||
without_private_fields[attr] = value
|
||||
return without_private_fields
|
||||
|
||||
def _reload_on_change(self):
|
||||
# Check if config file has been modified and reload if needed
|
||||
if time.time() - self.__last_read_time >= self.__file_check_interval:
|
||||
try:
|
||||
most_recent_modification = self.get_config_path().stat().st_mtime
|
||||
if most_recent_modification > self.__last_read_time:
|
||||
self.reload()
|
||||
except Exception as e:
|
||||
print(f"Error checking config file: {e}")
|
||||
|
||||
def _load_config(self):
|
||||
self.__last_read_time = self.get_config_path().stat().st_mtime
|
||||
def __load():
|
||||
with open(self.get_config_path(), "r") as configfile:
|
||||
data = json.load(configfile, object_hook=self._object_hook())
|
||||
self._handle_loaded_config(data)
|
||||
self.__with_lock_and_backup(self.get_config_path(), False, __load)
|
||||
|
||||
def _object_hook(self) -> Callable[[dict[Any, Any]], Any] | None:
|
||||
return lambda d: SimpleNamespace(**d)
|
||||
|
||||
def _save_file(self, path: Path | None | str, default = lambda o: o.__dict__, indent = 4):
|
||||
file_path = (Path(path) if type(path) is str else path) if path is not None else self.get_config_path()
|
||||
|
||||
def __save():
|
||||
with open(file_path, "w") as file:
|
||||
json.dump(self.to_dict(), file, indent=indent, default=default)
|
||||
self.__with_lock_and_backup(file_path, True, __save)
|
||||
|
||||
def __with_lock_and_backup(self, path: Path, backup: bool, callable: Callable[[], None]):
|
||||
lock_path = path.with_suffix('.lock')
|
||||
try:
|
||||
with FileLock(lock_path):
|
||||
# Create backup:
|
||||
if path.exists() and backup:
|
||||
backup_path = path.with_suffix('.backup')
|
||||
shutil.copy(path, backup_path)
|
||||
|
||||
try:
|
||||
callable()
|
||||
except Exception as e:
|
||||
if backup_path.exists():
|
||||
shutil.copy(backup_path, path)
|
||||
raise Exception(f"Failed to save config: {e}")
|
||||
finally:
|
||||
# Cleanup lock and backup files:
|
||||
lock_path.unlink()
|
||||
if backup and backup_path.exists():
|
||||
backup_path.unlink()
|
||||
|
||||
|
||||
@abstractmethod
|
||||
def _handle_loaded_config(self, data):
|
||||
pass
|
||||
|
||||
class AlltalkNewEnginesConfig(AbstractJsonConfig):
|
||||
__instance = None
|
||||
__this_dir = Path(__file__).parent.resolve()
|
||||
|
||||
def __init__(self, config_path: Path | str = os.path.join(__this_dir, "system", "tts_engines", "new_engines.json")):
|
||||
super().__init__(config_path, 5)
|
||||
self.engines_available: MutableSequence[AlltalkAvailableEngine] = []
|
||||
self._load_config()
|
||||
|
||||
def get_engine_names_available(self):
|
||||
return [engine.name for engine in self.engines_available]
|
||||
|
||||
@staticmethod
|
||||
def get_instance():
|
||||
if AlltalkNewEnginesConfig.__instance is None:
|
||||
AlltalkNewEnginesConfig.__instance = AlltalkNewEnginesConfig()
|
||||
AlltalkNewEnginesConfig.__instance._reload_on_change()
|
||||
return AlltalkNewEnginesConfig.__instance
|
||||
|
||||
def _handle_loaded_config(self, data):
|
||||
self.engines_available = data.engines_available
|
||||
|
||||
def get_engines_matching(self, condition: Callable[[AlltalkAvailableEngine], bool]):
|
||||
return [x for x in self.engines_available if condition(x)]
|
||||
|
||||
|
||||
class AlltalkTTSEnginesConfig(AbstractJsonConfig):
|
||||
__instance = None
|
||||
__this_dir = Path(__file__).parent.resolve()
|
||||
|
||||
def __init__(self, config_path: Path | str = os.path.join(__this_dir, "system", "tts_engines", "tts_engines.json")):
|
||||
super().__init__(config_path, 5)
|
||||
self.engines_available: MutableSequence[AlltalkAvailableEngine] = []
|
||||
self.engine_loaded = ""
|
||||
self.selected_model = ""
|
||||
self._load_config()
|
||||
|
||||
def get_engine_names_available(self):
|
||||
return [engine.name for engine in self.engines_available]
|
||||
|
||||
@staticmethod
|
||||
def get_instance(force_reload = False):
|
||||
if AlltalkTTSEnginesConfig.__instance is None:
|
||||
force_reload = False
|
||||
AlltalkTTSEnginesConfig.__instance = AlltalkTTSEnginesConfig()
|
||||
|
||||
if force_reload:
|
||||
AlltalkTTSEnginesConfig.__instance.reload()
|
||||
else:
|
||||
AlltalkTTSEnginesConfig.__instance._reload_on_change()
|
||||
return AlltalkTTSEnginesConfig.__instance
|
||||
|
||||
def _handle_loaded_config(self, data):
|
||||
# List of the available TTS engines:
|
||||
self.engines_available = self.__handle_loaded_config_engines(data)
|
||||
|
||||
# The currently set TTS engine from tts_engines.json
|
||||
self.engine_loaded = data.engine_loaded
|
||||
self.selected_model = data.selected_model
|
||||
|
||||
def __handle_loaded_config_engines(self, data):
|
||||
available_engines = data.engines_available
|
||||
available_engine_names = [engine.name for engine in available_engines]
|
||||
|
||||
# Getting the engines that are not already part of the available engines:
|
||||
new_engines_config = AlltalkNewEnginesConfig.get_instance()
|
||||
new_engines = new_engines_config.get_engines_matching(lambda eng: eng.name not in available_engine_names)
|
||||
|
||||
# Merge engines:
|
||||
return available_engines + new_engines
|
||||
|
||||
def save(self, path: Path | str | None = None):
|
||||
self._save_file(path)
|
||||
|
||||
def is_valid_engine(self, engine_name):
|
||||
return engine_name in self.get_engine_names_available()
|
||||
|
||||
def change_engine(self, requested_engine):
|
||||
if requested_engine == self.engine_loaded:
|
||||
return self
|
||||
for engine in self.engines_available:
|
||||
if engine.name == requested_engine:
|
||||
self.engine_loaded = requested_engine
|
||||
self.selected_model = engine.selected_model
|
||||
return self
|
||||
return self
|
||||
|
||||
|
||||
class AlltalkConfig(AbstractJsonConfig):
|
||||
__instance = None
|
||||
__this_dir = Path(__file__).parent.resolve()
|
||||
|
||||
def __init__(self, config_path: Path | str = __this_dir / "confignew.json"):
|
||||
super().__init__(config_path, 5)
|
||||
self.branding = ""
|
||||
self.delete_output_wavs = ""
|
||||
self.gradio_interface = False
|
||||
self.output_folder = ""
|
||||
self.gradio_port_number = 0
|
||||
self.firstrun_model = False
|
||||
self.firstrun_splash = False
|
||||
self.launch_gradio = False
|
||||
self.transcode_audio_format = ""
|
||||
self.theme = AlltalkConfigTheme()
|
||||
self.rvc_settings = AlltalkConfigRvcSettings()
|
||||
self.tgwui = AlltalkConfigTgwUi()
|
||||
self.api_def = AlltalkConfigApiDef()
|
||||
self.debugging = AlltalkConfigDebug()
|
||||
self.gradio_pages = AlltalkConfigGradioPages()
|
||||
self._load_config()
|
||||
|
||||
@staticmethod
|
||||
def default_config_path():
|
||||
return AlltalkConfig.__this_dir / "confignew.json"
|
||||
|
||||
@staticmethod
|
||||
def get_instance(force_reload = False):
|
||||
if AlltalkConfig.__instance is None:
|
||||
force_reload = False
|
||||
AlltalkConfig.__instance = AlltalkConfig()
|
||||
|
||||
if force_reload:
|
||||
AlltalkConfig.__instance.reload()
|
||||
else:
|
||||
AlltalkConfig.__instance._reload_on_change()
|
||||
return AlltalkConfig.__instance
|
||||
|
||||
def get_output_directory(self):
|
||||
return self.__this_dir / self.output_folder
|
||||
|
||||
def save(self, path: Path | str | None = None):
|
||||
self._save_file(path)
|
||||
|
||||
def _handle_loaded_config(self, data):
|
||||
# Copy those fields for which there are members in this class:
|
||||
for n, v in inspect.getmembers(data):
|
||||
if hasattr(self, n) and not n.startswith("__"):
|
||||
setattr(self, n, v)
|
||||
|
||||
# Special properties (cannot use 'class' as property name):
|
||||
self.theme.clazz = data.theme.__dict__["class"]
|
||||
|
||||
# As a side effect, create the output directory:
|
||||
self.get_output_directory().mkdir(parents=True, exist_ok=True)
|
||||
+33
-51
@@ -1,18 +1,19 @@
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import shutil
|
||||
import sys
|
||||
import zipfile
|
||||
import requests
|
||||
from tqdm import tqdm
|
||||
from inputimeout import inputimeout, TimeoutOccurred
|
||||
from pathlib import Path
|
||||
|
||||
# Setting the module search path:
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.resolve()))
|
||||
|
||||
from config import AlltalkTTSEnginesConfig, AlltalkConfig
|
||||
|
||||
this_dir = Path(__file__).parent.resolve().parent.resolve().parent.resolve()
|
||||
# File paths
|
||||
config_path = this_dir / 'confignew.json'
|
||||
tts_engines_path = this_dir / 'system/tts_engines/tts_engines.json'
|
||||
new_config_template_path = this_dir / 'system/config/confignew.json'
|
||||
|
||||
def download_file(url, dest_path):
|
||||
response = requests.get(url, stream=True)
|
||||
@@ -60,31 +61,14 @@ def setup_xtts():
|
||||
|
||||
|
||||
|
||||
def update_tts_engines(engine, model):
|
||||
with open(tts_engines_path, 'r') as file:
|
||||
tts_engines = json.load(file)
|
||||
|
||||
tts_engines['engine_loaded'] = engine
|
||||
tts_engines['selected_model'] = model
|
||||
|
||||
with open(tts_engines_path, 'w') as file:
|
||||
json.dump(tts_engines, file, indent=4)
|
||||
def update_tts_engines(engine):
|
||||
AlltalkTTSEnginesConfig.get_instance().change_engine(engine).save()
|
||||
|
||||
def set_firstrun_model_false():
|
||||
with open(config_path, 'r') as file:
|
||||
config = json.load(file)
|
||||
|
||||
config['firstrun_model'] = False
|
||||
|
||||
with open(config_path, 'w') as file:
|
||||
json.dump(config, file, indent=4)
|
||||
config.firstrun_model = False
|
||||
config.save()
|
||||
|
||||
def load_config(file_path):
|
||||
with open(file_path, "r") as config_file:
|
||||
config = json.load(config_file)
|
||||
return config
|
||||
|
||||
def warning_mesasge():
|
||||
def warning_message():
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[93mIf you have you have UPGRADED from v1 ensure you have re-installed\033[0m")
|
||||
print(f"[{branding}TTS] \033[93mthe requirements. Otherwise you will get failures and errors!\033[0m")
|
||||
@@ -92,34 +76,34 @@ def warning_mesasge():
|
||||
print(f"[{branding}TTS] \033[0m'using untested triton version' \033[93mmessages.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
# Load confignew.json
|
||||
with open(config_path, 'r') as file:
|
||||
config = json.load(file)
|
||||
# Load confignew.json (might be version 1 or 2):
|
||||
with open(AlltalkConfig.default_config_path(), 'r') as file:
|
||||
config_json = json.load(file)
|
||||
|
||||
branding = config['branding']
|
||||
branding = config_json['branding']
|
||||
|
||||
# Check if the config file is version 1
|
||||
if "ip_address" in config:
|
||||
if "ip_address" in config_json:
|
||||
print(f"[{branding}TTS] Detected version 1 configuration file.")
|
||||
print(f"[{branding}TTS] Upgrading to version 2 configuration file...")
|
||||
|
||||
# Backup the old configuration file
|
||||
backup_path = config_path + ".backup"
|
||||
shutil.copyfile(config_path, backup_path)
|
||||
backup_path = AlltalkConfig.default_config_path() + ".backup"
|
||||
shutil.copyfile(AlltalkConfig.default_config_path(), backup_path)
|
||||
|
||||
# Copy the new configuration template to replace the old config file
|
||||
shutil.copyfile(new_config_template_path, config_path)
|
||||
new_config_template_path = this_dir / 'system/config/confignew.json'
|
||||
shutil.copyfile(new_config_template_path, AlltalkConfig.default_config_path())
|
||||
|
||||
print(f"[{branding}TTS] Configuration file upgraded successfully.")
|
||||
|
||||
# Reload the new config file
|
||||
with open(config_path, 'r') as file:
|
||||
config = json.load(file)
|
||||
|
||||
config = AlltalkConfig.get_instance()
|
||||
branding = config.branding
|
||||
|
||||
# Check if firstrun_model is true
|
||||
if config.get('firstrun_model', False):
|
||||
if config.firstrun_model:
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[92mThis is the first time startup. Please download a start TTS model. Other TTS engines\033[0m")
|
||||
print(f"[{branding}TTS] \033[92mThis is the first time startup.. Please download a start TTS model. Other TTS engines\033[0m")
|
||||
print(f"[{branding}TTS] \033[92mand TTS models can be downloaded/managed in the Gradio Interface `TTS Engines Settings`\033[0m")
|
||||
print(f"[{branding}TTS] \033[92mtab after inital setup.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
@@ -159,32 +143,30 @@ if config.get('firstrun_model', False):
|
||||
os.makedirs('models/piper', exist_ok=True)
|
||||
os.makedirs('models/vits', exist_ok=True)
|
||||
os.makedirs('models/xtts/', exist_ok=True)
|
||||
update_tts_engines('piper', 'piper')
|
||||
update_tts_engines('piper')
|
||||
set_firstrun_model_false()
|
||||
warning_mesasge()
|
||||
warning_message()
|
||||
exit()
|
||||
|
||||
if user_choice is not None and user_choice.isdigit() and 1 <= int(user_choice) <= len(models):
|
||||
selected_model = models[int(user_choice) - 1]
|
||||
warning_mesasge()
|
||||
warning_message()
|
||||
|
||||
if user_choice is None or user_choice.lower() != 'own':
|
||||
if selected_model['name'] == 'piper':
|
||||
setup_piper()
|
||||
update_tts_engines('piper', 'piper')
|
||||
set_firstrun_model_false()
|
||||
update_tts_engines('piper')
|
||||
elif selected_model['name'] == 'vits':
|
||||
setup_vits()
|
||||
update_tts_engines('vits', 'vits - tts_models--en--vctk--vits')
|
||||
set_firstrun_model_false()
|
||||
update_tts_engines('vits')
|
||||
elif selected_model['name'] == 'xtts':
|
||||
setup_xtts()
|
||||
update_tts_engines('xtts', 'xtts - xttsv2_2.0.3')
|
||||
set_firstrun_model_false()
|
||||
update_tts_engines('xtts')
|
||||
|
||||
print(f"[{branding}TTS] {selected_model['name']} model downloaded and configuration updated successfully.")
|
||||
# Set firstrun_model to false
|
||||
set_firstrun_model_false()
|
||||
warning_mesasge()
|
||||
warning_message()
|
||||
exit()
|
||||
else:
|
||||
exit()
|
||||
@@ -1,18 +1,19 @@
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import shutil
|
||||
import sys
|
||||
import zipfile
|
||||
import requests
|
||||
from tqdm import tqdm
|
||||
from inputimeout import inputimeout, TimeoutOccurred
|
||||
from pathlib import Path
|
||||
|
||||
# Setting the module search path:
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.resolve()))
|
||||
|
||||
from config import AlltalkTTSEnginesConfig, AlltalkConfig
|
||||
|
||||
this_dir = Path(__file__).parent.resolve().parent.resolve().parent.resolve()
|
||||
# File paths
|
||||
config_path = this_dir / 'confignew.json'
|
||||
tts_engines_path = this_dir / 'system/tts_engines/tts_engines.json'
|
||||
new_config_template_path = this_dir / 'system/config/confignew.json'
|
||||
|
||||
def download_file(url, dest_path):
|
||||
response = requests.get(url, stream=True)
|
||||
@@ -60,31 +61,14 @@ def setup_xtts():
|
||||
|
||||
|
||||
|
||||
def update_tts_engines(engine, model):
|
||||
with open(tts_engines_path, 'r') as file:
|
||||
tts_engines = json.load(file)
|
||||
|
||||
tts_engines['engine_loaded'] = engine
|
||||
tts_engines['selected_model'] = model
|
||||
|
||||
with open(tts_engines_path, 'w') as file:
|
||||
json.dump(tts_engines, file, indent=4)
|
||||
def update_tts_engines(engine):
|
||||
AlltalkTTSEnginesConfig.get_instance().change_engine(engine).save()
|
||||
|
||||
def set_firstrun_model_false():
|
||||
with open(config_path, 'r') as file:
|
||||
config = json.load(file)
|
||||
|
||||
config['firstrun_model'] = False
|
||||
|
||||
with open(config_path, 'w') as file:
|
||||
json.dump(config, file, indent=4)
|
||||
config.firstrun_model = False
|
||||
config.save()
|
||||
|
||||
def load_config(file_path):
|
||||
with open(file_path, "r") as config_file:
|
||||
config = json.load(config_file)
|
||||
return config
|
||||
|
||||
def warning_mesasge():
|
||||
def warning_message():
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[93mIf you have you have UPGRADED from v1 ensure you have re-installed\033[0m")
|
||||
print(f"[{branding}TTS] \033[93mthe requirements. Otherwise you will get failures and errors!\033[0m")
|
||||
@@ -92,32 +76,32 @@ def warning_mesasge():
|
||||
print(f"[{branding}TTS] \033[0m'using untested triton version' \033[93mmessages.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
# Load confignew.json
|
||||
with open(config_path, 'r') as file:
|
||||
config = json.load(file)
|
||||
# Load confignew.json (might be version 1 or 2):
|
||||
with open(AlltalkConfig.default_config_path(), 'r') as file:
|
||||
config_json = json.load(file)
|
||||
|
||||
branding = config['branding']
|
||||
branding = config_json['branding']
|
||||
|
||||
# Check if the config file is version 1
|
||||
if "ip_address" in config:
|
||||
if "ip_address" in config_json:
|
||||
print(f"[{branding}TTS] Detected version 1 configuration file.")
|
||||
print(f"[{branding}TTS] Upgrading to version 2 configuration file...")
|
||||
|
||||
# Backup the old configuration file
|
||||
backup_path = config_path + ".backup"
|
||||
shutil.copyfile(config_path, backup_path)
|
||||
backup_path = AlltalkConfig.default_config_path() + ".backup"
|
||||
shutil.copyfile(AlltalkConfig.default_config_path(), backup_path)
|
||||
|
||||
# Copy the new configuration template to replace the old config file
|
||||
shutil.copyfile(new_config_template_path, config_path)
|
||||
new_config_template_path = this_dir / 'system/config/confignew.json'
|
||||
shutil.copyfile(new_config_template_path, AlltalkConfig.default_config_path())
|
||||
|
||||
print(f"[{branding}TTS] Configuration file upgraded successfully.")
|
||||
|
||||
# Reload the new config file
|
||||
with open(config_path, 'r') as file:
|
||||
config = json.load(file)
|
||||
|
||||
config = AlltalkConfig.get_instance()
|
||||
branding = config.branding
|
||||
|
||||
# Check if firstrun_model is true
|
||||
if config.get('firstrun_model', False):
|
||||
if config.firstrun_model:
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[92mThis is the first time startup. Please download a start TTS model.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
@@ -157,30 +141,30 @@ if config.get('firstrun_model', False):
|
||||
os.makedirs('models/piper', exist_ok=True)
|
||||
os.makedirs('models/vits', exist_ok=True)
|
||||
os.makedirs('models/xtts/', exist_ok=True)
|
||||
update_tts_engines('piper', 'piper')
|
||||
update_tts_engines('piper')
|
||||
set_firstrun_model_false()
|
||||
warning_mesasge()
|
||||
warning_message()
|
||||
exit()
|
||||
|
||||
if user_choice is not None and user_choice.isdigit() and 1 <= int(user_choice) <= len(models):
|
||||
selected_model = models[int(user_choice) - 1]
|
||||
warning_mesasge()
|
||||
warning_message()
|
||||
|
||||
if user_choice is None or user_choice.lower() != 'own':
|
||||
if selected_model['name'] == 'piper':
|
||||
setup_piper()
|
||||
update_tts_engines('piper', 'piper')
|
||||
update_tts_engines('piper')
|
||||
elif selected_model['name'] == 'vits':
|
||||
setup_vits()
|
||||
update_tts_engines('vits', 'vits - tts_models--en--vctk--vits')
|
||||
update_tts_engines('vits')
|
||||
elif selected_model['name'] == 'xtts':
|
||||
setup_xtts()
|
||||
update_tts_engines('xtts', 'xtts - xttsv2_2.0.3')
|
||||
update_tts_engines('xtts')
|
||||
|
||||
print(f"[{branding}TTS] {selected_model['name']} model downloaded and configuration updated successfully.")
|
||||
# Set firstrun_model to false
|
||||
set_firstrun_model_false()
|
||||
warning_mesasge()
|
||||
warning_message()
|
||||
exit()
|
||||
else:
|
||||
exit()
|
||||
@@ -1,15 +1,12 @@
|
||||
import os
|
||||
import json
|
||||
import pathlib as Path
|
||||
import gradio as gr
|
||||
|
||||
from config import AlltalkConfig
|
||||
|
||||
|
||||
def modify_config():
|
||||
config_file = os.path.join("confignew.json")
|
||||
with open(config_file, "r") as f:
|
||||
config = json.load(f)
|
||||
config["firstrun_splash"] = False
|
||||
with open(config_file, "w") as f:
|
||||
json.dump(config, f, indent=4)
|
||||
config = AlltalkConfig.get_instance()
|
||||
config.firstrun_splash = False
|
||||
config.save()
|
||||
return f"Welcome screen is disabled."
|
||||
|
||||
def alltalk_welcome(analytics_enabled=False):
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
coqui-tts>=0.24.3
|
||||
faster-whisper>=1.0.0
|
||||
filelock>=3.16.1
|
||||
fuzzywuzzy
|
||||
gradio==4.32.2
|
||||
importlib_metadata>=7.1.0
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
coqui-tts>=0.24.3
|
||||
filelock>=3.16.1
|
||||
fuzzywuzzy>=0.18.0
|
||||
gradio>=4.44.1
|
||||
importlib_metadata>=7.2.1
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
coqui-tts>=0.24.3
|
||||
filelock>=3.16.1
|
||||
fuzzywuzzy>=0.18.0
|
||||
importlib_metadata>=7.1.0
|
||||
inputimeout>=1.0.4
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
import os.path
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from config import AlltalkConfig, AlltalkTTSEnginesConfig, AlltalkNewEnginesConfig
|
||||
|
||||
|
||||
class TestAlltalkConfig(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.config = AlltalkConfig.get_instance()
|
||||
self.config.reload()
|
||||
|
||||
def test_default_config_path(self):
|
||||
expected_config_path = Path(__file__).parent.parent.resolve() / "confignew.json"
|
||||
self.assertEqual(self.config.get_config_path(), expected_config_path)
|
||||
self.assertEqual(AlltalkConfig.default_config_path(), expected_config_path)
|
||||
|
||||
def test_branding(self):
|
||||
self.assertEqual(self.config.branding, "AllTalk ")
|
||||
|
||||
def test_delete_output_wavs(self):
|
||||
self.assertEqual(self.config.delete_output_wavs, "Disabled")
|
||||
|
||||
def test_gradio_interface(self):
|
||||
self.assertTrue(self.config.gradio_interface)
|
||||
|
||||
def test_output_folder(self):
|
||||
self.assertEqual(self.config.output_folder, "outputs")
|
||||
# Testing the side effect of creating the output folder:
|
||||
output_folder = Path(__file__).parent.parent.resolve() / self.config.output_folder
|
||||
self.assertTrue(output_folder.exists())
|
||||
|
||||
def test_gradio_port_number(self):
|
||||
self.assertEqual(self.config.gradio_port_number, 7852)
|
||||
|
||||
def test_firstrun_model(self):
|
||||
self.assertTrue(self.config.firstrun_model)
|
||||
|
||||
def test_firstrun_splash(self):
|
||||
self.assertTrue(self.config.firstrun_splash)
|
||||
|
||||
def test_launch_gradio(self):
|
||||
self.assertTrue(self.config.launch_gradio)
|
||||
|
||||
def test_transcode_audio_format(self):
|
||||
self.assertEqual(self.config.transcode_audio_format, "Disabled")
|
||||
|
||||
def test_theme(self):
|
||||
self.assertEqual(self.config.theme.file, None)
|
||||
self.assertEqual(self.config.theme.clazz, "gradio/base")
|
||||
|
||||
def test_rvc_settings(self):
|
||||
self.assertFalse(self.config.rvc_settings.rvc_enabled)
|
||||
self.assertEqual(self.config.rvc_settings.rvc_char_model_file, "Disabled")
|
||||
self.assertEqual(self.config.rvc_settings.rvc_narr_model_file, "Disabled")
|
||||
self.assertTrue(self.config.rvc_settings.split_audio)
|
||||
self.assertEqual(self.config.rvc_settings.pitch, 0)
|
||||
self.assertEqual(self.config.rvc_settings.filter_radius, 3)
|
||||
self.assertEqual(self.config.rvc_settings.index_rate, 0.75)
|
||||
self.assertEqual(self.config.rvc_settings.rms_mix_rate, 1)
|
||||
self.assertEqual(self.config.rvc_settings.protect, 0.5)
|
||||
self.assertEqual(self.config.rvc_settings.hop_length, 130)
|
||||
self.assertEqual(self.config.rvc_settings.f0method, "fcpe")
|
||||
self.assertEqual(self.config.rvc_settings.embedder_model, "hubert")
|
||||
self.assertEqual(self.config.rvc_settings.training_data_size, 45000)
|
||||
|
||||
def test_tgwui(self):
|
||||
self.assertTrue(self.config.tgwui.tgwui_activate_tts)
|
||||
self.assertTrue(self.config.tgwui.tgwui_autoplay_tts)
|
||||
self.assertEqual(self.config.tgwui.tgwui_narrator_enabled, "false")
|
||||
self.assertEqual(self.config.tgwui.tgwui_non_quoted_text_is, "character")
|
||||
self.assertFalse(self.config.tgwui.tgwui_deepspeed_enabled)
|
||||
self.assertEqual(self.config.tgwui.tgwui_language, "English")
|
||||
self.assertFalse(self.config.tgwui.tgwui_lowvram_enabled)
|
||||
self.assertEqual(self.config.tgwui.tgwui_pitch_set, 0)
|
||||
self.assertEqual(self.config.tgwui.tgwui_temperature_set, 0.75)
|
||||
self.assertEqual(self.config.tgwui.tgwui_repetitionpenalty_set, 10)
|
||||
self.assertEqual(self.config.tgwui.tgwui_generationspeed_set, 1)
|
||||
self.assertEqual(self.config.tgwui.tgwui_narrator_voice, "female_01.wav")
|
||||
self.assertTrue(self.config.tgwui.tgwui_show_text)
|
||||
self.assertEqual(self.config.tgwui.tgwui_character_voice, "female_01.wav")
|
||||
self.assertEqual(self.config.tgwui.tgwui_rvc_char_voice, "Disabled")
|
||||
self.assertEqual(self.config.tgwui.tgwui_rvc_narr_voice, "Disabled")
|
||||
|
||||
def test_api_def(self):
|
||||
self.assertEqual(self.config.api_def.api_port_number, 7851)
|
||||
self.assertIn("a-zA-Z0-9", self.config.api_def.api_allowed_filter)
|
||||
self.assertEqual(self.config.api_def.api_length_stripping, 3)
|
||||
self.assertEqual(self.config.api_def.api_max_characters, 2000)
|
||||
self.assertFalse(self.config.api_def.api_use_legacy_api)
|
||||
self.assertEqual(self.config.api_def.api_legacy_ip_address, "127.0.0.1")
|
||||
self.assertEqual(self.config.api_def.api_text_filtering, "standard")
|
||||
self.assertEqual(self.config.api_def.api_narrator_enabled, "false")
|
||||
self.assertEqual(self.config.api_def.api_text_not_inside, "character")
|
||||
self.assertEqual(self.config.api_def.api_language, "en")
|
||||
self.assertEqual(self.config.api_def.api_output_file_name, "myoutputfile")
|
||||
self.assertTrue(self.config.api_def.api_output_file_timestamp)
|
||||
self.assertFalse(self.config.api_def.api_autoplay)
|
||||
self.assertEqual(self.config.api_def.api_autoplay_volume, 0.5)
|
||||
|
||||
def test_debugging(self):
|
||||
self.assertFalse(self.config.debugging.debug_transcode)
|
||||
self.assertFalse(self.config.debugging.debug_tts)
|
||||
self.assertFalse(self.config.debugging.debug_openai)
|
||||
self.assertFalse(self.config.debugging.debug_concat)
|
||||
self.assertFalse(self.config.debugging.debug_tts_variables)
|
||||
self.assertFalse(self.config.debugging.debug_rvc)
|
||||
|
||||
def test_gradio_pages(self):
|
||||
self.assertTrue(self.config.gradio_pages.Generate_Help_page)
|
||||
self.assertTrue(self.config.gradio_pages.Voice2RVC_page)
|
||||
self.assertTrue(self.config.gradio_pages.TTS_Generator_page)
|
||||
self.assertTrue(self.config.gradio_pages.TTS_Engines_Settings_page)
|
||||
self.assertTrue(self.config.gradio_pages.alltalk_documentation_page)
|
||||
self.assertTrue(self.config.gradio_pages.api_documentation_page)
|
||||
|
||||
def test_save_config(self):
|
||||
with tempfile.NamedTemporaryFile(suffix=".json") as tmp:
|
||||
self.config.branding = "foo"
|
||||
self.config.save(tmp.name)
|
||||
new_config = AlltalkConfig(tmp.name)
|
||||
self.assertEqual(new_config.branding, "foo")
|
||||
|
||||
def test_no_private_fields(self):
|
||||
for attr in self.config.to_dict().keys():
|
||||
self.assertTrue(not attr.startswith("_"))
|
||||
|
||||
class TestAlltalkTTSEnginesConfig(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.tts_engines_config = AlltalkTTSEnginesConfig.get_instance()
|
||||
self.tts_engines_config.reload()
|
||||
|
||||
def test_tts_engines(self):
|
||||
self.assertEqual(self.tts_engines_config.engine_loaded, "piper")
|
||||
self.assertEqual(self.tts_engines_config.selected_model, "piper")
|
||||
self.assertListEqual(self.tts_engines_config.get_engine_names_available(), ["parler", "piper", "vits", "xtts", "f5tts"])
|
||||
|
||||
def test_is_valid_engine(self):
|
||||
for engine in ["parler", "piper", "vits", "xtts", "f5tts"]:
|
||||
self.assertTrue(self.tts_engines_config.is_valid_engine(engine))
|
||||
|
||||
self.assertFalse(self.tts_engines_config.is_valid_engine("foo"))
|
||||
|
||||
def test_change_tts_engine(self):
|
||||
self.tts_engines_config.change_engine("vits")
|
||||
self.assertEqual(self.tts_engines_config.engine_loaded, "vits")
|
||||
self.assertEqual(self.tts_engines_config.selected_model, "vits - tts_models--en--vctk--vits")
|
||||
|
||||
def test_tts_engines_default_config_path(self):
|
||||
expected_config_path = os.path.join(Path(__file__).parent.parent.resolve(), "system", "tts_engines", "tts_engines.json")
|
||||
self.assertEqual(self.tts_engines_config.get_config_path(), Path(expected_config_path))
|
||||
|
||||
def test_tts_engines_save(self):
|
||||
with tempfile.NamedTemporaryFile(suffix=".json") as tmp:
|
||||
self.tts_engines_config.engine_loaded = "foo"
|
||||
self.tts_engines_config.save(tmp.name)
|
||||
new_config = AlltalkTTSEnginesConfig(tmp.name)
|
||||
self.assertEqual(new_config.engine_loaded, "foo")
|
||||
self.assertListEqual(new_config.get_engine_names_available(), ["parler", "piper", "vits", "xtts", "f5tts"])
|
||||
self.assertEqual(len(new_config.engines_available), len(new_config.get_engine_names_available()))
|
||||
|
||||
def test_merge_with_new_engines(self):
|
||||
with tempfile.NamedTemporaryFile(suffix=".json") as tmp:
|
||||
self.tts_engines_config.engines_available = []
|
||||
self.assertListEqual(self.tts_engines_config.get_engine_names_available(), [])
|
||||
|
||||
self.tts_engines_config.save(tmp.name)
|
||||
|
||||
new_config = AlltalkTTSEnginesConfig(tmp.name)
|
||||
self.assertEqual(new_config.get_engine_names_available(), ["parler", "xtts", "f5tts"])
|
||||
self.assertEqual(len(new_config.engines_available), len(new_config.get_engine_names_available()))
|
||||
|
||||
def test_no_private_fields(self):
|
||||
for attr in self.tts_engines_config.to_dict().keys():
|
||||
self.assertTrue(not attr.startswith("_"))
|
||||
|
||||
|
||||
class TestAlltalkNewEnginesConfig(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.new_engines_config = AlltalkNewEnginesConfig.get_instance()
|
||||
self.new_engines_config.reload()
|
||||
|
||||
def test_engine_names(self):
|
||||
self.assertListEqual(self.new_engines_config.get_engine_names_available(), ["parler", "xtts", "f5tts"])
|
||||
|
||||
def test_get_engine_names_matching(self):
|
||||
result = self.new_engines_config.get_engines_matching(lambda x: "tts" in x.name)
|
||||
self.assertEqual(len(result), 2)
|
||||
|
||||
def test_no_private_fields(self):
|
||||
for attr in self.new_engines_config.to_dict().keys():
|
||||
self.assertTrue(not attr.startswith("_"))
|
||||
+363
-472
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user