Merge branch 'erew123:alltalkbeta' into alltalkbeta
This commit is contained in:
21 files changed
+4848
-3383
No files matched your search
@@ -1,7 +1,11 @@
|
||||
# AllTalk TTS v2 BETA
|
||||
This is the BETA of v2. To be clear, that means they may well be bugs, issues, missing/incomplete documentation, a variety of potential problems etc (This is what BETA refers to in the software world for those whom dont know). This means you may need a bit of technical know how to deal with things that could come up and should only continue if you feel comfortable with that.
|
||||
|
||||
Github discussions on the BETA are [here in the discussion board](https://github.com/erew123/alltalk_tts/discussions/245)
|
||||
Github **discussions** on the BETA are [here in the discussion board](https://github.com/erew123/alltalk_tts/discussions/245)
|
||||
|
||||
For **Issues/Bugs/Support**, please open an issue ticket [here in the issues area](https://github.com/erew123/alltalk_tts/issues)
|
||||
|
||||
**Please note, my available time has become VERY limited due to unexpected family commitments. So please DYOR and refer to the TTS manufacturer (listed in the interface) for issues with their TTS engines.**
|
||||
|
||||
#### If you are going to run the BETA, please read all the info below....
|
||||
|
||||
@@ -20,6 +24,7 @@ Please go see [here](https://github.com/erew123/alltalk_tts/discussions/237)
|
||||
- FYI there is no limit on how many XTTS models AllTalk will now find/work with.
|
||||
- AllTalk starts up on 0.0.0.0, meaning it will bind to ALL available IP addresses. There is no setting its IP address any more.
|
||||
- Updated Coqui TTS engine.
|
||||
- XTTS multiple audio sample TTS generation to improve voice reproduction https://github.com/erew123/alltalk_tts/commit/b7aa3a7c5c8df260edede52dd1b31a7b40d9b202
|
||||
- Gradio web interface (see the screenshots)
|
||||
- Retrieval based Voice Conversion, AKA, RVC voice Pipeline, re-written to work on Python 3.11.
|
||||
- TTS Generator will now use any TTS engine.
|
||||
@@ -72,8 +77,12 @@ Quick setup scripts are available for users on Windows 10/11 and Linux. Instruct
|
||||
- Ensure that **Git** is installed on your system as it is required for cloning the repository. If you do not have Git installed, visit [**Git's official website**](https://git-scm.com/downloads) to download and install it.
|
||||
- **Important**: Do not use dashes or spaces in your folder path (e.g. avoid `/my folder-is-this/alltalk_tts-main`) as this causes issues with Python.
|
||||
|
||||
### **NOTE. IF YOU HAVE AN EXISTING ALLTALK INSTALL** this will want to create a folder called `alltalk_tts` so you will need to re-name your old `alltalk_tts` to something else OR put this in a different folder/location.
|
||||
### **NOTE**. I am not saying this is a over-the-top of an old alltalk upgrade ATM. It needs the Python environment rebuilding, hence a fresh install is needed for now.
|
||||
#### **NOTE. IF YOU HAVE AN EXISTING ALLTALK INSTALL** this will want to create a folder called `alltalk_tts` so you will need to re-name your old `alltalk_tts` to something else OR put this in a different folder/location.
|
||||
#### **NOTE**. I am not saying this is a over-the-top of an old alltalk upgrade ATM. It needs the Python environment rebuilding, hence a fresh install is needed for now.
|
||||
|
||||
---
|
||||
#### Python/PIP has recently made changes to the package installer and I have/am doing what I can to keep the requirements files working, however, this is a complicated time to say the least as some external requirements change and this can cause installation issues. Please raise a ticket if you have an error that a module is missing.
|
||||
---
|
||||
|
||||
<details>
|
||||
<summary>QUICK SETUP - Text-Generation-webui</summary>
|
||||
|
||||
+207
-32
@@ -139,6 +139,7 @@ goto StandaloneMenu
|
||||
:InstallNvidiaTextGen
|
||||
pip install -r system\requirements\requirements_textgen.txt
|
||||
pip install -r system\requirements\requirements_textgen2.txt
|
||||
pip install -r system\requirements\requirements_parler.txt
|
||||
echo ** Faiss **
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" install -y pytorch::faiss-cpu
|
||||
echo ** FFmpeg **
|
||||
@@ -398,24 +399,202 @@ if not exist "%INSTALL_ENV_DIR%\python.exe" ( echo. && echo Conda environment is
|
||||
@rem activate installer env
|
||||
call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%" || ( echo. && echo Miniconda hook not found. && goto end )
|
||||
rem Install required packages
|
||||
echo ** PyTorch 2.2.1 **
|
||||
|
||||
:install_pytorch
|
||||
echo ** Installing PyTorch 2.2.1 **
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" install -y pytorch==2.2.1 torchvision==0.17.1 torchaudio==2.2.1 pytorch-cuda=12.1 -c pytorch -c nvidia
|
||||
echo ** Faiss **
|
||||
echo.
|
||||
if errorlevel 1 (
|
||||
echo PyTorch installation failed, errorlevel was %errorlevel%. This could be caused by:
|
||||
echo.
|
||||
echo 1. Internet connection issues/unable to download PyTorch from Conda's website.
|
||||
echo 2. Disk space related issues - Check your disk space on this drive.
|
||||
echo 3. Incorrect or missing Conda environment - Restart installation.
|
||||
echo 4. Permissions issues - Check you have enough rights on this system.
|
||||
echo 5. Firewall or proxy settings blocking access to Conda's servers.
|
||||
echo 6. Antivirus or security software interference.
|
||||
echo 7. Other issues not mentioned above.
|
||||
echo.
|
||||
choice /C YN /M "Do you want to retry the Pytorch installation?"
|
||||
if errorlevel 1 goto install_pytorch
|
||||
if errorlevel 2 goto End
|
||||
) else (
|
||||
echo PyTorch installation was successful.
|
||||
echo.
|
||||
)
|
||||
|
||||
:install_faiss
|
||||
echo ** Installing Faiss **
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" install -y pytorch::faiss-cpu
|
||||
echo ** FFmpeg **
|
||||
echo.
|
||||
if errorlevel 1 (
|
||||
echo Faiss installation failed, errorlevel was %errorlevel%. This could be caused by:
|
||||
echo.
|
||||
echo 1. Internet connection issues/unable to download Faiss from Conda's website.
|
||||
echo 2. Disk space related issues - Check your disk space on this drive.
|
||||
echo 3. Incorrect or missing Conda environment - Restart installation.
|
||||
echo 4. Permissions issues - Check you have enough rights on this system.
|
||||
echo 5. Firewall or proxy settings blocking access to Conda's servers.
|
||||
echo 6. Antivirus or security software interference.
|
||||
echo 7. Other issues not mentioned above.
|
||||
echo.
|
||||
choice /C YN /M "Do you want to retry the Faiss installation?"
|
||||
if errorlevel 1 goto install_faiss
|
||||
if errorlevel 2 goto End
|
||||
) else (
|
||||
echo Faiss installation was successful.
|
||||
echo.
|
||||
)
|
||||
|
||||
:install_ffmpeg
|
||||
echo ** Installing FFmpeg **
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" install -y conda-forge::ffmpeg
|
||||
echo.
|
||||
if errorlevel 1 (
|
||||
echo FFmpeg installation failed, errorlevel was %errorlevel%. This could be caused by:
|
||||
echo.
|
||||
echo 1. Internet connection issues/unable to download FFmpeg from Conda's website.
|
||||
echo 2. Disk space related issues - Check your disk space on this drive.
|
||||
echo 3. Incorrect or missing Conda environment - Restart installation.
|
||||
echo 4. Permissions issues - Check you have enough rights on this system.
|
||||
echo 5. Firewall or proxy settings blocking access to Conda's servers.
|
||||
echo 6. Antivirus or security software interference.
|
||||
echo 7. Other issues not mentioned above.
|
||||
echo.
|
||||
choice /C YN /M "Do you want to retry the FFmpeg installation?"
|
||||
if errorlevel 1 goto install_ffmpeg
|
||||
if errorlevel 2 goto End
|
||||
) else (
|
||||
echo FFmpeg installation was successful.
|
||||
echo.
|
||||
)
|
||||
|
||||
echo ** Requirements file **
|
||||
pip install -r system\requirements\requirements_standalone.txt
|
||||
echo ** Gradio Update **
|
||||
pip install --upgrade gradio==4.32.2
|
||||
echo ** DeepSpeed **
|
||||
curl -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-14.0/deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
echo Installing DeepSpeed...
|
||||
pip install deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
del deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
echo ** Clean Environment **
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" clean --all --force-pkgs-dirs -y
|
||||
echo.
|
||||
|
||||
:update_gradio
|
||||
echo ** Updating Gradio **
|
||||
pip install --upgrade gradio==4.32.2
|
||||
echo.
|
||||
if errorlevel 1 (
|
||||
echo Gradio update failed, errorlevel was %errorlevel%. This could be caused by:
|
||||
echo.
|
||||
echo 1. Internet connection issues/unable to download Gradio from PyPI.
|
||||
echo 2. Disk space related issues - Check your disk space on this drive.
|
||||
echo 3. Incorrect or missing Python environment - Restart installation.
|
||||
echo 4. Permissions issues - Check you have enough rights on this system.
|
||||
echo 5. Firewall or proxy settings blocking access to PyPI servers.
|
||||
echo 6. Antivirus or security software interference.
|
||||
echo 7. Other issues not mentioned above.
|
||||
echo.
|
||||
choice /C YN /M "Do you want to retry the Gradio update?"
|
||||
if errorlevel 1 goto update_gradio
|
||||
if errorlevel 2 goto End
|
||||
) else (
|
||||
echo Gradio update was successful.
|
||||
echo.
|
||||
)
|
||||
|
||||
:install_deepspeed
|
||||
echo ** Downloading DeepSpeed **
|
||||
curl -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-14.0/deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
echo.
|
||||
if errorlevel 1 (
|
||||
echo DeepSpeed download failed, errorlevel was %errorlevel%. This could be caused by:
|
||||
echo.
|
||||
echo 1. Internet connection issues/unable to reach GitHub.
|
||||
echo 2. Disk space related issues - Check your disk space on this drive.
|
||||
echo 3. Permissions issues - Check you have enough rights on this system.
|
||||
echo 4. Firewall or proxy settings blocking access to GitHub.
|
||||
echo 5. Antivirus or security software interference.
|
||||
echo 6. The file may have been moved or deleted from the GitHub repository.
|
||||
echo 7. Other issues not mentioned above.
|
||||
echo.
|
||||
choice /C YN /M "Do you want to retry the DeepSpeed download?"
|
||||
if errorlevel 1 goto install_deepspeed
|
||||
if errorlevel 2 goto End
|
||||
) else (
|
||||
echo DeepSpeed download was successful.
|
||||
echo.
|
||||
)
|
||||
|
||||
echo ** Installing DeepSpeed **
|
||||
pip install deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
echo.
|
||||
if errorlevel 1 (
|
||||
echo DeepSpeed installation failed, errorlevel was %errorlevel%. This could be caused by:
|
||||
echo.
|
||||
echo 1. The DeepSpeed wheel file was not downloaded successfully in the previous step.
|
||||
echo 2. Microsoft C++ development tools for Python are not installed correctly.
|
||||
echo 3. Disk space related issues - Check your disk space on this drive.
|
||||
echo 4. Incorrect or missing Python environment - Restart installation.
|
||||
echo 5. Permissions issues - Check you have enough rights on this system.
|
||||
echo 6. Antivirus or security software interference.
|
||||
echo 7. Other issues not mentioned above.
|
||||
echo.
|
||||
echo Please ensure you have followed the instructions to install the Microsoft C++ development
|
||||
echo tools for Python, which is detailed on the AllTalk GitHub page.
|
||||
echo.
|
||||
choice /C YN /M "Do you want to retry the DeepSpeed installation?"
|
||||
if errorlevel 1 goto install_deepspeed
|
||||
if errorlevel 2 goto End
|
||||
) else (
|
||||
echo DeepSpeed installation was successful.
|
||||
del deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
echo.
|
||||
)
|
||||
|
||||
echo ** Installing Parler **
|
||||
pip install -r system\requirements\requirements_parler.txt
|
||||
echo Clean Environment
|
||||
call "%CONDA_ROOT_PREFIX%\Scripts\conda.exe" clean --all --force-pkgs-dirs -y
|
||||
echo.
|
||||
|
||||
:transformers_choice
|
||||
echo.
|
||||
echo ======================================== IMPORTANT NOTICE ===========================================
|
||||
echo Currently, Coqui-TTS and the XTTS engine requires transformers version 4.40.2 to generate streaming
|
||||
echo audio. XTTS can still generate standard non-streaming audio on any version of transformers. It is
|
||||
echo ONLY streaming audio that is affected and ONLY with the Coqui XTTS engine. So this would affect
|
||||
echo things like Kobold, or anywhere you use XTTS with streaming audio.
|
||||
echo.
|
||||
echo Parler-TTS states that it wants transformers version 4.43.3 but it appears to work fine with
|
||||
echo transformers 4.40.2, however using transformers 4.40.2 generates a dependcy error message as
|
||||
echo Parler-TTS is untested on 4.40.2 of transformers.
|
||||
echo.
|
||||
echo Until the Coqui-TTS engine is updated to perform streaming with newer versions of transformers, if
|
||||
echo you want to use streaming with XTTS, you will need to downgrade transformers to 4.40.2.
|
||||
echo.
|
||||
echo AllTalk is NOT responsible for the maintainance or upkeep of the Coqui-TTS engine.
|
||||
echo.
|
||||
echo If you change your mind in future you can re-run atsetup and re-apply the requirements.
|
||||
echo ====================================================================================================
|
||||
echo.
|
||||
choice /C YN /M " Do you want to downgrade transformers to version 4.40.2 for XTTS streaming support?"
|
||||
if errorlevel 2 (
|
||||
echo.
|
||||
echo Keeping transformers at version 4.43.3.
|
||||
echo Note: XTTS streaming may not work with this version.
|
||||
goto end_transformers_choice
|
||||
)
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo Downgrading transformers to version 4.40.2...
|
||||
echo.
|
||||
pip install transformers==4.40.2
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo Failed to downgrade transformers. Please check your internet connection and try manually later with:
|
||||
echo pip install transformers==4.40.2
|
||||
) else (
|
||||
echo.
|
||||
echo XTTS streaming should now work correctly.
|
||||
)
|
||||
)
|
||||
:end_transformers_choice
|
||||
echo.
|
||||
echo Installation process completed.
|
||||
|
||||
@rem Create start_environment.bat to run AllTalk environment
|
||||
echo @echo off > start_environment.bat
|
||||
@@ -448,6 +627,9 @@ Echo Run %L_YELLOW%start_alltalk.bat%RESET% to start AllTalk.
|
||||
Echo Run %L_YELLOW%start_diagnostics.bat%RESET% to start the diagnostics.
|
||||
Echo Run %L_YELLOW%start_finetune.bat%RESET% to start Finetuning.
|
||||
Echo Run %L_YELLOW%start_environment.bat%RESET% to start the AllTalk Python environment.
|
||||
Echo.
|
||||
Echo Documentation is built into the Gradio interface. Please explore the documentation for
|
||||
Echo tips, troubleshooing and explanations as most common questions are answered there.
|
||||
Echo.
|
||||
if "%1"=="-silent" goto End
|
||||
pause
|
||||
@@ -553,28 +735,14 @@ if errorlevel 1 (
|
||||
)
|
||||
@rem Run Reapply requirements
|
||||
echo.
|
||||
echo Re-installing requirements. If you have problems after this, it may indicate
|
||||
echo that the custom Python environment is damaged in some way. As such it may be
|
||||
echo best to delete the custom Python environment and re-run the entire setup
|
||||
echo routine again to rebuild AllTalk's Python environment. Please press a key
|
||||
echo to continue re-applying the Requirements for a standalone installation.
|
||||
echo.
|
||||
echo Installing requirements. If you have problems after this, you should
|
||||
echo delete the alltalk_environment and run the setup routine again.
|
||||
echo.
|
||||
pip install -r system\requirements\requirements_standalone.txt
|
||||
echo Installing DeepSpeed...
|
||||
pip install deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
del deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
echo.
|
||||
echo There was an error.
|
||||
echo Press any key to return to the menu.
|
||||
echo.
|
||||
pause
|
||||
goto StandaloneMenu
|
||||
)
|
||||
Echo.
|
||||
Echo.
|
||||
Echo Requirements have been re-applied/updated.
|
||||
Echo.
|
||||
pause
|
||||
goto StandaloneMenu
|
||||
goto install_faiss
|
||||
|
||||
:STPurgepipcache
|
||||
cd /D "%~dp0"
|
||||
@@ -666,12 +834,19 @@ goto StandaloneMenu
|
||||
echo Exiting AllTalk Setup Utility...
|
||||
echo.
|
||||
Echo Remember, after installation you can....
|
||||
Echo.
|
||||
Echo Run %L_YELLOW%start_alltalk.bat%RESET% to start AllTalk.
|
||||
Echo Run %L_YELLOW%start_finetune.bat%RESET% to start Finetuning.
|
||||
Echo Run %L_YELLOW%start_environment.bat%RESET% to start the AllTalk Python environment.
|
||||
Echo Run %L_YELLOW%start_diagnostics.bat%RESET% to start generate a diagnostics file.
|
||||
Echo.
|
||||
Echo Documentation is built into the Gradio interface. Please explore the documentation for
|
||||
Echo tips, troubleshooing and explanations as most common questions are answered there.
|
||||
exit /b
|
||||
|
||||
:End
|
||||
echo Exiting AllTalk Setup Utility...
|
||||
Echo.
|
||||
Echo Documentation is built into the Gradio interface. Please explore the documentation for
|
||||
Echo tips, troubleshooing and explanations as most common questions are answered there.
|
||||
exit /b
|
||||
@@ -396,6 +396,7 @@ install_custom_standalone() {
|
||||
echo Installing DeepSpeed...
|
||||
pip install deepspeed-0.14.2+cu121torch2.2-cp311-cp311-manylinux_2_24_x86_64.whl
|
||||
rm deepspeed-0.14.2+cu121torch2.2-cp311-cp311-manylinux_2_24_x86_64.whl
|
||||
pip install -r system\requirements\requirements_parler.txt
|
||||
conda clean --all --force-pkgs-dirs -y
|
||||
Create start_environment.sh to run AllTalk
|
||||
cat << EOF > start_environment.sh
|
||||
@@ -578,6 +579,7 @@ reapply_standalone() {
|
||||
echo " Installing additional requirements."
|
||||
echo
|
||||
pip install -r system/requirements/requirements_standalone.txt
|
||||
pip install -r system\requirements\requirements_parler.txt
|
||||
echo
|
||||
echo " Requirements have been re-applied/updated."
|
||||
echo
|
||||
|
||||
+23
-3
@@ -108,10 +108,30 @@ def get_cpu_info():
|
||||
|
||||
def get_disk_info():
|
||||
disk_info = []
|
||||
partitions = psutil.disk_partitions()
|
||||
partitions = psutil.disk_partitions(all=True)
|
||||
for p in partitions:
|
||||
usage = psutil.disk_usage(p.mountpoint)
|
||||
disk_info.append(f" Drive: {p.device} | Total: {usage.total / (1024 ** 3):.2f} GB | Used: {usage.used / (1024 ** 3):.2f} GB | Free: {usage.free / (1024 ** 3):.2f} GB | Type: {p.fstype}")
|
||||
try:
|
||||
usage = psutil.disk_usage(p.mountpoint)
|
||||
disk_info.append(
|
||||
f"Drive: {p.device} | Total: {usage.total / (1024 ** 3):.2f} GB | Used: {usage.used / (1024 ** 3):.2f} GB | Free: {usage.free / (1024 ** 3):.2f} GB | Type: {p.fstype}"
|
||||
)
|
||||
except Exception as e:
|
||||
# Handle various types of errors
|
||||
error_type = type(e).__name__
|
||||
error_message = str(e)
|
||||
|
||||
if isinstance(e, PermissionError):
|
||||
status = "Inaccessible or locked (Permission denied)"
|
||||
elif isinstance(e, OSError):
|
||||
if e.winerror == 1117: # WinError 1117: I/O device error
|
||||
status = "I/O device error"
|
||||
else:
|
||||
status = f"OS Error: {error_message}"
|
||||
else:
|
||||
status = f"Error: {error_type} - {error_message}"
|
||||
|
||||
disk_info.append(f"Drive: {p.device} | Status: {status} | Type: {p.fstype}")
|
||||
|
||||
return disk_info
|
||||
|
||||
def is_port_in_use(port):
|
||||
|
||||
+5
-3
@@ -1788,7 +1788,9 @@ if __name__ == "__main__":
|
||||
value=False,
|
||||
label="Continue Previous Project",
|
||||
scale=1,
|
||||
visible=False,
|
||||
)
|
||||
# Continue Run has been set to invisible from the interface as its setting a 1000 epoch run when used. Have been unable to track down where this is coming from.
|
||||
disable_shared_memory = gr.Checkbox(
|
||||
value=False,
|
||||
label="Disable Shared Memory Use",
|
||||
@@ -1800,11 +1802,11 @@ if __name__ == "__main__":
|
||||
scale=1,
|
||||
)
|
||||
train_csv = gr.Textbox(
|
||||
label="Train CSV:",
|
||||
label="Train CSV file path:",
|
||||
scale=2,
|
||||
)
|
||||
eval_csv = gr.Textbox(
|
||||
label="Eval CSV:",
|
||||
label="Eval CSV file path:",
|
||||
scale=2,
|
||||
)
|
||||
with gr.Row():
|
||||
@@ -1981,7 +1983,7 @@ if __name__ == "__main__":
|
||||
- What you are training (A human voice, A cartoon voice, A new language entirely etc)<br>
|
||||
- How much audio you have (you may want less or more eval or epochs)<br>
|
||||
◽ The key indicator of sufficient model training is whether it sounds right to you. Coqui suggests beginning with the base settings for training. If the resulting audio doesn't meet your expectations, additional training sessions may be necessary.<br>
|
||||
#### 🟪 <u>Continue Previous Project</u>
|
||||
#### 🟪 <u>Continue Previous Project (CURRENTLY REMOVED AND NOT AVAILABLE)</u>
|
||||
This option allows you to resume training from where it left off if your previous session was interrupted (e.g., due to a power outage or system crash). When enabled:<br>
|
||||
◽ The system will attempt to load the most recent checkpoint from your previous training session.<br>
|
||||
◽ It will continue training from that point, preserving your progress and saving time.<br>
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import time
|
||||
import argparse
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
async def send_tts_request(session, url, text, voice, request_id):
|
||||
start_time = time.time()
|
||||
try:
|
||||
async with session.post(url, data={
|
||||
"text_input": text,
|
||||
"text_filtering": "standard",
|
||||
"character_voice_gen": voice,
|
||||
"narrator_enabled": "false",
|
||||
"narrator_voice_gen": "en_US-ljspeech-high.onnx",
|
||||
"text_not_inside": "character",
|
||||
"language": "en",
|
||||
"output_file_name": f"loadtest_{request_id}",
|
||||
"output_file_timestamp": "true",
|
||||
"autoplay": "false",
|
||||
"autoplay_volume": "0.8"
|
||||
}) as response:
|
||||
result = await response.json()
|
||||
end_time = time.time()
|
||||
print(f"Request {request_id} completed in {end_time - start_time:.2f} seconds.")
|
||||
print(f"Response: {result}")
|
||||
return result
|
||||
except Exception as e:
|
||||
print(f"Request {request_id} failed: {str(e)}")
|
||||
return None
|
||||
|
||||
async def run_load_test(num_requests, text_length, api_url, voice):
|
||||
async with aiohttp.ClientSession() as session:
|
||||
tasks = []
|
||||
for i in range(num_requests):
|
||||
text = f"This is a test of the MEM load balancing system. Request number {i+1}. " * (text_length // 10)
|
||||
task = asyncio.ensure_future(send_tts_request(session, api_url, text, voice, i+1))
|
||||
tasks.append(task)
|
||||
|
||||
results = await asyncio.gather(*tasks)
|
||||
return results
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Load test for MEM TTS API")
|
||||
parser.add_argument("--requests", type=int, default=5, help="Number of simultaneous requests to send")
|
||||
parser.add_argument("--length", type=int, default=50, help="Approximate length of text for each request")
|
||||
parser.add_argument("--url", type=str, default="http://127.0.0.1:7401/api/tts-generate", help="URL of the MEM API")
|
||||
parser.add_argument("--voice", type=str, default="en_US-ljspeech-high.onnx", help="A voice the current TTS engine supports")
|
||||
args = parser.parse_args()
|
||||
|
||||
print(f"AllTalk MEM load tester.")
|
||||
print(f"\nYou can use this to load test MEM. You can specify:")
|
||||
print(f"\n --requests (the amount of simultaneous request to send)")
|
||||
print(f" --length (the amount of character text per request)")
|
||||
print(f" --url (the URL to send the request to)")
|
||||
print(f" --voice (the voice/audio sample to use)")
|
||||
print(f"\nA full command line would look like this")
|
||||
print(f"\npython mem_load_test.py --requests 3 --length 50 --url http://127.0.0.1:7401/api/tts-generate --voice female_01.wav")
|
||||
print(f"\nAll requests are sent simultaniously at the same time. As such the 'completed in' time is")
|
||||
print(f"calculated from the time the requests were sent, not the actual TTS processing time per")
|
||||
print(f"individual request within the TTS engine.")
|
||||
print(f"\nIf you dont specify a voice the loaded TTS engine uses, this will fail. The default voice")
|
||||
print(f"being sent is en_US-ljspeech-high.onnx which is for Piper TTS.")
|
||||
print(f"\nStarting load test with {args.requests} simultaneous requests...")
|
||||
print(f"Each request will have approximately {args.length} characters of text.")
|
||||
print(f"Sending requests to: {args.url}\n")
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
# Run the async function in a separate thread to avoid blocking
|
||||
with ThreadPoolExecutor() as executor:
|
||||
future = executor.submit(asyncio.run, run_load_test(args.requests, args.length, args.url, args.voice))
|
||||
results = future.result()
|
||||
|
||||
end_time = time.time()
|
||||
|
||||
successful_requests = sum(1 for result in results if result and result.get("status") == "generate-success")
|
||||
failed_requests = sum(1 for result in results if result is None or result.get("status") != "generate-success")
|
||||
|
||||
print(f"\nLoad test completed in {end_time - start_time:.2f} seconds.")
|
||||
print(f"Successful requests: {successful_requests}")
|
||||
print(f"Failed requests: {failed_requests}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -214,7 +214,7 @@ def run_firsttime_script():
|
||||
else:
|
||||
script_path = os.path.join(this_dir, 'system', 'config', 'firstrun.py') # Default to Standalone if nothing matched.
|
||||
|
||||
subprocess.run(['python', script_path], check=True)
|
||||
subprocess.run([sys.executable, script_path], check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error occurred while running the script: {e}")
|
||||
except Exception as e:
|
||||
@@ -356,7 +356,7 @@ if os.path.isfile("/.dockerenv") and 'google.colab' not in sys.modules:
|
||||
print(f"[{branding}TTS] Internal Gradio address: http://localhost:{params['gradio_port_number']}")
|
||||
|
||||
# Start the subprocess (now unified for both Docker and non-Docker environments)
|
||||
process = subprocess.Popen(["python", script_path])
|
||||
process = subprocess.Popen([sys.executable, script_path])
|
||||
|
||||
# Check if the subprocess has started successfully
|
||||
if process.poll() is None:
|
||||
@@ -468,7 +468,7 @@ check_espeak_ng()
|
||||
def start_subprocess():
|
||||
global process
|
||||
if process is None or process.poll() is not None:
|
||||
process = subprocess.Popen(["python", script_path])
|
||||
process = subprocess.Popen([sys.executable, script_path])
|
||||
return "Subprocess started."
|
||||
else:
|
||||
return "Subprocess is already running."
|
||||
|
||||
@@ -1 +1,20 @@
|
||||
Place the `alltalk.js` in your `\SillyTavern\public\scripts\extensions\tts\` folder, replacing the existing file.
|
||||
BASIC SETUP
|
||||
-----------
|
||||
Place the `alltalk.js` in your `\SillyTavern\public\scripts\extensions\tts\` folder, replacing the existing file.
|
||||
|
||||
CHANGING THE DEFAULT IP ADDRESS
|
||||
-------------------------------
|
||||
If you change the default IP/URL in the SillyTavern interface, you need to press Enter for it to save the setting. Just typing in an address/URL will not change the setting.
|
||||
|
||||
SIMPLE TROUBLESHOOTING
|
||||
----------------------
|
||||
The settings for AllTalk are stored, saved and managed by SillyTavern and not the AllTalk extension. You can manually edit OR delete these settings if necessary by editing the `settings.json` file that SillyTavern stores. I would suggest taking a copy of the file before making any changes.
|
||||
|
||||
Older versions of SillyTavern store `settings.json` file in `\SillyTavern\public\`
|
||||
|
||||
Newer version of SillyTavern store `settings.json` file in `\SillyTavern\data\default-user`
|
||||
|
||||
Within the `settings.json` file you will find a section called `"AllTalk": {` and it is closed out a few lines down with `},`
|
||||
|
||||
You can either manually edit any of the settings in there OR you can delete the entire section from the start of `"AllTalk":` to the end of `},` and when you refresh the SillyTavern web page OR restart SillyTavern, new settings for AllTalk will be created/saved.
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+190
-186
@@ -1,186 +1,190 @@
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import shutil
|
||||
import zipfile
|
||||
import requests
|
||||
from tqdm import tqdm
|
||||
from inputimeout import inputimeout, TimeoutOccurred
|
||||
from pathlib import Path
|
||||
|
||||
this_dir = Path(__file__).parent.resolve().parent.resolve().parent.resolve()
|
||||
# File paths
|
||||
config_path = this_dir / 'confignew.json'
|
||||
tts_engines_path = this_dir / 'system/tts_engines/tts_engines.json'
|
||||
new_config_template_path = this_dir / 'system/config/confignew.json'
|
||||
|
||||
def download_file(url, dest_path):
|
||||
response = requests.get(url, stream=True)
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
block_size = 1024 # 1 Kibibyte
|
||||
t = tqdm(total=total_size, unit='iB', unit_scale=True, desc=str(dest_path))
|
||||
with open(dest_path, 'wb') as file:
|
||||
for data in response.iter_content(block_size):
|
||||
t.update(len(data))
|
||||
file.write(data)
|
||||
t.close()
|
||||
|
||||
def setup_piper():
|
||||
os.makedirs(this_dir / 'models/piper', exist_ok=True)
|
||||
os.makedirs(this_dir / 'models/xtts', exist_ok=True)
|
||||
download_file("https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ljspeech/high/en_US-ljspeech-high.onnx?download=true",
|
||||
this_dir / "models/piper/en_US-ljspeech-high.onnx")
|
||||
download_file("https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ljspeech/high/en_US-ljspeech-high.onnx.json?download=true.json",
|
||||
this_dir / "models/piper/en_US-ljspeech-high.onnx.json")
|
||||
|
||||
def setup_vits():
|
||||
os.makedirs(this_dir / 'models/vits', exist_ok=True)
|
||||
os.makedirs(this_dir / 'models/xtts', exist_ok=True)
|
||||
zip_path = this_dir / 'models/vits/vits.zip'
|
||||
download_file("https://coqui.gateway.scarf.sh/v0.6.1_models/tts_models--en--vctk--vits.zip", zip_path)
|
||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(this_dir / 'models/vits')
|
||||
os.remove(zip_path)
|
||||
|
||||
def setup_xtts():
|
||||
os.makedirs(this_dir / 'models/xtts/xttsv2_2.0.3', exist_ok=True)
|
||||
base_url = "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/"
|
||||
files = [
|
||||
"LICENSE.txt",
|
||||
"README.md",
|
||||
"config.json",
|
||||
"model.pth",
|
||||
"dvae.pth",
|
||||
"mel_stats.pth",
|
||||
"speakers_xtts.pth",
|
||||
"vocab.json"
|
||||
]
|
||||
for file in files:
|
||||
download_file(base_url + file + "?download=true", this_dir / f"models/xtts/xttsv2_2.0.3/{file}")
|
||||
|
||||
|
||||
|
||||
def update_tts_engines(engine, model):
|
||||
with open(tts_engines_path, 'r') as file:
|
||||
tts_engines = json.load(file)
|
||||
|
||||
tts_engines['engine_loaded'] = engine
|
||||
tts_engines['selected_model'] = model
|
||||
|
||||
with open(tts_engines_path, 'w') as file:
|
||||
json.dump(tts_engines, file, indent=4)
|
||||
|
||||
def set_firstrun_model_false():
|
||||
with open(config_path, 'r') as file:
|
||||
config = json.load(file)
|
||||
|
||||
config['firstrun_model'] = False
|
||||
|
||||
with open(config_path, 'w') as file:
|
||||
json.dump(config, file, indent=4)
|
||||
|
||||
def load_config(file_path):
|
||||
with open(file_path, "r") as config_file:
|
||||
config = json.load(config_file)
|
||||
return config
|
||||
|
||||
def warning_mesasge():
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[93mIf you have you have UPGRADED from v1 ensure you have re-installed\033[0m")
|
||||
print(f"[{branding}TTS] \033[93mthe requirements. Otherwise you will get failures and errors!\033[0m")
|
||||
print(f"[{branding}TTS] \033[93mOn Linux ignore the \033[0m'sparse_attn requires a torch version' \033[93mand\033[0m")
|
||||
print(f"[{branding}TTS] \033[0m'using untested triton version' \033[93mmessages.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
# Load confignew.json
|
||||
with open(config_path, 'r') as file:
|
||||
config = json.load(file)
|
||||
|
||||
branding = config['branding']
|
||||
|
||||
# Check if the config file is version 1
|
||||
if "ip_address" in config:
|
||||
print(f"[{branding}TTS] Detected version 1 configuration file.")
|
||||
print(f"[{branding}TTS] Upgrading to version 2 configuration file...")
|
||||
|
||||
# Backup the old configuration file
|
||||
backup_path = config_path + ".backup"
|
||||
shutil.copyfile(config_path, backup_path)
|
||||
|
||||
# Copy the new configuration template to replace the old config file
|
||||
shutil.copyfile(new_config_template_path, config_path)
|
||||
|
||||
print(f"[{branding}TTS] Configuration file upgraded successfully.")
|
||||
|
||||
# Reload the new config file
|
||||
with open(config_path, 'r') as file:
|
||||
config = json.load(file)
|
||||
|
||||
# Check if firstrun_model is true
|
||||
if config.get('firstrun_model', False):
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[92mThis is the first time startup. Please download a start TTS model.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
# List of available models
|
||||
models = [
|
||||
{"name": "piper", "model": "piper"},
|
||||
{"name": "vits", "model": "tts_models--en--vctk--vits"},
|
||||
{"name": "xtts", "model": "xttsv2_2.0.3"},
|
||||
]
|
||||
|
||||
# Display models to the user
|
||||
print(f"[{branding}TTS] \033[94mAvailable First Time Start-up models:\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
for idx, model in enumerate(models):
|
||||
print(f"[{branding}TTS] \033[93m{idx + 1}. \033[94m{model['name']} - {model['model']}\033[0m")
|
||||
print(f"[{branding}TTS] \033[93m{len(models) + 1}.\033[94m I have my own models already\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[94mIn \033[91m60 seconds\033[0m \033[94ma Piper model will be \033[91mdownloaded automatically.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
# Auto-select model after 30 seconds
|
||||
selected_model = models[0] # Default to the first model (piper)
|
||||
try:
|
||||
user_choice = inputimeout(prompt=f"[{branding}TTS] \033[92mEnter your choice 1-4: \033[0m ", timeout=60)
|
||||
except TimeoutOccurred:
|
||||
user_choice = None
|
||||
|
||||
if user_choice is None:
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] No input received. Proceeding with the default model (piper).")
|
||||
elif user_choice.lower() == 'own' or (user_choice.isdigit() and int(user_choice) == len(models) + 1):
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] If you have your own XTTS models, please move them into the")
|
||||
print(f"[{branding}TTS] \033[93m/models/xtts/\033[0m folder")
|
||||
print(f"[{branding}TTS]")
|
||||
os.makedirs('models/piper', exist_ok=True)
|
||||
os.makedirs('models/vits', exist_ok=True)
|
||||
os.makedirs('models/xtts/', exist_ok=True)
|
||||
update_tts_engines('piper', 'piper')
|
||||
set_firstrun_model_false()
|
||||
warning_mesasge()
|
||||
exit()
|
||||
|
||||
if user_choice is not None and user_choice.isdigit() and 1 <= int(user_choice) <= len(models):
|
||||
selected_model = models[int(user_choice) - 1]
|
||||
warning_mesasge()
|
||||
|
||||
if user_choice is None or user_choice.lower() != 'own':
|
||||
if selected_model['name'] == 'piper':
|
||||
setup_piper()
|
||||
update_tts_engines('piper', 'piper')
|
||||
elif selected_model['name'] == 'vits':
|
||||
setup_vits()
|
||||
update_tts_engines('vits', 'vits - tts_models--en--vctk--vits')
|
||||
elif selected_model['name'] == 'xtts':
|
||||
setup_xtts()
|
||||
update_tts_engines('xtts', 'xtts - xttsv2_2.0.3')
|
||||
|
||||
print(f"[{branding}TTS] {selected_model['name']} model downloaded and configuration updated successfully.")
|
||||
# Set firstrun_model to false
|
||||
set_firstrun_model_false()
|
||||
warning_mesasge()
|
||||
exit()
|
||||
else:
|
||||
exit()
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import shutil
|
||||
import zipfile
|
||||
import requests
|
||||
from tqdm import tqdm
|
||||
from inputimeout import inputimeout, TimeoutOccurred
|
||||
from pathlib import Path
|
||||
|
||||
this_dir = Path(__file__).parent.resolve().parent.resolve().parent.resolve()
|
||||
# File paths
|
||||
config_path = this_dir / 'confignew.json'
|
||||
tts_engines_path = this_dir / 'system/tts_engines/tts_engines.json'
|
||||
new_config_template_path = this_dir / 'system/config/confignew.json'
|
||||
|
||||
def download_file(url, dest_path):
|
||||
response = requests.get(url, stream=True)
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
block_size = 1024 # 1 Kibibyte
|
||||
t = tqdm(total=total_size, unit='iB', unit_scale=True, desc=str(dest_path))
|
||||
with open(dest_path, 'wb') as file:
|
||||
for data in response.iter_content(block_size):
|
||||
t.update(len(data))
|
||||
file.write(data)
|
||||
t.close()
|
||||
|
||||
def setup_piper():
|
||||
os.makedirs(this_dir / 'models/piper', exist_ok=True)
|
||||
os.makedirs(this_dir / 'models/xtts', exist_ok=True)
|
||||
download_file("https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ljspeech/high/en_US-ljspeech-high.onnx?download=true",
|
||||
this_dir / "models/piper/en_US-ljspeech-high.onnx")
|
||||
download_file("https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ljspeech/high/en_US-ljspeech-high.onnx.json?download=true.json",
|
||||
this_dir / "models/piper/en_US-ljspeech-high.onnx.json")
|
||||
|
||||
def setup_vits():
|
||||
os.makedirs(this_dir / 'models/vits', exist_ok=True)
|
||||
os.makedirs(this_dir / 'models/xtts', exist_ok=True)
|
||||
zip_path = this_dir / 'models/vits/vits.zip'
|
||||
download_file("https://coqui.gateway.scarf.sh/v0.6.1_models/tts_models--en--vctk--vits.zip", zip_path)
|
||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(this_dir / 'models/vits')
|
||||
os.remove(zip_path)
|
||||
|
||||
def setup_xtts():
|
||||
os.makedirs(this_dir / 'models/xtts/xttsv2_2.0.3', exist_ok=True)
|
||||
base_url = "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.3/"
|
||||
files = [
|
||||
"LICENSE.txt",
|
||||
"README.md",
|
||||
"config.json",
|
||||
"model.pth",
|
||||
"dvae.pth",
|
||||
"mel_stats.pth",
|
||||
"speakers_xtts.pth",
|
||||
"vocab.json"
|
||||
]
|
||||
for file in files:
|
||||
download_file(base_url + file + "?download=true", this_dir / f"models/xtts/xttsv2_2.0.3/{file}")
|
||||
|
||||
|
||||
|
||||
def update_tts_engines(engine, model):
|
||||
with open(tts_engines_path, 'r') as file:
|
||||
tts_engines = json.load(file)
|
||||
|
||||
tts_engines['engine_loaded'] = engine
|
||||
tts_engines['selected_model'] = model
|
||||
|
||||
with open(tts_engines_path, 'w') as file:
|
||||
json.dump(tts_engines, file, indent=4)
|
||||
|
||||
def set_firstrun_model_false():
|
||||
with open(config_path, 'r') as file:
|
||||
config = json.load(file)
|
||||
|
||||
config['firstrun_model'] = False
|
||||
|
||||
with open(config_path, 'w') as file:
|
||||
json.dump(config, file, indent=4)
|
||||
|
||||
def load_config(file_path):
|
||||
with open(file_path, "r") as config_file:
|
||||
config = json.load(config_file)
|
||||
return config
|
||||
|
||||
def warning_mesasge():
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[93mIf you have you have UPGRADED from v1 ensure you have re-installed\033[0m")
|
||||
print(f"[{branding}TTS] \033[93mthe requirements. Otherwise you will get failures and errors!\033[0m")
|
||||
print(f"[{branding}TTS] \033[93mOn Linux ignore the \033[0m'sparse_attn requires a torch version' \033[93mand\033[0m")
|
||||
print(f"[{branding}TTS] \033[0m'using untested triton version' \033[93mmessages.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
# Load confignew.json
|
||||
with open(config_path, 'r') as file:
|
||||
config = json.load(file)
|
||||
|
||||
branding = config['branding']
|
||||
|
||||
# Check if the config file is version 1
|
||||
if "ip_address" in config:
|
||||
print(f"[{branding}TTS] Detected version 1 configuration file.")
|
||||
print(f"[{branding}TTS] Upgrading to version 2 configuration file...")
|
||||
|
||||
# Backup the old configuration file
|
||||
backup_path = config_path + ".backup"
|
||||
shutil.copyfile(config_path, backup_path)
|
||||
|
||||
# Copy the new configuration template to replace the old config file
|
||||
shutil.copyfile(new_config_template_path, config_path)
|
||||
|
||||
print(f"[{branding}TTS] Configuration file upgraded successfully.")
|
||||
|
||||
# Reload the new config file
|
||||
with open(config_path, 'r') as file:
|
||||
config = json.load(file)
|
||||
|
||||
# Check if firstrun_model is true
|
||||
if config.get('firstrun_model', False):
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[92mThis is the first time startup. Please download a start TTS model. Other TTS engines\033[0m")
|
||||
print(f"[{branding}TTS] \033[92mand TTS models can be downloaded/managed in the Gradio Interface `TTS Engines Settings`\033[0m")
|
||||
print(f"[{branding}TTS] \033[92mtab after inital setup.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
# List of available models
|
||||
models = [
|
||||
{"name": "piper", "model": "piper"},
|
||||
{"name": "vits", "model": "tts_models--en--vctk--vits"},
|
||||
{"name": "xtts", "model": "xttsv2_2.0.3"},
|
||||
]
|
||||
|
||||
# Display models to the user
|
||||
print(f"[{branding}TTS] \033[94mAvailable First Time Start-up models:\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
for idx, model in enumerate(models):
|
||||
print(f"[{branding}TTS] \033[93m{idx + 1}. \033[94m{model['name']} - {model['model']}\033[0m")
|
||||
print(f"[{branding}TTS] \033[93m{len(models) + 1}.\033[94m I have my own models already\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] \033[94mIn \033[91m60 seconds\033[0m \033[94ma Piper model will be \033[91mdownloaded automatically.\033[0m")
|
||||
print(f"[{branding}TTS]")
|
||||
|
||||
# Auto-select model after 30 seconds
|
||||
selected_model = models[0] # Default to the first model (piper)
|
||||
try:
|
||||
user_choice = inputimeout(prompt=f"[{branding}TTS] \033[92mEnter your choice 1-4: \033[0m ", timeout=60)
|
||||
except TimeoutOccurred:
|
||||
user_choice = None
|
||||
|
||||
if user_choice is None:
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] No input received. Proceeding with the default model (piper).")
|
||||
elif user_choice.lower() == 'own' or (user_choice.isdigit() and int(user_choice) == len(models) + 1):
|
||||
print(f"[{branding}TTS]")
|
||||
print(f"[{branding}TTS] If you have your own XTTS models, please move them into the")
|
||||
print(f"[{branding}TTS] \033[93m/models/xtts/\033[0m folder")
|
||||
print(f"[{branding}TTS]")
|
||||
os.makedirs('models/piper', exist_ok=True)
|
||||
os.makedirs('models/vits', exist_ok=True)
|
||||
os.makedirs('models/xtts/', exist_ok=True)
|
||||
update_tts_engines('piper', 'piper')
|
||||
set_firstrun_model_false()
|
||||
warning_mesasge()
|
||||
exit()
|
||||
|
||||
if user_choice is not None and user_choice.isdigit() and 1 <= int(user_choice) <= len(models):
|
||||
selected_model = models[int(user_choice) - 1]
|
||||
warning_mesasge()
|
||||
|
||||
if user_choice is None or user_choice.lower() != 'own':
|
||||
if selected_model['name'] == 'piper':
|
||||
setup_piper()
|
||||
update_tts_engines('piper', 'piper')
|
||||
set_firstrun_model_false()
|
||||
elif selected_model['name'] == 'vits':
|
||||
setup_vits()
|
||||
update_tts_engines('vits', 'vits - tts_models--en--vctk--vits')
|
||||
set_firstrun_model_false()
|
||||
elif selected_model['name'] == 'xtts':
|
||||
setup_xtts()
|
||||
update_tts_engines('xtts', 'xtts - xttsv2_2.0.3')
|
||||
set_firstrun_model_false()
|
||||
print(f"[{branding}TTS] {selected_model['name']} model downloaded and configuration updated successfully.")
|
||||
# Set firstrun_model to false
|
||||
set_firstrun_model_false()
|
||||
warning_mesasge()
|
||||
exit()
|
||||
else:
|
||||
exit()
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -23,7 +23,7 @@ tqdm>=4.66.0
|
||||
unidic-lite>=1.0.8
|
||||
uvicorn>=0.29.0
|
||||
pillow==10.3.0
|
||||
fastapi
|
||||
fastapi==0.112.2
|
||||
starlette
|
||||
pypinyin
|
||||
pyee
|
||||
@@ -41,6 +41,6 @@ tomlkit
|
||||
python-multipart
|
||||
hangul_romanize
|
||||
word2number
|
||||
git+https://github.com/huggingface/parler-tts.git
|
||||
cutlet==0.4.0
|
||||
fugashi==1.3.1
|
||||
piper-tts; sys_platform == "linux"
|
||||
trainer
|
||||
@@ -0,0 +1 @@
|
||||
git+https://github.com/huggingface/parler-tts.git
|
||||
@@ -1,35 +1,36 @@
|
||||
TTS
|
||||
faster-whisper>=1.0.0
|
||||
fuzzywuzzy
|
||||
coqui-tts>=0.24.1
|
||||
faster-whisper>=1.0.3
|
||||
fuzzywuzzy>=0.18.0
|
||||
gradio>=4.26.0
|
||||
importlib_metadata>=7.1.0
|
||||
importlib_metadata>=7.2.1
|
||||
inputimeout>=1.0.4
|
||||
Jinja2>=3.1.0
|
||||
Jinja2>=3.1.4
|
||||
librosa>=0.10.2.post1
|
||||
local_attention>=1.9.0
|
||||
nvidia-cublas-cu11>=11.11.3.6
|
||||
nvidia-cudnn-cu11>=9.1.1.17
|
||||
onnxruntime-gpu>=1.18.0
|
||||
pydantic>=2.7.0
|
||||
python-ffmpeg>=2.0.0
|
||||
onnxruntime-gpu>=1.18.1
|
||||
pydantic>=2.8.2
|
||||
python-ffmpeg>=2.0.12
|
||||
python-Levenshtein>=0.25.1
|
||||
praat-parselmouth>=0.4.0
|
||||
pyworld>=0.3.0
|
||||
praat-parselmouth>=0.4.4
|
||||
pyworld>=0.3.4
|
||||
sounddevice>=0.4.7
|
||||
soundfile>=0.12.0
|
||||
soundfile>=0.12.1
|
||||
spacy>=3.7.1
|
||||
torchcrepe>=0.0.2
|
||||
tqdm>=4.66.0
|
||||
tqdm>=4.66.5
|
||||
unidic-lite>=1.0.8
|
||||
uvicorn>=0.29.0
|
||||
pillow==10.3.0
|
||||
pypinyin
|
||||
hangul_romanize
|
||||
word2number
|
||||
git+https://github.com/huggingface/parler-tts.git
|
||||
pypinyin>=0.52.0
|
||||
hangul_romanize>=0.1.0
|
||||
word2number>=1.1
|
||||
cutlet==0.4.0
|
||||
fugashi==1.3.1
|
||||
./system/config/fairseq-0.12.4-cp311-cp311-win_amd64.whl; sys_platform == "win32"
|
||||
./system/config/fairseq-0.12.3.1-cp311-cp311-linux_x86_64.whl; sys_platform == "linux"
|
||||
piper-tts; sys_platform == "linux"
|
||||
piper-tts; sys_platform == "darwin"
|
||||
piper-phonemize==1.1.0; sys_platform == "darwin"
|
||||
trainer
|
||||
fastapi==0.112.2
|
||||
@@ -1,6 +1,6 @@
|
||||
coqui-tts>=0.24.1
|
||||
faster-whisper>=1.0.0
|
||||
fuzzywuzzy
|
||||
fuzzywuzzy>=0.18.0
|
||||
gradio>=4.26.0
|
||||
importlib_metadata>=7.1.0
|
||||
inputimeout>=1.0.4
|
||||
@@ -22,13 +22,13 @@ torchcrepe>=0.0.2
|
||||
tqdm>=4.66.0
|
||||
unidic-lite>=1.0.8
|
||||
uvicorn>=0.29.0
|
||||
pypinyin
|
||||
hangul_romanize
|
||||
word2number
|
||||
git+https://github.com/huggingface/parler-tts.git
|
||||
pypinyin>=0.52.0
|
||||
hangul_romanize>=0.1.0
|
||||
word2number>=1.1
|
||||
cutlet==0.4.0
|
||||
fugashi==1.3.1
|
||||
./system/config/fairseq-0.12.4-cp311-cp311-win_amd64.whl; sys_platform == "win32"
|
||||
./system/config/fairseq-0.12.3.1-cp311-cp311-linux_x86_64.whl; sys_platform == "linux"
|
||||
piper-tts; sys_platform == "linux"
|
||||
piper-tts; sys_platform == "darwin"
|
||||
piper-phonemize==1.1.0; sys_platform == "darwin"
|
||||
trainer
|
||||
@@ -37,6 +37,7 @@ try:
|
||||
import torchaudio
|
||||
import wave
|
||||
import io
|
||||
import random
|
||||
import numpy as np
|
||||
from TTS.tts.configs.xtts_config import XttsConfig
|
||||
from TTS.tts.models.xtts import Xtts
|
||||
@@ -287,7 +288,19 @@ class tts_class:
|
||||
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
|
||||
|
||||
directory = self.main_dir / "voices"
|
||||
voices = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f)) and f.endswith(".wav")]
|
||||
# Step 1: Add .wav files in the main "voices" directory to the list
|
||||
voices.extend([f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f)) and f.endswith(".wav")])
|
||||
|
||||
# Step 2: Walk through subfolders and add subfolder names if they contain .wav files
|
||||
for root, dirs, files in os.walk(directory):
|
||||
# Skip the root directory itself and only consider subfolders
|
||||
if os.path.normpath(root) != os.path.normpath(directory):
|
||||
if any(f.endswith(".wav") for f in files):
|
||||
folder_name = os.path.basename(root) + "/"
|
||||
voices.append(folder_name)
|
||||
|
||||
# Remove "voices/" from the list if it somehow got added
|
||||
voices = [v for v in voices if v != "voices/"]
|
||||
|
||||
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
|
||||
# ↓↓↓ Keep everything below this line ↓↓↓
|
||||
@@ -470,15 +483,31 @@ class tts_class:
|
||||
|
||||
# XTTSv2 LOCAL & Xttsv2 FT Method
|
||||
print(f"[{self.branding}Debug] Deciding if streaming or not") if self.debug_tts else None
|
||||
print(f"[{self.branding}Debug] self.current_model_loaded", self.current_model_loaded) if self.debug_tts else None
|
||||
print(f"[{self.branding}Debug] self.current_model_loaded is:", self.current_model_loaded) if self.debug_tts else None
|
||||
self.current_model_loaded
|
||||
if os.path.isdir(voice):
|
||||
wavs_files = glob.glob(os.path.join(voice, "*.wav"))
|
||||
print(f"[{self.branding}Debug] Audio Sample Detection") if self.debug_tts else None
|
||||
print(f"[{self.branding}Debug] Voice name sent in request is:", voice) if self.debug_tts else None
|
||||
# Check if the voice ends with a slash, indicating it's a directory
|
||||
if voice.endswith("/") or voice.endswith("\\"):
|
||||
# Remove the trailing slash for proper path detection
|
||||
voice = voice.rstrip("/\\")
|
||||
if os.path.isdir(os.path.join(self.main_dir, "voices", voice)):
|
||||
# Normalize the path for the directory and then search for .wav files
|
||||
normalized_path = os.path.normpath(os.path.join(self.main_dir, "voices", voice))
|
||||
wavs_files = glob.glob(os.path.join(normalized_path, "*.wav"))
|
||||
print(f"[{self.branding}Debug] Directory of multiple voice samples detected. Using multiple WAV files:", wavs_files) if self.debug_tts else None
|
||||
# If there are more than 5 .wav files, randomly select 5
|
||||
if len(wavs_files) > 5:
|
||||
wavs_files = random.sample(wavs_files, 5)
|
||||
print(f"[{self.branding}Debug] More than 5 wav files detected so only using 5x random audio samples:", wavs_files) if self.debug_tts else None
|
||||
else:
|
||||
wavs_files = [f"{self.main_dir}/voices/{voice}"]
|
||||
# Normalize the path for the file
|
||||
normalized_path = os.path.normpath(os.path.join(self.main_dir, "voices", voice))
|
||||
wavs_files = [normalized_path]
|
||||
print(f"[{self.branding}Debug] Single voice sample detected. Using one WAV sample:", wavs_files) if self.debug_tts else None
|
||||
|
||||
if self.current_model_loaded.startswith ("xtts"):
|
||||
print(f"[{self.branding}Debug] Text arriving at engine {text}") if self.debug_tts else None
|
||||
print(f"[{self.branding}Debug] Text arriving at TTS engine is: {text}") if self.debug_tts else None
|
||||
gpt_cond_latent, speaker_embedding = self.model.get_conditioning_latents(
|
||||
audio_path=wavs_files,
|
||||
gpt_cond_len=self.model.config.gpt_cond_len,
|
||||
|
||||
@@ -1,348 +1,357 @@
|
||||
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 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") 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(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():
|
||||
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.
|
||||
""")
|
||||
|
||||
|
||||
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("""
|
||||
### 🟧 Using my own Finetuned models
|
||||
Please your Finetuned models within their own folder in `/alltalk_tts/models/xtts/`. Once they are in here they will become availabe within the interface after reloading the XTTS engine.<br>
|
||||
|
||||
### 🟧 Using Voice Samples
|
||||
Voice samples are stored in `/alltalk_tts/voices/` and should be named using the following format `name.wav`<br>
|
||||
|
||||
### 🟧 Where are the outputs stored & Automatic output wav file deletion
|
||||
Voice outputs are stored in `/alltalk_tts/outputs/`. You can configure automatic maintenance deletion of old wav files by setting `Del WAV's older than` in the global settings.<br>
|
||||
|
||||
> When `Disabled`, your output wav files will be left untouched.<br>
|
||||
> When set to a setting `1 Day` or greater, your output wav files older than that time period will be automatically deleted on start-up of AllTalk.<br>
|
||||
|
||||
### 🟧 Where are the models stored?
|
||||
This extension will download the models to `/alltalk_tts/models/xtts/` folder.<br>
|
||||
|
||||
### 🟧 How do I create a new voice sample?
|
||||
To create a new voice sample, you need to make a wav file that is `22050Hz`, `Mono`, `16 bit` and between 6 to 30 seconds long, though 8 to 10 seconds is usually good enough. The model can handle up to 30 second samples, however I've not noticed any improvement in voice output from much longer clips.<br><br>
|
||||
You want to find a nice clear selection of audio, so lets say you wanted to clone your favourite celebrity. You may go looking for an interview where they are talking. Pay close attention to the audio you are listening to and trying to sample. Are there noises in the background, hiss on the soundtrack, a low humm, some quiet music playing or something? The better quality the audio the better the final TTS result. Don't forget, the AI that processes the sounds can hear everything in your sample and it will use them in the voice its trying to recreate.<br><br>
|
||||
Try make your clip one of nice flowing speech, like the included example files. No big pauses, gaps or other sounds. Preferably a sample that the person you are trying to copy will show a little vocal range and emotion in their voice. Also, try to avoid a clip starting or ending with breathy sounds (breathing in/out etc).<br>
|
||||
""")
|
||||
gr.Markdown("""
|
||||
### 🟧 Editing your sample!
|
||||
So, you've downloaded your favourite celebrity interview off YouTube, from here you need to chop it down to 6 to 30 seconds in length and resample it. If you need to clean it up, do audio processing, volume level changes etc, do this before down-sampling.<br><br>
|
||||
Using the latest version of Audacity `select/highlight` your 6 to 30 second clip and:<br><br>
|
||||
• `Tracks` > `Resample to 22050Hz`<br>
|
||||
• `Tracks` > `Mix` > `Stereo to Mono`<br>
|
||||
• `File` > `Export Audio` saving it as a `WAV` of `22050Hz`.<br><br>
|
||||
Save your generated wav file in the `/alltalk_tts/voices/` folder.<br>
|
||||
|
||||
### 🟧 Why doesnt it sound like XXX Person?
|
||||
Maybe you might be interested in trying Finetuning of the XTTS model. Otherwise, the reasons can be that you:<br>
|
||||
|
||||
> Didn't down-sample it as above.<br>
|
||||
> Have a bad quality voice sample.<br>
|
||||
> Try using the 2x different generation methods `API Local` and `XTTSv2 Local`, as they generate output in slightly different ways.<br>
|
||||
|
||||
Additionally, use the RVC pipeline with a matching voice model, however, some samples just never seem to work correctly, so maybe try a different sample. Always remember though, this is an AI model attempting to re-create a voice, so you will never get a 100% match.
|
||||
|
||||
### 🟧 API Local, XTTSv2 Generation methods & Speed
|
||||
These two methods both produce sound output in slightly different ways. XTTSv2 is the perferable method a it supports DeepSpeed, which, if you have a system capable of DeepSpeed genereation, can result in a 2-3x speed gain in generation.
|
||||
""")
|
||||
|
||||
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
|
||||
def xtts_at_gradio_settings_page(model_config_data):
|
||||
app = xtts_model_alltalk_settings(model_config_data)
|
||||
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 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") 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(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():
|
||||
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.
|
||||
""")
|
||||
|
||||
|
||||
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("""
|
||||
### 🟧 Using my own Finetuned models
|
||||
Please your Finetuned models within their own folder in `/alltalk_tts/models/xtts/`. Once they are in here they will become availabe within the interface after reloading the XTTS engine.<br>
|
||||
|
||||
### 🟧 Using Single Voice Samples
|
||||
Voice samples are stored in `/alltalk_tts/voices/` and should be named using the following format `name.wav`. These files will be listed as `name.wav` in the available voices list.<br>
|
||||
|
||||
### 🟧 Using Multiple Voice Samples
|
||||
If you have multiple voice samples for a single voice, you can organize them into subfolders within the `/alltalk_tts/voices/` directory. Each subfolder should be named according to the voice it contains, up to 5 voice samples will be randomly selected for use.<br>
|
||||
|
||||
• Each subfolder should reflect the name or type of the voice it contains (e.g., `female_voice`, `male_voice`).<br>
|
||||
• The voice samples inside each subfolder should follow the standard `.wav` format.<br>
|
||||
• An example folder path would be `/alltalk_tts/voices/mynewvoice/` and this would be listed in the available voices list as `mynewvoice/`.<br>
|
||||
|
||||
This organization allows for easy selection and management of multiple voice samples while ensuring the system can correctly identify and utilize each voice. Manual CURL API requests would send the folder in the format `mynewvoice/`.
|
||||
|
||||
### 🟧 Where are the outputs stored & Automatic output wav file deletion
|
||||
Voice outputs are stored in `/alltalk_tts/outputs/`. You can configure automatic maintenance deletion of old wav files by setting `Del WAV's older than` in the global settings.<br>
|
||||
|
||||
> When `Disabled`, your output wav files will be left untouched.<br>
|
||||
> When set to a setting `1 Day` or greater, your output wav files older than that time period will be automatically deleted on start-up of AllTalk.<br>
|
||||
|
||||
### 🟧 Where are the models stored?
|
||||
This extension will download the models to `/alltalk_tts/models/xtts/` folder.<br>
|
||||
|
||||
### 🟧 API Local, XTTSv2 Generation methods & Speed
|
||||
These two methods both produce sound output in slightly different ways. XTTSv2 is the perferable method a it supports DeepSpeed, which, if you have a system capable of DeepSpeed genereation, can result in a 2-3x speed gain in generation.
|
||||
""")
|
||||
gr.Markdown("""
|
||||
### 🟧 How do I create a new voice sample?
|
||||
To create a new voice sample, you need to make a wav file that is `22050Hz`, `Mono`, `16 bit` and between 6 to 30 seconds long, though 8 to 10 seconds is usually good enough. The model can handle up to 30 second samples, however I've not noticed any improvement in voice output from much longer clips.<br><br>
|
||||
You want to find a nice clear selection of audio, so lets say you wanted to clone your favourite celebrity. You may go looking for an interview where they are talking. Pay close attention to the audio you are listening to and trying to sample. Are there noises in the background, hiss on the soundtrack, a low humm, some quiet music playing or something? The better quality the audio the better the final TTS result. Don't forget, the AI that processes the sounds can hear everything in your sample and it will use them in the voice its trying to recreate.<br><br>
|
||||
Try make your clip one of nice flowing speech, like the included example files. No big pauses, gaps or other sounds. Preferably a sample that the person you are trying to copy will show a little vocal range and emotion in their voice. Also, try to avoid a clip starting or ending with breathy sounds (breathing in/out etc).<br>
|
||||
|
||||
### 🟧 Editing your sample!
|
||||
So, you've downloaded your favourite celebrity interview off YouTube, from here you need to chop it down to 6 to 30 seconds in length and resample it. If you need to clean it up, do audio processing, volume level changes etc, do this before down-sampling.<br><br>
|
||||
Using the latest version of Audacity `select/highlight` your 6 to 30 second clip and:<br><br>
|
||||
• `Tracks` > `Resample to 22050Hz`<br>
|
||||
• `Tracks` > `Mix` > `Stereo to Mono`<br>
|
||||
• `File` > `Export Audio` saving it as a `WAV` of `22050Hz`.<br><br>
|
||||
Save your generated wav file in the `/alltalk_tts/voices/` folder.<br>
|
||||
|
||||
### 🟧 Why doesnt it sound like XXX Person?
|
||||
Maybe you might be interested in trying Finetuning of the XTTS model. Otherwise, the reasons can be that you:<br>
|
||||
|
||||
> Didn't down-sample it as above.<br>
|
||||
> Have a bad quality voice sample.<br>
|
||||
> Try using the 2x different generation methods `API Local` and `XTTSv2 Local`, as they generate output in slightly different ways.<br>
|
||||
|
||||
Additionally, use the RVC pipeline with a matching voice model, however, some samples just never seem to work correctly, so maybe try a different sample. Always remember though, this is an AI model attempting to re-create a voice, so you will never get a 100% match.
|
||||
""")
|
||||
|
||||
return app
|
||||
|
||||
################################
|
||||
# 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
|
||||
def xtts_at_gradio_settings_page(model_config_data):
|
||||
app = xtts_model_alltalk_settings(model_config_data)
|
||||
return app
|
||||
@@ -23,7 +23,6 @@ from torch.nn.parallel import DistributedDataParallel as DDP_th
|
||||
from torch.optim.lr_scheduler import ReduceLROnPlateau
|
||||
from torch.utils.data import DataLoader
|
||||
|
||||
from trainer.analytics import ping_training_run
|
||||
from trainer.callbacks import TrainerCallback
|
||||
from trainer.generic_utils import (
|
||||
KeepAverage,
|
||||
@@ -597,7 +596,6 @@ class Trainer:
|
||||
self.callbacks.on_init_end(self)
|
||||
self.dashboard_logger.add_config(config)
|
||||
self.save_training_script()
|
||||
ping_training_run()
|
||||
|
||||
@property
|
||||
def use_apex(self):
|
||||
|
||||
+1082
File diff suppressed because it is too large.
Load diff
+15
-8
@@ -2,6 +2,7 @@ import os
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import argparse
|
||||
import librosa
|
||||
import logging
|
||||
import importlib
|
||||
@@ -659,7 +660,7 @@ async def generate_audio(text, voice, language, temperature, repetition_penalty,
|
||||
async for _ in response:
|
||||
pass
|
||||
except Exception as e:
|
||||
print(f"[GEN] Error during audio generation: {str(e)}")
|
||||
print(f"{branding}[GEN] Error during audio generation: {str(e)}")
|
||||
raise
|
||||
|
||||
###########################
|
||||
@@ -741,8 +742,8 @@ async def openai_tts_generate(request: Request):
|
||||
model = json_data["model"] # Currently ignored
|
||||
input_text = json_data["input"]
|
||||
voice = json_data["voice"]
|
||||
response_format = json_data["response_format"].lower()
|
||||
speed = json_data["speed"]
|
||||
response_format = json_data.get("response_format", "wav").lower()
|
||||
speed = json_data.get("speed", 1.0)
|
||||
print(f"[{branding}Debug] Input text: {input_text}") if debug_openai else None
|
||||
print(f"[{branding}Debug] Voice: {voice}") if debug_openai else None
|
||||
print(f"[{branding}Debug] Speed: {speed}") if debug_openai else None
|
||||
@@ -1594,7 +1595,7 @@ async def apifunction_trigger_analysis(threshold: int = Query(default=98)):
|
||||
env["PATH"] = os.path.join(venv_path, "bin") + ":" + env["PATH"]
|
||||
ttslist_path = this_dir / output_directory / "ttsList.json"
|
||||
wavfile_path = this_dir / output_directory
|
||||
subprocess.run(["python", "tts_diff.py", f"--threshold={threshold}", f"--ttslistpath={ttslist_path}", f"--wavfilespath={wavfile_path}"], cwd=this_dir / "system" / "tts_diff", env=env)
|
||||
subprocess.run([sys.executable, "tts_diff.py", f"--threshold={threshold}", f"--ttslistpath={ttslist_path}", f"--wavfilespath={wavfile_path}"], cwd=this_dir / "system" / "tts_diff", env=env)
|
||||
# Read the analysis summary
|
||||
try:
|
||||
with open(this_dir / output_directory / "analysis_summary.json", "r") as summary_file:
|
||||
@@ -1613,7 +1614,7 @@ async def apifunction_srt_generation():
|
||||
env["PATH"] = os.path.join(venv_path, "bin") + ":" + env["PATH"]
|
||||
ttslist_path = this_dir / output_directory / "ttsList.json"
|
||||
wavfile_path = this_dir / output_directory
|
||||
subprocess.run(["python", "tts_srt.py", f"--ttslistpath={ttslist_path}", f"--wavfilespath={wavfile_path}"], cwd=this_dir / "system" / "tts_srt", env=env)
|
||||
subprocess.run([sys.executable, "tts_srt.py", f"--ttslistpath={ttslist_path}", f"--wavfilespath={wavfile_path}"], cwd=this_dir / "system" / "tts_srt", env=env)
|
||||
srt_file_path = this_dir / output_directory / "subtitles.srt"
|
||||
if not srt_file_path.exists():
|
||||
raise HTTPException(status_code=404, detail="Subtitle file not found.")
|
||||
@@ -1678,11 +1679,17 @@ async def read_root():
|
||||
return HTMLResponse(content=rendered_html, status_code=200)
|
||||
|
||||
# Start Uvicorn Webserver
|
||||
port_parameter = int(params["api_def"]["api_port_number"])
|
||||
# port_parameter = int(params["api_def"]["api_port_number"])
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
|
||||
# Command line argument parser
|
||||
parser = argparse.ArgumentParser(description="AllTalk TTS Server")
|
||||
parser.add_argument("--port", type=int, help="Port number for the server")
|
||||
args = parser.parse_args()
|
||||
# Determine the port to use
|
||||
config_port = int(params["api_def"]["api_port_number"])
|
||||
port_to_use = args.port if args.port is not None else config_port
|
||||
# Start Uvicorn Webserver
|
||||
uvicorn_server = uvicorn.run(app, host="0.0.0.0", port=port_parameter, log_level="debug")
|
||||
uvicorn_server = uvicorn.run(app, host="0.0.0.0", port=port_to_use, log_level="debug")
|
||||
|
||||
Reference in new issue
Block a user