Merge pull request #395 from Paladinium/alltalkbeta_config_refactoring

Adding config classes and tests
This commit is contained in:
erew123 authored and GitHub committed 2024-11-18 22:25:28 +00:00
commit eea4bbf4da
9 files changed
+949 -579

No files matched your search

+317
View File
@@ -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
View File
@@ -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()
+31 -47
View File
@@ -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()
+6 -9
View File
@@ -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
+196
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff