Updates to TTS Engines

This commit is contained in:
erew123 authored and GitHub committed 2024-11-22 07:32:38 +00:00
1 parent 7e73053fd7
commit 1a5c10710d
19 files changed
+6420 -2572

No files matched your search

@@ -1,40 +1,33 @@
{
"first_start_model": "en_GB-jenny_dioco-medium",
"models": [
{
"model_name": "ar_JO-kareem-low",
"files_to_download": [
"https://huggingface.co/rhasspy/piper-voices/resolve/main/ar/ar_JO/kareem/low/ar_JO-kareem-low.onnx?download=true",
"https://huggingface.co/rhasspy/piper-voices/resolve/main/ar/ar_JO/kareem/low/ar_JO-kareem-low.onnx.json?download=true"
]
},
{
"model_name": "ar_JO-kareem-medium",
"files_to_download": [
"https://huggingface.co/rhasspy/piper-voices/resolve/main/ar/ar_JO/kareem/medium/ar_JO-kareem-medium.onnx?download=true",
"https://huggingface.co/rhasspy/piper-voices/resolve/main/ar/ar_JO/kareem/medium/ar_JO-kareem-medium.onnx.json?download=true"
]
},
{
"model_name": "vi_VN-vivos-x_low",
"files_to_download": [
"https://huggingface.co/rhasspy/piper-voices/resolve/main/vi/vi_VN/vivos/x_low/vi_VN-vivos-x_low.onnx?download=true",
"https://huggingface.co/rhasspy/piper-voices/resolve/main/vi/vi_VN/vivos/x_low/vi_VN-vivos-x_low.onnx.json?download=true"
]
},
{
"model_name": "zh_CN-huayan-medium",
"files_to_download": [
"https://huggingface.co/rhasspy/piper-voices/resolve/main/zh/zh_CN/huayan/medium/zh_CN-huayan-medium.onnx?download=true",
"https://huggingface.co/rhasspy/piper-voices/resolve/main/zh/zh_CN/huayan/medium/zh_CN-huayan-medium.onnx.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"
]
}
]
}
{
"first_start_model": "xttsv2_2.0.3",
"models": [
{
"model_name": "xttsv2_2.0.3",
"folder_path": "xttsv2_2.0.3",
"files_to_download": {
"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",
"dvae.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/dvae.pth?download=true",
"mel_stats.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/mel_stats.pth?download=true",
"speakers_xtts.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/speakers_xtts.pth?download=true",
"vocab.json": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/vocab.json?download=true"
}
},
{
"model_name": "xttsv2_2.0.2",
"folder_path": "xttsv2_2.0.2",
"files_to_download": {
"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",
"dvae.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/dvae.pth?download=true",
"mel_stats.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/mel_stats.pth?download=true",
"speakers_xtts.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/speakers_xtts.pth?download=true",
"vocab.json": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/vocab.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,42 +1,42 @@
{
"model_details": {
"manufacturer_name": "MyTTSEngine",
"manufacturer_website": "https://github.com/MyTTSEngine",
"model_description": "A description and detail about the TTS Engine"
},
"model_capabilties": {
"audio_format": "wav",
"deepspeed_capable": false,
"generationspeed_capable": false,
"languages_capable": false,
"lowvram_capable": false,
"multimodel_capable": false,
"repetitionpenalty_capable": false,
"streaming_capable": false,
"temperature_capable": false,
"multivoice_capable": false,
"pitch_capable": false,
"windows_capable": true,
"linux_capable": true,
"mac_capable": true
},
"settings": {
"def_character_voice": "defaultvoice.wav",
"def_narrator_voice": "defaultvoice.wav",
"deepspeed_enabled": false,
"engine_installed": true,
"generationspeed_set": 1,
"lowvram_enabled": false,
"pitch_set": 0,
"repetitionpenalty_set": 10,
"temperature_set": 0.75
},
"openai_voices": {
"alloy": "defaultvoice.wav",
"echo": "defaultvoice.wav",
"fable": "defaultvoice.wav",
"nova": "defaultvoice.wav",
"onyx": "defaultvoice.wav",
"shimmer": "defaultvoice.wav"
}
}
{
"model_details": {
"manufacturer_name": "MYNEWTTS",
"manufacturer_website": "https://something here",
"model_description": "A bit of blurb about the manufacturer/TTS engine"
},
"model_capabilties": {
"audio_format": "wav",
"deepspeed_capable": true,
"generationspeed_capable": true,
"languages_capable": true,
"lowvram_capable": true,
"multimodel_capable": true,
"repetitionpenalty_capable": true,
"streaming_capable": true,
"temperature_capable": true,
"multivoice_capable": true,
"pitch_capable": false,
"windows_capable": true,
"linux_capable": true,
"mac_capable": true
},
"settings": {
"def_character_voice": "female_01.wav",
"def_narrator_voice": "male_01.wav",
"deepspeed_enabled": true,
"engine_installed": true,
"generationspeed_set": 1,
"lowvram_enabled": false,
"pitch_set": 0,
"repetitionpenalty_set": 10,
"temperature_set": 0.75
},
"openai_voices": {
"alloy": "female_01.wav",
"echo": "female_01.wav",
"fable": "female_01.wav",
"nova": "female_01.wav",
"onyx": "female_01.wav",
"shimmer": "female_01.wav"
}
}
@@ -1,308 +1,290 @@
import os
import json
import requests
import gradio as gr
from tqdm import tqdm
from pathlib import Path
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
##########################################################################
# REQUIRED CHANGE #
# Populate the voices list, using the method specific to your TTS engine #
##########################################################################
# This function is responsible for populating the list of available voices for your TTS engine.
# 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.
# You should find/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`.
#
# 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
# engine's specific requirements. Typically this is the same code as will be in your model_engine.py file.
#
# For example, if your engine has a dedicated API or configuration file for managing voices, you should modify this
# function to interact with that API or read from that configuration file.
#
# 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.
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
return voices
######################################################
# REQUIRED CHANGE #
# Imports and saves the TTS engine-specific settings #
######################################################
# This function is responsible for importing and saving the settings specific to your TTS engine.
# You need to make the following change:
#
# 1. Change the name of the function `xxxx_model_update_settings` to match your engine's name.
# For example, if your engine is named "mytts", the function should be named `mytts_model_update_settings`.
#
# After making this change, the function will load the model settings from a JSON file, update the settings and voice
# 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.
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):
# Load the model_config_data from the JSON file
with open(os.path.join(this_dir, "model_settings.json"), "r") as f:
model_config_data = json.load(f)
# 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_narrator_voice"] = def_narrator_voice_gr
model_config_data["openai_voices"]["alloy"] = alloy_gr
model_config_data["openai_voices"]["echo"] = echo_gr
model_config_data["openai_voices"]["fable"] = fable_gr
model_config_data["openai_voices"]["nova"] = nova_gr
model_config_data["openai_voices"]["onyx"] = onyx_gr
model_config_data["openai_voices"]["shimmer"] = shimmer_gr
model_config_data["settings"]["lowvram_enabled"] = lowvram_enabled_gr == "Enabled"
model_config_data["settings"]["deepspeed_enabled"] = deepspeed_enabled_gr == "Enabled"
model_config_data["settings"]["temperature_set"] = temperature_set_gr
model_config_data["settings"]["repetitionpenalty_set"] = repetitionpenalty_set_gr
model_config_data["settings"]["pitch_set"] = pitch_set_gr
model_config_data["settings"]["generationspeed_set"] = generationspeed_set_gr
# Save the updated model_config_data to the JSON file
with open(os.path.join(this_dir, "model_settings.json"), "w") as f:
json.dump(model_config_data, f, indent=4)
return "Settings updated successfully!"
#######################################################
# REQUIRED CHANGE #
# Sets up the engine-specific settings page in Gradio #
#######################################################
# This function sets up the Gradio interface for the settings page specific to your TTS engine.
# You need to make the following changes:
#
# 1. Change the name of the function `xxxx_model_alltalk_settings` to match your engine's name.
# For example, if your engine is named "mytts", the function should be named `mytts_model_alltalk_settings`.
#
# 2. Change the name of the `submit_button.click` function call to match the name you gave to the function
# that imports and saves your engine's settings (the function you modified above).
#
# 3. Change the name of the `voice_list` function call to match the name of the function that lists
# the available voices for your TTS engine.
#
# 4. Change the 'title' of the `gr.Blocks` to match your engine's name e.g. title="mytts TTS"
#
# 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.
def myttsengine_model_alltalk_settings(model_config_data):
features_list = model_config_data['model_capabilties']
voice_list = myttsengine_voices_file_list()
with gr.Blocks(title="myttsengine TTS") as app:
with gr.Tab("Default Settings"):
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"])
deepspeed_enabled_gr = gr.Radio(choices={"Enabled": "true", "Disabled": "false"}, label="DeepSpeed Activate" if model_config_data["model_capabilties"]["deepspeed_capable"] else "DeepSpeed N/A", value="Enabled" if model_config_data["settings"]["deepspeed_enabled"] else "Disabled", interactive=model_config_data["model_capabilties"]["deepspeed_capable"])
temperature_set_gr = gr.Slider(value=float(model_config_data["settings"]["temperature_set"]), minimum=0, maximum=1, step=0.05, label="Temperature" if model_config_data["model_capabilties"]["temperature_capable"] else "Temperature N/A", interactive=model_config_data["model_capabilties"]["temperature_capable"])
repetitionpenalty_set_gr = gr.Slider(value=float(model_config_data["settings"]["repetitionpenalty_set"]), minimum=1, maximum=20, step=1, label="Repetition Penalty" if model_config_data["model_capabilties"]["repetitionpenalty_capable"] else "Repetition N/A", interactive=model_config_data["model_capabilties"]["repetitionpenalty_capable"])
pitch_set_gr = gr.Slider(value=float(model_config_data["settings"]["pitch_set"]), minimum=-10, maximum=10, step=1, label="Pitch" if model_config_data["model_capabilties"]["pitch_capable"] else "Pitch N/A", interactive=model_config_data["model_capabilties"]["pitch_capable"])
generationspeed_set_gr = gr.Slider(value=float(model_config_data["settings"]["generationspeed_set"]), minimum=0.25, maximum=2.00, step=0.25, label="Speed" if model_config_data["model_capabilties"]["generationspeed_capable"] else "Speed N/A", interactive=model_config_data["model_capabilties"]["generationspeed_capable"])
with gr.Row():
with gr.Column():
gr.Markdown("### OpenAI Voice Mappings")
with gr.Group():
with gr.Row():
alloy_gr = gr.Dropdown(value=model_config_data["openai_voices"]["alloy"], label="Alloy", choices=voice_list, allow_custom_value=True)
echo_gr = gr.Dropdown(value=model_config_data["openai_voices"]["echo"], label="Echo", choices=voice_list, allow_custom_value=True)
with gr.Row():
fable_gr = gr.Dropdown(value=model_config_data["openai_voices"]["fable"], label="Fable", choices=voice_list, allow_custom_value=True)
nova_gr = gr.Dropdown(value=model_config_data["openai_voices"]["nova"], label="Nova", choices=voice_list, allow_custom_value=True)
with gr.Row():
onyx_gr = gr.Dropdown(value=model_config_data["openai_voices"]["onyx"], label="Onyx", choices=voice_list, allow_custom_value=True)
shimmer_gr = gr.Dropdown(value=model_config_data["openai_voices"]["shimmer"], label="Shimmer", choices=voice_list, allow_custom_value=True)
with gr.Column():
gr.Markdown("### Default Voices")
with gr.Row():
def_character_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_character_voice"], label="Default/Character 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.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.")
with gr.Row():
submit_button = gr.Button("Update Settings")
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)
###########################################################################################
# Do not change this section apart from "TTS Engine Name" value to match your engine name #
###########################################################################################
with gr.Tab("Engine Information"):
with gr.Row():
with gr.Group():
gr.Textbox(label="Manufacturer Name", value=model_config_data['model_details']['manufacturer_name'], interactive=False)
gr.Textbox(label="Manufacturer Website/TTS Engine Support", value=model_config_data['model_details']['manufacturer_website'], interactive=False)
gr.Textbox(label="Engine/Model Description", value=model_config_data['model_details']['model_description'], interactive=False, lines=13)
with gr.Column():
with gr.Row():
gr.Textbox(label="DeepSpeed Capable", value='Yes' if features_list['deepspeed_capable'] else 'No', interactive=False)
gr.Textbox(label="Pitch Capable", value='Yes' if features_list['pitch_capable'] else 'No', interactive=False)
gr.Textbox(label="Generation Speed Capable", value='Yes' if features_list['generationspeed_capable'] else 'No', interactive=False)
with gr.Row():
gr.Textbox(label="Repetition Penalty Capable", value='Yes' if features_list['repetitionpenalty_capable'] else 'No', interactive=False)
gr.Textbox(label="Multi Languages Capable", value='Yes' if features_list['languages_capable'] else 'No', interactive=False)
gr.Textbox(label="Streaming Capable", value='Yes' if features_list['streaming_capable'] else 'No', interactive=False)
with gr.Row():
gr.Textbox(label="Low VRAM Capable", value='Yes' if features_list['lowvram_capable'] else 'No', interactive=False)
gr.Textbox(label="Temperature Capable", value='Yes' if features_list['temperature_capable'] else 'No', interactive=False)
gr.Textbox(label="Multi Model Capable Engine", value='Yes' if features_list['multimodel_capable'] else 'No', interactive=False)
with gr.Row():
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="TTS Engine Name", value="myttsengine", interactive=False)
with gr.Row():
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="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False)
with gr.Row():
gr.Markdown("""
#### 🟧 DeepSpeed Capable
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.
#### 🟧 Pitch Capable
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.
#### 🟧 Generation Speed Capable
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.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):
# 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", "myttsengine")
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!"
with gr.Row():
download_status = gr.Textbox(label="Download Status")
download_button.click(download_model, inputs=model_dropdown, outputs=download_status)
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"])
if all_files_exists:
return [gr.update(visible=True), gr.update(visible=True), gr.update(visible=True)]
else:
return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)]
def confirm_download(model_name):
download_status_text = download_model(model_name, force_download=True)
return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), download_status_text]
def cancel_download():
return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), ""]
with gr.Row():
confirm_button = gr.Button("Download Anyway", 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])
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])
###################################################################################################
# REQUIRED CHANGE #
# Add any engine specific help, bugs, issues, operating system specifc requirements/setup in here #
# Please use Markdown format, so gr.Markdown() with your markdown inside it. #
###################################################################################################
with gr.Tab("Engine Help"):
with gr.Row():
using_voice_samples = """
IF YOU WANT TO ADD HELP INSTRUCTIONS FOR THE MODEL, ADD THEM IN HERE USING MARKDOWN
"""
gr.Markdown(using_voice_samples)
return app
################################
# REQUIRED CHANGE #
# Sets up the Gradio interface #
################################
# This function sets up the Gradio interface for your TTS engine's settings page.
# You need to change the name of the function calls to match the names you set in the functions above.
#
# Specifically, you need to update the following:
#
# 1. The name of the function `xxxx_at_gradio_settings_page` to match your engine's name.
# For example, if your engine is named "mytts", the function should be named `mytts_at_gradio_settings_page`.
#
# 2. The name of the function call `xxxx_model_alltalk_settings(model_config_data)`.
# This should match the name you gave to the function that sets up the engine-specific settings page in Gradio.
# If you named that function `mytts_model_alltalk_settings`, then the call should be:
# `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.
def myttsengine_at_gradio_settings_page(model_config_data):
app = myttsengine_model_alltalk_settings(model_config_data)
return app
def myttsengine_at_gradio_settings_page(model_config_data):
app = myttsengine_model_alltalk_settings(model_config_data)
return app
import os
import json
import requests
import gradio as gr
from tqdm import tqdm
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.
main_dir = Path(__file__).parent.parent.parent.parent.resolve() # Sets up self.main_dir as a variable for the folder AllTalk is running in
##########################################################################
# REQUIRED CHANGE #
# Populate the voices list, using the method specific to your TTS engine #
##########################################################################
# This function is responsible for populating the list of available voices for your TTS engine.
# 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.
# 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`.
#
# 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.
#
# For example, if your engine has a dedicated API or configuration file for managing voices, you should modify this
# function to interact with that API or read from that configuration file.
#
# 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.
def xtts_voices_file_list():
directory = main_dir / "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 #
# Imports and saves the TTS engine-specific settings #
######################################################
# This function is responsible for importing and saving the settings specific to your TTS engine.
# You need to make the following change:
#
# 1. Change the name of the function `xxxx_model_update_settings` to match your engine's name.
# For example, if your engine is named "mytts", the function should be named `mytts_model_update_settings`.
#
# After making this change, the function will load the model settings from a JSON file, update the settings and voice
# 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.
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
with open(os.path.join(this_dir, "model_settings.json"), "r") as f:
model_config_data = json.load(f)
# 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_narrator_voice"] = def_narrator_voice_gr
model_config_data["openai_voices"]["alloy"] = alloy_gr
model_config_data["openai_voices"]["echo"] = echo_gr
model_config_data["openai_voices"]["fable"] = fable_gr
model_config_data["openai_voices"]["nova"] = nova_gr
model_config_data["openai_voices"]["onyx"] = onyx_gr
model_config_data["openai_voices"]["shimmer"] = shimmer_gr
model_config_data["settings"]["lowvram_enabled"] = lowvram_enabled_gr == "Enabled"
model_config_data["settings"]["deepspeed_enabled"] = deepspeed_enabled_gr == "Enabled"
model_config_data["settings"]["temperature_set"] = temperature_set_gr
model_config_data["settings"]["repetitionpenalty_set"] = repetitionpenalty_set_gr
model_config_data["settings"]["pitch_set"] = pitch_set_gr
model_config_data["settings"]["generationspeed_set"] = generationspeed_set_gr
# Save the updated model_config_data to the JSON file
with open(os.path.join(this_dir, "model_settings.json"), "w") as f:
json.dump(model_config_data, f, indent=4)
return "Settings updated successfully!"
#######################################################
# REQUIRED CHANGE #
# Sets up the engine-specific settings page in Gradio #
#######################################################
# This function sets up the Gradio interface for the settings page specific to your TTS engine.
# You need to make the following changes:
#
# 1. Change the name of the function `xxxx_model_alltalk_settings` to match your engine's name.
# For example, if your engine is named "mytts", the function should be named `mytts_model_alltalk_settings`.
#
# 2. Change the name of the `submit_button.click` function call to match the name you gave to the function
# that imports and saves your engine's settings (the function you modified above).
#
# 3. Change the name of the `voice_list` function call to match the name of the function that lists
# the available voices for your TTS engine.
#
# 4. Change the 'title' of the `gr.Blocks` to match your engine's name e.g. title="mytts TTS"
#
# 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.
def xtts_model_alltalk_settings(model_config_data):
features_list = model_config_data['model_capabilties']
voice_list = xtts_voices_file_list()
with gr.Blocks(title="Xtts TTS", analytics_enabled=False) as app:
with gr.Tab("Default Settings"):
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"])
deepspeed_enabled_gr = gr.Radio(choices={"Enabled": "true", "Disabled": "false"}, label="DeepSpeed Activate" if model_config_data["model_capabilties"]["deepspeed_capable"] else "DeepSpeed N/A", value="Enabled" if model_config_data["settings"]["deepspeed_enabled"] else "Disabled", interactive=model_config_data["model_capabilties"]["deepspeed_capable"])
temperature_set_gr = gr.Slider(value=float(model_config_data["settings"]["temperature_set"]), minimum=0, maximum=1, step=0.05, label="Temperature" if model_config_data["model_capabilties"]["temperature_capable"] else "Temperature N/A", interactive=model_config_data["model_capabilties"]["temperature_capable"])
repetitionpenalty_set_gr = gr.Slider(value=float(model_config_data["settings"]["repetitionpenalty_set"]), minimum=1, maximum=20, step=1, label="Repetition Penalty" if model_config_data["model_capabilties"]["repetitionpenalty_capable"] else "Repetition N/A", interactive=model_config_data["model_capabilties"]["repetitionpenalty_capable"])
pitch_set_gr = gr.Slider(value=float(model_config_data["settings"]["pitch_set"]), minimum=-10, maximum=10, step=1, label="Pitch" if model_config_data["model_capabilties"]["pitch_capable"] else "Pitch N/A", interactive=model_config_data["model_capabilties"]["pitch_capable"])
generationspeed_set_gr = gr.Slider(value=float(model_config_data["settings"]["generationspeed_set"]), minimum=0.25, maximum=2.00, step=0.25, label="Speed" if model_config_data["model_capabilties"]["generationspeed_capable"] else "Speed N/A", interactive=model_config_data["model_capabilties"]["generationspeed_capable"])
with gr.Row():
with gr.Column():
gr.Markdown("### OpenAI Voice Mappings")
with gr.Group():
with gr.Row():
alloy_gr = gr.Dropdown(value=model_config_data["openai_voices"]["alloy"], label="Alloy", choices=voice_list, allow_custom_value=True)
echo_gr = gr.Dropdown(value=model_config_data["openai_voices"]["echo"], label="Echo", choices=voice_list, allow_custom_value=True)
with gr.Row():
fable_gr = gr.Dropdown(value=model_config_data["openai_voices"]["fable"], label="Fable", choices=voice_list, allow_custom_value=True)
nova_gr = gr.Dropdown(value=model_config_data["openai_voices"]["nova"], label="Nova", choices=voice_list, allow_custom_value=True)
with gr.Row():
onyx_gr = gr.Dropdown(value=model_config_data["openai_voices"]["onyx"], label="Onyx", choices=voice_list, allow_custom_value=True)
shimmer_gr = gr.Dropdown(value=model_config_data["openai_voices"]["shimmer"], label="Shimmer", choices=voice_list, allow_custom_value=True)
with gr.Column():
gr.Markdown("### Default Voices")
with gr.Row():
def_character_voice_gr = gr.Dropdown(value=model_config_data["settings"]["def_character_voice"], label="Default/Character 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.Row():
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():
submit_button = gr.Button("Update Settings")
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)
###########################################################################################
# Do not change this section apart from "TTS Engine Name" value to match your engine name #
###########################################################################################
with gr.Tab("Engine Information"):
with gr.Row():
with gr.Group():
gr.Textbox(label="Manufacturer Name", value=model_config_data['model_details']['manufacturer_name'], interactive=False)
gr.Textbox(label="Manufacturer Website/TTS Engine Support", value=model_config_data['model_details']['manufacturer_website'], interactive=False)
gr.Textbox(label="Engine/Model Description", value=model_config_data['model_details']['model_description'], interactive=False, lines=13)
with gr.Column():
with gr.Row():
gr.Textbox(label="DeepSpeed Capable", value='Yes' if features_list['deepspeed_capable'] else 'No', interactive=False)
gr.Textbox(label="Pitch Capable", value='Yes' if features_list['pitch_capable'] else 'No', interactive=False)
gr.Textbox(label="Generation Speed Capable", value='Yes' if features_list['generationspeed_capable'] else 'No', interactive=False)
with gr.Row():
gr.Textbox(label="Repetition Penalty Capable", value='Yes' if features_list['repetitionpenalty_capable'] else 'No', interactive=False)
gr.Textbox(label="Multi Languages Capable", value='Yes' if features_list['languages_capable'] else 'No', interactive=False)
gr.Textbox(label="Streaming Capable", value='Yes' if features_list['streaming_capable'] else 'No', interactive=False)
with gr.Row():
gr.Textbox(label="Low VRAM Capable", value='Yes' if features_list['lowvram_capable'] else 'No', interactive=False)
gr.Textbox(label="Temperature Capable", value='Yes' if features_list['temperature_capable'] else 'No', interactive=False)
gr.Textbox(label="Multi Model Capable Engine", value='Yes' if features_list['multimodel_capable'] else 'No', interactive=False)
with gr.Row():
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="TTS Engine Name", value="XTTS", interactive=False)
with gr.Row():
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="Mac Support", value='Yes' if features_list['mac_capable'] else 'No', interactive=False)
with gr.Row():
with gr.Accordion("HELP - 🔊 Understanding TTS Engine Capabilities", open=False):
with gr.Row():
gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION, elem_classes="custom-markdown")
with gr.Row():
gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.ENGINE_INFORMATION2, elem_classes="custom-markdown")
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")
with gr.Row():
download_status = gr.Textbox(label="Download Status")
def download_model(model_name):
# 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", "xtts", selected_model["folder_path"])
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, file)) for file in files_to_download)
if all_files_exists:
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 file, url in files_to_download.items():
file_path = os.path.join(folder_path, file)
if not os.path.exists(file_path):
print(f"Downloading {file}...")
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!"
download_button.click(download_model, inputs=model_dropdown, outputs=download_status)
def show_confirm_cancel(model_name):
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:
return [gr.update(visible=True), gr.update(visible=True), gr.update(visible=True)]
else:
return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)]
def confirm_download(model_name):
download_model(model_name)
return [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)]
with gr.Row():
confirm_button = gr.Button("Download Anyway", visible=False)
cancel_button = gr.Button("Cancel", visible=False)
download_button.click(show_confirm_cancel, model_dropdown, [confirm_button, download_button, cancel_button])
confirm_button.click(confirm_download, model_dropdown, [confirm_button, download_button, cancel_button])
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 #
# Add any engine specific help, bugs, issues, operating system specifc requirements/setup in here #
# Please use Markdown format, so gr.Markdown() with your markdown inside it. #
###################################################################################################
with gr.Tab("Engine Help"):
with gr.Row():
gr.Markdown(AllTalkHelpContent.HELP_PAGE, elem_classes="custom-markdown")
with gr.Row():
gr.Markdown(AllTalkHelpContent.HELP_PAGE1, elem_classes="custom-markdown")
gr.Markdown(AllTalkHelpContent.HELP_PAGE2, elem_classes="custom-markdown")
return app
################################
# REQUIRED CHANGE #
# Sets up the Gradio interface #
################################
# This function sets up the Gradio interface for your TTS engine's settings page.
# You need to change the name of the function calls to match the names you set in the functions above.
#
# Specifically, you need to update the following:
#
# 1. The name of the function `xxxx_at_gradio_settings_page` to match your engine's name.
# For example, if your engine is named "mytts", the function should be named `mytts_at_gradio_settings_page`.
#
# 2. The name of the function call `xxxx_model_alltalk_settings(model_config_data)`.
# This should match the name you gave to the function that sets up the engine-specific settings page in Gradio.
# If you named that function `mytts_model_alltalk_settings`, then the call should be:
# `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.
def xtts_at_gradio_settings_page(model_config_data):
app = xtts_model_alltalk_settings(model_config_data)
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