From 2dd303f53c00211d2e76d0fbfa5c40412b7c629a Mon Sep 17 00:00:00 2001 From: erew123 <35898566+erew123@users.noreply.github.com> Date: Mon, 1 Jan 2024 18:10:14 +0000 Subject: [PATCH] Add files via upload --- script.py | 145 +- templates/TTS_Input_Proof_of_concept.html | 584 +++++++ templates/admin.html | 1791 +++++++++++++-------- tts_server.py | 212 ++- 4 files changed, 1918 insertions(+), 814 deletions(-) create mode 100644 templates/TTS_Input_Proof_of_concept.html diff --git a/script.py b/script.py index 3e6d98e..a3d6eab 100644 --- a/script.py +++ b/script.py @@ -509,11 +509,53 @@ def voice_preview(string): return f"[{params['branding']}Server] Audio generation failed. Status: {generate_response.get('status')}" -#def replace_asterisk(match): -# return match.group(0) + '"<*' +def process_text(text): + # Normalize HTML encoded quotes + text = html.unescape(text) -def replace_asterisk(match): - return '"<*' + # Replace ellipsis with a single dot + text = re.sub(r'\.{3,}', '.', text) + + # Pattern to identify combined narrator and character speech + combined_pattern = r'(\*[^*"]+\*|"[^"*]+")' + + # List to hold parts of speech along with their type + ordered_parts = [] + + # Track the start of the next segment + start = 0 + + # Find all matches + for match in re.finditer(combined_pattern, text): + # Add the text before the match, if any, as ambiguous + if start < match.start(): + ambiguous_text = text[start:match.start()].strip() + if ambiguous_text: + ordered_parts.append(('ambiguous', ambiguous_text)) + + # Add the matched part as either narrator or character + matched_text = match.group(0) + if matched_text.startswith('*') and matched_text.endswith('*'): + ordered_parts.append(('narrator', matched_text.strip('*').strip())) + elif matched_text.startswith('"') and matched_text.endswith('"'): + ordered_parts.append(('character', matched_text.strip('"').strip())) + else: + # In case of mixed or improperly formatted parts + if '*' in matched_text: + ordered_parts.append(('narrator', matched_text.strip('*').strip('"'))) + else: + ordered_parts.append(('character', matched_text.strip('"').strip('*'))) + + # Update the start of the next segment + start = match.end() + + # Add any remaining text after the last match as ambiguous + if start < len(text): + ambiguous_text = text[start:].strip() + if ambiguous_text: + ordered_parts.append(('ambiguous', ambiguous_text)) + + return ordered_parts ################################# #### TTS STANDARD GENERATION #### @@ -534,86 +576,55 @@ def output_modifier(string, state): if process_lock.acquire(blocking=False): try: if params["narrator_enabled"]: - # Do Some basic stripping and remove any double CR's - processed_string = ( - original_string - .replace("***", "*") - .replace("**", "*") - .replace("\n\n", "\n") - .replace("\n", "") - ) - processed_string = re.sub(r'\.\*\n\*', '. ', processed_string) - processed_string = (processed_string .replace('"\n\n*', '"<*')) - processed_string = (processed_string .replace('"\n', '< ')) - processed_string = (processed_string .replace("'", "'")) - processed_string = (processed_string .replace("\n", " ")) - processed_string = (processed_string .replace('"', '"<')) - processed_string = (processed_string .replace('"', '"<')) - #pattern = re.compile(r'(?<=[a-zA-Z!])"<(?=[a-zA-Z])') - pattern = re.compile(r'(?<=[a-zA-Z!?\.])"<(?=[a-zA-Z])') - processed_string = pattern.sub('" ', processed_string) - pattern = re.compile(r'(?<=[a-zA-Z])\*(?=[a-zA-Z])') - processed_string = pattern.sub('*"', processed_string) - processed_string = processed_string.replace('"<. *', '"< *"') - processed_string = processed_string.replace('< *"', '< *') - processed_string = processed_string.replace('. *', '< *') - processed_string = processed_string.replace('! *', '"< *') - processed_string = processed_string.replace('? *', '< *') - processed_string = processed_string.replace('* ', '* "<') - processed_string = processed_string.replace('*. ', '* "<') - processed_string = re.sub(r'\*(?=[a-zA-Z])', replace_asterisk, processed_string) - #print("PROCESSED STRING IS:", processed_string) - # Set up a tracking of the individual wav files. + processed_parts = process_text(original_string) + audio_files_all_paragraphs = [] - # Split the line using " and ".* " (so end of sentences, leaving special characters added to the start of all OTHER sentences, bar possibly the first one if its starting with a * - parts = re.split(r'"|\.\*', processed_string) - audio_files_paragraph = [] - for i, part in enumerate(parts): + for part_type, part in processed_parts: # Skip parts that are too short if len(part.strip()) <= 3: continue - # Figure out which type of line it is, then replace characters as necessary to avoid TTS trying to pronunce them, htmlunescape after. - # Character will always be a < with a letter immediately after it - #print("PART IS:", part) - if '<' in part and '< *' not in part and '<*' not in part and '< *' not in part and '< ' not in part and '< ' not in part: - cleaned_part = html.unescape(part.replace('<', '')) - voice_to_use = params["voice"] - #Narrator will always be an * or < with an * a position or two after it. - elif '<*' in part or '< *' in part or '< *' in part or '*' in part: - cleaned_part = html.unescape(part.replace('<*', '').replace('< *', '').replace('< *', '').replace('*', '')) + + # Determine the voice to use based on the part type + if part_type == 'narrator': voice_to_use = params["narrator_voice"] - #If the other two dont capture it, aka, the AI gave no * or " on the line, use non_quoted_text_is aka user interface, user can choose Char or Narrator - elif non_quoted_text_is: - #print("HIT ELIF CHAR VOICE") - cleaned_part = html.unescape(part.replace('< ', '').replace('< ', '').replace('< ', '')) + 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 else: - #print("HIT ELIF NARRATOR VOICE") - cleaned_part = html.unescape(part.replace('< ', '').replace('< ', '').replace('< ', '')) - voice_to_use = params["narrator_voice"] - # Generate that TTS and output to a file + # Handle ambiguous parts based on user preference + voice_to_use = params["voice"] if non_quoted_text_is else params["narrator_voice"] + voice_description = "\033[36mCharacter (Text-not-inside)\033[0m" if non_quoted_text_is 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) + # Further clean to remove any other unwanted characters + cleaned_part = re.sub(r'[^a-zA-Z0-9\s\.,;:!?\-\'"]', '', cleaned_part) + # Remove all newline characters (single or multiple) + cleaned_part = re.sub(r'\n+', ' ', cleaned_part) + + # Generate TTS and output to a file output_filename = get_output_filename(state) generate_response = send_generate_request( cleaned_part, voice_to_use, language_code, output_filename ) audio_path = generate_response.get("data", {}).get("audio_path") - audio_files_paragraph.append(audio_path) - # Accumulate audio files within the paragraph - audio_files_all_paragraphs.extend(audio_files_paragraph) + audio_files_all_paragraphs.append(audio_path) + # Combine audio files across paragraphs final_output_file = combine( audio_files_all_paragraphs, params["output_folder_wav"], state ) else: - processed_string = ( - original_string - .replace("***", "") - .replace("**", "") - .replace("*", "") - .replace("\n\n", "\n") - .replace("'", "'") - ) - cleaned_part = html.unescape(processed_string) + # Decode HTML entities first + cleaned_part = html.unescape(original_string) + # Replace multiple instances of certain punctuation marks with a single instance + cleaned_part = re.sub(r'([!?.])\1+', r'\1', cleaned_part) + # Further clean to remove any other unwanted characters + cleaned_part = re.sub(r'[^a-zA-Z0-9\s\.,;:!?\-\'"]', '', 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. if "character_menu" in state: output_file = Path(f'{params["output_folder_wav"]}/{state["character_menu"]}_{int(time.time())}.wav') diff --git a/templates/TTS_Input_Proof_of_concept.html b/templates/TTS_Input_Proof_of_concept.html new file mode 100644 index 0000000..0cb5333 --- /dev/null +++ b/templates/TTS_Input_Proof_of_concept.html @@ -0,0 +1,584 @@ + + + + + + + AllTalk TTS Generator + + + + +

