From e3b8cebb9cfb7909385a061c2b446ade94e05b0e Mon Sep 17 00:00:00 2001 From: Dakkaron Date: Wed, 30 Dec 2020 12:04:30 +0100 Subject: [PATCH] Added Amazon Polly TTS generation script --- polly.py | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 polly.py diff --git a/polly.py b/polly.py new file mode 100644 index 00000000..df5809a9 --- /dev/null +++ b/polly.py @@ -0,0 +1,101 @@ +import sys +import os +import xml.etree.ElementTree +import re +import json +import hashlib +try: + import boto3 +except: + print('Could not import boto3. Please install it using "pip3 install boto3"') + +if len(sys.argv)!=2: + print("Usage: python3 polly.py [input file]") +xmlFile = sys.argv[1] + +with open(xmlFile, "r") as f: + xmlRaw = "\n"+f.read()+"\n" + +try: + with open(xmlFile[:-4]+".pollycache.json", "r") as f: + fileCache = json.loads(f.read()) +except: + fileCache = {} + print("Could not open file cache, recreating all files over Polly.") + +if not "files" in fileCache: + fileCache["files"] = {} + + +def startPolly(awsAccessKeyId, awsSecretAccessKey): + pollyClient = boto3.Session( + aws_access_key_id=awsAccessKeyId, + aws_secret_access_key=awsSecretAccessKey, + region_name="eu-central-1").client("polly") + try: + response = pollyClient.synthesize_speech(VoiceId="Joanna",OutputFormat="ogg_vorbis",Text="") + except: + print("Error: Invalid credentials!") + raise + return False + return pollyClient + +def saveFileCache(): + global xmlFile + with open(xmlFile[:-4]+".pollycache.json", "w") as f: + f.write(json.dumps(fileCache)) + +if "awsAccessKeyId" not in fileCache or "awsSecretAccessKey" not in fileCache: + awsAccessKeyId = input("Amazon AWS Access Key ID: ") + awsSecretAccessKey = input("Amazon AWS Access Secret Key: ") + print("Testing access") + pollyClient = startPolly(awsAccessKeyId, awsSecretAccessKey) + if not pollyClient: + exit(1) + print("Credentials are working.") + if (input("Do you want me to save those credentials? [y/N] ").lower() == "y"): + fileCache["awsAccessKeyId"] = awsAccessKeyId + fileCache["awsSecretAccessKey"] = awsSecretAccessKey + print("Saving credentials") + saveFileCache() + else: + print("Not saving credentials") +else: + print("Found stored AWS credentials") + print("Testing access") + pollyClient = startPolly(fileCache["awsAccessKeyId"], fileCache["awsSecretAccessKey"]) + if not pollyClient: + print("Deleting stored credentials") + del fileCache["awsAccessKeyId"] + del fileCache["awsSecretAccessKey"] + saveFileCache() + print("Please restart the program.") + exit(1) + +xml.etree.ElementTree.register_namespace("amazon", "http://www.amazon.com") +root = xml.etree.ElementTree.fromstring(xmlRaw) + +for polly in root: + fileName = polly.attrib["file"] + voice = polly.attrib["voice"] + content = xml.etree.ElementTree.tostring(polly[0]).decode("utf-8").strip() + content = re.sub("^", "", content) + contentMd5 = hashlib.md5(content.encode("utf-8")).hexdigest() + + if (contentMd5 != fileCache["files"].get(fileName, {}).get("contentMd5","")) or \ + (not os.path.exists(fileName)) or \ + (hashlib.md5(open(fileName,'rb').read()).hexdigest() != fileCache["files"].get(fileName, {}).get("fileMd5","")): + + print("Generating "+fileName) + response = pollyClient.synthesize_speech(VoiceId=voice,OutputFormat="ogg_vorbis",TextType="ssml",Text=content) + + with open(fileName, "wb") as f: + f.write(response['AudioStream'].read()) + + fileCache["files"][fileName] = { + "contentMd5": contentMd5, + "fileMd5": hashlib.md5(open(fileName,'rb').read()).hexdigest(), + } + saveFileCache() + else: + print("File "+fileName+" does not need to be generated.")