From ff572702867a524095d2a4a10a176df8ca3fab90 Mon Sep 17 00:00:00 2001 From: erew123 <35898566+erew123@users.noreply.github.com> Date: Fri, 29 Dec 2023 09:53:02 +0000 Subject: [PATCH 1/9] Update README.md --- README.md | 81 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 3e728f2..28fa6fe 100644 --- a/README.md +++ b/README.md @@ -499,6 +499,64 @@ Deepspeed and other such things can be installed. Please read the relevant instr ### 🟠Overview The Text-to-Speech (TTS) Generation API allows you to generate speech from text input using various configuration options. This API supports both character and narrator voices, providing flexibility for creating dynamic and engaging audio content. +#### 🟠 Ready Endpoint
+Check if the Text-to-Speech (TTS) service is ready to accept requests. + +- URL: `http://127.0.0.1:7851/api/ready`
- Method: `GET`
- Response: `Ready` + + `curl -X GET "http://127.0.0.1:7851/api/ready"` + +#### 🟠 Voices List Endpoint
+Retrieve a list of available voices for generating speech. + +- URL: `http://127.0.0.1:7851/api/voices`
- Method: `GET`
+ + `curl -X GET "http://127.0.0.1:7851/api/voices"` + + JSON return: `{"voices": ["voice1.wav", "voice2.wav", "voice3.wav"]}` + +#### 🟠 Preview Voice Endpoint +Generate a preview of a specified voice with hardcoded settings. + +- URL: `http://127.0.0.1:7851/api/previewvoice/`
- Method: `POST`
- Content-Type: `application/x-www-form-urlencoded`
+ + `curl -X POST "http://127.0.0.1:7851/api/previewvoice/" -F "voice=female_01.wav"` + + Replace `female_01.wav` with the name of the voice sample you want to hear. + + JSON return: `{"status": "generate-success", "output_file_path": "/path/to/outputs/api_preview_voice.wav", "output_file_url": "http://127.0.0.1:7851/audio/api_preview_voice.wav"}` + +#### 🟠 Switching Model Endpoint
+ +- URL: `http://127.0.0.1:7851/api/reload`
- Method: `POST`

+ `curl -X POST "http://127.0.0.1:7851/api/reload?tts_method=API%20Local"`
+ `curl -X POST "http://127.0.0.1:7851/api/reload?tts_method=API%20TTS"`
+ `curl -X POST "http://127.0.0.1:7851/api/reload?tts_method=XTTSv2%20Local"`
+ + Switch between the 3 models respectively. + + JSON return `{"status": "model-success"}` + +#### 🟠 Switch DeepSpeed Endpoint
+ +- URL: `http://127.0.0.1:7851/api/deepspeed`
- Method: `POST`

+ `curl -X POST "http://127.0.0.1:7851/api/deepspeed?new_deepspeed_value=True"` + + Replace True with False to disable DeepSpeed mode. + + JSON return `{"status": "deepspeed-success"}` + +#### 🟠 Switching Low VRAM Endpoint
+ +- URL: `http://127.0.0.1:7851/api/lowvramsetting`
- Method: `POST`

+ `curl -X POST "http://127.0.0.1:7851/api/lowvramsetting?new_low_vram_value=True"` + + Replace True with False to disable Low VRAM mode. + + JSON return `{"status": "lowvram-success"}` + +### 🟠 TTS Generation Endpoint + - URL: `http://127.0.0.1:7851/api/tts-generate`
- Method: `POST`
- Content-Type: `application/x-www-form-urlencoded`
@@ -606,29 +664,6 @@ Example JSON TTS Generation Response: `{"status": "generate-success", "output_file_path": "C:\text-generation-webui\extensions\alltalk_tts\outputs\myoutputfile_1703149973.wav", "output_file_url": "http://127.0.0.1:7851/audio/myoutputfile_1703149973.wav"}` -🟠 **Switching Model**