AllTalk TTS Generator

+ +
+
+ + +
+ +
+ +
+ + +
+ +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+ + + 3 +
+ +
+ + + 0.8 +
+
+ + +
+ + + +
+ + +
+ + + + + + + + \ No newline at end of file diff --git a/templates/admin.html b/templates/admin.html index 02a756d..fbcfcf8 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -7,189 +7,212 @@ AllTalk TTS for Text generation webUI

AllTalk TTS for Text generation webUI

- +

Table of Contents

Getting Started

-

AllTalk is a web interface, based around the Coqui TTS voice cloning/speech generation system. To generate TTS, you can use the provided gradio interface or interact with the server using JSON/CURL commands. 

-

Note: When loading up a new character in Text generation webUI it may look like nothing is happening for 20-30 seconds. Its actually processing the introduction section (greeting message) of the text and once that is completed, it will appear. You can see the activity occuring in the console window. Refreshing the page multiple times will try force the TTS engine to keep re-generating the text, so please just wait and check the console if needed.

-

Note: Ensure that your RP character card has asterisks around anything for the narration and double quotes around anything spoken. There is a complication ONLY with the greeting card so, ensuring it has the correct use of quotes and asterisks will help make sure that the greeting card sounds correct. I will aim to address this issue in a future update. In Text-generation-webUI parameters menu > character tab > greeting make sure that anything in there that is the narrator is in asterisks and anything spoken is in double quotes, then hit the save (💾) button.

