Merge pull request #417 from erew123/configrework

AllTalk Version 2 Complete
This commit is contained in:
erew123 authored and GitHub committed 2024-11-24 11:59:55 +00:00
commit eef198eae1
69 files changed
+18421 -7054

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
name: Python CI
on: [push, pull_request]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11.9
uses: actions/setup-python@v3
if: ${{ hashFiles('./test') != '' }}
with:
python-version: "3.11.9"
- name: Install dependencies
if: ${{ hashFiles('./test') != '' }}
run: |
python -m pip install --upgrade pip
if [ -f system/requirements/requirements_unit_test.txt ]; then
pip install -r system/requirements/requirements_unit_test.txt;
fi
- name: Test with pytest
if: ${{ hashFiles('./test') != '' }}
run: |
pytest test --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html
- name: Surface failing tests
if: always()
uses: pmeier/pytest-results-action@v0.6.0
with:
# A list of JUnit XML files, directories containing the former, and wildcard
# patterns to process.
# See @actions/glob for supported patterns.
path: junit/test-results.xml
# (Optional) Add a summary of the results at the top of the report
summary: true
# (Optional) Select which results should be included in the report.
# Follows the same syntax as `pytest -r`
display-options: fEX
# (Optional) Fail the workflow if no JUnit XML was found.
fail-on-empty: false
# (Optional) Title of the test results section in the workflow summary
title: Test results
+1 -1
View File
@@ -495,7 +495,7 @@ echo.
:update_gradio :update_gradio
echo ** Updating Gradio ** echo ** Updating Gradio **
pip install --upgrade gradio==4.32.2 pip install --upgrade gradio==4.44.1
echo. echo.
if errorlevel 1 ( if errorlevel 1 (
echo Gradio update failed, errorlevel was %errorlevel%. There should be an error echo Gradio update failed, errorlevel was %errorlevel%. There should be an error
+1 -1
View File
@@ -392,7 +392,7 @@ install_custom_standalone() {
echo echo
pip install -r system/requirements/requirements_standalone.txt pip install -r system/requirements/requirements_standalone.txt
curl -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-14.0/deepspeed-0.14.2+cu121torch2.2-cp311-cp311-manylinux_2_24_x86_64.whl curl -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-14.0/deepspeed-0.14.2+cu121torch2.2-cp311-cp311-manylinux_2_24_x86_64.whl
pip install --upgrade gradio==4.32.2 pip install --upgrade gradio==4.44.1
echo Installing DeepSpeed... echo Installing DeepSpeed...
pip install deepspeed-0.14.2+cu121torch2.2-cp311-cp311-manylinux_2_24_x86_64.whl pip install deepspeed-0.14.2+cu121torch2.2-cp311-cp311-manylinux_2_24_x86_64.whl
rm deepspeed-0.14.2+cu121torch2.2-cp311-cp311-manylinux_2_24_x86_64.whl rm deepspeed-0.14.2+cu121torch2.2-cp311-cp311-manylinux_2_24_x86_64.whl
+413
View File
@@ -0,0 +1,413 @@
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: bool = False
rvc_char_model_file: str = "Disabled"
rvc_narr_model_file: str = "Disabled"
split_audio: bool = True
autotune: bool = False
pitch: int = 0
filter_radius: int = 3
index_rate: float = 0.75
rms_mix_rate: int = 1
protect: float = 0.5
hop_length: int = 130
f0method: str = "fcpe"
embedder_model: str = "hubert"
training_data_size: int = 45000
@dataclass
class AlltalkConfigTgwUi:
tgwui_activate_tts: bool = True
tgwui_autoplay_tts: bool = True
tgwui_narrator_enabled: str = "false"
tgwui_non_quoted_text_is: str = "character"
tgwui_deepspeed_enabled: bool = False
tgwui_language: str = "English"
tgwui_lowvram_enabled: bool = False
tgwui_pitch_set: int = 0
tgwui_temperature_set: float = 0.75
tgwui_repetitionpenalty_set: int = 10
tgwui_generationspeed_set: int = 1
tgwui_narrator_voice: str = "female_01.wav"
tgwui_show_text: bool = True
tgwui_character_voice: str = "female_01.wav"
tgwui_rvc_char_voice: str = "Disabled"
tgwui_rvc_char_pitch: int = 0
tgwui_rvc_narr_voice: str = "Disabled"
tgwui_rvc_narr_pitch: int = 0
@dataclass
class AlltalkConfigApiDef:
api_port_number: int = 7851
api_allowed_filter: str = "[^a-zA-Z0-9\\s.,;:!?\\-\\'\"$\\u0400-\\u04FF\\u00C0-\\u017F\\u0150\\u0151\\u0170\\u0171\\u011E\\u011F\\u0130\\u0131\\u0900-\\u097F\\u2018\\u2019\\u201C\\u201D\\u3001\\u3002\\u3040-\\u309F\\u30A0-\\u30FF\\u4E00-\\u9FFF\\u3400-\\u4DBF\\uF900-\\uFAFF\\u0600-\\u06FF\\u0750-\\u077F\\uFB50-\\uFDFF\\uFE70-\\uFEFF\\uAC00-\\uD7A3\\u1100-\\u11FF\\u3130-\\u318F\\uFF01\\uFF0c\\uFF1A\\uFF1B\\uFF1F]"
api_length_stripping: int = 3
api_max_characters: int = 2000
api_use_legacy_api: bool = False
api_legacy_ip_address: str = "127.0.0.1"
api_text_filtering: str = "standard"
api_narrator_enabled: str = "false"
api_text_not_inside: str = "character"
api_language: str = "en"
api_output_file_name: str = "myoutputfile"
api_output_file_timestamp: bool = True
api_autoplay: bool = False
api_autoplay_volume: float = 0.5
@dataclass
class AlltalkConfigDebug:
debug_transcode: bool = False
debug_tts: bool = False
debug_openai: bool = False
debug_concat: bool = False
debug_tts_variables: bool = False
debug_rvc: bool = False
debug_func: bool = False
debug_api: bool = False
debug_fullttstext: bool = False
debug_narrator: bool = False
debug_gradio_IP: bool = False
debug_transcribe: bool = False
@dataclass
class AlltalkConfigGradioPages:
Generate_Help_page: bool = True
Voice2RVC_page: bool = True
TTS_Generator_page: bool = True
TTS_Engines_Settings_page: bool = True
alltalk_documentation_page: bool = True
api_documentation_page: bool = True
@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=None, indent=4):
file_path = (Path(path) if type(path) is str else path) if path is not None else self.get_config_path()
def custom_default(o):
if isinstance(o, Path):
return str(o) # Convert Path objects to strings
elif hasattr(o, '__dict__'):
return o.__dict__ # Use the object's __dict__ if it exists
else:
raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable")
default = default or custom_default
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')
backup_path = None
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 and backup_path.exists():
shutil.copy(backup_path, path)
raise Exception(f"Failed to save config: {e}")
finally:
# Cleanup lock and backup files:
if lock_path.exists(): # Only try to delete if it exists
try:
lock_path.unlink()
except FileNotFoundError:
pass # Ignore if file doesn't exist
if backup and backup_path and backup_path.exists():
try:
backup_path.unlink()
except FileNotFoundError:
pass # Ignore if file doesn't exist
@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
@dataclass
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):
from dataclasses import fields, is_dataclass, asdict
debug_me =False
if debug_me:
print("=== Loading Config ===")
print(f"Initial data state: {vars(data)}")
# Create new instances with defaults
default_instances = {
'debugging': AlltalkConfigDebug(),
'rvc_settings': AlltalkConfigRvcSettings(),
'tgwui': AlltalkConfigTgwUi(),
'api_def': AlltalkConfigApiDef(),
'theme': AlltalkConfigTheme(),
'gradio_pages': AlltalkConfigGradioPages()
}
if debug_me:
print("\nDefault values for each class:")
for name, instance in default_instances.items():
if debug_me:
print(f"{name}: {asdict(instance)}")
# Show actual default values from dataclass
print(f"Default values: {[(f.name, getattr(instance, f.name)) for f in fields(instance)]}")
if hasattr(data, name):
source = getattr(data, name)
if debug_me:
print(f"Source data: {vars(source) if hasattr(source, '__dict__') else source}")
for field in fields(instance):
if hasattr(source, field.name):
setattr(instance, field.name, getattr(source, field.name))
if debug_me:
print(f"Field {field.name}: {getattr(instance, field.name)}")
setattr(self, name, instance)
# Handle non-dataclass fields
for n, v in inspect.getmembers(data):
if hasattr(self, n) and not n.startswith("__") and not is_dataclass(type(getattr(self, n))):
setattr(self, n, v)
self.theme.clazz = data.theme.__dict__.get("class", data.theme.__dict__.get("clazz", ""))
self.get_output_directory().mkdir(parents=True, exist_ok=True)
def to_dict(self):
from dataclasses import is_dataclass, asdict
debug_me =False
if debug_me:
print("=== Converting to dict ===")
result = {}
for key, value in vars(self).items():
if not key.startswith('_'):
# print(f"\nProcessing {key}:")
if is_dataclass(value):
# print(f"Dataclass value before conversion: {vars(value)}")
result[key] = asdict(value)
# print(f"Converted to dict: {result[key]}")
elif isinstance(value, SimpleNamespace):
# print(f"SimpleNamespace value: {value.__dict__}")
result[key] = value.__dict__
else:
# print(f"Regular value: {value}")
result[key] = value
if 'theme' in result:
if debug_me:
print("\nProcessing theme:")
print(f"Before class handling: {result['theme']}")
result['theme']['class'] = self.theme.clazz
result['theme'].pop('clazz', None)
if debug_me:
print(f"After class handling: {result['theme']}")
if debug_me:
print(f"\nFinal dict: {result}")
return result
+30 -30
View File
@@ -889,20 +889,20 @@ def create_pfc_interface():
with gr.Row(): with gr.Row():
with gr.Column(): with gr.Column():
with gr.Accordion("💻 Hardware Requirements", open=False): with gr.Accordion("💻 Hardware Requirements", open=False):
gr.Markdown(HELP_CONTENT["gpu_requirements"]) gr.Markdown(HELP_CONTENT["gpu_requirements"], elem_classes="custom-markdown")
with gr.Column(): with gr.Column():
with gr.Accordion("🖥️ Storage Requirements", open=False): with gr.Accordion("🖥️ Storage Requirements", open=False):
gr.Markdown(HELP_CONTENT["disk_space_details"]) gr.Markdown(HELP_CONTENT["disk_space_details"], elem_classes="custom-markdown")
with gr.Row(): with gr.Row():
with gr.Column(): with gr.Column():
with gr.Accordion("🤖 PyTorch & CUDA", open=False): with gr.Accordion("🤖 PyTorch & CUDA", open=False):
gr.Markdown(HELP_CONTENT["pytorch_cuda"]) gr.Markdown(HELP_CONTENT["pytorch_cuda"], elem_classes="custom-markdown")
with gr.Column(): with gr.Column():
with gr.Accordion("📦 Model Setup", open=False): with gr.Accordion("📦 Model Setup", open=False):
gr.Markdown(HELP_CONTENT["model_setup"]) gr.Markdown(HELP_CONTENT["model_setup"], elem_classes="custom-markdown")
def run_checks(): def run_checks():
system_checks.run_all_checks() system_checks.run_all_checks()
@@ -3925,25 +3925,25 @@ if __name__ == "__main__":
) )
with gr.Accordion("🎯 Quick Start Guide", open=False): with gr.Accordion("🎯 Quick Start Guide", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP1_QUICKSTART) # pylint: disable=no-member FinetuneContent.STEP1_QUICKSTART, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("📋 Detailed Instructions", open=False): with gr.Accordion("📋 Detailed Instructions", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP1_DETAILED_INSTRUCTIONS) # pylint: disable=no-member FinetuneContent.STEP1_DETAILED_INSTRUCTIONS, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("🔧 Process Overview", open=False): with gr.Accordion("🔧 Process Overview", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP1_PROCESS_OVERVIEW) # pylint: disable=no-member FinetuneContent.STEP1_PROCESS_OVERVIEW, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("🔍 Whisper Model Selection", open=False): with gr.Accordion("🔍 Whisper Model Selection", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP1_WHISPER_MODEL_SELECTION) # pylint: disable=no-member FinetuneContent.STEP1_WHISPER_MODEL_SELECTION, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("⚙️ Advanced Settings", open=False): with gr.Accordion("⚙️ Advanced Settings", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP1_ADVANCED_SETTINGS) # pylint: disable=no-member FinetuneContent.STEP1_ADVANCED_SETTINGS, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("🔍 Dataset Creation Debug Settings", open=False): with gr.Accordion("🔍 Dataset Creation Debug Settings", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP1_DEBUG_SETTINGS) # pylint: disable=no-member FinetuneContent.STEP1_DEBUG_SETTINGS, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("❗ Troubleshooting", open=False): with gr.Accordion("❗ Troubleshooting", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP1_TROUBLESHOOTING) # pylint: disable=no-member FinetuneContent.STEP1_TROUBLESHOOTING, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.TabItem("📊 Dataset Validation"): with gr.TabItem("📊 Dataset Validation"):
with gr.Row(): with gr.Row():
@@ -3953,10 +3953,10 @@ if __name__ == "__main__":
with gr.Row(): with gr.Row():
with gr.Column(): with gr.Column():
gr.Markdown( gr.Markdown(
FinetuneContent.DATASET_VALIDATION_1) # pylint: disable=no-member FinetuneContent.DATASET_VALIDATION_1, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Column(): with gr.Column():
gr.Markdown( gr.Markdown(
FinetuneContent.DATASET_VALIDATION_2) # pylint: disable=no-member FinetuneContent.DATASET_VALIDATION_2, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Row(): with gr.Row():
progress_box = gr.Textbox(label="Progress", interactive=False) progress_box = gr.Textbox(label="Progress", interactive=False)
@@ -4456,31 +4456,31 @@ if __name__ == "__main__":
) )
with gr.Accordion("🎯 Quick Start Training Guide", open=False): with gr.Accordion("🎯 Quick Start Training Guide", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP2_QUICKSTART) # pylint: disable=no-member FinetuneContent.STEP2_QUICKSTART, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("📁 Using Your Own Training Dataset", open=False): with gr.Accordion("📁 Using Your Own Training Dataset", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP2_YOUR_OWN_DATASET) # pylint: disable=no-member FinetuneContent.STEP2_YOUR_OWN_DATASET, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("📊 Training Metrics and Logs", open=False): with gr.Accordion("📊 Training Metrics and Logs", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP2_TRAINING_METRICS) # pylint: disable=no-member FinetuneContent.STEP2_TRAINING_METRICS, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("💾 Memory Management", open=False): with gr.Accordion("💾 Memory Management", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP2_MEMORY_MANAGEMENT) # pylint: disable=no-member FinetuneContent.STEP2_MEMORY_MANAGEMENT, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("⚙️ Batch Size & Gradient Accumulation", open=False): with gr.Accordion("⚙️ Batch Size & Gradient Accumulation", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP2_BATCH_SIZE) # pylint: disable=no-member FinetuneContent.STEP2_BATCH_SIZE, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("📊 Learning Rate & Schedulers", open=False): with gr.Accordion("📊 Learning Rate & Schedulers", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP2_LEARNING_RATE) # pylint: disable=no-member FinetuneContent.STEP2_LEARNING_RATE, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("🔧 Optimizers", open=False): with gr.Accordion("🔧 Optimizers", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP2_OPTIMIZERS) # pylint: disable=no-member FinetuneContent.STEP2_OPTIMIZERS, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("🔄 Training Epochs", open=False): with gr.Accordion("🔄 Training Epochs", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP2_EPOCHS) # pylint: disable=no-member FinetuneContent.STEP2_EPOCHS, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("📈 Max Audio Length", open=False): with gr.Accordion("📈 Max Audio Length", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP2_AUDIO_LENGTH) # pylint: disable=no-member FinetuneContent.STEP2_AUDIO_LENGTH, elem_classes="custom-markdown") # pylint: disable=no-member
####################### #######################
#### GRADIO STEP 3 #### #### GRADIO STEP 3 ####
@@ -4625,30 +4625,30 @@ if __name__ == "__main__":
) )
with gr.Accordion("🎯 Testing Overview", open=False): with gr.Accordion("🎯 Testing Overview", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP3_TESTING_OVERVIEW) # pylint: disable=no-member FinetuneContent.STEP3_TESTING_OVERVIEW, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("⚠️ Important Notes", open=False): with gr.Accordion("⚠️ Important Notes", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP3_IMPORTANT) # pylint: disable=no-member FinetuneContent.STEP3_IMPORTANT, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("📝 Testing Instructions", open=False): with gr.Accordion("📝 Testing Instructions", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP3_INSTRUCTIONS) # pylint: disable=no-member FinetuneContent.STEP3_INSTRUCTIONS, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("🔍 What the Testing Step Does", open=False): with gr.Accordion("🔍 What the Testing Step Does", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.STEP3_WHAT_IT_DOES) # pylint: disable=no-member FinetuneContent.STEP3_WHAT_IT_DOES, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Tab("📦 Model Export"): with gr.Tab("📦 Model Export"):
with gr.Accordion("🎯 Export Overview", open=False): with gr.Accordion("🎯 Export Overview", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.EXPORT_OVERVIEW) # pylint: disable=no-member FinetuneContent.EXPORT_OVERVIEW, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("📊 Voice Sample Organization", open=False): with gr.Accordion("📊 Voice Sample Organization", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.EXPORT_VOICE_SAMPLES) # pylint: disable=no-member FinetuneContent.EXPORT_VOICE_SAMPLES, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("🔄 Export Options", open=False): with gr.Accordion("🔄 Export Options", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.EXPORT_OPTIONS) # pylint: disable=no-member FinetuneContent.EXPORT_OPTIONS, elem_classes="custom-markdown") # pylint: disable=no-member
with gr.Accordion("💾 Storage Management", open=False): with gr.Accordion("💾 Storage Management", open=False):
gr.Markdown( gr.Markdown(
FinetuneContent.EXPORT_STORAGE) # pylint: disable=no-member FinetuneContent.EXPORT_STORAGE, elem_classes="custom-markdown") # pylint: disable=no-member
final_progress_data = gr.Label(label="Progress:") final_progress_data = gr.Label(label="Progress:")
with gr.Row(): with gr.Row():
+2
View File
@@ -0,0 +1,2 @@
[pytest]
pythonpath = .
+4303 -1745
View File
File diff suppressed because it is too large. Load diff
-696
View File
@@ -1,696 +0,0 @@
import re
import json
import time
import random
import logging
import requests
import threading
import gradio as gr
from pathlib import Path
from modules import chat, shared, ui_chat
from modules.utils import gradio
from requests.exceptions import RequestException, ConnectionError
# Store the current disable level
current_disable_level = logging.getLogger().manager.disable
####################################################################
# Load in the confignew.json and put the main settings into params #
####################################################################
this_dir = Path(__file__).parent.resolve()
def load_config(file_path):
with open(file_path, "r") as config_file:
config = json.load(config_file)
return config
# Set confiig file path
config_file_path = this_dir / "tgwui_remote_config.json"
# Load the params dictionary from the tgwui_remote_config.json file
params = load_config(config_file_path)
# Set branding
branding = params['branding']
################################
# Print Spashscreen to console #
################################
print(f"[{branding}Startup]\033[94m _ _ _ \033[1;35m_____ _ _ \033[0m _____ _____ ____ ")
print(f"[{branding}Startup]\033[94m / \ | | |\033[1;35m_ _|_ _| | | __ \033[0m |_ _|_ _/ ___| ")
print(f"[{branding}Startup]\033[94m / _ \ | | |\033[1;35m | |/ _` | | |/ / \033[0m | | | | \___ \ ")
print(f"[{branding}Startup]\033[94m / ___ \| | |\033[1;35m | | (_| | | < \033[0m | | | | ___) |")
print(f"[{branding}Startup]\033[94m /_/ \_\_|_|\033[1;35m |_|\__,_|_|_|\_\ \033[0m |_| |_| |____/ ")
print(f"[{branding}Startup]")
print(f"[{branding}Startup] \033[92m{branding}startup Mode : \033[93mText-Gen-webui Remote\033[0m")
print(f"[{branding}Startup]")
##########################
# Setup global variables #
##########################
# STARTUP VARIABLE - Import languges file for Gradio to be able to display them in the interface
with open(this_dir / "languages.json", encoding="utf8") as f:
languages = json.load(f)
# Create a global lock for tracking TTS generation occuring
process_lock = threading.Lock()
# Pull the values for IP address, port and protocol for communication with the AllTalk renote server
alltalk_protocol = params["api_def"]["api_alltalk_protocol"]
alltalk_ip_port = params["api_def"]["api_alltalk_ip_port"]
# Pull the connection timeout value for communication requests with the AllTalk remote server
connection_timeout = params["api_def"]["api_connection_timeout"]
# Create a few base global variables that are required
models_available = None # Gets populated with the list of all models/engines available on the AllTalk Server
alltalk_settings = None # Gets populated with the list of all settings currently set on the AllTalk Server
current_model_loaded = None # Gets populated with the name of the current loaded TTS engine/model on the AllTalk Server
# Used to detect if a model is loaded in to AllTalk server to block TTS genereation if needed.
tts_model_loaded = None
#################################################
# Pull all the settings from the AllTalk Server #
#################################################
def get_alltalk_settings():
global current_model_loaded, models_available
voices_url = f"{alltalk_protocol}{alltalk_ip_port}/api/voices"
settings_url = f"{alltalk_protocol}{alltalk_ip_port}/api/currentsettings"
rvcvoices_url = f"{alltalk_protocol}{alltalk_ip_port}/api/rvcvoices"
try:
voices_response = requests.get(voices_url, timeout=connection_timeout)
rvcvoices_response = requests.get(rvcvoices_url, timeout=connection_timeout)
settings_response = requests.get(settings_url, timeout=connection_timeout)
if voices_response.status_code == 200 and settings_response.status_code == 200:
voices_data = voices_response.json()
rvcvoices_data = rvcvoices_response.json()
settings_data = settings_response.json()
models_available = [model["name"] for model in settings_data["models_available"]]
current_model_loaded = settings_data["current_model_loaded"]
return {
"voices": sorted(voices_data["voices"]),
"rvcvoices": (rvcvoices_data["rvcvoices"]),
"models_available": models_available,
"current_model_loaded": current_model_loaded,
"manufacturer_name": settings_data.get("manufacturer_name", ""),
"deepspeed_capable": settings_data.get("deepspeed_capable", False),
"deepspeed_available": settings_data.get("deepspeed_available", False),
"deepspeed_enabled": settings_data.get("deepspeed_enabled", False),
"generationspeed_capable": settings_data.get("generationspeed_capable", False),
"generationspeed_set": settings_data.get("generationspeed_set", 1.0),
"lowvram_capable": settings_data.get("lowvram_capable", False),
"lowvram_enabled": settings_data.get("lowvram_enabled", False),
"pitch_capable": settings_data.get("pitch_capable", False),
"pitch_set": settings_data.get("pitch_enabled", False),
"repetitionpenalty_capable": settings_data.get("repetitionpenalty_capable", False),
"repetitionpenalty_set": settings_data.get("repetitionpenalty_set", 10.0),
"streaming_capable": settings_data.get("streaming_capable", False),
"temperature_capable": settings_data.get("temperature_capable", False),
"temperature_set": settings_data.get("temperature_set", 0.75),
"ttsengines_installed": settings_data.get("ttsengines_installed", False),
"languages_capable": settings_data.get("languages_capable", False),
"multivoice_capable": settings_data.get("multivoice_capable", False),
"multimodel_capable": settings_data.get("multimodel_capable", False),
}
else:
print(f"[{branding}Server] \033[91mWarning\033[0m Failed to retrieve {branding}settings from API.")
if voices_response.status_code != 200:
print(f"[{branding}Server] \033[91mWarning\033[0m Failed to retrieve voices from API. Status code:\n{voices_response.status_code}")
if settings_response.status_code != 200:
print(f"[{branding}Server] \033[91mWarning\033[0m Failed to retrieve current settings from API. Status code:\n{settings_response.status_code}")
return {
"voices": ["Please Refresh Settings"],
"rvcvoices": ["Please Refresh Settings"],
"models_available": ["Please Refresh Settings"],
"current_model_loaded": "Please Refresh Settings",
"manufacturer_name": "",
"deepspeed_capable": False,
"deepspeed_available": False,
"deepspeed_enabled": False,
"generationspeed_capable": False,
"generationspeed_set": 1.0,
"lowvram_capable": False,
"lowvram_enabled": False,
"pitch_capable": False,
"pitch_set": 0,
"repetitionpenalty_capable": False,
"repetitionpenalty_set": 10.0,
"streaming_capable": False,
"temperature_capable": False,
"temperature_set": 0.75,
"ttsengines_installed": False,
"languages_capable": False,
"multivoice_capable": False,
"multimodel_capable": False,
}
except (RequestException, ConnectionError) as e:
print(f"[{branding}Server] \033[91mWarning\033[0m Unable to connect to the {branding}server. Status code:\n{str(e)}")
return {
"voices": ["Please Refresh Settings"],
"rvcvoices": ["Please Refresh Settings"],
"models_available": ["Please Refresh Settings"],
"current_model_loaded": "Please Refresh Settings",
"manufacturer_name": "",
"deepspeed_capable": False,
"deepspeed_available": False,
"deepspeed_enabled": False,
"generationspeed_capable": False,
"generationspeed_set": 1.0,
"lowvram_capable": False,
"lowvram_enabled": False,
"pitch_capable": False,
"pitch_set": 0,
"repetitionpenalty_capable": False,
"repetitionpenalty_set": 10.0,
"streaming_capable": False,
"temperature_capable": False,
"temperature_set": 0.75,
"ttsengines_installed": False,
"languages_capable": False,
"multivoice_capable": False,
"multimodel_capable": False,
}
#############################
#### TTS STOP GENERATION ####
#############################
def stop_generate_tts():
api_url = f"{alltalk_protocol}{alltalk_ip_port}/api/stop-generation"
try:
response = requests.put(api_url, timeout=connection_timeout)
if response.status_code == 200:
return response.json()["message"]
else:
print(f"[{branding}Server] \033[91mWarning\033[0m Failed to stop generation. Status code:\n{response.status_code}")
return {"message": "Failed to stop generation"}
except (RequestException, ConnectionError) as e:
print(f"[{branding}Server] \033[91mWarning\033[0m Unable to connect to the {branding}server. Status code:\n{str(e)}")
return {"message": "Failed to stop generation"}
#####################################
#### MODEL LOADING AND UNLOADING ####
#####################################
# MODEL - Swap model based on Gradio selection
def send_reload_request(value_sent):
try:
url = f"{alltalk_protocol}{alltalk_ip_port}/api/reload"
payload = {"tts_method": value_sent}
response = requests.post(url, params=payload)
response.raise_for_status() # Raises an HTTPError for bad responses
except requests.exceptions.RequestException as e:
# Handle the HTTP request error
print(f"[{branding}Server] \033[91mWarning\033[0m Error during request to webserver process: Status code:\n{e}")
return {"status": "error", "message": str(e)}
####################################################################################################
# TGWUI # Saves all settings back to the config file for the REMOTE version of the TGWUI extension #
####################################################################################################
def tgwui_save_settings():
settings = {
"branding": params['branding'],
"tgwui": {
"tgwui_activate_tts": params["tgwui"]['tgwui_activate_tts'],
"tgwui_autoplay_tts": params["tgwui"]['tgwui_autoplay_tts'],
"tgwui_narrator_enabled": params["tgwui"]['tgwui_narrator_enabled'],
"tgwui_non_quoted_text_is": params["tgwui"]["tgwui_non_quoted_text_is"],
"tgwui_deepspeed_enabled": params["tgwui"]['tgwui_deepspeed_enabled'],
"tgwui_language": params["tgwui"]['tgwui_language'],
"tgwui_lowvram_enabled": params["tgwui"]['tgwui_lowvram_enabled'],
"tgwui_pitch_set": params["tgwui"]['tgwui_pitch_set'],
"tgwui_temperature_set": params["tgwui"]['tgwui_temperature_set'],
"tgwui_repetitionpenalty_set": params["tgwui"]['tgwui_repetitionpenalty_set'],
"tgwui_generationspeed_set": params["tgwui"]['tgwui_generationspeed_set'],
"tgwui_narrator_voice": params["tgwui"]['tgwui_narrator_voice'],
"tgwui_show_text": params["tgwui"]['tgwui_show_text'],
"tgwui_character_voice": params["tgwui"]['tgwui_character_voice'],
"tgwui_rvc_char_voice": params["tgwui"]['tgwui_rvc_char_voice'],
"tgwui_rvc_narr_voice": params["tgwui"]['tgwui_rvc_narr_voice']
},
"api_def": {
"api_use_legacy_api": params['api_def']['api_use_legacy_api'],
"api_alltalk_protocol": alltalk_protocol,
"api_alltalk_ip_port": alltalk_ip_port,
"api_connection_timeout": 5,
}
}
with open(config_file_path, "w") as file:
json.dump(settings, file, indent=4)
#############################################
# Low VRAM change request to enable/disable #
#############################################
# LOW VRAM - Gradio Checkbox handling
def send_lowvram_request(value_sent):
try:
params["tgwui"]["tts_model_loaded"] = False
if value_sent:
audio_path = this_dir / "lowvramenabled.wav"
else:
audio_path = this_dir / "lowvramdisabled.wav"
url = f"{alltalk_protocol}{alltalk_ip_port}/api/lowvramsetting?new_low_vram_value={value_sent}"
headers = {"Content-Type": "application/json"}
response = requests.post(url, headers=headers)
response.raise_for_status() # Raises an HTTPError for bad responses
json_response = response.json()
# Check if the low VRAM request was successful
if json_response.get("status") == "lowvram-success":
# Update any relevant variables or perform other actions on success
params["tgwui"]["tts_model_loaded"] = True
return f'<audio src="file/{audio_path}" controls autoplay></audio>'
except requests.exceptions.RequestException as e:
# Handle the HTTP request error
print(f"[{branding}Server] \033[91mWarning\033[0m Error during request to webserver process: Status code:\n{e}")
return {"status": "error", "message": str(e)}
###################
#### DeepSpeed ####
###################
def send_deepspeed_request(value_sent):
try:
params["tgwui"]["tts_model_loaded"] = False
if value_sent:
audio_path = this_dir / "deepspeedenabled.wav"
else:
audio_path = this_dir / "deepspeeddisabled.wav"
url = f"{alltalk_protocol}{alltalk_ip_port}/api/deepspeed?new_deepspeed_value={value_sent}"
headers = {"Content-Type": "application/json"}
response = requests.post(url, headers=headers)
response.raise_for_status() # Raises an HTTPError for bad responses
json_response = response.json()
# Check if the deepspeed request was successful
if json_response.get("status") == "deepspeed-success":
# Update any relevant variables or perform other actions on success
params["tgwui"]["tts_model_loaded"] = True
return f'<audio src="file/{audio_path}" controls autoplay></audio>'
except requests.exceptions.RequestException as e:
# Handle the HTTP request error
print(f"[{branding}Server] \033[91mWarning\033[0m Error during request to webserver process: Status code:\n{e}")
return {"status": "error", "message": str(e)}
#################################
#### TTS STANDARD GENERATION ####
#################################
def send_and_generate(gen_text, gen_character_voice, gen_rvccharacter_voice, gen_narrator_voice, gen_rvcnarrator_voice, gen_narrator_activated, gen_textnotinisde, gen_repetition, gen_language, gen_filter, gen_speed, gen_pitch, gen_autoplay, gen_autoplay_vol, gen_file_name, gen_temperature, gen_filetimestamp, gen_stream, gen_stopcurrentgen):
api_url = f"{alltalk_protocol}{alltalk_ip_port}/api/tts-generate"
if gen_stopcurrentgen:
stop_generate_tts() # Call for the current generation to stop
tgwui_save_settings() # Save the current TGWUI settings to the config file
if gen_stream == "true":
api_url = f"{alltalk_protocol}{alltalk_ip_port}/api/tts-generate-streaming"
encoded_text = requests.utils.quote(gen_text)
streaming_url = f"{api_url}?text={encoded_text}&voice={gen_character_voice}&language={gen_language}&output_file={gen_file_name}"
return streaming_url, str("TTS Streaming Audio Generated")
else:
data = {
"text_input": gen_text,
"text_filtering": gen_filter,
"character_voice_gen": gen_character_voice,
"rvccharacter_voice_gen": gen_rvccharacter_voice,
"narrator_enabled": str(gen_narrator_activated).lower(),
"narrator_voice_gen": gen_narrator_voice,
"rvcnarrator_voice_gen": gen_rvcnarrator_voice,
"text_not_inside": gen_textnotinisde,
"language": gen_language,
"output_file_name": str(gen_file_name),
"output_file_timestamp": str(gen_filetimestamp).lower(),
"autoplay": str(gen_autoplay).lower(),
"autoplay_volume": str(gen_autoplay_vol),
"speed": str(gen_speed),
"pitch": str(gen_pitch),
"temperature": str(gen_temperature),
"repetition_penalty": str(gen_repetition),
}
#print(f"Debug: Generate request param:", data) if params["debug_tts"] else None
try:
response = requests.post(api_url, data=data)
response.raise_for_status() # Raise an exception for 4xx or 5xx status codes
result = response.json()
if gen_autoplay == "true":
return None, str("TTS Audio Generated (Played remotely)")
else:
if params["api_def"]["api_use_legacy_api"]:
return result['output_file_url'], str("TTS Audio Generated")
else:
# Prepend the URL and PORT to the output_file_url
output_file_url = f"{alltalk_protocol}{alltalk_ip_port}{result['output_file_url']}"
return output_file_url, str("TTS Audio Generated")
except (RequestException, ConnectionError) as e:
print(f"[{branding}Server] \033[91mWarning\033[0m Error occurred during the API request: Status code:\n{str(e)}")
return None, str("Error occurred during the API request")
####################################################################
# TGWUI # Text-generation-webui sends text for TTS generation here #
####################################################################
def output_modifier(string, state):
if not params["tgwui"]["tgwui_activate_tts"]:
return string
# Strip out Images
img_info = ""
cleaned_text, img_info = tgwui_extract_and_remove_images(string)
if cleaned_text is None:
return
# Get current settings
language_code = languages.get(params["tgwui"]["tgwui_language"])
character_voice = params["tgwui"]["tgwui_character_voice"]
rvc_character_voice = params["tgwui"]["tgwui_rvc_char_voice"]
narrator_voice = params["tgwui"]["tgwui_narrator_voice"]
rvc_narrator_voice = params["tgwui"]["tgwui_rvc_narr_voice"]
narrator_enabled = params["tgwui"]["tgwui_narrator_enabled"]
text_not_inside = params["tgwui"]["tgwui_non_quoted_text_is"]
repetition_policy = params["tgwui"]["tgwui_repetitionpenalty_set"]
text_filtering = "html"
speed = params["tgwui"]["tgwui_generationspeed_set"]
pitch = params["tgwui"]["tgwui_pitch_set"]
autoplay = False # This is never used in TGWUI so a base False setting is sent
autoplay_volume = 0.8 # This is never used in TGWUI so a base False setting is sent
temperature = params["tgwui"]["tgwui_temperature_set"]
# Lock and process TTS request
if process_lock.acquire(blocking=False):
try:
if "character_menu" in state:
output_file = state["character_menu"]
else:
output_file = str("TTSOUT_")
generate_response, status_message = send_and_generate(cleaned_text, character_voice, rvc_character_voice, narrator_voice, rvc_narrator_voice, narrator_enabled, text_not_inside, repetition_policy, language_code, text_filtering, speed, pitch, autoplay, autoplay_volume, output_file, temperature, True, False, False)
if status_message == "TTS Audio Generated":
# Handle Gradio and playback
autoplay = "autoplay" if params["tgwui"]["tgwui_autoplay_tts"] else ""
string = f'<audio src="{generate_response}" controls {autoplay}></audio>'
if params["tgwui"]["tgwui_show_text"]:
string += tgwui_reinsert_images(cleaned_text, img_info)
shared.processing_message = "*Is typing...*"
return string
else:
print(f"[{branding}Server] \033[91mWarning\033[0m Audio generation failed. Status code:\n{status_message}")
finally:
# Always release the lock, whether an exception occurs or not
process_lock.release()
else:
# The lock is already acquired
print(f"[{branding}Model] \033[91mWarning\033[0m Audio generation is already in progress. Please wait.")
return
###########################################################################################################
# TGWUI # Strips out images from the TGWUI string if needed and re-inserts the image after TTS generation #
###########################################################################################################
img_pattern = r'<img[^>]*src\s*=\s*["\'][^"\'>]+["\'][^>]*>'
def tgwui_extract_and_remove_images(text):
"""
Extracts all image data from the text and removes it for clean TTS processing.
Returns the cleaned text and the extracted image data.
"""
img_matches = re.findall(img_pattern, text)
img_info = "\n".join(img_matches) # Store extracted image data
cleaned_text = re.sub(img_pattern, '', text) # Remove images from text
return cleaned_text, img_info
def tgwui_reinsert_images(text, img_info):
"""
Reinserts the previously extracted image data back into the text.
"""
if img_info: # Check if there are images to reinsert
text += f"\n\n{img_info}"
return text
################################################################
# TGWUI # Used to generate a preview voice sample within TGWUI #
################################################################
def random_sentence():
with open(this_dir / "harvard_sentences.txt") as f:
return random.choice(list(f)).rstrip()
def voice_preview(string):
if not params["tgwui"]["tgwui_activate_tts"]:
return string
language_code = languages.get(params["tgwui"]["tgwui_language"])
if not string:
string = random_sentence()
generate_response, status_message = send_and_generate(string, params["tgwui"]["tgwui_character_voice"], params["tgwui"]["tgwui_rvc_char_voice"], params["tgwui"]["tgwui_narrator_voice"], params["tgwui"]["tgwui_rvc_narr_voice"], False, "character", params["tgwui"]["tgwui_repetitionpenalty_set"], language_code, "standard", params["tgwui"]["tgwui_generationspeed_set"], params["tgwui"]["tgwui_pitch_set"], False, 0.8, "previewvoice", params["tgwui"]["tgwui_temperature_set"], False, False, False)
if status_message == "TTS Audio Generated":
# Handle Gradio and playback
autoplay = "autoplay" if params["tgwui"]["tgwui_autoplay_tts"] else ""
return f'<audio src="{generate_response}?{int(time.time())}" controls {autoplay}></audio>'
else:
# Handle the case where audio generation was not successful
return f"[{branding}Server] Audio generation failed. Status code:\n{status_message}"
###################################################################
# TGWUI # Used to inform TGWUI that TTS is disabled/not activated #
###################################################################
def state_modifier(state):
if not params["tgwui"]["tgwui_activate_tts"]:
return state
state["stream"] = False
return state
###################################################################
# TGWUI # Sends message to TGWUI interface during TTS generation #
###################################################################
def input_modifier(string, state):
if not params["tgwui"]["tgwui_activate_tts"]:
return string
shared.processing_message = "*Is recording a voice message...*"
return string
########################################################################
# TGWUI # Used to delete historic TTS audios from TGWUI chat interface #
########################################################################
def remove_tts_from_history(history):
for i, entry in enumerate(history["internal"]):
history["visible"][i] = [history["visible"][i][0], entry[1]]
return history
def toggle_text_in_history(history):
for i, entry in enumerate(history["visible"]):
visible_reply = entry[1]
if visible_reply.startswith("<audio"):
if params["tgwui"]["tgwui_show_text"]:
reply = history["internal"][i][1]
history["visible"][i] = [
history["visible"][i][0],
f"{visible_reply.split('</audio>')[0]}</audio>\n\n{reply}",
]
else:
history["visible"][i] = [
history["visible"][i][0],
f"{visible_reply.split('</audio>')[0]}</audio>",
]
return history
def history_modifier(history):
# Remove autoplay from the last reply
if len(history["internal"]) > 0:
history["visible"][-1] = [
history["visible"][-1][0],
history["visible"][-1][1].replace("controls autoplay>", "controls>"),
]
return history
###########################################################
# TGWUI # Update IP address and Port from TGWUI interface #
###########################################################
def tgwui_update_alltalk_ip_port(value_sent):
global alltalk_ip_port
alltalk_ip_port = value_sent
###########################################################
# TGWUI # Update http/https protocol from TGWUI interface #
###########################################################
# Update Protocol from Gradio
def tgwui_update_alltalk_protocol(value_sent):
global alltalk_protocol
alltalk_protocol = value_sent
###########################################################################################################################
# TGWUI # Debounces model updates when tgwui_update_dropdowns is called, preventing an update from causing a model reload #
###########################################################################################################################
def tgwui_handle_ttsmodel_dropdown_change(model_name):
if not getattr(tgwui_handle_ttsmodel_dropdown_change, "skip_reload", False):
send_reload_request(model_name)
tgwui_handle_ttsmodel_dropdown_change.skip_reload = False
##################################################################################################
# TGWUI # Pulls the current AllTalk Server settings & updates gradio when Refresh button pressed #
##################################################################################################
def tgwui_update_dropdowns():
global at_settings
at_settings = get_alltalk_settings() # Pull all the current settings from the AllTalk server, if its online.
current_voices = at_settings["voices"]
rvccurrent_voices = at_settings["rvcvoices"]
rvccurrent_character_voice = params["tgwui"]["tgwui_rvc_char_voice"]
rvccurrent_narrator_voice = params["tgwui"]["tgwui_rvc_char_voice"]
current_models_available = sorted(at_settings["models_available"])
current_model_loaded = at_settings["current_model_loaded"]
current_character_voice = params["tgwui"]["tgwui_character_voice"]
current_narrator_voice = params["tgwui"]["tgwui_narrator_voice"]
current_lowvram_capable = at_settings["lowvram_capable"]
current_lowvram_enabled = at_settings["lowvram_enabled"]
current_temperature_capable = at_settings["temperature_capable"]
current_repetitionpenalty_capable = at_settings["repetitionpenalty_capable"]
current_generationspeed_capable = at_settings["generationspeed_capable"]
current_pitch_capable = at_settings["pitch_capable"]
current_deepspeed_capable = at_settings["deepspeed_capable"]
current_deepspeed_enabled = at_settings["deepspeed_enabled"]
current_non_quoted_text_is = params.get("tgwui")["tgwui_non_quoted_text_is"] # Use the correct parameter path
current_languages_capable = at_settings["languages_capable"]
if at_settings["languages_capable"]:
language_label = "Languages"
else:
language_label = "Model not multi language"
if current_character_voice not in current_voices:
current_character_voice = current_voices[0] if current_voices else ""
params["tgwui"]["tgwui_character_voice"] = current_character_voice
if current_narrator_voice not in current_voices:
current_narrator_voice = current_voices[0] if current_voices else ""
params["tgwui"]["tgwui_narrator_voice"] = current_narrator_voice
if rvccurrent_character_voice not in rvccurrent_voices:
rvccurrent_character_voice = rvccurrent_voices[0] if rvccurrent_voices else ""
params["tgwui"]["tgwui_rvc_char_voice"] = rvccurrent_character_voice
if rvccurrent_narrator_voice not in rvccurrent_voices:
rvccurrent_narrator_voice = rvccurrent_voices[0] if rvccurrent_voices else ""
params["tgwui"]["tgwui_rvc_char_voice"] = rvccurrent_narrator_voice
tgwui_handle_ttsmodel_dropdown_change.skip_reload = True # Debounce tgwui_tts_dropdown_gr and stop it sending a model reload when it is updated.
return (
gr.Checkbox(interactive=current_lowvram_capable, value=current_lowvram_enabled),
gr.Checkbox(interactive=current_deepspeed_capable, value=current_deepspeed_enabled),
gr.Dropdown(choices=current_voices, value=current_character_voice),
gr.Dropdown(choices=rvccurrent_voices, value=rvccurrent_character_voice, interactive=True),
gr.Dropdown(choices=current_voices, value=current_narrator_voice),
gr.Dropdown(choices=rvccurrent_voices, value=rvccurrent_narrator_voice, interactive=True),
gr.Dropdown(choices=current_models_available, value=current_model_loaded),
gr.Dropdown(interactive=current_temperature_capable),
gr.Dropdown(interactive=current_repetitionpenalty_capable),
gr.Dropdown(interactive=current_languages_capable, label=language_label),
gr.Dropdown(interactive=current_generationspeed_capable),
gr.Dropdown(interactive=current_pitch_capable),
gr.Dropdown(value=current_non_quoted_text_is),
)
###############################################################
# TGWUI # Gradio interface & layout for Text-generation-webui #
###############################################################
def ui():
global alltalk_settings
alltalk_settings = get_alltalk_settings() # Pull all the current settings from the AllTalk server, if its online.
with gr.Accordion(params["branding"] + " TTS (Text-gen-webui Remote)"):
tgwui_available_voices_gr = alltalk_settings["voices"]
tgwui_rvc_available_voices_gr = alltalk_settings["rvcvoices"]
# Activate alltalk_tts, Enable autoplay, Show text
with gr.Row():
tgwui_activate_tts_gr = gr.Checkbox(value=params["tgwui"]["tgwui_activate_tts"], label="Enable TGWUI TTS")
tgwui_autoplay_gr = gr.Checkbox(value=params["tgwui"]["tgwui_autoplay_tts"], label="Autoplay TTS Generated")
tgwui_show_text_gr = gr.Checkbox(value=params["tgwui"]["tgwui_show_text"], label="Show Text in chat")
# Low vram enable, Deepspeed enable, Link
with gr.Row():
tgwui_lowvram_enabled_gr = gr.Checkbox(value=alltalk_settings["lowvram_enabled"] if alltalk_settings["lowvram_capable"] else False, label="Enable Low VRAM Mode", interactive=alltalk_settings["lowvram_capable"])
tgwui_lowvram_enabled_play_gr = gr.HTML(visible=False)
tgwui_deepspeed_enabled_gr = gr.Checkbox(value=params["tgwui"]["tgwui_deepspeed_enabled"], label="Enable DeepSpeed", interactive=alltalk_settings["deepspeed_capable"],)
tgwui_deepspeed_enabled_play_gr = gr.HTML(visible=False)
tgwui_empty_space_gr = gr.HTML(f"<p><a href='{alltalk_protocol}{alltalk_ip_port}'>AllTalk Server & Documentation Link</a><a href='{alltalk_protocol}{alltalk_ip_port}'></a>")
# Model, Language, Character voice
with gr.Row():
tgwui_tts_dropdown_gr = gr.Dropdown(choices=models_available, label="TTS Engine/Model", value=current_model_loaded,)
tgwui_language_gr = gr.Dropdown(languages.keys(), label="Languages" if alltalk_settings["languages_capable"] else "Model not multi language", interactive=alltalk_settings["languages_capable"], value=params["tgwui"]["tgwui_language"])
tgwui_narrator_enabled_gr = gr.Dropdown(choices=[("Enabled", "true"), ("Disabled", "false"), ("Silent", "silent")], label="Narrator Enable", value="true" if params.get("tgwui_narrator_enabled") == "true" else ("silent" if params.get("tgwui_narrator_enabled") == "silent" else "false"))
# Narrator
with gr.Row():
tgwui_available_voices_gr = alltalk_settings["voices"]
tgwui_default_voice_gr = params["tgwui"]["tgwui_character_voice"]
if tgwui_default_voice_gr not in tgwui_available_voices_gr:
tgwui_default_voice_gr = tgwui_available_voices_gr[0] if tgwui_available_voices_gr else ""
tgwui_character_voice_gr = gr.Dropdown(choices=tgwui_available_voices_gr, label="Character Voice", value=tgwui_default_voice_gr, allow_custom_value=True,)
tgwui_narr_voice_gr = params["tgwui"]["tgwui_narrator_voice"]
if tgwui_narr_voice_gr not in tgwui_available_voices_gr:
tgwui_narr_voice_gr = tgwui_available_voices_gr[0] if tgwui_available_voices_gr else ""
tgwui_narrator_voice_gr = gr.Dropdown(choices=tgwui_available_voices_gr, label="Narrator Voice", value=tgwui_narr_voice_gr, allow_custom_value=True,)
tgwui_non_quoted_text_is_gr = gr.Dropdown(choices=[("Character", "character"), ("Narrator", "narrator"), ("Silent", "silent")], label='Narrator unmarked text is', value=params.get("tgwui_non_quoted_text_is", "character"))
# RVC voices
with gr.Row():
tgwui_rvc_default_voice_gr = params["tgwui"]["tgwui_rvc_char_voice"]
tgwui_rvc_narrator_voice_gr = params["tgwui"]["tgwui_rvc_narr_voice"]
if tgwui_rvc_default_voice_gr not in tgwui_rvc_available_voices_gr:
tgwui_rvc_default_voice_gr = tgwui_rvc_available_voices_gr[0] if tgwui_rvc_available_voices_gr else ""
tgwui_rvc_char_voice_gr = gr.Dropdown(choices=tgwui_rvc_available_voices_gr, label="RVC Character Voice", value=tgwui_rvc_default_voice_gr, allow_custom_value=True,)
if tgwui_rvc_narrator_voice_gr not in tgwui_rvc_available_voices_gr:
tgwui_rvc_narrator_voice_gr = tgwui_rvc_available_voices_gr[0] if tgwui_rvc_available_voices_gr else ""
tgwui_rvc_narr_voice_gr = gr.Dropdown(choices=tgwui_rvc_available_voices_gr, label="RVC Narrator Voice", value=tgwui_rvc_narrator_voice_gr, allow_custom_value=True,)
# Temperature, Repetition Penalty, Speed, pitch
with gr.Row():
tgwui_temperature_set_gr = gr.Slider(minimum=0.05, maximum=1, step=0.05, label="Temperature", value=params["tgwui"]["tgwui_temperature_set"], interactive=alltalk_settings["temperature_capable"])
tgwui_repetitionpenalty_set_gr = gr.Slider(minimum=0.5, maximum=20, step=0.5, label="Repetition Penalty", value=params["tgwui"]["tgwui_repetitionpenalty_set"], interactive=alltalk_settings["repetitionpenalty_capable"])
with gr.Row():
tgwui_generationspeed_set_gr = gr.Slider(minimum=0.30, maximum=2.00, step=0.10, label="TTS Speed", value=params["tgwui"]["tgwui_generationspeed_set"], interactive=alltalk_settings["generationspeed_capable"])
tgwui_pitch_set_gr = gr.Slider(minimum=-10, maximum=10, step=1, label="Pitch", value=params["tgwui"]["tgwui_pitch_set"], interactive=alltalk_settings["pitch_capable"])
# Preview speech
with gr.Row():
tgwui_preview_text_gr = gr.Text(show_label=False, placeholder="Preview text", elem_id="silero_preview_text", scale=2,)
tgwui_preview_play_gr = gr.Button("Generate Preview", scale=1)
tgwui_preview_audio_gr = gr.HTML(visible=False)
with gr.Row():
tgwui_protocol_gr = gr.Dropdown(choices=["http://", "https://"], label="AllTalk Server Protocol", value=alltalk_protocol)
tgwui_protocol_gr.change(tgwui_update_alltalk_protocol, tgwui_protocol_gr, None)
tgwui_ip_address_port_gr = gr.Textbox(label="AllTalk Server IP:Port", value=alltalk_ip_port)
tgwui_ip_address_port_gr.change(tgwui_update_alltalk_ip_port, tgwui_ip_address_port_gr, None)
tgwui_refresh_settings_gr = gr.Button("Refresh settings & voices")
tgwui_refresh_settings_gr.click(tgwui_update_dropdowns, None, [tgwui_lowvram_enabled_gr, tgwui_deepspeed_enabled_gr, tgwui_character_voice_gr, tgwui_rvc_char_voice_gr, tgwui_narrator_voice_gr, tgwui_rvc_narr_voice_gr, tgwui_tts_dropdown_gr, tgwui_temperature_set_gr, tgwui_repetitionpenalty_set_gr, tgwui_language_gr, tgwui_generationspeed_set_gr, tgwui_pitch_set_gr, tgwui_non_quoted_text_is_gr])
with gr.Row():
tgwui_convert_gr = gr.Button("Remove old TTS audio and leave only message texts")
tgwui_convert_cancel_gr = gr.Button("Cancel", visible=False)
tgwui_convert_confirm_gr = gr.Button("Confirm (cannot be undone)", variant="stop", visible=False)
tgwui_stop_generation_gr = gr.Button("Stop current TTS generation")
tgwui_stop_generation_gr.click(stop_generate_tts, None, None,)
# Convert history with confirmation
convert_arr = [tgwui_convert_confirm_gr, tgwui_convert_gr, tgwui_convert_cancel_gr]
tgwui_convert_gr.click(lambda: [gr.update(visible=True), gr.update(visible=False), gr.update(visible=True),], None, convert_arr,)
tgwui_convert_confirm_gr.click(lambda: [ gr.update(visible=False), gr.update(visible=True), gr.update(visible=False),], None, convert_arr,
).then(remove_tts_from_history, gradio("history"), gradio("history")
).then(chat.save_history, gradio("history", "unique_id", "character_menu", "mode"), None,
).then(chat.redraw_html, gradio(ui_chat.reload_arr), gradio("display"))
tgwui_convert_cancel_gr.click(lambda: [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False),], None, convert_arr,)
# Toggle message text in history
tgwui_show_text_gr.change(lambda x: params["tgwui"].update({"tgwui_show_text": x}), tgwui_show_text_gr, None
).then(toggle_text_in_history, gradio("history"), gradio("history")
).then(chat.save_history, gradio("history", "unique_id", "character_menu", "mode"), None,
).then(chat.redraw_html, gradio(ui_chat.reload_arr), gradio("display"))
# Event functions to update the parameters in the backend
tgwui_activate_tts_gr.change(lambda x: params["tgwui"].update({"tgwui_activate_tts": x}), tgwui_activate_tts_gr, None)
tgwui_autoplay_gr.change(lambda x: params["tgwui"].update({"tgwui_autoplay_tts": x}), tgwui_autoplay_gr, None)
tgwui_lowvram_enabled_gr.change(lambda x: params["tgwui"].update({"tgwui_lowvram_enabled": x}), tgwui_lowvram_enabled_gr, None)
tgwui_lowvram_enabled_gr.change(lambda x: send_lowvram_request(x), tgwui_lowvram_enabled_gr, tgwui_lowvram_enabled_play_gr, None)
# Trigger the send_reload_request function when the dropdown value changes
tgwui_tts_dropdown_gr.change(tgwui_handle_ttsmodel_dropdown_change, tgwui_tts_dropdown_gr, None)
tgwui_deepspeed_enabled_gr.change(lambda x: params["tgwui"].update({"tgwui_deepspeed_enabled": x}), tgwui_deepspeed_enabled_gr, None)
tgwui_deepspeed_enabled_gr.change(send_deepspeed_request, tgwui_deepspeed_enabled_gr, tgwui_deepspeed_enabled_play_gr, None)
tgwui_character_voice_gr.change(lambda x: params["tgwui"].update({"tgwui_character_voice": x}), tgwui_character_voice_gr, None)
tgwui_language_gr.change(lambda x: params["tgwui"].update({"tgwui_language": x}), tgwui_language_gr, None)
# TSS Settings
tgwui_temperature_set_gr.change(lambda x: params["tgwui"].update({"tgwui_temperature_set": x}), tgwui_temperature_set_gr, None)
tgwui_repetitionpenalty_set_gr.change(lambda x: params["tgwui"].update({"tgwui_repetitionpenalty_set": x}), tgwui_repetitionpenalty_set_gr, None)
tgwui_generationspeed_set_gr.change(lambda x: params["tgwui"].update({"tgwui_generationspeed_set": x}), tgwui_generationspeed_set_gr, None)
tgwui_pitch_set_gr.change(lambda x: params["tgwui"].update({"tgwui_pitch_set": x}), tgwui_pitch_set_gr, None)
# Narrator selection actions
tgwui_narrator_enabled_gr.change(lambda x: params["tgwui"].update({"tgwui_narrator_enabled": x}), tgwui_narrator_enabled_gr, None)
tgwui_non_quoted_text_is_gr.change(lambda x: params["tgwui"].update({"tgwui_non_quoted_text_is": x}), tgwui_non_quoted_text_is_gr, None)
tgwui_narrator_voice_gr.change(lambda x: params["tgwui"].update({"tgwui_narrator_voice": x}), tgwui_narrator_voice_gr, None)
# RVC selection actions
tgwui_rvc_char_voice_gr.change(lambda x: params["tgwui"].update({"tgwui_rvc_char_voice": x}), tgwui_rvc_char_voice_gr, None)
tgwui_rvc_narr_voice_gr.change(lambda x: params["tgwui"].update({"tgwui_rvc_narr_voice": x}), tgwui_rvc_narr_voice_gr, None)
# Play preview
tgwui_preview_text_gr.submit(voice_preview, tgwui_preview_text_gr, tgwui_preview_audio_gr)
tgwui_preview_play_gr.click(voice_preview, tgwui_preview_text_gr, tgwui_preview_audio_gr)
File renamed without changes.
File diff suppressed because it is too large. Load diff
@@ -4,7 +4,7 @@
"tgwui_activate_tts": true, "tgwui_activate_tts": true,
"tgwui_autoplay_tts": true, "tgwui_autoplay_tts": true,
"tgwui_narrator_enabled": "false", "tgwui_narrator_enabled": "false",
"tgwui_non_quoted_text_is": "narrator", "tgwui_non_quoted_text_is": "silent",
"tgwui_deepspeed_enabled": false, "tgwui_deepspeed_enabled": false,
"tgwui_language": "English", "tgwui_language": "English",
"tgwui_lowvram_enabled": false, "tgwui_lowvram_enabled": false,
@@ -12,16 +12,18 @@
"tgwui_temperature_set": 0.75, "tgwui_temperature_set": 0.75,
"tgwui_repetitionpenalty_set": 10, "tgwui_repetitionpenalty_set": 10,
"tgwui_generationspeed_set": 1, "tgwui_generationspeed_set": 1,
"tgwui_narrator_voice": "Please Refresh Settings", "tgwui_narrator_voice": "en_US-ljspeech-high.onnx",
"tgwui_show_text": true, "tgwui_show_text": true,
"tgwui_character_voice": "Please Refresh Settings", "tgwui_character_voice": "en_US-ljspeech-high.onnx",
"tgwui_rvc_char_voice": "Disabled", "tgwui_rvc_char_voice": "Disabled",
"tgwui_rvc_narr_voice": "Disabled" "tgwui_rvc_char_pitch": 0,
"tgwui_rvc_narr_voice": "Disabled",
"tgwui_rvc_narr_pitch": 0
}, },
"api_def": { "remote_connection": {
"api_use_legacy_api": false, "server_protocol": "http://",
"api_alltalk_protocol": "http://", "server_address": "127.0.0.1:7851",
"api_alltalk_ip_port": "127.0.0.1:7851", "connection_timeout": 5,
"api_connection_timeout": 5 "use_legacy_api": false
} }
} }
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 KiB

-2
View File
@@ -1,2 +0,0 @@
{
}
-2
View File
@@ -1,2 +0,0 @@
{
}
+295 -259
View File
@@ -145,7 +145,7 @@ CONDA PACKAGES IN CURRENT ENVIRONMENT:
harfbuzz Version: 9.0.0 Channel: conda-forge harfbuzz Version: 9.0.0 Channel: conda-forge
icu Version: 75.1 Channel: conda-forge icu Version: 75.1 Channel: conda-forge
lcms2 Version: 2.15 Channel: conda-forge lcms2 Version: 2.15 Channel: conda-forge
libexpat Version: 2.6.3 Channel: conda-forge libexpat Version: 2.6.4 Channel: conda-forge
libglib Version: 2.82.2 Channel: conda-forge libglib Version: 2.82.2 Channel: conda-forge
libiconv Version: 1.17 Channel: conda-forge libiconv Version: 1.17 Channel: conda-forge
libintl Version: 0.22.5 Channel: conda-forge libintl Version: 0.22.5 Channel: conda-forge
@@ -153,18 +153,18 @@ CONDA PACKAGES IN CURRENT ENVIRONMENT:
libpng Version: 1.6.44 Channel: conda-forge libpng Version: 1.6.44 Channel: conda-forge
libsqlite Version: 3.47.0 Channel: conda-forge libsqlite Version: 3.47.0 Channel: conda-forge
libxcb Version: 1.13 Channel: conda-forge libxcb Version: 1.13 Channel: conda-forge
libxml2 Version: 2.13.4 Channel: conda-forge libxml2 Version: 2.13.5 Channel: conda-forge
libzlib Version: 1.3.1 Channel: conda-forge libzlib Version: 1.3.1 Channel: conda-forge
openh264 Version: 2.4.1 Channel: conda-forge openh264 Version: 2.4.1 Channel: conda-forge
openssl Version: 3.3.2 Channel: conda-forge openssl Version: 3.4.0 Channel: conda-forge
pcre2 Version: 10.44 Channel: conda-forge pcre2 Version: 10.44 Channel: conda-forge
pixman Version: 0.43.4 Channel: conda-forge pixman Version: 0.43.4 Channel: conda-forge
python Version: 3.11.10 Channel: conda-forge python Version: 3.11.10 Channel: conda-forge
python_abi Version: 3.11 Channel: conda-forge python_abi Version: 3.11 Channel: conda-forge
svt-av1 Version: 2.2.1 Channel: conda-forge svt-av1 Version: 2.2.1 Channel: conda-forge
tk Version: 8.6.13 Channel: conda-forge tk Version: 8.6.13 Channel: conda-forge
vc14_runtime Version: 14.40.33810 Channel: conda-forge vc14_runtime Version: 14.42.34433 Channel: conda-forge
vs2015_runtime Version: 14.40.33810 Channel: conda-forge vs2015_runtime Version: 14.42.34433 Channel: conda-forge
x264 Version: 1!164.3095 Channel: conda-forge x264 Version: 1!164.3095 Channel: conda-forge
x265 Version: 3.5 Channel: conda-forge x265 Version: 3.5 Channel: conda-forge
xorg-libxau Version: 1.0.11 Channel: conda-forge xorg-libxau Version: 1.0.11 Channel: conda-forge
@@ -180,7 +180,6 @@ CONDA PACKAGES IN CURRENT ENVIRONMENT:
certifi Version: 2024.8.30 Channel: pkgs/main certifi Version: 2024.8.30 Channel: pkgs/main
charset-normalizer Version: 3.3.2 Channel: pkgs/main charset-normalizer Version: 3.3.2 Channel: pkgs/main
dav1d Version: 1.2.1 Channel: pkgs/main dav1d Version: 1.2.1 Channel: pkgs/main
filelock Version: 3.13.1 Channel: pkgs/main
font-ttf-dejavu-sans-mono Version: 2.37 Channel: pkgs/main font-ttf-dejavu-sans-mono Version: 2.37 Channel: pkgs/main
font-ttf-inconsolata Version: 2.001 Channel: pkgs/main font-ttf-inconsolata Version: 2.001 Channel: pkgs/main
font-ttf-source-code-pro Version: 2.030 Channel: pkgs/main font-ttf-source-code-pro Version: 2.030 Channel: pkgs/main
@@ -224,7 +223,6 @@ CONDA PACKAGES IN CURRENT ENVIRONMENT:
sqlite Version: 3.45.3 Channel: pkgs/main sqlite Version: 3.45.3 Channel: pkgs/main
sympy Version: 1.13.2 Channel: pkgs/main sympy Version: 1.13.2 Channel: pkgs/main
tbb Version: 2021.8.0 Channel: pkgs/main tbb Version: 2021.8.0 Channel: pkgs/main
typing_extensions Version: 4.11.0 Channel: pkgs/main
ucrt Version: 10.0.20348.0 Channel: pkgs/main ucrt Version: 10.0.20348.0 Channel: pkgs/main
urllib3 Version: 2.2.3 Channel: pkgs/main urllib3 Version: 2.2.3 Channel: pkgs/main
vc Version: 14.40 Channel: pkgs/main vc Version: 14.40 Channel: pkgs/main
@@ -250,17 +248,15 @@ CONDA PACKAGES IN CURRENT ENVIRONMENT:
PACKAGE VERSIONS vs REQUIREMENTS FILE: PACKAGE VERSIONS vs REQUIREMENTS FILE:
coqui-tts Required: >= 0.24.3 Installed: 0.24.3 coqui-tts Required: >= 0.24.3 Installed: 0.24.3
faster-whisper Required: >= 1.0.3 Installed: 1.0.3 filelock Required: >= 3.16.1 Installed: 3.13.4
fuzzywuzzy Required: >= 0.18.0 Installed: 0.18.0 fuzzywuzzy Required: >= 0.18.0 Installed: 0.18.0
gradio Required: >= 4.44.1 Installed: 4.32.2 gradio Required: == 4.44.1 Installed: 4.44.1
importlib_metadata Required: >= 7.2.1 Installed: 8.5.0 importlib_metadata Required: >= 7.2.1 Installed: 8.5.0
inputimeout Required: >= 1.0.4 Installed: 1.0.4 inputimeout Required: >= 1.0.4 Installed: 1.0.4
Jinja2 Required: >= 3.1.4 Installed: 3.1.4 Jinja2 Required: >= 3.1.4 Installed: 3.1.4
librosa Required: >= 0.10.2.post1 Installed: 0.10.2.post1 librosa Required: >= 0.10.2.post1 Installed: 0.10.2.post1
nvidia-cublas-cu11 Required: >= 11.11.3.6 Installed: 11.11.3.6 onnxruntime-gpu Required: >= 1.18.1 Installed: 1.20.1
nvidia-cudnn-cu11 Required: >= 9.1.1.17 Installed: 9.5.1.17 pydantic Required: >= 2.8.2 Installed: 2.10.1
onnxruntime-gpu Required: >= 1.18.1 Installed: 1.20.0
pydantic Required: >= 2.8.2 Installed: 2.9.2
python-ffmpeg Required: >= 2.0.12 Installed: 2.0.12 python-ffmpeg Required: >= 2.0.12 Installed: 2.0.12
python-Levenshtein Required: >= 0.25.1 Installed: 0.26.1 python-Levenshtein Required: >= 0.25.1 Installed: 0.26.1
praat-parselmouth Required: >= 0.4.4 Installed: 0.4.5 praat-parselmouth Required: >= 0.4.4 Installed: 0.4.5
@@ -269,261 +265,300 @@ PACKAGE VERSIONS vs REQUIREMENTS FILE:
soundfile Required: >= 0.12.1 Installed: 0.12.1 soundfile Required: >= 0.12.1 Installed: 0.12.1
spacy Required: >= 3.7.1 Installed: 3.7.5 spacy Required: >= 3.7.1 Installed: 3.7.5
torchcrepe Required: >= 0.0.2 Installed: 0.0.23 torchcrepe Required: >= 0.0.2 Installed: 0.0.23
tqdm Required: >= 4.66.5 Installed: 4.66.6 tqdm Required: >= 4.66.5 Installed: 4.67.0
unidic-lite Required: >= 1.0.8 Installed: 1.0.8 unidic-lite Required: >= 1.0.8 Installed: 1.0.8
uvicorn Required: >= 0.29.0 Installed: 0.32.0 uvicorn Required: >= 0.29.0 Installed: 0.32.1
pillow Required: == 10.3.0 Installed: 10.3.0 pillow Required: == 10.3.0 Installed: 10.3.0
pypinyin Required: >= 0.52.0 Installed: 0.53.0 pypinyin Required: >= 0.52.0 Installed: 0.53.0
word2number Required: >= 1.1 Installed: 1.1 word2number Required: >= 1.1 Installed: 1.1
cutlet Required: == 0.4.0 Installed: 0.4.0 cutlet Required: == 0.4.0 Installed: 0.4.0
fugashi Required: == 1.3.1 Installed: 1.3.1 fugashi Required: == 1.3.1 Installed: 1.3.1
fastapi Required: == 0.112.2 Installed: 0.112.2 fastapi Required: == 0.112.2 Installed: 0.112.2
ctranslate2 Required: == 4.4.0 Installed: 4.4.0 plotly Required: == 5.24.1 Installed: 5.24.1
scipy Required: == 1.14.1 Installed: 1.14.1
PYTHON PACKAGES: PYTHON PACKAGES:
absl-py = 2.1.0 absl-py = 2.1.0
aiofiles = 23.2.1 accelerate = 1.1.1
aiohappyeyeballs = 2.4.3 aiofiles = 23.2.1
aiohttp = 3.10.10 aiohappyeyeballs = 2.4.3
aiosignal = 1.3.1 aiohttp = 3.11.7
altair = 5.4.1 aiosignal = 1.3.1
annotated-types = 0.7.0 altair = 5.4.1
antlr4-python3-runtime = 4.9.3 annotated-types = 0.7.0
anyascii = 0.3.2 antlr4-python3-runtime = 4.9.3
anyio = 4.6.2.post1 anyascii = 0.3.2
argbind = 0.3.9 anyio = 4.6.2.post1
asttokens = 2.4.1 argbind = 0.3.9
attrs = 24.2.0 asttokens = 2.4.1
audioread = 3.0.1 attrs = 24.2.0
av = 12.3.0 audioread = 3.0.1
babel = 2.16.0 babel = 2.16.0
bitarray = 3.0.0 bitarray = 3.0.0
blis = 0.7.11 bitsandbytes = 0.44.1
Brotli = 1.0.9 blis = 0.7.11
catalogue = 2.0.10 boto3 = 1.35.67
certifi = 2024.8.30 botocore = 1.35.67
cffi = 1.17.1 Brotli = 1.0.9
charset-normalizer = 3.3.2 cached_path = 1.6.4
click = 8.1.7 cachetools = 5.5.0
cloudpathlib = 0.20.0 catalogue = 2.0.10
colorama = 0.4.6 certifi = 2024.8.30
coloredlogs = 15.0.1 cffi = 1.17.1
confection = 0.1.5 charset-normalizer = 3.3.2
contourpy = 1.3.0 click = 8.1.7
coqpit = 0.0.17 cloudpathlib = 0.20.0
coqui-tts = 0.24.3 colorama = 0.4.6
coqui-tts-trainer = 0.1.6 coloredlogs = 15.0.1
ctranslate2 = 4.4.0 confection = 0.1.5
cutlet = 0.4.0 contourpy = 1.3.1
cycler = 0.12.1 coqpit = 0.0.17
cymem = 2.0.8 coqui-tts = 0.24.3
Cython = 3.0.11 coqui-tts-trainer = 0.1.7
dateparser = 1.1.8 cutlet = 0.4.0
decorator = 5.1.1 cycler = 0.12.1
deepspeed = 0.14.0+ce78a63 cymem = 2.0.8
descript-audiotools = 0.7.4 Cython = 3.0.11
descript-audio-codec = 1.0.0 datasets = 3.1.0
docopt = 0.6.2 dateparser = 1.1.8
docstring_parser = 0.16 decorator = 5.1.1
einops = 0.8.0 deepspeed = 0.14.0+ce78a63
encodec = 0.1.1 descript-audiotools = 0.7.4
executing = 2.1.0 descript-audio-codec = 1.0.0
fairseq = 0.12.4 dill = 0.3.8
faiss = 1.9.0 docker-pycreds = 0.4.0
fastapi = 0.112.2 docopt = 0.6.2
faster-whisper = 1.0.3 docstring_parser = 0.16
ffmpy = 0.4.0 einops = 0.8.0
filelock = 3.13.1 einx = 0.3.0
fire = 0.7.0 ema-pytorch = 0.7.6
flatbuffers = 24.3.25 encodec = 0.1.1
flatten-dict = 0.4.2 executing = 2.1.0
fonttools = 4.54.1 f5-tts = 0.1.2
frozenlist = 1.5.0 fairseq = 0.12.4
fsspec = 2024.10.0 faiss = 1.9.0
fugashi = 1.3.1 fastapi = 0.112.2
future = 1.0.0 ffmpy = 0.4.0
fuzzywuzzy = 0.18.0 filelock = 3.13.4
gmpy2 = 2.1.2 fire = 0.7.0
gradio = 4.32.2 flatbuffers = 24.3.25
gradio_client = 0.17.0 flatten-dict = 0.4.2
grpcio = 1.67.1 fonttools = 4.55.0
gruut = 2.4.0 frozendict = 2.4.6
gruut-ipa = 0.13.0 frozenlist = 1.5.0
gruut_lang_de = 2.0.1 fsspec = 2024.9.0
gruut_lang_en = 2.0.1 fugashi = 1.3.1
gruut_lang_es = 2.0.1 future = 1.0.0
gruut_lang_fr = 2.0.2 fuzzywuzzy = 0.18.0
h11 = 0.14.0 gitdb = 4.0.11
hangul-romanize = 0.1.0 GitPython = 3.1.43
hjson = 3.1.0 gmpy2 = 2.1.2
httpcore = 1.0.6 googleapis-common-protos = 1.66.0
httpx = 0.27.2 google-api-core = 2.23.0
huggingface-hub = 0.26.2 google-auth = 2.36.0
humanfriendly = 10.0 google-cloud-core = 2.4.1
hydra-core = 1.3.2 google-cloud-storage = 2.18.2
idna = 3.7 google-crc32c = 1.6.0
importlib_metadata = 8.5.0 google-resumable-media = 2.7.2
importlib_resources = 6.4.5 gradio = 4.44.1
inflect = 7.4.0 gradio_client = 1.3.0
inputimeout = 1.0.4 grpcio = 1.68.0
ipython = 8.29.0 gruut = 2.4.0
jaconv = 0.4.0 gruut-ipa = 0.13.0
jedi = 0.19.1 gruut_lang_de = 2.0.1
Jinja2 = 3.1.4 gruut_lang_en = 2.0.1
joblib = 1.4.2 gruut_lang_es = 2.0.1
jsonlines = 1.2.0 gruut_lang_fr = 2.0.2
jsonschema = 4.23.0 h11 = 0.14.0
jsonschema-specifications = 2024.10.1 hangul-romanize = 0.1.0
julius = 0.2.7 hjson = 3.1.0
kiwisolver = 1.4.7 httpcore = 1.0.7
langcodes = 3.4.1 httpx = 0.27.2
language_data = 1.2.0 huggingface-hub = 0.26.2
lazy_loader = 0.4 humanfriendly = 10.0
Levenshtein = 0.26.1 hydra-core = 1.3.2
librosa = 0.10.2.post1 idna = 3.7
llvmlite = 0.43.0 importlib_metadata = 8.5.0
local-attention = 1.9.15 importlib_resources = 6.4.5
lxml = 5.3.0 inflect = 7.4.0
marisa-trie = 1.2.1 inputimeout = 1.0.4
Markdown = 3.7 ipython = 8.29.0
markdown2 = 2.5.1 jaconv = 0.4.0
markdown-it-py = 3.0.0 jedi = 0.19.2
MarkupSafe = 2.1.3 jieba = 0.42.1
matplotlib = 3.9.2 Jinja2 = 3.1.4
matplotlib-inline = 0.1.7 jmespath = 1.0.1
mdurl = 0.1.2 joblib = 1.4.2
mkl_fft = 1.3.11 jsonlines = 1.2.0
mkl_random = 1.2.8 jsonschema = 4.23.0
mkl-service = 2.4.0 jsonschema-specifications = 2024.10.1
mojimoji = 0.0.13 julius = 0.2.7
more-itertools = 10.5.0 kiwisolver = 1.4.7
mpmath = 1.3.0 langcodes = 3.5.0
msgpack = 1.1.0 language_data = 1.3.0
multidict = 6.1.0 lazy_loader = 0.4
murmurhash = 1.0.10 Levenshtein = 0.26.1
narwhals = 1.13.2 librosa = 0.10.2.post1
networkx = 3.2.1 llvmlite = 0.43.0
ninja = 1.11.1.1 local-attention = 1.9.15
num2words = 0.5.13 lxml = 5.3.0
numba = 0.60.0 marisa-trie = 1.2.1
numpy = 1.26.4 Markdown = 3.7
nvidia-cublas-cu11 = 11.11.3.6 markdown2 = 2.5.1
nvidia-cudnn-cu11 = 9.5.1.17 markdown-it-py = 3.0.0
omegaconf = 2.3.0 MarkupSafe = 2.1.3
onnxruntime = 1.20.0 matplotlib = 3.9.2
onnxruntime-gpu = 1.20.0 matplotlib-inline = 0.1.7
orjson = 3.10.11 mdurl = 0.1.2
packaging = 24.1 mkl_fft = 1.3.11
pandas = 2.2.3 mkl_random = 1.2.8
parler_tts = 0.2.1 mkl-service = 2.4.0
parso = 0.8.4 mojimoji = 0.0.13
pillow = 10.3.0 more-itertools = 10.5.0
pip = 24.2 mpmath = 1.3.0
platformdirs = 4.3.6 msgpack = 1.1.0
pooch = 1.8.2 multidict = 6.1.0
portalocker = 2.10.1 multiprocess = 0.70.16
praat-parselmouth = 0.4.5 murmurhash = 1.0.10
preshed = 3.0.9 narwhals = 1.14.1
prompt_toolkit = 3.0.48 networkx = 3.2.1
propcache = 0.2.0 ninja = 1.11.1.1
protobuf = 4.25.5 num2words = 0.5.13
psutil = 6.1.0 numba = 0.60.0
pure_eval = 0.2.3 numpy = 1.26.4
pycparser = 2.22 omegaconf = 2.3.0
pydantic = 2.9.2 onnxruntime-gpu = 1.20.1
pydantic_core = 2.23.4 openai-whisper = 20240930
pydub = 0.25.1 orjson = 3.10.11
pyee = 12.0.0 packaging = 24.1
Pygments = 2.18.0 pandas = 2.2.3
pyloudnorm = 0.1.1 parso = 0.8.4
pynvml = 11.5.3 pillow = 10.3.0
pyparsing = 3.2.0 pip = 24.2
pypinyin = 0.53.0 platformdirs = 4.3.6
PyQt6 = 6.7.1 plotly = 5.24.1
PyQt6-Qt6 = 6.7.3 pooch = 1.8.2
PyQt6_sip = 13.8.0 portalocker = 3.0.0
pyreadline3 = 3.5.4 praat-parselmouth = 0.4.5
pysbd = 0.3.4 preshed = 3.0.9
PySocks = 1.7.1 prompt_toolkit = 3.0.48
pystoi = 0.4.1 propcache = 0.2.0
python-crfsuite = 0.9.11 protobuf = 4.25.5
python-dateutil = 2.9.0.post0 proto-plus = 1.25.0
python-ffmpeg = 2.0.12 psutil = 6.1.0
python-Levenshtein = 0.26.1 pure_eval = 0.2.3
python-multipart = 0.0.17 pyarrow = 18.0.0
pytz = 2024.2 pyasn1 = 0.6.1
pywin32 = 308 pyasn1_modules = 0.4.1
pyworld = 0.3.4 pycparser = 2.22
PyYAML = 6.0.2 pydantic = 2.10.1
py-cpuinfo = 9.0.0 pydantic_core = 2.27.1
randomname = 0.2.1 pydub = 0.25.1
RapidFuzz = 3.10.1 pyee = 12.1.1
referencing = 0.35.1 Pygments = 2.18.0
regex = 2024.9.11 pyloudnorm = 0.1.1
requests = 2.32.3 pynvml = 11.5.3
resampy = 0.4.3 pyparsing = 3.2.0
rich = 13.9.4 pypinyin = 0.53.0
rotary-embedding-torch = 0.8.4 PyQt6 = 6.7.1
rpds-py = 0.20.1 PyQt6-Qt6 = 6.7.3
ruff = 0.7.2 PyQt6_sip = 13.8.0
sacrebleu = 2.4.3 pyreadline3 = 3.5.4
safetensors = 0.4.5 pysbd = 0.3.4
scikit-learn = 1.5.2 PySocks = 1.7.1
scipy = 1.14.1 pystoi = 0.4.1
semantic-version = 2.10.0 python-crfsuite = 0.9.11
sentencepiece = 0.2.0 python-dateutil = 2.9.0.post0
setuptools = 75.1.0 python-ffmpeg = 2.0.12
shellingham = 1.5.4 python-Levenshtein = 0.26.1
six = 1.16.0 python-multipart = 0.0.17
smart-open = 7.0.5 pytz = 2024.2
sniffio = 1.3.1 pywin32 = 308
sounddevice = 0.5.1 pyworld = 0.3.4
soundfile = 0.12.1 PyYAML = 6.0.2
soxr = 0.5.0.post1 py-cpuinfo = 9.0.0
spacy = 3.7.5 randomname = 0.2.1
spacy-legacy = 3.0.12 RapidFuzz = 3.10.1
spacy-loggers = 1.0.5 referencing = 0.35.1
srsly = 2.4.8 regex = 2024.11.6
stack-data = 0.6.3 requests = 2.32.3
starlette = 0.38.6 resampy = 0.4.3
SudachiDict-core = 20241021 rich = 13.9.4
SudachiPy = 0.6.8 rotary-embedding-torch = 0.8.5
sympy = 1.13.2 rpds-py = 0.21.0
tabulate = 0.9.0 rsa = 4.9
tensorboard = 2.18.0 ruff = 0.7.4
tensorboard-data-server = 0.7.2 s3transfer = 0.10.4
termcolor = 2.5.0 sacrebleu = 2.4.3
thinc = 8.2.5 safetensors = 0.4.5
threadpoolctl = 3.5.0 scikit-learn = 1.5.2
tokenizers = 0.20.3 scipy = 1.14.1
tomlkit = 0.12.0 semantic-version = 2.10.0
torch = 2.2.1 sentencepiece = 0.2.0
torchaudio = 2.2.1 sentry-sdk = 2.19.0
torchcrepe = 0.0.23 setproctitle = 1.3.4
torchvision = 0.17.1 setuptools = 75.1.0
torch-stoi = 0.2.3 shellingham = 1.5.4
tqdm = 4.66.6 six = 1.16.0
traitlets = 5.14.3 smart-open = 7.0.5
transformers = 4.46.1 smmap = 5.0.1
typeguard = 4.4.1 sniffio = 1.3.1
typer = 0.12.5 sounddevice = 0.5.1
typing_extensions = 4.11.0 soundfile = 0.12.1
tzdata = 2024.2 soxr = 0.5.0.post1
tzlocal = 5.2 spacy = 3.7.5
unidic-lite = 1.0.8 spacy-legacy = 3.0.12
urllib3 = 2.2.3 spacy-loggers = 1.0.5
uvicorn = 0.32.0 srsly = 2.4.8
wasabi = 1.1.3 stack-data = 0.6.3
wcwidth = 0.2.13 starlette = 0.38.6
weasel = 0.4.1 SudachiDict-core = 20241021
websockets = 11.0.3 SudachiPy = 0.6.9
Werkzeug = 3.1.2 sympy = 1.13.2
wheel = 0.44.0 tabulate = 0.9.0
win-inet-pton = 1.1.0 tenacity = 9.0.0
word2number = 1.1 tensorboard = 2.18.0
wrapt = 1.16.0 tensorboard-data-server = 0.7.2
yarl = 1.17.1 termcolor = 2.5.0
zipp = 3.20.2 thinc = 8.2.5
threadpoolctl = 3.5.0
tiktoken = 0.8.0
tokenizers = 0.20.3
tomli = 2.1.0
tomlkit = 0.12.0
torch = 2.2.1
torchaudio = 2.2.1
torchcrepe = 0.0.23
torchdiffeq = 0.2.5
torchvision = 0.17.1
torch-stoi = 0.2.3
tqdm = 4.67.0
traitlets = 5.14.3
transformers = 4.46.1
transformers-stream-generator = 0.0.5
typeguard = 4.4.1
typer = 0.13.1
typing_extensions = 4.12.2
tzdata = 2024.2
tzlocal = 5.2
unidic-lite = 1.0.8
urllib3 = 2.2.3
uvicorn = 0.32.1
vocos = 0.1.0
wandb = 0.18.7
wasabi = 1.1.3
wcwidth = 0.2.13
weasel = 0.4.1
websockets = 11.0.3
Werkzeug = 3.1.3
wheel = 0.44.0
win-inet-pton = 1.1.0
word2number = 1.1
wrapt = 1.17.0
xxhash = 3.5.0
x-transformers = 1.42.12
yarl = 1.18.0
zipp = 3.21.0
DeepSpeed Installation Requirements: DeepSpeed Installation Requirements:
OS : Windows OS : Windows
@@ -534,3 +569,4 @@ DeepSpeed Installation Requirements:
To install DeepSpeed, run the following command based on your environment: To install DeepSpeed, run the following command based on your environment:
pip install deepspeed==<version> --no-cache-dir pip install deepspeed==<version> --no-cache-dir
Ensure to choose the correct DeepSpeed version matching your environment. Ensure to choose the correct DeepSpeed version matching your environment.
+32 -50
View File
@@ -1,18 +1,19 @@
import json import json
import os import os
import time
import shutil import shutil
import sys
import zipfile import zipfile
import requests import requests
from tqdm import tqdm from tqdm import tqdm
from inputimeout import inputimeout, TimeoutOccurred from inputimeout import inputimeout, TimeoutOccurred
from pathlib import Path 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() 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): def download_file(url, dest_path):
response = requests.get(url, stream=True) response = requests.get(url, stream=True)
@@ -60,31 +61,14 @@ def setup_xtts():
def update_tts_engines(engine, model): def update_tts_engines(engine):
with open(tts_engines_path, 'r') as file: AlltalkTTSEnginesConfig.get_instance().change_engine(engine).save()
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 set_firstrun_model_false(): def set_firstrun_model_false():
with open(config_path, 'r') as file: config.firstrun_model = False
config = json.load(file) config.save()
config['firstrun_model'] = False def warning_message():
with open(config_path, 'w') as file:
json.dump(config, file, indent=4)
def load_config(file_path):
with open(file_path, "r") as config_file:
config = json.load(config_file)
return config
def warning_mesasge():
print(f"[{branding}TTS]") 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[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") 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] \033[0m'using untested triton version' \033[93mmessages.\033[0m")
print(f"[{branding}TTS]") print(f"[{branding}TTS]")
# Load confignew.json # Load confignew.json (might be version 1 or 2):
with open(config_path, 'r') as file: with open(AlltalkConfig.default_config_path(), 'r') as file:
config = json.load(file) config_json = json.load(file)
branding = config['branding'] branding = config_json['branding']
# Check if the config file is version 1 # 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] Detected version 1 configuration file.")
print(f"[{branding}TTS] Upgrading to version 2 configuration file...") print(f"[{branding}TTS] Upgrading to version 2 configuration file...")
# Backup the old configuration file # Backup the old configuration file
backup_path = config_path + ".backup" backup_path = AlltalkConfig.default_config_path() + ".backup"
shutil.copyfile(config_path, backup_path) shutil.copyfile(AlltalkConfig.default_config_path(), backup_path)
# Copy the new configuration template to replace the old config file # 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.") print(f"[{branding}TTS] Configuration file upgraded successfully.")
# Reload the new config file config = AlltalkConfig.get_instance()
with open(config_path, 'r') as file: branding = config.branding
config = json.load(file)
# Check if firstrun_model is true # Check if firstrun_model is true
if config.get('firstrun_model', False): if config.firstrun_model:
print(f"[{branding}TTS]") 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[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] \033[92mtab after inital setup.\033[0m")
print(f"[{branding}TTS]") print(f"[{branding}TTS]")
@@ -159,32 +143,30 @@ if config.get('firstrun_model', False):
os.makedirs('models/piper', exist_ok=True) os.makedirs('models/piper', exist_ok=True)
os.makedirs('models/vits', exist_ok=True) os.makedirs('models/vits', exist_ok=True)
os.makedirs('models/xtts/', exist_ok=True) os.makedirs('models/xtts/', exist_ok=True)
update_tts_engines('piper', 'piper') update_tts_engines('piper')
set_firstrun_model_false() set_firstrun_model_false()
warning_mesasge() warning_message()
exit() exit()
if user_choice is not None and user_choice.isdigit() and 1 <= int(user_choice) <= len(models): if user_choice is not None and user_choice.isdigit() and 1 <= int(user_choice) <= len(models):
selected_model = models[int(user_choice) - 1] selected_model = models[int(user_choice) - 1]
warning_mesasge() warning_message()
if user_choice is None or user_choice.lower() != 'own': if user_choice is None or user_choice.lower() != 'own':
if selected_model['name'] == 'piper': if selected_model['name'] == 'piper':
setup_piper() setup_piper()
update_tts_engines('piper', 'piper') update_tts_engines('piper')
set_firstrun_model_false()
elif selected_model['name'] == 'vits': elif selected_model['name'] == 'vits':
setup_vits() setup_vits()
update_tts_engines('vits', 'vits - tts_models--en--vctk--vits') update_tts_engines('vits')
set_firstrun_model_false()
elif selected_model['name'] == 'xtts': elif selected_model['name'] == 'xtts':
setup_xtts() setup_xtts()
update_tts_engines('xtts', 'xtts - xttsv2_2.0.3') update_tts_engines('xtts')
set_firstrun_model_false()
print(f"[{branding}TTS] {selected_model['name']} model downloaded and configuration updated successfully.") print(f"[{branding}TTS] {selected_model['name']} model downloaded and configuration updated successfully.")
# Set firstrun_model to false # Set firstrun_model to false
set_firstrun_model_false() set_firstrun_model_false()
warning_mesasge() warning_message()
exit() exit()
else: else:
exit() exit()
+30 -46
View File
@@ -1,18 +1,19 @@
import json import json
import os import os
import time
import shutil import shutil
import sys
import zipfile import zipfile
import requests import requests
from tqdm import tqdm from tqdm import tqdm
from inputimeout import inputimeout, TimeoutOccurred from inputimeout import inputimeout, TimeoutOccurred
from pathlib import Path 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() 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): def download_file(url, dest_path):
response = requests.get(url, stream=True) response = requests.get(url, stream=True)
@@ -60,31 +61,14 @@ def setup_xtts():
def update_tts_engines(engine, model): def update_tts_engines(engine):
with open(tts_engines_path, 'r') as file: AlltalkTTSEnginesConfig.get_instance().change_engine(engine).save()
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 set_firstrun_model_false(): def set_firstrun_model_false():
with open(config_path, 'r') as file: config.firstrun_model = False
config = json.load(file) config.save()
config['firstrun_model'] = False def warning_message():
with open(config_path, 'w') as file:
json.dump(config, file, indent=4)
def load_config(file_path):
with open(file_path, "r") as config_file:
config = json.load(config_file)
return config
def warning_mesasge():
print(f"[{branding}TTS]") 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[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") 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] \033[0m'using untested triton version' \033[93mmessages.\033[0m")
print(f"[{branding}TTS]") print(f"[{branding}TTS]")
# Load confignew.json # Load confignew.json (might be version 1 or 2):
with open(config_path, 'r') as file: with open(AlltalkConfig.default_config_path(), 'r') as file:
config = json.load(file) config_json = json.load(file)
branding = config['branding'] branding = config_json['branding']
# Check if the config file is version 1 # 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] Detected version 1 configuration file.")
print(f"[{branding}TTS] Upgrading to version 2 configuration file...") print(f"[{branding}TTS] Upgrading to version 2 configuration file...")
# Backup the old configuration file # Backup the old configuration file
backup_path = config_path + ".backup" backup_path = AlltalkConfig.default_config_path() + ".backup"
shutil.copyfile(config_path, backup_path) shutil.copyfile(AlltalkConfig.default_config_path(), backup_path)
# Copy the new configuration template to replace the old config file # 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.") print(f"[{branding}TTS] Configuration file upgraded successfully.")
# Reload the new config file config = AlltalkConfig.get_instance()
with open(config_path, 'r') as file: branding = config.branding
config = json.load(file)
# Check if firstrun_model is true # Check if firstrun_model is true
if config.get('firstrun_model', False): if config.firstrun_model:
print(f"[{branding}TTS]") 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] \033[92mThis is the first time startup. Please download a start TTS model.\033[0m")
print(f"[{branding}TTS]") print(f"[{branding}TTS]")
@@ -157,30 +141,30 @@ if config.get('firstrun_model', False):
os.makedirs('models/piper', exist_ok=True) os.makedirs('models/piper', exist_ok=True)
os.makedirs('models/vits', exist_ok=True) os.makedirs('models/vits', exist_ok=True)
os.makedirs('models/xtts/', exist_ok=True) os.makedirs('models/xtts/', exist_ok=True)
update_tts_engines('piper', 'piper') update_tts_engines('piper')
set_firstrun_model_false() set_firstrun_model_false()
warning_mesasge() warning_message()
exit() exit()
if user_choice is not None and user_choice.isdigit() and 1 <= int(user_choice) <= len(models): if user_choice is not None and user_choice.isdigit() and 1 <= int(user_choice) <= len(models):
selected_model = models[int(user_choice) - 1] selected_model = models[int(user_choice) - 1]
warning_mesasge() warning_message()
if user_choice is None or user_choice.lower() != 'own': if user_choice is None or user_choice.lower() != 'own':
if selected_model['name'] == 'piper': if selected_model['name'] == 'piper':
setup_piper() setup_piper()
update_tts_engines('piper', 'piper') update_tts_engines('piper')
elif selected_model['name'] == 'vits': elif selected_model['name'] == 'vits':
setup_vits() setup_vits()
update_tts_engines('vits', 'vits - tts_models--en--vctk--vits') update_tts_engines('vits')
elif selected_model['name'] == 'xtts': elif selected_model['name'] == 'xtts':
setup_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.") print(f"[{branding}TTS] {selected_model['name']} model downloaded and configuration updated successfully.")
# Set firstrun_model to false # Set firstrun_model to false
set_firstrun_model_false() set_firstrun_model_false()
warning_mesasge() warning_message()
exit() exit()
else: else:
exit() exit()
-16
View File
@@ -1,16 +0,0 @@
import gradio as gr
def alltalk_about():
about = """
### 🛠️ About this project
> AllTalk is a labour of love that has been developed, supported and sustained in my personal free time. As a solo enthusiast (not a business or team) my resources are inherently limited. This project has been one of my passions, but I must balance it with other commitments.<br><br>
To manage AllTalk sustainably, I prioritize support requests based on their overall impact and the number of users affected. I encourage you to utilize the comprehensive documentation and engage with the AllTalk community discussion area. These resources often provide immediate answers and foster a supportive user network.<br><br>
Should your inquiry extend beyond the documentation, especially if it concerns a bug or feature request, I assure you I’ll offer my best support as my schedule permits. However, please be prepared for varying response times, reflective of the personal dedication I bring to AllTalk. Your understanding and patience in this regard are greatly appreciated.<br><br>
It's important to note that **I am not** the developer of any TTS models utilized by AllTalk, nor do I claim to be an expert on them, including understanding all their nuances, issues, and quirks. For specific TTS model concerns, I’ve provided links to the original developers in each TTS engines "Engine Information" section for direct assistance/research.<br><br>
Thank you for your continued support and understanding.
### 💖 Showing Your Support
> If AllTalk has been helpful to you, consider showing your support through a donation on my **[Ko-fi page](https://ko-fi.com/erew123)**. <br><br>
Your support is greatly appreciated and helps ensure the continued development and improvement of AllTalk.
"""
gr.Markdown(about)
File diff suppressed because it is too large. Load diff
@@ -1,99 +0,0 @@
import gradio as gr
def alltalk_generation_help():
generation_blurb = """
The Generation Screen is the main interface where you can input text to generate speech, as well as swap **and set the default** Text-to-Speech (TTS) engine and model. Below is a detailed description of each setting and its functionality.
"""
generation_help = """
### 🟨 TTS Engine and Model<br>
**Swap TTS Engine**<br>
> This button allows you to change and set the current TTS engine. Swapping the engine will also set the new engine as the default for future sessions. When you swap the engine, the settings on the page will refresh to match the capabilities of the selected engine. Some settings may become unavailable or newly available depending on the chosen engine.<br>
**Load Different Model**<br>
> This dropdown lists the available models for the selected TTS engine. These models are located in the models folder and are specific to each TTS engine. Changing the model will also set it as the default for future sessions and refresh the settings on the page.<br>
### 🟨 RVC Pipeline<br>
**RVC Character Voice**<br>
> This setting is part of the RVC pipeline. If RVC is not enabled (which can be done in the RVC tab), "Disabled" will be the only option. Once RVC is enabled and the required models (approximately 700MB) are downloaded, any voices stored in the `/models/rvc_voices/{yourmodelhere}` folder will be available for selection. Selecting a voice will apply it during the TTS generation process. You can select "Disabled" at any time to bypass the RVC pipeline even when it is globally enabled.<br>
**RVC Narrator Voice**<br>
> Similar to the RVC Character Voice, this setting applies to the narrator voice in the RVC pipeline.<br>
### 🟨 Generation Settings<br>
**Generation Mode**<br>
> Choose the mode of TTS generation, such as Standard or Streaming. Note that Gradio may have difficulty with streaming, so you might receive standard audio as a file even when streaming is selected. If the engine doesn't support Streaming, only Standard mode will be shown.<br>
**Language/Model not multi-language**<br>
> Select the language for TTS generation here. Some models are **not** multi-language capable and the language it generates in is built into the model itself. In such cases, this option will change to `Model not multi-language` and it will no longer be selectable when the model doesn't support multiple languages.<br>
**Narrator Enabled/Disabled**<br>
> Enable or disable the narrator feature. When enabled, the TTS engine processes three types of text (Refer to the "Narrator Function" help tab for more details):<br>
> **Narrated Text** : Text enclosed in asterisks *Narrated text*.<br>
> **Character Text** : Text enclosed in double quotes "Character text".<br>
> **Text-Not-Inside**: Any text not enclosed in asterisks or double quotes. The handling of this text is customizable.<br>
**Narrator Text-not-inside**<br>
> Configures how text that is not enclosed in asterisks or double quotes is handled. Detailed explanations are available in the "Narrator Function" help tab.<br>
**Auto-Stop Current Generation**<br>
> If the loaded model or generation method supports stopping the current TTS generation when sending a new request, this setting will attempt to stop the current process before starting a new one.
### 🟨 Voice Selection<br>
**Character (Main TTS) Voice**<br>
> Select the character voice from the available voices within the currently loaded TTS engine and model.<br>
**Narrator Voice**<br>
> Choose the narrator voice from the available voices within the currently loaded TTS engine and model.<br>
"""
generation_help2 = """
### 🟨 Additional Settings
**Text Filtering**<br>
> **None**: No filtering. Raw text is sent to the TTS engine, which may result in odd sounds with some special characters.<br>
> **HTML**: For HTML content, using HTML entities like emojis or text characters.<br>
> **Standard**: Human-readable text with basic filtering to clean up special characters.<br>
**Play Locally or Remotely**<br>
> Choose to play the generated speech locally or on the terminal/console where the server is running.<br>
**Remote Play Volume**<br>
> Adjust the volume for remote playback.<br>
**Output File Name**<br>
> Specify the name for the output file.<br>
**Include Timestamp**<br>
> If enabled, each generated file will include a timestamp to ensure uniqueness. If disabled, the output filename will be used, and the file will be overwritten with each generation.<br>
**Speed**<br>
> Adjust the speed of the generated speech. This option is not available if the selected TTS engine doesn't support it.<br>
**Pitch**<br>
>Adjust the pitch of the generated speech. This option is not available if the selected TTS engine doesn't support it.<br>
**Temperature**<br>
> Control the randomness of the generation process. Higher values result in more varied output. This option is not available if the selected TTS engine doesn't support it.<br>
**Repetition Penalty**<br>
> Set the penalty for repetitive sequences in the generated speech. This option is not available if the selected TTS engine doesn't support it.<br>
### 🟨 Output and Controls
**TTS Result**<br>
> View the result of the TTS generation process here.<br>
**Playback Controls**<br>
> Use these controls to play, pause, and navigate through the generated speech.<br>
**Light/Dark Mode**<br>
> Toggle between light and dark mode for the interface.<br>
**Refresh Server Settings**<br>
>Refresh the server settings to apply any changes made. This is useful if you have reloaded the engine elsewhere or added new models/voices to your folders. If refreshing doesn't update your voices, you can use the "Swap TTS Engine" button to force a full refresh.<br>
**Interrupt TTS Generation**<br>
> Manually stop the current TTS generation process, similar to the "Auto-Stop Current Generation" setting but applied manually.<br>
"""
gr.Markdown(generation_blurb)
with gr.Row():
gr.Markdown(generation_help)
gr.Markdown(generation_help2)
-62
View File
@@ -1,62 +0,0 @@
import os
import json
import pathlib as Path
import gradio as gr
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)
return f"Welcome screen is disabled."
def alltalk_welcome(analytics_enabled=False):
welcome = """
## 🟧 AllTalk v2 BETA
For detailed information on using AllTalk, please look at the WIKI Github page https://github.com/erew123/alltalk_tts/wiki for the most up-to-date information, however some information is built in on the Documentation and Help tab section up above.
Please use the **Light/Dark Mode** button at the top right of this page to make it easier to read. I would suggest reading the TLDR's on this page before you disable this splash screen.
"""
welcome2 = """
### 🟧 TLDR what you need to do
> **Generating TTS & Swapping TTS Engines** - You can do this on the Generate TTS tab, Swap Engines (Piper, Parler, VITS, XTTS etc) and also choose which model to load for the currently loaded TTS Engine. There is a Generate help tab on the Generate TTS page for more details.<br>
> **Download Voices/Models** - Go to the `TTS Engines Settings` > Choose the engine you want > `Model/Voices Download`. Additional instructions/information about each TTS engine, its specific settings, how to use it, are all stored here.<br>
> **RVC & RVC Voices** - To make RVC work, you have to enable RVC in `Gloabl Settings` > `RVC Settings`. RVC will download about 800MB of models that it needs to work. [RVC WIKI page link](https://github.com/erew123/alltalk_tts/wiki/RVC-(Retrieval%E2%80%90based-Voice-Conversion))<br>
### 🟧 Error Message at the Console/Terminal
> I am mantaining an up-to-date list of known error messages and fixes on the [Error Messages WIKI page](https://github.com/erew123/alltalk_tts/wiki/Error-Messages-List)<br>
### 🟧 Showing Your Support
> If AllTalk has been helpful to you, consider showing your support through a donation on my **[Ko-fi page](https://ko-fi.com/erew123)**. Your support is greatly appreciated and helps ensure the continued development and improvement of AllTalk.
"""
welcome3 = """
### 🟧 SillyTavern users
> There is an updated ST extension and instructions for installation are in the [SillyTavern Extension WIKI page](https://github.com/erew123/alltalk_tts/wiki/SillyTavern-Extension).
### 🟧 DeepSpeed on Linux
> If you need DeepSpeed for Linux, please see the [DeepSpeed Releases page](https://github.com/erew123/alltalk_tts/releases/tag/DeepSpeed-14.2-Linux).
### 🟧 Text-generation-webui Remote Extension
> AllTalk now ALSO has a TGWUI remote server extension, allowing you to install AllTalk outside of TGWUI's Python environment. Please see [TGWUI Remote Extension WIKI page](https://github.com/erew123/alltalk_tts/wiki/Text%E2%80%90generation%E2%80%90webui-Remote-Extension).
### 🟧 Future features/Feature Requests
> The current list is available here [Feature Request List page](https://github.com/erew123/alltalk_tts/discussions/74)
### 🟧 Can I add other TTS engines?
Yes if you have a bit of coding experience. All the Coqui supported engines should be pretty easy to set up now, I just havnt gotten around it yet. Other engines like Piper and Parler have been done of course, showing other engines can be imported. Rough instructions are in the `system/tts_engines/template` folder.
"""
with gr.Tab("AllTalk v2 BETA"):
gr.Markdown(welcome)
with gr.Row():
with gr.Column(): gr.Markdown(welcome2)
with gr.Column(): gr.Markdown(welcome3)
with gr.Row():
output = gr.Textbox(label="Output")
update_btn = gr.Button("Dont show me this screen again!")
update_btn.click(fn=modify_config, inputs=None, outputs=output)
-597
View File
@@ -1,597 +0,0 @@
import gradio as gr
def api_documentation():
best_practices = """
### 🟠 Best Practices for writing an extension
You will need to store the IP address and Port (minimum) that your extension will be connecting to. Potentially also http/https if you wish to use AllTalk over tunnels. Additionally, you may also wish to store a connection timeout value.<br>
```
{
"api_alltalk_protocol": "http://",
"api_alltalk_ip_port": "127.0.0.1:7851",
"api_connection_timeout": 5
}
```
When your extension starts up you will need to connect to the IP/Port and check the **/api/ready** end point for a 'Ready' status. You may wish to do this on a loop for the period of the connection timeout.<br>
If the timeout is reached without a response, you can set voices, models available, models loaded, basically whatever values you are going to store/present to the user as "Server Offline" or whatever terminology you wish.<br>
If the connection is available, then you would:<br>
> 1) Pull the current settings and populate those into a paramaters variabele. **/api/currentsettings**<br>
2) Pull the current voices and populate those into a paramaters variabele. **/api/voices**<br>
3) Pull the current rvcvoices and populate those into a paramaters variabele. **/api/rvcvoices**<br>
You can now present those to the user interface, choosing if you are just going to present the voices (narrator or not), RVC voices, model loaded, models available etc.<br>
If you are going to present a multitude of options, please abide by the **xxxxxx_capable** settings provided by **/api/currentsettings**, disabling or enabling options in your user interface as the loaded in TTS engine does or doesnt allow for e.g. if the current TTS engine doesnt support changing your generation audio speed, it will send **"generationspeed_capable": false** over when you use **/api/currentsettings**. As such, you should disable the option to change the generation speed within your interface, however, ultimately, even if not disabled, if the current TTS engine loaded isnt capable of speed generation, changing the generation speed will have no effect on the resulting TTS generation, but you may end up with users asking why!<br>
It is also advisable to have a refresh button to pull make AllTalk update its settings **/api/reload_config** and then you can pull current settings & voices again. This ensures the use always has a way to reconnect to the AllTalk server if its unavailable when your extension starts, or in the scenario that something else was changed in the Gradio interface and now the TTS Engine loaded in is different from when your extension started up.<br>
You can obviously choose if you will give the user access to change the model loaded, TTS engine etc. Please read the documentation on the API endpoints for more information.<br>
If you are presenting all the variables/options to the user, then when you send off a generation request to **/api/tts-generate** send all of the variable/options that are stored within your interface.<br>
If you are NOT presenting all the variables/options to the user, then you have 2x options when sending to **/api/tts-generate**:<br>
> 1) Send all the values/options but hard code some settings in your outbound generation request. This will ensure you always get the TTS generation result you want. Please read the **/api/tts-generate** section for details.<br>
OR<br>
>2) Dont send all the values/options in the generation request. In this scenario, the AllTalk server will populate missing settings from the global API Default Settings and the current TTS Engine's settings that are loaded in. e.g. if you dont provide a character voice, the default set character voice of whatever TTS engine is loaded in will be used. The same goes for all the other settings, except the actual text of the generation request.<br>
Finally, depending on how you are storing your settings, for your extension, you may wish to save the settings each time there is a successful generation request. This ensures that the settings are valid and the connected IP address/port are correct.
"""
settings_endpoints = """
### 🟠 Ready Endpoint<br>
Check if the Text-to-Speech (TTS) engine has started and is ready to accept requests. This endpoint is useful when performing reload model/engine requests as it will return "Unloaded" while the engine is restarting. You can poll this endpoint every second or so to confirm a "Ready" status, indicating AllTalk is ready to process requests. Note that if there is an issue loading the selected model (e.g., missing from the file system), the endpoint will still return "Ready". This status only indicates that the engine has loaded.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **URL**: `http://{ipaddress}:{port}/api/ready`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Method**: `GET`<br>
> `curl -X GET "http://127.0.0.1:7851/api/ready"`
Response: `Ready` or `Unloaded`
### 🟠 Standard Voices List Endpoint<br>
Retrieve a list of available voices for generating speech that the currently loaded TTS engine and model supports. If the currently loaded TTS engine does not load a model directly (e.g., Piper), the models themselves will be displayed as voices.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **URL**: `http://{ipaddress}:{port}/api/voices`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Method**: `GET`<br>
> `curl -X GET "http://127.0.0.1:7851/api/voices"`
```
{
"status": "success",
"voices": ["voice1", "voice2", "voice3"]
}
```
### 🟠 RVC Voices List Endpoint<br>
Retrieve a list of available RVC voices for further processing your TTS with the RVC pipeline. `Disabled` will always be included in the list. When `Disabled` is used, the RVC pipeline will not be utilized. If the RVC pipeline is globally disabled in AllTalk, `Disabled` will be the only item in the list. Index files matching their RVC voices will not be displayed; if an index file exists for an RVC voice, it will be automatically selected during generation. If multiple index files exist and it is impossible to automatically select one, a message will be output in the console.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **URL**: `http://{ipaddress}:{port}/api/rvcvoices`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Method**: `GET`<br>
> `curl -X GET "http://127.0.0.1:7851/api/rvcvoices"`
```
{
"status": "success",
"voices": ["Disabled", "folder1\\voice1.pth", "folder2\\voice2.pth", "folder3\\voice3.pth"]
}
```
### 🟠 Current Settings Endpoint<br>
Retrieve the current settings of the TTS engine.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **URL**: `http://{ipaddress}:{port}/api/currentsettings`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Method**: `GET`<br>
> `curl -X GET "http://127.0.0.1:7851/api/currentsettings"`
```
{
"engines_available": ["parler", "piper", "vits", "xtts"],
"current_engine_loaded": "xtts",
"models_available": [
{"name": "xtts - xttsv2_2.0.2"},
{"name": "apitts - xttsv2_2.0.2"},
{"name": "xtts - xttsv2_2.0.3"},
{"name": "apitts - xttsv2_2.0.3"}
],
"current_model_loaded": "xtts - xttsv2_2.0.3",
"manufacturer_name": "Coqui",
"audio_format": "wav",
"deepspeed_capable": true,
"deepspeed_available": true,
"deepspeed_enabled": true,
"generationspeed_capable": true,
"generationspeed_set": 1,
"lowvram_capable": true,
"lowvram_enabled": false,
"pitch_capable": false,
"pitch_set": 0,
"repetitionpenalty_capable": true,
"repetitionpenalty_set": 10,
"streaming_capable": true,
"temperature_capable": true,
"temperature_set": 0.75,
"ttsengines_installed": true,
"languages_capable": true,
"multivoice_capable": true,
"multimodel_capable": true
}
```
#### **engines_available**
> Lists the currently available TTS engines that can be loaded.
#### **current_engine_loaded**
> Shows the currently loaded TTS engine.
These can be used together with the **/api/enginereload** endpoint to determine and change the currently loaded engine. Note that swapping the engine using this method can cause the main script process of AllTalk to lose sync with the subprocess. This results in a message indicating that script.py lost control of the subprocess when exiting AllTalk.
#### **models_available**
> Lists all the models available for the currently loaded TTS engine. Displayed as {engine-name - model-name} from models_available.
#### **current_model_loaded**
> Shows the currently loaded model.
You can swap models using the **/api/reload** endpoint by specifying the full {enginename - modelname}.
#### **audio_format**
> The primary format in which the currently loaded engine produces audio output. This does not account for any global transcoding settings in the AllTalk Settings page but is used by the transcoding process to determine if transcoding is necessary.
#### **deepspeed_capable**
> Indicates if the current TTS engine supports DeepSpeed and can handle DeepSpeed enable/disable requests.
#### **deepspeed_available**
> If the current TTS engine is DeepSpeed capable, shows whether DeepSpeed was detected and loaded for use.
#### **deepspeed_enabled**
> Indicates whether DeepSpeed is currently enabled or disabled for the current TTS engine, assuming the above two are true.
#### **generationspeed_capable**
> Indicates if the current TTS engine supports generating TTS at different speeds.
#### **generationspeed_set**
> Shows the current default speed set in the TTS engine's configuration settings.
#### **lowvram_capable**
> Indicates if the current TTS engine allows moving the TTS model between VRAM and System RAM, which is useful in low VRAM situations, such as when using AllTalk with an LLM that fills up VRAM. This helps keep models contiguous within VRAM and speeds up processing.
#### **lowvram_enabled**
> If the model is lowvram_capable, setting this to true allows the model to move between VRAM and System RAM as necessary.
#### **pitch_capable**
> Indicates if the current TTS engine supports generating TTS at different pitches.
#### **pitch_set**
> Shows the current default audio pitch set in the TTS engine's configuration settings.
#### **repetitionpenalty_capable**
> Indicates if the current TTS engine supports different repetition penalties for its TTS models.
#### **repetitionpenalty_set**
> Shows the current default repetition penalty set in the TTS engine's configuration settings.
#### **temperature_capable**
> Indicates if the current TTS engine supports different temperature settings for its TTS models.
#### **temperature_set**
> Shows the current default temperature set in the TTS engine's configuration settings.
#### **languages_capable**
> Indicates if the models within the current TTS engine support multiple languages. This can be used to disable language selection in your interface if necessary.
#### **multivoice_capable**
> Indicates if the current model loaded into the TTS engine supports multiple voices or just one voice. If a model is not multi-voice capable, you can display 'Default' as the only available voice.
#### **multimodel_capable**
> Some TTS engines, such as Piper, use models as voices. In such cases, you don't need to load different models but present the models as voices. If a model is not multimodel_capable, it indicates this status in your interface.
"""
openapi_endpoint = """
### 🟠 OpenAI Speech API Compatible Endpoint<br>
Validate and generate audio based on text input using an OpenAI Speech v1 API compatible endpoint, as per the documentation at [OpenAI Text-to-Speech Guide](https://platform.openai.com/docs/guides/text-to-speech) and [OpenAI API Reference](https://platform.openai.com/docs/api-reference/audio).
Voices are mapped on a one-to-one basis within the AllTalk Gradio interface on a TTS engine by TTS engine basis. If RVC is globally enabled in AllTalk settings and a voice other than "Disabled" is selected for the character voice, the chosen RVC voice will be applied after the TTS is generated and before the audio is transcoded and sent back out.
Note that there is no capability within the OpenAI API to specify a language, so the response will be in whatever language the currently loaded TTS engine and model support.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **URL**: `http://{ipaddress}:{port}/v1/audio/speech`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Method**: `POST`<br>
`curl -X POST "http://127.0.0.1:7851/v1/audio/speech" -H "Content-Type: application/json" -d "{\"model\":\"any_model_name\",\"input\":\"Hello, this is a test.\",\"voice\":\"nova\",\"response_format\":\"wav\",\"speed\":1.0}"`
The request body must be a JSON object with the following fields:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**model** (string): The TTS model to use. Currently ignored, but is required in the request.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**input** (string): The text to generate audio for. Maximum length is 4096 characters.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**voice** (string): The voice to use when generating the audio. Supported voices are ["alloy", "echo", "fable", "nova", "onyx", "shimmer"].<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**response_format** (string, optional): The format of the audio. Audio will be transcoded to the requested format.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**speed** (float, optional): The speed of the generated audio. Must be between 0.25 and 4.0. Default is 1.0. Id the TTS engine loaded doesnt support different speeds, then the audio generated will not abide by this speed request.<br><br>
```
{
"model": "any_model_name",
"input": "Hello, this is a test.",
"voice": "nova",
"response_format": "wav",
"speed": 1.0
}
```
Remapping the voices through an API call:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **URL**: `http://{ipaddress}:{port}/api/openai-voicemap`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Method**: `POST`<br>
`curl -X PUT "http://localhost:7851/api/openai-voicemap" -H "Content-Type: application/json" -d "{\"alloy\":\"female_01.wav\",\"echo\":\"female_01.wav\",\"fable\":\"female_01.wav\",\"nova\":\"female_01.wav\",\"onyx\":\"male_01.wav\",\"shimmer\":\"male_02.wav\"}"`
You can re-map the 6x voices on the fly, to any voices supported/available for the currently loaded TTS engine by using the above style post. You can use the `curl -X GET "http://127.0.0.1:7851/api/voices"` endpoint to get a list of all currently available voices. Please note that the Gradio interface will not reflect these changes until AllTalk is reloaded as gradio caches the list.
#### Python Example
```
import requests
import json
# Define the endpoint URL
url = "http://127.0.0.1:7851/v1/audio/speech"
# Define the request payload
payload = {
"model": "any_model_name",
"input": "Hello, this is a test.",
"voice": "nova",
"response_format": "wav",
"speed": 1.0
}
# Set the headers
headers = {
"Content-Type": "application/json"
}
# Send the POST request
response = requests.post(url, data=json.dumps(payload), headers=headers)
# Check the response
if response.status_code == 200:
with open("output.wav", "wb") as f:
f.write(response.content)
print("Audio file saved as output.wav")
else:
print(f"Error: {response.status_code} - {response.text}")
```
#### Javascript Example
```
// Define the endpoint URL
const url = "http://127.0.0.1:7851/v1/audio/speech";
// Define the request payload
const payload = {
model: "any_model_name",
input: "Hello, this is a test.",
voice: "nova",
response_format: "wav",
speed: 1.0
};
// Set the headers
const headers = {
"Content-Type": "application/json"
};
// Send the POST request
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(payload)
})
.then(response => {
if (response.ok) {
return response.blob();
} else {
return response.text().then(text => { throw new Error(text); });
}
})
.then(blob => {
// Create a link element
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = 'output.wav';
// Append the link to the body
document.body.appendChild(a);
// Programmatically click the link to trigger the download
a.click();
// Remove the link from the document
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
console.log("Audio file saved as output.wav");
})
.catch(error => {
console.error("Error:", error);
});
```
"""
interaction_endpoints = """
### 🟠 Stop Generation Endpoint<br>
Interrupt the current TTS generation process. When this endpoint is called, it sets tts_stop_generation in the model_engine to True, which can be used to interrupt the current TTS generation. Stop requests will only be honored if the current TTS engine is capable of handling and can honor a stop request partway through generation.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **URL**: `http://{ipaddress}:{port}/api/stop-generation`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Method**: `PUT`<br>
> `curl -X PUT "http://127.0.0.1:7851/api/stop-generation"`
```
{
"message": "Cancelling current TTS generation"
}
```
### 🟠 Reload Configuration Endpoint<br>
Reload the TTS engine's configuration and scan for new voices and models. When this endpoint is called, it reloads all current settings from the configuration files and scans for new voices and models that are available. This ensures that subsequent calls to /api/currentsettings, /api/voices, and /api/rvcvoices return an up-to-date set of settings and information about the current state of the TTS engine.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **URL**: `http://{ipaddress}:{port}/api/reload_config`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Method**: `GET`<br>
> `curl -X GET "http://127.0.0.1:7851/api/reload_config"`
`Config file reloaded successfully`
### 🟠 Reload/Swap model<br>
Can be used to load in/swap to one of the models presented by /api/currentsettings in the `models_available` list.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **URL**: `http://{ipaddress}:{port}/api/reload?tts_method=x`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Method**: `POST`<br>
> `curl -X POST "http://127.0.0.1:7851/api/reload?tts_method=xtts%20-%20xttsv2_2.0.2"`
{"status": "model-success"} or {"status": "model-failure"}
### 🟠 Switch DeepSpeed Endpoint<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **URL**: `http://{ipaddress}:{port}/api/deepspeed`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Method**: `POST`<br>
> `curl -X POST "http://127.0.0.1:7851/api/deepspeed?new_deepspeed_value=True"`
Replace True with False to disable DeepSpeed mode.
```
{
"status": "deepspeed-success"
}
```
### 🟠 Switching Low VRAM Endpoint<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **URL**: `http://{ipaddress}:{port}/api/lowvramsetting`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Method: `POST`<br>
> `curl -X POST "http://127.0.0.1:7851/api/lowvramsetting?new_low_vram_value=True"`
Replace True with False to disable Low VRAM mode.
```
{
"status": "lowvram-success"
}
```
"""
standardtts_endpoint = """
### 🟠 TTS Generation Endpoint (Standard Generation)<br>
Generate TTS audio based on text input. This endpoint supports both character and narrator speech generation. All global settings for the API endpoint can be configured within the AllTalk interface under Global Settings > AllTalk API Defaults. TTS engine-specific settings, such as voices to use or engine parameters, can be set on an engine-by-engine basis in TTS Engine Settings > TTS Engine of your choice.<br>
It's important to note that although you can send all these variables/settings, the loaded TTS engine will only support them if it is capable e.g. you can request a TTS generation in Russian, but if the TTS model that is loaded in only support English, it's only going to generate english sounding text to speech.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **URL**: `http://{ipaddress}:{port}/api/tts-generate`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Method**: `POST`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Content-Type**: application/x-www-form-urlencoded<br>
### 🟠 Example Command Lines (Standard Generation)
Standard TTS generation supports narration and generates a WAV file/blob.
> **Standard TTS Speech Example** - Generate a time-stamped file for standard text and play the audio at the command prompt/terminal:<br><br>
`curl -X POST "http://127.0.0.1:7851/api/tts-generate" -d "text_input=All of this is text spoken by the character. This is text not inside quotes, though that doesnt matter in the slightest" -d "text_filtering=standard" -d "character_voice_gen=female_01.wav" -d "narrator_enabled=false" -d "narrator_voice_gen=male_01.wav" -d "text_not_inside=character" -d "language=en" -d "output_file_name=myoutputfile" -d "output_file_timestamp=true" -d "autoplay=true" -d "autoplay_volume=0.8"`
> **Narrator Example** - Generate a time-stamped file for text with narrator and character speech and play the audio at the command prompt/terminal:<br><br>
`curl -X POST "http://127.0.0.1:7851/api/tts-generate" -d "text_input=*This is text spoken by the narrator* \\\"This is text spoken by the character\\\;". This is text not inside quotes." -d "text_filtering=standard" -d "character_voice_gen=female_01.wav" -d "narrator_enabled=true" -d "narrator_voice_gen=male_01.wav" -d "text_not_inside=character" -d "language=en" -d "output_file_name=myoutputfile" -d "output_file_timestamp=true" -d "autoplay=true" -d "autoplay_volume=0.8"`<br>
> If your text contains double quotes, escape them with &#92;" (see the narrator example).<br>
Voices sent in the request have to match the voices available within the TTS engine loaded. Generation requests where the voices dont match, will result nothing being generated and possibly an error message.
Because of the way AllTalk works you can send a request with any mix of settings you wish e.g.
> `curl -X POST "http://127.0.0.1:7851/api/tts-generate" -d "text_input=All of this is text spoken by the character. This is text not inside quotes, though that doesnt matter in the slightest"`
Would generate the TTS for whatver engine is curretly loaded in. It will use the default API settings and default TTS engine settings `Global Settings > AllTalk API Defaults` to populate any missing fields, which gives you flexibility on how you want to send API requests to AllTalk.
### 🟠 Request Parameters
#### **text_input**
> The text you want the TTS engine to produce. Use escaped double quotes for character speech and asterisks for narrator speech if using the narrator function. Example:<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "text_input=*This is text spoken by the narrator* &#92;"This is text spoken by the character&#92;". This is text not inside quotes."
#### **text_filtering**
> Filter for text. Options:<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**none**: No filtering. Raw text is sent to the TTS engine.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**standard**: Basic level of filtering to clean up special characters.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**html**: For HTML content with entities like &quot;.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "text_filtering=none"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "text_filtering=standard"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "text_filtering=html"<br>
#### **character_voice_gen**
> The name of the character's voice file (WAV format).<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "character_voice_gen=female_01.wav"
#### **rvccharacter_voice_gen**
> The name of the RVC voice file for the character. Should be in the format `folder\\file.pth` or the word `Disabled`. When Disabled is sent and RVC is globally enabled, the RVC pipeline will not be used for the character/main voice.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "rvccharacter_voice_gen=folder\\voice1.pth"
#### **rvccharacter_pitch**
> The pitch for the RVC voice for the character. Should be in the range `-24` up to `24` with `0` being the central point and the global setting, set in the Gradio RVC page being used if the pitch is not specified in the TTS request.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "rvccharacter_pitch=3"
#### **narrator_enabled**
> Enable or disable the narrator function. If true, minimum text filtering is set to standard.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "narrator_enabled=true"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "narrator_enabled=false"
#### **narrator_voice_gen**
> The name of the narrator's voice file (WAV format).<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "narrator_voice_gen=male_01.wav"
#### **rvcnarrator_voice_gen**
> The name of the RVC voice file for the narrator. Should be in the format folder\\file.pth or the word Disabled. When Disabled is sent and RVC is globally enabled, the RVC pipeline will not be used for the character/main voice.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "rvcnarrator_voice_gen=folder\\voice2.pth"
#### **rvcnarrator_pitch**
> The pitch for the RVC voice for the narrator. Should be in the range `-24` up to `24` with `0` being the central point and the global setting, set in the Gradio RVC page being used if the pitch is not specified in the TTS request.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "rvcnarrator_pitch=3"
#### **text_not_inside**
> Specify the handling of lines not inside double quotes or asterisks for the narrator feature. Options:<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**character**: Treat as character speech.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**narrator**: Treat as narrator speech.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**silent**: Ignore text not inside quotes or asterisks.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "text_not_inside=character"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "text_not_inside=narrator"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "text_not_inside=silent"<br>
#### **language**
> Choose the language for TTS. Options:<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**ar**: Arabic<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**zh-cn**: Chinese (Simplified)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**cs**: Czech<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**nl**: Dutch<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**en**: English<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**fr**: French<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**de**: German<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**hi**: Hindi (limited support)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**hu**: Hungarian<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**it**: Italian<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**ja**: Japanese<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**ko**: Korean<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**pl**: Polish<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**pt**: Portuguese<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**ru**: Russian<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**es**: Spanish<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**tr**: Turkish<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "language=en"
#### **output_file_name***
> The name of the output file (excluding the .wav extension).<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "output_file_name=myoutputfile"
#### **output_file_timestamp**
> Add a timestamp to the output file name. If true, each file will have a unique timestamp; otherwise, the same file name will be overwritten each time you generate TTS.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "output_file_timestamp=true"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "output_file_timestamp=false"
#### **autoplay**
> Enable or disable playing the generated TTS to your standard sound output device at the time of TTS generation.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "autoplay=true"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "autoplay=false"
#### **autoplay_volume**
> Set the autoplay volume. Should be between 0.1 and 1.0.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "autoplay_volume=0.8"
#### **speed**
> Set the speed of the generated audio. Should be between 0.25 and 2.0.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "speed=1.0"
#### **pitch**
> Set the pitch of the generated audio. Should be between -10 and 10.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "pitch=0"
#### **temperature**
> Set the temperature for the TTS engine. Should be between 0.1 and 1.0.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "temperature=0.75"
#### **repetition_penalty**
> Set the repetition penalty for the TTS engine. Should be between 1.0 and 20.0.<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d "repetition_penalty=10"
### 🟠 TTS Generation Response
> The API returns a JSON object with the following properties:<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**status**: Indicates whether the generation was successful (generate-success) or failed (generate-failure).<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**output_file_path**: The on-disk location of the generated WAV file.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**output_file_url**: The HTTP location for accessing the generated WAV file for browser playback.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**output_cache_url**: The HTTP location for accessing the generated WAV file as a pushed download.<br>
```
{
"status": "generate-success",
"output_file_path": "C:\\text-generation-webui\\extensions\\alltalk_tts\\outputs\\myoutputfile_1704141936.wav",
"output_file_url": "/audio/myoutputfile_1704141936.wav",
"output_cache_url": "/audiocache/myoutputfile_1704141936.wav"
}
```
<br>
Note: The response no longer includes the IP address and port number. You will need to add these in your own software/extension.
"""
streamingtts_endpoint = """
### 🟠 TTS Generation Endpoint (Streaming Generation)
Generate TTS audio as a stream. This endpoint does not support narration and will generate an audio stream, not a file. It also does not support the RVC pipeline. Generate and stream TTS audio directly for real-time playback.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **URL**: `http://{ipaddress}:{port}/api/tts-generate-streaming`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Method**: POST<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **Content-Type**: application/x-www-form-urlencoded<br>
> `http://127.0.0.1:7851/api/tts-generate-streaming?text=Here%20is%20some%20text&voice=female_01.wav&language=en&output_file=stream_output.wav`
Example JavaScript for Streaming Playback:
```
const text = "Here is some text";
const voice = "female_01.wav";
const language = "en";
const outputFile = "stream_output.wav";
const encodedText = encodeURIComponent(text);
const streamingUrl = `http://localhost:7851/api/tts-generate-streaming?text=${encodedText}&voice=${voice}&language=${language}&output_file=${outputFile}`;
const audioElement = new Audio(streamingUrl);
audioElement.play();
```
Response: A StreamingResponse for the audio stream.
Request Parameters:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**text**: The text to convert to speech.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**voice**: The voice type to use.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**language**: The language for the TTS.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**output_file**: The name of the output file.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**Response**: A JSON object indicating the status of the request.
```
{
"output_file_path": "stream_output.wav"
}
```
"""
with gr.Tab("API Endpoints & Dev"):
with gr.Tab("Best Development Practices"): gr.Markdown(best_practices)
with gr.Tab("Standard TTS Generation"): gr.Markdown(standardtts_endpoint)
with gr.Tab("Streaming TTS Generation"): gr.Markdown(streamingtts_endpoint)
with gr.Tab("Settings API's"): gr.Markdown(settings_endpoints)
with gr.Tab("Interaction API's"): gr.Markdown(interaction_endpoints)
with gr.Tab("OpenAPI Compatible Endpoint"): gr.Markdown(openapi_endpoint)
File diff suppressed because it is too large. Load diff
+5 -5
View File
@@ -1,14 +1,13 @@
coqui-tts>=0.24.3 coqui-tts>=0.24.3
faster-whisper>=1.0.0 openai-whisper
filelock>=3.16.1
fuzzywuzzy fuzzywuzzy
gradio==4.32.2 gradio==4.44.1
importlib_metadata>=7.1.0 importlib_metadata>=7.1.0
inputimeout>=1.0.4 inputimeout>=1.0.4
Jinja2>=3.1.0 Jinja2>=3.1.0
librosa>=0.10.2.post1 librosa>=0.10.2.post1
local_attention>=1.9.0 local_attention>=1.9.0
nvidia-cublas-cu11==11.11.3.6
nvidia-cudnn-cu11==9.1.1.17
onnxruntime-gpu>=1.18.0 onnxruntime-gpu>=1.18.0
pydantic>=2.7.0 pydantic>=2.7.0
python-ffmpeg>=2.0.0 python-ffmpeg>=2.0.0
@@ -44,4 +43,5 @@ word2number
cutlet==0.4.0 cutlet==0.4.0
fugashi==1.3.1 fugashi==1.3.1
piper-tts; sys_platform == "linux" piper-tts; sys_platform == "linux"
ctranslate2==4.4.0 plotly==5.24.1
scipy==1.14.1
@@ -1,6 +1,7 @@
coqui-tts>=0.24.3 coqui-tts>=0.24.3
filelock>=3.16.1
fuzzywuzzy>=0.18.0 fuzzywuzzy>=0.18.0
gradio>=4.44.1 gradio==4.44.1
importlib_metadata>=7.2.1 importlib_metadata>=7.2.1
inputimeout>=1.0.4 inputimeout>=1.0.4
Jinja2>=3.1.4 Jinja2>=3.1.4
@@ -32,3 +33,5 @@ piper-tts; sys_platform == "linux"
piper-tts; sys_platform == "darwin" piper-tts; sys_platform == "darwin"
piper-phonemize==1.1.0; sys_platform == "darwin" piper-phonemize==1.1.0; sys_platform == "darwin"
fastapi==0.112.2 fastapi==0.112.2
plotly==5.24.1
scipy==1.14.1
@@ -1,4 +1,5 @@
coqui-tts>=0.24.3 coqui-tts>=0.24.3
filelock>=3.16.1
fuzzywuzzy>=0.18.0 fuzzywuzzy>=0.18.0
importlib_metadata>=7.1.0 importlib_metadata>=7.1.0
inputimeout>=1.0.4 inputimeout>=1.0.4
@@ -29,3 +30,5 @@ fugashi==1.3.1
piper-tts; sys_platform == "linux" piper-tts; sys_platform == "linux"
piper-tts; sys_platform == "darwin" piper-tts; sys_platform == "darwin"
piper-phonemize==1.1.0; sys_platform == "darwin" piper-phonemize==1.1.0; sys_platform == "darwin"
plotly==5.24.1
scipy==1.14.1
@@ -0,0 +1,4 @@
filelock>=3.16.1
pydantic>=2.7.0
pytest>=8.3.3
pytest-cov>=6.0.0
+6 -2
View File
@@ -28,6 +28,8 @@ parser = argparse.ArgumentParser(description="Compare TTS output with the origin
parser.add_argument("--threshold", type=int, default=98, help="Similarity threshold for considering a match (default: 98)") parser.add_argument("--threshold", type=int, default=98, help="Similarity threshold for considering a match (default: 98)")
parser.add_argument("--ttslistpath", help="Path to the ttsList.json file") parser.add_argument("--ttslistpath", help="Path to the ttsList.json file")
parser.add_argument("--wavfilespath", help="Path to the wav outputs folder") parser.add_argument("--wavfilespath", help="Path to the wav outputs folder")
parser.add_argument("--whisper-model", type=str, default="large-v3", help="Whisper model to use (default: large-v3)")
args = parser.parse_args() args = parser.parse_args()
if not args.ttslistpath: if not args.ttslistpath:
@@ -38,6 +40,7 @@ if not args.wavfilespath:
json_file_path = Path(args.ttslistpath).resolve() json_file_path = Path(args.ttslistpath).resolve()
wav_file_path = Path(args.wavfilespath).resolve() wav_file_path = Path(args.wavfilespath).resolve()
accuracy_threshold = args.threshold accuracy_threshold = args.threshold
whisper_model_name = args.whisper_model # Capture the model name from the argument
def disclaimer_text(): def disclaimer_text():
print(f"\nDESCRIPTION: ") print(f"\nDESCRIPTION: ")
@@ -196,11 +199,12 @@ def main():
print("[AllTalk TTSDiff] \033[94mJSON file :\033[92m", json_file_path, "\033[0m") print("[AllTalk TTSDiff] \033[94mJSON file :\033[92m", json_file_path, "\033[0m")
print("[AllTalk TTSDiff] \033[94mWAV files :\033[92m", wav_file_path, "\033[0m") print("[AllTalk TTSDiff] \033[94mWAV files :\033[92m", wav_file_path, "\033[0m")
print("[AllTalk TTSDiff] \033[94mAccuracy :\033[92m", accuracy_threshold, "%", "\033[0m") print("[AllTalk TTSDiff] \033[94mAccuracy :\033[92m", accuracy_threshold, "%", "\033[0m")
print("[AllTalk TTSDiff] \033[94mWhisper :\033[92m", whisper_model_name, "\033[0m")
device = "cuda" if torch.cuda.is_available() else "cpu" device = "cuda" if torch.cuda.is_available() else "cpu"
print("[AllTalk TTSDiff] \033[94mDevice :\033[92m", device, "\033[0m") print("[AllTalk TTSDiff] \033[94mDevice :\033[92m", device, "\033[0m")
print("[AllTalk TTSDiff] Loading Whisper Large-v3 model...") print("[AllTalk TTSDiff] Loading Whisper model...")
model = whisper.load_model("large-v3", device=device) model = whisper.load_model(whisper_model_name, device=device) # Use the specified or default model
flagged_ids = [] # Initialize the list to track IDs needing review flagged_ids = [] # Initialize the list to track IDs needing review
+135 -133
View File
@@ -2,8 +2,16 @@ import os
import json import json
import requests import requests
import gradio as gr import gradio as gr
import whisper
from typing import List, Tuple
from tqdm import tqdm from tqdm import tqdm
from pathlib import Path from pathlib import Path
import gc
import torch
import warnings
# Filter Flash Attention warning
warnings.filterwarnings("ignore", message="1Torch was not compiled with flash attention")
from .help_content import AllTalkHelpContent
this_dir = Path(__file__).parent.resolve() # Sets up self.this_dir as a variable for the folder THIS script is running in. this_dir = Path(__file__).parent.resolve() # Sets up self.this_dir as a variable for the folder THIS script is running in.
main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up self.main_dir as a variable for the folder AllTalk is running in main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up self.main_dir as a variable for the folder AllTalk is running in
@@ -53,6 +61,71 @@ def f5tts_voices_file_list():
return sorted(voices) return sorted(voices)
def get_files_needing_transcription(directory: Path) -> List[Tuple[Path, str]]:
"""Get all audio files that need transcription."""
files_to_transcribe = []
for ext in ['.wav', '.mp3', '.flac']:
# Check main directory
for f in directory.glob(f"*{ext}"):
if not f.with_suffix('.reference.txt').exists():
files_to_transcribe.append((f, ext[1:])) # Remove the dot from extension
# Check subdirectories
for folder in directory.iterdir():
if folder.is_dir():
for f in folder.glob(f"*{ext}"):
if not f.with_suffix('.reference.txt').exists():
files_to_transcribe.append((f, ext[1:]))
return files_to_transcribe
def transcribe_files(model_name: str, use_cpu: bool = False, progress=gr.Progress()) -> str:
"""Transcribe all files without reference text."""
files = get_files_needing_transcription(Path(main_dir)/'voices')
if not files:
return "No files need transcription!"
model = None
try:
progress(0, desc="Loading Whisper model...")
# Determine device
device = "cpu" if use_cpu else ("cuda" if torch.cuda.is_available() else "cpu")
model = whisper.load_model(model_name).to(device)
progress(0, desc=f"Transcribing files using {device.upper()}...")
for idx, (file_path, _) in enumerate(progress.tqdm(files, desc="Transcribing files")):
# Transcribe the audio
result = model.transcribe(str(file_path))
# Save the transcription
with open(file_path.with_suffix('.reference.txt'), 'w', encoding='utf-8') as f:
f.write(result["text"].strip())
progress((idx + 1) / len(files))
return f"Successfully transcribed {len(files)} files using {device.upper()}!"
except Exception as e:
return f"Error during transcription: {str(e)}"
finally:
if model is not None:
# Move model to CPU before deletion if it was on CUDA
if torch.cuda.is_available() and not use_cpu:
model.cpu()
torch.cuda.empty_cache()
# Delete the model explicitly
del model
model = None # Add this line to explicitly clear the reference
# Run garbage collection
gc.collect()
###################################################### ######################################################
# REQUIRED CHANGE # # REQUIRED CHANGE #
# Imports and saves the TTS engine-specific settings # # Imports and saves the TTS engine-specific settings #
@@ -143,10 +216,16 @@ def f5tts_model_alltalk_settings(model_config_data):
def_narrator_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_narrator_voice"], label="Narrator Voice", choices=voice_list, allow_custom_value=True) def_narrator_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_narrator_voice"], label="Narrator Voice", choices=voice_list, allow_custom_value=True)
with gr.Group(): with gr.Group():
with gr.Row(): with gr.Row():
details_text = gr.Textbox(label="Details", show_label=False, lines=5, interactive=False, value="In this section, you can set the default settings for this TTS engine. Settings that are not supported by the current engine will be greyed out and cannot be selected. Default voices specified here will be used when no specific voice is provided in the TTS generation request. If a voice is specified in the request, it will override these default settings. When using the OpenAI API compatable API with this TTS engine, the voice mappings will be applied. As the OpenAI API has a limited set of 6 voices, these mappings ensure compatibility by mapping the OpenAI voices to the available voices in this TTS engine.") details_text = gr.Textbox(label="Details", show_label=False, lines=5, interactive=False, value="Configure default settings and voice mappings for the selected TTS engine. Unavailable options are grayed out based on engine capabilities. See the Help section below for detailed information about each setting.")
with gr.Row(): with gr.Row():
submit_button = gr.Button("Update Settings") submit_button = gr.Button("Update Settings")
output_message = gr.Textbox(label="Output Message", interactive=False, show_label=False) output_message = gr.Textbox(label="Output Message", interactive=False, show_label=False)
with gr.Accordion("HELP - 🔊 Understanding TTS Engine Default Settings Page", open=False):
with gr.Row():
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS, elem_classes="custom-markdown")
with gr.Row():
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS2, elem_classes="custom-markdown")
submit_button.click(f5tts_model_update_settings, inputs=[def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr], outputs=output_message) submit_button.click(f5tts_model_update_settings, inputs=[def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr], outputs=output_message)
########################################################################################### ###########################################################################################
@@ -180,34 +259,12 @@ def f5tts_model_alltalk_settings(model_config_data):
gr.Textbox(label="Linux Support", value='Yes' if features_list['linux_capable'] else 'No', interactive=False) gr.Textbox(label="Linux Support", value='Yes' if features_list['linux_capable'] else 'No', interactive=False)
gr.Textbox(label="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False) gr.Textbox(label="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False)
with gr.Row(): with gr.Row():
gr.Markdown(""" with gr.Accordion("HELP - 🔊 Understanding TTS Engine Capabilities", open=False):
#### 🟧 DeepSpeed Capable with gr.Row():
DeepSpeed is a deep learning optimization library that can significantly speed up model training and inference. If a model is DeepSpeed capable, it means it can utilize DeepSpeed to accelerate the generation of text-to-speech output. This requires the model to be loaded into CUDA/VRAM on an Nvidia GPU and the model's inference method to support DeepSpeed. gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION, elem_classes="custom-markdown")
#### 🟧 Pitch Capable with gr.Row():
Pitch refers to the highness or lowness of a sound. If a model is pitch capable, it can adjust the pitch of the generated speech, allowing for more expressive and varied output. gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION1, elem_classes="custom-markdown")
#### 🟧 Generation Speed Capable gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION2, elem_classes="custom-markdown")
Generation speed refers to the rate at which the model can generate text-to-speech output. If a model is generation speed capable, it means the speed of the generated speech can be adjusted, making it faster or slower depending on the desired output.
#### 🟧 Repetition Penalty Capable
Repetition penalty is a technique used to discourage the model from repeating the same words or phrases multiple times in the same sounding way. If a model is repetition penalty capable, it can apply this penalty during generation to improve the diversity and naturalness of the output.
#### 🟧 Multi-Languages Capable
Multi-language capable models can generate speech in multiple languages. This means that the model has been trained on data from different languages and can switch between them during generation. Some models are language-specific.
#### 🟧 Multi-Voice Capable
Multi-voice capable models generate speech in multiple voices or speaking styles. This means that the model has been trained on data from different speakers and can mimic their voices during generation, or is a voice cloning model that can generate speech based on the input sample.
""")
gr.Markdown("""
#### 🟧 Streaming Capable
Streaming refers to the ability to generate speech output in real-time, without the need to generate the entire output before playback. If a model is streaming capable, it can generate speech on-the-fly, allowing for faster response times and more interactive applications.
#### 🟧 Low VRAM Capable
VRAM (Video Random Access Memory) is a type of memory used by GPUs to store and process data. If a model is low VRAM capable, it can efficiently utilize the available VRAM by moving data between CPU and GPU memory as needed, allowing for generation even on systems with limited VRAM where it may be competing with an LLM model for VRAM.
#### 🟧 Temperature Capable
Temperature is a hyperparameter that controls the randomness of the generated output. If a model is temperature capable, the temperature can be adjusted to make the output more or less random, affecting the creativity and variability of the generated speech.
#### 🟧 Multi-Model Capable Engine
If an engine is multi-model capable, it means that it can support and utilize multiple models for text-to-speech generation. This allows for greater flexibility and the ability to switch between different models depending on the desired output. Different models may be capable of different languages, specific languages, voices, etc.
#### 🟧 Default Audio Output Format
Specifies the file format in which the generated speech will be saved. Common audio formats include WAV, MP3, FLAC, Opus, AAC, and PCM. If you want different outputs, you can set the transcode function to change the output audio, though transcoding will add a little time to the generation and is not available for streaming generation.
#### 🟧 Windows/Linux/Mac Support
These indicators show whether the model and engine are compatible with Windows, Linux, or macOS. However, additional setup or requirements may be necessary to ensure full functionality on your operating system. Please note that full platform support has not been extensively tested.
""")
####################################################################################################################################################################################################### #######################################################################################################################################################################################################
# REQUIRED CHANGE # # REQUIRED CHANGE #
@@ -292,7 +349,6 @@ def f5tts_model_alltalk_settings(model_config_data):
confirm_button.click(confirm_download, inputs=model_dropdown, outputs=[confirm_button, download_button, cancel_button, download_status]) confirm_button.click(confirm_download, inputs=model_dropdown, outputs=[confirm_button, download_button, cancel_button, download_status])
cancel_button.click(cancel_download, inputs=None, outputs=[confirm_button, download_button, cancel_button, download_status]) cancel_button.click(cancel_download, inputs=None, outputs=[confirm_button, download_button, cancel_button, download_status])
def get_voice_files(): def get_voice_files():
"""Get list of voice files with their status""" """Get list of voice files with their status"""
files = [ files = [
@@ -304,74 +360,45 @@ def f5tts_model_alltalk_settings(model_config_data):
with gr.Tab("Reference Text/Sample Manager"): with gr.Tab("Reference Text/Sample Manager"):
with gr.Row(): with gr.Row():
gr.Markdown(""" # List all WAV files and their status
### Reference Text/Sample Manager file_list = gr.Dropdown(
This tool helps you manage reference text files for your voice samples. Each WAV file should have a corresponding .reference.txt file label="Voice Files",
containing the exact text that was spoken in the recording. This is important for voice cloning quality.<br> choices=get_voice_files(),
value=None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Files marked in 🔴 red need a reference text file<br> )
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Files marked in 🟢 green already have a reference text file<br> refresh_btn = gr.Button("Refresh List")
model_selector = gr.Dropdown(
It is important to note that F5-TTS only supports English and Chinese languages. label="Whisper Model",
choices=["base", "medium", "large-v3"],
For more information on the F5-TTS engine, please visit the: [F5-TTS GitHub Repository](https://github.com/SWivid/F5-TTS/) value="base"
""") )
transcribe_button = gr.Button("Auto-Transcribe Missing Files")
gr.Markdown("""
#### Important Guidelines:
* Reference WAV files should be no longer than 15 seconds in length, or it may affect playback speed.
* You can play the audio below and listen to it. You then need to populate the Reference Text box with the exact spoken audio, preferably adding punctuation where appropriate:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Period (.)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Comma (,)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Semi-colon (;)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Apostrophe (') - Important for words like "I'm", "don't", "can't", etc.<br>
* After saving the reference text file, you'll need to go to the main generation page and click "Refresh Server Settings" for the voice to be shown as available.
""")
with gr.Row(): with gr.Row():
with gr.Column(): # Add audio player with small height
# List all WAV files and their status audio_player = gr.Audio(
file_list = gr.Dropdown( label="Preview Voice Sample",
label="Voice Files", type="filepath",
choices=get_voice_files(), interactive=False,
value=None elem_classes="small-audio-player" # Custom CSS class for sizing
) )
with gr.Row():
current_text = gr.Textbox(
label="Manually Edit Reference Text",
placeholder="Enter the exact text that was spoken in the recording...",
lines=2,
scale=2
)
status_text = gr.Textbox(label="Status", interactive=False, scale=1)
with gr.Row():
save_btn = gr.Button("Save Reference Text", variant="primary")
delete_btn = gr.Button("Delete Reference Text", variant="secondary")
with gr.Accordion("HELP - 🎯 Reference Text/Sample Manager", open=False):
with gr.Row():
gr.Markdown(AllTalkHelpContent.REFERENCE_MANAGER, elem_classes="custom-markdown")
with gr.Row():
gr.Markdown(AllTalkHelpContent.REFERENCE_MANAGER1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.REFERENCE_MANAGER2, elem_classes="custom-markdown")
# Add audio player with small height
audio_player = gr.Audio(
label="Preview Voice Sample",
type="filepath",
interactive=False,
elem_classes="small-audio-player" # Custom CSS class for sizing
)
refresh_btn = gr.Button("Refresh List")
with gr.Column():
current_text = gr.Textbox(
label="Reference Text",
placeholder="Enter the exact text that was spoken in the recording...",
lines=5
)
with gr.Row():
save_btn = gr.Button("Save Reference Text", variant="primary")
delete_btn = gr.Button("Delete Reference Text", variant="secondary")
status_text = gr.Textbox(label="Status", interactive=False)
# Add custom CSS to make the audio player smaller
gr.HTML("""
<style>
.small-audio-player audio {
height: 40px !important;
margin-top: 0px !important;
}
.small-audio-player {
margin-bottom: 10px !important;
}
</style>
""")
def load_file_data(wav_file): def load_file_data(wav_file):
if not wav_file: if not wav_file:
@@ -457,6 +484,14 @@ def f5tts_model_alltalk_settings(model_config_data):
outputs=file_list outputs=file_list
) )
refresh_btn.click(refresh_file_list, outputs=file_list) refresh_btn.click(refresh_file_list, outputs=file_list)
transcribe_button.click(
fn=transcribe_files,
inputs=[model_selector],
outputs=status_text # Use the existing status box instead of creating a new one
).then(
fn=refresh_file_list,
outputs=file_list
)
################################################################################################### ###################################################################################################
# REQUIRED CHANGE # # REQUIRED CHANGE #
@@ -465,43 +500,10 @@ def f5tts_model_alltalk_settings(model_config_data):
################################################################################################### ###################################################################################################
with gr.Tab("Engine Help"): with gr.Tab("Engine Help"):
with gr.Row(): with gr.Row():
gr.Markdown(""" gr.Markdown(AllTalkHelpContent.HELP_PAGE, elem_classes="custom-markdown")
### 🟧 Where are the f5tts models stored? with gr.Row():
This extension will download the f5tts models to `/alltalk_tts/models/f5tts/` folder. gr.Markdown(AllTalkHelpContent.HELP_PAGE1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.HELP_PAGE2, elem_classes="custom-markdown")
### 🟧 How do clone/reference voices work?
F5-TTS uses voice samples with corresponding reference text files for voice cloning:
1. Place your WAV voice samples in the `/alltalk_tts/voices/` folder
2. Create a matching `.reference.txt` file containing the exact text spoken in the recording.
3. Use the `Reference Text/Sample Manager` tab to create and manage these text files
4. Only voice samples with valid reference text files will be available for use
For best results:
- Keep voice samples under 15 seconds
- Ensure the reference text exactly matches what is spoken
- Use high-quality recordings with minimal background noise
### 🟧 Where are the outputs stored & Automatic output wav file deletion
Voice outputs are stored in `/alltalk_tts/outputs/`. You can configure automatic maintenance deletion of old wav files by setting `Del WAV's older than` in the global settings.
> When `Disabled`, your output wav files will be left untouched.
> When set to a setting `1 Day` or greater, your output wav files older than that time period will be automatically deleted on start-up of AllTalk.
""")
gr.Markdown("""
### 🟧 Speed settings and voice cloning
F5-TTS appears to generate audio a little faster than the audio sample. As such, in AllTalk, the speed setting for generation is set to 0.9 (see the F5-TTS `Default Settings` tab). Certainly the better the punctuation you use, the better the end result, both in the audio samples reference file and the text you send to be generated as TTS. If you wish to globally adjust this, you can make the change on the Default Settings tab.
### 🟧 Cloned audio and punctuation.
When F5-TTS reproduces audio, punctuation appears to matter greatly. As such `Im` and `I'm` or `I am` will all sound a little different. Additionally it appears to want to spell out text in CAPS. You may want to look at the F5-TTS developers page for more information on this.
### 🟧 Difference between F5-TTS and E2-TTS models.
F5-TTS and E2-TTS represent two different approaches to zero-shot text-to-speech:
- F5-TTS is optimized for voice fidelity and natural speech patterns. It excels at capturing the nuances and characteristics of the reference voice, producing highly natural and faithful speech output. The tradeoff is slightly longer generation times and higher computational requirements.<br>
- E2-TTS prioritizes efficiency and ease of use. It offers faster generation speeds and better memory efficiency, making it ideal for longer texts or resource-constrained environments. While its voice reproduction may be slightly less precise than F5-TTS, it still produces high-quality output with good speaker similarity.
Choose F5-TTS when voice fidelity is paramount, or E2-TTS when generation speed and efficiency are the priority.
""")
return app return app
+546
View File
@@ -0,0 +1,546 @@
# help_content.py
# pylint: disable=no-member
class AllTalkHelpContent:
"""CSS and help content for help_content.py"""
custom_css = """
/* Add this to your existing CSS */
.gradio-container .prose {
max-width: none !important;
padding: 0.5rem !important; /* Reduced padding */
margin: 0 !important;
}
.custom-markdown div {
border: none !important; /* Remove the inner border */
margin-top: 0 !important; /* Remove top margin */
margin-bottom: 0 !important; /* Remove bottom margin */
padding-top: 0 !important; /* Remove top padding */
padding-bottom: 0 !important; /* Remove bottom padding */
}
/* Update the existing custom-markdown class */
.custom-markdown {
font-size: 15px !important;
line-height: 1.6 !important;
color: var(--body-text-color) !important;
background-color: var(--background-fill-primary) !important;
border: 1px solid var(--border-color-primary) !important;
border-radius: 8px !important;
padding: 0.5rem !important;
margin: 0 !important; /* Changed from 1rem 0 to 0 */
max-width: 100% !important;
box-sizing: border-box !important;
/* Default text color for all content (grey) */
color: rgba(156, 163, 175, 1) !important; /* Adjust this grey value to match your interface */
}
/* Make headings white */
.custom-markdown h1,
.custom-markdown h2,
.custom-markdown h3,
.custom-markdown h4,
.custom-markdown h5,
.custom-markdown h6 {
color: var(--heading-text-color, var(--body-text-color)) !important;
font-weight: 600 !important;
}
/* Keep all other elements in the grey color */
.custom-markdown p,
.custom-markdown li,
.custom-markdown ul,
.custom-markdown ol {
color: rgba(156, 163, 175, 1) !important; /* Same grey as the base text */
}
/* Additional targeting for any wrapping elements */
.gradio-container .prose > * {
margin: 0 !important;
padding: 0 !important;
}
/* Update the list item spacing in your existing CSS */
.custom-markdown li {
font-size: 0.95rem !important;
margin-bottom: 0.2rem !important; /* Reduced from 0.5rem to 0.3rem */
}
/* Add specific styling for definition-style lists (like your Default, Recommendation, Tip items) */
.custom-markdown li p {
margin: 0 !important; /* Remove paragraph margins within list items */
}
/* If you need even tighter spacing for specific types of lists */
.custom-markdown li + li {
margin-top: 0.2rem !important; /* Space between consecutive list items */
}
/* Ensure nested lists maintain proper spacing */
.custom-markdown li > ul,
.custom-markdown li > ol {
margin: 0.2rem 0 0.2rem 1rem !important; /* Reduced from 0.5rem */
}
/* Consistent heading styles */
.custom-markdown h2 {
font-size: 1.2rem !important; /* Fixed size relative to root */
font-weight: 600 !important;
margin: 1.5rem 0 1rem !important;
color: var(--heading-text-color, var(--body-text-color)) !important;
border-bottom: 1px solid var(--border-color-primary) !important;
padding-bottom: 0.5rem !important;
}
/* First paragraph styling */
.custom-markdown p:first-of-type {
font-size: 0.95rem !important; /* Match base size */
font-weight: 400 !important;
margin-bottom: 1rem !important;
}
/* Regular paragraphs */
.custom-markdown p {
font-size: 0.95rem !important;
margin: 0.8rem 0 !important;
}
/* List styling */
.custom-markdown ul,
.custom-markdown ol {
margin: 0.8rem 0 !important;
padding-left: 1.5rem !important;
}
/* Code styling */
.custom-markdown code {
font-family: ui-monospace, monospace !important;
background-color: var(--background-fill-secondary) !important;
padding: 0.2rem 0.4rem !important;
border-radius: 4px !important;
font-size: 0.8rem !important; /* Slightly smaller than regular text */
color: var(--body-text-color) !important;
}
/* Add styles for bold and emphasis */
.custom-markdown strong {
font-weight: 600 !important;
color: var(--body-text-color) !important;
}
.custom-markdown em {
font-style: italic !important;
}
/* Ensure both columns take equal width */
.gradio-row > div {
flex: 1 1 50% !important;
min-width: 0 !important; /* Prevents flex items from overflowing */
}
"""
ENGINE_INFORMATION = """
## 🔊 TTS Engine Capabilities Help
This guide explains the various capabilities that **may** be available in different TTS engines and models. Each capability affects how the TTS engine processes and generates speech output.
"""
ENGINE_INFORMATION1 = """
## 🚀 Performance Features
- **DeepSpeed Capable**: Enables GPU acceleration using the DeepSpeed optimization library.
- **Requires**: NVIDIA GPU with CUDA support
- **Benefit**: Significantly faster text-to-speech generation
- **Note**: Model must specifically support DeepSpeed inference
- **Low VRAM Capable**: Optimized for systems with limited GPU memory.
- **Benefit**: Efficient memory management between CPU and GPU
- **Use Case**: Ideal when running alongside other GPU-intensive applications like LLMs
- **Note**: May trade speed for memory efficiency
- **Streaming Capable**: Enables real-time speech generation.
- **Benefit**: Immediate playback without generating entire audio first
- **Use Case**: Interactive applications and real-time responses
- **Note**: Not all output formats support streaming
## 🎵 Voice Control Features
- **Pitch Capable**: Allows adjustment of voice pitch.
- **Benefit**: Creates more expressive and varied speech output
- **Use Case**: Customizing voice characteristics
- **Note**: Adjustment range varies by model
- **Generation Speed Capable**: Controls speech rate.
- **Benefit**: Adjustable playback speed during generation
- **Use Case**: Creating faster or slower speech output
- **Note**: May affect audio quality at extreme settings
- **Temperature Capable**: Controls output randomness.
- **Benefit**: Adjustable speech variation and creativity
- **Use Case**: Balancing consistency vs. naturality
- **Note**: Higher values increase variation but may reduce quality
"""
ENGINE_INFORMATION2 = """
## 🎯 Quality Enhancement Features
- **Repetition Penalty Capable**: Prevents unnatural speech patterns.
- **Benefit**: Reduces repeated sounds and phrases
- **Use Case**: Improving natural flow of longer texts
- **Note**: Strength of penalty may be adjustable
## 🌐 Multi-Feature Support
- **Multi-Languages Capable Models**: Each model Supports multiple languages.
- **Benefit**: Generate speech in different languages
- **Note**: Quality may vary between languages
- **Tip**: Check model-specific language support
- **Multi-Voice Capable**: Supports multiple speaking voices.
- **Benefit**: Different voices or speaking styles
- **Types**: Pre-trained voices or voice cloning
- **Note**: Voice quality may vary by model
- **Multi-Model Capable Engine**: Supports multiple TTS models.
- **Benefit**: Flexibility in model selection
- **Use Case**: Switching between models for different needs
- **Note**: Each model may have different capabilities
## 📁 Technical Features
- **Default Audio Output Format**: Specifies output file format.
- **Common Formats**: WAV, MP3, FLAC, Opus, AAC, PCM
- **Note**: Transcoding to different formats adds processing time
- **Warning**: Not all formats support streaming
- **Platform Support**: Operating system compatibility.
- **Platforms**: Windows, Linux, macOS
- **Note**: Additional setup may be required
- **Warning**: Support level may vary by platform
"""
DEFAULT_SETTINGS = """
## 🎯 TTS Engine Settings Help
This guide explains the settings and configuration options available for individual Text-to-Speech engines within AllTalk.
"""
DEFAULT_SETTINGS1 = """
## 🎚️ Engine Capabilities & Controls
- **Low VRAM Mode**
- Optimizes memory usage for systems with limited GPU memory
- Efficiently manages resources by moving data between CPU and GPU
- Recommended for systems with less than 4GB VRAM or when running alongside other GPU-intensive applications
- **DeepSpeed Capability**
- Accelerates TTS generation using optimized inference
- Only available for engines and models that support DeepSpeed
- Requires NVIDIA GPU with CUDA support
- **Temperature Control**
- Adjusts the variability in speech generation
- **Range**: 0.0 to 1.0
- **Lower values** (0.1-0.5): More consistent, stable output
- **Higher values** (0.6-1.0): More variable, potentially more natural-sounding output
- **Repetition Penalty**
- Helps prevent repetitive speech patterns
- **Range**: 1.0 to 15.0
- Higher values more strongly discourage repetition
- Typically most effective between 1.0-3.0
- **Pitch Adjustment**
- Modifies the voice pitch when supported
- **Range**: -20 to +20
- Use subtle adjustments for most natural results
- **Generation Speed**
- Controls the pace of generated speech
- **Range**: 0.5 to 2.0
- 1.0 represents normal speed
"""
DEFAULT_SETTINGS2 = """
## 🗣️ Voice Configuration
### OpenAI Voice Mappings
- Only relevant when using the OpenAI-compatible API endpoint
- Maps OpenAI's six standard voices to equivalent voices in the current engine:
- `alloy`
- `echo`
- `fable`
- `nova`
- `onyx`
- `shimmer`
- Essential for maintaining compatibility with OpenAI API calls
- Each mapping can be customized to any available voice in the current engine
Information on the OpenAI Endpoint is available in the [Github Wiki](https://github.com/erew123/alltalk_tts/wiki)
### Default Voices
- **Default/Character Voice**: Used when no specific voice is specified in API calls
- **Narrator Voice**: Separate default for narrator-specific text
- These defaults are engine-specific and won't affect other TTS engines
- Can be overridden by explicitly specifying voices in API calls
## ⚙️ Important Notes
- Settings availability is determined by engine capabilities
- Grayed-out options indicate features not supported by the current engine
- Changes only affect the currently selected TTS engine
- Settings here act as defaults but can be overridden via API parameters
- All changes require clicking "Update Settings" to take effect
- Some settings require an engine reload to take effect
"""
HELP_PAGE = """
## 🎯 F5-TTS Voice Cloning Engine Help
F5-TTS is a zero-shot voice cloning system that specializes in high-fidelity voice reproduction with precise reference text matching.
"""
HELP_PAGE1 = """
## 🎚️ Model Variants
### F5-TTS (High Fidelity)
- Optimized for voice accuracy and naturalness
- Superior voice characteristic capture
- Higher computational requirements
- Best for quality-focused applications
- Longer generation times
### E2-TTS (Efficient)
- Focused on speed and efficiency
- Lower resource requirements
- Faster generation times
- Good for longer texts
- Suitable for resource-constrained systems
## 🗣️ Voice Cloning System
### Reference Text Requirements
- Each voice sample needs a matching `.reference.txt` file
- Text must exactly match spoken audio
- Punctuation significantly affects output quality
- Use the Reference Text/Sample Manager for setup
- Supports English and Chinese languages only
### Audio Sample Guidelines
- Format: WAV/MP3/Flac files
- Length: Maximum 15 seconds recommended
- Quality: Clear audio, minimal background noise
- Location: `/alltalk_tts/voices/` directory
- Names: Should match reference text filename
### Punctuation Impact
- Precise punctuation affects voice reproduction
- Examples of differences:
- `Im` vs `I'm` vs `I am`
- Commas affect pacing
- Periods affect sentence flow
- Capital letters may be spelled out
- Use appropriate punctuation marks:
- Periods (.)
- Commas (,)
- Semi-colons (;)
- Apostrophes (')
## ⚙️ Performance Settings
### Speed Adjustment
- Default speed setting: 0.9
- 1.0 seems faster than reference audio
- Compensates for faster audio generation
- Adjustable in Default Settings tab
- Affected by:
- Sample length
- Text punctuation
- Reference text accuracy
"""
HELP_PAGE2 = """
### Best Practices
1. **Voice Samples**
- Keep under 15 seconds
- Use clear recordings
- Ensure consistent audio quality
- Avoid background noise
2. **Reference Text**
- Match spoken content exactly
- Include proper punctuation
- Verify text accuracy
- Consider natural speech patterns
3. **Model Selection**
- F5-TTS: When quality is priority
- E2-TTS: When speed is priority
- Consider system resources
- Test both for optimal results
## 📁 File Management
- **Models**: `/alltalk_tts/models/f5tts/`
- **Voice Samples**: `/alltalk_tts/voices/`
- **Reference Texts**: `.reference.txt` files alongside WAVs
- **Outputs**: `/alltalk_tts/outputs/`
- Automatic cleanup available
- Configurable retention period
- Set to 'Disabled' to keep all files
## 🔄 Reference Text Management
### Using the Manager
- Access via Reference Text/Sample Manager tab
- Color-coded file status:
- 🔴 Red: Needs reference text
- 🟢 Green: Has reference text
- Built-in audio playback
- Whisper transcription available
### Whisper Transcription Options
- **base** (200MB download): Fast, basic quality
- **medium** (1.5GB download): Better quality
- **large-v3** (3GB download): Best quality
- Automatic model download
- Helps create initial reference text
## 🔧 System Integration
- Click "Refresh Server Settings" after adding new voices
- Monitor system resources for optimal performance
- Consider storage space for models and samples
- Regular maintenance of output files recommended
## ⚠️ Important Notes
- Language Support: English and Chinese only
- Reference text accuracy is crucial
- Punctuation affects voice reproduction
- Sample length impacts playback speed
- Model selection based on use case
- System resources affect performance
- Regular updates may improve functionality
"""
REFERENCE_MANAGER = """
## 🎯 Reference Text/Sample Manager Help
The Reference Text/Sample Manager is a crucial tool for F5-TTS voice cloning, helping you manage and create accurate reference text files for your voice samples.
"""
REFERENCE_MANAGER1 = """
## 📝 Core Functionality
### File Status Indicators
- 🔴 Red: Files needing a reference text file
- 🟢 Green: Files with existing reference text file
- Visual system helps track incomplete samples
### Basic Operations
- **Preview Voice Sample**: Listen to selected audio
- **Refresh List**: Update file listing
- **Save Reference Text**: Create/update reference file
- **Delete Reference Text**: Remove existing reference
- **Auto-Transcribe**: Use Whisper for automatic transcription
## 📒 Creating Reference Text Files
### Manual Process
1. Select voice file from dropdown
2. Play audio using Preview button
3. Type exact spoken text in editor
4. Add appropriate punctuation
5. Save reference text
6. Click "Refresh Server Settings" on main page
### Punctuation Guidelines
- **Period (.)**: End of sentences
- **Comma (,)**: Natural pauses
- **Semi-colon (;)**: Longer pauses
- **Apostrophe (')**: Contractions like:
- "I'm"
- "don't"
- "can't"
- "we're"
- Where necessary use phonetics
- This is a test of TTS (vs)
- This is a test of tea tea ess
## 🎤 Voice Sample Requirements
### Audio Guidelines
- Maximum length: 15 seconds
- Format: WAV files
- Quality: Clear, minimal noise
- Location: `/alltalk_tts/voices/`
### Important Notes
- Longer samples may affect playback speed
- Only English and Chinese languages supported
- Exact text matching is crucial
- Include natural speech punctuation
"""
REFERENCE_MANAGER2 = """
## 🤖 Whisper Transcription
### Available Models
1. **base (1GB VRAM)**
- Fast processing
- Basic quality
- Good for most uses
- Smallest disk space
2. **medium (4GB VRAM)**
- Better quality
- Slower processing
- Moderate disk space
3. **large-v3 (10GB VRAM)**
- Best quality
- Slowest processing
- Largest disk space
### Using Whisper
- Select desired model from dropdown
- Click "Auto-Transcribe Missing Files"
- Review and edit transcriptions
- Add punctuation as needed
- Save corrected text
### Storage Notes
- Models download automatically
- Verify available disk space
- One-time download per model
- Models persist between sessions
## 💡 Best Practices
1. **Text Accuracy**
- Listen to audio multiple times
- Match text exactly
- Include all spoken words
- Maintain speech patterns
2. **Punctuation Usage**
- Mark natural pauses
- Use appropriate marks
- Consider speech flow
- Be consistent
3. **Workflow Tips**
- Process files in batches
- Verify saved references
- Use Whisper for initial draft
- Double-check automated transcriptions
## ⚠️ Important Reminders
- Always refresh server settings after changes
- Keep voice samples under 15 seconds
- Back up reference text files
- Review automated transcriptions
- Consider system storage for Whisper models
- Language support limited to English and Chinese
"""
+19 -7
View File
@@ -389,11 +389,13 @@ class tts_class:
models_dir = self.main_dir / "models" / "f5tts" models_dir = self.main_dir / "models" / "f5tts"
if not models_dir.exists(): if not models_dir.exists():
print(f"[{self.branding}ENG] Models directory not found: {models_dir}") print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Models directory not found: {models_dir}")
self.available_models["No Models Found"] = "No Models Found" print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Please use the Gradio inteface to download/select a model.")
self.available_models["No Models Found"] = "f5tts"
return self.available_models return self.available_models
# Look for model directories that match the pattern f5tts_v* # Look for model directories that match the pattern f5tts_v*
found_valid_model = False
for model_dir in models_dir.glob("*tts_v*"): for model_dir in models_dir.glob("*tts_v*"):
if model_dir.is_dir(): if model_dir.is_dir():
# First try to find model_*.safetensors files # First try to find model_*.safetensors files
@@ -410,16 +412,20 @@ class tts_class:
# Check if we have at least one model file and all other required files # Check if we have at least one model file and all other required files
if model_files and all(f.exists() for f in [vocab_file, vocos_config, vocos_model]): if model_files and all(f.exists() for f in [vocab_file, vocos_config, vocos_model]):
model_name = model_dir.name model_name = model_dir.name
self.available_models[model_name] = model_name self.available_models[f"f5tts - {model_name}"] = "f5tts"
found_valid_model = True
print(f"[{self.branding}ENG] Found valid model: {model_name}") if self.debug_tts else None
else:
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Model folder '{model_dir.name}' is missing required files")
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ # ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ↓↓↓ Keep everything below this line ↓↓↓ # ↓↓↓ Keep everything below this line ↓↓↓
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ # ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
if not self.available_models: if not found_valid_model:
self.available_models["No Models Found"] = "No Models Found" # Return a list with {'No Models Found'} if there are no models found. self.available_models["No Models Found"] = "f5tts"
return self.available_models # Return a list of models in the format {'engine name': 'model 1', 'engine name': 'model 2", etc} print(f"[{self.branding}ENG] \033[91mWarning\033[0m: No valid F5-TTS models found")
return self.available_models
#############################################################
############################################################# #############################################################
# CHANGE ME # POPULATE FILES LIST FROM VOICES DIRECTORY #### # CHANGE ME # POPULATE FILES LIST FROM VOICES DIRECTORY ####
############################################################# #############################################################
@@ -487,6 +493,12 @@ class tts_class:
# Split the engine name from model name and get just the model folder name # Split the engine name from model name and get just the model folder name
model_folder = model_name.split(" - ")[-1] model_folder = model_name.split(" - ")[-1]
model_dir = self.main_dir / "models" / "f5tts" / model_folder
if not model_dir.exists():
print(f"[{self.branding}ENG] \033[91mError\033[0m: Model directory not found: {model_dir}")
print(f"[{self.branding}ENG] \033[93mPlease download an F5-TTS model file in the Gradio interface section for the F5-TTS engine.\033[0m")
raise HTTPException(status_code=404, detail=f"Model directory not found: {model_dir}")
try: try:
# Set up paths using the correct model folder name # Set up paths using the correct model folder name
+432
View File
@@ -0,0 +1,432 @@
# help_content.py
# pylint: disable=no-member
class AllTalkHelpContent:
"""CSS and help content for help_content.py"""
custom_css = """
/* Add this to your existing CSS */
.gradio-container .prose {
max-width: none !important;
padding: 0.5rem !important; /* Reduced padding */
margin: 0 !important;
}
.custom-markdown div {
border: none !important; /* Remove the inner border */
margin-top: 0 !important; /* Remove top margin */
margin-bottom: 0 !important; /* Remove bottom margin */
padding-top: 0 !important; /* Remove top padding */
padding-bottom: 0 !important; /* Remove bottom padding */
}
/* Update the existing custom-markdown class */
.custom-markdown {
font-size: 15px !important;
line-height: 1.6 !important;
color: var(--body-text-color) !important;
background-color: var(--background-fill-primary) !important;
border: 1px solid var(--border-color-primary) !important;
border-radius: 8px !important;
padding: 0.5rem !important;
margin: 0 !important; /* Changed from 1rem 0 to 0 */
max-width: 100% !important;
box-sizing: border-box !important;
/* Default text color for all content (grey) */
color: rgba(156, 163, 175, 1) !important; /* Adjust this grey value to match your interface */
}
/* Make headings white */
.custom-markdown h1,
.custom-markdown h2,
.custom-markdown h3,
.custom-markdown h4,
.custom-markdown h5,
.custom-markdown h6 {
color: var(--heading-text-color, var(--body-text-color)) !important;
font-weight: 600 !important;
}
/* Keep all other elements in the grey color */
.custom-markdown p,
.custom-markdown li,
.custom-markdown ul,
.custom-markdown ol {
color: rgba(156, 163, 175, 1) !important; /* Same grey as the base text */
}
/* Additional targeting for any wrapping elements */
.gradio-container .prose > * {
margin: 0 !important;
padding: 0 !important;
}
/* Update the list item spacing in your existing CSS */
.custom-markdown li {
font-size: 0.95rem !important;
margin-bottom: 0.2rem !important; /* Reduced from 0.5rem to 0.3rem */
}
/* Add specific styling for definition-style lists (like your Default, Recommendation, Tip items) */
.custom-markdown li p {
margin: 0 !important; /* Remove paragraph margins within list items */
}
/* If you need even tighter spacing for specific types of lists */
.custom-markdown li + li {
margin-top: 0.2rem !important; /* Space between consecutive list items */
}
/* Ensure nested lists maintain proper spacing */
.custom-markdown li > ul,
.custom-markdown li > ol {
margin: 0.2rem 0 0.2rem 1rem !important; /* Reduced from 0.5rem */
}
/* Consistent heading styles */
.custom-markdown h2 {
font-size: 1.2rem !important; /* Fixed size relative to root */
font-weight: 600 !important;
margin: 1.5rem 0 1rem !important;
color: var(--heading-text-color, var(--body-text-color)) !important;
border-bottom: 1px solid var(--border-color-primary) !important;
padding-bottom: 0.5rem !important;
}
/* First paragraph styling */
.custom-markdown p:first-of-type {
font-size: 0.95rem !important; /* Match base size */
font-weight: 400 !important;
margin-bottom: 1rem !important;
}
/* Regular paragraphs */
.custom-markdown p {
font-size: 0.95rem !important;
margin: 0.8rem 0 !important;
}
/* List styling */
.custom-markdown ul,
.custom-markdown ol {
margin: 0.8rem 0 !important;
padding-left: 1.5rem !important;
}
/* Code styling */
.custom-markdown code {
font-family: ui-monospace, monospace !important;
background-color: var(--background-fill-secondary) !important;
padding: 0.2rem 0.4rem !important;
border-radius: 4px !important;
font-size: 0.8rem !important; /* Slightly smaller than regular text */
color: var(--body-text-color) !important;
}
/* Add styles for bold and emphasis */
.custom-markdown strong {
font-weight: 600 !important;
color: var(--body-text-color) !important;
}
.custom-markdown em {
font-style: italic !important;
}
/* Ensure both columns take equal width */
.gradio-row > div {
flex: 1 1 50% !important;
min-width: 0 !important; /* Prevents flex items from overflowing */
}
"""
ENGINE_INFORMATION = """
## 🔊 TTS Engine Capabilities Help
This guide explains the various capabilities that **may** be available in different TTS engines and models. Each capability affects how the TTS engine processes and generates speech output.
"""
ENGINE_INFORMATION1 = """
## 🚀 Performance Features
- **DeepSpeed Capable**: Enables GPU acceleration using the DeepSpeed optimization library.
- **Requires**: NVIDIA GPU with CUDA support
- **Benefit**: Significantly faster text-to-speech generation
- **Note**: Model must specifically support DeepSpeed inference
- **Low VRAM Capable**: Optimized for systems with limited GPU memory.
- **Benefit**: Efficient memory management between CPU and GPU
- **Use Case**: Ideal when running alongside other GPU-intensive applications like LLMs
- **Note**: May trade speed for memory efficiency
- **Streaming Capable**: Enables real-time speech generation.
- **Benefit**: Immediate playback without generating entire audio first
- **Use Case**: Interactive applications and real-time responses
- **Note**: Not all output formats support streaming
## 🎵 Voice Control Features
- **Pitch Capable**: Allows adjustment of voice pitch.
- **Benefit**: Creates more expressive and varied speech output
- **Use Case**: Customizing voice characteristics
- **Note**: Adjustment range varies by model
- **Generation Speed Capable**: Controls speech rate.
- **Benefit**: Adjustable playback speed during generation
- **Use Case**: Creating faster or slower speech output
- **Note**: May affect audio quality at extreme settings
- **Temperature Capable**: Controls output randomness.
- **Benefit**: Adjustable speech variation and creativity
- **Use Case**: Balancing consistency vs. naturality
- **Note**: Higher values increase variation but may reduce quality
"""
ENGINE_INFORMATION2 = """
## 🎯 Quality Enhancement Features
- **Repetition Penalty Capable**: Prevents unnatural speech patterns.
- **Benefit**: Reduces repeated sounds and phrases
- **Use Case**: Improving natural flow of longer texts
- **Note**: Strength of penalty may be adjustable
## 🌐 Multi-Feature Support
- **Multi-Languages Capable Models**: Each model Supports multiple languages.
- **Benefit**: Generate speech in different languages
- **Note**: Quality may vary between languages
- **Tip**: Check model-specific language support
- **Multi-Voice Capable**: Supports multiple speaking voices.
- **Benefit**: Different voices or speaking styles
- **Types**: Pre-trained voices or voice cloning
- **Note**: Voice quality may vary by model
- **Multi-Model Capable Engine**: Supports multiple TTS models.
- **Benefit**: Flexibility in model selection
- **Use Case**: Switching between models for different needs
- **Note**: Each model may have different capabilities
## 📁 Technical Features
- **Default Audio Output Format**: Specifies output file format.
- **Common Formats**: WAV, MP3, FLAC, Opus, AAC, PCM
- **Note**: Transcoding to different formats adds processing time
- **Warning**: Not all formats support streaming
- **Platform Support**: Operating system compatibility.
- **Platforms**: Windows, Linux, macOS
- **Note**: Additional setup may be required
- **Warning**: Support level may vary by platform
"""
DEFAULT_SETTINGS = """
## 🎯 TTS Engine Settings Help
This guide explains the settings and configuration options available for individual Text-to-Speech engines within AllTalk.
"""
DEFAULT_SETTINGS1 = """
## 🎚️ Engine Capabilities & Controls
- **Low VRAM Mode**
- Optimizes memory usage for systems with limited GPU memory
- Efficiently manages resources by moving data between CPU and GPU
- Recommended for systems with less than 4GB VRAM or when running alongside other GPU-intensive applications
- **DeepSpeed Capability**
- Accelerates TTS generation using optimized inference
- Only available for engines and models that support DeepSpeed
- Requires NVIDIA GPU with CUDA support
- **Temperature Control**
- Adjusts the variability in speech generation
- **Range**: 0.0 to 1.0
- **Lower values** (0.1-0.5): More consistent, stable output
- **Higher values** (0.6-1.0): More variable, potentially more natural-sounding output
- **Repetition Penalty**
- Helps prevent repetitive speech patterns
- **Range**: 1.0 to 15.0
- Higher values more strongly discourage repetition
- Typically most effective between 1.0-3.0
- **Pitch Adjustment**
- Modifies the voice pitch when supported
- **Range**: -20 to +20
- Use subtle adjustments for most natural results
- **Generation Speed**
- Controls the pace of generated speech
- **Range**: 0.5 to 2.0
- 1.0 represents normal speed
"""
DEFAULT_SETTINGS2 = """
## 🗣️ Voice Configuration
### OpenAI Voice Mappings
- Only relevant when using the OpenAI-compatible API endpoint
- Maps OpenAI's six standard voices to equivalent voices in the current engine:
- `alloy`
- `echo`
- `fable`
- `nova`
- `onyx`
- `shimmer`
- Essential for maintaining compatibility with OpenAI API calls
- Each mapping can be customized to any available voice in the current engine
Information on the OpenAI Endpoint is available in the [Github Wiki](https://github.com/erew123/alltalk_tts/wiki)
### Default Voices
- **Default/Character Voice**: Used when no specific voice is specified in API calls
- **Narrator Voice**: Separate default for narrator-specific text
- These defaults are engine-specific and won't affect other TTS engines
- Can be overridden by explicitly specifying voices in API calls
## ⚙️ Important Notes
- Settings availability is determined by engine capabilities
- Grayed-out options indicate features not supported by the current engine
- Changes only affect the currently selected TTS engine
- Settings here act as defaults but can be overridden via API parameters
- All changes require clicking "Update Settings" to take effect
- Some settings require an engine reload to take effect
"""
HELP_PAGE = """
## 🎯 Parler TTS Engine Settings Help
Parler TTS is a unique text-to-speech system that generates voices based on descriptive prompts, similar to how image generation AI works with text descriptions.
"""
HELP_PAGE1 = """
## 📁 File Locations & Management
- **Model Storage**
- Models are stored in `/alltalk_tts/models/parler/{model name}`
## 🎚️ Engine Capabilities & Controls
- **Low VRAM Mode**
- Enabled by default for optimized memory management
- Helps balance resource usage when running alongside other applications
- Recommended for most setups
- **Multi-Model Support**
- Supports multiple internal models for voice generation
- Allows for diverse voice characteristics and styles
- Enables both native and custom voice descriptions
## 🗣️ Voice System
### Native Voices
- 34 built-in consistent voices including:
- Aaron, Alisa, Anna, Barbara, Bill, etc.
- Each native voice provides more consistent results
- Use these when you need reproducible voice characteristics
### Custom Voice Descriptions
- Create voices by describing desired characteristics:
- Gender and age
- Speaking style and pace
- Accent and tone
- Audio quality characteristics
- **Example**: "A female speaker with an enthusiastic and lively voice. Her tone is bright and energetic, with a fast pace and a lot of inflection."
### Voice Editor
- Add and manage custom voice descriptions
- Save frequently used voice configurations
- Edit existing voice descriptions
- Voice settings are stored in `system/tts_engines/parler/parler_voices.json`
"""
HELP_PAGE2 = """
## 📝 Important Notes
- **Voice Consistency**
- Unlike traditional TTS engines, each generation may sound slightly different
- Native voices provide more consistent results
- Custom voice descriptions may vary between generations
- **Audio Quality Control**
- Include "very clear audio" in description for highest quality
- Use "very noisy audio" for intentional background noise
- Control reverb and recording proximity through descriptions
- **Best Practices**
- Use punctuation to control speech rhythm
- Be specific in voice descriptions
- Test different description combinations for desired results
- Consider using native voices for consistent output
## ⚠️ Known Limitations
- No support for:
- DeepSpeed acceleration
- Pitch adjustment
- Generation speed control
- Repetition penalty
- Temperature adjustment
- Streaming generation
- Multi-language capabilities
## 🔧 System Requirements
- Runs on all major operating systems:
- Windows
- Linux
- macOS
- Outputs in WAV format
- May show flash attention warnings on Windows (normal behavior)
"""
VOICE_EDITOR = """
## 🎙️ Parler Voice Editor Help
The Voice Editor allows you to create, manage, and customize voice descriptions for Parler TTS. Each voice consists of a name and a detailed description that defines its characteristics.
"""
VOICE_EDITOR1 = """
## 📝 Creating Voice Descriptions
### Basic Structure
- **Voice Name**: A unique identifier for your voice (e.g., "Soothing female", "Angry Tom")
- **Voice Description**: Detailed description of voice characteristics
### Description Components
Include these elements for best results:
- Gender and age characteristics
- Speaking style and pace
- Tone and emotional quality
- Audio environment/quality
- Accent or language characteristics (if desired)
### Example Descriptions
`A female speaker with a soft, soothing voice. Her tone is gentle and calming, with a slight reverb as if she is in a small, cozy room.`
`A male speaker with a strong, authoritative voice. His tone is firm and commanding, with a slight bass boost that adds to the depth. He speaks at a moderate pace.`
"""
VOICE_EDITOR2 = """
## 💡 Best Practices
- **Be Specific**: The more detailed your description, the better the results
- **Include Audio Quality**: Mention desired audio characteristics (clear, reverb, etc.)
- **Consider Pacing**: Specify speaking speed (slow, moderate, fast)
- **Define Personality**: Include emotional and stylistic elements
## 🔧 Managing Voices
- Use **Add/Save Voice** to create new or update existing voices
- **Delete Selected Voice** removes the currently selected voice
- **Clear Text Boxes** resets the input fields
- Select any voice from the dropdown to edit its properties
## ⚠️ Important Notes
- Each generation may sound slightly different even with the same description
- Native voices tend to be more consistent than custom voices
- Changes are saved to the voice configuration file automatically
"""
+30 -20
View File
@@ -244,18 +244,25 @@ class tts_class:
# voices that can be selected in the interface. # voices that can be selected in the interface.
# If no models are found, we return "No Models Available" and continue on with the script. # If no models are found, we return "No Models Available" and continue on with the script.
def scan_models_folder(self): def scan_models_folder(self):
models_folder = self.main_dir / "models" / "parler" # Edit to match the name of your folder where voices are stored models_folder = self.main_dir / "models" / "parler"
print("models_folder is:", models_folder) if self.debug_tts else None print("models_folder is:", models_folder) if self.debug_tts else None
self.available_models = {} self.available_models = {}
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↑↑↑ Keep everything above this line ↑↑↑ # Add immediate check for models folder existence
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ if not models_folder.exists():
# Check if model_path exists print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Models folder does not exist: {models_folder}")
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Please use the Gradio inteface to download/select a model.")
self.available_models = {'No Models Available': 'parler'}
return self.available_models
# Check basic files needed for any model
common_required_files = [ common_required_files = [
"config.json", "generation_config.json", "preprocessor_config.json", "config.json",
"special_tokens_map.json", "spiece.model", "tokenizer.json", "tokenizer_config.json" "tokenizer_config.json",
"special_tokens_map.json"
] ]
found_valid_model = False
for subfolder in models_folder.iterdir(): for subfolder in models_folder.iterdir():
if subfolder.is_dir(): if subfolder.is_dir():
model_name = subfolder.name model_name = subfolder.name
@@ -263,28 +270,26 @@ class tts_class:
# Check for common required files # Check for common required files
if all(subfolder.joinpath(file).exists() for file in common_required_files): if all(subfolder.joinpath(file).exists() for file in common_required_files):
# Check for mini model (single safetensors file) # Look for any safetensors files
if subfolder.joinpath("model.safetensors").exists(): safetensor_files = list(subfolder.glob("*.safetensors"))
self.available_models[f"parler - {model_name}"] = "parler" if safetensor_files:
print("self.available_models is:", self.available_models) if self.debug_tts else None
# Check for large model (split safetensors files and index)
elif (subfolder.joinpath("model.safetensors.index.json").exists() and
subfolder.joinpath("model-00001-of-00002.safetensors").exists() and
subfolder.joinpath("model-00002-of-00002.safetensors").exists()):
self.available_models[f"parler - {model_name}"] = "parler" self.available_models[f"parler - {model_name}"] = "parler"
found_valid_model = True
print("self.available_models is:", self.available_models) if self.debug_tts else None print("self.available_models is:", self.available_models) if self.debug_tts else None
else: else:
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Model folder '{model_name}' is missing required model files.") print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Model folder '{model_name}' has no .safetensors files.")
else: else:
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Model folder '{model_name}' is missing common required files.") print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Model folder '{model_name}' is missing common required files.")
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ # ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ↓↓↓ Keep everything below this line ↓↓↓ # ↓↓↓ Keep everything below this line ↓↓↓
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ # ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
else:
self.available_models = {'No Models Available': 'parler'} # Change the name in here to your TTS engine name if not found_valid_model:
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Model folder '{model_name}' is missing required") self.available_models = {'No Models Available': 'parler'}
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: files or the folder does not exist.") print(f"[{self.branding}ENG] \033[91mWarning\033[0m: No valid Parler models found.")
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Please download and install Parler models.")
return self.available_models return self.available_models
############################################################# #############################################################
@@ -341,6 +346,11 @@ class tts_class:
model_path = self.main_dir / "models" / "parler" / model_name model_path = self.main_dir / "models" / "parler" / model_name
print("model_path is:", model_path) if self.debug_tts_variables else None print("model_path is:", model_path) if self.debug_tts_variables else None
if not model_path.exists():
print(f"[{self.branding}ENG] \033[91mError\033[0m: Model directory not found: {model_path}")
print(f"[{self.branding}ENG] \033[93mPlease download a Parler model file in the Gradio interface section for the Parler engine.\033[0m")
raise HTTPException(status_code=404, detail=f"Model directory not found: {model_path}")
# Get the appropriate dtype # Get the appropriate dtype
dtype = self.get_dtype() dtype = self.get_dtype()
@@ -4,6 +4,7 @@ import requests
import gradio as gr import gradio as gr
from tqdm import tqdm from tqdm import tqdm
from pathlib import Path from pathlib import Path
from .help_content import AllTalkHelpContent
this_dir = Path(__file__).parent.resolve() # Sets up self.this_dir as a variable for the folder THIS script is running in. this_dir = Path(__file__).parent.resolve() # Sets up self.this_dir as a variable for the folder THIS script is running in.
main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up self.main_dir as a variable for the folder AllTalk is running in main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up self.main_dir as a variable for the folder AllTalk is running in
@@ -127,11 +128,17 @@ def parler_model_alltalk_settings(model_config_data):
def_narrator_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_narrator_voice"], label="Narrator Voice", choices=voice_list, allow_custom_value=True) def_narrator_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_narrator_voice"], label="Narrator Voice", choices=voice_list, allow_custom_value=True)
with gr.Group(): with gr.Group():
with gr.Row(): with gr.Row():
details_text = gr.Textbox(label="Details", show_label=False, lines=5, interactive=False, value="In this section, you can set the default settings for this TTS engine. Settings that are not supported by the current engine will be greyed out and cannot be selected. Default voices specified here will be used when no specific voice is provided in the TTS generation request. If a voice is specified in the request, it will override these default settings. When using the OpenAI API compatable API with this TTS engine, the voice mappings will be applied. As the OpenAI API has a limited set of 6 voices, these mappings ensure compatibility by mapping the OpenAI voices to the available voices in this TTS engine.") details_text = gr.Textbox(label="Details", show_label=False, lines=5, interactive=False, value="Configure default settings and voice mappings for the selected TTS engine. Unavailable options are grayed out based on engine capabilities. See the Help section below for detailed information about each setting.")
with gr.Row(): with gr.Row():
submit_button = gr.Button("Update Settings") submit_button = gr.Button("Update Settings")
output_message = gr.Textbox(label="Output Message", interactive=False, show_label=False) output_message = gr.Textbox(label="Output Message", interactive=False, show_label=False)
submit_button.click(parler_model_update_settings, inputs=[def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr], outputs=output_message) submit_button.click(parler_model_update_settings, inputs=[def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr], outputs=output_message)
with gr.Accordion("HELP - 🔊 Understanding TTS Engine Default Settings Page", open=False):
with gr.Row():
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS, elem_classes="custom-markdown")
with gr.Row():
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS2, elem_classes="custom-markdown")
########################################################################################### ###########################################################################################
# Do not change this section apart from "TTS Engine Name" value to match your engine name # # Do not change this section apart from "TTS Engine Name" value to match your engine name #
@@ -164,34 +171,12 @@ def parler_model_alltalk_settings(model_config_data):
gr.Textbox(label="Linux Support", value='Yes' if features_list['linux_capable'] else 'No', interactive=False) gr.Textbox(label="Linux Support", value='Yes' if features_list['linux_capable'] else 'No', interactive=False)
gr.Textbox(label="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False) gr.Textbox(label="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False)
with gr.Row(): with gr.Row():
gr.Markdown(""" with gr.Accordion("HELP - 🔊 Understanding TTS Engine Capabilities", open=False):
#### 🟧 DeepSpeed Capable with gr.Row():
DeepSpeed is a deep learning optimization library that can significantly speed up model training and inference. If a model is DeepSpeed capable, it means it can utilize DeepSpeed to accelerate the generation of text-to-speech output. This requires the model to be loaded into CUDA/VRAM on an Nvidia GPU and the model's inference method to support DeepSpeed. gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION, elem_classes="custom-markdown")
#### 🟧 Pitch Capable with gr.Row():
Pitch refers to the highness or lowness of a sound. If a model is pitch capable, it can adjust the pitch of the generated speech, allowing for more expressive and varied output. gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION1, elem_classes="custom-markdown")
#### 🟧 Generation Speed Capable gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION2, elem_classes="custom-markdown")
Generation speed refers to the rate at which the model can generate text-to-speech output. If a model is generation speed capable, it means the speed of the generated speech can be adjusted, making it faster or slower depending on the desired output.
#### 🟧 Repetition Penalty Capable
Repetition penalty is a technique used to discourage the model from repeating the same words or phrases multiple times in the same sounding way. If a model is repetition penalty capable, it can apply this penalty during generation to improve the diversity and naturalness of the output.
#### 🟧 Multi-Languages Capable
Multi-language capable models can generate speech in multiple languages. This means that the model has been trained on data from different languages and can switch between them during generation. Some models are language-specific.
#### 🟧 Multi-Voice Capable
Multi-voice capable models generate speech in multiple voices or speaking styles. This means that the model has been trained on data from different speakers and can mimic their voices during generation, or is a voice cloning model that can generate speech based on the input sample.
""")
gr.Markdown("""
#### 🟧 Streaming Capable
Streaming refers to the ability to generate speech output in real-time, without the need to generate the entire output before playback. If a model is streaming capable, it can generate speech on-the-fly, allowing for faster response times and more interactive applications.
#### 🟧 Low VRAM Capable
VRAM (Video Random Access Memory) is a type of memory used by GPUs to store and process data. If a model is low VRAM capable, it can efficiently utilize the available VRAM by moving data between CPU and GPU memory as needed, allowing for generation even on systems with limited VRAM where it may be competing with an LLM model for VRAM.
#### 🟧 Temperature Capable
Temperature is a hyperparameter that controls the randomness of the generated output. If a model is temperature capable, the temperature can be adjusted to make the output more or less random, affecting the creativity and variability of the generated speech.
#### 🟧 Multi-Model Capable Engine
If an engine is multi-model capable, it means that it can support and utilize multiple models for text-to-speech generation. This allows for greater flexibility and the ability to switch between different models depending on the desired output. Different models may be capable of different languages, specific languages, voices, etc.
#### 🟧 Default Audio Output Format
Specifies the file format in which the generated speech will be saved. Common audio formats include WAV, MP3, FLAC, Opus, AAC, and PCM. If you want different outputs, you can set the transcode function to change the output audio, though transcoding will add a little time to the generation and is not available for streaming generation.
#### 🟧 Windows/Linux/Mac Support
These indicators show whether the model and engine are compatible with Windows, Linux, or macOS. However, additional setup or requirements may be necessary to ensure full functionality on your operating system. Please note that full platform support has not been extensively tested.
""")
####################################################################################################################################################################################################### #######################################################################################################################################################################################################
# REQUIRED CHANGE # # REQUIRED CHANGE #
@@ -347,6 +332,12 @@ def parler_model_alltalk_settings(model_config_data):
add_update_button.click(add_update_voice, inputs=[voice_name, description, selected_index, button_label], outputs=[voice_list, voice_name, description, selected_index, voice_name, button_label]) add_update_button.click(add_update_voice, inputs=[voice_name, description, selected_index, button_label], outputs=[voice_list, voice_name, description, selected_index, voice_name, button_label])
delete_button.click(delete_selected_voice, inputs=selected_index, outputs=[voice_list, voice_name, description, selected_index, voice_name, button_label]) delete_button.click(delete_selected_voice, inputs=selected_index, outputs=[voice_list, voice_name, description, selected_index, voice_name, button_label])
clear_button.click(clear_text_boxes, outputs=[voice_name, description, selected_index, voice_name, button_label]) clear_button.click(clear_text_boxes, outputs=[voice_name, description, selected_index, voice_name, button_label])
with gr.Accordion("HELP - 🎙️ Parler Voice Editor Help", open=False):
with gr.Row():
gr.Markdown(AllTalkHelpContent.VOICE_EDITOR, elem_classes="custom-markdown")
with gr.Row():
gr.Markdown(AllTalkHelpContent.VOICE_EDITOR1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.VOICE_EDITOR2, elem_classes="custom-markdown")
################################################################################################### ###################################################################################################
# REQUIRED CHANGE # # REQUIRED CHANGE #
@@ -355,54 +346,10 @@ def parler_model_alltalk_settings(model_config_data):
################################################################################################### ###################################################################################################
with gr.Tab("Engine Help"): with gr.Tab("Engine Help"):
with gr.Row(): with gr.Row():
gr.Markdown(""" gr.Markdown(AllTalkHelpContent.HELP_PAGE, elem_classes="custom-markdown")
### 🟧 Where are the Parler models stored? with gr.Row():
This extension will download the models to `/alltalk_tts/models/parler/` folder.<br> gr.Markdown(AllTalkHelpContent.HELP_PAGE1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.HELP_PAGE2, elem_classes="custom-markdown")
### 🟧 Where are the voices stored for parler models?
Parler is unlike any other TTS engine. It is actually mode like Stable Diffusion, where you write a text based description of what you want your image to look like, but in this case, you describe what you want the voice to sound like. For example `A female speaker with an enthusiastic and lively voice. Her tone is bright and energetic, with a fast pace and a lot of inflection. The audio is clear and vibrant.`
This means you can have pretty much any voice you want, however, the downside to this is, there is little consistency of the voices, meaning that no 2x TTS generations will sound exactly like the same voice. You can however use one of the `Native` built in voices to give a level of consistency. Please refer to the Parler website for more infomation https://github.com/huggingface/parler-tts.<br>
### 🟧 So how do I create my voices for Parler?
On the settings page for Parler, there is a Voice Editor tab. In there you can add/remove/ammend voices as you wish, or edit the `parler_voices.json` file stored in `system/tts_engines/parler/`.
### 🟧 Where are the outputs stored & Automatic output wav file deletion
Voice outputs are stored in `/alltalk_tts/outputs/`. You can configure automatic maintenance deletion of old wav files by setting `Del WAV's older than` in the global settings.<br>
> When `Disabled`, your output wav files will be left untouched.<br>
> When set to a setting `1 Day` or greater, your output wav files older than that time period will be automatically deleted on start-up of AllTalk.<br>
### 🟧 Skipped text/speech
At time of writing, this model is 1x day old and I could see reports of issues with some TTS not being generated, some longer text missing the middle portion of the text etc. You can confirm what AllTalk sent to the Parler TTS engine by looking at the command prompt/terminal window. If your text shows up there, it was sent to the Parler TTS engine. Please refer to the Parler website for more details https://github.com/huggingface/parler-tts.
""")
gr.Markdown("""
### 🟧 How do I use Parler's voice generation system?
To create a voice with Parler:
Describe the voice characteristics in your prompt. For example: `Jon's voice is monotone yet slightly fast in delivery, with a very close recording that almost has no background noise.`
Use one of the 34 inbuilt `Native` speaker names for a level of consistency: `Aaron, Alisa, Anna, Barbara, Bill, Brenda, Bruce, Carol, David, Eileen, Emily, Eric, Gary, James, Jason, Jenna, Jerry, Jon, Jordan, Joy, Karen, Laura, Lauren, Lea, Mike, Naomie, Patrick, Rebecca, Rick, Rose, Tina, Tom, Will, Yann`
Control audio quality in the voice characteristics prompt:
> Include `very clear audio` for highest quality<br>
> Use `very noisy audio` for high levels of background noise
Adjust other features in your voice characteristics prompt:
> Gender<br>
> Speaking rate<br>
> Pitch<br>
> Reverberation
Remember, while you can create diverse voices, each generation may sound slightly different even with the same description.
In the text sent for TTS generation, you can use punctuation to control speech rhythm (e.g. use `,` commas for small breaks)
### 🟧 UserWarning: 1Torch was not compiled with flash attention
This is a limitation of Windows Pytorch not yet having full flash attention support on later builds of Pytorch (is my understanding at this time).
""")
return app return app
+360
View File
@@ -0,0 +1,360 @@
# help_content.py
# pylint: disable=no-member
class AllTalkHelpContent:
"""CSS and help content for help_content.py"""
custom_css = """
/* Add this to your existing CSS */
.gradio-container .prose {
max-width: none !important;
padding: 0.5rem !important; /* Reduced padding */
margin: 0 !important;
}
.custom-markdown div {
border: none !important; /* Remove the inner border */
margin-top: 0 !important; /* Remove top margin */
margin-bottom: 0 !important; /* Remove bottom margin */
padding-top: 0 !important; /* Remove top padding */
padding-bottom: 0 !important; /* Remove bottom padding */
}
/* Update the existing custom-markdown class */
.custom-markdown {
font-size: 15px !important;
line-height: 1.6 !important;
color: var(--body-text-color) !important;
background-color: var(--background-fill-primary) !important;
border: 1px solid var(--border-color-primary) !important;
border-radius: 8px !important;
padding: 0.5rem !important;
margin: 0 !important; /* Changed from 1rem 0 to 0 */
max-width: 100% !important;
box-sizing: border-box !important;
/* Default text color for all content (grey) */
color: rgba(156, 163, 175, 1) !important; /* Adjust this grey value to match your interface */
}
/* Make headings white */
.custom-markdown h1,
.custom-markdown h2,
.custom-markdown h3,
.custom-markdown h4,
.custom-markdown h5,
.custom-markdown h6 {
color: var(--heading-text-color, var(--body-text-color)) !important;
font-weight: 600 !important;
}
/* Keep all other elements in the grey color */
.custom-markdown p,
.custom-markdown li,
.custom-markdown ul,
.custom-markdown ol {
color: rgba(156, 163, 175, 1) !important; /* Same grey as the base text */
}
/* Additional targeting for any wrapping elements */
.gradio-container .prose > * {
margin: 0 !important;
padding: 0 !important;
}
/* Update the list item spacing in your existing CSS */
.custom-markdown li {
font-size: 0.95rem !important;
margin-bottom: 0.2rem !important; /* Reduced from 0.5rem to 0.3rem */
}
/* Add specific styling for definition-style lists (like your Default, Recommendation, Tip items) */
.custom-markdown li p {
margin: 0 !important; /* Remove paragraph margins within list items */
}
/* If you need even tighter spacing for specific types of lists */
.custom-markdown li + li {
margin-top: 0.2rem !important; /* Space between consecutive list items */
}
/* Ensure nested lists maintain proper spacing */
.custom-markdown li > ul,
.custom-markdown li > ol {
margin: 0.2rem 0 0.2rem 1rem !important; /* Reduced from 0.5rem */
}
/* Consistent heading styles */
.custom-markdown h2 {
font-size: 1.2rem !important; /* Fixed size relative to root */
font-weight: 600 !important;
margin: 1.5rem 0 1rem !important;
color: var(--heading-text-color, var(--body-text-color)) !important;
border-bottom: 1px solid var(--border-color-primary) !important;
padding-bottom: 0.5rem !important;
}
/* First paragraph styling */
.custom-markdown p:first-of-type {
font-size: 0.95rem !important; /* Match base size */
font-weight: 400 !important;
margin-bottom: 1rem !important;
}
/* Regular paragraphs */
.custom-markdown p {
font-size: 0.95rem !important;
margin: 0.8rem 0 !important;
}
/* List styling */
.custom-markdown ul,
.custom-markdown ol {
margin: 0.8rem 0 !important;
padding-left: 1.5rem !important;
}
/* Code styling */
.custom-markdown code {
font-family: ui-monospace, monospace !important;
background-color: var(--background-fill-secondary) !important;
padding: 0.2rem 0.4rem !important;
border-radius: 4px !important;
font-size: 0.8rem !important; /* Slightly smaller than regular text */
color: var(--body-text-color) !important;
}
/* Add styles for bold and emphasis */
.custom-markdown strong {
font-weight: 600 !important;
color: var(--body-text-color) !important;
}
.custom-markdown em {
font-style: italic !important;
}
/* Ensure both columns take equal width */
.gradio-row > div {
flex: 1 1 50% !important;
min-width: 0 !important; /* Prevents flex items from overflowing */
}
"""
ENGINE_INFORMATION = """
## 🔊 TTS Engine Capabilities Help
This guide explains the various capabilities that **may** be available in different TTS engines and models. Each capability affects how the TTS engine processes and generates speech output.
"""
ENGINE_INFORMATION1 = """
## 🚀 Performance Features
- **DeepSpeed Capable**: Enables GPU acceleration using the DeepSpeed optimization library.
- **Requires**: NVIDIA GPU with CUDA support
- **Benefit**: Significantly faster text-to-speech generation
- **Note**: Model must specifically support DeepSpeed inference
- **Low VRAM Capable**: Optimized for systems with limited GPU memory.
- **Benefit**: Efficient memory management between CPU and GPU
- **Use Case**: Ideal when running alongside other GPU-intensive applications like LLMs
- **Note**: May trade speed for memory efficiency
- **Streaming Capable**: Enables real-time speech generation.
- **Benefit**: Immediate playback without generating entire audio first
- **Use Case**: Interactive applications and real-time responses
- **Note**: Not all output formats support streaming
## 🎵 Voice Control Features
- **Pitch Capable**: Allows adjustment of voice pitch.
- **Benefit**: Creates more expressive and varied speech output
- **Use Case**: Customizing voice characteristics
- **Note**: Adjustment range varies by model
- **Generation Speed Capable**: Controls speech rate.
- **Benefit**: Adjustable playback speed during generation
- **Use Case**: Creating faster or slower speech output
- **Note**: May affect audio quality at extreme settings
- **Temperature Capable**: Controls output randomness.
- **Benefit**: Adjustable speech variation and creativity
- **Use Case**: Balancing consistency vs. naturality
- **Note**: Higher values increase variation but may reduce quality
"""
ENGINE_INFORMATION2 = """
## 🎯 Quality Enhancement Features
- **Repetition Penalty Capable**: Prevents unnatural speech patterns.
- **Benefit**: Reduces repeated sounds and phrases
- **Use Case**: Improving natural flow of longer texts
- **Note**: Strength of penalty may be adjustable
## 🌐 Multi-Feature Support
- **Multi-Languages Capable Models**: Each model Supports multiple languages.
- **Benefit**: Generate speech in different languages
- **Note**: Quality may vary between languages
- **Tip**: Check model-specific language support
- **Multi-Voice Capable**: Supports multiple speaking voices.
- **Benefit**: Different voices or speaking styles
- **Types**: Pre-trained voices or voice cloning
- **Note**: Voice quality may vary by model
- **Multi-Model Capable Engine**: Supports multiple TTS models.
- **Benefit**: Flexibility in model selection
- **Use Case**: Switching between models for different needs
- **Note**: Each model may have different capabilities
## 📁 Technical Features
- **Default Audio Output Format**: Specifies output file format.
- **Common Formats**: WAV, MP3, FLAC, Opus, AAC, PCM
- **Note**: Transcoding to different formats adds processing time
- **Warning**: Not all formats support streaming
- **Platform Support**: Operating system compatibility.
- **Platforms**: Windows, Linux, macOS
- **Note**: Additional setup may be required
- **Warning**: Support level may vary by platform
"""
DEFAULT_SETTINGS = """
## 🎯 TTS Engine Settings Help
This guide explains the settings and configuration options available for individual Text-to-Speech engines within AllTalk.
"""
DEFAULT_SETTINGS1 = """
## 🎚️ Engine Capabilities & Controls
- **Low VRAM Mode**
- Optimizes memory usage for systems with limited GPU memory
- Efficiently manages resources by moving data between CPU and GPU
- Recommended for systems with less than 4GB VRAM or when running alongside other GPU-intensive applications
- **DeepSpeed Capability**
- Accelerates TTS generation using optimized inference
- Only available for engines and models that support DeepSpeed
- Requires NVIDIA GPU with CUDA support
- **Temperature Control**
- Adjusts the variability in speech generation
- **Range**: 0.0 to 1.0
- **Lower values** (0.1-0.5): More consistent, stable output
- **Higher values** (0.6-1.0): More variable, potentially more natural-sounding output
- **Repetition Penalty**
- Helps prevent repetitive speech patterns
- **Range**: 1.0 to 15.0
- Higher values more strongly discourage repetition
- Typically most effective between 1.0-3.0
- **Pitch Adjustment**
- Modifies the voice pitch when supported
- **Range**: -20 to +20
- Use subtle adjustments for most natural results
- **Generation Speed**
- Controls the pace of generated speech
- **Range**: 0.5 to 2.0
- 1.0 represents normal speed
"""
DEFAULT_SETTINGS2 = """
## 🗣️ Voice Configuration
### OpenAI Voice Mappings
- Only relevant when using the OpenAI-compatible API endpoint
- Maps OpenAI's six standard voices to equivalent voices in the current engine:
- `alloy`
- `echo`
- `fable`
- `nova`
- `onyx`
- `shimmer`
- Essential for maintaining compatibility with OpenAI API calls
- Each mapping can be customized to any available voice in the current engine
Information on the OpenAI Endpoint is available in the [Github Wiki](https://github.com/erew123/alltalk_tts/wiki)
### Default Voices
- **Default/Character Voice**: Used when no specific voice is specified in API calls
- **Narrator Voice**: Separate default for narrator-specific text
- These defaults are engine-specific and won't affect other TTS engines
- Can be overridden by explicitly specifying voices in API calls
## ⚙️ Important Notes
- Settings availability is determined by engine capabilities
- Grayed-out options indicate features not supported by the current engine
- Changes only affect the currently selected TTS engine
- Settings here act as defaults but can be overridden via API parameters
- All changes require clicking "Update Settings" to take effect
- Some settings require an engine reload to take effect
"""
HELP_PAGE = """
## 🎯 Piper TTS Engine Help
Piper is a fast, local neural Text-to-Speech system designed for efficient performance with high-quality output.
"""
HELP_PAGE1 = """
## 📁 File Locations & Management
- **Model Storage**
- Models are stored in `/alltalk_tts/models/piper/`
- Each model consists of two required files:
- `.onnx` file (the voice model)
- `.onnx.json` file (model configuration)
- **Output Files**
- Generated audio is saved to `/alltalk_tts/outputs/`
- Automatic cleanup available via `Del WAV's older than` setting
- When enabled, old files are removed on startup
- Set to `Disabled` to preserve all output files
## 🗣️ Voice System
- **Built-in Voices**
- Voices are integrated into the models themselves
- No separate voice files needed
- Each model represents a complete voice with its own characteristics
- Models are organized by language and quality levels (x_low, low, medium, high)
- **Language Support**
- Wide range of languages available
- Models named using language codes (e.g., en_US, de_DE)
- Multiple voice options per language
- Different quality levels for varying needs
"""
HELP_PAGE2 = """
## ⚡ Performance Features
- **Quality Levels**
- `x_low`: Fastest, lowest resource usage
- `low`: Good balance of speed and quality
- `medium`: Higher quality, moderate resources
- `high`: Best quality, higher resource usage
## 📝 Important Notes
- **Model Names**
- Format: `[language_code]-[voice_name]-[quality]`
- Example: `en_US-lessac-medium`
- Indicates language, speaker, and quality level
- **Best Practices**
- Choose quality level based on your system capabilities
- Use appropriate language model for your text
## 🔄 Model Downloads
- Models can be downloaded individually or as language packs
- All models are sourced from the official Piper repository
- Downloads include both required files automatically
- Models can be managed through the Models/Voices Download tab
"""
+203 -85
View File
@@ -4,6 +4,7 @@ import requests
import gradio as gr import gradio as gr
from tqdm import tqdm from tqdm import tqdm
from pathlib import Path from pathlib import Path
from .help_content import AllTalkHelpContent
this_dir = Path(__file__).parent.resolve() # Sets up self.this_dir as a variable for the folder THIS script is running in. this_dir = Path(__file__).parent.resolve() # Sets up self.this_dir as a variable for the folder THIS script is running in.
main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up self.main_dir as a variable for the folder AllTalk is running in main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up self.main_dir as a variable for the folder AllTalk is running in
@@ -40,6 +41,148 @@ def piper_voices_file_list():
return voices return voices
# Load the available models from the JSON file
with open(os.path.join(this_dir, "available_models.json"), "r") as f:
available_models = json.load(f)
# Extract the model names for the dropdown
model_names = [model["model_name"] for model in available_models["models"]]
#####################################################################
# Piper Specific section for grouping/downloading the models/voices #
#####################################################################
def group_models_by_language():
"""Group available models by language code (first 2 letters)"""
language_groups = {}
for model in available_models["models"]:
model_name = model["model_name"]
lang_code = model_name[:2] # Get first two letters (language code)
if lang_code not in language_groups:
language_groups[lang_code] = {
"name": get_language_name(lang_code),
"models": []
}
language_groups[lang_code]["models"].append(model)
return language_groups
def get_language_name(lang_code):
"""Convert language code to full name"""
language_names = {
"ar": "Arabic",
"ca": "Catalan",
"cs": "Czech",
"da": "Danish",
"de": "German",
"el": "Greek",
"en": "English",
"es": "Spanish",
"fa": "Persian",
"fi": "Finnish",
"fr": "French",
"hu": "Hungarian",
"is": "Icelandic",
"it": "Italian",
"ka": "Georgian",
"kk": "Kazakh",
"lb": "Luxembourgish",
"ne": "Nepali",
"nl": "Dutch",
"no": "Norwegian",
"pl": "Polish",
"pt": "Portuguese",
"ro": "Romanian",
"ru": "Russian",
"sk": "Slovak",
"sl": "Slovenian",
"sr": "Serbian",
"sv": "Swedish",
"sw": "Swahili",
"tr": "Turkish",
"uk": "Ukrainian",
"vi": "Vietnamese",
"zh": "Chinese"
}
return language_names.get(lang_code, f"Unknown ({lang_code})")
def download_model(model_name, force_download=False):
# Find the selected model in the available models
selected_model = next(model for model in available_models["models"] if model["model_name"] == model_name)
# Get the folder path and files to download
folder_path = os.path.join(main_dir, "models", "piper")
files_to_download = selected_model["files_to_download"]
# Check if all files are already downloaded
all_files_exists = all(os.path.exists(os.path.join(folder_path, os.path.basename(url.split('?')[0]))) for url in files_to_download)
if all_files_exists and not force_download:
return "All files are already downloaded. No need to download again."
else:
# Create the folder if it doesn't exist
os.makedirs(folder_path, exist_ok=True)
# Download the missing files
for url in files_to_download:
file_name = os.path.basename(url.split('?')[0])
file_path = os.path.join(folder_path, file_name)
if not os.path.exists(file_path) or force_download:
print(f"Downloading {file_name}...")
response = requests.get(url, stream=True)
total_size_in_bytes = int(response.headers.get("content-length", 0))
block_size = 1024 # 1 Kibibyte
progress_bar = tqdm(total=total_size_in_bytes, unit="iB", unit_scale=True)
with open(file_path, "wb") as file:
for data in response.iter_content(block_size):
progress_bar.update(len(data))
file.write(data)
progress_bar.close()
return "Model downloaded successfully!"
def download_language_pack(lang_code, progress=gr.Progress()):
"""Download all models for a specific language"""
language_groups = group_models_by_language()
if lang_code not in language_groups:
return f"Error: Language pack {lang_code} not found"
models = language_groups[lang_code]["models"]
total_models = len(models)
progress(0, desc=f"Downloading {get_language_name(lang_code)} voice pack")
folder_path = os.path.join(main_dir, "models", "piper")
os.makedirs(folder_path, exist_ok=True)
downloaded_files = []
errors = []
for idx, model in enumerate(models, 1):
progress(idx/total_models, desc=f"Downloading model {idx}/{total_models}")
for url in model["files_to_download"]:
try:
file_name = os.path.basename(url.split('?')[0])
file_path = os.path.join(folder_path, file_name)
if not os.path.exists(file_path):
response = requests.get(url, stream=True)
total_size = int(response.headers.get("content-length", 0))
with open(file_path, "wb") as file:
for chunk in response.iter_content(chunk_size=1024):
if chunk:
file.write(chunk)
downloaded_files.append(file_name)
except Exception as e:
errors.append(f"Error downloading {file_name}: {str(e)}")
if errors:
return f"Downloaded {len(downloaded_files)} files with {len(errors)} errors:\n" + "\n".join(errors)
else:
return f"Successfully downloaded {len(downloaded_files)} files for {get_language_name(lang_code)}"
###################################################### ######################################################
# REQUIRED CHANGE # # REQUIRED CHANGE #
# Imports and saves the TTS engine-specific settings # # Imports and saves the TTS engine-specific settings #
@@ -130,10 +273,16 @@ def piper_model_alltalk_settings(model_config_data):
def_narrator_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_narrator_voice"], label="Narrator Voice", choices=voice_list, allow_custom_value=True) def_narrator_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_narrator_voice"], label="Narrator Voice", choices=voice_list, allow_custom_value=True)
with gr.Group(): with gr.Group():
with gr.Row(): with gr.Row():
details_text = gr.Textbox(label="Details", show_label=False, lines=5, interactive=False, value="In this section, you can set the default settings for this TTS engine. Settings that are not supported by the current engine will be greyed out and cannot be selected. Default voices specified here will be used when no specific voice is provided in the TTS generation request. If a voice is specified in the request, it will override these default settings. When using the OpenAI API compatable API with this TTS engine, the voice mappings will be applied. As the OpenAI API has a limited set of 6 voices, these mappings ensure compatibility by mapping the OpenAI voices to the available voices in this TTS engine.") details_text = gr.Textbox(label="Details", show_label=False, lines=5, interactive=False, value="Configure default settings and voice mappings for the selected TTS engine. Unavailable options are grayed out based on engine capabilities. See the Help section below for detailed information about each setting.")
with gr.Row(): with gr.Row():
submit_button = gr.Button("Update Settings") submit_button = gr.Button("Update Settings")
output_message = gr.Textbox(label="Output Message", interactive=False, show_label=False) output_message = gr.Textbox(label="Output Message", interactive=False, show_label=False)
with gr.Accordion("HELP - 🔊 Understanding TTS Engine Default Settings Page", open=False):
with gr.Row():
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS, elem_classes="custom-markdown")
with gr.Row():
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS2, elem_classes="custom-markdown")
submit_button.click(piper_model_update_settings, inputs=[def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr], outputs=output_message) submit_button.click(piper_model_update_settings, inputs=[def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr], outputs=output_message)
########################################################################################### ###########################################################################################
@@ -167,84 +316,64 @@ def piper_model_alltalk_settings(model_config_data):
gr.Textbox(label="Linux Support", value='Yes' if features_list['linux_capable'] else 'No', interactive=False) gr.Textbox(label="Linux Support", value='Yes' if features_list['linux_capable'] else 'No', interactive=False)
gr.Textbox(label="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False) gr.Textbox(label="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False)
with gr.Row(): with gr.Row():
gr.Markdown(""" with gr.Accordion("HELP - 🔊 Understanding TTS Engine Capabilities", open=False):
#### 🟧 DeepSpeed Capable with gr.Row():
DeepSpeed is a deep learning optimization library that can significantly speed up model training and inference. If a model is DeepSpeed capable, it means it can utilize DeepSpeed to accelerate the generation of text-to-speech output. This requires the model to be loaded into CUDA/VRAM on an Nvidia GPU and the model's inference method to support DeepSpeed. gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION, elem_classes="custom-markdown")
#### 🟧 Pitch Capable with gr.Row():
Pitch refers to the highness or lowness of a sound. If a model is pitch capable, it can adjust the pitch of the generated speech, allowing for more expressive and varied output. gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION1, elem_classes="custom-markdown")
#### 🟧 Generation Speed Capable gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION2, elem_classes="custom-markdown")
Generation speed refers to the rate at which the model can generate text-to-speech output. If a model is generation speed capable, it means the speed of the generated speech can be adjusted, making it faster or slower depending on the desired output.
#### 🟧 Repetition Penalty Capable
Repetition penalty is a technique used to discourage the model from repeating the same words or phrases multiple times in the same sounding way. If a model is repetition penalty capable, it can apply this penalty during generation to improve the diversity and naturalness of the output.
#### 🟧 Multi-Languages Capable
Multi-language capable models can generate speech in multiple languages. This means that the model has been trained on data from different languages and can switch between them during generation. Some models are language-specific.
#### 🟧 Multi-Voice Capable
Multi-voice capable models generate speech in multiple voices or speaking styles. This means that the model has been trained on data from different speakers and can mimic their voices during generation, or is a voice cloning model that can generate speech based on the input sample.
""")
gr.Markdown("""
#### 🟧 Streaming Capable
Streaming refers to the ability to generate speech output in real-time, without the need to generate the entire output before playback. If a model is streaming capable, it can generate speech on-the-fly, allowing for faster response times and more interactive applications.
#### 🟧 Low VRAM Capable
VRAM (Video Random Access Memory) is a type of memory used by GPUs to store and process data. If a model is low VRAM capable, it can efficiently utilize the available VRAM by moving data between CPU and GPU memory as needed, allowing for generation even on systems with limited VRAM where it may be competing with an LLM model for VRAM.
#### 🟧 Temperature Capable
Temperature is a hyperparameter that controls the randomness of the generated output. If a model is temperature capable, the temperature can be adjusted to make the output more or less random, affecting the creativity and variability of the generated speech.
#### 🟧 Multi-Model Capable Engine
If an engine is multi-model capable, it means that it can support and utilize multiple models for text-to-speech generation. This allows for greater flexibility and the ability to switch between different models depending on the desired output. Different models may be capable of different languages, specific languages, voices, etc.
#### 🟧 Default Audio Output Format
Specifies the file format in which the generated speech will be saved. Common audio formats include WAV, MP3, FLAC, Opus, AAC, and PCM. If you want different outputs, you can set the transcode function to change the output audio, though transcoding will add a little time to the generation and is not available for streaming generation.
#### 🟧 Windows/Linux/Mac Support
These indicators show whether the model and engine are compatible with Windows, Linux, or macOS. However, additional setup or requirements may be necessary to ensure full functionality on your operating system. Please note that full platform support has not been extensively tested.
""")
####################################################################################################################################################################################################### #######################################################################################################################################################################################################
# REQUIRED CHANGE # # REQUIRED CHANGE #
# You will need to build a custom method to identify if your models are installed and download them. Store your models list in the available_models.json file, alongside your model_settings.json etc # # You will need to build a custom method to identify if your models are installed and download them. Store your models list in the available_models.json file, alongside your model_settings.json etc #
####################################################################################################################################################################################################### #######################################################################################################################################################################################################
with gr.Tab("Models/Voices Download"): with gr.Tab("Models/Voices Download"):
with gr.Row():
# Load the available models from the JSON file
with open(os.path.join(this_dir, "available_models.json"), "r") as f:
available_models = json.load(f)
# Extract the model names for the dropdown
model_names = [model["model_name"] for model in available_models["models"]]
# Create the dropdown
model_dropdown = gr.Dropdown(choices=sorted(model_names), label="Select Model", value=model_names[0])
download_button = gr.Button("Download Model/Missing Files")
def download_model(model_name, force_download=False): with gr.Tab("Language Pack Download"):
# Find the selected model in the available models with gr.Row():
selected_model = next(model for model in available_models["models"] if model["model_name"] == model_name) language_groups = group_models_by_language()
# Get the folder path and files to download language_choices = [
folder_path = os.path.join(main_dir, "models", "piper") f"{code} - {info['name']} ({len(info['models'])} voices)"
files_to_download = selected_model["files_to_download"] for code, info in sorted(language_groups.items())
# Check if all files are already downloaded ]
all_files_exists = all(os.path.exists(os.path.join(folder_path, os.path.basename(url.split('?')[0]))) for url in files_to_download)
if all_files_exists and not force_download:
return "All files are already downloaded. No need to download again."
else:
# Create the folder if it doesn't exist
os.makedirs(folder_path, exist_ok=True)
# Download the missing files
for url in files_to_download:
file_name = os.path.basename(url.split('?')[0])
file_path = os.path.join(folder_path, file_name)
if not os.path.exists(file_path) or force_download:
print(f"Downloading {file_name}...")
response = requests.get(url, stream=True)
total_size_in_bytes = int(response.headers.get("content-length", 0))
block_size = 1024 # 1 Kibibyte
progress_bar = tqdm(total=total_size_in_bytes, unit="iB", unit_scale=True)
with open(file_path, "wb") as file:
for data in response.iter_content(block_size):
progress_bar.update(len(data))
file.write(data)
progress_bar.close()
return "Model downloaded successfully!"
with gr.Row(): lang_pack_dropdown = gr.Dropdown(
download_status = gr.Textbox(label="Download Status") choices=language_choices,
label="Select Language Pack",
value=language_choices[0]
)
lang_pack_download_button = gr.Button("Download Language Pack")
download_button.click(download_model, inputs=model_dropdown, outputs=download_status) with gr.Row():
lang_pack_status = gr.Textbox(label="Language Pack Download Status")
def download_selected_language_pack(selected_pack):
lang_code = selected_pack.split(" - ")[0]
return download_language_pack(lang_code)
lang_pack_download_button.click(
download_selected_language_pack,
inputs=lang_pack_dropdown,
outputs=lang_pack_status
)
with gr.Tab("Individual Voice Download"):
with gr.Row():
model_dropdown = gr.Dropdown(
choices=sorted(model_names),
label="Select Individual Voice",
value=model_names[0]
)
download_button = gr.Button("Download Selected Voice")
with gr.Row():
download_status = gr.Textbox(label=" Individual Voice Download Status")
download_button.click(
download_model,
inputs=model_dropdown,
outputs=download_status
)
def show_confirm_cancel(model_name): def show_confirm_cancel(model_name):
all_files_exists = all(os.path.exists(os.path.join(main_dir, "models", "piper", os.path.basename(file.split('?')[0]))) for model in available_models["models"] if model["model_name"] == model_name for file in model["files_to_download"]) all_files_exists = all(os.path.exists(os.path.join(main_dir, "models", "piper", os.path.basename(file.split('?')[0]))) for model in available_models["models"] if model["model_name"] == model_name for file in model["files_to_download"])
@@ -275,21 +404,10 @@ def piper_model_alltalk_settings(model_config_data):
################################################################################################### ###################################################################################################
with gr.Tab("Engine Help"): with gr.Tab("Engine Help"):
with gr.Row(): with gr.Row():
gr.Markdown(""" gr.Markdown(AllTalkHelpContent.HELP_PAGE, elem_classes="custom-markdown")
### 🟧 Where are the Piper models stored? with gr.Row():
This extension will download the models to `/alltalk_tts/models/piper/` folder.<br> gr.Markdown(AllTalkHelpContent.HELP_PAGE1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.HELP_PAGE2, elem_classes="custom-markdown")
### 🟧 Where are the voices stored for piper models?
Piper models themselves are the voices/have the voices built into them. The models are made up of 2x files, an `onnx` file and a `onnx.json` file.<br>
### 🟧 Where are the outputs stored & Automatic output wav file deletion
Voice outputs are stored in `/alltalk_tts/outputs/`. You can configure automatic maintenance deletion of old wav files by setting `Del WAV's older than` in the global settings.<br>
> When `Disabled`, your output wav files will be left untouched.<br>
> When set to a setting `1 Day` or greater, your output wav files older than that time period will be automatically deleted on start-up of AllTalk.<br>
""")
gr.Markdown("""
""")
return app return app
@@ -1,40 +1,33 @@
{ {
"first_start_model": "en_GB-jenny_dioco-medium", "first_start_model": "xttsv2_2.0.3",
"models": [ "models": [
{ {
"model_name": "ar_JO-kareem-low", "model_name": "xttsv2_2.0.3",
"files_to_download": [ "folder_path": "xttsv2_2.0.3",
"https://huggingface.co/rhasspy/piper-voices/resolve/main/ar/ar_JO/kareem/low/ar_JO-kareem-low.onnx?download=true", "files_to_download": {
"https://huggingface.co/rhasspy/piper-voices/resolve/main/ar/ar_JO/kareem/low/ar_JO-kareem-low.onnx.json?download=true" "LICENSE.txt": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/LICENSE.txt?download=true",
] "README.md": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/README.md?download=true",
}, "config.json": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/config.json?download=true",
{ "model.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/model.pth?download=true",
"model_name": "ar_JO-kareem-medium", "dvae.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/dvae.pth?download=true",
"files_to_download": [ "mel_stats.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/mel_stats.pth?download=true",
"https://huggingface.co/rhasspy/piper-voices/resolve/main/ar/ar_JO/kareem/medium/ar_JO-kareem-medium.onnx?download=true", "speakers_xtts.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/speakers_xtts.pth?download=true",
"https://huggingface.co/rhasspy/piper-voices/resolve/main/ar/ar_JO/kareem/medium/ar_JO-kareem-medium.onnx.json?download=true" "vocab.json": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/vocab.json?download=true"
] }
}, },
{ {
"model_name": "vi_VN-vivos-x_low", "model_name": "xttsv2_2.0.2",
"files_to_download": [ "folder_path": "xttsv2_2.0.2",
"https://huggingface.co/rhasspy/piper-voices/resolve/main/vi/vi_VN/vivos/x_low/vi_VN-vivos-x_low.onnx?download=true", "files_to_download": {
"https://huggingface.co/rhasspy/piper-voices/resolve/main/vi/vi_VN/vivos/x_low/vi_VN-vivos-x_low.onnx.json?download=true" "LICENSE.txt": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/LICENSE.txt?download=true",
] "README.md": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/README.md?download=true",
}, "config.json": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/config.json?download=true",
{ "model.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/model.pth?download=true",
"model_name": "zh_CN-huayan-medium", "dvae.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/dvae.pth?download=true",
"files_to_download": [ "mel_stats.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/mel_stats.pth?download=true",
"https://huggingface.co/rhasspy/piper-voices/resolve/main/zh/zh_CN/huayan/medium/zh_CN-huayan-medium.onnx?download=true", "speakers_xtts.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/speakers_xtts.pth?download=true",
"https://huggingface.co/rhasspy/piper-voices/resolve/main/zh/zh_CN/huayan/medium/zh_CN-huayan-medium.onnx.json?download=true" "vocab.json": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/vocab.json?download=true"
] }
}, }
{ ]
"model_name": "zh_CN-huayan-x_low", }
"files_to_download": [
"https://huggingface.co/rhasspy/piper-voices/resolve/main/zh/zh_CN/huayan/x_low/zh_CN-huayan-x_low.onnx?download=true",
"https://huggingface.co/rhasspy/piper-voices/resolve/main/zh/zh_CN/huayan/x_low/zh_CN-huayan-x_low.onnx.json?download=true"
]
}
]
}
@@ -0,0 +1,458 @@
# help_content.py
# pylint: disable=no-member
class AllTalkHelpContent:
"""CSS and help content for help_content.py"""
custom_css = """
/* Add this to your existing CSS */
.gradio-container .prose {
max-width: none !important;
padding: 0.5rem !important; /* Reduced padding */
margin: 0 !important;
}
.custom-markdown div {
border: none !important; /* Remove the inner border */
margin-top: 0 !important; /* Remove top margin */
margin-bottom: 0 !important; /* Remove bottom margin */
padding-top: 0 !important; /* Remove top padding */
padding-bottom: 0 !important; /* Remove bottom padding */
}
/* Update the existing custom-markdown class */
.custom-markdown {
font-size: 15px !important;
line-height: 1.6 !important;
color: var(--body-text-color) !important;
background-color: var(--background-fill-primary) !important;
border: 1px solid var(--border-color-primary) !important;
border-radius: 8px !important;
padding: 0.5rem !important;
margin: 0 !important; /* Changed from 1rem 0 to 0 */
max-width: 100% !important;
box-sizing: border-box !important;
/* Default text color for all content (grey) */
color: rgba(156, 163, 175, 1) !important; /* Adjust this grey value to match your interface */
}
/* Make headings white */
.custom-markdown h1,
.custom-markdown h2,
.custom-markdown h3,
.custom-markdown h4,
.custom-markdown h5,
.custom-markdown h6 {
color: var(--heading-text-color, var(--body-text-color)) !important;
font-weight: 600 !important;
}
/* Keep all other elements in the grey color */
.custom-markdown p,
.custom-markdown li,
.custom-markdown ul,
.custom-markdown ol {
color: rgba(156, 163, 175, 1) !important; /* Same grey as the base text */
}
/* Additional targeting for any wrapping elements */
.gradio-container .prose > * {
margin: 0 !important;
padding: 0 !important;
}
/* Update the list item spacing in your existing CSS */
.custom-markdown li {
font-size: 0.95rem !important;
margin-bottom: 0.2rem !important; /* Reduced from 0.5rem to 0.3rem */
}
/* Add specific styling for definition-style lists (like your Default, Recommendation, Tip items) */
.custom-markdown li p {
margin: 0 !important; /* Remove paragraph margins within list items */
}
/* If you need even tighter spacing for specific types of lists */
.custom-markdown li + li {
margin-top: 0.2rem !important; /* Space between consecutive list items */
}
/* Ensure nested lists maintain proper spacing */
.custom-markdown li > ul,
.custom-markdown li > ol {
margin: 0.2rem 0 0.2rem 1rem !important; /* Reduced from 0.5rem */
}
/* Consistent heading styles */
.custom-markdown h2 {
font-size: 1.2rem !important; /* Fixed size relative to root */
font-weight: 600 !important;
margin: 1.5rem 0 1rem !important;
color: var(--heading-text-color, var(--body-text-color)) !important;
border-bottom: 1px solid var(--border-color-primary) !important;
padding-bottom: 0.5rem !important;
}
/* First paragraph styling */
.custom-markdown p:first-of-type {
font-size: 0.95rem !important; /* Match base size */
font-weight: 400 !important;
margin-bottom: 1rem !important;
}
/* Regular paragraphs */
.custom-markdown p {
font-size: 0.95rem !important;
margin: 0.8rem 0 !important;
}
/* List styling */
.custom-markdown ul,
.custom-markdown ol {
margin: 0.8rem 0 !important;
padding-left: 1.5rem !important;
}
/* Code styling */
.custom-markdown code {
font-family: ui-monospace, monospace !important;
background-color: var(--background-fill-secondary) !important;
padding: 0.2rem 0.4rem !important;
border-radius: 4px !important;
font-size: 0.8rem !important; /* Slightly smaller than regular text */
color: var(--body-text-color) !important;
}
/* Add styles for bold and emphasis */
.custom-markdown strong {
font-weight: 600 !important;
color: var(--body-text-color) !important;
}
.custom-markdown em {
font-style: italic !important;
}
/* Ensure both columns take equal width */
.gradio-row > div {
flex: 1 1 50% !important;
min-width: 0 !important; /* Prevents flex items from overflowing */
}
"""
ENGINE_INFORMATION = """
## 🔊 TTS Engine Capabilities Help
This guide explains the various capabilities that **may** be available in different TTS engines and models. Each capability affects how the TTS engine processes and generates speech output.
"""
ENGINE_INFORMATION1 = """
## 🚀 Performance Features
- **DeepSpeed Capable**: Enables GPU acceleration using the DeepSpeed optimization library.
- **Requires**: NVIDIA GPU with CUDA support
- **Benefit**: Significantly faster text-to-speech generation
- **Note**: Model must specifically support DeepSpeed inference
- **Low VRAM Capable**: Optimized for systems with limited GPU memory.
- **Benefit**: Efficient memory management between CPU and GPU
- **Use Case**: Ideal when running alongside other GPU-intensive applications like LLMs
- **Note**: May trade speed for memory efficiency
- **Streaming Capable**: Enables real-time speech generation.
- **Benefit**: Immediate playback without generating entire audio first
- **Use Case**: Interactive applications and real-time responses
- **Note**: Not all output formats support streaming
## 🎵 Voice Control Features
- **Pitch Capable**: Allows adjustment of voice pitch.
- **Benefit**: Creates more expressive and varied speech output
- **Use Case**: Customizing voice characteristics
- **Note**: Adjustment range varies by model
- **Generation Speed Capable**: Controls speech rate.
- **Benefit**: Adjustable playback speed during generation
- **Use Case**: Creating faster or slower speech output
- **Note**: May affect audio quality at extreme settings
- **Temperature Capable**: Controls output randomness.
- **Benefit**: Adjustable speech variation and creativity
- **Use Case**: Balancing consistency vs. naturality
- **Note**: Higher values increase variation but may reduce quality
"""
ENGINE_INFORMATION2 = """
## 🎯 Quality Enhancement Features
- **Repetition Penalty Capable**: Prevents unnatural speech patterns.
- **Benefit**: Reduces repeated sounds and phrases
- **Use Case**: Improving natural flow of longer texts
- **Note**: Strength of penalty may be adjustable
## 🌐 Multi-Feature Support
- **Multi-Languages Capable Models**: Each model Supports multiple languages.
- **Benefit**: Generate speech in different languages
- **Note**: Quality may vary between languages
- **Tip**: Check model-specific language support
- **Multi-Voice Capable**: Supports multiple speaking voices.
- **Benefit**: Different voices or speaking styles
- **Types**: Pre-trained voices or voice cloning
- **Note**: Voice quality may vary by model
- **Multi-Model Capable Engine**: Supports multiple TTS models.
- **Benefit**: Flexibility in model selection
- **Use Case**: Switching between models for different needs
- **Note**: Each model may have different capabilities
## 📁 Technical Features
- **Default Audio Output Format**: Specifies output file format.
- **Common Formats**: WAV, MP3, FLAC, Opus, AAC, PCM
- **Note**: Transcoding to different formats adds processing time
- **Warning**: Not all formats support streaming
- **Platform Support**: Operating system compatibility.
- **Platforms**: Windows, Linux, macOS
- **Note**: Additional setup may be required
- **Warning**: Support level may vary by platform
"""
DEFAULT_SETTINGS = """
## 🎯 TTS Engine Settings Help
This guide explains the settings and configuration options available for individual Text-to-Speech engines within AllTalk.
"""
DEFAULT_SETTINGS1 = """
## 🎚️ Engine Capabilities & Controls
- **Low VRAM Mode**
- Optimizes memory usage for systems with limited GPU memory
- Efficiently manages resources by moving data between CPU and GPU
- Recommended for systems with less than 4GB VRAM or when running alongside other GPU-intensive applications
- **DeepSpeed Capability**
- Accelerates TTS generation using optimized inference
- Only available for engines and models that support DeepSpeed
- Requires NVIDIA GPU with CUDA support
- **Temperature Control**
- Adjusts the variability in speech generation
- **Range**: 0.0 to 1.0
- **Lower values** (0.1-0.5): More consistent, stable output
- **Higher values** (0.6-1.0): More variable, potentially more natural-sounding output
- **Repetition Penalty**
- Helps prevent repetitive speech patterns
- **Range**: 1.0 to 15.0
- Higher values more strongly discourage repetition
- Typically most effective between 1.0-3.0
- **Pitch Adjustment**
- Modifies the voice pitch when supported
- **Range**: -20 to +20
- Use subtle adjustments for most natural results
- **Generation Speed**
- Controls the pace of generated speech
- **Range**: 0.5 to 2.0
- 1.0 represents normal speed
"""
DEFAULT_SETTINGS2 = """
## 🗣️ Voice Configuration
### OpenAI Voice Mappings
- Only relevant when using the OpenAI-compatible API endpoint
- Maps OpenAI's six standard voices to equivalent voices in the current engine:
- `alloy`
- `echo`
- `fable`
- `nova`
- `onyx`
- `shimmer`
- Essential for maintaining compatibility with OpenAI API calls
- Each mapping can be customized to any available voice in the current engine
Information on the OpenAI Endpoint is available in the [Github Wiki](https://github.com/erew123/alltalk_tts/wiki)
### Default Voices
- **Default/Character Voice**: Used when no specific voice is specified in API calls
- **Narrator Voice**: Separate default for narrator-specific text
- These defaults are engine-specific and won't affect other TTS engines
- Can be overridden by explicitly specifying voices in API calls
## ⚙️ Important Notes
- Settings availability is determined by engine capabilities
- Grayed-out options indicate features not supported by the current engine
- Changes only affect the currently selected TTS engine
- Settings here act as defaults but can be overridden via API parameters
- All changes require clicking "Update Settings" to take effect
- Some settings require an engine reload to take effect
"""
HELP_PAGE = """
## 🎯 XTTS Voice Cloning Engine Help
XTTS is a powerful multi-speaker, voice cloning model that can generate speech in multiple languages using short audio samples for voice cloning.
"""
HELP_PAGE1 = """
## 🎚️ Engine Capabilities & Controls
- **DeepSpeed Support**
- Accelerates generation using optimized inference
- Requires NVIDIA GPU with CUDA support
- 2-3x speed improvement in generation
- Recommended when available
- **Multi-Language Support**
- Clone voices across multiple languages
- No need for language-specific training
- Full Hindi support in v2.0.3 (API Local method only)
- Natural-sounding output in target language
- **Generation Methods**
- API Local: Standard generation method
- XTTSv2 Local: Enhanced method with DeepSpeed support
- Each method may produce slightly different results
- Try both methods if voice quality isn't optimal
## 🎤 Voice Sample Creation Guide
### Audio Requirements
- Format: WAV or MP3
- Sample Rate: 22050Hz
- Channels: Mono
- Bit Depth: 16-bit
- Duration: 6-30 seconds (optimal: 8-10 seconds)
### Recording Tips
1. **Audio Quality**
- Choose clear, clean recordings
- Avoid background noise, music, or echoes
- Watch for audio artifacts like hiss or hum
- Ensure consistent volume levels
2. **Speech Content**
- Use flowing, natural speech
- Avoid long pauses or gaps
- Include some emotional range
- Avoid breathing sounds at start/end
- Choose samples with good vocal variety
### Using Audacity
1. **Basic Editing**
- Open your audio file in Audacity
- Select the best 6-30 second segment
- Remove unwanted sounds or silence
2. **Processing Steps**
```
1. Clean up audio if needed (noise reduction, normalization)
2. Tracks > Resample to 22050Hz
3. Tracks > Mix > Stereo to Mono
4. File > Export Audio as WAV
```
## 🗣️ Voice Management
### Single Voice Setup
- Place WAV/MP3 files in `/alltalk_tts/voices/`
- Use descriptive filenames (e.g., `broadcaster_male.wav`)
- Files appear as individual voices in interface
- Best for quick testing or simple use cases
### Multi-Voice Sets
- Create folders in `/alltalk_tts/voices/xtts_multi_voice_sets/`
- Add multiple samples per voice
- System randomly selects up to 5 samples
- Better for consistent voice reproduction
- Example: `/voices/xtts_multi_voice_sets/broadcaster_voice/`
### Pre-computed Latents
- Stored in `/voices/xtts_latents/`
- Faster generation times
- Reduced memory usage
- Recommended for frequently used voices
"""
HELP_PAGE2 = """
## 📝 Model Versions
### v2.0.3 (Recommended)
- Latest stable release
- Full language support including Hindi
- Best overall performance
- Complete feature set
### v2.0.2 (Alternative)
- Stable fallback option
- Good performance
- Use if v2.0.3 has issues
### Required Files
- `config.json`: Model configuration
- `model.pth`: Core model weights
- `mel_stats.pth`: Audio statistics
- `speakers_xtts.pth`: Speaker embeddings
- `vocab.json`: Tokenizer vocabulary
- `dvae.pth`: Discrete VAE weights
## 🔍 Troubleshooting Voice Quality
If voice cloning results aren't satisfactory:
1. **Audio Quality Issues**
- Verify sample meets technical requirements
- Check for background noise
- Ensure proper resampling
- Try processing audio to improve clarity
2. **Generation Options**
- Try both API Local and XTTSv2 Local methods
- Adjust temperature settings
- Use multiple voice samples
- Consider creating latents
3. **Advanced Solutions**
- Try model finetuning (see Github Wiki)
- Use RVC pipeline for additional processing
- Test different voice samples
- Remember: 100% match isn't possible
## 📁 File Management
- **Models**: `/alltalk_tts/models/xtts/`
- **Voice Samples**: `/alltalk_tts/voices/`
- **Multi-Voice Sets**: `/alltalk_tts/voices/xtts_multi_voice_sets/`
- **Latents**: `/alltalk_tts/voices/xtts_latents/`
- **Outputs**: `/alltalk_tts/outputs/`
- Automatic cleanup available
- Configurable retention period
- Set to 'Disabled' to keep all files
## 💡 Best Practices
1. **Sample Selection**
- Use high-quality recordings
- Choose emotionally varied speech
- Avoid background noise
- Test multiple samples
2. **Performance**
- Enable DeepSpeed when available
- Use pre-computed latents
- Consider multi-voice sets
- Monitor system resources
3. **Workflow**
- Process audio before use
- Test both generation methods
- Keep original samples organized
- Regular cleanup of output files
"""
@@ -1,29 +1,29 @@
{ {
"model_details": { "model_details": {
"manufacturer_name": "MyTTSEngine", "manufacturer_name": "MYNEWTTS",
"manufacturer_website": "https://github.com/MyTTSEngine", "manufacturer_website": "https://something here",
"model_description": "A description and detail about the TTS Engine" "model_description": "A bit of blurb about the manufacturer/TTS engine"
}, },
"model_capabilties": { "model_capabilties": {
"audio_format": "wav", "audio_format": "wav",
"deepspeed_capable": false, "deepspeed_capable": true,
"generationspeed_capable": false, "generationspeed_capable": true,
"languages_capable": false, "languages_capable": true,
"lowvram_capable": false, "lowvram_capable": true,
"multimodel_capable": false, "multimodel_capable": true,
"repetitionpenalty_capable": false, "repetitionpenalty_capable": true,
"streaming_capable": false, "streaming_capable": true,
"temperature_capable": false, "temperature_capable": true,
"multivoice_capable": false, "multivoice_capable": true,
"pitch_capable": false, "pitch_capable": false,
"windows_capable": true, "windows_capable": true,
"linux_capable": true, "linux_capable": true,
"mac_capable": true "mac_capable": true
}, },
"settings": { "settings": {
"def_character_voice": "defaultvoice.wav", "def_character_voice": "female_01.wav",
"def_narrator_voice": "defaultvoice.wav", "def_narrator_voice": "male_01.wav",
"deepspeed_enabled": false, "deepspeed_enabled": true,
"engine_installed": true, "engine_installed": true,
"generationspeed_set": 1, "generationspeed_set": 1,
"lowvram_enabled": false, "lowvram_enabled": false,
@@ -32,11 +32,11 @@
"temperature_set": 0.75 "temperature_set": 0.75
}, },
"openai_voices": { "openai_voices": {
"alloy": "defaultvoice.wav", "alloy": "female_01.wav",
"echo": "defaultvoice.wav", "echo": "female_01.wav",
"fable": "defaultvoice.wav", "fable": "female_01.wav",
"nova": "defaultvoice.wav", "nova": "female_01.wav",
"onyx": "defaultvoice.wav", "onyx": "female_01.wav",
"shimmer": "defaultvoice.wav" "shimmer": "female_01.wav"
} }
} }
@@ -4,6 +4,7 @@ import requests
import gradio as gr import gradio as gr
from tqdm import tqdm from tqdm import tqdm
from pathlib import Path from pathlib import Path
from .help_content import AllTalkHelpContent
this_dir = Path(__file__).parent.resolve() # Sets up self.this_dir as a variable for the folder THIS script is running in. this_dir = Path(__file__).parent.resolve() # Sets up self.this_dir as a variable for the folder THIS script is running in.
main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up self.main_dir as a variable for the folder AllTalk is running in main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up self.main_dir as a variable for the folder AllTalk is running in
@@ -15,11 +16,9 @@ main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up sel
# You need to modify this function to use the appropriate method for your engine to retrieve the voice list. # You need to modify this function to use the appropriate method for your engine to retrieve the voice list.
# #
# The current implementation lists all the WAV files in a "voices" directory, which may not be suitable for your engine. # The current implementation lists all the WAV files in a "voices" directory, which may not be suitable for your engine.
# You should find/replace the `xxxx_voices_file_list` function name to match your engine name. For example, if your engine # You should replace the `xxxx_voices_file_list` function name to match your engine name. For example, if your engine
# is named "mytts", the function should be named `mytts_voices_file_list`. # is named "mytts", the function should be named `mytts_voices_file_list`.
# #
# You can pretty much find/replace "myttsengine" with the name of your TTS engine (about 14 entries in here)
#
# You will also neef to update the code with your own implementation that retrieves the voice list according to your # You will also neef to update the code with your own implementation that retrieves the voice list according to your
# engine's specific requirements. Typically this is the same code as will be in your model_engine.py file. # engine's specific requirements. Typically this is the same code as will be in your model_engine.py file.
# #
@@ -28,13 +27,11 @@ main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up sel
# #
# After making the necessary changes, this function should return a list of available voices that can be used # After making the necessary changes, this function should return a list of available voices that can be used
# in your TTS engine's settings page. # in your TTS engine's settings page.
def myttsengine_voices_file_list():
voices = []
models_dir = main_dir / "models" / "myttsengine"
# Basically the same way you are finding/reporting available voices in your model_engine.py file def xtts_voices_file_list():
directory = main_dir / "voices"
return voices files = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f)) and f.endswith(".wav")]
return files
###################################################### ######################################################
# REQUIRED CHANGE # # REQUIRED CHANGE #
@@ -50,10 +47,12 @@ def myttsengine_voices_file_list():
# dictionaries with the values provided as arguments, and save the updated settings back to the JSON file. # dictionaries with the values provided as arguments, and save the updated settings back to the JSON file.
# #
# You do not need to modify the function's logic or any other part of the code. # You do not need to modify the function's logic or any other part of the code.
def myttsengine_model_update_settings(def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr):
def xtts_model_update_settings(def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr):
# Load the model_config_data from the JSON file # Load the model_config_data from the JSON file
with open(os.path.join(this_dir, "model_settings.json"), "r") as f: with open(os.path.join(this_dir, "model_settings.json"), "r") as f:
model_config_data = json.load(f) model_config_data = json.load(f)
# Update the settings and openai_voices dictionaries with the new values # Update the settings and openai_voices dictionaries with the new values
model_config_data["settings"]["def_character_voice"] = def_character_voice_gr model_config_data["settings"]["def_character_voice"] = def_character_voice_gr
model_config_data["settings"]["def_narrator_voice"] = def_narrator_voice_gr model_config_data["settings"]["def_narrator_voice"] = def_narrator_voice_gr
@@ -69,9 +68,11 @@ def myttsengine_model_update_settings(def_character_voice_gr, def_narrator_voice
model_config_data["settings"]["repetitionpenalty_set"] = repetitionpenalty_set_gr model_config_data["settings"]["repetitionpenalty_set"] = repetitionpenalty_set_gr
model_config_data["settings"]["pitch_set"] = pitch_set_gr model_config_data["settings"]["pitch_set"] = pitch_set_gr
model_config_data["settings"]["generationspeed_set"] = generationspeed_set_gr model_config_data["settings"]["generationspeed_set"] = generationspeed_set_gr
# Save the updated model_config_data to the JSON file # Save the updated model_config_data to the JSON file
with open(os.path.join(this_dir, "model_settings.json"), "w") as f: with open(os.path.join(this_dir, "model_settings.json"), "w") as f:
json.dump(model_config_data, f, indent=4) json.dump(model_config_data, f, indent=4)
return "Settings updated successfully!" return "Settings updated successfully!"
####################################################### #######################################################
@@ -94,10 +95,11 @@ def myttsengine_model_update_settings(def_character_voice_gr, def_narrator_voice
# #
# After making these changes, this function will create and return the Gradio interface for your TTS engine's # After making these changes, this function will create and return the Gradio interface for your TTS engine's
# settings page, allowing users to configure various options and voice selections. # settings page, allowing users to configure various options and voice selections.
def myttsengine_model_alltalk_settings(model_config_data):
def xtts_model_alltalk_settings(model_config_data):
features_list = model_config_data['model_capabilties'] features_list = model_config_data['model_capabilties']
voice_list = myttsengine_voices_file_list() voice_list = xtts_voices_file_list()
with gr.Blocks(title="myttsengine TTS") as app: with gr.Blocks(title="Xtts TTS", analytics_enabled=False) as app:
with gr.Tab("Default Settings"): with gr.Tab("Default Settings"):
with gr.Row(): with gr.Row():
lowvram_enabled_gr = gr.Radio(choices={"Enabled": "true", "Disabled": "false"}, label="Low VRAM" if model_config_data["model_capabilties"]["lowvram_capable"] else "Low VRAM N/A", value="Enabled" if model_config_data["settings"]["lowvram_enabled"] else "Disabled", interactive=model_config_data["model_capabilties"]["lowvram_capable"]) lowvram_enabled_gr = gr.Radio(choices={"Enabled": "true", "Disabled": "false"}, label="Low VRAM" if model_config_data["model_capabilties"]["lowvram_capable"] else "Low VRAM N/A", value="Enabled" if model_config_data["settings"]["lowvram_enabled"] else "Disabled", interactive=model_config_data["model_capabilties"]["lowvram_capable"])
@@ -126,11 +128,17 @@ def myttsengine_model_alltalk_settings(model_config_data):
def_narrator_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_narrator_voice"], label="Narrator Voice", choices=voice_list, allow_custom_value=True) def_narrator_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_narrator_voice"], label="Narrator Voice", choices=voice_list, allow_custom_value=True)
with gr.Group(): with gr.Group():
with gr.Row(): with gr.Row():
details_text = gr.Textbox(label="Details", show_label=False, lines=5, interactive=False, value="In this section, you can set the default settings for this TTS engine. Settings that are not supported by the current engine will be greyed out and cannot be selected. Default voices specified here will be used when no specific voice is provided in the TTS generation request. If a voice is specified in the request, it will override these default settings. When using the OpenAI API compatable API with this TTS engine, the voice mappings will be applied. As the OpenAI API has a limited set of 6 voices, these mappings ensure compatibility by mapping the OpenAI voices to the available voices in this TTS engine.") details_text = gr.Textbox(label="Details", show_label=False, lines=5, interactive=False, value="Configure default settings and voice mappings for the selected TTS engine. Unavailable options are grayed out based on engine capabilities. See the Help section below for detailed information about each setting.")
with gr.Row(): with gr.Row():
submit_button = gr.Button("Update Settings") submit_button = gr.Button("Update Settings")
output_message = gr.Textbox(label="Output Message", interactive=False, show_label=False) output_message = gr.Textbox(label="Output Message", interactive=False, show_label=False)
submit_button.click(myttsengine_model_update_settings, inputs=[def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr], outputs=output_message) with gr.Accordion("HELP - 🔊 Understanding TTS Engine Default Settings Page", open=False):
with gr.Row():
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS, elem_classes="custom-markdown")
with gr.Row():
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS2, elem_classes="custom-markdown")
submit_button.click(xtts_model_update_settings, inputs=[def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr], outputs=output_message)
########################################################################################### ###########################################################################################
# Do not change this section apart from "TTS Engine Name" value to match your engine name # # Do not change this section apart from "TTS Engine Name" value to match your engine name #
@@ -157,45 +165,20 @@ def myttsengine_model_alltalk_settings(model_config_data):
with gr.Row(): with gr.Row():
gr.Textbox(label="Multi Voice Capable Models", value='Yes' if features_list['multivoice_capable'] else 'No', interactive=False) gr.Textbox(label="Multi Voice Capable Models", value='Yes' if features_list['multivoice_capable'] else 'No', interactive=False)
gr.Textbox(label="Default Audio output format", value=model_config_data['model_capabilties']['audio_format'], interactive=False) gr.Textbox(label="Default Audio output format", value=model_config_data['model_capabilties']['audio_format'], interactive=False)
gr.Textbox(label="TTS Engine Name", value="myttsengine", interactive=False) gr.Textbox(label="TTS Engine Name", value="XTTS", interactive=False)
with gr.Row(): with gr.Row():
gr.Textbox(label="Windows Support", value='Yes' if features_list['windows_capable'] else 'No', interactive=False) gr.Textbox(label="Windows Support", value='Yes' if features_list['windows_capable'] else 'No', interactive=False)
gr.Textbox(label="Linux Support", value='Yes' if features_list['linux_capable'] else 'No', interactive=False) gr.Textbox(label="Linux Support", value='Yes' if features_list['linux_capable'] else 'No', interactive=False)
gr.Textbox(label="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False) gr.Textbox(label="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False)
with gr.Row(): with gr.Row():
gr.Markdown(""" with gr.Accordion("HELP - 🔊 Understanding TTS Engine Capabilities", open=False):
#### 🟧 DeepSpeed Capable with gr.Row():
DeepSpeed is a deep learning optimization library that can significantly speed up model training and inference. If a model is DeepSpeed capable, it means it can utilize DeepSpeed to accelerate the generation of text-to-speech output. This requires the model to be loaded into CUDA/VRAM on an Nvidia GPU and the model's inference method to support DeepSpeed. gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION, elem_classes="custom-markdown")
#### 🟧 Pitch Capable with gr.Row():
Pitch refers to the highness or lowness of a sound. If a model is pitch capable, it can adjust the pitch of the generated speech, allowing for more expressive and varied output. gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION1, elem_classes="custom-markdown")
#### 🟧 Generation Speed Capable gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION2, elem_classes="custom-markdown")
Generation speed refers to the rate at which the model can generate text-to-speech output. If a model is generation speed capable, it means the speed of the generated speech can be adjusted, making it faster or slower depending on the desired output.
#### 🟧 Repetition Penalty Capable
Repetition penalty is a technique used to discourage the model from repeating the same words or phrases multiple times in the same sounding way. If a model is repetition penalty capable, it can apply this penalty during generation to improve the diversity and naturalness of the output.
#### 🟧 Multi-Languages Capable
Multi-language capable models can generate speech in multiple languages. This means that the model has been trained on data from different languages and can switch between them during generation. Some models are language-specific.
#### 🟧 Multi-Voice Capable
Multi-voice capable models generate speech in multiple voices or speaking styles. This means that the model has been trained on data from different speakers and can mimic their voices during generation, or is a voice cloning model that can generate speech based on the input sample.
""")
gr.Markdown("""
#### 🟧 Streaming Capable
Streaming refers to the ability to generate speech output in real-time, without the need to generate the entire output before playback. If a model is streaming capable, it can generate speech on-the-fly, allowing for faster response times and more interactive applications.
#### 🟧 Low VRAM Capable
VRAM (Video Random Access Memory) is a type of memory used by GPUs to store and process data. If a model is low VRAM capable, it can efficiently utilize the available VRAM by moving data between CPU and GPU memory as needed, allowing for generation even on systems with limited VRAM where it may be competing with an LLM model for VRAM.
#### 🟧 Temperature Capable
Temperature is a hyperparameter that controls the randomness of the generated output. If a model is temperature capable, the temperature can be adjusted to make the output more or less random, affecting the creativity and variability of the generated speech.
#### 🟧 Multi-Model Capable Engine
If an engine is multi-model capable, it means that it can support and utilize multiple models for text-to-speech generation. This allows for greater flexibility and the ability to switch between different models depending on the desired output. Different models may be capable of different languages, specific languages, voices, etc.
#### 🟧 Default Audio Output Format
Specifies the file format in which the generated speech will be saved. Common audio formats include WAV, MP3, FLAC, Opus, AAC, and PCM. If you want different outputs, you can set the transcode function to change the output audio, though transcoding will add a little time to the generation and is not available for streaming generation.
#### 🟧 Windows/Linux/Mac Support
These indicators show whether the model and engine are compatible with Windows, Linux, or macOS. However, additional setup or requirements may be necessary to ensure full functionality on your operating system. Please note that full platform support has not been extensively tested.
""")
#######################################################################################################################################################################################################
# REQUIRED CHANGE #
# You will need to build a custom method to identify if your models are installed and download them. Store your models list in the available_models.json file, alongside your model_settings.json etc #
#######################################################################################################################################################################################################
with gr.Tab("Models/Voices Download"): with gr.Tab("Models/Voices Download"):
with gr.Row(): with gr.Row():
# Load the available models from the JSON file # Load the available models from the JSON file
@@ -207,62 +190,67 @@ def myttsengine_model_alltalk_settings(model_config_data):
model_dropdown = gr.Dropdown(choices=sorted(model_names), label="Select Model", value=model_names[0]) model_dropdown = gr.Dropdown(choices=sorted(model_names), label="Select Model", value=model_names[0])
download_button = gr.Button("Download Model/Missing Files") download_button = gr.Button("Download Model/Missing Files")
def download_model(model_name, force_download=False): with gr.Row():
download_status = gr.Textbox(label="Download Status")
def download_model(model_name):
# Find the selected model in the available models # Find the selected model in the available models
selected_model = next(model for model in available_models["models"] if model["model_name"] == model_name) selected_model = next(model for model in available_models["models"] if model["model_name"] == model_name)
# Get the folder path and files to download # Get the folder path and files to download
folder_path = os.path.join(main_dir, "models", "myttsengine") folder_path = os.path.join(main_dir, "models", "xtts", selected_model["folder_path"])
files_to_download = selected_model["files_to_download"] files_to_download = selected_model["files_to_download"]
# Check if all files are already downloaded # Check if all files are already downloaded
all_files_exists = all(os.path.exists(os.path.join(folder_path, os.path.basename(url.split('?')[0]))) for url in files_to_download) all_files_exists = all(os.path.exists(os.path.join(folder_path, file)) for file in files_to_download)
if all_files_exists and not force_download:
if all_files_exists:
return "All files are already downloaded. No need to download again." return "All files are already downloaded. No need to download again."
else: else:
# Create the folder if it doesn't exist # Create the folder if it doesn't exist
os.makedirs(folder_path, exist_ok=True) os.makedirs(folder_path, exist_ok=True)
# Download the missing files # Download the missing files
for url in files_to_download: for file, url in files_to_download.items():
file_name = os.path.basename(url.split('?')[0]) file_path = os.path.join(folder_path, file)
file_path = os.path.join(folder_path, file_name) if not os.path.exists(file_path):
if not os.path.exists(file_path) or force_download: print(f"Downloading {file}...")
print(f"Downloading {file_name}...")
response = requests.get(url, stream=True) response = requests.get(url, stream=True)
total_size_in_bytes = int(response.headers.get("content-length", 0)) total_size_in_bytes = int(response.headers.get("content-length", 0))
block_size = 1024 # 1 Kibibyte block_size = 1024 # 1 Kibibyte
progress_bar = tqdm(total=total_size_in_bytes, unit="iB", unit_scale=True) progress_bar = tqdm(total=total_size_in_bytes, unit="iB", unit_scale=True)
with open(file_path, "wb") as file: with open(file_path, "wb") as file:
for data in response.iter_content(block_size): for data in response.iter_content(block_size):
progress_bar.update(len(data)) progress_bar.update(len(data))
file.write(data) file.write(data)
progress_bar.close()
return "Model downloaded successfully!"
with gr.Row(): progress_bar.close()
download_status = gr.Textbox(label="Download Status")
return "Model downloaded successfully!"
download_button.click(download_model, inputs=model_dropdown, outputs=download_status) download_button.click(download_model, inputs=model_dropdown, outputs=download_status)
def show_confirm_cancel(model_name): def show_confirm_cancel(model_name):
all_files_exists = all(os.path.exists(os.path.join(main_dir, "models", "myttsengine", os.path.basename(file.split('?')[0]))) for model in available_models["models"] if model["model_name"] == model_name for file in model["files_to_download"]) all_files_exists = all(os.path.exists(os.path.join(main_dir, "models", "xtts", model["folder_path"], file)) for model in available_models["models"] if model["model_name"] == model_name for file in model["files_to_download"])
if all_files_exists: if all_files_exists:
return [gr.update(visible=True), gr.update(visible=True), gr.update(visible=True)] return [gr.update(visible=True), gr.update(visible=True), gr.update(visible=True)]
else: else:
return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)] return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)]
def confirm_download(model_name): def confirm_download(model_name):
download_status_text = download_model(model_name, force_download=True) download_model(model_name)
return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), download_status_text] return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)]
def cancel_download():
return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), ""]
with gr.Row(): with gr.Row():
confirm_button = gr.Button("Download Anyway", visible=False) confirm_button = gr.Button("Download Anyway", visible=False)
cancel_button = gr.Button("Cancel", visible=False) cancel_button = gr.Button("Cancel", visible=False)
download_button.click(show_confirm_cancel, inputs=model_dropdown, outputs=[confirm_button, download_button, cancel_button]) download_button.click(show_confirm_cancel, model_dropdown, [confirm_button, download_button, cancel_button])
confirm_button.click(confirm_download, inputs=model_dropdown, outputs=[confirm_button, download_button, cancel_button, download_status]) confirm_button.click(confirm_download, model_dropdown, [confirm_button, download_button, cancel_button])
cancel_button.click(cancel_download, inputs=None, outputs=[confirm_button, download_button, cancel_button, download_status]) cancel_button.click(lambda: [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)], None, [confirm_button, download_button, cancel_button])
################################################################################################### ###################################################################################################
# REQUIRED CHANGE # # REQUIRED CHANGE #
@@ -271,14 +259,10 @@ def myttsengine_model_alltalk_settings(model_config_data):
################################################################################################### ###################################################################################################
with gr.Tab("Engine Help"): with gr.Tab("Engine Help"):
with gr.Row(): with gr.Row():
using_voice_samples = """ gr.Markdown(AllTalkHelpContent.HELP_PAGE, elem_classes="custom-markdown")
with gr.Row():
gr.Markdown(AllTalkHelpContent.HELP_PAGE1, elem_classes="custom-markdown")
IF YOU WANT TO ADD HELP INSTRUCTIONS FOR THE MODEL, ADD THEM IN HERE USING MARKDOWN gr.Markdown(AllTalkHelpContent.HELP_PAGE2, elem_classes="custom-markdown")
"""
gr.Markdown(using_voice_samples)
return app return app
@@ -300,9 +284,7 @@ def myttsengine_model_alltalk_settings(model_config_data):
# `mytts_model_alltalk_settings(model_config_data)` # `mytts_model_alltalk_settings(model_config_data)`
# #
# After making these changes, this function will create and return the Gradio app for your TTS engine's settings page. # After making these changes, this function will create and return the Gradio app for your TTS engine's settings page.
def myttsengine_at_gradio_settings_page(model_config_data):
app = myttsengine_model_alltalk_settings(model_config_data) def xtts_at_gradio_settings_page(model_config_data):
return app app = xtts_model_alltalk_settings(model_config_data)
def myttsengine_at_gradio_settings_page(model_config_data):
app = myttsengine_model_alltalk_settings(model_config_data)
return app return app
@@ -0,0 +1,887 @@
"""
Version: 1.0
Last Updated: 2024
Implementation Notes:
- All core system variables must be maintained
- All functions prefixed with "DONT CHANGE" must remain unmodified
- Code additions should be placed between the marked sections in each function
- Debug messages use self.print_message() with appropriate message types
- All functions must implement self.debug_func_entry() for trace logging
Note: Text between "↑↑↑ Keep everything above this line ↑↑↑" and "↓↓↓ Keep everything below this line ↓↓↓"
markers **TYPICALLY** must remain unchanged as it contains critical system integration code.
Note: You can add new functions, just DONT remove the functions that are already there, even if they
are doing nothing as `tts_server.py` will still look for their existance and fail if they are missing.
"""
########################################
# Default imports # Do not change this #
########################################
import os
import gc
import sys
import glob
import json
import time
import inspect
import torch
import logging
from pathlib import Path
from fastapi import (HTTPException)
logging.disable(logging.WARNING)
# Confguration file management for confignew.json
try:
from .config import AlltalkConfig, AlltalkTTSEnginesConfig, AlltalkNewEnginesConfig # TGWUI import
except ImportError:
from config import AlltalkConfig, AlltalkTTSEnginesConfig, AlltalkNewEnginesConfig # Standalone import
def initialize_configs():
"""Initialize all configuration instances"""
config = AlltalkConfig.get_instance()
tts_engines_config = AlltalkTTSEnginesConfig.get_instance()
new_engines_config = AlltalkNewEnginesConfig.get_instance()
return config, tts_engines_config, new_engines_config
# Load in the central config management
config, tts_engines_config, new_engines_config = initialize_configs()
######################################################
# Get Pytorch & Python versions # Do not change this #
######################################################
pytorch_version = torch.__version__
cuda_version = torch.version.cuda
major, minor, micro = sys.version_info[:3]
python_version = f"{major}.{minor}.{micro}"
############################################
# DeepSpeed imports # POSSIBLY change this #
############################################
"""
If the new TTS engine you are importing doesnt support DeepSpeed, then
you can simply change `model_supports_deepspeed_true_or_false` to `False`
This will be much faster when starting up the engine. This is seperate
from what is stored in your `model_settings.json` file.
"""
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ↓↓↓ MODIFY THIS LINE ↓↓↓
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
model_supports_deepspeed_true_or_false = False
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↑↑↑ MODIFY THIS LINE ↑↑↑
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
if model_supports_deepspeed_true_or_false:
try:
import deepspeed
deepspeed_available = True
except ImportError:
deepspeed_available = False
pass
#######################################################
# TTS Engine-Specific Imports and Setup # Change this #
#######################################################
"""
This section is for TTS engine specific imports and global variable setup.
Guidelines:
1. Import all required modules for your TTS engine
2. Handle import errors with appropriate error messages
3. Set up any global variables or configurations needed by your engine
4. Use try/except blocks to gracefully handle missing dependencies
5. Ensure all error messages follow the AllTalk format for print messages.
At this stage the `def print_messages` is not available, so please use
standard `print("[AllTalk ENG] some message here")` messages.
Example structure:
try:
# Import your TTS engine's required modules
from your_tts_engine import required_modules
except ModuleNotFoundError:
# Handle missing dependencies with helpful error messages
print("Missing required modules. Please install...")
raise
"""
try:
import torchaudio
except ModuleNotFoundError:
brand = "[AllTalk ENG]"
print(f"{brand} \033[91mError\033[0m Could not find the XXX TTS modules.")
print(f"{brand} \033[91mError\033[0m Please re-install the requirements.")
raise
#########################################################
# Class setup # Change the relevant functions as needed #
#########################################################
class tts_class:
"""
TTS Engine Implementation Class
This class provides the interface between `tts_server.py` and whatever TTS engine you install.
It handles model loading, voice management, and TTS generation in both streaming
and non-streaming modes. Streaming will only be supported if the underlying TTS engine
actually supports streaming.
Key Responsibilities:
1. Model Management:
- Loading/unloading models
- Managing model state between CPU and GPU
- Handling DeepSpeed integration
2. Voice Management:
- Managing voice samples or model files
3. TTS Generation:
- Converting text to speech
- Supporting streaming output (If the engine supports it)
- Managing generation parameters
4. System Integration:
- Implementing standard AllTalk interfaces
- Managing engine state and configuration
- Handling resource allocation
"""
###############################################
# Central print function # Do not change this #
###############################################
def print_message(self, message, message_type="standard", component="ENG"):
"""
Centralized print function for messages. Use this for print output to console.
As this is the model Engine, all `component` printouts are set to ENG as default.
Args:
message (str): The message to print
message_type (str): Type of message (standard/warning/error/debug_*/debug)
component (str): Component identifier (TTS/ENG/GEN/API/etc.)
Example Use:
self.print_message("This is a standard print out mesage to a user)
self.print_message("This is a debug_tts message, message_type="debug_tts")
self.print_message("This is an error message to a user, message_type="error")
self.print_message("This is an warning message to a user, message_type="warning")
Debug Types:
debug_func: Tracks function entry
debug_tts: Enable TTS process debugging
debug_tts_variables: Enable variable state debugging
WARNING: This is a core system function. Do not modify its implementation
as it provides standardized version reporting across all engines.
"""
# ANSI color codes
BLUE = "\033[94m"
MAGENTA = "\033[95m"
YELLOW = "\033[93m"
RED = "\033[91m"
GREEN = "\033[92m"
RESET = "\033[0m"
prefix = f"[{config.branding}{component}] "
if message_type.startswith("debug_"):
debug_flag = getattr(config.debugging, message_type, False)
if not debug_flag:
return
if message_type == "debug_func" and "Function entry:" in message:
message_parts = message.split("Function entry:", 1)
print(f"{prefix}{BLUE}Debug{RESET} {YELLOW}{message_type}{RESET} Function entry:{GREEN}{message_parts[1]}{RESET} in model_engine")
else:
print(f"{prefix}{BLUE}Debug{RESET} {YELLOW}{message_type}{RESET} {message}")
elif message_type == "debug":
print(f"{prefix}{BLUE}Debug{RESET} {message}")
elif message_type == "warning":
print(f"{prefix}{YELLOW}Warning{RESET} {message}")
elif message_type == "error":
print(f"{prefix}{RED}Error{RESET} {message}")
else:
print(f"{prefix}{message}")
def debug_func_entry(self):
"""Log function entry if debug_func is enabled."""
if config.debugging.debug_func:
current_func = inspect.currentframe().f_back.f_code.co_name
self.print_message(f"Function entry: {current_func}", "debug_func")
#############################################
# Script initalisation # Do not change this #
#############################################
def __init__(self):
"""
Initialize the TTS engine instance.
WARNING: This class requires specific variables to interface with AllTalk's main system (tts_server.py).
Do not remove or rename any of the predefined variables as they are required for proper system integration.
Required System Interface Variables:
1. Core System Variables (DO NOT MODIFY):
Base Configuration:
- self.this_dir: Engine directory path (where this script is located)
- self.main_dir: AllTalk root directory
- self.device: Processing device ("cuda" or "cpu")
- self.cuda_is_available: Whether GPU/CUDA is available
State Tracking:
- self.tts_generating_lock: Prevents concurrent generation requests
- self.tts_stop_generation: Signals generation stop request
- self.tts_narrator_generatingtts: Tracks narrator mode for optimization
- self.model: Active TTS model instance
- self.is_tts_model_loaded: Whether a model is currently loaded
- self.current_model_loaded: Name of currently loaded model
- self.available_models: List of models found by scan_models_folder
- self.setup_has_run: Tracks if setup() has completed
2. Engine Configuration Variables (DO NOT MODIFY):
- self.engines_available: List of all available TTS engines
- self.engine_loaded: Currently selected TTS engine
- self.selected_model: Currently selected model name
3. Model Settings (SET VIA model_settings.json):
Capability Flags:
- self.audio_format: Output audio format (wav, mp3, etc.)
- self.deepspeed_capable: DeepSpeed acceleration support
- self.generationspeed_capable: Speed adjustment support
- self.languages_capable: Multi-language support
- self.lowvram_capable: Low VRAM mode support
- self.multimodel_capable: Multiple model support
- self.repetitionpenalty_capable: Repetition penalty support
- self.streaming_capable: Audio streaming support
- self.temperature_capable: Temperature adjustment support
- self.multivoice_capable: Multiple voice support
- self.pitch_capable: Pitch adjustment support
Engine Settings:
- self.def_character_voice: Default character voice
- self.def_narrator_voice: Default narrator voice
- self.deepspeed_enabled: DeepSpeed status
- self.engine_installed: Engine installation status
- self.generationspeed_set: Current speed setting
- self.lowvram_enabled: Low VRAM mode status
- self.repetitionpenalty_set: Current repetition penalty
- self.temperature_set: Current temperature setting
- self.pitch_set: Current pitch setting
OpenAI Voice Mappings:
- self.openai_alloy: Alloy voice mapping
- self.openai_echo: Echo voice mapping
- self.openai_fable: Fable voice mapping
- self.openai_nova: Nova voice mapping
- self.openai_onyx: Onyx voice mapping
- self.openai_shimmer: Shimmer voice mapping
Integration Requirements:
- All variables must be present even if unused by your engine
- Capability flags should accurately reflect engine features
- Settings should have sensible defaults even if not used
- OpenAI mappings should be set even if not supporting OpenAI compatibility
Note: Variables marked (DO NOT MODIFY) are critical system integration points.
Other variables should be configured through their respective JSON files or
you can add new central variables in the section provided down below.
"""
# DO NOT MODIFY - Sets up the base variables required for any tts engine #
self.this_dir = Path(__file__).parent.resolve()
self.main_dir = Path(__file__).parent.parent.parent.parent.resolve()
self.device = "cuda" if torch.cuda.is_available() else "cpu"
self.cuda_is_available = torch.cuda.is_available()
self.tts_generating_lock = False
self.tts_stop_generation = False
self.tts_narrator_generatingtts = False
self.model = None
self.is_tts_model_loaded = False
self.current_model_loaded = None
self.available_models = None
self.setup_has_run = False
self.engines_available = tts_engines_config.get_engine_names_available()
self.engine_loaded = tts_engines_config.engine_loaded
self.selected_model = tts_engines_config.selected_model
# DO NOT MODIFY - Load in the current TTS Engines model_settings.json file
with open(os.path.join(self.this_dir, "model_settings.json"), "r") as f:
model_settings_file = json.load(f)
# DO NOT MODIFY - Model details from model_settings.json
self.manufacturer_name = model_settings_file["model_details"]["manufacturer_name"]
self.manufacturer_website = model_settings_file["model_details"]["manufacturer_website"]
# DO NOT MODIFY - Model capabilities from model_settings.json
self.audio_format = model_settings_file["model_capabilties"]["audio_format"]
self.deepspeed_capable = model_settings_file["model_capabilties"]["deepspeed_capable"]
self.deepspeed_available = 'deepspeed' in globals()
self.generationspeed_capable = model_settings_file["model_capabilties"]["generationspeed_capable"]
self.languages_capable = model_settings_file["model_capabilties"]["languages_capable"]
self.lowvram_capable = model_settings_file["model_capabilties"]["lowvram_capable"]
self.multimodel_capable = model_settings_file["model_capabilties"]["multimodel_capable"]
self.repetitionpenalty_capable = model_settings_file["model_capabilties"]["repetitionpenalty_capable"]
self.streaming_capable = model_settings_file["model_capabilties"]["streaming_capable"]
self.temperature_capable = model_settings_file["model_capabilties"]["temperature_capable"]
self.multivoice_capable = model_settings_file["model_capabilties"]["multivoice_capable"]
self.pitch_capable = model_settings_file["model_capabilties"]["pitch_capable"]
# DO NOT MODIFY - Engine settings from model_settings.json
self.def_character_voice = model_settings_file["settings"]["def_character_voice"]
self.def_narrator_voice = model_settings_file["settings"]["def_narrator_voice"]
self.deepspeed_enabled = model_settings_file["settings"]["deepspeed_enabled"]
self.engine_installed = model_settings_file["settings"]["engine_installed"]
self.generationspeed_set = model_settings_file["settings"]["generationspeed_set"]
self.lowvram_enabled = model_settings_file["settings"]["lowvram_enabled"]
self.lowvram_enabled = False if not torch.cuda.is_available() else self.lowvram_enabled
self.repetitionpenalty_set = model_settings_file["settings"]["repetitionpenalty_set"]
self.temperature_set = model_settings_file["settings"]["temperature_set"]
self.pitch_set = model_settings_file["settings"]["pitch_set"]
# DO NOT MODIFY - OpenAI voice mappings from model_settings.json
self.openai_alloy = model_settings_file["openai_voices"]["alloy"]
self.openai_echo = model_settings_file["openai_voices"]["echo"]
self.openai_fable = model_settings_file["openai_voices"]["fable"]
self.openai_nova = model_settings_file["openai_voices"]["nova"]
self.openai_onyx = model_settings_file["openai_voices"]["onyx"]
self.openai_shimmer = model_settings_file["openai_voices"]["shimmer"]
"""
Below is the name of the folder that will be created-used under `/models/{folder}`
And is further used by the base functions of this script. Change the name stored in
`self.model_folder_name` to the model folder name you will be using. Ensure to use
the correct CAPS/Non-CAPS spelling as Linux OS is CAPS specific on folder names.
"""
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ↓↓↓ MODIFY THIS LINE ↓↓↓
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
self.model_folder_name = "MYNEWTTSENGINE"
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↑↑↑ MODIFY THIS LINE ↑↑↑
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ↓↓↓ Add your own central `self.myvariable` variables in here if needed for your engine ↓↓↓
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
"""
If you need globally accessable variables of your own for your own purposes, you can put
them in here as self.myvariable = "whatever".
"""
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↑↑↑ Add your own central `self.myvariable` variables in here if needed for your engine ↑↑↑
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# DO NOT MODIFY - log the function call to this function
self.debug_func_entry()
#####################################################
# Printout engine loading bits # Do not change this #
#####################################################
def printout_versions(self):
"""
Print Python, DeepSpeed, Pytorch and CUDA version on start-up.
WARNING: This is a core system function. Do not modify its implementation
as it provides standardized version reporting across all engines.
"""
self.debug_func_entry()
if not model_supports_deepspeed_true_or_false:
self.print_message(f"\033[92mDeepSpeed version :\033[93m Not supported on {self.model_folder_name}\033[0m", message_type="standard")
else:
if deepspeed_available:
self.print_message("\033[92mDeepSpeed version :\033[93m " + str(deepspeed.__version__) + "\033[0m", message_type="standard")
else:
self.print_message("\033[92mDeepSpeed version :\033[93m Not available\033[0m", message_type="standard")
self.print_message(f"\033[92mPython Version :\033[93m {python_version}\033[0m", message_type="standard")
self.print_message(f"\033[92mPyTorch Version :\033[93m {pytorch_version}\033[0m", message_type="standard")
if cuda_version is None:
self.print_message("\033[92mCUDA Version :\033[91m Not available\033[0m", message_type="standard")
else:
self.print_message(f"\033[92mCUDA Version :\033[93m {cuda_version}\033[0m", message_type="standard")
self.print_message("", message_type="standard")
return
################################################################
# Handle low VRAM change between CUDA/CPU # Do not change this #
################################################################
async def handle_lowvram_change(self):
"""
Manage model location between CPU and GPU memory for low VRAM operation.
This function handles the movement of models between CPU and GPU memory
to support systems with limited VRAM. It's called automatically during
generation when low VRAM mode is enabled.
Operation:
1. Checks CUDA availability
2. Moves model between devices based on current location:
- GPU (cuda) -> CPU
- CPU -> GPU (cuda)
3. Manages CUDA cache to optimize memory usage
States Affected:
- self.device: Updated to reflect current processing device
- self.model.device: Model's current memory location
Requirements:
- CUDA must be available for GPU operations
- Model must be loaded (self.model is not None)
- lowvram_enabled must be `True` in the `model_settings.json` file
Note: This function is only called when self.lowvram_enabled is True
meaning the engine does or doesnt support the call, hence if its not
True, then this function would never be called anyway, so doesnt need
changing.
"""
self.debug_func_entry()
# Initial validation
if not self.is_tts_model_loaded:
self.print_message("No model is currently loaded. Please select a model to load.", message_type="error")
raise HTTPException(status_code=400, detail="No model is currently loaded. Please select a model to load.")
if torch.cuda.is_available():
if self.device == "cuda":
self.print_message("Moving model to CPU", message_type="debug_tts")
self.device = "cpu"
self.model.to(self.device)
torch.cuda.empty_cache()
gc.collect()
else:
self.device = "cuda"
self.print_message("Moving model to GPU", message_type="debug_tts")
self.model.to(self.device)
gc.collect()
################################################
# Handle DeepSpeed change # Do not change this #
################################################
async def handle_deepspeed_change(self, value):
"""
Handle enabling/disabling of DeepSpeed acceleration.
This function manages the process of reloading the model with or without
DeepSpeed acceleration. DeepSpeed can significantly improve performance on
supported hardware.
Args:
value (bool): True to enable DeepSpeed, False to disable
Operation:
1. Unloads current model
2. Updates DeepSpeed settings
3. Reloads model with new configuration
States Affected:
- self.deepspeed_enabled: Updated to reflect new state
- self.model: Reloaded with new configuration
Returns:
bool: The new DeepSpeed state (same as input value)
Note: DeepSpeed must be installed and available in the system for
this functionality to work. `deepspeed_capable` must be set `True`
in the `model_settings.json` file
"""
self.debug_func_entry()
# Initial validation
if not self.is_tts_model_loaded:
self.print_message("No model is currently loaded. Please select a model to load.", message_type="error")
raise HTTPException(status_code=400, detail="No model is currently loaded. Please select a model to load.")
if value:
self.print_message("\033[93mDeepSpeed Activating\033[0m", message_type="standard")
await self.unload_model()
self.deepspeed_enabled = True
await self.setup()
else:
self.print_message("\033[93mDeepSpeed De-Activating\033[0m", message_type="standard")
self.deepspeed_enabled = False
await self.unload_model()
await self.setup()
return value
################################################################
# Unload models from VRAM/RAM if possible # Do not change this #
################################################################
async def unload_model(self):
"""
Unload the current model and free associated resources.
This function handles the cleanup of model resources, including:
1. Setting model loaded flag to False
2. Deleting the model instance
3. Clearing CUDA cache if available
Operation:
1. Updates model loading status
2. Logs unloading process if a model is loaded
3. Removes model from memory
4. Cleans up CUDA cache if using GPU
States Affected:
- self.is_tts_model_loaded: Set to False
- self.model: Set to None after unloading
"""
self.debug_func_entry()
self.is_tts_model_loaded = False
if not self.current_model_loaded == None:
self.print_message("Unloading model", message_type="debug_tts")
if hasattr(self, 'model'):
del self.model
if torch.cuda.is_available():
torch.cuda.empty_cache()
return None
############################################################
# On start-up, perform these actions # Change as necessary #
############################################################
async def setup(self):
"""
Initialize the TTS engine and load initial model configuration.
This function is called during system startup and handles:
1. Version information display
2. Model scanning and availability check
3. Initial model loading if specified
The setup sequence ensures:
- Proper version reporting
- Model availability verification
- Graceful handling of missing models
- Correct initial model loading state
States Set:
- self.available_models: Updated with found models
- self.current_model_loaded: Set to loaded model name or None
- self.setup_has_run: Set True when complete
Returns:
None
Note: Custom initialization code should be placed between the marked sections.
"""
self.debug_func_entry()
self.print_message("Initializing TTS engine", message_type="debug_tts")
self.printout_versions()
self.available_models = self.scan_models_folder()
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↑↑↑ Keep everything above this line ↑↑↑
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
if self.selected_model:
tts_model = f"{self.selected_model}"
if tts_model in self.available_models:
self.print_message(f"Loading selected model: {tts_model}", message_type="debug_tts")
await self.handle_tts_method_change(tts_model)
self.current_model_loaded = tts_model
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ↓↓↓ Keep everything below this line ↓↓↓
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
else:
self.current_model_loaded = "No Models Available"
self.print_message(f"Selected model '{self.selected_model}' not found in models folder.", message_type="error")
self.print_message(f"Please download a model or select a different model file.", message_type="error")
self.setup_has_run = True
###########################################################################
# Scan your models folder for models OR voice files # Change as necessary #
###########################################################################
def scan_models_folder(self):
"""
Scan for available TTS models in the models directory.
This function searches the models directory for valid TTS model installations.
Each model must contain all required files to be considered valid.
Required Files for Each Model:
- Whatever your TTS engine needs/supports
Operation:
1. Scans the models/{folder} directory
2. Checks each subfolder for required files
3. Registers valid models
States Affected:
- self.available_models: Updated with found models
Returns:
dict: Dictionary of available models in format:
{model_identifier: engine_type}
Note: If no valid models are found, returns {"No Models Available": "TTS Engine Name"}
"""
self.debug_func_entry()
models_folder = self.main_dir / "models" / self.model_folder_name
self.available_models = {}
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↑↑↑ Keep everything above this line ↑↑↑
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
required_files = ["config.json", "model.pth"]
model_name = "DO SOMETHING HERE"
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ↓↓↓ Keep everything below this line ↓↓↓
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
else:
self.available_models = {'No Models Available': self.model_folder_name}
self.print_message(f"Model folder '{model_name}' is missing required files", message_type="warning")
self.print_message("Required files or folder does not exist", message_type="warning")
self.print_message("Please download some models/voices for this engine", message_type="warning")
return self.available_models
################################################################
# Scan your voice folder for voice files # Change as necessary #
################################################################
def voices_file_list(self):
"""
Scan and compile a list of available voices
This function scans multiple directories to find voice models/samples in different formats:
1. Individual WAV/MP3 etc files in the main voices directory
Directory Structure:
- voices/: Individual audio files
Returns:
list: Available voices with appropriate prefixes:
- Standard WAV: filename.wav
Note: Returns ["No Voices Found"] if no valid voices are detected
"""
self.debug_func_entry()
try:
voices = [] # An empy variable for the list of voices to be put into.
directory = self.main_dir / "voices" # Base directory that voices are stored in.
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↑↑↑ Keep everything above this line ↑↑↑
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ↓↓↓ Keep everything below this line ↓↓↓
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# Sort voices by type alphabetically
voices.sort(key=lambda x: (x.startswith("voiceset:"), x.startswith("latent:"), x))
if not voices:
return ["No Voices Found"]
return voices
except Exception as e:
self.print_message(f"Error scanning for voices: {str(e)}", message_type="error")
return ["No Voices Found"]
############################################
# Load in your model # Change as necessary #
############################################
async def load_model(self, model_name):
"""
Load a model using the your TTS API interface.
Args:
model_name (str): Name of the model to load
Operation:
1. Validates model availability
2. Constructs model and config paths
3. Initializes model using TTS API
4. Moves model to appropriate device (CPU/GPU)
States Affected:
- self.model: Updated with loaded model
- self.is_tts_model_loaded: Set to True on success
Returns:
The loaded model instance
Raises:
HTTPException: If no models are available to load
"""
self.debug_func_entry()
if "No Models Available" in self.available_models:
self.print_message("No models for this TTS engine were found to load", message_type="error")
return
model_path = self.main_dir / "models" / self.model_folder_name / model_name # You may need to edit/modfy depending on how your TTS engine works with models
self.print_message(f"Loading model from: {model_path}", message_type="debug_tts")
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↑↑↑ Keep everything above this line ↑↑↑
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
self.model = TTS(
model_path=model_path,
config_path=model_path / "config.json",
).to(self.device)
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ↓↓↓ Keep everything below this line ↓↓↓
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
self.is_tts_model_loaded = True
return self.model
async def handle_tts_method_change(self, tts_method):
"""
Handle switching between different TTS models/voices.
This function manages actual model loading process.
Args:
tts_method (str): Format "type - modelname" where type is either
Operation:
1. Validates model availability
2. Unloads current model if any
3. Parses method string to determine loader type
4. Calls appropriate model loader
5. Updates current model tracking
States Affected:
- self.current_model_loaded: Updated to new model identifier
- self.model: Updated with newly loaded model
Returns:
bool: True if model loaded successfully, False otherwise
Timing:
Records and reports model loading time
"""
self.debug_func_entry()
# Track loading time
generate_start_time = time.time()
# Validate model availability
if "No Models Available" in self.available_models:
self.print_message("No models for this TTS engine were found to load", message_type="error")
return False
# Unload current model
await self.unload_model()
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↑↑↑ Keep everything above this line ↑↑↑
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ↓↓↓ Keep everything below this line ↓↓↓
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
else:
self.print_message(f"Unknown model type in: {tts_method}", message_type="error")
self.current_model_loaded = None
return False
# Report loading time
generate_end_time = time.time()
generate_elapsed_time = generate_end_time - generate_start_time
self.print_message(f"\033[94mModel Loadtime: \033[93m{generate_elapsed_time:.2f}\033[94m seconds\033[0m")
return True
async def generate_tts(self, text, voice, language, temperature, repetition_penalty, speed, pitch, output_file, streaming):
"""
Generate speech from text using the TTS model.
This core function handles all TTS generation, supporting both streaming and
non-streaming output, multiple voice input types,
and various generation parameters.
Args:
text (str): Text to convert to speech
voice (str): Voice identifier (WAV/MP3 file, voice set, or latent)
language (str): Target language code
temperature (float): Generation temperature (0.0-1.0)
repetition_penalty (float): Penalty for repetitive generation
speed (float): Speech speed multiplier
pitch (float): Voice pitch adjustment
output_file (str): Path for output audio file
streaming (bool): Whether to stream audio chunks
Returns:
For streaming=True: Generator yielding audio chunks
For streaming=False: None (saves to output_file)
States Used:
- self.model: Active TTS model
- self.device: Current processing device
- self.lowvram_enabled: Low VRAM mode status
- self.current_model_loaded: Current model type
"""
self.debug_func_entry()
# Initial validation
if not self.is_tts_model_loaded:
self.print_message("No TTS model loaded", message_type="error")
raise HTTPException(status_code=400, detail="You currently have no TTS model loaded.")
# Lock generation and track start time
self.tts_generating_lock = True
self.print_message("Starting TTS generation process", message_type="debug_tts")
self.print_message(f"Generation parameters: temperature={temperature}, speed={speed}, streaming={streaming}",
message_type="debug_tts_variables")
# Handle low VRAM mode if needed
if self.lowvram_enabled and self.device == "cpu":
self.print_message("Low VRAM mode: Moving model to GPU", message_type="debug_tts")
await self.handle_lowvram_change()
generate_start_time = time.time()
try:
# Voice input processing
self.print_message(f"Processing voice input: {voice}", message_type="debug_tts")
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↑↑↑ Keep everything above this line ↑↑↑
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# BUILD ANY SETTINGS NEEED FOR TTS HERE
# DO ANY LOGIC TESTS E.G. CHECK IF THE AUDIO FILE/MODEL EXISTS
# ALWAYS CHECK IF STREAMING FIRST THEN DO OTHER METHODS
if streaming:
# PUT YOUR TTS ENGINE STREAMING GENERATION LOGIC IN HERE
yield
else:
self.print_message("Starting non-streaming generation", message_type="debug_tts")
# PUT YOUR TTS ENGINE STANDARD GENERATION LOGIC IN HERE
self.print_message(f"Saved audio to: {output_file}", message_type="debug_tts")
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ↓↓↓ Keep everything below this line ↓↓↓
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
finally:
# Generation complete
generate_end_time = time.time()
generate_elapsed_time = generate_end_time - generate_start_time
# Standard output message (not debug)
self.print_message(
f"\033[94mTTS Generate: \033[93m{generate_elapsed_time:.2f} seconds. \033[94mLowVRAM: \033[33m{self.lowvram_enabled} \033[94mDeepSpeed: \033[33m{self.deepspeed_enabled}\033[0m",
message_type="standard"
)
# Handle low VRAM cleanup
if self.lowvram_enabled and self.device == "cuda" and not self.tts_narrator_generatingtts:
self.print_message("Low VRAM mode: Moving model back to CPU", message_type="debug_tts")
await self.handle_lowvram_change()
self.tts_generating_lock = False
+378
View File
@@ -0,0 +1,378 @@
# help_content.py
# pylint: disable=no-member
class AllTalkHelpContent:
"""CSS and help content for help_content.py"""
custom_css = """
/* Add this to your existing CSS */
.gradio-container .prose {
max-width: none !important;
padding: 0.5rem !important; /* Reduced padding */
margin: 0 !important;
}
.custom-markdown div {
border: none !important; /* Remove the inner border */
margin-top: 0 !important; /* Remove top margin */
margin-bottom: 0 !important; /* Remove bottom margin */
padding-top: 0 !important; /* Remove top padding */
padding-bottom: 0 !important; /* Remove bottom padding */
}
/* Update the existing custom-markdown class */
.custom-markdown {
font-size: 15px !important;
line-height: 1.6 !important;
color: var(--body-text-color) !important;
background-color: var(--background-fill-primary) !important;
border: 1px solid var(--border-color-primary) !important;
border-radius: 8px !important;
padding: 0.5rem !important;
margin: 0 !important; /* Changed from 1rem 0 to 0 */
max-width: 100% !important;
box-sizing: border-box !important;
/* Default text color for all content (grey) */
color: rgba(156, 163, 175, 1) !important; /* Adjust this grey value to match your interface */
}
/* Make headings white */
.custom-markdown h1,
.custom-markdown h2,
.custom-markdown h3,
.custom-markdown h4,
.custom-markdown h5,
.custom-markdown h6 {
color: var(--heading-text-color, var(--body-text-color)) !important;
font-weight: 600 !important;
}
/* Keep all other elements in the grey color */
.custom-markdown p,
.custom-markdown li,
.custom-markdown ul,
.custom-markdown ol {
color: rgba(156, 163, 175, 1) !important; /* Same grey as the base text */
}
/* Additional targeting for any wrapping elements */
.gradio-container .prose > * {
margin: 0 !important;
padding: 0 !important;
}
/* Update the list item spacing in your existing CSS */
.custom-markdown li {
font-size: 0.95rem !important;
margin-bottom: 0.2rem !important; /* Reduced from 0.5rem to 0.3rem */
}
/* Add specific styling for definition-style lists (like your Default, Recommendation, Tip items) */
.custom-markdown li p {
margin: 0 !important; /* Remove paragraph margins within list items */
}
/* If you need even tighter spacing for specific types of lists */
.custom-markdown li + li {
margin-top: 0.2rem !important; /* Space between consecutive list items */
}
/* Ensure nested lists maintain proper spacing */
.custom-markdown li > ul,
.custom-markdown li > ol {
margin: 0.2rem 0 0.2rem 1rem !important; /* Reduced from 0.5rem */
}
/* Consistent heading styles */
.custom-markdown h2 {
font-size: 1.2rem !important; /* Fixed size relative to root */
font-weight: 600 !important;
margin: 1.5rem 0 1rem !important;
color: var(--heading-text-color, var(--body-text-color)) !important;
border-bottom: 1px solid var(--border-color-primary) !important;
padding-bottom: 0.5rem !important;
}
/* First paragraph styling */
.custom-markdown p:first-of-type {
font-size: 0.95rem !important; /* Match base size */
font-weight: 400 !important;
margin-bottom: 1rem !important;
}
/* Regular paragraphs */
.custom-markdown p {
font-size: 0.95rem !important;
margin: 0.8rem 0 !important;
}
/* List styling */
.custom-markdown ul,
.custom-markdown ol {
margin: 0.8rem 0 !important;
padding-left: 1.5rem !important;
}
/* Code styling */
.custom-markdown code {
font-family: ui-monospace, monospace !important;
background-color: var(--background-fill-secondary) !important;
padding: 0.2rem 0.4rem !important;
border-radius: 4px !important;
font-size: 0.8rem !important; /* Slightly smaller than regular text */
color: var(--body-text-color) !important;
}
/* Add styles for bold and emphasis */
.custom-markdown strong {
font-weight: 600 !important;
color: var(--body-text-color) !important;
}
.custom-markdown em {
font-style: italic !important;
}
/* Ensure both columns take equal width */
.gradio-row > div {
flex: 1 1 50% !important;
min-width: 0 !important; /* Prevents flex items from overflowing */
}
"""
ENGINE_INFORMATION = """
## 🔊 TTS Engine Capabilities Help
This guide explains the various capabilities that **may** be available in different TTS engines and models. Each capability affects how the TTS engine processes and generates speech output.
"""
ENGINE_INFORMATION1 = """
## 🚀 Performance Features
- **DeepSpeed Capable**: Enables GPU acceleration using the DeepSpeed optimization library.
- **Requires**: NVIDIA GPU with CUDA support
- **Benefit**: Significantly faster text-to-speech generation
- **Note**: Model must specifically support DeepSpeed inference
- **Low VRAM Capable**: Optimized for systems with limited GPU memory.
- **Benefit**: Efficient memory management between CPU and GPU
- **Use Case**: Ideal when running alongside other GPU-intensive applications like LLMs
- **Note**: May trade speed for memory efficiency
- **Streaming Capable**: Enables real-time speech generation.
- **Benefit**: Immediate playback without generating entire audio first
- **Use Case**: Interactive applications and real-time responses
- **Note**: Not all output formats support streaming
## 🎵 Voice Control Features
- **Pitch Capable**: Allows adjustment of voice pitch.
- **Benefit**: Creates more expressive and varied speech output
- **Use Case**: Customizing voice characteristics
- **Note**: Adjustment range varies by model
- **Generation Speed Capable**: Controls speech rate.
- **Benefit**: Adjustable playback speed during generation
- **Use Case**: Creating faster or slower speech output
- **Note**: May affect audio quality at extreme settings
- **Temperature Capable**: Controls output randomness.
- **Benefit**: Adjustable speech variation and creativity
- **Use Case**: Balancing consistency vs. naturality
- **Note**: Higher values increase variation but may reduce quality
"""
ENGINE_INFORMATION2 = """
## 🎯 Quality Enhancement Features
- **Repetition Penalty Capable**: Prevents unnatural speech patterns.
- **Benefit**: Reduces repeated sounds and phrases
- **Use Case**: Improving natural flow of longer texts
- **Note**: Strength of penalty may be adjustable
## 🌐 Multi-Feature Support
- **Multi-Languages Capable Models**: Each model Supports multiple languages.
- **Benefit**: Generate speech in different languages
- **Note**: Quality may vary between languages
- **Tip**: Check model-specific language support
- **Multi-Voice Capable**: Supports multiple speaking voices.
- **Benefit**: Different voices or speaking styles
- **Types**: Pre-trained voices or voice cloning
- **Note**: Voice quality may vary by model
- **Multi-Model Capable Engine**: Supports multiple TTS models.
- **Benefit**: Flexibility in model selection
- **Use Case**: Switching between models for different needs
- **Note**: Each model may have different capabilities
## 📁 Technical Features
- **Default Audio Output Format**: Specifies output file format.
- **Common Formats**: WAV, MP3, FLAC, Opus, AAC, PCM
- **Note**: Transcoding to different formats adds processing time
- **Warning**: Not all formats support streaming
- **Platform Support**: Operating system compatibility.
- **Platforms**: Windows, Linux, macOS
- **Note**: Additional setup may be required
- **Warning**: Support level may vary by platform
"""
DEFAULT_SETTINGS = """
## 🎯 TTS Engine Settings Help
This guide explains the settings and configuration options available for individual Text-to-Speech engines within AllTalk.
"""
DEFAULT_SETTINGS1 = """
## 🎚️ Engine Capabilities & Controls
- **Low VRAM Mode**
- Optimizes memory usage for systems with limited GPU memory
- Efficiently manages resources by moving data between CPU and GPU
- Recommended for systems with less than 4GB VRAM or when running alongside other GPU-intensive applications
- **DeepSpeed Capability**
- Accelerates TTS generation using optimized inference
- Only available for engines and models that support DeepSpeed
- Requires NVIDIA GPU with CUDA support
- **Temperature Control**
- Adjusts the variability in speech generation
- **Range**: 0.0 to 1.0
- **Lower values** (0.1-0.5): More consistent, stable output
- **Higher values** (0.6-1.0): More variable, potentially more natural-sounding output
- **Repetition Penalty**
- Helps prevent repetitive speech patterns
- **Range**: 1.0 to 15.0
- Higher values more strongly discourage repetition
- Typically most effective between 1.0-3.0
- **Pitch Adjustment**
- Modifies the voice pitch when supported
- **Range**: -20 to +20
- Use subtle adjustments for most natural results
- **Generation Speed**
- Controls the pace of generated speech
- **Range**: 0.5 to 2.0
- 1.0 represents normal speed
"""
DEFAULT_SETTINGS2 = """
## 🗣️ Voice Configuration
### OpenAI Voice Mappings
- Only relevant when using the OpenAI-compatible API endpoint
- Maps OpenAI's six standard voices to equivalent voices in the current engine:
- `alloy`
- `echo`
- `fable`
- `nova`
- `onyx`
- `shimmer`
- Essential for maintaining compatibility with OpenAI API calls
- Each mapping can be customized to any available voice in the current engine
Information on the OpenAI Endpoint is available in the [Github Wiki](https://github.com/erew123/alltalk_tts/wiki)
### Default Voices
- **Default/Character Voice**: Used when no specific voice is specified in API calls
- **Narrator Voice**: Separate default for narrator-specific text
- These defaults are engine-specific and won't affect other TTS engines
- Can be overridden by explicitly specifying voices in API calls
## ⚙️ Important Notes
- Settings availability is determined by engine capabilities
- Grayed-out options indicate features not supported by the current engine
- Changes only affect the currently selected TTS engine
- Settings here act as defaults but can be overridden via API parameters
- All changes require clicking "Update Settings" to take effect
- Some settings require an engine reload to take effect
"""
HELP_PAGE = """
## 🎯 VITS TTS Engine Help
VITS (Conditional Variational Autoencoder with Adversarial Learning) is an end-to-end text-to-speech model that combines advanced techniques for high-quality voice synthesis.
"""
HELP_PAGE1 = """
## 🎚️ Engine Capabilities & Controls
- **Low VRAM Mode**
- Enabled for optimized memory usage
- Efficiently manages resources between CPU and GPU
- Recommended when running alongside other GPU applications
- **Multi-Model Support**
- Supports multiple model types:
- Single-speaker models
- Multi-speaker models e.g. `tts_models--en--vctk--vits`
- Multi-language models
- Models can be switched without restarting
## 🗣️ Voice System
### Model Types
- **Single-Speaker Models**
- Contains one voice
- Uses `default` as the speaker name
- Requires `config.json` and `model_file.pth`
- **Multi-Speaker Models**
- Contains multiple voices in one model
- Uses `speaker_ids.json` to define available voices
- Requires `config.json`, `model_file.pth`, and `speaker_ids.json`
- **Multi-Language Models**
- Supports multiple languages and speakers e.g. `tts_models--en--vctk--vits`
- Requires `config.json`, `model_file.pth.tar`, `speaker_ids.json`, and `language_ids.json`
- Allows language switching within the same model
### Language Support
- Wide range of languages available:
- English (VCTK dataset)
- German (Thorsten, CSS10)
- French (CSS10)
- Spanish (CSS10)
- Italian (Mai)
- And many more specialized models
"""
HELP_PAGE2 = """
## 📝 Model Management
- **Model Storage**
- Models stored in `/alltalk_tts/models/vits/`
- Each model has its own subfolder
- Required files vary by model type
- **Output Files**
- Generated audio saved to `/alltalk_tts/outputs/`
- Automatic cleanup available via `Del WAV's older than`
- Set to `Disabled` to preserve all outputs
## ⚠️ Known Limitations
- No support for:
- DeepSpeed acceleration
- Pitch adjustment
- Generation speed control
- Repetition penalty
- Temperature adjustment
- Streaming generation
## 🔧 System Requirements
- Runs on all major operating systems:
- Windows
- Linux
- macOS
- Outputs in WAV format
- GPU recommended for optimal performance
"""
+126 -26
View File
@@ -7,6 +7,7 @@ import json
import time import time
import torch import torch
import logging import logging
import inspect
from pathlib import Path from pathlib import Path
from fastapi import (HTTPException) from fastapi import (HTTPException)
logging.disable(logging.WARNING) logging.disable(logging.WARNING)
@@ -142,6 +143,18 @@ class tts_class:
print(f"[{self.branding}ENG]") print(f"[{self.branding}ENG]")
return return
###############################################
# Central print function # Do not change this #
###############################################
def debug_func_entry(self):
"""Log function entry if debug_func is enabled."""
quick_debug = False
if quick_debug:
current_func = inspect.currentframe().f_back.f_code.co_name
print(f"Function entry: {current_func}", "debug_func")
################################################################################### ###################################################################################
################################################################################### ###################################################################################
# CHANGE ME # Inital setup of the model and engine. Called when the script starts # # CHANGE ME # Inital setup of the model and engine. Called when the script starts #
@@ -152,6 +165,7 @@ class tts_class:
# engine doesnt actually load a model into CUDA or System RAM, you may be doing # engine doesnt actually load a model into CUDA or System RAM, you may be doing
# Something to fake its start-up. # Something to fake its start-up.
async def setup(self): async def setup(self):
self.debug_func_entry()
self.printout_versions() self.printout_versions()
self.available_models = self.scan_models_folder() self.available_models = self.scan_models_folder()
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ # ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
@@ -189,6 +203,7 @@ class tts_class:
# However, its quite a simple check along the lines of "if CUDA is available and model is # However, its quite a simple check along the lines of "if CUDA is available and model is
# in X place, then send it to Y place (or Y to X). # in X place, then send it to Y place (or Y to X).
async def handle_lowvram_change(self): async def handle_lowvram_change(self):
self.debug_func_entry()
if torch.cuda.is_available(): if torch.cuda.is_available():
if self.device == "cuda": if self.device == "cuda":
self.device = "cpu" self.device = "cpu"
@@ -210,6 +225,7 @@ class tts_class:
# model_settings.JSON and this function will never get called, however it still needs # model_settings.JSON and this function will never get called, however it still needs
# to exist as a function. # to exist as a function.
async def handle_deepspeed_change(self, value): async def handle_deepspeed_change(self, value):
self.debug_func_entry()
if value: if value:
# DeepSpeed enabled # DeepSpeed enabled
print(f"[{self.branding}ENG] \033[93mDeepSpeed Activating\033[0m") print(f"[{self.branding}ENG] \033[93mDeepSpeed Activating\033[0m")
@@ -240,32 +256,69 @@ class tts_class:
# voices that can be selected in the interface. # voices that can be selected in the interface.
# If no models are found, we return "No Models Available" and continue on with the script. # If no models are found, we return "No Models Available" and continue on with the script.
def scan_models_folder(self): def scan_models_folder(self):
self.debug_func_entry()
models_folder = self.main_dir / "models" / "vits" # Edit to match the name of your folder where voices are stored models_folder = self.main_dir / "models" / "vits" # Edit to match the name of your folder where voices are stored
self.available_models = {} self.available_models = {}
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ # ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↑↑↑ Keep everything above this line ↑↑↑ # ↑↑↑ Keep everything above this line ↑↑↑
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ # ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
required_files_multi_speaker = ["config.json", "model_file.pth", "speaker_ids.json"] # Define possible model file names
required_files_single_speaker = ["config.json", "model_file.pth"] model_files = ["model_file.pth", "model.pth"]
required_files_multi_language = ["config.json", "model_file.pth.tar", "speaker_ids.json", "language_ids.json"]
found_any_models = False
for subfolder in models_folder.iterdir(): for subfolder in models_folder.iterdir():
if subfolder.is_dir(): if subfolder.is_dir():
model_name = subfolder.name model_name = subfolder.name
if all(subfolder.joinpath(file).exists() for file in required_files_multi_speaker):
self.available_models[f"vits - {model_name}"] = "vits_multi_speaker" # Check if config.json exists (this is the minimum requirement)
elif all(subfolder.joinpath(file).exists() for file in required_files_single_speaker): if not (subfolder / "config.json").exists():
self.available_models[f"vits - {model_name}"] = "vits_single_speaker" print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Model folder '{model_name}' missing config.json")
elif all(subfolder.joinpath(file).exists() for file in required_files_multi_language): continue
# Load config to check model type
try:
with open(subfolder / "config.json", "r") as f:
config = json.load(f)
use_speaker_embedding = config["model_args"].get("use_speaker_embedding", False)
num_speakers = config["model_args"].get("num_speakers", 0)
except Exception as e:
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Couldn't read config.json for '{model_name}': {str(e)}")
continue
# Check for model file
has_model_file = any(subfolder.joinpath(model_file).exists() for model_file in model_files)
has_model_file_tar = subfolder.joinpath("model_file.pth.tar").exists()
if not (has_model_file or has_model_file_tar):
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Model folder '{model_name}' missing model file")
continue
# Determine model type based on files and config
if (subfolder / "language_ids.json").exists() and (subfolder / "speaker_ids.json").exists():
self.available_models[f"vits - {model_name}"] = "vits_multi_language" self.available_models[f"vits - {model_name}"] = "vits_multi_language"
found_any_models = True
#print(f"[{self.branding}ENG] Found multi-language model: {model_name}")
elif (subfolder / "speaker_ids.json").exists() or (use_speaker_embedding or num_speakers > 0):
self.available_models[f"vits - {model_name}"] = "vits_multi_speaker"
found_any_models = True
#print(f"[{self.branding}ENG] Found multi-speaker model: {model_name}")
else:
self.available_models[f"vits - {model_name}"] = "vits_single_speaker"
found_any_models = True
#print(f"[{self.branding}ENG] Found single-speaker model: {model_name}")
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ # ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ↓↓↓ Keep everything below this line ↓↓↓ # ↓↓↓ Keep everything below this line ↓↓↓
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ # ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
else:
self.available_models = {'No Models Available': 'vits'} # Change the name in here to your TTS engine name if not found_any_models:
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Model folder '{model_name}' is missing required") self.available_models = {'No Models Available': 'vits'} # Change the name in here to your TTS engine name
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: files or the folder does not exist.") print(f"[{self.branding}ENG] \033[91mWarning\033[0m: Model folder '{model_name}' is missing required")
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: files or the folder does not exist.")
return self.available_models return self.available_models
############################################################# #############################################################
@@ -279,38 +332,55 @@ class tts_class:
# populate the "voices" variable somehow and if no voices are found, we return # populate the "voices" variable somehow and if no voices are found, we return
# "No Voices Found" back to the interface/api. # "No Voices Found" back to the interface/api.
def voices_file_list(self): def voices_file_list(self):
self.debug_func_entry()
try: try:
voices = [] voices = []
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
# ↑↑↑ Keep everything above this line ↑↑↑
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
model_name = self.selected_model.replace("vits - ", "") model_name = self.selected_model.replace("vits - ", "")
print("model_name", model_name) if self.debug_tts else None print("model_name", model_name) if self.debug_tts else None
model_type = self.available_models[self.selected_model] model_type = self.available_models[self.selected_model]
print("model_type", model_type) if self.debug_tts else None print("model_type", model_type) if self.debug_tts else None
if model_type == "vits_multi_speaker" or model_type == "vits_multi_language": # Load config to check model type
config_path = self.main_dir / "models" / "vits" / model_name / "config.json"
if config_path.exists():
with open(config_path, "r") as f:
config = json.load(f)
use_speaker_embedding = config["model_args"].get("use_speaker_embedding", False)
num_speakers = config["model_args"].get("num_speakers", 0)
else:
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: config.json not found for model '{model_name}'")
return ["No Voices Found"]
# Check for speakers file and model configuration
if model_type in ["vits_multi_speaker", "vits_multi_language"]:
speaker_ids_path = self.main_dir / "models" / "vits" / model_name / "speaker_ids.json" speaker_ids_path = self.main_dir / "models" / "vits" / model_name / "speaker_ids.json"
if speaker_ids_path.exists(): if speaker_ids_path.exists():
with open(speaker_ids_path, "r") as f: with open(speaker_ids_path, "r") as f:
speaker_ids = json.load(f) speaker_ids = json.load(f)
voices = [speaker for speaker in speaker_ids.keys() if speaker != "ED\n"] voices = [speaker for speaker in speaker_ids.keys() if speaker != "ED\n"]
print(f"[{self.branding}ENG] Found {len(voices)} voices in speaker_ids.json") if self.debug_tts else None
elif use_speaker_embedding or num_speakers > 0:
# If there's no speaker_ids.json but config indicates multiple speakers,
# create a default list of numbered speakers
voices = [f"Speaker{i}" for i in range(num_speakers)]
print(f"[{self.branding}ENG] Created {len(voices)} default voice names from config") if self.debug_tts else None
else: else:
print(f"[{self.branding}ENG] \033[91mWarning\033[0m: speaker_ids.json not found for model \033[0m'{model_name}'\033[0m.") if self.debug_tts else None print(f"[{self.branding}ENG] No speaker information found for multi-speaker model '{model_name}'") if self.debug_tts else None
elif model_type == "vits_single_speaker": elif model_type == "vits_single_speaker":
voices = ["default"] # Return a list containing only the default voice for single-speaker models voices = ["default"]
print(f"[{self.branding}ENG] Using default voice for single-speaker model") if self.debug_tts else None
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
# ↓↓↓ Keep everything below this line ↓↓↓
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
if not voices: # If the voices list is empty if not voices: # If the voices list is empty
return ["No Voices Found"] # Return a list with 'No Voices Found' if there are no voices/voice models voices = ["default"] # Fallback to default if no voices were found
print(f"[{self.branding}ENG] No voices found, using default") if self.debug_tts else None
return voices # Return the list of voices return voices # Return the list of voices
except Exception as e: except Exception as e:
print(f"[{self.branding}ENG] \033[91mError\033[0m: Voices/Voice Models not found. Cannot load a list of voices.") print(f"[{self.branding}ENG] \033[91mError\033[0m: Voices/Voice Models not found. Cannot load a list of voices.")
print(f"[{self.branding}ENG] Exception: {str(e)}") # Optional: Print the exception message for debugging print(f"[{self.branding}ENG] Exception: {str(e)}")
return ["No Voices Found"] return ["No Voices Found"]
############################# #############################
@@ -326,6 +396,7 @@ class tts_class:
# We always check for "No Models Available" being sent as that means we are trying to load in a model that # We always check for "No Models Available" being sent as that means we are trying to load in a model that
# doesnt exist/wasnt found on script start-up e.g. someone deleted the model from the folder or something. # doesnt exist/wasnt found on script start-up e.g. someone deleted the model from the folder or something.
async def api_manual_load_model(self, model_name): async def api_manual_load_model(self, model_name):
self.debug_func_entry()
if "No Models Available" in self.available_models: if "No Models Available" in self.available_models:
print(f"[{self.branding}ENG] \033[91mError\033[0m: No models for this TTS engine were found to load. Please download a model.") print(f"[{self.branding}ENG] \033[91mError\033[0m: No models for this TTS engine were found to load. Please download a model.")
return return
@@ -354,10 +425,36 @@ class tts_class:
# Save the updated config dictionary back to the config.json file # Save the updated config dictionary back to the config.json file
with open(config_file_path, "w") as f: with open(config_file_path, "w") as f:
json.dump(config_dict, f, indent=4) json.dump(config_dict, f, indent=4)
def get_model_path(model_dir, model_type):
"""Helper function to find the correct model file"""
print(f"Searching for model file in {model_dir} for type {model_type}") if self.debug_tts else None
if model_type == "vits_multi_language":
# Check for .pth.tar file first for multi-language models
if (model_dir / "model_file.pth.tar").exists():
print(f"Found model_file.pth.tar") if self.debug_tts else None
return model_dir / "model_file.pth.tar"
# Check for regular .pth files
if (model_dir / "model_file.pth").exists():
print(f"Found model_file.pth") if self.debug_tts else None
return model_dir / "model_file.pth"
elif (model_dir / "model.pth").exists():
print(f"Found model.pth") if self.debug_tts else None
return model_dir / "model.pth"
print(f"No model file found in {model_dir}") if self.debug_tts else None
raise FileNotFoundError(f"No model file found in {model_dir}")
# Then in api_manual_load_model:
model_type = self.available_models[f"vits - {model_name}"]
model_file = get_model_path(model_path, model_type)
if model_type == "vits_multi_language": if model_type == "vits_multi_language":
# Load multi-language model # Load multi-language model
self.model = Synthesizer( self.model = Synthesizer(
tts_checkpoint=model_path / "model_file.pth.tar", tts_checkpoint=model_file, # Use the detected model file
tts_config_path=config_file_path, tts_config_path=config_file_path,
tts_speakers_file=speakers_file, tts_speakers_file=speakers_file,
tts_languages_file=model_path / "language_ids.json", tts_languages_file=model_path / "language_ids.json",
@@ -366,14 +463,14 @@ class tts_class:
elif not use_speaker_embedding and num_speakers == 0: elif not use_speaker_embedding and num_speakers == 0:
# Single-speaker model without speaker embeddings # Single-speaker model without speaker embeddings
self.model = Synthesizer( self.model = Synthesizer(
tts_checkpoint=model_path / "model_file.pth", tts_checkpoint=model_file,
tts_config_path=config_file_path, tts_config_path=config_file_path,
use_cuda=self.cuda_is_available, use_cuda=self.cuda_is_available,
) )
else: else:
# Multi-speaker model or single-speaker model with speaker embeddings # Multi-speaker model or single-speaker model with speaker embeddings
self.model = Synthesizer( self.model = Synthesizer(
tts_checkpoint=model_path / "model_file.pth", tts_checkpoint=model_file,
tts_config_path=config_file_path, tts_config_path=config_file_path,
tts_speakers_file=speakers_file, tts_speakers_file=speakers_file,
use_cuda=self.cuda_is_available, use_cuda=self.cuda_is_available,
@@ -397,6 +494,7 @@ class tts_class:
# other than set "self.is_tts_model_loaded = False", which would be set back to true by the model loader. # other than set "self.is_tts_model_loaded = False", which would be set back to true by the model loader.
# So look at the Piper model_engine.py if you DONT need to unload models. # So look at the Piper model_engine.py if you DONT need to unload models.
async def unload_model(self): async def unload_model(self):
self.debug_func_entry()
self.is_tts_model_loaded = False self.is_tts_model_loaded = False
if not self.current_model_loaded == None: if not self.current_model_loaded == None:
print(f"[{self.branding}ENG] \033[94mUnloading model \033[0m") if self.debug_tts else None print(f"[{self.branding}ENG] \033[94mUnloading model \033[0m") if self.debug_tts else None
@@ -418,6 +516,7 @@ class tts_class:
# we just have a fake function that doesnt really do anything. We always check to see if the model name has "No Models Available" in the # we just have a fake function that doesnt really do anything. We always check to see if the model name has "No Models Available" in the
# name thats sent over, just to catch any potential errors. We display the start load time and end load time. Thats about it. # name thats sent over, just to catch any potential errors. We display the start load time and end load time. Thats about it.
async def handle_tts_method_change(self, tts_method): async def handle_tts_method_change(self, tts_method):
self.debug_func_entry()
generate_start_time = time.time() # Record the start time of loading the model generate_start_time = time.time() # Record the start time of loading the model
if "No Models Available" in self.available_models: if "No Models Available" in self.available_models:
print(f"[{self.branding}ENG] \033[91mError\033[0m: No models for this TTS engine were found to load. Please download a model.") print(f"[{self.branding}ENG] \033[91mError\033[0m: No models for this TTS engine were found to load. Please download a model.")
@@ -467,6 +566,7 @@ class tts_class:
# Piper TTS, which uses command line based calls and therefore has different ones for Windows and Linux/Mac, has an example of doing this # Piper TTS, which uses command line based calls and therefore has different ones for Windows and Linux/Mac, has an example of doing this
# within its model_engine.py file. # within its model_engine.py file.
async def generate_tts(self, text, voice, language, temperature, repetition_penalty, speed, pitch, output_file, streaming): async def generate_tts(self, text, voice, language, temperature, repetition_penalty, speed, pitch, output_file, streaming):
self.debug_func_entry()
print(f"[{self.branding}Debug] Entered model_engine.py generate_tts function") if self.debug_tts else None print(f"[{self.branding}Debug] Entered model_engine.py generate_tts function") if self.debug_tts else None
if not self.is_tts_model_loaded: # Check if a model is loaded and error out if not. if not self.is_tts_model_loaded: # Check if a model is loaded and error out if not.
error_message = f"[{self.branding}ENG] \033[91mError\033[0m: You currently have no TTS model loaded." error_message = f"[{self.branding}ENG] \033[91mError\033[0m: You currently have no TTS model loaded."
+211 -68
View File
@@ -6,6 +6,7 @@ import requests
import gradio as gr import gradio as gr
from tqdm import tqdm from tqdm import tqdm
from pathlib import Path from pathlib import Path
from .help_content import AllTalkHelpContent
this_dir = Path(__file__).parent.resolve() # Sets up self.this_dir as a variable for the folder THIS script is running in. this_dir = Path(__file__).parent.resolve() # Sets up self.this_dir as a variable for the folder THIS script is running in.
main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up self.main_dir as a variable for the folder AllTalk is running in main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up self.main_dir as a variable for the folder AllTalk is running in
@@ -28,6 +29,12 @@ main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up sel
# #
# After making the necessary changes, this function should return a list of available voices that can be used # After making the necessary changes, this function should return a list of available voices that can be used
# in your TTS engine's settings page. # in your TTS engine's settings page.
# Load the available models from the JSON file
with open(os.path.join(this_dir, "available_models.json"), "r") as f:
available_models = json.load(f)
# Extract the model names for the dropdown
model_names = [model["model_name"] for model in available_models["models"]]
def vits_voices_file_list(): def vits_voices_file_list():
models_folder = main_dir / "models" / "vits" models_folder = main_dir / "models" / "vits"
# Create the folder if it doesn't exist # Create the folder if it doesn't exist
@@ -35,32 +42,57 @@ def vits_voices_file_list():
models_folder.mkdir(parents=True, exist_ok=True) models_folder.mkdir(parents=True, exist_ok=True)
voices = [] voices = []
available_models = {} available_models = {}
required_files_multi_speaker = ["config.json", "model_file.pth", "speaker_ids.json"]
required_files_single_speaker = ["config.json", "model_file.pth"] # Define possible model files
required_files_multi_language = ["config.json", "model_file.pth.tar", "speaker_ids.json", "language_ids.json"] model_files = ["model_file.pth", "model.pth"]
for subfolder in models_folder.iterdir(): for subfolder in models_folder.iterdir():
if subfolder.is_dir(): if subfolder.is_dir():
model_name = subfolder.name model_name = subfolder.name
if all(subfolder.joinpath(file).exists() for file in required_files_multi_speaker):
available_models[f"VITS - {model_name}"] = "VITS_multi_speaker" # Check if config.json exists (minimum requirement)
elif all(subfolder.joinpath(file).exists() for file in required_files_single_speaker): if not (subfolder / "config.json").exists():
available_models[f"VITS - {model_name}"] = "VITS_single_speaker" continue
elif all(subfolder.joinpath(file).exists() for file in required_files_multi_language):
# Load config to check model type
try:
with open(subfolder / "config.json", "r") as f:
config = json.load(f)
use_speaker_embedding = config["model_args"].get("use_speaker_embedding", False)
num_speakers = config["model_args"].get("num_speakers", 0)
except Exception:
continue
# Check for model file
has_model_file = any(subfolder.joinpath(model_file).exists() for model_file in model_files)
has_model_file_tar = subfolder.joinpath("model_file.pth.tar").exists()
if not (has_model_file or has_model_file_tar):
continue
# Determine model type
if (subfolder / "language_ids.json").exists() and (subfolder / "speaker_ids.json").exists():
available_models[f"VITS - {model_name}"] = "VITS_multi_language" available_models[f"VITS - {model_name}"] = "VITS_multi_language"
elif (subfolder / "speaker_ids.json").exists() or (use_speaker_embedding or num_speakers > 0):
available_models[f"VITS - {model_name}"] = "VITS_multi_speaker"
else: else:
print(f"[AllTalk ENG] \033[91mWarning\033[0m: Model '{model_name}' does not match any known model type.") available_models[f"VITS - {model_name}"] = "VITS_single_speaker"
model_type = available_models.get(f"VITS - {model_name}")
if model_type == "VITS_multi_speaker" or model_type == "VITS_multi_language": # Get voices based on model type
model_type = available_models[f"VITS - {model_name}"]
if model_type in ["VITS_multi_speaker", "VITS_multi_language"]:
speaker_ids_path = subfolder / "speaker_ids.json" speaker_ids_path = subfolder / "speaker_ids.json"
if speaker_ids_path.exists(): if speaker_ids_path.exists():
with open(speaker_ids_path, "r") as f: with open(speaker_ids_path, "r") as f:
speaker_ids = json.load(f) speaker_ids = json.load(f)
speakers = [speaker for speaker in speaker_ids.keys() if speaker != "ED\n"] speakers = [speaker for speaker in speaker_ids.keys() if speaker != "ED\n"]
voices.extend(speakers) voices.extend(speakers)
else: elif use_speaker_embedding or num_speakers > 0:
print(f"[AllTalk ENG] \033[91mWarning\033[0m: speaker_ids.json not found for model '{model_name}'.") # If no speaker_ids.json but config indicates multiple speakers
voices.extend([f"Speaker{i}" for i in range(num_speakers)])
elif model_type == "VITS_single_speaker": elif model_type == "VITS_single_speaker":
voices.append("default") voices.append("default")
# Remove duplicate speaker names # Remove duplicate speaker names
voices = list(set(voices)) voices = list(set(voices))
# Sort the voices alphabetically # Sort the voices alphabetically
@@ -71,6 +103,120 @@ def vits_voices_file_list():
voices.insert(0, "default") voices.insert(0, "default")
return voices return voices
def group_vits_models_by_language():
"""Group available VITS models by language code"""
language_groups = {}
for model in available_models["models"]:
model_name = model["model_name"]
# Extract language code from model name (format: tts_models--{lang}--...)
parts = model_name.split('--')
if len(parts) >= 2:
lang_code = parts[1]
if lang_code not in language_groups:
language_groups[lang_code] = {
"name": get_language_name(lang_code),
"models": []
}
language_groups[lang_code]["models"].append(model)
return language_groups
def get_language_name(lang_code):
"""Convert VITS language code to full name"""
language_names = {
"en": "English",
"de": "German",
"fr": "French",
"es": "Spanish",
"it": "Italian",
"nl": "Dutch",
"pl": "Polish",
"pt": "Portuguese",
"ru": "Russian",
"cs": "Czech",
"hu": "Hungarian",
"bn": "Bengali",
"ca": "Catalan",
"el": "Greek",
"fi": "Finnish",
"hr": "Croatian",
"lt": "Lithuanian",
"lv": "Latvian",
"mt": "Maltese",
"ro": "Romanian",
"sk": "Slovak",
"sl": "Slovenian",
"sv": "Swedish",
"bg": "Bulgarian",
"da": "Danish",
"et": "Estonian",
"ga": "Irish",
"uk": "Ukrainian",
"ewe": "Ewe",
"hau": "Hausa",
"lin": "Lingala",
"tw": "Twi",
"yor": "Yoruba"
}
return language_names.get(lang_code, f"Unknown ({lang_code})")
def download_language_pack(lang_code, progress=gr.Progress()):
"""Download all models for a specific language"""
language_groups = group_vits_models_by_language()
if lang_code not in language_groups:
return f"Error: Language pack {lang_code} not found"
models = language_groups[lang_code]["models"]
total_models = len(models)
progress(0, desc=f"Downloading {get_language_name(lang_code)} voice pack")
downloaded_files = []
errors = []
for idx, model in enumerate(models, 1):
progress(idx/total_models, desc=f"Downloading model {idx}/{total_models}")
try:
# Create the model folder
vits_folder = os.path.join(main_dir, "models", "vits")
folder_path = os.path.join(vits_folder, model["folder_path"])
os.makedirs(folder_path, exist_ok=True)
# Download and extract the model
zip_url = model["github_rls_url"]
zip_file_path = os.path.join(vits_folder, f"{model['model_name']}.zip")
response = requests.get(zip_url, stream=True)
total_size = int(response.headers.get("content-length", 0))
with open(zip_file_path, "wb") as file:
for chunk in response.iter_content(chunk_size=1024):
if chunk:
file.write(chunk)
# Extract ZIP file
with zipfile.ZipFile(zip_file_path, "r") as zip_ref:
zip_ref.extractall(vits_folder)
# Cleanup
os.remove(zip_file_path)
macosx_folder = os.path.join(vits_folder, "__MACOSX")
if os.path.exists(macosx_folder):
shutil.rmtree(macosx_folder)
downloaded_files.append(model["model_name"])
except Exception as e:
errors.append(f"Error downloading {model['model_name']}: {str(e)}")
if errors:
return f"Downloaded {len(downloaded_files)} models with {len(errors)} errors:\n" + "\n".join(errors)
else:
return f"Successfully downloaded {len(downloaded_files)} models for {get_language_name(lang_code)}"
###################################################### ######################################################
# REQUIRED CHANGE # # REQUIRED CHANGE #
# Imports and saves the TTS engine-specific settings # # Imports and saves the TTS engine-specific settings #
@@ -161,10 +307,16 @@ def vits_model_alltalk_settings(model_config_data):
def_narrator_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_narrator_voice"], label="Narrator Voice", choices=voice_list, allow_custom_value=True) def_narrator_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_narrator_voice"], label="Narrator Voice", choices=voice_list, allow_custom_value=True)
with gr.Group(): with gr.Group():
with gr.Row(): with gr.Row():
details_text = gr.Textbox(label="Details", show_label=False, lines=5, interactive=False, value="In this section, you can set the default settings for this TTS engine. Settings that are not supported by the current engine will be greyed out and cannot be selected. Default voices specified here will be used when no specific voice is provided in the TTS generation request. If a voice is specified in the request, it will override these default settings. When using the OpenAI API compatable API with this TTS engine, the voice mappings will be applied. As the OpenAI API has a limited set of 6 voices, these mappings ensure compatibility by mapping the OpenAI voices to the available voices in this TTS engine.") details_text = gr.Textbox(label="Details", show_label=False, lines=5, interactive=False, value="Configure default settings and voice mappings for the selected TTS engine. Unavailable options are grayed out based on engine capabilities. See the Help section below for detailed information about each setting.")
with gr.Row(): with gr.Row():
submit_button = gr.Button("Update Settings") submit_button = gr.Button("Update Settings")
output_message = gr.Textbox(label="Output Message", interactive=False, show_label=False) output_message = gr.Textbox(label="Output Message", interactive=False, show_label=False)
with gr.Accordion("HELP - 🔊 Understanding TTS Engine Default Settings Page", open=False):
with gr.Row():
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS, elem_classes="custom-markdown")
with gr.Row():
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS2, elem_classes="custom-markdown")
submit_button.click(vits_model_update_settings, inputs=[def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr], outputs=output_message) submit_button.click(vits_model_update_settings, inputs=[def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr], outputs=output_message)
########################################################################################### ###########################################################################################
@@ -198,52 +350,54 @@ def vits_model_alltalk_settings(model_config_data):
gr.Textbox(label="Linux Support", value='Yes' if features_list['linux_capable'] else 'No', interactive=False) gr.Textbox(label="Linux Support", value='Yes' if features_list['linux_capable'] else 'No', interactive=False)
gr.Textbox(label="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False) gr.Textbox(label="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False)
with gr.Row(): with gr.Row():
gr.Markdown(""" with gr.Accordion("HELP - 🔊 Understanding TTS Engine Capabilities", open=False):
#### 🟧 DeepSpeed Capable with gr.Row():
DeepSpeed is a deep learning optimization library that can significantly speed up model training and inference. If a model is DeepSpeed capable, it means it can utilize DeepSpeed to accelerate the generation of text-to-speech output. This requires the model to be loaded into CUDA/VRAM on an Nvidia GPU and the model's inference method to support DeepSpeed. gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION, elem_classes="custom-markdown")
#### 🟧 Pitch Capable with gr.Row():
Pitch refers to the highness or lowness of a sound. If a model is pitch capable, it can adjust the pitch of the generated speech, allowing for more expressive and varied output. gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION1, elem_classes="custom-markdown")
#### 🟧 Generation Speed Capable gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION2, elem_classes="custom-markdown")
Generation speed refers to the rate at which the model can generate text-to-speech output. If a model is generation speed capable, it means the speed of the generated speech can be adjusted, making it faster or slower depending on the desired output.
#### 🟧 Repetition Penalty Capable
Repetition penalty is a technique used to discourage the model from repeating the same words or phrases multiple times in the same sounding way. If a model is repetition penalty capable, it can apply this penalty during generation to improve the diversity and naturalness of the output.
#### 🟧 Multi-Languages Capable
Multi-language capable models can generate speech in multiple languages. This means that the model has been trained on data from different languages and can switch between them during generation. Some models are language-specific.
#### 🟧 Multi-Voice Capable
Multi-voice capable models generate speech in multiple voices or speaking styles. This means that the model has been trained on data from different speakers and can mimic their voices during generation, or is a voice cloning model that can generate speech based on the input sample.
""")
gr.Markdown("""
#### 🟧 Streaming Capable
Streaming refers to the ability to generate speech output in real-time, without the need to generate the entire output before playback. If a model is streaming capable, it can generate speech on-the-fly, allowing for faster response times and more interactive applications.
#### 🟧 Low VRAM Capable
VRAM (Video Random Access Memory) is a type of memory used by GPUs to store and process data. If a model is low VRAM capable, it can efficiently utilize the available VRAM by moving data between CPU and GPU memory as needed, allowing for generation even on systems with limited VRAM where it may be competing with an LLM model for VRAM.
#### 🟧 Temperature Capable
Temperature is a hyperparameter that controls the randomness of the generated output. If a model is temperature capable, the temperature can be adjusted to make the output more or less random, affecting the creativity and variability of the generated speech.
#### 🟧 Multi-Model Capable Engine
If an engine is multi-model capable, it means that it can support and utilize multiple models for text-to-speech generation. This allows for greater flexibility and the ability to switch between different models depending on the desired output. Different models may be capable of different languages, specific languages, voices, etc.
#### 🟧 Default Audio Output Format
Specifies the file format in which the generated speech will be saved. Common audio formats include WAV, MP3, FLAC, Opus, AAC, and PCM. If you want different outputs, you can set the transcode function to change the output audio, though transcoding will add a little time to the generation and is not available for streaming generation.
#### 🟧 Windows/Linux/Mac Support
These indicators show whether the model and engine are compatible with Windows, Linux, or macOS. However, additional setup or requirements may be necessary to ensure full functionality on your operating system. Please note that full platform support has not been extensively tested.
""")
####################################################################################################################################################################################################### #######################################################################################################################################################################################################
# REQUIRED CHANGE # # REQUIRED CHANGE #
# You will need to build a custom method to identify if your models are installed and download them. Store your models list in the available_models.json file, alongside your model_settings.json etc # # You will need to build a custom method to identify if your models are installed and download them. Store your models list in the available_models.json file, alongside your model_settings.json etc #
####################################################################################################################################################################################################### #######################################################################################################################################################################################################
with gr.Tab("Models/Voices Download"): with gr.Tab("Models/Voices Download"):
with gr.Row(): with gr.Tab("Language Pack Download"):
# Load the available models from the JSON file with gr.Row():
with open(os.path.join(this_dir, "available_models.json"), "r") as f: language_groups = group_vits_models_by_language()
available_models = json.load(f) language_choices = [
# Extract the model names for the dropdown f"{code} - {info['name']} ({len(info['models'])} models)"
model_names = [model["model_name"] for model in available_models["models"]] for code, info in sorted(language_groups.items())
# Create the dropdown ]
model_dropdown = gr.Dropdown(choices=sorted(model_names), label="Select Model", value=model_names[0])
download_button = gr.Button("Download Model/Missing Files")
with gr.Row(): lang_pack_dropdown = gr.Dropdown(
download_status = gr.Textbox(label="Download Status") choices=language_choices,
label="Select Language Pack",
value=language_choices[0]
)
lang_pack_download_button = gr.Button("Download Language Pack")
with gr.Row():
lang_pack_status = gr.Textbox(label="Language Pack Download Status")
def download_selected_language_pack(selected_pack):
lang_code = selected_pack.split(" - ")[0]
return download_language_pack(lang_code)
lang_pack_download_button.click(
download_selected_language_pack,
inputs=lang_pack_dropdown,
outputs=lang_pack_status
)
with gr.Tab("Individual Voice Download"):
with gr.Row():
# Create the dropdown
model_dropdown = gr.Dropdown(choices=sorted(model_names), label="Select Model", value=model_names[0])
download_button = gr.Button("Download Model/Missing Files")
with gr.Row():
download_status = gr.Textbox(label="Download Status")
def download_model(model_name): def download_model(model_name):
# Find the selected model in the available models # Find the selected model in the available models
@@ -351,21 +505,10 @@ def vits_model_alltalk_settings(model_config_data):
################################################################################################### ###################################################################################################
with gr.Tab("Engine Help"): with gr.Tab("Engine Help"):
with gr.Row(): with gr.Row():
gr.Markdown(""" gr.Markdown(AllTalkHelpContent.HELP_PAGE, elem_classes="custom-markdown")
### 🟧 Where are the vits models stored? with gr.Row():
This extension will download the models to `/alltalk_tts/models/vits/` folder.<br> gr.Markdown(AllTalkHelpContent.HELP_PAGE1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.HELP_PAGE2, elem_classes="custom-markdown")
### 🟧 Where are the voices stored for vits models?
Vits models themselves are the voices/have the voices built into them. Some models have mutliple voices embedded and some models only the one voice embedded in them.<br>
### 🟧 Where are the outputs stored & Automatic output wav file deletion
Voice outputs are stored in `/alltalk_tts/outputs/`. You can configure automatic maintenance deletion of old wav files by setting `Del WAV's older than` in the global settings.<br>
> When `Disabled`, your output wav files will be left untouched.<br>
> When set to a setting `1 Day` or greater, your output wav files older than that time period will be automatically deleted on start-up of AllTalk.<br>
""")
gr.Markdown("""
""")
return app return app
+474
View File
@@ -0,0 +1,474 @@
# help_content.py
# pylint: disable=no-member
class AllTalkHelpContent:
"""CSS and help content for help_content.py"""
custom_css = """
/* Add this to your existing CSS */
.gradio-container .prose {
max-width: none !important;
padding: 0.5rem !important; /* Reduced padding */
margin: 0 !important;
}
.custom-markdown div {
border: none !important; /* Remove the inner border */
margin-top: 0 !important; /* Remove top margin */
margin-bottom: 0 !important; /* Remove bottom margin */
padding-top: 0 !important; /* Remove top padding */
padding-bottom: 0 !important; /* Remove bottom padding */
}
/* Update the existing custom-markdown class */
.custom-markdown {
font-size: 15px !important;
line-height: 1.6 !important;
color: var(--body-text-color) !important;
background-color: var(--background-fill-primary) !important;
border: 1px solid var(--border-color-primary) !important;
border-radius: 8px !important;
padding: 0.5rem !important;
margin: 0 !important; /* Changed from 1rem 0 to 0 */
max-width: 100% !important;
box-sizing: border-box !important;
/* Default text color for all content (grey) */
color: rgba(156, 163, 175, 1) !important; /* Adjust this grey value to match your interface */
}
/* Make headings white */
.custom-markdown h1,
.custom-markdown h2,
.custom-markdown h3,
.custom-markdown h4,
.custom-markdown h5,
.custom-markdown h6 {
color: var(--heading-text-color, var(--body-text-color)) !important;
font-weight: 600 !important;
}
/* Keep all other elements in the grey color */
.custom-markdown p,
.custom-markdown li,
.custom-markdown ul,
.custom-markdown ol {
color: rgba(156, 163, 175, 1) !important; /* Same grey as the base text */
}
/* Additional targeting for any wrapping elements */
.gradio-container .prose > * {
margin: 0 !important;
padding: 0 !important;
}
/* Update the list item spacing in your existing CSS */
.custom-markdown li {
font-size: 0.95rem !important;
margin-bottom: 0.2rem !important; /* Reduced from 0.5rem to 0.3rem */
}
/* Add specific styling for definition-style lists (like your Default, Recommendation, Tip items) */
.custom-markdown li p {
margin: 0 !important; /* Remove paragraph margins within list items */
}
/* If you need even tighter spacing for specific types of lists */
.custom-markdown li + li {
margin-top: 0.2rem !important; /* Space between consecutive list items */
}
/* Ensure nested lists maintain proper spacing */
.custom-markdown li > ul,
.custom-markdown li > ol {
margin: 0.2rem 0 0.2rem 1rem !important; /* Reduced from 0.5rem */
}
/* Consistent heading styles */
.custom-markdown h2 {
font-size: 1.2rem !important; /* Fixed size relative to root */
font-weight: 600 !important;
margin: 1.5rem 0 1rem !important;
color: var(--heading-text-color, var(--body-text-color)) !important;
border-bottom: 1px solid var(--border-color-primary) !important;
padding-bottom: 0.5rem !important;
}
/* First paragraph styling */
.custom-markdown p:first-of-type {
font-size: 0.95rem !important; /* Match base size */
font-weight: 400 !important;
margin-bottom: 1rem !important;
}
/* Regular paragraphs */
.custom-markdown p {
font-size: 0.95rem !important;
margin: 0.8rem 0 !important;
}
/* List styling */
.custom-markdown ul,
.custom-markdown ol {
margin: 0.8rem 0 !important;
padding-left: 1.5rem !important;
}
/* Code styling */
.custom-markdown code {
font-family: ui-monospace, monospace !important;
background-color: var(--background-fill-secondary) !important;
padding: 0.2rem 0.4rem !important;
border-radius: 4px !important;
font-size: 0.8rem !important; /* Slightly smaller than regular text */
color: var(--body-text-color) !important;
}
/* Add styles for bold and emphasis */
.custom-markdown strong {
font-weight: 600 !important;
color: var(--body-text-color) !important;
}
.custom-markdown em {
font-style: italic !important;
}
/* Ensure both columns take equal width */
.gradio-row > div {
flex: 1 1 50% !important;
min-width: 0 !important; /* Prevents flex items from overflowing */
}
"""
ENGINE_INFORMATION = """
## 🔊 TTS Engine Capabilities Help
This guide explains the various capabilities that **may** be available in different TTS engines and models. Each capability affects how the TTS engine processes and generates speech output.
"""
ENGINE_INFORMATION1 = """
## 🚀 Performance Features
- **DeepSpeed Capable**: Enables GPU acceleration using the DeepSpeed optimization library.
- **Requires**: NVIDIA GPU with CUDA support
- **Benefit**: Significantly faster text-to-speech generation
- **Note**: Model must specifically support DeepSpeed inference
- **Low VRAM Capable**: Optimized for systems with limited GPU memory.
- **Benefit**: Efficient memory management between CPU and GPU
- **Use Case**: Ideal when running alongside other GPU-intensive applications like LLMs
- **Note**: May trade speed for memory efficiency
- **Streaming Capable**: Enables real-time speech generation.
- **Benefit**: Immediate playback without generating entire audio first
- **Use Case**: Interactive applications and real-time responses
- **Note**: Not all output formats support streaming
## 🎵 Voice Control Features
- **Pitch Capable**: Allows adjustment of voice pitch.
- **Benefit**: Creates more expressive and varied speech output
- **Use Case**: Customizing voice characteristics
- **Note**: Adjustment range varies by model
- **Generation Speed Capable**: Controls speech rate.
- **Benefit**: Adjustable playback speed during generation
- **Use Case**: Creating faster or slower speech output
- **Note**: May affect audio quality at extreme settings
- **Temperature Capable**: Controls output randomness.
- **Benefit**: Adjustable speech variation and creativity
- **Use Case**: Balancing consistency vs. naturality
- **Note**: Higher values increase variation but may reduce quality
"""
ENGINE_INFORMATION2 = """
## 🎯 Quality Enhancement Features
- **Repetition Penalty Capable**: Prevents unnatural speech patterns.
- **Benefit**: Reduces repeated sounds and phrases
- **Use Case**: Improving natural flow of longer texts
- **Note**: Strength of penalty may be adjustable
## 🌐 Multi-Feature Support
- **Multi-Languages Capable Models**: Each model Supports multiple languages.
- **Benefit**: Generate speech in different languages
- **Note**: Quality may vary between languages
- **Tip**: Check model-specific language support
- **Multi-Voice Capable**: Supports multiple speaking voices.
- **Benefit**: Different voices or speaking styles
- **Types**: Pre-trained voices or voice cloning
- **Note**: Voice quality may vary by model
- **Multi-Model Capable Engine**: Supports multiple TTS models.
- **Benefit**: Flexibility in model selection
- **Use Case**: Switching between models for different needs
- **Note**: Each model may have different capabilities
## 📁 Technical Features
- **Default Audio Output Format**: Specifies output file format.
- **Common Formats**: WAV, MP3, FLAC, Opus, AAC, PCM
- **Note**: Transcoding to different formats adds processing time
- **Warning**: Not all formats support streaming
- **Platform Support**: Operating system compatibility.
- **Platforms**: Windows, Linux, macOS
- **Note**: Additional setup may be required
- **Warning**: Support level may vary by platform
"""
DEFAULT_SETTINGS = """
## 🎯 TTS Engine Settings Help
This guide explains the settings and configuration options available for individual Text-to-Speech engines within AllTalk.
"""
DEFAULT_SETTINGS1 = """
## 🎚️ Engine Capabilities & Controls
- **Low VRAM Mode**
- Optimizes memory usage for systems with limited GPU memory
- Efficiently manages resources by moving data between CPU and GPU
- Recommended for systems with less than 4GB VRAM or when running alongside other GPU-intensive applications
- **DeepSpeed Capability**
- Accelerates TTS generation using optimized inference
- Only available for engines and models that support DeepSpeed
- Requires NVIDIA GPU with CUDA support
- **Temperature Control**
- Adjusts the variability in speech generation
- **Range**: 0.0 to 1.0
- **Lower values** (0.1-0.5): More consistent, stable output
- **Higher values** (0.6-1.0): More variable, potentially more natural-sounding output
- **Repetition Penalty**
- Helps prevent repetitive speech patterns
- **Range**: 1.0 to 15.0
- Higher values more strongly discourage repetition
- Typically most effective between 1.0-3.0
- **Pitch Adjustment**
- Modifies the voice pitch when supported
- **Range**: -20 to +20
- Use subtle adjustments for most natural results
- **Generation Speed**
- Controls the pace of generated speech
- **Range**: 0.5 to 2.0
- 1.0 represents normal speed
"""
DEFAULT_SETTINGS2 = """
## 🗣️ Voice Configuration
### OpenAI Voice Mappings
- Only relevant when using the OpenAI-compatible API endpoint
- Maps OpenAI's six standard voices to equivalent voices in the current engine:
- `alloy`
- `echo`
- `fable`
- `nova`
- `onyx`
- `shimmer`
- Essential for maintaining compatibility with OpenAI API calls
- Each mapping can be customized to any available voice in the current engine
Information on the OpenAI Endpoint is available in the [Github Wiki](https://github.com/erew123/alltalk_tts/wiki)
### Default Voices
- **Default/Character Voice**: Used when no specific voice is specified in API calls
- **Narrator Voice**: Separate default for narrator-specific text
- These defaults are engine-specific and won't affect other TTS engines
- Can be overridden by explicitly specifying voices in API calls
## ⚙️ Important Notes
- Settings availability is determined by engine capabilities
- Grayed-out options indicate features not supported by the current engine
- Changes only affect the currently selected TTS engine
- Settings here act as defaults but can be overridden via API parameters
- All changes require clicking "Update Settings" to take effect
- Some settings require an engine reload to take effect
- JSON latent files are automatically created on first run of generation with a voice
"""
HELP_PAGE = """
## 🎯 XTTS Voice Cloning Engine Help
XTTS is a powerful multi-speaker, voice cloning model that can generate speech in multiple languages using short audio samples for voice cloning.
"""
HELP_PAGE1 = """
## 🎚️ Engine Capabilities & Controls
- **DeepSpeed Support**
- Accelerates generation using optimized inference
- Requires NVIDIA GPU with CUDA support
- 2-3x speed improvement in generation
- Recommended when available
- **Multi-Language Support**
- Clone voices across multiple languages
- No need for language-specific training
- Full Hindi support in v2.0.3 (API Local method only)
- Natural-sounding output in target language
- **Generation Methods**
- API Local: Standard generation method
- XTTSv2 Local: Enhanced method with DeepSpeed support
- Each method may produce slightly different results
- Try both methods if voice quality isn't optimal
## 🎤 Voice Sample Creation Guide
### Audio Requirements
- Format: WAV or MP3
- Sample Rate: 22050Hz
- Channels: Mono
- Bit Depth: 16-bit
- Duration: 6-30 seconds (optimal: 8-10 seconds)
### Recording Tips
1. **Audio Quality**
- Choose clear, clean recordings
- Avoid background noise, music, or echoes
- Watch for audio artifacts like hiss or hum
- Ensure consistent volume levels
2. **Speech Content**
- Use flowing, natural speech
- Avoid long pauses or gaps
- Include some emotional range
- Avoid breathing sounds at start/end
- Choose samples with good vocal variety
### Using Audacity
1. **Basic Editing**
- Open your audio file in Audacity
- Select the best 6-30 second segment
- Remove unwanted sounds or silence
2. **Processing Steps**
```
1. Clean up audio if needed (noise reduction, normalization)
2. Tracks > Resample to 22050Hz
3. Tracks > Mix > Stereo to Mono
4. File > Export Audio as WAV
```
## 🗣️ Voice Management
### Single Voice Setup
- Place WAV/MP3 files in `/alltalk_tts/voices/`
- Use descriptive filenames (e.g., `broadcaster_male.wav`)
- Files appear as individual voices in interface
- Best for quick testing or simple use cases
### Multi-Voice Sets
- Create folders in `/alltalk_tts/voices/xtts_multi_voice_sets/`
- Add multiple samples per voice
- System randomly selects up to 5 samples
- Better for consistent voice reproduction
- Example: `/voices/xtts_multi_voice_sets/broadcaster_voice/`
### Pre-computed Latents
- Stored in `/voices/xtts_latents/`
- Faster generation times
- Reduced memory usage
- Recommended for frequently used voices
### Automatic Latent Generation
- System automatically creates `.json` latent files alongside voice samples
- Latents are voice characteristics extracted from audio
- Generated on first use of a voice file
- Stored next to original audio (e.g., `broadcaster_male.wav` → `broadcaster_male.json`)
- Improves generation speed for subsequent uses
- No manual management needed
### Manual Latent Storage
- Pre-computed latents can also be stored in `/voices/xtts_latents/`
- Useful for organizing frequently used voice profiles
- Allows sharing latents without original audio
- Same format as automatic latents
- Takes priority over local latent files
"""
HELP_PAGE2 = """
## 📝 Model Versions
### v2.0.3 (Recommended)
- Latest stable release
- Full language support including Hindi
- Best overall performance
- Complete feature set
### v2.0.2 (Alternative)
- Stable fallback option
- Good performance
- Use if v2.0.3 has issues
### Required Files
- `config.json`: Model configuration
- `model.pth`: Core model weights
- `mel_stats.pth`: Audio statistics
- `speakers_xtts.pth`: Speaker embeddings
- `vocab.json`: Tokenizer vocabulary
- `dvae.pth`: Discrete VAE weights
## 🔍 Troubleshooting Voice Quality
If voice cloning results aren't satisfactory:
1. **Audio Quality Issues**
- Verify sample meets technical requirements
- Check for background noise
- Ensure proper resampling
- Try processing audio to improve clarity
2. **Generation Options**
- Try both API Local and XTTSv2 Local methods
- Adjust temperature settings
- Use multiple voice samples
- Consider creating latents
3. **Advanced Solutions**
- Try model finetuning (see Github Wiki)
- Use RVC pipeline for additional processing
- Test different voice samples
- Remember: 100% match isn't possible
## 📁 File Management
- **Models**: `/alltalk_tts/models/xtts/`
- **Voice Samples**: `/alltalk_tts/voices/`
- **Multi-Voice Sets**: `/alltalk_tts/voices/xtts_multi_voice_sets/`
- **Latents**: `/alltalk_tts/voices/xtts_latents/`
- **Outputs**: `/alltalk_tts/outputs/`
- Automatic cleanup available
- Configurable retention period
- Set to 'Disabled' to keep all files
## 💡 Best Practices
1. **Sample Selection**
- Use high-quality recordings
- Choose emotionally varied speech
- Avoid background noise
- Test multiple samples
2. **Performance**
- Enable DeepSpeed when available
- Use pre-computed latents
- Consider multi-voice sets
- Monitor system resources
3. **Workflow**
- Process audio before use
- Test both generation methods
- Keep original samples organized
- Regular cleanup of output files
"""
File diff suppressed because it is too large. Load diff
+18 -84
View File
@@ -4,6 +4,7 @@ import requests
import gradio as gr import gradio as gr
from tqdm import tqdm from tqdm import tqdm
from pathlib import Path from pathlib import Path
from .help_content import AllTalkHelpContent
this_dir = Path(__file__).parent.resolve() # Sets up self.this_dir as a variable for the folder THIS script is running in. this_dir = Path(__file__).parent.resolve() # Sets up self.this_dir as a variable for the folder THIS script is running in.
main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up self.main_dir as a variable for the folder AllTalk is running in main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up self.main_dir as a variable for the folder AllTalk is running in
@@ -128,11 +129,16 @@ def xtts_model_alltalk_settings(model_config_data):
def_narrator_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_narrator_voice"], label="Narrator Voice", choices=voice_list, allow_custom_value=True) def_narrator_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_narrator_voice"], label="Narrator Voice", choices=voice_list, allow_custom_value=True)
with gr.Group(): with gr.Group():
with gr.Row(): with gr.Row():
details_text = gr.Textbox(label="Details", show_label=False, lines=5, interactive=False, value="In this section, you can set the default settings for this TTS engine. Settings that are not supported by the current engine will be greyed out and cannot be selected. Default voices specified here will be used when no specific voice is provided in the TTS generation request. If a voice is specified in the request, it will override these default settings. When using the OpenAI API compatable API with this TTS engine, the voice mappings will be applied. As the OpenAI API has a limited set of 6 voices, these mappings ensure compatibility by mapping the OpenAI voices to the available voices in this TTS engine.") details_text = gr.Textbox(label="Details", show_label=False, lines=5, interactive=False, value="Configure default settings and voice mappings for the selected TTS engine. Unavailable options are grayed out based on engine capabilities. See the Help section below for detailed information about each setting.")
with gr.Row(): with gr.Row():
submit_button = gr.Button("Update Settings") submit_button = gr.Button("Update Settings")
output_message = gr.Textbox(label="Output Message", interactive=False, show_label=False) output_message = gr.Textbox(label="Output Message", interactive=False, show_label=False)
with gr.Accordion("HELP - 🔊 Understanding TTS Engine Default Settings Page", open=False):
with gr.Row():
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS, elem_classes="custom-markdown")
with gr.Row():
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.DEFAULT_SETTINGS2, elem_classes="custom-markdown")
submit_button.click(xtts_model_update_settings, inputs=[def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr], outputs=output_message) submit_button.click(xtts_model_update_settings, inputs=[def_character_voice_gr, def_narrator_voice_gr, lowvram_enabled_gr, deepspeed_enabled_gr, temperature_set_gr, repetitionpenalty_set_gr, pitch_set_gr, generationspeed_set_gr, alloy_gr, echo_gr, fable_gr, nova_gr, onyx_gr, shimmer_gr], outputs=output_message)
########################################################################################### ###########################################################################################
@@ -166,34 +172,12 @@ def xtts_model_alltalk_settings(model_config_data):
gr.Textbox(label="Linux Support", value='Yes' if features_list['linux_capable'] else 'No', interactive=False) gr.Textbox(label="Linux Support", value='Yes' if features_list['linux_capable'] else 'No', interactive=False)
gr.Textbox(label="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False) gr.Textbox(label="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False)
with gr.Row(): with gr.Row():
gr.Markdown(""" with gr.Accordion("HELP - 🔊 Understanding TTS Engine Capabilities", open=False):
#### 🟧 DeepSpeed Capable with gr.Row():
DeepSpeed is a deep learning optimization library that can significantly speed up model training and inference. If a model is DeepSpeed capable, it means it can utilize DeepSpeed to accelerate the generation of text-to-speech output. This requires the model to be loaded into CUDA/VRAM on an Nvidia GPU and the model's inference method to support DeepSpeed. gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION, elem_classes="custom-markdown")
#### 🟧 Pitch Capable with gr.Row():
Pitch refers to the highness or lowness of a sound. If a model is pitch capable, it can adjust the pitch of the generated speech, allowing for more expressive and varied output. gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION1, elem_classes="custom-markdown")
#### 🟧 Generation Speed Capable gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION2, elem_classes="custom-markdown")
Generation speed refers to the rate at which the model can generate text-to-speech output. If a model is generation speed capable, it means the speed of the generated speech can be adjusted, making it faster or slower depending on the desired output.
#### 🟧 Repetition Penalty Capable
Repetition penalty is a technique used to discourage the model from repeating the same words or phrases multiple times in the same sounding way. If a model is repetition penalty capable, it can apply this penalty during generation to improve the diversity and naturalness of the output.
#### 🟧 Multi-Languages Capable
Multi-language capable models can generate speech in multiple languages. This means that the model has been trained on data from different languages and can switch between them during generation. Some models are language-specific.
#### 🟧 Multi-Voice Capable
Multi-voice capable models generate speech in multiple voices or speaking styles. This means that the model has been trained on data from different speakers and can mimic their voices during generation, or is a voice cloning model that can generate speech based on the input sample.
""")
gr.Markdown("""
#### 🟧 Streaming Capable
Streaming refers to the ability to generate speech output in real-time, without the need to generate the entire output before playback. If a model is streaming capable, it can generate speech on-the-fly, allowing for faster response times and more interactive applications.
#### 🟧 Low VRAM Capable
VRAM (Video Random Access Memory) is a type of memory used by GPUs to store and process data. If a model is low VRAM capable, it can efficiently utilize the available VRAM by moving data between CPU and GPU memory as needed, allowing for generation even on systems with limited VRAM where it may be competing with an LLM model for VRAM.
#### 🟧 Temperature Capable
Temperature is a hyperparameter that controls the randomness of the generated output. If a model is temperature capable, the temperature can be adjusted to make the output more or less random, affecting the creativity and variability of the generated speech.
#### 🟧 Multi-Model Capable Engine
If an engine is multi-model capable, it means that it can support and utilize multiple models for text-to-speech generation. This allows for greater flexibility and the ability to switch between different models depending on the desired output. Different models may be capable of different languages, specific languages, voices, etc.
#### 🟧 Default Audio Output Format
Specifies the file format in which the generated speech will be saved. Common audio formats include WAV, MP3, FLAC, Opus, AAC, and PCM. If you want different outputs, you can set the transcode function to change the output audio, though transcoding will add a little time to the generation and is not available for streaming generation.
#### 🟧 Windows/Linux/Mac Support
These indicators show whether the model and engine are compatible with Windows, Linux, or macOS. However, additional setup or requirements may be necessary to ensure full functionality on your operating system. Please note that full platform support has not been extensively tested.
""")
with gr.Tab("Models/Voices Download"): with gr.Tab("Models/Voices Download"):
@@ -276,60 +260,10 @@ def xtts_model_alltalk_settings(model_config_data):
################################################################################################### ###################################################################################################
with gr.Tab("Engine Help"): with gr.Tab("Engine Help"):
with gr.Row(): with gr.Row():
gr.Markdown(""" gr.Markdown(AllTalkHelpContent.HELP_PAGE, elem_classes="custom-markdown")
### 🟧 Using my own Finetuned models with gr.Row():
Please your Finetuned models within their own folder in `/alltalk_tts/models/xtts/`. Once they are in here they will become availabe within the interface after reloading the XTTS engine.<br> gr.Markdown(AllTalkHelpContent.HELP_PAGE1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.HELP_PAGE2, elem_classes="custom-markdown")
### 🟧 Using Single Voice Samples
Voice samples are stored in `/alltalk_tts/voices/` and should be named using the following format `name.wav`. These files will be listed as `name.wav` in the available voices list.<br>
### 🟧 Using Multiple Voice Samples
If you have multiple voice samples for a single voice, you can organize them into subfolders within the `/alltalk_tts/voices/` directory. Each subfolder should be named according to the voice it contains, up to 5 voice samples will be randomly selected for use.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;• Each subfolder should reflect the name or type of the voice it contains (e.g., `female_voice`, `male_voice`).<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;• The voice samples inside each subfolder should follow the standard `.wav` format.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;• An example folder path would be `/alltalk_tts/voices/mynewvoice/` and this would be listed in the available voices list as `mynewvoice/`.<br>
This organization allows for easy selection and management of multiple voice samples while ensuring the system can correctly identify and utilize each voice. Manual CURL API requests would send the folder in the format `mynewvoice/`.
### 🟧 Where are the outputs stored & Automatic output wav file deletion
Voice outputs are stored in `/alltalk_tts/outputs/`. You can configure automatic maintenance deletion of old wav files by setting `Del WAV's older than` in the global settings.<br>
> When `Disabled`, your output wav files will be left untouched.<br>
> When set to a setting `1 Day` or greater, your output wav files older than that time period will be automatically deleted on start-up of AllTalk.<br>
### 🟧 Where are the models stored?
This extension will download the models to `/alltalk_tts/models/xtts/` folder.<br>
### 🟧 API Local, XTTSv2 Generation methods & Speed
These two methods both produce sound output in slightly different ways. XTTSv2 is the perferable method a it supports DeepSpeed, which, if you have a system capable of DeepSpeed genereation, can result in a 2-3x speed gain in generation.
### 🟧 Hindi Support on XTTS
Currently Hindi only works on XTTS model 2.0.3 and it has to be loaded as the API Local method.
""")
gr.Markdown("""
### 🟧 How do I create a new voice sample?
To create a new voice sample, you need to make a wav file that is `22050Hz`, `Mono`, `16 bit` and between 6 to 30 seconds long, though 8 to 10 seconds is usually good enough. The model can handle up to 30 second samples, however I've not noticed any improvement in voice output from much longer clips.<br><br>
You want to find a nice clear selection of audio, so lets say you wanted to clone your favourite celebrity. You may go looking for an interview where they are talking. Pay close attention to the audio you are listening to and trying to sample. Are there noises in the background, hiss on the soundtrack, a low humm, some quiet music playing or something? The better quality the audio the better the final TTS result. Don't forget, the AI that processes the sounds can hear everything in your sample and it will use them in the voice its trying to recreate.<br><br>
Try make your clip one of nice flowing speech, like the included example files. No big pauses, gaps or other sounds. Preferably a sample that the person you are trying to copy will show a little vocal range and emotion in their voice. Also, try to avoid a clip starting or ending with breathy sounds (breathing in/out etc).<br>
### 🟧 Editing your sample!
So, you've downloaded your favourite celebrity interview off YouTube, from here you need to chop it down to 6 to 30 seconds in length and resample it. If you need to clean it up, do audio processing, volume level changes etc, do this before down-sampling.<br><br>
Using the latest version of Audacity `select/highlight` your 6 to 30 second clip and:<br><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;• `Tracks` > `Resample to 22050Hz`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;• `Tracks` > `Mix` > `Stereo to Mono`<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;• `File` > `Export Audio` saving it as a `WAV` of `22050Hz`.<br><br>
Save your generated wav file in the `/alltalk_tts/voices/` folder.<br>
### 🟧 Why doesnt it sound like XXX Person?
Maybe you might be interested in trying Finetuning of the XTTS model. Otherwise, the reasons can be that you:<br>
> Didn't down-sample it as above.<br>
> Have a bad quality voice sample.<br>
> Try using the 2x different generation methods `API Local` and `XTTSv2 Local`, as they generate output in slightly different ways.<br>
Additionally, use the RVC pipeline with a matching voice model, however, some samples just never seem to work correctly, so maybe try a different sample. Always remember though, this is an AI model attempting to re-create a voice, so you will never get a 100% match.
""")
return app return app
+12 -1
View File
@@ -725,6 +725,16 @@
<option value="91">91</option> <option value="91">91</option>
<option value="90">90</option> <option value="90">90</option>
</select> </select>
<label for="whisperModel">WhisperV:</label>
<select id="whisperModel" name="whisperModel" class="fixed-size-dropdown">
<option value="large-v3" selected>Large-v3 (Default)</option>
<option value="tiny">Tiny</option>
<option value="base">Base</option>
<option value="small">Small</option>
<option value="medium">Medium</option>
<option value="turbo">Turbo</option>
<option value="large-v3-turbo">Large-v3-Turbo</option>
</select>
<div id="paginationControls"> <div id="paginationControls">
<button class="conditional-btn pagination-btn" id="prevPage">Previous</button> <button class="conditional-btn pagination-btn" id="prevPage">Previous</button>
<span id="pageIndicator">Page 1 of X</span> <span id="pageIndicator">Page 1 of X</span>
@@ -902,7 +912,8 @@
// If the server confirms the data was saved successfully, trigger analysis // If the server confirms the data was saved successfully, trigger analysis
if (saveData.message === "Data saved successfully") { if (saveData.message === "Data saved successfully") {
const accuracy = parseInt(document.getElementById('AnalyzeAccuracy').value) || 98; const accuracy = parseInt(document.getElementById('AnalyzeAccuracy').value) || 98;
const analyzeResponse = await fetch(`/api/trigger-analysis?threshold=${accuracy}`); const whisperModel = document.getElementById('whisperModel').value;
const analyzeResponse = await fetch(`/api/trigger-analysis?threshold=${accuracy}&whisper_model=${whisperModel}`);
const analyzeData = await analyzeResponse.json(); const analyzeData = await analyzeResponse.json();
if (analyzeData.summary.flagged_ids && analyzeData.summary.flagged_ids.length > 0) { if (analyzeData.summary.flagged_ids && analyzeData.summary.flagged_ids.length > 0) {
// Update the global problematicIds array with the new flagged IDs // Update the global problematicIds array with the new flagged IDs
+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("_"))
+1184
View File
File diff suppressed because it is too large. Load diff
+129 -46
View File
@@ -4,67 +4,150 @@
class FinetuneContent: class FinetuneContent:
"""CSS and help content for finetune.py""" """CSS and help content for finetune.py"""
custom_css = """ custom_css = """
/* Status indicators and labels */ /* Add this to your existing CSS */
.status-label { .gradio-container .prose {
font-size: 1.2em; max-width: none !important;
font-weight: bold; padding: 0.5rem !important; /* Reduced padding */
padding: 10px; margin: 0 !important;
border-radius: 5px;
margin: 10px 0;
} }
.status-indicator { .custom-markdown div {
padding: 5px 10px; border: none !important; /* Remove the inner border */
border-radius: 3px; margin-top: 0 !important; /* Remove top margin */
font-weight: bold; margin-bottom: 0 !important; /* Remove bottom margin */
padding-top: 0 !important; /* Remove top padding */
padding-bottom: 0 !important; /* Remove bottom padding */
} }
/* Layout components */ /* Update the existing custom-markdown class */
.status-box { .custom-markdown {
display: flex; font-size: 15px !important;
align-items: center; line-height: 1.6 !important;
padding: 0.5rem; color: var(--body-text-color) !important;
margin-bottom: 0.5rem; background-color: var(--background-fill-primary) !important;
border-radius: 4px; border: 1px solid var(--border-color-primary) !important;
background: var(--background-fill-secondary); border-radius: 8px !important;
padding: 0.5rem !important;
margin: 0 !important; /* Changed from 1rem 0 to 0 */
max-width: 100% !important;
box-sizing: border-box !important;
/* Default text color for all content (grey) */
color: rgba(156, 163, 175, 1) !important; /* Adjust this grey value to match your interface */
} }
.status-group { /* Make headings white */
margin-bottom: 1rem; .custom-markdown h1,
padding: 1rem; .custom-markdown h2,
border-radius: 8px; .custom-markdown h3,
background: var(--background-fill-primary); .custom-markdown h4,
.custom-markdown h5,
.custom-markdown h6 {
color: var(--heading-text-color, var(--body-text-color)) !important;
font-weight: 600 !important;
} }
/* Help section styling */ /* Keep all other elements in the grey color */
.help-section { .custom-markdown p,
margin-top: 2rem; .custom-markdown li,
border-top: 1px solid var(--border-color-primary); .custom-markdown ul,
padding-top: 1rem; .custom-markdown ol {
color: rgba(156, 163, 175, 1) !important; /* Same grey as the base text */
} }
.help-accordion { /* Additional targeting for any wrapping elements */
margin-bottom: 0.5rem; .gradio-container .prose > * {
margin: 0 !important;
padding: 0 !important;
} }
/* Ensure consistent font size in accordions */ /* Update the list item spacing in your existing CSS */
.gradio-container .prose, .custom-markdown li {
.gradio-container .prose p, font-size: 0.95rem !important;
.gradio-container .prose ul, margin-bottom: 0.2rem !important; /* Reduced from 0.5rem to 0.3rem */
.gradio-container .prose ol,
.gradio-container .prose ul li,
.gradio-container .prose ol li {
font-size: 1.02em !important; /* Adjust to the preferred size, e.g., 1em or 14px */
line-height: 1.3; /* Improves readability */
} }
/* Grid layout */ /* Add specific styling for definition-style lists (like your Default, Recommendation, Tip items) */
.check-grid { .custom-markdown li p {
display: grid; margin: 0 !important; /* Remove paragraph margins within list items */
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
margin-bottom: 1rem;
} }
/* If you need even tighter spacing for specific types of lists */
.custom-markdown li + li {
margin-top: 0.2rem !important; /* Space between consecutive list items */
}
/* Ensure nested lists maintain proper spacing */
.custom-markdown li > ul,
.custom-markdown li > ol {
margin: 0.2rem 0 0.2rem 1rem !important; /* Reduced from 0.5rem */
}
/* Consistent heading styles */
.custom-markdown h2 {
font-size: 1.2rem !important; /* Fixed size relative to root */
font-weight: 600 !important;
margin: 1.5rem 0 1rem !important;
color: var(--heading-text-color, var(--body-text-color)) !important;
border-bottom: 1px solid var(--border-color-primary) !important;
padding-bottom: 0.5rem !important;
}
/* First paragraph styling */
.custom-markdown p:first-of-type {
font-size: 0.95rem !important; /* Match base size */
font-weight: 400 !important;
margin-bottom: 1rem !important;
}
/* Regular paragraphs */
.custom-markdown p {
font-size: 0.95rem !important;
margin: 0.8rem 0 !important;
}
/* List styling */
.custom-markdown ul,
.custom-markdown ol {
margin: 0.8rem 0 !important;
padding-left: 1.5rem !important;
}
/* Code styling */
.custom-markdown code {
font-family: ui-monospace, monospace !important;
background-color: var(--background-fill-secondary) !important;
padding: 0.2rem 0.4rem !important;
border-radius: 4px !important;
font-size: 0.8rem !important; /* Slightly smaller than regular text */
color: var(--body-text-color) !important;
}
/* Add styles for bold and emphasis */
.custom-markdown strong {
font-weight: 600 !important;
color: var(--body-text-color) !important;
}
.custom-markdown em {
font-style: italic !important;
}
/* Ensure both columns take equal width */
.gradio-row > div {
flex: 1 1 50% !important;
min-width: 0 !important; /* Prevents flex items from overflowing */
}
.small-file-upload {
min-height: 200px;
max-height: 200px;
}
.small-file-upload2 {
min-height: 90px;
max-height: 90px;
}
""" """
STEP1_QUICKSTART = """ STEP1_QUICKSTART = """
+1860 -1068
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
Please see the XTTS Engine help for details of using multi-voice sets or JSON latents
@@ -0,0 +1 @@
Please see the XTTS Engine help for details of using multi-voice sets or JSON latents