Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c7cb72c13 | ||
|
|
3a105ce922 | ||
|
|
690018c4ab | ||
|
|
6808439ca1 | ||
|
|
8cf56faad2 | ||
|
|
cb7d486288 | ||
|
|
086999fc1b | ||
|
|
a1b889108f | ||
|
|
9f18b24465 | ||
|
|
a3f157249c | ||
|
|
eb08d31509 | ||
|
|
1e1b7fdd8c | ||
|
|
5aad7bcc45 | ||
|
|
dd52597f49 | ||
|
|
5f836e08b8 | ||
|
|
b89b6cdc1d | ||
|
|
558aed1888 | ||
|
|
5eab3d28df | ||
|
|
fd76f496a0 | ||
|
|
4d9b44d9a0 | ||
|
|
951df5a239 | ||
|
|
0a35ee2310 | ||
|
|
efeb2e67e0 | ||
|
|
131f14de76 | ||
|
|
4e67931fe9 | ||
|
|
785525327d | ||
|
|
d4647573cd | ||
|
|
c3895b602c | ||
|
|
f18eb9a4a0 | ||
|
|
2834778e8f | ||
|
|
2f42c69d25 | ||
|
|
8c65f026e6 | ||
|
|
fff01107c8 | ||
|
|
0bdc66f6e5 | ||
|
|
1c3fc86085 | ||
|
|
d9eb0876a6 | ||
|
|
9b4130a8eb | ||
|
|
8fb5b4f695 | ||
|
|
65e306a198 | ||
|
|
3dabb63656 | ||
|
|
241fa91473 | ||
|
|
2a5c8dd58a | ||
|
|
2bfa10d7be | ||
|
|
3501e2e2f3 | ||
|
|
679e3a0982 | ||
|
|
35d05c7689 | ||
|
|
084cc2d2a2 | ||
|
|
a96c82ff01 | ||
|
|
aa7ff1940a | ||
|
|
58465ae14e | ||
|
|
2f49f61645 | ||
|
|
58a70caebc | ||
|
|
d0d470db0f | ||
|
|
068fc72346 | ||
|
|
fc5c8c748f | ||
|
|
24f86d08b7 | ||
|
|
99e402664c | ||
|
|
24cf9eae59 | ||
|
|
18b1582d2a | ||
|
|
96d9df9438 | ||
|
|
4ca156a032 | ||
|
|
5aecb5b7fd | ||
|
|
63c308ff05 | ||
|
|
e6e4b0b47f | ||
|
|
af4c63f1ee | ||
|
|
bedc8148ad | ||
|
|
21cd171719 | ||
|
|
856c0c1baa | ||
|
|
09977956f5 | ||
|
|
2c7feb31e5 | ||
|
|
cead53a808 | ||
|
|
e7996ebc7a | ||
|
|
6815ba0f2e | ||
|
|
51fa4ce9e9 | ||
|
|
043648e24a | ||
|
|
b76ff028f8 | ||
|
|
14214cc141 | ||
|
|
872638a198 | ||
|
|
5d2720c118 | ||
|
|
460216819a | ||
|
|
412d1442a6 | ||
|
|
5a1dd31ab6 | ||
|
|
ce84f153ca | ||
|
|
ab3570c899 | ||
|
|
42f08cd19c | ||
|
|
21fb1b58d9 | ||
|
|
d4741edf94 | ||
|
|
e3c7144272 | ||
|
|
27a4fe2338 | ||
|
|
a0913db3c9 | ||
|
|
645c0d3a67 | ||
|
|
e3878b595b | ||
|
|
825e4a7d12 |
No files matched your search
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: Support request OR Bug report
|
||||
about: Create a report to help us improve
|
||||
name: Support Request/Issue
|
||||
about: Use this to create a support request or report a bug/issue
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
about: Use this to create a Feature request
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
FROM ubuntu:22.04
|
||||
FROM nvidia/cuda:12.1.1-devel-ubuntu22.04
|
||||
ENV HOST 0.0.0.0
|
||||
RUN apt-get update && apt-get upgrade -y \
|
||||
&& apt-get install -y git build-essential portaudio19-dev \
|
||||
python3 python3-pip gcc wget \
|
||||
ocl-icd-opencl-dev opencl-headers clinfo \
|
||||
libclblast-dev libopenblas-dev libaio-dev \
|
||||
&& mkdir -p /etc/OpenCL/vendors && echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd \
|
||||
&& ln -s /usr/bin/python3 /usr/bin/python
|
||||
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN pip install --no-cache-dir -r requirements_other.txt
|
||||
EXPOSE 7851
|
||||
ENV CUDA_DOCKER_ARCH=all
|
||||
RUN pip install --no-cache-dir --no-deps -r system/requirements/requirements_docker.txt && \
|
||||
pip install --no-cache-dir deepspeed
|
||||
|
||||
EXPOSE 7851 7852
|
||||
RUN chmod +x launch.sh
|
||||
ENTRYPOINT ["sh", "-c", "./launch.sh"]
|
||||
@@ -39,8 +39,16 @@ AllTalk is an updated version of the Coqui_tts extension for Text Generation web
|
||||
- 🔴 [Future to-do list & Upcoming updates](https://github.com/erew123/alltalk_tts?#-future-to-do-list)
|
||||
|
||||
---
|
||||
### 🛠️ **About this project**
|
||||
AllTalk is a labour of love, developed and supported in my personal free time. As such, my ability to respond to support requests is limited. I prioritize issues based on their impact and the number of users affected. I appreciate your understanding and patience. If your inquiry isn't covered by the documentation or existing discussions, and it's not related to a bug or feature request, I'll do my best to assist as time allows.
|
||||
### 🛠️ **About this project & me**
|
||||
AllTalk is a labour of love that has been developed, supported and sustained in my personal free time. As a solo enthusiast (not a business or team) my resources are inherently limited. This project has been one of my passions, but I must balance it with other commitments.
|
||||
|
||||
To manage AllTalk sustainably, I prioritize support requests based on their overall impact and the number of users affected. I encourage you to utilize the comprehensive documentation and engage with the AllTalk community discussion area. These resources often provide immediate answers and foster a supportive user network.
|
||||
|
||||
Should your inquiry extend beyond the documentation, especially if it concerns a bug or feature request, I assure you I’ll offer my best support as my schedule permits. However, please be prepared for varying response times, reflective of the personal dedication I bring to AllTalk. Your understanding and patience in this regard are greatly appreciated.
|
||||
|
||||
It's important to note that **I am not** the developer of any TTS models utilized by AllTalk, nor do I claim to be an expert on them, including understanding all their nuances, issues, and quirks. For specific TTS model concerns, I’ve provided links to the original developers in the Help section for direct assistance.
|
||||
|
||||
Thank you for your continued support and understanding.
|
||||
|
||||
---
|
||||
|
||||
@@ -68,7 +76,7 @@ To set up AllTalk within Text-generation-webui, follow either method:
|
||||
- **Via Terminal/Console (Recommended)**:
|
||||
- `cd \text-generation-webui\extensions\`
|
||||
- `git clone https://github.com/erew123/alltalk_tts`
|
||||
- **Via Releases Page**:
|
||||
- **Via Releases Page (Cannot be automatically updated after install as its not linked to Github)**:
|
||||
- Download the latest `alltalk_tts.zip` from [Releases](https://github.com/erew123/alltalk_tts/releases) and extract it to `\text-generation-webui\extensions\alltalk_tts\`.
|
||||
|
||||
2. **Start Python Environment**:
|
||||
@@ -104,7 +112,7 @@ To perform a Standalone installation of AllTalk:
|
||||
- **Via Terminal/Console (Recommended)**:
|
||||
- Navigate to your preferred directory: `cd C:\myfiles\`
|
||||
- Clone the AllTalk repository: `git clone https://github.com/erew123/alltalk_tts`
|
||||
- **Via Releases Page**:
|
||||
- **Via Releases Page (Cannot be automatically updated after install as its not linked to Github)**:
|
||||
- Download `alltalk_tts.zip` from [Releases](https://github.com/erew123/alltalk_tts/releases) and extract it to your chosen directory, for example, `C:\myfiles\alltalk_tts\`.
|
||||
|
||||
2. **Start AllTalk Setup**:
|
||||
@@ -114,15 +122,24 @@ To perform a Standalone installation of AllTalk:
|
||||
- Linux: `./atsetup.sh`
|
||||
|
||||
3. **Follow the Setup Prompts**:
|
||||
- Comply with the on-screen instructions to install the required files. Verify AllTalk's functionality before proceeding with DeepSpeed installation.
|
||||
- Select Standalone Installation and then Option 1 and follow any on-screen instructions to install the required files. DeepSpeed is automatically installed on **Windows** based system, but will only work on Nvidia GPU's. **Linux** based system users will have to follow the DeepSpeed installation instructions.
|
||||
|
||||
> If you're unfamiliar with Python environments and wish to learn more, consider reviewing **Understanding Python Environments Simplified** in the Help section.
|
||||
|
||||
> **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.
|
||||
> **Important**: Do not use spaces in your folder path (e.g. avoid `/my folder-is-this/alltalk_tts-main`) as this causes issues with Python & Conda.
|
||||
|
||||
</details>
|
||||
|
||||
Refer to `🟩 Other installation notes` for further details, including information on additional voices, changing IP, character card notes etc.
|
||||
> If you wish to understand AllTalks start-up screen, please read **Understanding the AllTalk start-up screen** in the Help section.
|
||||
|
||||
---
|
||||
|
||||
### 🟩 Docker Builds and Google Colab's
|
||||
|
||||
While an AllTalk Docker build exists, it's important to note that this version is based on an earlier iteration of AllTalk and was set up by a third party. At some point, my goal is to deepen my understanding of Docker and its compatibility with AllTalk. This exploration may lead to significant updates to AllTalk to ensure a seamless Docker experience. However, as of now, the Docker build should be considered a BETA version and isn't directly supported by me.
|
||||
|
||||
As for Google Colab, there is partial compatibility with AllTalk, though with some quirks. I am currently investigating these issues and figuring out the necessary adjustments to enhance the integration. Until I can ensure a smooth experience, I won't be officially releasing any Google Colab implementations of AllTalk.
|
||||
|
||||
---
|
||||
|
||||
@@ -160,11 +177,9 @@ If you're using a Mac or prefer a manual installation for any other reason, plea
|
||||
- `cd alltalk_tts`
|
||||
|
||||
6. **Install Required Dependencies**:
|
||||
- Install dependencies based on your machine type:
|
||||
- For Nvidia graphics card machines:
|
||||
- `pip install -r requirements_nvidia.txt`
|
||||
- For other machines (mac, AMD, etc.):
|
||||
- `pip install -r requirements_other.txt`
|
||||
- Install dependencies for your machine type:
|
||||
- For Windows: `pip install -r system\requirements\requirements_textgen.txt`
|
||||
- For Linux/Mac: `pip install -r system/requirements/requirements_textgen.txt`
|
||||
|
||||
7. **Optional DeepSpeed Installation**:
|
||||
- If you're using an Nvidia graphics card on Linux or Windows and wish to install **DeepSpeed**, follow the instructions [here](https://github.com/erew123/alltalk_tts?#-deepspeed-installation-options).
|
||||
@@ -223,7 +238,7 @@ Support for custom Python environments is limted. Please read **Custom Python en
|
||||
To run AllTalk as a standalone application with a custom Python environment, ensure you install AllTalk's requirements into the environment of your choice. The instructions provided are generalized due to the variety of potential Python environments.
|
||||
|
||||
- **Python Compatibility**: The TTS engine requires Python **3.9.x** to **3.11.x**. AllTalk is tested with Python **3.11.x**. [See TTS Engine details](https://pypi.org/project/TTS/).
|
||||
- **Path Names**: Avoid spaces and dashes `-` in path names as this can cause issues.
|
||||
- **Path Names**: Avoid spaces in path names as this can cause issues.
|
||||
- **Custom Python Environments**: If encountering issues potentially related to a custom environment, consider testing AllTalk with the quick setup standalone method that builds its own environment.
|
||||
|
||||
#### Quick Overview of Python Environments
|
||||
@@ -254,10 +269,8 @@ To run AllTalk as a standalone application with a custom Python environment, ens
|
||||
|
||||
5. **Install Requirements**:
|
||||
- Install dependencies based on your machine type:
|
||||
- For Nvidia graphics card machines:
|
||||
- `pip install -r requirements_nvidia.txt`
|
||||
- For other machines (mac, AMD, etc.):
|
||||
- `pip install -r requirements_other.txt`
|
||||
- For Windows: `pip install -r system\requirements\requirements_standalone.txt`
|
||||
- For Linux/Mac: `pip install -r system/requirements/requirements_standalone.txt`
|
||||
|
||||
6. **Start AllTalk**:
|
||||
- Run AllTalk with the following:
|
||||
@@ -373,12 +386,18 @@ The update process closely mirrors the installation steps. Follow these to ensur
|
||||
- **For Linux/Mac**:
|
||||
- `pip install -r system/requirements/requirements_textgen.txt`
|
||||
|
||||
5. **DeepSpeed Requirements**:
|
||||
- If Text-gen-webui is using a new version of PyTorch, you may need to uninstall and update your DeepSpeed version.
|
||||
- Use AllTalks diagnostics or start-up menu to identify your version of PyTorch.
|
||||
<br><br>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>UPDATING - Standalone Application</summary>
|
||||
<br>
|
||||
|
||||
If you installed from a ZIP file, you cannot use a `git pull` to update, as noted in the Quick Setup instructions.
|
||||
|
||||
For Standalone Application users, here's how to update your setup:
|
||||
|
||||
1. **Open a Command Prompt/Terminal**:
|
||||
@@ -404,7 +423,7 @@ For Standalone Application users, here's how to update your setup:
|
||||
- `pip install -r system\requirements\requirements_standalone.txt`
|
||||
- **For Linux/Mac**:
|
||||
- `pip install -r system/requirements/requirements_standalone.txt`
|
||||
|
||||
<br><br>
|
||||
</details>
|
||||
|
||||
### 🟪 Resolving Update Issues
|
||||
@@ -412,46 +431,26 @@ For Standalone Application users, here's how to update your setup:
|
||||
If you encounter problems during or after an update, following these steps can help resolve the issue by refreshing your installation while preserving your data:
|
||||
|
||||
<details>
|
||||
<summary>RESOLVING - Text-Generation-webui</summary><br>
|
||||
<summary>RESOLVING - Updates</summary><br>
|
||||
|
||||
The process involves renaming your existing `alltalk_tts` directory, setting up a fresh instance, and then migrating your data:
|
||||
|
||||
1. **Rename Existing Directory**:
|
||||
- First, rename your current `alltalk_tts` folder to back it up, e.g., `alltalk_tts.old`. This preserves any existing data.
|
||||
- First, rename your current `alltalk_tts` folder to keep it safe e.g. `alltalk_tts.old`. This preserves any existing data.
|
||||
|
||||
2. **Open a Console/Terminal**:
|
||||
- Navigate to the Text-generation-webui directory and start the Python environment appropriate for your operating system:
|
||||
- `cd text-generation-webui`
|
||||
|
||||
- Then use one of the following commands based on your OS:
|
||||
- Windows: `cmd_windows.bat`
|
||||
- Linux: `./cmd_linux.sh`
|
||||
- macOS: `cmd_macos.sh`
|
||||
- WSL (Windows Subsystem for Linux): `cmd_wsl.bat`<br><br>
|
||||
2. **Follow the Quick Setup instructions**:
|
||||
- You will now follow the **Quick Setup** instructions, performing the `git clone https://github.com/erew123/alltalk_tts` to pull down a new copy of AllTalk and install the requirements.
|
||||
|
||||
> If you're not familiar with Python environments, see **Understanding Python Environments Simplified** in the Help section for more info.
|
||||
|
||||
3. **Clone the AllTalk TTS Repository**:
|
||||
- Move into the `extensions` directory and clone a fresh copy of `alltalk_tts`:
|
||||
- `cd extensions`
|
||||
- `git clone https://github.com/erew123/alltalk_tts`
|
||||
3. **Migrate Your Data**:
|
||||
- **Before** starting the AllTalk, transfer the `models`, `voices`, `outputs` folders and also `confignew.json` from `alltalk_tts.old` to the new `alltalk_tts` directory. This action preserves your voice history and prevents the need to re-download the model.
|
||||
|
||||
4. **Install Requirements**:
|
||||
- Navigate to the newly cloned `alltalk_tts` directory and install the necessary dependencies for your system:
|
||||
- `cd alltalk_tts`
|
||||
- Depending on your machine's OS, install the required dependencies using pip:
|
||||
- **For Windows Machines**:
|
||||
- `pip install -r system\requirements\requirements_textgen.txt`
|
||||
- **For Linux/Mac**:
|
||||
- `pip install -r system/requirements/requirements_textgen.txt`
|
||||
|
||||
5. **Migrate Your Data**:
|
||||
- Before starting the application, transfer the `models`, `voices`, and `outputs` folders from `alltalk_tts.old` to the new `alltalk_tts` directory. This action preserves your voice history and prevents the need to re-download the model.
|
||||
|
||||
You're now ready to launch Text-generation-webui. Note that you may need to reapply any previously saved configuration changes through the configuration page.
|
||||
4) **Launch AllTalk**
|
||||
- You're now ready to launch AllTalk and check it works correctly.
|
||||
|
||||
6. **Final Step**:
|
||||
- Once you've verified that everything is working as expected and you're satisfied with the setup, feel free to delete the `alltalk_tts.old` directory to free up space.
|
||||
- Once you've verified that everything is working as expected and you're satisfied with the setup, feel free to delete the `alltalk_tts.old` directory to free up space.
|
||||
|
||||
</details>
|
||||
|
||||
@@ -715,7 +714,7 @@ When a Python environment starts up, it changes the command prompt to show the P
|
||||
<details>
|
||||
<summary>🟨 Standalone Install - start_{youros}.xx opens and closes instantly and AllTalk doesnt start</summary><br>
|
||||
|
||||
This is more than likely caused by having a `-` in your folder path e.g. `c:\myfiles\alltalk_tts-main`. In this circumstance you would be best renaming the folder to remove the `-` from its name e.g. `c:\myfiles\alltalk_tts`, delete the `alltalk_environment` folder and `start_alltalk.bat` or `start_alltalk.sh` and then re-run `atsetup` to re-create the environment and startup files.
|
||||
This is more than likely caused by having a space ` ` in your folder path e.g. `c:\program files\alltalk_tts`. In this circumstance you would be best moving the folder to a path without a space e.g. `c:\myfiles\alltalk_tts`. You would have to delete the `alltalk_environment` folder and `start_alltalk.bat` or `start_alltalk.sh` and then re-run `atsetup` to re-create the environment and startup files.
|
||||
</details>
|
||||
<details>
|
||||
<summary>🟨 I think AllTalks requirements file has installed something another extension doesn't like</summary><br>
|
||||
@@ -775,7 +774,114 @@ Also, is your text-generation-webui up to date? [instructions here](https://gith
|
||||
As far as I am aware, these are to do with the chrome browser the gradio text-generation-webui in some way. I raised an issue about this on the text-generation-webui [here](https://github.com/oobabooga/text-generation-webui/issues/4788) where you can see that AllTalk is not loaded and the messages persist. Either way, this is more a warning than an actual issue, so shouldnt affect any functionality of either AllTalk or text-generation-webui, they are more just an annoyance.
|
||||
</details>
|
||||
|
||||
### Performance and Compatibility Issues
|
||||
### Startup, Performance and Compatibility Issues
|
||||
|
||||
<details>
|
||||
<summary>🟨 Understanding the AllTalk start-up screen</summary><br>
|
||||
|
||||
The AllTalk start-up screen provides various bits of information about the detected Python environment and errors.
|
||||
|
||||

|
||||
|
||||
**Config file check**<br>
|
||||
- Sometimes I need to add/remove something to your existing configuration file settings. Obviously, I don’t want to impact your existing settings, however any new features may need these settings to be created before AllTalk starts up. Ive added extra code that checks `alltalk_tts/system/config/at_configupdate.json` and `alltalk_tts/system/config/at_configdowngrade.json`, either adding or removing items to your configuration as necessary. If a change is made, you will be notified and a backup of the previous configuration file will be created in the `alltalk_tts` folder.
|
||||
|
||||
**AllTalk startup Mode**<br>
|
||||
- informational. This will state if AllTalk has detected it is running as part of Text-generation-webui or as a Standalone Application.
|
||||
|
||||
**WAV file deletion**<br>
|
||||
- If you have set deletion of old generated WAV files, this will state the time frame after which they are purged.
|
||||
|
||||
**DeepSpeed version**<br>
|
||||
- What version of DeepSpeed is installed/detected. This will **not** tell you if the version of DeepSpeed is compiled for your Python, PyTorch or CUDA version. Its important to remember that DeepSpeed has to be compiled for the exact version of Python, PyTorch and CUDA that you are using, so please ensure you have the correct DeepSpeed version installed if necessary.
|
||||
|
||||
**Model is available**<br>
|
||||
- AllTalk is checking if your model files exist. This is not a validity check of the actual model files, they can still be corrupted. If files are missing, AllTalk will attempt to download them from Huggingface, however, if Huggingface has an outage/issue or your internet connection has issues, its possible corrupted or incomplete files will be downloaded. Please read `RuntimeError: PytorchStreamReader failed reading zip archive: failed finding central directory` if you need to confirm your model files are ok.
|
||||
|
||||
**Current Python Version**<br>
|
||||
- Informational. Literally tells you the version of Python running in your Python environment.
|
||||
|
||||
**Current PyTorch Version**<br>
|
||||
- Informational. Tell tells you the version of **PyTorch** running in your Python environment, however if you have an Nvidia card, you should be running a CUDA based version of Pytorch. This is indicated with a `+cXXX` after the PyTorch version e.g. `2.2.2+cu121` would be PyTorch version 2.2.2 with CUDA 12.1 extensions. If you don’t have the PyTorch CUDA extensions installed, but you do have an Nvidia card, you may need to re-install PyTorch.
|
||||
|
||||
**Current CUDA Version**<br>
|
||||
- Informational. This is linked to the Current PyTorch Version, as detailed above.
|
||||
|
||||
**Current TTS Version**<br>
|
||||
- Informational. The current version of the TTS engine that is running.
|
||||
|
||||
**AllTalk Github updated**<br>
|
||||
- As long as you have an internet connection, this will tell you last time AllTalk was updated on Github. It is checking the [commit list](https://github.com/erew123/alltalk_tts/commits/main/) to see when the last commit was made. As such, this could be simply a documentation update, a bug fix or new features. Its simply there as a guide to let you know the last time something was changed on AllTalk's Github.
|
||||
|
||||
**TTS Subprocess**<br>
|
||||
- When AllTalk reaches this stage, the subprocess that loads in the AI model is starting. This is most likely where an error could occur with loading the TTS model, just after the documentation message.
|
||||
|
||||
**AllTalk Settings & Documentation: http ://x.x.x.x**<br>
|
||||
- The link where you can reach AllTalks built in settings and documentation page. The TTS model will be loading immediately after this is displayed.
|
||||
<br><br>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🟨 AllTalk is only loading into CPU, but I have an Nvidia GPU so it should be loading into CUDA</summary><br>
|
||||
|
||||
This is caused by Pytorch (Torch) not having the CUDA extensions installed (You can check by running the diagnostics). Typically this happens (on Standalone installations) because when the setup routine goes to install Pytorch with CUDA, it looks in the PIP cache and if a previous application has downloaded a version of Pytorch that **doesn't** have CUDA extensions, the PIP installer doesnt recognise this fact and just uses the cached version for installation. To resolve this:
|
||||
|
||||
1) On the `atsetup` utility, on the `Standalone menu` select to `Purge the PIP cache`. This will remove cached packages from the PIP cache, meaning it will have to download fresh copies.
|
||||
2) As we need to force the upgrade to the Python environment, the easiest way to do this will be to use `atsetup` to `Delete AllTalk's custom Python environment`. This means it will have to rebuild the Python environment. **Note**, you may have to run this step twice, as it has to exit the current Python environment, then you have to re-load `atsetup` and select `Delete AllTalk's custom Python environment` again.
|
||||
3) You can now use `atsetup` to `Install AllTalk as a Standalone Application` which will download fresh copies of everything and re-install the Python environment.
|
||||
4) Once this is done you can check if CUDA is now working with the diagnostics or starting AllTalk and checking the model loads into CUDA.
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>🟨 RuntimeError: PytorchStreamReader failed reading zip archive: failed finding central directory</summary><br>
|
||||
|
||||
This error message is caused by the model being corrupted or damaged in some way. This error can occur if Huggingface, where the model is downloaded from, have an error (when the model is downloaded) or potentailly internet issues occuring while the model is downloaded on first start-up.
|
||||
|
||||
```
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
RuntimeError: PytorchStreamReader failed reading zip archive: failed finding central directory
|
||||
|
||||
ERROR: Application startup failed. Exiting.
|
||||
[AllTalk Startup] Warning TTS Subprocess has NOT started up yet, Will keep trying for 120 seconds maximum. Please wait.
|
||||
```
|
||||
|
||||
To resolve this, first look in your `alltalk_tts/models/xttsv2_2.0.2` (or whichever) model folder and confirm that the file sizes are correct.
|
||||
|
||||

|
||||
|
||||
You can delete one or more suspect files and a factory fresh copy of that file or files will be downloaded on next start-up of AllTalk.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🟨 RuntimeError: Found no NVIDIA driver on your system.</summary><br>
|
||||
|
||||
This error message is caused by DeepSpeed being enabled when you do not have a Nvidia GPU. To resolve this, edit `confignew.json` and change `"deepspeed_activate": true,` to `"deepspeed_activate": false,` then restart AllTalk.
|
||||
|
||||
```
|
||||
File "C:\alltalk_tts\alltalk_environment\env\Lib\site-packages\torch\cuda\__init__.py", line 302, in _lazy_init
|
||||
torch._C._cuda_init()
|
||||
RuntimeError: Found no NVIDIA driver on your system. Please check that you have an NVIDIA GPU and installed a driver from http://www.nvidia.com/Download/index.aspx
|
||||
|
||||
ERROR: Application startup failed. Exiting.
|
||||
[AllTalk Startup] Warning TTS Subprocess has NOT started up yet, Will keep trying for 120 seconds maximum. Please wait.
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🟨 raise RuntimeError("PyTorch version mismatch! DeepSpeed ops were compiled and installed.</summary><br>
|
||||
|
||||
This error message is caused by having DeepSpeed enabled, but you have a version of DeepSpeed installed that was compiled for a different version of Python, PyTorch or CUDA (or any mix of those). You will need to start your Python environment and run `pip uninstall deepspeed` to remove DeepSpeed from your Python environment and then install the correct version of DeepSpeed.
|
||||
|
||||
```
|
||||
raise RuntimeError("PyTorch version mismatch! DeepSpeed ops were compiled and installed
|
||||
RuntimeError: PyTorch version mismatch! DeepSpeed ops were compiled and installed with a different version than what is being used at runtime. Please re-install DeepSpeed or switch torch versions. Install torch version=2.1, Runtime torch version=2.2
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🟨 Warning TTS Subprocess has NOT started up yet, Will keep trying for 120 seconds maximum. Please wait. It times out after 120 seconds.</summary><br>
|
||||
@@ -833,7 +939,13 @@ Depending on which of your Nvidia GPU's is the more powerful one, you can change
|
||||
<details>
|
||||
<summary>🟨 Firefox - Streaming Audio doesnt work on Firefox</summary><br>
|
||||
|
||||
This is a long standing issue with Firefox and one I am unable to resolve. The solution is to use another web browser if you want to use Streaming audio. For details of my prior invesitigation please look at this [ticket](https://github.com/erew123/alltalk_tts/issues/143)
|
||||
This is a long standing issue with Mozilla & Firefox and one I am unable to resolve as Mozilla have not resolved the issue with Firefox. The solution is to use another web browser if you want to use Streaming audio. For details of my prior invesitigation please look at this [ticket](https://github.com/erew123/alltalk_tts/issues/143)
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🟨 Hindi Support - Not working or issues</summary><br>
|
||||
|
||||
Hindi support does not officially exist according to Coqui. Ive added a limited Hindi support at this time, however, It only works with API TTS method and Im sure there will be issues. [ticket](https://github.com/erew123/alltalk_tts/issues/178)
|
||||
</details>
|
||||
|
||||
### Application Specific Issues
|
||||
@@ -889,7 +1001,7 @@ If you wish to try out the XTTS version 2.0.3 model and see if it works better,
|
||||
### ⚫ Finetuning a model
|
||||
If you have a voice that the model doesnt quite reproduce correctly, or indeed you just want to improve the reproduced voice, then finetuning is a way to train your "XTTSv2 local" model **(stored in `/alltalk_tts/models/xxxxx/`)** on a specific voice. For this you will need:
|
||||
|
||||
- An Nvidia graphics card. (Please see the help section [note](https://github.com/erew123/alltalk_tts/edit/main/README.md#performance-and-compatibility-issues) if you have multiple Nvidia GPU's).
|
||||
- An Nvidia graphics card. (Please see the help section [note](https://github.com/erew123/alltalk_tts/edit/main/README.md#performance-and-compatibility-issues) if you have multiple Nvidia GPU's). Preferably 12GB+ VRAM on Windows. Minimum 16GB VRAM on Linux.
|
||||
- 18GB of disk space free (most of this is used temporarily)
|
||||
- At least 2 minutes of good quality speech from your chosen speaker in mp3, wav or flacc format, in one or more files (have tested as far as 20 minutes worth of audio).
|
||||
- As a side note, many people seem to think that the Whisper v2 model (used on Step 1) is giving better results at generating training datasets, so you may prefer to try that, as opposed to the Whisper 3 model.
|
||||
@@ -1051,6 +1163,14 @@ At the end of the finetune process, you will have an option to `Compact and move
|
||||
|
||||
If you've compacted and moved your model, its highly unlikely you would want to keep that data, however the choice is there to keep it if you wish. It will be between 5-10GB in size, so most people will want to delete it.
|
||||
|
||||
#### ⚫ I have deeper questions about training the XTTS model, where can I find more information?
|
||||
|
||||
If you have deeper questions about the XTTS model, its capabilites, the training process etc, anything thats not covered within the above text or the interface of `finetune.py`, please use the following links to research Coqui's documentation on the XTTS model.
|
||||
|
||||
- https://docs.coqui.ai/en/latest/models/xtts.html
|
||||
- https://github.com/coqui-ai/TTS
|
||||
- https://github.com/coqui-ai/TTS/discussions
|
||||
|
||||
---
|
||||
|
||||
### ⬜ AllTalk TTS Generator
|
||||
@@ -1102,6 +1222,8 @@ You will be able to see the ID's and Text (orignal and as interpreted) by lookin
|
||||
|
||||
The Analyze TTS feature uses the Whisper Larger-v2 AI engine, which will download on first use if necessary. This will require about 2.5GB's of disk space and could take a few minutes to download, depending on your internet connection.
|
||||
|
||||
You can use this feature on systems that do not have an Nvidia GPU, however, unless you have a very powerful CPU, expect it to be slow.
|
||||
|
||||
#### ⬜ Tricks to get the model to say things correctly
|
||||
Sometimes the AI model won’t say something the way that you want it to. It could be because it’s a new word, an acronym or just something it’s not good at for whatever reason. There are some tricks you can use to improve the chances of it saying something correctly.
|
||||
|
||||
@@ -1275,6 +1397,7 @@ Example:
|
||||
`en` English<br>
|
||||
`fr` French<br>
|
||||
`de` German<br>
|
||||
`hi` Hindi (Please see this re Hindi support, which is very limited https://github.com/erew123/alltalk_tts/issues/178) <br>
|
||||
`hu` Hungarian<br>
|
||||
`it` Italian<br>
|
||||
`ja` Japanese<br>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@echo off
|
||||
cd /D "%~dp0"
|
||||
|
||||
set PATH=%PATH%;%SystemRoot%\system32
|
||||
setlocal enabledelayedexpansion
|
||||
@set "PATH=%PATH%;%SystemRoot%\system32"
|
||||
|
||||
:: Generate the ESC character
|
||||
for /F %%a in ('echo prompt $E ^| cmd') do set "ESC=%%a"
|
||||
@@ -25,6 +25,15 @@ set "L_CYAN=%ESC%[96m"
|
||||
set "L_WHITE=%ESC%[97m"
|
||||
set "RESET=%ESC%[0m"
|
||||
|
||||
echo "%CD%"| findstr /C:" " >nul && echo. && echo %L_BLUE%ALLTALK WINDOWS SETUP UTILITY%RESET% && echo. && echo. && echo You are trying to install AllTalk in a folder that has a space in the folder path e.g. && echo. && echo C:\%L_RED%program files%RESET%\alltalk_tts && echo. && echo This causes errors with Conda and Python scripts. Please follow this link for reference: && echo. && echo %L_CYAN%https://docs.anaconda.com/free/working-with-conda/reference/faq/#installing-anaconda%RESET% && echo. && echo Please use a folder path that has no spaces in it e.g. && echo. && echo C:\myfiles\alltalk_tts\ && echo. && echo. && pause && goto :end
|
||||
|
||||
@rem Check for special characters in installation path
|
||||
set "SPCHARMESSAGE="WARNING: Special characters were detected in the installation path!" " This can cause the installation to fail!""
|
||||
echo "%CD%"| findstr /R /C:"[!#\$%&()\*+,;<=>?@\[\]\^`{|}~]" >nul && (
|
||||
call :PrintBigMessage %SPCHARMESSAGE%
|
||||
)
|
||||
set SPCHARMESSAGE=
|
||||
|
||||
@rem Check if curl is available
|
||||
curl --version >nul 2>&1
|
||||
if "%ERRORLEVEL%" NEQ "0" (
|
||||
@@ -120,7 +129,7 @@ if "%StandaloneOption%"=="3" goto STReapplyrequirements
|
||||
if "%StandaloneOption%"=="4" goto STDeleteCustomStandalone
|
||||
if "%StandaloneOption%"=="5" goto STPurgepipcache
|
||||
if "%StandaloneOption%"=="8" goto GenerateDiagsStandalone
|
||||
if "%StandaloneOption%"=="9" goto End
|
||||
if "%StandaloneOption%"=="9" goto EndStandalone
|
||||
goto StandaloneMenu
|
||||
|
||||
:InstallNvidiaTextGen
|
||||
@@ -128,6 +137,8 @@ pip install -r system\requirements\requirements_textgen.txt
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
echo.
|
||||
echo There was an error installing the requirements.
|
||||
echo Have you started your Text-gen-webui Python environment
|
||||
echo with cmd_{yourOS} before running atsetup.bat?
|
||||
echo Press any key to return to the menu.
|
||||
echo.
|
||||
pause
|
||||
@@ -383,14 +394,14 @@ echo Downloading and installing PyTorch. This step can take a long time
|
||||
echo depending on your internet connection and hard drive speed. Please
|
||||
echo be patient.
|
||||
echo.
|
||||
pip install torch>=2.2.1+cu121 torchaudio>=2.2.1+cu121 --extra-index-url https://download.pytorch.org/whl/cu121
|
||||
pip install torch==2.2.2+cu121 torchaudio>=2.2.2+cu121 --upgrade --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121
|
||||
echo Installing other requirements.
|
||||
echo.
|
||||
pip install -r system\requirements\requirements_standalone.txt
|
||||
curl -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-12.7/deepspeed-0.12.7+d058d4b-cp311-cp311-win_amd64.whl
|
||||
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.12.7+d058d4b-cp311-cp311-win_amd64.whl
|
||||
del deepspeed-0.12.7+d058d4b-cp311-cp311-win_amd64.whl
|
||||
pip install deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
del deepspeed-0.14.0+ce78a63-cp311-cp311-win_amd64.whl
|
||||
|
||||
|
||||
@rem Create start_environment.bat to run AllTalk environment
|
||||
@@ -524,14 +535,14 @@ echo Downloading and installing PyTorch. This step can take a long time
|
||||
echo depending on your internet connection and hard drive speed. Please
|
||||
echo be patient.
|
||||
echo.
|
||||
pip install torch>=2.2.1+cu121 torchaudio>=2.2.1+cu121 --extra-index-url https://download.pytorch.org/whl/cu121
|
||||
pip install torch==2.2.2+cu121 torchaudio>=2.2.2+cu121 --upgrade --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121
|
||||
echo Installing other requirements.
|
||||
echo.
|
||||
pip install -r system\requirements\requirements_standalone.txt
|
||||
curl -LO https://github.com/erew123/alltalk_tts/releases/download/DeepSpeed-12.7/deepspeed-0.12.7+d058d4b-cp311-cp311-win_amd64.whl
|
||||
C:/Windows/system32/curl.exe -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.12.7+d058d4b-cp311-cp311-win_amd64.whl
|
||||
del deepspeed-0.12.7+d058d4b-cp311-cp311-win_amd64.whl
|
||||
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.
|
||||
@@ -633,6 +644,16 @@ Echo.
|
||||
pause
|
||||
goto StandaloneMenu
|
||||
|
||||
:EndStandalone
|
||||
echo Exiting AllTalk Setup Utility...
|
||||
echo.
|
||||
Echo Remember, after installation you can....
|
||||
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.
|
||||
exit /b
|
||||
|
||||
:End
|
||||
echo Exiting AllTalk Setup Utility...
|
||||
exit /b
|
||||
@@ -28,6 +28,40 @@ check_curl() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if the current directory path contains a space
|
||||
containsSpace=false
|
||||
currentPath=$(pwd)
|
||||
if echo "$currentPath" | grep -q ' '; then
|
||||
containsSpace=true
|
||||
fi
|
||||
|
||||
if [ "$containsSpace" = true ]; then
|
||||
echo
|
||||
echo -e " ${L_BLUE}ALLTALK LINUX SETUP UTILITY${NC}"
|
||||
echo
|
||||
echo
|
||||
echo -e " You are trying to install AllTalk in a folder that has a space in the"
|
||||
echo -e " folder path e.g."
|
||||
echo
|
||||
echo -e " /home/${L_RED}program files${NC}/alltalk_tts"
|
||||
echo
|
||||
echo -e " This causes errors with Conda and Python scripts. Please follow this"
|
||||
echo -e " link for reference:"
|
||||
echo
|
||||
echo -e " ${L_CYAN}https://docs.anaconda.com/free/working-with-conda/reference/faq/#installing-anaconda${NC}"
|
||||
echo
|
||||
echo -e " Please use a folder path that has no spaces in it e.g."
|
||||
echo
|
||||
echo -e " /home/myfiles/alltalk_tts/"
|
||||
echo
|
||||
echo
|
||||
read -p "Press Enter to continue..."
|
||||
exit 1
|
||||
else
|
||||
# Continue with the main menu
|
||||
echo "Continue with the main menu."
|
||||
fi
|
||||
|
||||
# Main Menu
|
||||
main_menu() {
|
||||
while true; do
|
||||
@@ -291,7 +325,7 @@ install_custom_standalone() {
|
||||
echo " Downloading and installing PyTorch. This step can take a long time"
|
||||
echo " depending on your internet connection and hard drive speed. Please"
|
||||
echo " be patient."
|
||||
pip install torch>=2.2.1+cu121 torchaudio>=2.2.1+cu121 --extra-index-url https://download.pytorch.org/whl/cu121
|
||||
pip install torch>=2.2.1+cu121 torchaudio>=2.2.1+cu121 --upgrade --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121
|
||||
echo
|
||||
echo " Installing additional requirements."
|
||||
echo
|
||||
@@ -469,7 +503,7 @@ reapply_standalone() {
|
||||
echo " Downloading and installing PyTorch. This step can take a long time"
|
||||
echo " depending on your internet connection and hard drive speed. Please"
|
||||
echo " be patient."
|
||||
pip install torch>=2.2.1+cu121 torchaudio>=2.2.1+cu121 --extra-index-url https://download.pytorch.org/whl/cu121
|
||||
pip install torch>=2.2.1+cu121 torchaudio>=2.2.1+cu121 --upgrade --force-reinstall --extra-index-url https://download.pytorch.org/whl/cu121
|
||||
echo
|
||||
echo " Installing additional requirements."
|
||||
echo
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
version: '3.8'
|
||||
services:
|
||||
alltalk-tts:
|
||||
image: erew123/alltalk_tts:cpu
|
||||
image: alltalk:v1-9c
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "7851:7851"
|
||||
- "7852:7852"
|
||||
volumes:
|
||||
- ./outputs:/app/outputs/
|
||||
- ./models:/app/models/
|
||||
- ./voices:/app/voices/
|
||||
- ./finetune/put-voice-samples-in-here:/app/finetune/put-voice-samples-in-here
|
||||
- ./dockerconfig.json:/app/confignew.json
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [ gpu ]
|
||||
@@ -291,12 +291,12 @@ def create_temporary_file(folder, suffix=".wav"):
|
||||
unique_filename = f"custom_tempfile_{int(time.time())}_{random.randint(1, 1000)}{suffix}"
|
||||
return os.path.join(folder, unique_filename)
|
||||
|
||||
def format_audio_list(target_language, whisper_model, out_path, eval_split_number, gradio_progress=progress):
|
||||
def format_audio_list(target_language, whisper_model, out_path, eval_split_number, speaker_name_input, gradio_progress=progress):
|
||||
pfc_check_fail()
|
||||
audio_files = [os.path.join(audio_folder, file) for file in os.listdir(audio_folder) if file.endswith(('.mp3', '.flac', '.wav'))]
|
||||
buffer=0.2
|
||||
eval_percentage = eval_split_number / 100.0
|
||||
speaker_name="coqui"
|
||||
speaker_name=speaker_name_input
|
||||
audio_total_size = 0
|
||||
os.makedirs(out_path, exist_ok=True)
|
||||
temp_folder = os.path.join(out_path, "temp") # Update with your folder name
|
||||
@@ -533,7 +533,7 @@ def basemodel_or_finetunedmodel_choice(value):
|
||||
elif value == "Existing finetuned model":
|
||||
basemodel_or_finetunedmodel = False
|
||||
|
||||
def train_gpt(language, num_epochs, batch_size, grad_acumm, train_csv, eval_csv, output_path, max_audio_length=255995):
|
||||
def train_gpt(language, num_epochs, batch_size, grad_acumm, train_csv, eval_csv, learning_rate, output_path, max_audio_length=255995):
|
||||
pfc_check_fail()
|
||||
# Logging parameters
|
||||
RUN_NAME = "XTTS_FT"
|
||||
@@ -657,7 +657,7 @@ def train_gpt(language, num_epochs, batch_size, grad_acumm, train_csv, eval_csv,
|
||||
optimizer="AdamW",
|
||||
optimizer_wd_only_on_weights=OPTIMIZER_WD_ONLY_ON_WEIGHTS,
|
||||
optimizer_params={"betas": [0.9, 0.96], "eps": 1e-8, "weight_decay": 1e-2},
|
||||
lr=5e-06, # learning rate
|
||||
lr=learning_rate, # learning rate
|
||||
lr_scheduler="MultiStepLR",
|
||||
# it was adjusted accordly for the new step scheme
|
||||
lr_scheduler_params={"milestones": [50000 * 18, 150000 * 18, 300000 * 18], "gamma": 0.5, "last_epoch": -1},
|
||||
@@ -735,6 +735,9 @@ def load_model(xtts_checkpoint, xtts_config, xtts_vocab):
|
||||
config.load_json(xtts_config)
|
||||
XTTS_MODEL = Xtts.init_from_config(config)
|
||||
print("[FINETUNE] \033[94mStarting Step 3\033[0m Loading XTTS model!")
|
||||
print(xtts_checkpoint)
|
||||
print(xtts_vocab)
|
||||
print(xtts_speakers_pth)
|
||||
XTTS_MODEL.load_checkpoint(config, checkpoint_path=xtts_checkpoint, vocab_path=xtts_vocab, use_deepspeed=False, speaker_file_path=xtts_speakers_pth)
|
||||
if torch.cuda.is_available():
|
||||
XTTS_MODEL.cuda()
|
||||
@@ -773,18 +776,22 @@ def get_available_voices(minimum_size_kb=1200):
|
||||
]
|
||||
return sorted([str(file) for file in voice_files]) # Return full path as string
|
||||
|
||||
def find_best_models(directory):
|
||||
"""Find files named 'best_model.pth' in the given directory."""
|
||||
return [str(file) for file in Path(directory).rglob("best_model.pth")]
|
||||
|
||||
def find_models(directory, extension):
|
||||
"""Find files with a specific extension in the given directory."""
|
||||
return [file for file in Path(directory).rglob(f"*.{extension}")]
|
||||
return [str(file) for file in Path(directory).rglob(f"*.{extension}")]
|
||||
|
||||
def find_jsons(directory, filename):
|
||||
"""Find files with a specific filename in the given directory."""
|
||||
return list(Path(directory).rglob(filename))
|
||||
return [str(file) for file in Path(directory).rglob(filename)]
|
||||
|
||||
# Your main directory
|
||||
main_directory = Path(this_dir) / "finetune" / "tmp-trn"
|
||||
# XTTS checkpoint files (*.pth)
|
||||
xtts_checkpoint_files = find_models(main_directory, "pth")
|
||||
# XTTS checkpoint files (best_model.pth)
|
||||
xtts_checkpoint_files = find_best_models(main_directory)
|
||||
# XTTS config files (config.json)
|
||||
xtts_config_files = find_jsons(main_directory, "config.json")
|
||||
# XTTS vocab files (vocab.json)
|
||||
@@ -800,48 +807,49 @@ def find_latest_best_model(folder_path):
|
||||
latest_file = max(files, key=os.path.getctime, default=None)
|
||||
return latest_file
|
||||
|
||||
def compact_model():
|
||||
def compact_model(xtts_checkpoint_copy):
|
||||
this_dir = Path(__file__).parent.resolve()
|
||||
|
||||
best_model_path_str = find_latest_best_model(this_dir / "finetune" / "tmp-trn" / "training")
|
||||
print("THIS DIR:", this_dir)
|
||||
best_model_path_str = str(xtts_checkpoint_copy) # Convert to string
|
||||
print("best_model_path_str", best_model_path_str)
|
||||
|
||||
# Check if the best model file exists
|
||||
if best_model_path_str is None:
|
||||
if not best_model_path_str:
|
||||
print("[FINETUNE] No trained model was found.")
|
||||
return "No trained model was found."
|
||||
|
||||
# Convert model_path_str to Path
|
||||
best_model_path = Path(best_model_path_str)
|
||||
print(f"[FINETUNE] Best model path: {best_model_path_str}")
|
||||
|
||||
# Attempt to load the model
|
||||
try:
|
||||
checkpoint = torch.load(best_model_path, map_location=torch.device("cpu"))
|
||||
checkpoint = torch.load(best_model_path_str, map_location=torch.device("cpu"))
|
||||
print(f"[FINETUNE] Checkpoint loaded: {best_model_path_str}")
|
||||
except Exception as e:
|
||||
print("[FINETUNE] Error loading checkpoint:", e)
|
||||
raise
|
||||
|
||||
del checkpoint["optimizer"]
|
||||
|
||||
for key in list(checkpoint["model"].keys()):
|
||||
if "dvae" in key:
|
||||
del checkpoint["model"][key]
|
||||
|
||||
# Define the target directory
|
||||
target_dir = this_dir / "models" / "trainedmodel"
|
||||
|
||||
# Create the target directory if it doesn't exist
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
del checkpoint["optimizer"]
|
||||
|
||||
for key in list(checkpoint["model"].keys()):
|
||||
if "dvae" in key:
|
||||
del checkpoint["model"][key]
|
||||
|
||||
# Save the modified checkpoint in the target directory
|
||||
torch.save(checkpoint, target_dir / "model.pth")
|
||||
torch.save(checkpoint, str(target_dir / "model.pth")) # Convert to string
|
||||
|
||||
# Specify the files you want to copy
|
||||
files_to_copy = ["vocab.json", "config.json", "dvae.pth", "mel_stats.pth","speakers_xtts.pth", ]
|
||||
files_to_copy = ["vocab.json", "config.json", "speakers_xtts.pth", "mel_stats.pth", "dvae.pth"]
|
||||
|
||||
for file_name in files_to_copy:
|
||||
src_path = this_dir / base_path / base_model_path / file_name
|
||||
dest_path = target_dir / file_name
|
||||
shutil.copy(str(src_path), str(dest_path))
|
||||
shutil.copy(str(src_path), str(dest_path)) # Convert to string
|
||||
|
||||
source_wavs_dir = this_dir / "finetune" / "tmp-trn" / "wavs"
|
||||
target_wavs_dir = target_dir / "wavs"
|
||||
@@ -852,16 +860,17 @@ def compact_model():
|
||||
# Check if it's a file and larger than 1000 KB
|
||||
if file_path.is_file() and file_path.stat().st_size > 1000 * 1024:
|
||||
# Copy the file to the target directory
|
||||
shutil.copy(str(file_path), str(target_wavs_dir / file_path.name))
|
||||
shutil.copy(str(file_path), str(target_wavs_dir / file_path.name)) # Convert to string
|
||||
|
||||
print("[FINETUNE] Model copied to '/models/trainedmodel/'")
|
||||
return "Model copied to '/models/trainedmodel/'"
|
||||
|
||||
|
||||
def compact_lastfinetuned_model():
|
||||
def compact_lastfinetuned_model(xtts_checkpoint_copy):
|
||||
this_dir = Path(__file__).parent.resolve()
|
||||
|
||||
best_model_path_str = find_latest_best_model(this_dir / "finetune" / "tmp-trn" / "training")
|
||||
best_model_path_str = xtts_checkpoint_copy
|
||||
print(f"[FINETUNE] Best model path: {best_model_path_str}")
|
||||
|
||||
# Check if the best model file exists
|
||||
if best_model_path_str is None:
|
||||
@@ -880,21 +889,21 @@ def compact_lastfinetuned_model():
|
||||
|
||||
del checkpoint["optimizer"]
|
||||
|
||||
for key in list(checkpoint["model"].keys()):
|
||||
if "dvae" in key:
|
||||
del checkpoint["model"][key]
|
||||
|
||||
# Define the target directory
|
||||
target_dir = this_dir / "models" / "lastfinetuned"
|
||||
|
||||
# Create the target directory if it doesn't exist
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for key in list(checkpoint["model"].keys()):
|
||||
if "dvae" in key:
|
||||
del checkpoint["model"][key]
|
||||
|
||||
# Save the modified checkpoint in the target directory
|
||||
torch.save(checkpoint, target_dir / "model.pth")
|
||||
|
||||
# Specify the files you want to copy
|
||||
files_to_copy = ["vocab.json", "config.json", "dvae.pth", "mel_stats.pth", "speakers_xtts.pth",]
|
||||
files_to_copy = ["vocab.json", "config.json", "speakers_xtts.pth", "mel_stats.pth", "dvae.pth",]
|
||||
|
||||
for file_name in files_to_copy:
|
||||
src_path = this_dir / base_path / base_model_path / file_name
|
||||
@@ -916,15 +925,16 @@ def compact_lastfinetuned_model():
|
||||
return "Model copied to '/models/lastfinetuned/'"
|
||||
|
||||
|
||||
def compact_legacy_model():
|
||||
def compact_custom_model(xtts_checkpoint_copy, folder_path):
|
||||
this_dir = Path(__file__).parent.resolve()
|
||||
|
||||
best_model_path_str = os.path.join(this_dir, "finetune", "best_model.pth")
|
||||
best_model_path_str = xtts_checkpoint_copy
|
||||
print(f"[FINETUNE] Best model path: {best_model_path_str}")
|
||||
|
||||
# Check if the best model file exists
|
||||
if not os.path.exists(best_model_path_str):
|
||||
print("[FINETUNE] No model called best_model.pth was found in /finetune/")
|
||||
return "No model called best_model.pth was found in /finetune/"
|
||||
if best_model_path_str is None:
|
||||
print("[FINETUNE] No trained model was found.")
|
||||
return "No trained model was found."
|
||||
|
||||
# Convert model_path_str to Path
|
||||
best_model_path = Path(best_model_path_str)
|
||||
@@ -938,21 +948,41 @@ def compact_legacy_model():
|
||||
|
||||
del checkpoint["optimizer"]
|
||||
|
||||
for key in list(checkpoint["model"].keys()):
|
||||
if "dvae" in key:
|
||||
del checkpoint["model"][key]
|
||||
|
||||
# Define the target directory
|
||||
target_dir = this_dir / "finetune"
|
||||
target_dir = this_dir / "models" / folder_path
|
||||
|
||||
# Create the target directory if it doesn't exist
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for key in list(checkpoint["model"].keys()):
|
||||
if "dvae" in key:
|
||||
del checkpoint["model"][key]
|
||||
|
||||
# Save the modified checkpoint in the target directory
|
||||
torch.save(checkpoint, target_dir / "model.pth")
|
||||
|
||||
print("[FINETUNE] model.pth created in '/finetune/'")
|
||||
return "model.pth created in '/finetune/'"
|
||||
# Specify the files you want to copy
|
||||
files_to_copy = ["vocab.json", "config.json", "speakers_xtts.pth", "mel_stats.pth", "dvae.pth",]
|
||||
|
||||
for file_name in files_to_copy:
|
||||
src_path = this_dir / base_path / base_model_path / file_name
|
||||
dest_path = target_dir / file_name
|
||||
shutil.copy(str(src_path), str(dest_path))
|
||||
|
||||
source_wavs_dir = this_dir / "finetune" / "tmp-trn" / "wavs"
|
||||
target_wavs_dir = target_dir / "wavs"
|
||||
target_wavs_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Iterate through files in the source directory
|
||||
for file_path in source_wavs_dir.iterdir():
|
||||
# Check if it's a file and larger than 1000 KB
|
||||
if file_path.is_file() and file_path.stat().st_size > 1000 * 1024:
|
||||
# Copy the file to the target directory
|
||||
shutil.copy(str(file_path), str(target_wavs_dir / file_path.name))
|
||||
|
||||
print("[FINETUNE] Model copied to '/models/",folder_path,"/")
|
||||
return f"Model copied to '/models/{folder_path}/'"
|
||||
|
||||
|
||||
def delete_training_data():
|
||||
# Define the folder to be deleted
|
||||
@@ -1264,6 +1294,9 @@ if __name__ == "__main__":
|
||||
### 🟥 <u>Important Note - Windows - "UserWarning: huggingface_hub cache-system uses symlinks."</u>
|
||||
◽ This error is caused by Huggingfaces download software downloading the Whisper model. If you get this error, please restart your Windows command prompt with "Run as Administrator" and restart finetuning.<br>
|
||||
◽ This should only occur the 1st time it downloads the Whisper model. [Huggingface Reference here](https://huggingface.co/docs/huggingface_hub/en/guides/manage-cache#limitations)
|
||||
### 🟥 <u>Important Note - Language support.</u>
|
||||
◽ Although I have done my best to help automate this step, the Whisper model is not great with all languages and may fail to build your training data correctly. The Large-v3 may be better at certain languages.<br>
|
||||
◽ You can find information about the Whisper model [here](https://github.com/openai/whisper?tab=readme-ov-file#available-models-and-languages) and you can find data about manually building training data [here](https://docs.coqui.ai/en/latest/formatting_your_dataset.html), as well as details below about the file structure this step performs.<br>
|
||||
### 🟦 <u>What you need to do</u>
|
||||
◽ Please read Coqui's guide on what makes a good dataset [here](https://docs.coqui.ai/en/latest/what_makes_a_good_dataset.html#what-makes-a-good-dataset)<br>
|
||||
◽ Place your audio files in <span style="color: #3366ff;">{str(audio_folder)}</span>
|
||||
@@ -1276,6 +1309,7 @@ if __name__ == "__main__":
|
||||
◽ Whisper is making a best effort to find spoken audio and break it down into smaller audio files. The content of these audio files is then transcribed into CSV fles (which you can edit in Excel or similar).<br>
|
||||
◽ These files (audio and CSV) are used at the next step to train the model "this is what the audio sounds like and these are the words being spoken".<br>
|
||||
◽ If you wish to manually look at the CSV files before running the next step, you are welcome to do so and edit them as necessary. The greater the accuracy of the text the better the training will be.<br>
|
||||
◽ <span style="color: #3366ff;">/alltalk_tts/finetune/tmp-trn/lang.txt</span> Contains a two digit langauage code e.g. `en`, `fr` etc.<br>
|
||||
◽ <span style="color: #3366ff;">/alltalk_tts/finetune/tmp-trn/metadata_train.csv</span> Contains the list of wavs to text that will be used. This is what the model is trained with.<br>
|
||||
◽ <span style="color: #3366ff;">/alltalk_tts/finetune/tmp-trn/metadata_eval.csv</span> Lists the evaluation wav to text, used to generate TTS while training and evaluate the quality of generated TTS to the original sample.<br>
|
||||
◽ <span style="color: #3366ff;">/alltalk_tts/finetune/tmp-trn/wavs/</span> These are the wavs split out from your original training samples and match the contents of the CSV files.<br>
|
||||
@@ -1334,6 +1368,11 @@ if __name__ == "__main__":
|
||||
maximum=95, # Maximum value
|
||||
step=1, # Increment step
|
||||
)
|
||||
speaker_name_input = gr.Textbox(
|
||||
label="The name of the speaker/person you are training",
|
||||
value="personsname",
|
||||
visible=True,
|
||||
)
|
||||
progress_data = gr.Label(
|
||||
label="Progress:"
|
||||
)
|
||||
@@ -1345,14 +1384,15 @@ if __name__ == "__main__":
|
||||
|
||||
prompt_compute_btn = gr.Button(value="Step 1 - Create dataset")
|
||||
|
||||
def preprocess_dataset(language, whisper_model, out_path, eval_split_number, progress=gr.Progress(track_tqdm=True)):
|
||||
def preprocess_dataset(language, whisper_model, out_path, eval_split_number, speaker_name_input, progress=gr.Progress(track_tqdm=True)):
|
||||
clear_gpu_cache()
|
||||
test_for_audio_files = [file for file in os.listdir(audio_folder) if any(file.lower().endswith(ext) for ext in ['.wav', '.mp3', '.flac'])]
|
||||
if not test_for_audio_files:
|
||||
return "I cannot find any mp3, wav or flac files in the folder called 'put-voice-samples-in-here'", "", ""
|
||||
else:
|
||||
try:
|
||||
train_meta, eval_meta, audio_total_size = format_audio_list(target_language=language, whisper_model=whisper_model, out_path=out_path, eval_split_number=eval_split_number, gradio_progress=progress)
|
||||
|
||||
train_meta, eval_meta, audio_total_size = format_audio_list(target_language=language, whisper_model=whisper_model, out_path=out_path, eval_split_number=eval_split_number, speaker_name_input=speaker_name_input, gradio_progress=progress)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
error = traceback.format_exc()
|
||||
@@ -1373,10 +1413,12 @@ if __name__ == "__main__":
|
||||
#### GRADIO STEP 2 ####
|
||||
#######################
|
||||
with gr.Tab("💻 Step 2 - Training"):
|
||||
|
||||
with gr.Tab("Training"):
|
||||
gr.Markdown(
|
||||
f"""
|
||||
### 💻 <u>Training</u><br>
|
||||
### 🟥 <u>Important Note - Language support.</u>
|
||||
◽ If this step is failing/erroring you may wish to check your training data was created correctly (Detailed in Step 1), confirming that wav files have been generated and your `metadata_train.csv` and `metadata_eval.csv` files have been populated.<br>
|
||||
### 🟦 <u>What you need to do</u>
|
||||
◽ The <span style="color: #3366ff;">Train CSV</span> and <span style="color: #3366ff;">Eval CSV</span> should already be populated. If not, just go back to Step 1 and click "Create Dataset" again.<br>
|
||||
◽ The default settings below are the suggested settings for most purposes, however you may choose to alter them depending on your specific use case.<br>
|
||||
@@ -1384,10 +1426,6 @@ 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>
|
||||
◽ **Number of epochs:** Defines how many times the entire dataset is passed through the neural network; more epochs can improve learning but increase the risk of memorizing the training data.<br>
|
||||
◽ **Batch size:** Sets how many training examples are used in one iteration. Larger sizes speed up training but require more computational memory.<br>
|
||||
◽ **Grad(ient) accumulation steps:** Allows larger batches by spreading the computation across multiple steps, enabling training with limited hardware resources.<br>
|
||||
◽ **Max permitted audio size in seconds:** Limits the length of audio that the model processes. Any audio exceeding this duration will be truncated to fit the model's input constraints.<br>
|
||||
### 🟨 <u>What this step is doing</u><br>
|
||||
◽ Very simply put, it's taking all our wav files generated in Step 1, along with our recorded speech in out excel documents and its training the model on that voice e.g. listen to this audio file and this is what is being said in it, so learn to reproduce it.<br>
|
||||
### 🟩 <u>How long will this take?</u><br>
|
||||
@@ -1398,9 +1436,27 @@ if __name__ == "__main__":
|
||||
with gr.Row():
|
||||
train_csv = gr.Textbox(
|
||||
label="Train CSV:",
|
||||
scale=2,
|
||||
)
|
||||
eval_csv = gr.Textbox(
|
||||
label="Eval CSV:",
|
||||
scale=2,
|
||||
)
|
||||
learning_rates = gr.Dropdown(
|
||||
value=5e-6,
|
||||
label="Learning Rate",
|
||||
choices=[
|
||||
("1e-6", 1e-6),
|
||||
("5e-6", 5e-6),
|
||||
("1e-5", 1e-5),
|
||||
("5e-5", 5e-5),
|
||||
("1e-4", 1e-4),
|
||||
("5e-4", 5e-4),
|
||||
("1e-3", 1e-3),
|
||||
],
|
||||
type="value",
|
||||
allow_custom_value=True,
|
||||
scale=0,
|
||||
)
|
||||
with gr.Row():
|
||||
num_epochs = gr.Slider(
|
||||
@@ -1419,8 +1475,8 @@ if __name__ == "__main__":
|
||||
)
|
||||
grad_acumm = gr.Slider(
|
||||
label="Grad accumulation steps:",
|
||||
minimum=2,
|
||||
maximum=128,
|
||||
minimum=1,
|
||||
maximum=32,
|
||||
step=1,
|
||||
value=args.grad_acumm,
|
||||
)
|
||||
@@ -1456,14 +1512,15 @@ if __name__ == "__main__":
|
||||
demo.load(read_logs, None, logs_tts_train, every=1)
|
||||
train_btn = gr.Button(value="Step 2 - Run the training")
|
||||
|
||||
def train_model(language, train_csv, eval_csv, num_epochs, batch_size, grad_acumm, output_path, max_audio_length):
|
||||
def train_model(language, train_csv, eval_csv, learning_rates, num_epochs, batch_size, grad_acumm, output_path, max_audio_length):
|
||||
clear_gpu_cache()
|
||||
if not train_csv or not eval_csv:
|
||||
return "You need to run the data processing step or manually set `Train CSV` and `Eval CSV` fields !", "", "", "", ""
|
||||
try:
|
||||
# convert seconds to waveform frames
|
||||
max_audio_length = int(max_audio_length * 22050)
|
||||
config_path, original_xtts_checkpoint, vocab_file, exp_path, speaker_wav = train_gpt(language, num_epochs, batch_size, grad_acumm, train_csv, eval_csv, output_path=str(output_path), max_audio_length=max_audio_length)
|
||||
learning_rate = float(learning_rates) # Convert the learning rate value to a float
|
||||
config_path, original_xtts_checkpoint, vocab_file, exp_path, speaker_wav = train_gpt(language, num_epochs, batch_size, grad_acumm, train_csv, eval_csv, learning_rate, output_path=str(output_path), max_audio_length=max_audio_length)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
error = traceback.format_exc()
|
||||
@@ -1477,6 +1534,84 @@ if __name__ == "__main__":
|
||||
print("[FINETUNE] Model training done. Move to Step 3")
|
||||
clear_gpu_cache()
|
||||
return "Model training done. Move to Step 3", config_path, vocab_file, ft_xtts_checkpoint, speaker_wav
|
||||
with gr.Tab("Info - Grad Accumulation"):
|
||||
gr.Markdown(
|
||||
f"""
|
||||
### 🟩 <u>Grad Accumulation</u><br>
|
||||
◽ Gradient accumulation is a technique that allows you to simulate a larger batch size without actually increasing the memory consumption. Here's how it works:<br>
|
||||
◽ Instead of updating the model's parameters after every batch, gradient accumulation enables you to process multiple batches and accumulate their gradients.<br>
|
||||
◽ By setting steps greater than 1, you can process multiple batches before a single optimization step e.g if steps is set to 4, the gradients will be accumulated over 4 batches before updating the model's parameters.<br>
|
||||
◽ This means that you can effectively use a larger batch size while keeping the actual batch size per iteration smaller, thereby reducing the memory footprint.<br>
|
||||
◽ Increasing the steps allows you to find a balance between memory consumption and computational efficiency. You can process more examples per optimization step without exceeding the available memory.<br><br>
|
||||
◽ However, it's important to note that increasing the gradient accumulation steps does have an impact on the training process:<br>
|
||||
◽ Since the model's parameters are updated less frequently (every grad_accum_steps batches), the training dynamics may be slightly different compared to updating the model after every batch.<br>
|
||||
◽ You may need to adjust the learning rate and other hyperparameters accordingly to compensate for the less frequent updates. Typically, you can increase the learning rate slightly when using gradient accumulation.<br>
|
||||
◽ The training progress will be slower in terms of the number of optimization steps per epoch, as the model updates occur less frequently.<br>
|
||||
◽ However, the overall training time may still be reduced compared to using a smaller batch size without gradient accumulation, as it allows for better utilization of GPU resources.<br>
|
||||
◽ To start, you can try setting steps to a value like 4 and see if it resolves the OOM error. If the error persists, you can experiment with higher values until you find a balance that works for your specific setup.
|
||||
"""
|
||||
)
|
||||
with gr.Tab("Info - Batch Size"):
|
||||
gr.Markdown(
|
||||
f"""
|
||||
### 🟩 <u>Batch Size</u><br>
|
||||
◽ Batch size refers to the number of training examples processed in a single iteration (forward and backward pass) before updating the model's parameters.<br>
|
||||
◽ A larger batch size allows for more efficient computation and utilization of hardware resources, especially when using GPUs.<br>
|
||||
◽ However, increasing the batch size also increases the memory consumption during training, as more examples need to be stored in memory.<br>
|
||||
◽ If the batch size is too large, it can lead to out-of-memory (OOM) errors, especially when training on GPUs with limited memory.<br>
|
||||
◽ On the other hand, using a smaller batch size can result in slower training and may require more iterations to converge.<br>
|
||||
◽ The optimal batch size depends on various factors, such as the model architecture, available hardware resources, and the specific problem being solved.<br>
|
||||
◽ It's common to experiment with different batch sizes to find a balance between training speed and memory efficiency.<br>
|
||||
◽ If you encounter OOM errors, try reducing the batch size until the training can proceed without memory issues.<br>
|
||||
◽ Keep in mind that the batch size also affects the model's generalization and convergence behavior, so it's important to monitor the model's performance while adjusting the batch size.
|
||||
"""
|
||||
)
|
||||
with gr.Tab("Info - Learning Rate"):
|
||||
gr.Markdown(
|
||||
f"""
|
||||
### 🟩 <u>Learning Rate</u><br>
|
||||
◽ 1e-6: Very small learning rate, slow but stable learning.<br>
|
||||
◽ 5e-6: Small learning rate, slow but stable learning.<br>
|
||||
◽ 1e-5: Moderate learning rate, balanced between stability and convergence speed.<br>
|
||||
◽ 5e-5: Higher learning rate, faster convergence but potential instability.<br>
|
||||
◽ 1e-4: High learning rate, faster convergence but increased risk of instability.<br>
|
||||
◽ 5e-4: Very high learning rate, fast convergence but higher risk of instability.<br>
|
||||
◽ 1e-3: Extremely high learning rate, very fast convergence but high risk of instability.<br><br>
|
||||
The optimal learning rate depends on the model architecture, dataset, and other hyperparameters.
|
||||
"""
|
||||
)
|
||||
with gr.Tab("Info - Epochs"):
|
||||
gr.Markdown(
|
||||
f"""
|
||||
### 🟩 <u>Epochs</u><br>
|
||||
◽ An epoch represents a single pass through the entire training dataset during the training process.<br>
|
||||
◽ In each epoch, the model sees and learns from all the training examples once.<br>
|
||||
◽ The number of epochs determines how many times the model will iterate over the complete training dataset.<br>
|
||||
◽ Increasing the number of epochs allows the model to learn more from the data and potentially improve its performance.<br>
|
||||
◽ However, training for too many epochs can lead to overfitting, where the model becomes too specialized to the training data and fails to generalize well to unseen data.<br>
|
||||
◽ The optimal number of epochs depends on factors such as the complexity of the problem, the size of the dataset, and the model's capacity.<br>
|
||||
◽ It's common to use techniques like early stopping or validation monitoring to determine the appropriate number of epochs.<br>
|
||||
◽ Early stopping involves monitoring the model's performance on a validation set and stopping the training when the performance starts to degrade, indicating potential overfitting.<br>
|
||||
◽ Validation monitoring involves evaluating the model's performance on a separate validation set after each epoch and selecting the model checkpoint that performs best on the validation set.<br>
|
||||
◽ It's recommended to start with a reasonable number of epochs and monitor the model's performance to determine if more epochs are needed or if early stopping should be applied
|
||||
"""
|
||||
)
|
||||
with gr.Tab("Info - Max Audio"):
|
||||
gr.Markdown(
|
||||
f"""
|
||||
### 🟩 <u>Max Permitted Audio Size (in seconds)</u><br>
|
||||
◽ The max permitted audio size determines the maximum duration of audio files that can be used as input to the model during training and inference.<br>
|
||||
◽ It is specified in seconds and represents the longest audio clip that the model can process.<br>
|
||||
◽ Limiting the audio size helps to control the memory usage and computational requirements of the model.<br>
|
||||
◽ If the audio files in your dataset vary in length, it's important to consider the max permitted audio size to ensure that all files can be processed effectively.<br>
|
||||
◽ Audio files longer than the max permitted size will typically be truncated or split into smaller segments before being fed into the model.<br>
|
||||
◽ The choice of max permitted audio size depends on the specific requirements of your application and the available hardware resources.<br>
|
||||
◽ Increasing the max permitted audio size allows the model to handle longer audio clips but also increases the memory consumption and computational burden.<br>
|
||||
◽ If you encounter memory issues or slow processing times, you may need to reduce the max permitted audio size to find a suitable balance.<br>
|
||||
◽ It's important to consider the nature of your audio data and choose a max permitted audio size that captures the relevant information while being computationally feasible.
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
#######################
|
||||
#### GRADIO STEP 3 ####
|
||||
@@ -1572,7 +1707,7 @@ if __name__ == "__main__":
|
||||
refresh_button = create_refresh_button(
|
||||
[xtts_checkpoint, xtts_config, xtts_vocab, speaker_reference_audio],
|
||||
[
|
||||
lambda: {"choices": find_models(main_directory, "pth"), "value": ""},
|
||||
lambda: {"choices": find_best_models(main_directory), "value": ""},
|
||||
lambda: {"choices": find_jsons(main_directory, "config.json"), "value": ""},
|
||||
lambda: {"choices": find_jsons(main_directory, "vocab.json"), "value": ""},
|
||||
lambda: {"choices": get_available_voices(), "value": ""},
|
||||
@@ -1605,7 +1740,8 @@ if __name__ == "__main__":
|
||||
◽ **Note:** Sample wav files will be copied into the model folder. You will need to MANUALLY copy/move the WAV file(s) you want to use to the AllTalk voices folder, to make them available within the interface.<br>
|
||||
◽ **Note:** Text-generation-webui users, <span style="color: #3366ff;">OPTION A - Compact and move model to '/trainedmodel/'</span>. will make the model available for use within Text-gen-webui.<br>
|
||||
### 🟩 <u>Using your Finetuned model as you main model</u>
|
||||
◽ If you wish to use the model you have just fintuned as your main model, you will need to MANUALLY copy it over the base model in <span style="color: #3366ff;">/models/trainedmodel/</span> after you have used Option A or B.<br>
|
||||
◽ **Currently** only Text-gen-webui and SillyTavern have loaders built for loading models in the <span style="color: #3366ff;">'/finetuned/'</span> folder. So if you wish to use your finetuned model as elsewhere in AllTalk please copy it over your base model e.g. copy your model over the top of <span style="color: #3366ff;">/models/xttsv2_2.0.2/</span><br>
|
||||
◽ If you wish to use the model you have just fintuned as your main model, you will need to MANUALLY copy it over the base model e.g copy it over <span style="color: #3366ff;">/models/xttsv2_2.0.2/</span> after you have used Option A or B.<br>
|
||||
◽ Should you ever wish to revert your model back to the base model, you can delete the files in <span style="color: #3366ff;">/models/xttsv2_2.0.2/</span> and new copies will be re-downloaded when AllTalk starts up.<br>
|
||||
### 🟨 <u>Clearing up disk space</u>
|
||||
◽ If you are not going to train anything again, you can delete the whisper model from inside of your huggingface cache (3GB approx) <br>
|
||||
@@ -1617,6 +1753,21 @@ if __name__ == "__main__":
|
||||
final_progress_data = gr.Label(
|
||||
label="Progress:"
|
||||
)
|
||||
with gr.Row():
|
||||
xtts_checkpoint_copy = gr.Dropdown(
|
||||
[str(file) for file in xtts_checkpoint_files],
|
||||
label="XTTS checkpoint path (Select the model you want to copy over):",
|
||||
value="",
|
||||
allow_custom_value=True,
|
||||
scale=3,
|
||||
)
|
||||
# Create refresh button
|
||||
refresh_button = create_refresh_button(
|
||||
[xtts_checkpoint_copy,],
|
||||
[
|
||||
lambda: {"choices": find_best_models(main_directory), "value": ""},
|
||||
],
|
||||
elem_class="refresh-button-class")
|
||||
with gr.Row():
|
||||
compact_btn = gr.Button(value="OPTION A - Compact and move model to '/trainedmodel/'")
|
||||
gr.Markdown(
|
||||
@@ -1631,6 +1782,9 @@ if __name__ == "__main__":
|
||||
This will compact the model and move it, along with the reference wav's to <span style="color: #3366ff;">/models/lastfinetuned/</span> and will <span style="color: red;">OVERWRITE</span> any model in that location. This will just leave you a finetuned model that you can do with as you please. It will <span style="color: red;">NOT</span> be available in Text-gen-webui unless you copy it over one of the other model loader locations.
|
||||
"""
|
||||
)
|
||||
with gr.Row():
|
||||
compact_custom_btn = gr.Button(value="OPTION C - Compact and move model to a folder name of your choosing")
|
||||
folder_path = gr.Textbox(label="Enter a new folder name (will be sub the models folder)", lines=1, value="mycustomfolder")
|
||||
with gr.Row():
|
||||
delete_training_btn = gr.Button(value="Delete generated training data")
|
||||
gr.Markdown(
|
||||
@@ -1653,6 +1807,7 @@ if __name__ == "__main__":
|
||||
whisper_model,
|
||||
out_path,
|
||||
eval_split_number,
|
||||
speaker_name_input,
|
||||
],
|
||||
outputs=[
|
||||
progress_data,
|
||||
@@ -1668,6 +1823,7 @@ if __name__ == "__main__":
|
||||
lang,
|
||||
train_csv,
|
||||
eval_csv,
|
||||
learning_rates,
|
||||
num_epochs,
|
||||
batch_size,
|
||||
grad_acumm,
|
||||
@@ -1696,13 +1852,19 @@ if __name__ == "__main__":
|
||||
],
|
||||
outputs=[progress_gen, tts_output_audio, reference_audio],
|
||||
)
|
||||
|
||||
compact_btn.click(
|
||||
fn=compact_model,
|
||||
inputs=[xtts_checkpoint_copy],
|
||||
outputs=[final_progress_data],
|
||||
)
|
||||
compact_lastfinetuned_btn.click(
|
||||
fn=compact_lastfinetuned_model,
|
||||
inputs=[xtts_checkpoint_copy],
|
||||
outputs=[final_progress_data],
|
||||
)
|
||||
compact_custom_btn.click(
|
||||
fn=compact_custom_model,
|
||||
inputs=[xtts_checkpoint_copy, folder_path],
|
||||
outputs=[final_progress_data],
|
||||
)
|
||||
delete_training_btn.click(
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import requests
|
||||
from requests.exceptions import ConnectionError
|
||||
from tqdm import tqdm
|
||||
import importlib.metadata as metadata
|
||||
import json
|
||||
from packaging import version
|
||||
from datetime import datetime
|
||||
|
||||
#################################################################
|
||||
#### LOAD PARAMS FROM confignew.json - REQUIRED FOR BRANDING ####
|
||||
@@ -12,14 +15,12 @@ from packaging import version
|
||||
# STARTUP VARIABLE - Create "this_dir" variable as the current script directory
|
||||
this_dir = Path(__file__).parent.resolve()
|
||||
|
||||
|
||||
# load standard config file in and get settings
|
||||
def load_config(file_path):
|
||||
with open(file_path, "r") as config_file:
|
||||
config = json.load(config_file)
|
||||
return config
|
||||
|
||||
|
||||
config_file_path = this_dir / "confignew.json"
|
||||
params = load_config(config_file_path)
|
||||
|
||||
@@ -37,12 +38,8 @@ if modeldownload_config_file_path.exists():
|
||||
files_to_download = settings.get("files_to_download", {})
|
||||
else:
|
||||
# Default settings if the JSON file doesn't exist or is empty
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m modeldownload.json is missing so please re-download it and save it in the coquii_tts main folder."
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m API Local and XTTSv2 Local will error unless this is corrected."
|
||||
)
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m modeldownload.json is missing so please re-download it and save it in the coquii_tts main folder.")
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m API Local and XTTSv2 Local will error unless this is corrected.")
|
||||
|
||||
# Read the version specifier from requirements_nvidia.txt
|
||||
with open(this_dir / "system" / "requirements" / "requirements_standalone.txt", "r") as req_file:
|
||||
@@ -55,16 +52,12 @@ for req in requirements:
|
||||
break
|
||||
|
||||
if tts_version_required is None:
|
||||
raise ValueError(
|
||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m Could not find TTS version specifier in requirements file"
|
||||
)
|
||||
|
||||
raise ValueError(f"[{params['branding']}Startup] \033[91mWarning\033[0m Could not find TTS version specifier in requirements file")
|
||||
|
||||
def create_directory_if_not_exists(directory):
|
||||
if not directory.exists():
|
||||
directory.mkdir(parents=True)
|
||||
|
||||
|
||||
def download_file(url, destination):
|
||||
response = requests.get(url, stream=True)
|
||||
total_size_in_bytes = int(response.headers.get("content-length", 0))
|
||||
@@ -83,63 +76,118 @@ def download_file(url, destination):
|
||||
def check_tts_version():
|
||||
try:
|
||||
tts_version = metadata.version("tts")
|
||||
print(
|
||||
f"[{params['branding']}Startup] TTS version installed: \033[93m"
|
||||
+ tts_version
|
||||
+ "\033[0m"
|
||||
)
|
||||
print(f"[{params['branding']}Startup] \033[92mCurrent TTS Version : \033[93m"+tts_version+"\033[0m")
|
||||
|
||||
if version.parse(tts_version) < version.parse(tts_version_required):
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS version is too old. Please upgrade to version \033[93m"
|
||||
+ tts_version_required
|
||||
+ "\033[0m or later.\033[0m"
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m At your terminal/command prompt \033[94mpip install --upgrade tts\033[0m"
|
||||
)
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS version is too old. Please upgrade to version \033[93m"+tts_version_required+"\033[0m or later.\033[0m")
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m At your terminal/command prompt \033[94mpip install --upgrade tts\033[0m")
|
||||
else:
|
||||
print(f"[{params['branding']}Startup] TTS version is up to date.")
|
||||
print(f"[{params['branding']}Startup] \033[92mCurrent TTS Version is :\033[93m Up to date\033[0m")
|
||||
except metadata.PackageNotFoundError:
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS is not installed."
|
||||
)
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS is not installed")
|
||||
|
||||
def check_torch_version():
|
||||
import torch
|
||||
pytorch_version = torch.__version__
|
||||
cuda_version = torch.version.cuda
|
||||
major, minor, micro = sys.version_info[:3]
|
||||
python_version = f"{major}.{minor}.{micro}"
|
||||
print(f"[{params['branding']}Startup] \033[92mCurrent Python Version :\033[93m {python_version}\033[0m")
|
||||
print(f"[{params['branding']}Startup] \033[92mCurrent PyTorch Version:\033[93m {pytorch_version}\033[0m")
|
||||
if cuda_version is None:
|
||||
print(f"[{params['branding']}Startup] \033[92mCurrent CUDA Version :\033[91m CUDA is not available\033[0m")
|
||||
else:
|
||||
print(f"[{params['branding']}Startup] \033[92mCurrent CUDA Version :\033[93m {cuda_version}\033[0m")
|
||||
|
||||
def ordinal(n):
|
||||
return "%d%s" % (n, "th" if 4 <= n % 100 <= 20 else {1: "st", 2: "nd", 3: "rd"}.get(n % 10, "th"))
|
||||
|
||||
def format_datetime(iso_str):
|
||||
# Parse the ISO 8601 string to datetime
|
||||
dt = datetime.strptime(iso_str, "%Y-%m-%dT%H:%M:%SZ")
|
||||
# Format the datetime into a more readable string
|
||||
return dt.strftime(f"{ordinal(dt.day)} %B %Y at %H:%M")
|
||||
|
||||
def fetch_latest_commit_sha_and_date(owner, repo):
|
||||
url = f"https://api.github.com/repos/{owner}/{repo}/commits"
|
||||
try:
|
||||
response = requests.get(url)
|
||||
if response.status_code == 200:
|
||||
latest_commit = response.json()[0]
|
||||
latest_commit_sha = latest_commit['sha']
|
||||
latest_commit_date = latest_commit['commit']['committer']['date']
|
||||
return latest_commit_sha, latest_commit_date
|
||||
else:
|
||||
print(f"[{params['branding']}Startup] \033[92m{params['branding']}Github updated :\033[91m Failed to fetch the latest commits due to an unexpected response from GitHub")
|
||||
return None, None
|
||||
except ConnectionError:
|
||||
# This block is executed when a connection error occurs
|
||||
print(f"[{params['branding']}Startup] \033[92m{params['branding']}Github updated :\033[91m Could not reach GitHub to check for updates\033[0m")
|
||||
return None, None
|
||||
|
||||
def read_or_initialize_sha(file_path):
|
||||
if os.path.exists(file_path):
|
||||
with open(file_path, 'r') as file:
|
||||
data = json.load(file)
|
||||
return data.get("last_known_commit_sha")
|
||||
else:
|
||||
# File doesn't exist, fetch the latest SHA and create the file
|
||||
latest_commit_sha = fetch_latest_commit_sha_and_date(github_site, github_repository)
|
||||
if latest_commit_sha:
|
||||
with open(file_path, 'w') as file:
|
||||
json.dump({"last_known_commit_sha": latest_commit_sha}, file)
|
||||
return latest_commit_sha
|
||||
else:
|
||||
# Handle the case where GitHub couldn't be reached
|
||||
return None
|
||||
|
||||
def update_sha_file(file_path, new_sha):
|
||||
with open(file_path, 'w') as file:
|
||||
json.dump({"last_known_commit_sha": new_sha}, file)
|
||||
|
||||
# Check and create directories
|
||||
if str(base_path) == "models":
|
||||
create_directory_if_not_exists(this_dir / base_path / model_path)
|
||||
else:
|
||||
create_directory_if_not_exists(base_path / model_path)
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[94mInfo\033[0m Custom path set in \033[93mmodeldownload.json\033[0m. Using the following settings:"
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[94mInfo\033[0m Base folder Path:\033[93m",
|
||||
base_path,
|
||||
"\033[0m",
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[94mInfo\033[0m Model folder Path:\033[93m",
|
||||
model_path,
|
||||
"\033[0m",
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[94mInfo\033[0m Full Path:\033[93m",
|
||||
base_path / model_path,
|
||||
"\033[0m",
|
||||
)
|
||||
print(f"[{params['branding']}Startup] \033[94mInfo\033[0m Custom path set in \033[93mmodeldownload.json\033[0m. Using the following settings:")
|
||||
print(f"[{params['branding']}Startup] \033[94mInfo\033[0m Base folder Path:\033[93m",base_path,"\033[0m",)
|
||||
print(f"[{params['branding']}Startup] \033[94mInfo\033[0m Model folder Path:\033[93m",model_path,"\033[0m",)
|
||||
print(f"[{params['branding']}Startup] \033[94mInfo\033[0m Full Path:\033[93m",base_path / model_path,"\033[0m",)
|
||||
|
||||
# Download files if they don't exist
|
||||
print("[" + params["branding"] + "Startup] Checking Model is Downloaded.")
|
||||
print(f"[{params['branding']}Startup] \033[92mModel is available :\033[93m Checking\033[0m")
|
||||
for filename, url in files_to_download.items():
|
||||
if str(base_path) == "models":
|
||||
destination = this_dir / base_path / model_path / filename
|
||||
else:
|
||||
destination = Path(base_path) / model_path / filename
|
||||
|
||||
if not destination.exists():
|
||||
print(f"[{params['branding']}Startup] Downloading " + filename + "...")
|
||||
print(f"[{params['branding']}Startup] \033[92mModel Downloading file : \033[93m" + filename + "\033[0m")
|
||||
download_file(url, destination)
|
||||
print(f"[{params['branding']}Startup] \033[92mModel is available :\033[93m Checked\033[0m")
|
||||
|
||||
github_site = "erew123"
|
||||
github_repository = "alltalk_tts"
|
||||
|
||||
check_torch_version()
|
||||
check_tts_version()
|
||||
# Define the file path based on your directory structure
|
||||
sha_file_path = this_dir / "system" / "config" / "at_github_sha.json"
|
||||
|
||||
# Read or initialize the SHA (adjusted for handling both SHA and date)
|
||||
last_known_commit_sha = read_or_initialize_sha(sha_file_path) # Assuming adjustment for date
|
||||
|
||||
# Assuming you have fetched the latest commit SHA and date
|
||||
latest_commit_sha, latest_commit_date = fetch_latest_commit_sha_and_date(github_site, github_repository)
|
||||
|
||||
formatted_date = format_datetime(latest_commit_date) if latest_commit_date else "an unknown date"
|
||||
|
||||
if latest_commit_sha and latest_commit_sha != last_known_commit_sha:
|
||||
#print(f"There's an update available for alltalk_tts.")
|
||||
print(f"[{params['branding']}Startup] \033[92m{params['branding']}Github updated :\033[93m {formatted_date}\033[0m")
|
||||
# Update the file with the new SHA
|
||||
update_sha_file(sha_file_path, latest_commit_sha)
|
||||
elif latest_commit_sha == last_known_commit_sha:
|
||||
#print(f"Your alltalk_tts software is up to date.")
|
||||
print(f"[{params['branding']}Startup] \033[92m{params['branding']}Github updated :\033[93m {formatted_date}\033[0m")
|
||||
@@ -7,14 +7,16 @@ RUN apt-get update && apt-get upgrade -y \
|
||||
libclblast-dev libopenblas-dev \
|
||||
&& mkdir -p /etc/OpenCL/vendors && echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd \
|
||||
&& ln -s /usr/bin/python3 /usr/bin/python
|
||||
|
||||
RUN mkdir /app/pip_cache
|
||||
ENV PIP_CACHE_DIR=/app/pip_cache
|
||||
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
ENV CUDA_DOCKER_ARCH=all
|
||||
RUN pip install --no-cache-dir --no-deps -r system/requirements/requirements_standalone.txt --cache-dir=/app/pip_cache && \
|
||||
pip install --no-cache-dir deepspeed --cache-dir=/app/pip_cache
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements_nvidia.txt && \
|
||||
pip install --no-cache-dir -r requirements_finetune.txt && \
|
||||
pip install --no-cache-dir -r requirements_other.txt && \
|
||||
pip install --no-cache-dir deepspeed
|
||||
EXPOSE 7851
|
||||
RUN chmod +x launch.sh
|
||||
ENTRYPOINT ["sh", "-c", "./launch.sh"]
|
||||
@@ -9,12 +9,16 @@ import threading
|
||||
import signal
|
||||
import sys
|
||||
import atexit
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timedelta
|
||||
import re
|
||||
import numpy as np
|
||||
import soundfile as sf
|
||||
import uuid
|
||||
import logging
|
||||
# Store the current disable level
|
||||
current_disable_level = logging.getLogger().manager.disable
|
||||
|
||||
######################################
|
||||
#### ALLTALK ALLOWED STARTUP TIME ####
|
||||
@@ -30,43 +34,109 @@ startup_wait_time = 120
|
||||
# STARTUP VARIABLE - Create "this_dir" variable as the current script directory
|
||||
this_dir = Path(__file__).parent.resolve()
|
||||
|
||||
|
||||
# load config file in and get settings
|
||||
def load_config(file_path):
|
||||
with open(file_path, "r") as config_file:
|
||||
config = json.load(config_file)
|
||||
return config
|
||||
|
||||
|
||||
config_file_path = this_dir / "confignew.json"
|
||||
# Load the params dictionary from the confignew.json file
|
||||
params = load_config(config_file_path)
|
||||
|
||||
print(f"[{params['branding']}Startup]\033[94m _ _ _ \033[1;35m_____ _ _ \033[0m _____ _____ ____ ")
|
||||
print(f"[{params['branding']}Startup]\033[94m / \ | | |\033[1;35m_ _|_ _| | | __ \033[0m |_ _|_ _/ ___| ")
|
||||
print(f"[{params['branding']}Startup]\033[94m / _ \ | | |\033[1;35m | |/ _` | | |/ / \033[0m | | | | \___ \ ")
|
||||
print(f"[{params['branding']}Startup]\033[94m / ___ \| | |\033[1;35m | | (_| | | < \033[0m | | | | ___) |")
|
||||
print(f"[{params['branding']}Startup]\033[94m /_/ \_\_|_|\033[1;35m |_|\__,_|_|_|\_\ \033[0m |_| |_| |____/ ")
|
||||
print(f"[{params['branding']}Startup]")
|
||||
|
||||
##############################################
|
||||
#### Update any changes to confignew.json ####
|
||||
##############################################
|
||||
|
||||
update_config_path = this_dir / "system" / "config" / "at_configupdate.json"
|
||||
downgrade_config_path = this_dir / "system" / "config" / "at_configdowngrade.json"
|
||||
|
||||
def changes_needed(main_config, update_config, downgrade_config):
|
||||
"""Check if there are any changes to be made to the main configuration."""
|
||||
for key in downgrade_config.keys():
|
||||
if key in main_config:
|
||||
return True
|
||||
for key, value in update_config.items():
|
||||
if key not in main_config:
|
||||
return True
|
||||
return False
|
||||
|
||||
def update_config(config_file_path, update_config_path, downgrade_config_path):
|
||||
try:
|
||||
with open(config_file_path, 'r') as file:
|
||||
main_config = json.load(file)
|
||||
with open(update_config_path, 'r') as file:
|
||||
update_config = json.load(file)
|
||||
with open(downgrade_config_path, 'r') as file:
|
||||
downgrade_config = json.load(file)
|
||||
|
||||
# Determine if changes are needed
|
||||
if changes_needed(main_config, update_config, downgrade_config):
|
||||
# Backup with timestamp to avoid overwriting
|
||||
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
|
||||
backup_path = config_file_path.with_suffix(f".{timestamp}.bak")
|
||||
logging.info(f"Creating backup of the main config to {backup_path}")
|
||||
shutil.copy(config_file_path, backup_path)
|
||||
|
||||
# Proceed with updates and downgrades
|
||||
for key, value in update_config.items():
|
||||
if key not in main_config:
|
||||
main_config[key] = value
|
||||
for key in downgrade_config.keys():
|
||||
if key in main_config:
|
||||
del main_config[key]
|
||||
|
||||
# Save the updated configuration
|
||||
with open(config_file_path, 'w') as file:
|
||||
json.dump(main_config, file, indent=4)
|
||||
|
||||
print(f"[{params['branding']}Startup] \033[92mConfig file check : \033[91mUpdates applied\033[0m")
|
||||
else:
|
||||
print(f"[{params['branding']}Startup] \033[92mConfig file check : \033[93mNo Updates required\033[0m")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[{params['branding']}Startup] \033[92mConfig file check : \033[91mError updating\033[0m")
|
||||
|
||||
# Update the configuration
|
||||
update_config(config_file_path, update_config_path, downgrade_config_path)
|
||||
# Re-Load the params dictionary from the confignew.json file
|
||||
params = load_config(config_file_path)
|
||||
|
||||
#########################################
|
||||
#### Continue on with Startup Checks ####
|
||||
#########################################
|
||||
|
||||
# Required for sentence splitting
|
||||
try:
|
||||
from TTS.api import TTS
|
||||
from TTS.utils.synthesizer import Synthesizer
|
||||
except ModuleNotFoundError:
|
||||
logger.error(
|
||||
f"[{params['branding']}]\033[91mWarning\033[0m Could not find the TTS module. Make sure to install the requirements for the {params['branding']} extension."
|
||||
f"[{params['branding']}]\033[91mWarning\033[0m Linux / Mac:\npip install -r /alltalk_tts/requirements.txt\n"
|
||||
f"[{params['branding']}]\033[91mWarning\033[0m Windows:\npip install -r \\alltalk_tts\\requirements.txt\n"
|
||||
f"[{params['branding']}]\033[91mWarning\033[0m If you used the one-click installer, paste the command above in the terminal window launched after running the cmd_ script. On Windows, that's cmd_windows.bat."
|
||||
)
|
||||
# Inform the user about the missing module and suggest next steps
|
||||
print(f"[{params['branding']}]\033[91mWarning\033[0m Could not find the TTS module. Make sure to install the requirements for the {params['branding']} extension.")
|
||||
print(f"[{params['branding']}]\033[91mWarning\033[0m Please use the ATSetup utility or check the Github installation instructions.")
|
||||
# Re-raise the ModuleNotFoundError to stop the program and print the traceback
|
||||
raise
|
||||
|
||||
# IMPORT - Attempt Importing DeepSpeed (required for displaying Deepspeed checkbox in gradio)
|
||||
# Suppress logging
|
||||
logging.disable(logging.ERROR)
|
||||
try:
|
||||
import deepspeed
|
||||
|
||||
deepspeed_installed = True
|
||||
except ImportError:
|
||||
deepspeed_installed = False
|
||||
# Restore previous logging level
|
||||
logging.disable(current_disable_level)
|
||||
|
||||
# Import gradio if being used within text generation webUI
|
||||
try:
|
||||
import gradio as gr
|
||||
|
||||
from modules import chat, shared, ui_chat
|
||||
from modules.logging_colors import logger
|
||||
from modules.ui import create_refresh_button
|
||||
@@ -75,9 +145,10 @@ try:
|
||||
# This is set to check if the script is being run within text generation webui or as a standalone script. False is running as part of text gen web ui or a gradio interface
|
||||
running_in_standalone = False
|
||||
output_folder_wav = params["output_folder_wav"]
|
||||
print(f"[{params['branding']}Startup] \033[92m{params['branding']}startup Mode : \033[93mText-Gen-webui mode\033[0m")
|
||||
except ModuleNotFoundError:
|
||||
output_folder_wav = params["output_folder_wav_standalone"]
|
||||
print(f"[{params['branding']}Startup] Running script.py in standalone mode")
|
||||
print(f"[{params['branding']}Startup] \033[92m{params['branding']}startup Mode : \033[93mStandalone mode\033[0m")
|
||||
# This is set to check if the script is being run within text generation webui or as a standalone script. true means standalone
|
||||
running_in_standalone = True
|
||||
|
||||
@@ -98,23 +169,12 @@ def get_available_voices():
|
||||
return sorted([voice.name for voice in Path(f"{this_dir}/voices").glob("*.wav")])
|
||||
|
||||
|
||||
#########################
|
||||
#### LICENSE DISPLAY ####
|
||||
#########################
|
||||
# STARTUP Display Licence Information
|
||||
print(f"[{params['branding']}Startup] \033[94mCoqui Public Model License\033[0m")
|
||||
print(f"[{params['branding']}Startup] \033[94mhttps://coqui.ai/cpml.txt\033[0m")
|
||||
|
||||
|
||||
############################################
|
||||
#### DELETE OLD OUTPUT WAV FILES IF SET ####
|
||||
############################################
|
||||
def delete_old_files(folder_path, days_to_keep):
|
||||
current_time = datetime.now()
|
||||
print(
|
||||
f"[{params['branding']}Startup] Deletion of old output folder WAV files is currently enabled and set at",
|
||||
delete_output_wavs_setting,
|
||||
)
|
||||
print(f"[{params['branding']}Startup] \033[92mWAV file deletion :\033[93m", delete_output_wavs_setting,"\033[0m")
|
||||
for file_name in os.listdir(folder_path):
|
||||
file_path = os.path.join(folder_path, file_name)
|
||||
if os.path.isfile(file_path):
|
||||
@@ -130,20 +190,18 @@ output_folder_wav = os.path.normpath(output_folder_wav)
|
||||
|
||||
# Check and perform file deletion
|
||||
if delete_output_wavs_setting.lower() == "disabled":
|
||||
print(
|
||||
"["
|
||||
+ params["branding"]
|
||||
+ "Startup] Old output wav file deletion is set to disabled."
|
||||
)
|
||||
print("["+ params["branding"]+"Startup] \033[92mWAV file deletion :\033[93m Disabled\033[0m")
|
||||
else:
|
||||
try:
|
||||
days_to_keep = int(delete_output_wavs_setting.split()[0])
|
||||
delete_old_files(output_folder_wav, days_to_keep)
|
||||
except ValueError:
|
||||
print(
|
||||
f"[{params['branding']}Startup] Invalid setting for deleting old wav files. Please use 'Disabled' or 'X Days' format."
|
||||
)
|
||||
print(f"[{params['branding']}Startup] \033[92mWAV file deletion :\033[93m Invalid setting for deleting old wav files. Please use 'Disabled' or 'X Days' format\033[0m")
|
||||
|
||||
if deepspeed_installed:
|
||||
print(f"[{params['branding']}Startup] \033[92mDeepSpeed version :\033[93m",deepspeed.__version__,"\033[0m")
|
||||
else:
|
||||
print(f"[{params['branding']}Startup] \033[92mDeepSpeed version :\033[91m Not Detected\033[0m")
|
||||
|
||||
########################
|
||||
#### STARTUP CHECKS ####
|
||||
@@ -153,8 +211,6 @@ def check_required_files():
|
||||
this_dir = Path(__file__).parent.resolve()
|
||||
download_script_path = this_dir / "modeldownload.py"
|
||||
subprocess.run(["python", str(download_script_path)])
|
||||
print(f"[{params['branding']}Startup] All required files are present.")
|
||||
|
||||
|
||||
# STARTUP Call Check routine
|
||||
check_required_files()
|
||||
@@ -174,7 +230,7 @@ if finetuned_model:
|
||||
(trained_model_directory / file).exists() for file in required_files
|
||||
)
|
||||
if finetuned_model:
|
||||
print(f"[{params['branding']}Startup] Finetuned model \033[93mDetected\033[0m")
|
||||
print(f"[{params['branding']}Startup] \033[92mFinetuned model :\033[93m Detected\033[0m")
|
||||
|
||||
####################################################
|
||||
#### SET GRADIO BUTTONS BASED ON confignew.json ####
|
||||
@@ -190,7 +246,6 @@ elif params["tts_method_xtts_local"] == True:
|
||||
# Set the default for Narrated text without asterisk or quotes to be Narrator
|
||||
non_quoted_text_is = True
|
||||
|
||||
|
||||
######################
|
||||
#### GRADIO STUFF ####
|
||||
######################
|
||||
@@ -237,9 +292,7 @@ script_path = this_dir / "tts_server.py"
|
||||
|
||||
|
||||
def signal_handler(sig, frame):
|
||||
print(
|
||||
f"[{params['branding']}Shutdown] \033[94mReceived Ctrl+C, terminating subprocess\033[92m"
|
||||
)
|
||||
print(f"[{params['branding']}Shutdown] \033[94mReceived Ctrl+C, terminating subprocess\033[92m")
|
||||
if process.poll() is None:
|
||||
process.terminate()
|
||||
process.wait() # Wait for the subprocess to finish
|
||||
@@ -258,33 +311,20 @@ else:
|
||||
process = subprocess.Popen(["python", script_path])
|
||||
# Check if the subprocess has started successfully
|
||||
if process.poll() is None:
|
||||
print(f"[{params['branding']}Startup] TTS Subprocess starting")
|
||||
print(f"[{params['branding']}Startup] \033[92mTTS Subprocess :\033[93m Starting up\033[0m")
|
||||
print(f"[{params['branding']}Startup]")
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[94m {params['branding']}Settings & Documentation:\033[00m",
|
||||
f"[{params['branding']}Startup] \033[94m{params['branding']}Settings & Documentation:\033[00m",
|
||||
f"\033[92mhttp://{params['ip_address']}:{params['port_number']}\033[00m",
|
||||
)
|
||||
print(f"[{params['branding']}Startup]")
|
||||
else:
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS Subprocess Webserver failing to start process"
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m It could be that you have something on port:",
|
||||
params["port_number"],
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m Or you have not started in a Python environement with all the necesssary bits installed"
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m Check you are starting Text-generation-webui with either the start_xxxxx file or the Python environment with cmd_xxxxx file."
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m xxxxx is the type of OS you are on e.g. windows, linux or mac."
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m Alternatively, you could check no other Python processes are running that shouldnt be e.g. Restart your computer is the simple way."
|
||||
)
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS Subprocess Webserver failing to start process")
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m It could be that you have something on port:",params["port_number"],)
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m Or you have not started in a Python environement with all the necesssary bits installed")
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m Check you are starting Text-generation-webui with either the start_xxxxx file or the Python environment with cmd_xxxxx file.")
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m xxxxx is the type of OS you are on e.g. windows, linux or mac.")
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m Alternatively, you could check no other Python processes are running that shouldnt be e.g. Restart your computer is the simple way.")
|
||||
# Cleanly kill off this script, but allow text-generation-webui to keep running, albeit without this alltalk_tts
|
||||
sys.exit(1)
|
||||
|
||||
@@ -300,26 +340,14 @@ else:
|
||||
break
|
||||
except requests.RequestException as e:
|
||||
# Print the exception for debugging purposes
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS Subprocess has NOT started up yet, Will keep trying for {timeout} seconds maximum. Please wait."
|
||||
)
|
||||
print(f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS Subprocess has NOT started up yet, Will keep trying for {timeout} seconds maximum. Please wait.")
|
||||
time.sleep(5)
|
||||
else:
|
||||
print(
|
||||
f"\n[{params['branding']}Startup] Startup timed out. Full help available here \033[92mhttps://github.com/erew123/alltalk_tts#-help-with-problems\033[0m"
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] On older system you may wish to open and edit \033[94mscript.py\033[0m with a text editor and changing the"
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] \033[94mstartup_wait_time = 120\033[0m setting to something like \033[94mstartup_wait_time = 240\033[0m as this will allow"
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] AllTalk more time to try load the model into your VRAM. Otherise please visit the Github for"
|
||||
)
|
||||
print(
|
||||
f"[{params['branding']}Startup] a list of other possible troubleshooting options."
|
||||
)
|
||||
print(f"\n[{params['branding']}Startup] Startup timed out. Full help available here \033[92mhttps://github.com/erew123/alltalk_tts#-help-with-problems\033[0m")
|
||||
print(f"[{params['branding']}Startup] On older system you may wish to open and edit \033[94mscript.py\033[0m with a text editor and changing the")
|
||||
print(f"[{params['branding']}Startup] \033[94mstartup_wait_time = 120\033[0m setting to something like \033[94mstartup_wait_time = 240\033[0m as this will allow")
|
||||
print(f"[{params['branding']}Startup] AllTalk more time to try load the model into your VRAM. Otherise please visit the Github for")
|
||||
print(f"[{params['branding']}Startup] a list of other possible troubleshooting options.")
|
||||
# Cleanly kill off this script, but allow text-generation-webui to keep running, albeit without this alltalk_tts
|
||||
sys.exit(1)
|
||||
|
||||
@@ -371,9 +399,7 @@ def send_reload_request(tts_method):
|
||||
return f'<audio src="file/{audio_path}" controls autoplay></audio>'
|
||||
except requests.exceptions.RequestException as e:
|
||||
# Handle the HTTP request error
|
||||
print(
|
||||
f"[{params['branding']}Server] \033[91mWarning\033[0m Error during request to webserver process: {e}"
|
||||
)
|
||||
print(f"[{params['branding']}Server] \033[91mWarning\033[0m Error during request to webserver process: {e}")
|
||||
return {"status": "error", "message": str(e)}
|
||||
|
||||
|
||||
@@ -400,9 +426,7 @@ def send_lowvram_request(low_vram):
|
||||
return f'<audio src="file/{audio_path}" controls autoplay></audio>'
|
||||
except requests.exceptions.RequestException as e:
|
||||
# Handle the HTTP request error
|
||||
print(
|
||||
f"[{params['branding']}Server] \033[91mWarning\033[0m Error during request to webserver process: {e}"
|
||||
)
|
||||
print(f"[{params['branding']}Server] \033[91mWarning\033[0m Error during request to webserver process: {e}")
|
||||
return {"status": "error", "message": str(e)}
|
||||
|
||||
|
||||
@@ -417,7 +441,6 @@ def send_deepspeed_request(deepspeed_param):
|
||||
audio_path = this_dir / "system" / "at_sounds" / "deepspeedenabled.wav"
|
||||
else:
|
||||
audio_path = this_dir / "system" / "at_sounds" / "deepspeeddisabled.wav"
|
||||
|
||||
url = f"{base_url}/api/deepspeed?new_deepspeed_value={deepspeed_param}"
|
||||
headers = {"Content-Type": "application/json"}
|
||||
response = requests.post(url, headers=headers)
|
||||
@@ -430,9 +453,7 @@ def send_deepspeed_request(deepspeed_param):
|
||||
return f'<audio src="file/{audio_path}" controls autoplay></audio>'
|
||||
except requests.exceptions.RequestException as e:
|
||||
# Handle the HTTP request error
|
||||
print(
|
||||
f"[{params['branding']}Server] \033[91mWarning\033[0m Error during request to webserver process: {e}"
|
||||
)
|
||||
print(f"[{params['branding']}Server] \033[91mWarning\033[0m Error during request to webserver process: {e}")
|
||||
return {"status": "error", "message": str(e)}
|
||||
|
||||
|
||||
@@ -465,9 +486,7 @@ Synthesizer.split_into_sentences = new_split_into_sentences
|
||||
def before_audio_generation(string, params):
|
||||
# Check Model is loaded into cuda or cpu and error if not
|
||||
if not params["tts_model_loaded"]:
|
||||
print(
|
||||
f"[{params['branding']}Model] \033[91mWarning\033[0m Model is still loading, please wait before trying to generate TTS"
|
||||
)
|
||||
print(f"[{params['branding']}Model] \033[91mWarning\033[0m Model is still loading, please wait before trying to generate TTS")
|
||||
return
|
||||
string = html.unescape(string) or random_sentence()
|
||||
if string == "":
|
||||
@@ -491,13 +510,9 @@ def combine(audio_files, output_folder, state):
|
||||
|
||||
# Save the combined audio to a file with a specified sample rate
|
||||
if "character_menu" in state:
|
||||
output_file_path = os.path.join(
|
||||
output_folder, f'{state["character_menu"]}_{int(time.time())}_combined.wav'
|
||||
)
|
||||
output_file_path = os.path.join(output_folder, f'{state["character_menu"]}_{int(time.time())}_combined.wav')
|
||||
else:
|
||||
output_file_path = os.path.join(
|
||||
output_folder, f"TTSOUT_{int(time.time())}_combined.wav"
|
||||
)
|
||||
output_file_path = os.path.join(output_folder, f"TTSOUT_{int(time.time())}_combined.wav")
|
||||
sf.write(output_file_path, audio, samplerate=sample_rate)
|
||||
# Clean up unnecessary files
|
||||
for audio_file in audio_files:
|
||||
@@ -544,9 +559,7 @@ def voice_preview(string):
|
||||
)
|
||||
# Check if lock is already acquired
|
||||
if process_lock.locked():
|
||||
print(
|
||||
f"[{params['branding']}Model] \033[91mWarning\033[0m Audio generation is already in progress. Please wait."
|
||||
)
|
||||
print(f"[{params['branding']}Model] \033[91mWarning\033[0m Audio generation is already in progress. Please wait.")
|
||||
return
|
||||
if generate_response.get("status") == "generate-success":
|
||||
# Handle Gradio and playback
|
||||
@@ -666,14 +679,10 @@ def output_modifier(string, state):
|
||||
# Determine the voice to use based on the part type
|
||||
if part_type == "narrator":
|
||||
voice_to_use = params["narrator_voice"]
|
||||
print(
|
||||
f"[{params['branding']}TTSGen] \033[92mNarrator\033[0m"
|
||||
) # Green
|
||||
print(f"[{params['branding']}TTSGen] \033[92mNarrator\033[0m") # Green
|
||||
elif part_type == "character":
|
||||
voice_to_use = params["voice"]
|
||||
print(
|
||||
f"[{params['branding']}TTSGen] \033[36mCharacter\033[0m"
|
||||
) # Yellow
|
||||
print(f"[{params['branding']}TTSGen] \033[36mCharacter\033[0m") # Yellow
|
||||
else:
|
||||
# Handle ambiguous parts based on user preference
|
||||
voice_to_use = (
|
||||
@@ -689,9 +698,11 @@ def output_modifier(string, state):
|
||||
print(f"[{params['branding']}TTSGen] {voice_description}")
|
||||
|
||||
# Replace multiple exclamation marks, question marks, or other punctuation with a single instance
|
||||
cleaned_part = re.sub(r"([!?.])\1+", r"\1", part)
|
||||
cleaned_part = re.sub(r"([!?.\u3002\uFF1F\uFF01\uFF0C])\1+", r"\1", part)
|
||||
# Replace "Chinese ellipsis" with a single dot
|
||||
cleaned_part = re.sub(r"\u2026{1,2}", ". ", cleaned_part)
|
||||
# Further clean to remove any other unwanted characters
|
||||
cleaned_part = re.sub(r'[^a-zA-Z0-9\s\.,;:!?\-\'"\u0100-\u017F\u0400-\u04FFÀ-ÿ\u0150\u0151\u0170\u0171\u4E00-\u9FFF\u3400-\u4DBF\u20000-\u2A6DF\u3000-\u303F\$]', '', cleaned_part)
|
||||
cleaned_part = re.sub(r'[^a-zA-Z0-9\s.,;:!?\-\'"$\u0400-\u04FF\u00C0-\u00FF\u0150\u0151\u0170\u0171\u0900-\u097F\u2018\u2019\u201C\u201D\u3001\u3002\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF\uAC00-\uD7A3\u1100-\u11FF\u3130-\u318F\uFF01\uFF0c\uFF1A\uFF1B\uFF1F]', '', cleaned_part)
|
||||
# Remove all newline characters (single or multiple)
|
||||
cleaned_part = re.sub(r"\n+", " ", cleaned_part)
|
||||
|
||||
@@ -716,9 +727,11 @@ def output_modifier(string, state):
|
||||
# Decode HTML entities first
|
||||
cleaned_part = html.unescape(cleaned_string)
|
||||
# Replace multiple instances of certain punctuation marks with a single instance
|
||||
cleaned_part = re.sub(r"([!?.])\1+", r"\1", cleaned_part)
|
||||
cleaned_part = re.sub(r"([!?.\u3002\uFF1F\uFF01\uFF0C])\1+", r"\1", cleaned_part)
|
||||
# Replace "Chinese ellipsis" with a single dot
|
||||
cleaned_part = re.sub(r"\u2026{1,2}", ". ", cleaned_part)
|
||||
# Further clean to remove any other unwanted characters
|
||||
cleaned_part = re.sub(r'[^a-zA-Z0-9\s\.,;:!?\-\'"\u0100-\u017F\u0400-\u04FFÀ-ÿ\u0150\u0151\u0170\u0171\u4E00-\u9FFF\u3400-\u4DBF\u20000-\u2A6DF\u3000-\u303F\$]', '', cleaned_part)
|
||||
cleaned_part = re.sub(r'[^a-zA-Z0-9\s.,;:!?\-\'"$\u0400-\u04FF\u00C0-\u00FF\u0150\u0151\u0170\u0171\u0900-\u097F\u2018\u2019\u201C\u201D\u3001\u3002\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF\uAC00-\uD7A3\u1100-\u11FF\u3130-\u318F\uFF01\uFF0c\uFF1A\uFF1B\uFF1F]', '', cleaned_part)
|
||||
# Remove all newline characters (single or multiple)
|
||||
cleaned_part = re.sub(r"\n+", " ", cleaned_part)
|
||||
# Process the part and give it a non-character name if being used vai API or standalone.
|
||||
|
||||
@@ -304,6 +304,7 @@
|
||||
<option value="nl">Dutch</option>
|
||||
<option value="fr">French</option>
|
||||
<option value="de">German</option>
|
||||
<option value="hi">Hindi</option>
|
||||
<option value="hu">Hungarian</option>
|
||||
<option value="it">Italian</option>
|
||||
<option value="ja">Japanese</option>
|
||||
@@ -474,7 +475,7 @@
|
||||
<span style="color: #3366ff;">22050Hz</span>, <span style="color: #3366ff;">Mono</span>, <span
|
||||
style="color: #3366ff;">16 bit</span> 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 a much longer clips.
|
||||
output from much longer clips.
|
||||
</p>
|
||||
<p>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
|
||||
@@ -1357,6 +1358,7 @@
|
||||
<h3 id="🟨-help-with-problems">🟨 Help with problems</h3>
|
||||
<h4 id="🔄-minor-updatesbug-fixes-list-can-be-found-here"> 🔄 <strong>Minor updates/bug
|
||||
fixes list</strong> can be found <a href="https://github.com/erew123/alltalk_tts/issues/25">here</a></h4>
|
||||
<h4> Please check Github for the most up to date help list <a href="https://github.com/erew123/alltalk_tts#-help-with-problems">here</a></h4>
|
||||
<details>
|
||||
<summary>🟨 How to make a diagnostics report file</summary>
|
||||
|
||||
@@ -2499,6 +2501,7 @@
|
||||
<code>en</code> English<br>
|
||||
<code>fr</code> French<br>
|
||||
<code>de</code> German<br>
|
||||
<code>hi</code> Hindi<br>
|
||||
<code>hu</code> Hungarian<br>
|
||||
<code>it</code> Italian<br>
|
||||
<code>ja</code> Japanese<br>
|
||||
|
||||
|
Before Width: | Height: | Size: 440 KiB After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 11 KiB |
@@ -124,6 +124,7 @@
|
||||
<option value="English" {% if data.language=='English' %}selected{% endif %}>English</option>
|
||||
<option value="French" {% if data.language=='French' %}selected{% endif %}>French</option>
|
||||
<option value="German" {% if data.language=='German' %}selected{% endif %}>German</option>
|
||||
<option value="Hindi" {% if data.language=='Hindi' %}selected{% endif %}>Hindi</option>
|
||||
<option value="Hungarian" {% if data.language=='Hungarian' %}selected{% endif %}>Hungarian</option>
|
||||
<option value="Italian" {% if data.language=='Italian' %}selected{% endif %}>Italian</option>
|
||||
<option value="Japanese" {% if data.language=='Japanese' %}selected{% endif %}>Japanese</option>
|
||||
|
||||
|
Before Width: | Height: | Size: 445 KiB After Width: | Height: | Size: 216 KiB |
|
Before Width: | Height: | Size: 476 KiB After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 547 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 52 KiB |
@@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
"English": "en",
|
||||
"French": "fr",
|
||||
"German": "de",
|
||||
"Hindi": "hi",
|
||||
"Hungarian": "hu",
|
||||
"Italian": "it",
|
||||
"Japanese": "ja",
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
absl-py==2.1.0
|
||||
aiofiles==23.2.1
|
||||
aiohttp==3.9.3
|
||||
aiosignal==1.3.1
|
||||
altair==5.2.0
|
||||
annotated-types==0.6.0
|
||||
anyascii==0.3.2
|
||||
anyio==4.3.0
|
||||
attrs==23.2.0
|
||||
audioread==3.0.1
|
||||
av==11.0.0
|
||||
Babel==2.14.0
|
||||
bangla==0.0.2
|
||||
blinker==1.7.0
|
||||
blis==0.7.11
|
||||
bnnumerizer==0.0.2
|
||||
bnunicodenormalizer==0.1.6
|
||||
catalogue==2.0.10
|
||||
certifi==2024.2.2
|
||||
cffi==1.16.0
|
||||
charset-normalizer==3.3.2
|
||||
click==8.1.7
|
||||
cloudpathlib==0.16.0
|
||||
colorama==0.4.6
|
||||
coloredlogs==15.0.1
|
||||
confection==0.1.4
|
||||
contourpy==1.2.0
|
||||
coqpit==0.0.17
|
||||
ctranslate2==4.1.0
|
||||
cutlet==0.4.0
|
||||
cycler==0.12.1
|
||||
cymem==2.0.8
|
||||
Cython==3.0.9
|
||||
dateparser==1.1.8
|
||||
decorator==5.1.1
|
||||
docopt==0.6.2
|
||||
einops==0.7.0
|
||||
encodec==0.1.1
|
||||
exceptiongroup
|
||||
fastapi==0.110.0
|
||||
faster-whisper==1.0.1
|
||||
ffmpy==0.3.2
|
||||
filelock==3.13.3
|
||||
Flask==3.0.2
|
||||
flatbuffers==24.3.25
|
||||
fonttools==4.50.0
|
||||
frozenlist==1.4.1
|
||||
fsspec==2024.3.1
|
||||
fugashi==1.3.1
|
||||
fuzzywuzzy>=0.18.0
|
||||
g2pkk==0.1.2
|
||||
gradio==3.50.2
|
||||
gradio_client==0.6.1
|
||||
grpcio==1.62.1
|
||||
gruut==2.2.3
|
||||
gruut-ipa==0.13.0
|
||||
gruut-lang-de==2.0.0
|
||||
gruut-lang-en==2.0.0
|
||||
gruut-lang-es==2.0.0
|
||||
gruut-lang-fr==2.0.2
|
||||
h11==0.14.0
|
||||
hangul-romanize==0.1.0
|
||||
httpcore==1.0.4
|
||||
httpx==0.27.0
|
||||
huggingface-hub==0.22.1
|
||||
humanfriendly==10.0
|
||||
idna==3.6
|
||||
importlib_metadata==7.1.0
|
||||
importlib_resources==6.4.0
|
||||
inflect==7.0.0
|
||||
itsdangerous==2.1.2
|
||||
jaconv==0.3.4
|
||||
jamo==0.4.1
|
||||
jieba==0.42.1
|
||||
Jinja2==3.1.3
|
||||
joblib==1.3.2
|
||||
jsonlines==1.2.0
|
||||
jsonschema==4.21.1
|
||||
jsonschema-specifications==2023.12.1
|
||||
kiwisolver==1.4.5
|
||||
langcodes==3.3.0
|
||||
lazy_loader==0.3
|
||||
librosa==0.10.1
|
||||
llvmlite==0.42.0
|
||||
Markdown==3.6
|
||||
MarkupSafe==2.1.5
|
||||
matplotlib==3.8.3
|
||||
mojimoji==0.0.13
|
||||
mpmath==1.3.0
|
||||
msgpack==1.0.8
|
||||
multidict==6.0.5
|
||||
murmurhash==1.0.10
|
||||
networkx==2.8.8
|
||||
nltk==3.8.1
|
||||
num2words==0.5.13
|
||||
numba==0.59.1
|
||||
numpy==1.26.4
|
||||
nvidia-cublas-cu11>=11.11.3.6
|
||||
nvidia-cudnn-cu11>=9.0.0.312
|
||||
onnxruntime==1.17.1
|
||||
orjson==3.9.15
|
||||
packaging==24.0
|
||||
pandas==1.5.3
|
||||
pillow==10.2.0
|
||||
platformdirs==4.2.0
|
||||
pooch==1.8.1
|
||||
preshed==3.0.9
|
||||
protobuf==5.26.0
|
||||
psutil==5.9.8
|
||||
pycparser==2.21
|
||||
pydantic==2.6.4
|
||||
pydantic_core==2.16.3
|
||||
pydub==0.25.1
|
||||
pynndescent==0.5.11
|
||||
pyparsing==3.1.2
|
||||
pypinyin==0.51.0
|
||||
pyreadline3==3.4.1
|
||||
pysbd==0.3.4
|
||||
python-crfsuite==0.9.10
|
||||
python-dateutil==2.9.0.post0
|
||||
python-Levenshtein>=0.25.0
|
||||
python-multipart==0.0.9
|
||||
pytz==2024.1
|
||||
PyYAML==6.0.1
|
||||
referencing==0.34.0
|
||||
regex==2023.12.25
|
||||
requests==2.31.0
|
||||
rpds-py==0.18.0
|
||||
safetensors==0.4.2
|
||||
scikit-learn==1.4.1.post1
|
||||
scipy==1.12.0
|
||||
semantic-version==2.10.0
|
||||
six==1.16.0
|
||||
smart-open==6.4.0
|
||||
sniffio==1.3.1
|
||||
sounddevice==0.4.6
|
||||
soundfile==0.12.1
|
||||
soxr==0.3.7
|
||||
spacy==3.7.4
|
||||
spacy-legacy==3.0.12
|
||||
spacy-loggers==1.0.5
|
||||
srsly==2.4.8
|
||||
starlette==0.36.3
|
||||
SudachiDict-core==20240109
|
||||
SudachiPy==0.6.8
|
||||
sympy==1.12
|
||||
tensorboard==2.16.2
|
||||
tensorboard-data-server==0.7.2
|
||||
thinc==8.2.3
|
||||
threadpoolctl==3.4.0
|
||||
tokenizers==0.15.2
|
||||
toolz==0.12.1
|
||||
torch>=2.2.0
|
||||
torchaudio>=2.2.0
|
||||
tqdm==4.66.2
|
||||
trainer==0.0.36
|
||||
transformers==4.39.1
|
||||
TTS==0.22.0
|
||||
typer==0.9.4
|
||||
typing_extensions==4.10.0
|
||||
tzdata==2024.1
|
||||
tzlocal==5.2
|
||||
umap-learn==0.5.5
|
||||
Unidecode==1.3.8
|
||||
unidic-lite==1.0.8
|
||||
urllib3==2.2.1
|
||||
uvicorn==0.29.0
|
||||
wasabi==1.1.2
|
||||
weasel==0.3.4
|
||||
websockets==11.0.3
|
||||
Werkzeug==3.0.1
|
||||
yarl==1.9.4
|
||||
zipp==3.18.1
|
||||
@@ -0,0 +1,171 @@
|
||||
absl-py==2.1.0
|
||||
aiofiles==23.2.1
|
||||
aiohttp==3.9.3
|
||||
aiosignal==1.3.1
|
||||
altair==5.2.0
|
||||
annotated-types==0.6.0
|
||||
anyascii==0.3.2
|
||||
anyio==4.3.0
|
||||
attrs==23.2.0
|
||||
audioread==3.0.1
|
||||
av==11.0.0
|
||||
Babel==2.14.0
|
||||
bangla==0.0.2
|
||||
blinker==1.7.0
|
||||
blis==0.7.11
|
||||
bnnumerizer==0.0.2
|
||||
bnunicodenormalizer==0.1.6
|
||||
catalogue==2.0.10
|
||||
certifi==2024.2.2
|
||||
cffi==1.16.0
|
||||
charset-normalizer==3.3.2
|
||||
click==8.1.7
|
||||
cloudpathlib==0.16.0
|
||||
colorama==0.4.6
|
||||
coloredlogs==15.0.1
|
||||
confection==0.1.4
|
||||
contourpy==1.2.0
|
||||
coqpit==0.0.17
|
||||
ctranslate2==4.1.0
|
||||
cutlet==0.4.0
|
||||
cycler==0.12.1
|
||||
cymem==2.0.8
|
||||
Cython==3.0.9
|
||||
dateparser==1.1.8
|
||||
decorator==5.1.1
|
||||
docopt==0.6.2
|
||||
einops==0.7.0
|
||||
encodec==0.1.1
|
||||
fastapi==0.110.0
|
||||
faster-whisper==1.0.1
|
||||
ffmpy==0.3.2
|
||||
filelock==3.13.3
|
||||
Flask==3.0.2
|
||||
flatbuffers==24.3.25
|
||||
fonttools==4.50.0
|
||||
frozenlist==1.4.1
|
||||
fsspec==2024.3.1
|
||||
fugashi==1.3.1
|
||||
fuzzywuzzy>=0.18.0
|
||||
g2pkk==0.1.2
|
||||
gradio==3.50.2
|
||||
gradio_client==0.6.1
|
||||
grpcio==1.62.1
|
||||
gruut==2.2.3
|
||||
gruut-ipa==0.13.0
|
||||
gruut-lang-de==2.0.0
|
||||
gruut-lang-en==2.0.0
|
||||
gruut-lang-es==2.0.0
|
||||
gruut-lang-fr==2.0.2
|
||||
h11==0.14.0
|
||||
hangul-romanize==0.1.0
|
||||
httpcore==1.0.4
|
||||
httpx==0.27.0
|
||||
huggingface-hub==0.22.1
|
||||
humanfriendly==10.0
|
||||
idna==3.6
|
||||
importlib_metadata==7.1.0
|
||||
importlib_resources==6.4.0
|
||||
inflect==7.0.0
|
||||
itsdangerous==2.1.2
|
||||
jaconv==0.3.4
|
||||
jamo==0.4.1
|
||||
jieba==0.42.1
|
||||
Jinja2==3.1.3
|
||||
joblib==1.3.2
|
||||
jsonlines==1.2.0
|
||||
jsonschema==4.21.1
|
||||
jsonschema-specifications==2023.12.1
|
||||
kiwisolver==1.4.5
|
||||
langcodes==3.3.0
|
||||
lazy_loader==0.3
|
||||
librosa==0.10.1
|
||||
llvmlite==0.42.0
|
||||
Markdown==3.6
|
||||
MarkupSafe==2.1.5
|
||||
matplotlib==3.8.3
|
||||
mojimoji==0.0.13
|
||||
mpmath==1.3.0
|
||||
msgpack==1.0.8
|
||||
multidict==6.0.5
|
||||
murmurhash==1.0.10
|
||||
networkx==2.8.8
|
||||
nltk==3.8.1
|
||||
num2words==0.5.13
|
||||
numba==0.59.1
|
||||
numpy>=1.17.0,<1.29.0
|
||||
nvidia-cublas-cu11>=11.11.3.6
|
||||
nvidia-cudnn-cu11>=9.0.0.312
|
||||
onnxruntime==1.17.1
|
||||
orjson==3.9.15
|
||||
packaging==24.0
|
||||
pandas==1.5.3
|
||||
pillow==10.2.0
|
||||
platformdirs==4.2.0
|
||||
pooch==1.8.1
|
||||
preshed==3.0.9
|
||||
protobuf==5.26.0
|
||||
psutil==5.9.8
|
||||
pycparser==2.21
|
||||
pydantic==2.6.4
|
||||
pydantic_core==2.16.3
|
||||
pydub==0.25.1
|
||||
pynndescent==0.5.11
|
||||
pyparsing==3.1.2
|
||||
pypinyin==0.51.0
|
||||
pyreadline3==3.4.1
|
||||
pysbd==0.3.4
|
||||
python-crfsuite==0.9.10
|
||||
python-dateutil==2.9.0.post0
|
||||
python-Levenshtein>=0.25.0
|
||||
python-multipart==0.0.9
|
||||
pytz==2024.1
|
||||
PyYAML==6.0.1
|
||||
referencing==0.34.0
|
||||
regex==2023.12.25
|
||||
requests==2.31.0
|
||||
rpds-py==0.18.0
|
||||
safetensors==0.4.2
|
||||
scikit-learn==1.4.1.post1
|
||||
scipy==1.12.0
|
||||
semantic-version==2.10.0
|
||||
six==1.16.0
|
||||
smart-open==6.4.0
|
||||
sniffio==1.3.1
|
||||
sounddevice==0.4.6
|
||||
soundfile==0.12.1
|
||||
soxr==0.3.7
|
||||
spacy==3.7.4
|
||||
spacy-legacy==3.0.12
|
||||
spacy-loggers==1.0.5
|
||||
srsly==2.4.8
|
||||
starlette==0.36.3
|
||||
SudachiDict-core==20240109
|
||||
SudachiPy==0.6.8
|
||||
sympy==1.12
|
||||
tensorboard==2.16.2
|
||||
tensorboard-data-server==0.7.2
|
||||
thinc==8.2.3
|
||||
threadpoolctl==3.4.0
|
||||
tokenizers==0.15.2
|
||||
toolz==0.12.1
|
||||
torch>=2.2.0
|
||||
torchaudio>=2.2.0
|
||||
tqdm==4.66.2
|
||||
trainer==0.0.36
|
||||
transformers==4.39.1
|
||||
typer==0.9.4
|
||||
typing_extensions==4.10.0
|
||||
tzdata==2024.1
|
||||
tzlocal==5.2
|
||||
umap-learn==0.5.5
|
||||
Unidecode==1.3.8
|
||||
unidic-lite==1.0.8
|
||||
urllib3==2.2.1
|
||||
uvicorn==0.29.0
|
||||
wasabi==1.1.2
|
||||
weasel==0.3.4
|
||||
websockets==11.0.3
|
||||
Werkzeug==3.0.1
|
||||
yarl==1.9.4
|
||||
zipp==3.18.1
|
||||
@@ -22,3 +22,4 @@ nvidia-cublas-cu11>=11.11.3.6
|
||||
nvidia-cudnn-cu11>=9.0.0.312
|
||||
fuzzywuzzy>=0.18.0
|
||||
python-Levenshtein>=0.25.0
|
||||
spacy>=3.7.2
|
||||
@@ -281,7 +281,7 @@ class AllTalkTtsProvider {
|
||||
if (narratorVoiceSelect) narratorVoiceSelect.disabled = !this.settings.narrator_enabled;
|
||||
}
|
||||
const modelSelect = document.getElementById('switch_model');
|
||||
if (this.settings.finetuned_model === 'true') {
|
||||
if (this.settings.finetuned_model === true) {
|
||||
const ftOption = document.createElement('option');
|
||||
ftOption.value = 'XTTSv2 FT';
|
||||
ftOption.textContent = 'XTTSv2 FT';
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
var e={d:(t,n)=>{for(var r in n)e.o(n,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:n[r]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};function n(e){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n(e)}function r(e){return function(e){if(Array.isArray(e))return a(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return a(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return a(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function a(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){for(var r=0;r<t.length;r++){var a=t[r];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,(o=a.key,i=void 0,i=function(e,t){if("object"!==n(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var a=r.call(e,t||"default");if("object"!==n(a))return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(o,"string"),"symbol"===n(i)?i:String(i)),a)}var o,i}e.d(t,{Z:()=>u});var u=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.sampleRate;o(this,e),this._context=this._createContext(n),n||(n=this._context.sampleRate),this._sampleRate=n}var t,n,a;return t=e,n=[{key:"_createContext",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:44100;return window.AudioContext=window.AudioContext||window.webkitAudioContext||window.mozAudioContext,new AudioContext({sampleRate:e})}},{key:"context",get:function(){return this._context}},{key:"fetchAudio",value:async function(){for(var e=this,t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];return await Promise.all(n.map((async function(t){var n;return n=t instanceof File||t instanceof Blob?await t.arrayBuffer():await fetch(t).then((function(e){return e.headers.has("Content-Type")&&!e.headers.get("Content-Type").includes("audio/")&&console.warn("Crunker: Attempted to fetch an audio file, but its MIME type is `".concat(e.headers.get("Content-Type").split(";")[0],"`. We'll try and continue anyway. (file: \"").concat(t,'")')),e.arrayBuffer()})),await e._context.decodeAudioData(n)})))}},{key:"mergeAudio",value:function(e){var t=this._context.createBuffer(this._maxNumberOfChannels(e),this._sampleRate*this._maxDuration(e),this._sampleRate);return e.forEach((function(e){for(var n=0;n<e.numberOfChannels;n++){for(var r=t.getChannelData(n),a=e.getChannelData(n),o=e.getChannelData(n).length-1;o>=0;o--)r[o]+=a[o];t.getChannelData(n).set(r)}})),t}},{key:"concatAudio",value:function(e){var t=this._context.createBuffer(this._maxNumberOfChannels(e),this._totalLength(e),this._sampleRate),n=0;return e.forEach((function(e){for(var r=0;r<e.numberOfChannels;r++)t.getChannelData(r).set(e.getChannelData(r),n);n+=e.length})),t}},{key:"padAudio",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;if(0===n)return e;if(t<0)throw new Error('Crunker: Parameter "padStart" in padAudio must be positive');if(n<0)throw new Error('Crunker: Parameter "seconds" in padAudio must be positive');for(var r=this._context.createBuffer(e.numberOfChannels,Math.ceil(e.length+n*e.sampleRate),e.sampleRate),a=0;a<e.numberOfChannels;a++){var o=e.getChannelData(a);r.getChannelData(a).set(o.subarray(0,Math.ceil(t*e.sampleRate)+1),0),r.getChannelData(a).set(o.subarray(Math.ceil(t*e.sampleRate)+2,r.length+1),Math.ceil((t+n)*e.sampleRate))}return r}},{key:"sliceAudio",value:function(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0;if(t>=n)throw new Error('Crunker: "start" time should be less than "end" time in sliceAudio method');for(var o=Math.round((n-t)*this._sampleRate),i=Math.round(t*this._sampleRate),u=this._context.createBuffer(e.numberOfChannels,o,this._sampleRate),l=0;l<e.numberOfChannels;l++)for(var s=e.getChannelData(l),c=u.getChannelData(l),f=0;f<o;f++)c[f]=s[i+f],f<r*this._sampleRate&&(c[f]*=f/(r*this._sampleRate)),f>o-a*this._sampleRate&&(c[f]*=(o-f)/(a*this._sampleRate));return u}},{key:"play",value:function(e){var t=this._context.createBufferSource();return t.buffer=e,t.connect(this._context.destination),t.start(),Line truncated
|
||||
var e={d:(t,n)=>{for(var r in n)e.o(n,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:n[r]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};function n(e){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n(e)}function r(e){return function(e){if(Array.isArray(e))return a(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return a(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return a(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function a(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){for(var r=0;r<t.length;r++){var a=t[r];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,(o=a.key,i=void 0,i=function(e,t){if("object"!==n(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var a=r.call(e,t||"default");if("object"!==n(a))return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(o,"string"),"symbol"===n(i)?i:String(i)),a)}var o,i}e.d(t,{Z:()=>u});var u=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.sampleRate;o(this,e),this._context=this._createContext(n),n||(n=this._context.sampleRate),this._sampleRate=n}var t,n,a;return t=e,n=[{key:"_createContext",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:44100;return window.AudioContext=window.AudioContext||window.webkitAudioContext||window.mozAudioContext,new AudioContext({sampleRate:e})}},{key:"context",get:function(){return this._context}},{key:"fetchAudio",value:async function(){for(var e=this,t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];return await Promise.all(n.map((async function(t){var n;return n=t instanceof File||t instanceof Blob?await t.arrayBuffer():await fetch(t).then((function(e){return e.headers.has("Content-Type")&&!e.headers.get("Content-Type").includes("audio/")&&console.warn("Crunker: Attempted to fetch an audio file, but its MIME type is `".concat(e.headers.get("Content-Type").split(";")[0],"`. We'll try and continue anyway. (file: \"").concat(t,'")')),e.arrayBuffer()})),await e._context.decodeAudioData(n)})))}},{key:"mergeAudio",value:function(e){var t=this._context.createBuffer(this._maxNumberOfChannels(e),this._sampleRate*this._maxDuration(e),this._sampleRate);return e.forEach((function(e){for(var n=0;n<e.numberOfChannels;n++){for(var r=t.getChannelData(n),a=e.getChannelData(n),o=e.getChannelData(n).length-1;o>=0;o--)r[o]+=a[o];t.getChannelData(n).set(r)}})),t}},{key:"concatAudio",value:function(e){var t=this._context.createBuffer(this._maxNumberOfChannels(e),this._totalLength(e),this._sampleRate),n=0;return e.forEach((function(e){for(var r=0;r<e.numberOfChannels;r++)t.getChannelData(r).set(e.getChannelData(r),n);n+=e.length})),t}},{key:"padAudio",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;if(0===n)return e;if(t<0)throw new Error('Crunker: Parameter "padStart" in padAudio must be positive');if(n<0)throw new Error('Crunker: Parameter "seconds" in padAudio must be positive');for(var r=this._context.createBuffer(e.numberOfChannels,Math.ceil(e.length+n*e.sampleRate),e.sampleRate),a=0;a<e.numberOfChannels;a++){var o=e.getChannelData(a);r.getChannelData(a).set(o.subarray(0,Math.ceil(t*e.sampleRate)+1),0),r.getChannelData(a).set(o.subarray(Math.ceil(t*e.sampleRate)+2,r.length+1),Math.ceil((t+n)*e.sampleRate))}return r}},{key:"sliceAudio",value:function(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0;if(t>=n)throw new Error('Crunker: "start" time should be less than "end" time in sliceAudio method');for(var o=Math.round((n-t)*this._sampleRate),i=Math.round(t*this._sampleRate),u=this._context.createBuffer(e.numberOfChannels,o,this._sampleRate),l=0;l<e.numberOfChannels;l++)for(var s=e.getChannelData(l),c=u.getChannelData(l),f=0;f<o;f++)c[f]=s[i+f],f<r*this._sampleRate&&(c[f]*=f/(r*this._sampleRate)),f>o-a*this._sampleRate&&(c[f]*=(o-f)/(a*this._sampleRate));return u}},{key:"play",value:function(e){var t=this._context.createBufferSource();return t.buffer=e,t.connect(this._context.destination),t.start(),Line truncated
|
||||
//# sourceMappingURL=crunker.esm.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"crunker.esm.js","mappings":"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 truncated
|
||||
{"version":3,"file":"crunker.esm.js","mappings":"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 truncated
|
||||
@@ -532,6 +532,7 @@
|
||||
<option value="en" selected>English</option>
|
||||
<option value="fr">French</option>
|
||||
<option value="de">German</option>
|
||||
<option value="hi">Hindi</option>
|
||||
<option value="hu">Hungarian</option>
|
||||
<option value="it">Italian</option>
|
||||
<option value="ja">Japanese</option>
|
||||
@@ -921,18 +922,21 @@
|
||||
const playType = document.getElementById('playType').value; // Play type (chunk or stream)
|
||||
playModeValue = document.getElementById('playMode').value;
|
||||
|
||||
let cleanedText = textInput.replace(/ \- | \– /g, ' ');
|
||||
let cleanedText = textInput.replace(/ \\- | \\– /g, ' ');
|
||||
cleanedText = cleanedText.replace(/%/g, " percent");
|
||||
cleanedText = cleanedText.replace(/\.\s'/g, ".'");
|
||||
cleanedText = cleanedText.replace(/(?<!\w)[']+(?!\w)/g, '');
|
||||
cleanedText = cleanedText.replace(/\\.\\s'/g, ".'");
|
||||
cleanedText = cleanedText.replace(/(?<!\\w)\['\]+(?!\\w)/g, '');
|
||||
cleanedText = cleanedText.replace(/"/g, "'");
|
||||
cleanedText = cleanedText.replace(/[^a-zA-Z0-9\s\.,;:!?\-\'"À-ÿ\u0400-\u04FF\u0150\u0151\u0170\u0171]\$/g, '');
|
||||
// Replace dash followed by space with comma and space
|
||||
cleanedText = cleanedText.replace(/-\s/g, '; ');
|
||||
// Replace double dash "--" with semicolon "; "
|
||||
cleanedText = cleanedText.replace(/[^a-zA-Z0-9\s.,;:!?\-'"$À-ÿ\u0400-\u04FF\u0150\u0151\u0170\u0171\u0900-\u097F\u2018\u2019\u201C\u201D\u2026\u3001\u3002\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF\uAC00-\uD7A3\u1100-\u11FF\u3130-\u318F\uFF01\uFF0c\uFF1A\uFF1B\uFF1F]/g, '');
|
||||
cleanedText = cleanedText.replace(/-\\s/g, '; ');
|
||||
cleanedText = cleanedText.replace(/--/g, '; ');
|
||||
|
||||
let sentences = cleanedText.split(/(?<=[.!?:])\s+/);
|
||||
// Split by Fullwidth/CJK punctuation regardless of if there are spaces behind them
|
||||
// Please test if it works properly. In my test they it should be
|
||||
// (?<=[.!?:])\s+ instead of
|
||||
// (?<=\[.!?:\])\\s+
|
||||
// so I don't know whats going on here
|
||||
// let sentences = cleanedText.split(/(?<=[\[.!?:\]])\s+|(?<=[\u3002\uFF01\uFF1A\uFF1F])/);
|
||||
let sentences = cleanedText.split(/(?<=[\[.!?:\]]['"\u2018\u2019\u201C\u201D]*)\s+|(?<=[\u3002\uFF01\uFF1A\uFF1F])/);
|
||||
|
||||
if (!sentences) {
|
||||
console.error("No sentences found in the input text.");
|
||||
|
||||
@@ -8,7 +8,8 @@ from TTS.tts.configs.xtts_config import XttsConfig
|
||||
from TTS.tts.models.xtts import Xtts
|
||||
import io
|
||||
import wave
|
||||
|
||||
import logging
|
||||
logging.disable(logging.WARNING)
|
||||
##########################
|
||||
#### Webserver Imports####
|
||||
##########################
|
||||
@@ -120,12 +121,6 @@ try:
|
||||
deepspeed_available = True
|
||||
except ImportError:
|
||||
pass
|
||||
if deepspeed_available:
|
||||
print(f"[{params['branding']}Startup] DeepSpeed \033[93mDetected\033[0m")
|
||||
print(f"[{params['branding']}Startup] Activate DeepSpeed in {params['branding']}settings")
|
||||
else:
|
||||
print(f"[{params['branding']}Startup] DeepSpeed \033[93mNot Detected\033[0m. See https://github.com/microsoft/DeepSpeed")
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def startup_shutdown(no_actual_value_it_demanded_something_be_here):
|
||||
@@ -187,9 +182,8 @@ async def setup():
|
||||
# Calculate start time minus end time
|
||||
generate_elapsed_time = generate_end_time - generate_start_time
|
||||
# Print out the result of the load time
|
||||
print(
|
||||
f"[{params['branding']}Model] \033[94mModel Loaded in \033[93m{generate_elapsed_time:.2f} seconds.\033[0m"
|
||||
)
|
||||
print(f"[{params['branding']}Model] \033[94mModel Loaded in \033[93m{generate_elapsed_time:.2f} seconds.\033[0m")
|
||||
print(f"[{params['branding']}Model] Ready")
|
||||
# Set "tts_model_loaded" to true
|
||||
params["tts_model_loaded"] = True
|
||||
# Set the output path for wav files
|
||||
@@ -223,6 +217,8 @@ async def api_manual_load_model():
|
||||
model_path=modeldownload_base_path / modeldownload_model_path,
|
||||
config_path=modeldownload_base_path / modeldownload_model_path / "config.json",
|
||||
).to(device)
|
||||
print(f"[{params['branding']}Model] \033[94mCoqui Public Model License\033[0m")
|
||||
print(f"[{params['branding']}Model] \033[94mhttps://coqui.ai/cpml.txt\033[0m")
|
||||
return model
|
||||
|
||||
|
||||
@@ -252,6 +248,8 @@ async def xtts_manual_load_model():
|
||||
use_deepspeed=params["deepspeed_activate"],
|
||||
)
|
||||
model.to(device)
|
||||
print(f"[{params['branding']}Model] \033[94mCoqui Public Model License\033[0m")
|
||||
print(f"[{params['branding']}Model] \033[94mhttps://coqui.ai/cpml.txt\033[0m")
|
||||
return model
|
||||
|
||||
# MODEL LOADER For "XTTSv2 FT"
|
||||
@@ -270,6 +268,8 @@ async def xtts_ft_manual_load_model():
|
||||
use_deepspeed=params["deepspeed_activate"],
|
||||
)
|
||||
model.to(device)
|
||||
print(f"[{params['branding']}Model] \033[94mCoqui Public Model License\033[0m")
|
||||
print(f"[{params['branding']}Model] \033[94mhttps://coqui.ai/cpml.txt\033[0m")
|
||||
return model
|
||||
|
||||
# MODEL UNLOADER
|
||||
@@ -476,6 +476,11 @@ async def deepspeed(request: Request, new_deepspeed_value: bool):
|
||||
########################
|
||||
#### TTS GENERATION ####
|
||||
########################
|
||||
debug_generate_audio = False
|
||||
tts_stop_generation = False # Called to stop generation of the current text at whatever stage its at. currently only set for streaming.
|
||||
tts_generation_lock = False # Tracks locking of the generaetion process.
|
||||
tts_narrator_generatingtts = False # Tracks if the current tts processes are narrator based, to avoid moving model on each chunk of text generated.
|
||||
# Not in use tts_queue_behaviour = False # True is to queue the current generation request. False is to cancel the current generation and start a new one.
|
||||
|
||||
# TTS VOICE GENERATION METHODS (called from voice_preview and output_modifer)
|
||||
async def generate_audio(text, voice, language, temperature, repetition_penalty, output_file, streaming=False):
|
||||
@@ -487,8 +492,10 @@ async def generate_audio(text, voice, language, temperature, repetition_penalty,
|
||||
async for _ in response:
|
||||
pass
|
||||
|
||||
|
||||
async def generate_audio_internal(text, voice, language, temperature, repetition_penalty, output_file, streaming):
|
||||
global model
|
||||
global model, tts_stop_generation, tts_generation_lock
|
||||
tts_generation_lock = True
|
||||
if params["low_vram"] and device == "cpu":
|
||||
await switch_device()
|
||||
generate_start_time = time.time() # Record the start time of generating TTS
|
||||
@@ -539,6 +546,12 @@ async def generate_audio_internal(text, voice, language, temperature, repetition
|
||||
yield wav_buf.read()
|
||||
|
||||
for i, chunk in enumerate(output):
|
||||
if tts_stop_generation:
|
||||
print(f"[{params['branding']}TTSGen] Stopping audio generation.")
|
||||
file_chunks.clear() # Clear the file_chunks list
|
||||
tts_stop_generation = False
|
||||
tts_generation_lock = False
|
||||
break
|
||||
file_chunks.append(chunk)
|
||||
if isinstance(chunk, list):
|
||||
chunk = torch.cat(chunk, dim=0)
|
||||
@@ -547,6 +560,7 @@ async def generate_audio_internal(text, voice, language, temperature, repetition
|
||||
chunk = np.clip(chunk, -1, 1)
|
||||
chunk = (chunk * 32767).astype(np.int16)
|
||||
yield chunk.tobytes()
|
||||
print(f"[{params['branding']}Debug] Stream audio generation: Yielded audio chunk {i}.") if debug_generate_audio else None
|
||||
else:
|
||||
# Non-streaming-specific operation
|
||||
torchaudio.save(output_file, torch.tensor(output["wav"]).unsqueeze(0), 24000)
|
||||
@@ -565,9 +579,9 @@ async def generate_audio_internal(text, voice, language, temperature, repetition
|
||||
file_path=output_file,
|
||||
speaker_wav=[f"{this_dir}/voices/{voice}"],
|
||||
language=language,
|
||||
temperature=temperature,
|
||||
length_penalty=model.config.length_penalty,
|
||||
repetition_penalty=repetition_penalty,
|
||||
temperature=float(temperature),
|
||||
length_penalty=float(model.config.length_penalty),
|
||||
repetition_penalty=float(repetition_penalty),
|
||||
top_k=model.config.top_k,
|
||||
top_p=model.config.top_p,
|
||||
)
|
||||
@@ -589,12 +603,11 @@ async def generate_audio_internal(text, voice, language, temperature, repetition
|
||||
# Print Generation time and settings
|
||||
generate_end_time = time.time() # Record the end time to generate TTS
|
||||
generate_elapsed_time = generate_end_time - generate_start_time
|
||||
print(
|
||||
f"[{params['branding']}TTSGen] \033[93m{generate_elapsed_time:.2f} seconds. \033[94mLowVRAM: \033[33m{params['low_vram']} \033[94mDeepSpeed: \033[33m{params['deepspeed_activate']}\033[0m"
|
||||
)
|
||||
print(f"[{params['branding']}TTSGen] \033[93m{generate_elapsed_time:.2f} seconds. \033[94mLowVRAM: \033[33m{params['low_vram']} \033[94mDeepSpeed: \033[33m{params['deepspeed_activate']}\033[0m")
|
||||
# Move model back to cpu system ram if needed.
|
||||
if params["low_vram"] and device == "cuda":
|
||||
if params["low_vram"] and device == "cuda" and tts_narrator_generatingtts == False:
|
||||
await switch_device()
|
||||
tts_generation_lock = False
|
||||
return
|
||||
|
||||
|
||||
@@ -854,6 +867,13 @@ async def tts_generate_streaming(request: Request, text: str = Form(...), voice:
|
||||
print(f"An error occurred: {e}")
|
||||
return JSONResponse(content={"error": "An error occurred"}, status_code=500)
|
||||
|
||||
@app.put("/api/stop-generation")
|
||||
async def stop_generation_endpoint():
|
||||
global tts_stop_generation, tts_generation_lock
|
||||
if tts_generation_lock and not tts_stop_generation:
|
||||
tts_stop_generation = True
|
||||
return {"message": "Generation stopped"}
|
||||
|
||||
##############################
|
||||
#### Standard Generation ####
|
||||
##############################
|
||||
@@ -890,7 +910,7 @@ class JSONInput(BaseModel):
|
||||
narrator_enabled: bool = Field(..., description="narrator_enabled needs to be true or false.")
|
||||
narrator_voice_gen: str = Field(..., pattern="^.*\.wav$", description="narrator_voice_gen needs to be the name of a wav file e.g. mysample.wav.")
|
||||
text_not_inside: str = Field(..., pattern="^(character|narrator)$", description="text_not_inside needs to be 'character' or 'narrator'.")
|
||||
language: str = Field(..., pattern="^(ar|zh-cn|cs|nl|en|fr|de|hu|it|ja|ko|pl|pt|ru|es|tr)$", description="language needs to be one of the following ar|zh-cn|cs|nl|en|fr|de|hu|it|ja|ko|pl|pt|ru|es|tr.")
|
||||
language: str = Field(..., pattern="^(ar|zh-cn|cs|nl|en|fr|de|hu|hi|it|ja|ko|pl|pt|ru|es|tr)$", description="language needs to be one of the following ar|zh-cn|cs|nl|en|fr|de|hu|hi|it|ja|ko|pl|pt|ru|es|tr.")
|
||||
output_file_name: str = Field(..., pattern="^[a-zA-Z0-9_]+$", description="output_file_name needs to be the name without any special characters or file extension e.g. 'filename'")
|
||||
output_file_timestamp: bool = Field(..., description="output_file_timestamp needs to be true or false.")
|
||||
autoplay: bool = Field(..., description="autoplay needs to be a true or false value.")
|
||||
@@ -1029,12 +1049,17 @@ async def tts_generate(
|
||||
"autoplay_volume": autoplay_volume,
|
||||
"streaming": streaming,
|
||||
}
|
||||
global tts_narrator_generatingtts
|
||||
JSONresult = TTSGenerator.validate_json_input(json_input_data)
|
||||
if JSONresult is None:
|
||||
pass
|
||||
else:
|
||||
print(f"[{params['branding']}API] \033[91mError with API request:\033[0m", JSONresult)
|
||||
return JSONResponse(content={"error": JSONresult}, status_code=400)
|
||||
if narrator_enabled:
|
||||
if params["low_vram"] and device == "cpu":
|
||||
await switch_device()
|
||||
tts_narrator_generatingtts = True
|
||||
processed_parts = process_text(text_input)
|
||||
audio_files_all_paragraphs = []
|
||||
for part_type, part in processed_parts:
|
||||
@@ -1054,9 +1079,11 @@ async def tts_generate(
|
||||
voice_description = "\033[36mCharacter (Text-not-inside)\033[0m" if text_not_inside == "character" else "\033[92mNarrator (Text-not-inside)\033[0m"
|
||||
print(f"[{params['branding']}TTSGen] {voice_description}")
|
||||
# Replace multiple exclamation marks, question marks, or other punctuation with a single instance
|
||||
cleaned_part = re.sub(r'([!?.])\1+', r'\1', part)
|
||||
cleaned_part = re.sub(r'([!?.\u3002\uFF1F\uFF01\uFF0C])\1+', r'\1', part)
|
||||
# Replace "Chinese ellipsis" with a single dot
|
||||
cleaned_part = re.sub(r"\u2026{1,2}", ". ", cleaned_part)
|
||||
# Further clean to remove any other unwanted characters
|
||||
cleaned_part = re.sub(r'[^a-zA-Z0-9\s\.,;:!?\-\'"\u0400-\u04FFÀ-ÿ\u0150\u0151\u0170\u0171]\$', '', cleaned_part)
|
||||
cleaned_part = re.sub(r'[^a-zA-Z0-9\s.,;:!?\-\'"$\u0400-\u04FF\u00C0-\u00FF\u0150\u0151\u0170\u0171\u0900-\u097F\u2018\u2019\u201C\u201D\u3001\u3002\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF\uAC00-\uD7A3\u1100-\u11FF\u3130-\u318F\uFF01\uFF0c\uFF1A\uFF1B\uFF1F]', '', cleaned_part)
|
||||
# Remove all newline characters (single or multiple)
|
||||
cleaned_part = re.sub(r'\n+', ' ', cleaned_part)
|
||||
output_file = this_dir / "outputs" / f"{output_file_name}_{uuid.uuid4()}_{int(time.time())}.wav"
|
||||
@@ -1066,6 +1093,10 @@ async def tts_generate(
|
||||
audio_files_all_paragraphs.append(audio_path)
|
||||
# Combine audio files across paragraphs
|
||||
output_file_path, output_file_url, output_cache_url = combine(output_file_timestamp, output_file_name, audio_files_all_paragraphs)
|
||||
tts_narrator_generatingtts = False
|
||||
# Move model back to cpu system ram if needed.
|
||||
if params["low_vram"] and device == "cuda":
|
||||
await switch_device()
|
||||
else:
|
||||
if output_file_timestamp:
|
||||
timestamp = int(time.time())
|
||||
@@ -1085,15 +1116,19 @@ async def tts_generate(
|
||||
output_cache_url = f'http://{params["ip_address"]}:{params["port_number"]}/audiocache/{output_file_name}.wav'
|
||||
if text_filtering == "html":
|
||||
cleaned_string = html.unescape(standard_filtering(text_input))
|
||||
cleaned_string = re.sub(r'([!?.])\1+', r'\1', text_input)
|
||||
cleaned_string = re.sub(r'([!?.\u3002\uFF1F\uFF01\uFF0C])\1+', r'\1', text_input)
|
||||
# Replace "Chinese ellipsis" with a single dot
|
||||
cleaned_string = re.sub(r"\u2026{1,2}", ". ", cleaned_string)
|
||||
# Further clean to remove any other unwanted characters
|
||||
cleaned_string = re.sub(r'[^a-zA-Z0-9\s\.,;:!?\-\'"\u0400-\u04FFÀ-ÿ\u0150\u0151\u0170\u0171]\$', '', cleaned_string)
|
||||
cleaned_string = re.sub(r'[^a-zA-Z0-9\s.,;:!?\-\'"$\u0400-\u04FF\u00C0-\u00FF\u0150\u0151\u0170\u0171\u0900-\u097F\u2018\u2019\u201C\u201D\u3001\u3002\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF\uAC00-\uD7A3\u1100-\u11FF\u3130-\u318F\uFF01\uFF0c\uFF1A\uFF1B\uFF1F]', '', cleaned_string)
|
||||
# Remove all newline characters (single or multiple)
|
||||
cleaned_string = re.sub(r'\n+', ' ', cleaned_string)
|
||||
elif text_filtering == "standard":
|
||||
cleaned_string = re.sub(r'([!?.])\1+', r'\1', text_input)
|
||||
cleaned_string = re.sub(r'([!?.\u3002\uFF1F\uFF01\uFF0C])\1+', r'\1', text_input)
|
||||
# Replace "Chinese ellipsis" with a single dot
|
||||
cleaned_string = re.sub(r"\u2026{1,2}", ". ", cleaned_string)
|
||||
# Further clean to remove any other unwanted characters
|
||||
cleaned_string = re.sub(r'[^a-zA-Z0-9\s\.,;:!?\-\'"\u0400-\u04FFÀ-ÿ\u0150\u0151\u0170\u0171]\$', '', cleaned_string)
|
||||
cleaned_string = re.sub(r'[^a-zA-Z0-9\s.,;:!?\-\'"$\u0400-\u04FF\u00C0-\u00FF\u0150\u0151\u0170\u0171\u0900-\u097F\u2018\u2019\u201C\u201D\u3001\u3002\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF\uAC00-\uD7A3\u1100-\u11FF\u3130-\u318F\uFF01\uFF0c\uFF1A\uFF1B\uFF1F]', '', cleaned_string)
|
||||
# Remove all newline characters (single or multiple)
|
||||
cleaned_string = re.sub(r'\n+', ' ', cleaned_string)
|
||||
else:
|
||||
|
||||