-

AllTalk Minor Bug Fixes Changelog & Known issues

-

If I squash any minor bugs or find any issues, I will try to apply an update asap. If you think something isnt working correctly or you have a problem, check these two links below first.

+

AllTalk is a web interface, based around the Coqui TTS voice + cloning/speech generation system. To generate TTS, you can use the provided gradio interface or interact with + the server using JSON/CURL commands. 

+

Note: When loading up a new + character in Text generation webUI it may look like nothing is happening for 20-30 seconds. Its actually + processing the introduction section (greeting message) of the text and once that is completed, it will appear. + You can see the activity occuring in the console window. Refreshing the page multiple times will try force the + TTS engine to keep re-generating the text, so please just wait and check the console if needed.

+

Note: Ensure that your RP + character card has asterisks around anything for the narration and double quotes around anything spoken. There + is a complication ONLY with the greeting card so, ensuring it has the correct use of quotes and asterisks will + help make sure that the greeting card sounds correct. I will aim to address this issue in a future update. In + Text-generation-webUI parameters menu > character tab > greeting make + sure that anything in there that is the narrator is in asterisks and anything spoken is in double quotes, then + hit the save (💾) button.

+

AllTalk Minor Bug Fixes Changelog & Known + issues

+

If I squash any minor bugs or find any issues, I will try to apply an update asap. If + you think something isnt working correctly or you have a problem, check these two links below first.

-

AllTalk
Github link here
Update instructions link here
Help and issues link here

Text generation webUI
Web interface link here
Documentation link here

+

AllTalk +
Github link + here
Update instructions link here
Help and issues link + here

Text generation webUI +
Web interface link + here
Documentation link here

Back to top of page

- +

Server Information

Back to top of page

@@ -242,7 +293,9 @@ - + - +