-`curl -X POST "http://127.0.0.1:7851/api/reload?tts_method=API%20Local"`
-`curl -X POST "http://127.0.0.1:7851/api/reload?tts_method=API%20TTS"`
-`curl -X POST "http://127.0.0.1:7851/api/reload?tts_method=XTTSv2%20Local"`
- -Switch between the 3 models respectively. - -JSON return `{"status": "model-success"}` - -🟠 **Switch DeepSpeed**

-`curl -X POST "http://127.0.0.1:7851/api/deepspeed?new_deepspeed_value=True"` - -Replace True with False to disable DeepSpeed mode. - -JSON return `{"status": "deepspeed-success"}` - -🟠 **Switching Low VRAM**

-`curl -X POST "http://127.0.0.1:7851/api/lowvramsetting?new_low_vram_value=True"` - -Replace True with False to disable Low VRAM mode. - -JSON return `{"status": "lowvram-success"}` - ### πŸ”΄ Future to-do list - Voice output within the command prompt/terminal (TBD). - Correct a few spelling mistakes in the documentation. From 95659d5b7aecfdcb0d9e85ef7df997957a7945bb Mon Sep 17 00:00:00 2001 From: erew123 <35898566+erew123@users.noreply.github.com> Date: Fri, 29 Dec 2023 09:55:23 +0000 Subject: [PATCH 2/9] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 28fa6fe..984e573 100644 --- a/README.md +++ b/README.md @@ -557,9 +557,7 @@ Generate a preview of a specified voice with hardcoded settings. ### 🟠 TTS Generation Endpoint -- URL: `http://127.0.0.1:7851/api/tts-generate`
-- Method: `POST`
-- Content-Type: `application/x-www-form-urlencoded`
+- URL: `http://127.0.0.1:7851/api/tts-generate`
- Method: `POST`
- Content-Type: `application/x-www-form-urlencoded`
### 🟠 Example command lines Standard TTS speech Example (standard text) generating a time-stamped file
From 65e257077c7e44899cf94555bde952423e4e34a5 Mon Sep 17 00:00:00 2001 From: erew123 <35898566+erew123@users.noreply.github.com> Date: Fri, 29 Dec 2023 09:56:51 +0000 Subject: [PATCH 3/9] 3x new API endpoints /api/voices/ /api/previewvoice/ /api/ready/ --- tts_server.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tts_server.py b/tts_server.py index 61fb07b..6e3db2a 100644 --- a/tts_server.py +++ b/tts_server.py @@ -619,6 +619,53 @@ async def get_audio(filename: str): audio_path = this_dir / "outputs" / filename return FileResponse(audio_path) + +######################### +#### VOICES LIST API #### +######################### +# Define the new endpoint +@app.get("/api/voices") +async def get_voices(): + wav_files = list_files(this_dir / "voices") + return {"voices": wav_files} + +########################### +#### PREVIEW VOICE API #### +########################### +@app.post("/api/previewvoice/", response_class=JSONResponse) +async def preview_voice(request: Request, voice: str = Form(...)): + try: + # Hardcoded settings + language = "en" + output_file_name = "api_preview_voice" + + # Clean the voice filename for inclusion in the text + clean_voice_filename = re.sub(r'\.wav$', '', voice.replace(' ', '_')) + clean_voice_filename = re.sub(r'[^a-zA-Z0-9]', ' ', clean_voice_filename) + + # Generate the audio + text = f"Hello, this is a preview of voice {clean_voice_filename}." + + # Generate the audio + output_file_path = this_dir / "outputs" / f"{output_file_name}.wav" + await generate_audio(text, voice, language, output_file_path) + + # Generate the URL + output_file_url = f'http://{params["ip_address"]}:{params["port_number"]}/audio/{output_file_name}.wav' + + # Return the response with both local file path and URL + return JSONResponse( + content={ + "status": "generate-success", + "output_file_path": str(output_file_path), + "output_file_url": str(output_file_url), + }, + status_code=200, + ) + except Exception as e: + print(f"An error occurred: {e}") + return JSONResponse(content={"error": "An error occurred"}, status_code=500) + ######################## #### GENERATION API #### ######################## @@ -1717,10 +1764,20 @@ template = Template(simple_webpage) # Render the template with the dynamic values rendered_html = template.render(params=params) +############################### +#### Internal script ready #### +############################### @app.get("/ready") async def ready(): return Response("Ready endpoint") +############################ +#### External API ready #### +############################ +@app.get("/api/ready") +async def ready(): + return Response("Ready") + @app.get("/") async def read_root(): return HTMLResponse(content=rendered_html, status_code=200) From e81a88938a2208478ac12347ec1f941651c16eb2 Mon Sep 17 00:00:00 2001 From: erew123 <35898566+erew123@users.noreply.github.com> Date: Fri, 29 Dec 2023 10:11:01 +0000 Subject: [PATCH 4/9] Completed built-in documentation update For the new API endpoints --- tts_server.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tts_server.py b/tts_server.py index 6e3db2a..c92b87d 100644 --- a/tts_server.py +++ b/tts_server.py @@ -1720,6 +1720,33 @@ simple_webpage = """

