support both gtts and aws polly (we borrow from the streamlabs api) moved some configuration stuff around added one test method for creating file names, but it doesn't have any assertions, so it's useless added enums for different configuration properties like tts engine, file naming, and poly voices
99 lines
3.0 KiB
Python
99 lines
3.0 KiB
Python
import datetime
|
|
import hashlib
|
|
import os
|
|
|
|
import requests
|
|
from gtts import gTTS
|
|
from playsound import playsound
|
|
|
|
import config
|
|
|
|
streamLabsUrl = "https://streamlabs.com/polly/speak"
|
|
|
|
def tts(inputText: str, *args):
|
|
outpath = create_speech_file(inputText)
|
|
playsound(outpath)
|
|
|
|
|
|
def create_speech_gtts(input_text: str):
|
|
path = os.path.join(get_tts_dir(), create_file_name(input_text, "mp3"))
|
|
if not os.path.exists(path):
|
|
sound_digest = gTTS(text=input_text, lang='en')
|
|
sound_digest.save(path)
|
|
return path
|
|
|
|
|
|
def create_speech_streamlabs(text: str):
|
|
path = os.path.join(get_tts_dir(), create_file_name(text, "ogg"))
|
|
if not os.path.exists(path):
|
|
body = {"voice": config.streamlabsVoice.value, "text": text}
|
|
resp = requests.post(streamLabsUrl, data=body).json()
|
|
sound_file_url = resp["speak_url"]
|
|
if sound_file_url is not None:
|
|
sound_bytes = requests.get(sound_file_url, stream=True)
|
|
f = open(path, "+wb")
|
|
f.write(sound_bytes.content)
|
|
f.close()
|
|
return path
|
|
|
|
|
|
speechCreationFunctions = { # this is a mapping of the Speaker enum to function pointers
|
|
config.Speaker.STREAMLABS_API: create_speech_streamlabs,
|
|
config.Speaker.GOOGLE_TEXT_TO_SPEECH: create_speech_gtts
|
|
}
|
|
|
|
|
|
def create_speech_file(text: str):
|
|
text_creation_function = speechCreationFunctions.get(config.currentSpeaker)
|
|
output_path = text_creation_function(text)
|
|
return output_path
|
|
|
|
|
|
def create_file_name(text: str, ext: str):
|
|
"""
|
|
:param text: the content of the message. using the CONTENT_BASED FileNameStrategy, this will (ostensibly) produce a
|
|
unique file name based on the content of the message. Two messages of equal content will produce the same name
|
|
:param ext: the desired file extension i.e. mp3, ogg, wav, etc...
|
|
:return: returns the formatted filename i.e. 01-01-20_01-01-01_tts.mp3
|
|
"""
|
|
if config.fileNameStrategy == config.FileNameStrategy.CONTENT_BASED:
|
|
unique_id = hashlib.md5(bytes(text, 'utf-8')).hexdigest()
|
|
return "%s_tts.%s" % (unique_id, ext)
|
|
|
|
elif config.fileNameStrategy == config.FileNameStrategy.CONTENT_BASED:
|
|
time = datetime.datetime.now()
|
|
return "%s_tts.%s" % (time.strftime("%m-%d-%Y_%H-%M-%S"), ext)
|
|
|
|
else:
|
|
return "unconfigured_tts.%s" % ext
|
|
|
|
|
|
def play_speech(fileName):
|
|
destPath = get_tts_dir()
|
|
playsound(destPath + fileName)
|
|
|
|
|
|
def get_tts_dir():
|
|
"""
|
|
Checks for the tts directory, and will create it if it does not exist
|
|
:return: the relative file path of the tts dir
|
|
"""
|
|
dir = os.path.join(os.getcwd(), "tts") # this is platform-agnostic
|
|
if not os.path.exists(dir):
|
|
os.mkdir(dir)
|
|
return dir
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("Enter Text: ")
|
|
textInput = str(input())
|
|
print("Custom FileName? y/n: ")
|
|
bool_string = str(input())
|
|
|
|
if bool_string == "y":
|
|
print("Enter FileName: ")
|
|
fileName = str(input())
|
|
tts(textInput, fileName)
|
|
else:
|
|
tts(textInput)
|