curl -X POST "http://127.0.0.1:7851/api/lowvramsetting?new_low_vram_value=True"

Replace True with False to disable Low VRAM mode.

JSON return {"status": "lowvram-success"}

+

Ready Endpoint

+

Check if the Text-to-Speech (TTS) service is ready to accept requests.

+ +

curl -X GET "http://127.0.0.1:7851/api/ready"

+

Voices List Endpoint

+

Retrieve a list of available voices for generating speech.

+ +

curl -X GET "http://127.0.0.1:7851/api/voices"

+

JSON return: {"voices": ["voice1.wav", "voice2.wav", "voice3.wav"]}

+

Preview Voice Endpoint

+

Generate a preview of a specified voice with hardcoded settings.

+ +

curl -X POST "http://127.0.0.1:7851/api/previewvoice/" -F "voice=female_01.wav"

+

Replace female_01.wav with the name of the voice sample you want to hear.

+

JSON return: {"status": "generate-success", "output_file_path": "/path/to/outputs/api_preview_voice.wav", "output_file_url": "http://127.0.0.1:7851/audio/api_preview_voice.wav"}

+

Back to top of page

Debugging and TTS Generation Information

From 221efbddb49a537b371c6c04c2c98dfcdf0e4738 Mon Sep 17 00:00:00 2001 From: erew123 <35898566+erew123@users.noreply.github.com> Date: Fri, 29 Dec 2023 10:42:35 +0000 Subject: [PATCH 5/9] Supports playback at the command line prompt Added sounddevice as its currently well supported. Allows playback at the terminal/command prompt. Added speakers_xtts.pth to the modeldownload.json as it will be needed for finetuning in future updates of TTS 0.22.0+ --- modeldownload.json | 3 ++- requirements_nvidia.txt | 1 + requirements_other.txt | 1 + tts_server.py | 8 ++++++++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/modeldownload.json b/modeldownload.json index 76afdcd..d18ab27 100644 --- a/modeldownload.json +++ b/modeldownload.json @@ -8,6 +8,7 @@ "model.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/model.pth?download=true", "dvae.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/dvae.pth?download=true", "mel_stats.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/mel_stats.pth?download=true", + "speakers_xtts.pth": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/speakers_xtts.pth?download=true", "vocab.json": "https://huggingface.co/coqui/XTTS-v2/resolve/v2.0.2/vocab.json?download=true" } -} +} \ No newline at end of file diff --git a/requirements_nvidia.txt b/requirements_nvidia.txt index 82579fd..ef574c4 100644 --- a/requirements_nvidia.txt +++ b/requirements_nvidia.txt @@ -11,3 +11,4 @@ tqdm>=4.66.1 importlib-metadata>=4.8.1 packaging>=23.2 pydantic>=1.10.13 +sounddevice>=0.4.6 diff --git a/requirements_other.txt b/requirements_other.txt index aad8a62..8bc9597 100644 --- a/requirements_other.txt +++ b/requirements_other.txt @@ -11,3 +11,4 @@ tqdm>=4.66.1 importlib-metadata>=4.8.1 packaging>=23.2 pydantic>=1.10.13 +sounddevice>=0.4.6 diff --git a/tts_server.py b/tts_server.py index c92b87d..95cd725 100644 --- a/tts_server.py +++ b/tts_server.py @@ -674,9 +674,15 @@ import re import uuid import numpy as np import soundfile as sf +import sounddevice as sd from typing import Union, Dict from pydantic import BaseModel, ValidationError, Field +def play_audio(file_path, volume): + data, fs = sf.read(file_path) + sd.play(volume * data, fs) + sd.wait() + class Request(BaseModel): # Define the structure of the 'Request' class if needed pass @@ -874,6 +880,8 @@ async def tts_generate( else: cleaned_string = text_input await generate_audio(cleaned_string, character_voice_gen, language, output_file_path) + if autoplay: + play_audio(output_file_path, autoplay_volume) return JSONResponse(content={"status": "generate-success", "output_file_path": str(output_file_path), "output_file_url": str(output_file_url)}, status_code=200) except Exception as e: return JSONResponse(content={"status": "generate-failure", "error": "An error occurred"}, status_code=500) From 06a632459e1463e8ddd452b7d4fe945ed7221576 Mon Sep 17 00:00:00 2001 From: erew123 <35898566+erew123@users.noreply.github.com> Date: Fri, 29 Dec 2023 10:44:39 +0000 Subject: [PATCH 6/9] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 984e573..89a6778 100644 --- a/README.md +++ b/README.md @@ -642,12 +642,12 @@ Example: `-d "output_file_timestamp=true"`
`-d "output_file_timestamp=false"` -🟠 **autoplay**: Feature not yet available. Enable or disable autoplay. Still needs to be specified in the JSON request. +🟠 **autoplay**: Enable or disable playing the generated TTS to your standard sound output device at time of TTS generation. `-d "autoplay=true"`
`-d "autoplay=false"` -🟠 **autoplay_volume**: Feature not yet available. Set the autoplay volume. Should be between 0.1 and 1.0. Still needs to be specified in the JSON request. +🟠 **autoplay_volume**: Set the autoplay volume. Should be between 0.1 and 1.0. Needs to be specified in the JSON request even if autoplay is false. `-d "autoplay_volume=0.8"` From aeb225ec7cef6c5c2611d3865a422b9bccf26fb4 Mon Sep 17 00:00:00 2001 From: erew123 <35898566+erew123@users.noreply.github.com> Date: Fri, 29 Dec 2023 10:51:06 +0000 Subject: [PATCH 7/9] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 89a6778..fc6801b 100644 --- a/README.md +++ b/README.md @@ -502,10 +502,12 @@ The Text-to-Speech (TTS) Generation API allows you to generate speech from text #### 🟠 Ready Endpoint
Check if the Text-to-Speech (TTS) service is ready to accept requests. -- URL: `http://127.0.0.1:7851/api/ready`
- Method: `GET`
- Response: `Ready` +- URL: `http://127.0.0.1:7851/api/ready`
- Method: `GET`
`curl -X GET "http://127.0.0.1:7851/api/ready"` + Response: `Ready` + #### 🟠 Voices List Endpoint
Retrieve a list of available voices for generating speech. From bb028af69464224a05fb7a728b7267ca41a181be Mon Sep 17 00:00:00 2001 From: erew123 <35898566+erew123@users.noreply.github.com> Date: Fri, 29 Dec 2023 10:54:02 +0000 Subject: [PATCH 8/9] Update README.md --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index fc6801b..6fd8e55 100644 --- a/README.md +++ b/README.md @@ -616,22 +616,22 @@ Example: 🟠 **language**: Choose the language for TTS. Options: -`ar Arabic`
-`zh-cn Chinese (Simplified)`
-`cs Czech`
-`nl Dutch`
-`en English`
-`fr French`
-`de German`
-`hu Hungarian`
-`it Italian`
-`ja Japanese`
-`ko Korean`
-`pl Polish`
-`pt Portuguese`
-`ru Russian`
-`es Spanish`
-`tr Turkish`
+`ar` Arabic
+`zh-cn` Chinese (Simplified)
+`cs` Czech
+`nl` Dutch
+`en` English
+`fr` French
+`de` German
+`hu` Hungarian
+`it` Italian
+`ja` Japanese
+`ko` Korean
+`pl` Polish
+`pt` Portuguese
+`ru` Russian
+`es` Spanish
+`tr` Turkish
`-d "language=en"`
From a094d4f9dac7f57ad1eb54190a562fd2972ad96d Mon Sep 17 00:00:00 2001 From: erew123 <35898566+erew123@users.noreply.github.com> Date: Fri, 29 Dec 2023 20:25:08 +0000 Subject: [PATCH 9/9] Completed autoplay at command line Added additional requirement. Lowered the repetition on the start-up warning when its taking a while for the model to load. --- requirements_nvidia.txt | 1 + requirements_other.txt | 1 + script.py | 4 ++-- tts_server.py | 18 +++++++++++++++++- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/requirements_nvidia.txt b/requirements_nvidia.txt index ef574c4..b8d22e9 100644 --- a/requirements_nvidia.txt +++ b/requirements_nvidia.txt @@ -12,3 +12,4 @@ importlib-metadata>=4.8.1 packaging>=23.2 pydantic>=1.10.13 sounddevice>=0.4.6 +python-multipart>=0.0.6 diff --git a/requirements_other.txt b/requirements_other.txt index 8bc9597..6566ced 100644 --- a/requirements_other.txt +++ b/requirements_other.txt @@ -12,3 +12,4 @@ importlib-metadata>=4.8.1 packaging>=23.2 pydantic>=1.10.13 sounddevice>=0.4.6 +python-multipart>=0.0.6 diff --git a/script.py b/script.py index 30eb714..38bac24 100644 --- a/script.py +++ b/script.py @@ -252,7 +252,7 @@ else: timeout = 120 # Adjust the timeout as needed # Introduce a delay before starting the check loop -time.sleep(25) # Wait 25 secs before checking if the tts_server.py has started up. +time.sleep(26) # Wait 26 secs before checking if the tts_server.py has started up. start_time = time.time() while time.time() - start_time < timeout: try: @@ -264,7 +264,7 @@ while time.time() - start_time < timeout: print( f"[{params['branding']}Startup] \033[91mWarning\033[0m TTS Subprocess has NOT started up yet, Will keep trying for 120 seconds maximum. Please wait." ) - time.sleep(1) + time.sleep(4) else: print( f"[{params['branding']}Startup] Startup timed out. Check the server logs for more information." diff --git a/tts_server.py b/tts_server.py index 95cd725..57ac453 100644 --- a/tts_server.py +++ b/tts_server.py @@ -674,7 +674,21 @@ import re import uuid import numpy as np import soundfile as sf -import sounddevice as sd +import sys + +# Check for PortAudio library on Linux +try: + import sounddevice as sd + sounddevice_installed=True +except OSError: + print(f"[{params['branding']}Startup] \033[91mInfo\033[0m PortAudio library not found. If you wish to play TTS in standalone mode through the API suite") + print(f"[{params['branding']}Startup] \033[91mInfo\033[0m please install PortAudio. This will not affect any other features or use of Alltalk.") + print(f"[{params['branding']}Startup] \033[91mInfo\033[0m If you don't know what the API suite is, then this message is nothing to worry about.") + sounddevice_installed=False + if sys.platform.startswith('linux'): + print(f"[{params['branding']}Startup] \033[91mInfo\033[0m On Linux, you can use the following command to install PortAudio:") + print(f"[{params['branding']}Startup] \033[91mInfo\033[0m sudo apt-get install portaudio19-dev") + from typing import Union, Dict from pydantic import BaseModel, ValidationError, Field @@ -880,6 +894,8 @@ async def tts_generate( else: cleaned_string = text_input await generate_audio(cleaned_string, character_voice_gen, language, output_file_path) + if sounddevice_installed == False: + autoplay = False if autoplay: play_audio(output_file_path, autoplay_volume) return JSONResponse(content={"status": "generate-success", "output_file_path": str(output_file_path), "output_file_url": str(output_file_url)}, status_code=200)