Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion python/aws-sandbox/.gitignore

This file was deleted.

20 changes: 0 additions & 20 deletions python/aws-sandbox/polly.py

This file was deleted.

Binary file not shown.
Binary file not shown.
Binary file not shown.
15 changes: 8 additions & 7 deletions python/text-to-speech/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# Third party
import requests
from google.cloud import texttospeech
import azure.cognitiveservices.speech as speechsdk
# import azure.cognitiveservices.speech as speechsdk
import boto3


Expand Down Expand Up @@ -141,9 +141,9 @@ def validate_request(self, req: requests) -> None:
Raises:
ValueError: If any required value is missing or invalid.
"""
if not req.payload.get("API_KEY"):
if not req.variables.get("API_KEY"):
raise ValueError("Missing API_KEY.")
if not req.payload.get("SECRET_API_KEY"):
if not req.variables.get("SECRET_API_KEY"):
raise ValueError("Missing SECRET_API_KEY.")
self.api_key = req.payload.get("API_KEY")
self.secret_api_key = req.payload.get("SECRET_API_KEY")
Expand Down Expand Up @@ -172,7 +172,7 @@ def speech(self, text: str, language: str) -> bytes:
Text=text,
LanguageCode=language
)
return response["Audiostream"].read()
return response["Audiostream"]


list_of_providers = ["google", "azure", "aws"]
Expand All @@ -195,7 +195,7 @@ def validate_common(req: requests) -> tuple:
"""
# Check if the payload is empty.
if not req.payload:
raise ValueError("Missing payload")
raise ValueError("Missing Payload.")

# Check if variables is empty.
if not req.variables:
Expand All @@ -206,7 +206,7 @@ def validate_common(req: requests) -> tuple:
raise ValueError("Missing Provider.")

# Check if provider is in the list
if req.payload.get("provider").lower not in list_of_providers:
if (req.payload.get("provider").lower() not in list_of_providers):
raise ValueError("Invalid Provider.")

# Check if text is empty.
Expand All @@ -221,8 +221,9 @@ def validate_common(req: requests) -> tuple:
return (req.payload.get("provider").lower(),
req.payload.get("text"), req.payload.get("language"))


# print("google".lower() not in list_of_providers)
def main(req: requests, res: json) -> json:

"""
Main Function for Text to Speech.

Expand Down
2 changes: 1 addition & 1 deletion python/text-to-speech/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
boto3==1.28.9
azure-cognitiveservices-speech==1.24.0
google-cloud-texttospeech==2.14.1
# azure-cognitiveservices-speech==1.30.0
parameterized==0.9.0
1 change: 1 addition & 0 deletions python/text-to-speech/results/aws.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//NExAASoAEkAUAAAXwGQ/p/gDhGY/4fADM/x/ADAzMfwfAM6/o/AyB+Y/N4A7pkc+A7AyOeH/AMwZD/0+A4P8/4DgDo/4fADo/w/gBgZ4f4/AR63R+AhfA81AUf47wD//NExAgUiyowAZNoAIHidDXtgtAXBH/EmB2CZkr/4WsZZff/+tOHPLw8P/8S8Yc3RN3Hp//+XEEXQNzM3////qNHMzcwLiCac0/////zM3bWncwNC+boKhAsSKDAV90A//NExAgS4cKcAYNQAM+vABFdTDxmRCqimDwaEZaIkBAUgNs/NLnbGEhMNPzrVIFPvJm/ONfYwkE+Ri5l/+Y11WLnAAXV+n6HjBQmc//+tLaagQESJOt3hyTZiQnjMvw6//NExA8TMWKoAc9IAFYEPV3dawoSzDBkasnJWCooQpTjVuz/P9/zz/3/fWQ/j3LQPH1nZe+++0EQcPlKrkoFWGBCMftpbLOTvFRagKXtjORQvVLmEjQcfnk70D7pU44b//NExBUWuTagAMvMcDtwm6jSR/sJNlQTAxWVzG+QdAJrAomaWUlU/yzNX+T3z//9m1medMBsUYkgeGBEYgFAbSFGO0OOAuQiizvfUOD0uoe6fx3u7JlQ3nZYLMs3UOao//NExA0VgWawAMYMlKw4YVjA12JJyT0fBI0uKzxl83MlCXgQieqwO2nyudv6pLP4Um/zt4973h+2fx+9/T03XRCSZPHJp1AIMjsoo0EPtWz/2F3AQwrvLoMXLesIVzrT//NExAoU8W60AMYQlCR77CH4FFF5QIEOLk6ALq4t1JeV0sKALV+zDpq9luT6/3VHl9Bz/sfzfp8L9+8XBrYdg8DUkB5lUJpkSKowQzVc3A1nctiP/xwx39CitfwVQwyz//NExAkSEVq8AMPMlGLWpsVa02Kdgz46LEOgRyRwm07wNAY0rsvMVTqaNSaNaBLqk1fdtfX/////d23VmoGgthZ1zc1CLJHC5Iwd+lXFogOmaGSeL2E8uLOd1kyECQp+//NExBMRIVK8AHvMlQ+zheivslKjEZU+DDLC2nWswY8a943vjWr43vb43b//vrM9MTpIBgqBA2uf6V1A6h+l3xIBQ8u7JU/BYnzwQGKPgGCQmpwHEcgkLWpzrH6vjRP4//NExCESeWa4AHvKlIeQc2jrfKlxfzTyRZtbrjOldd1/qlHFhpzCYsLsGi1GMPMokZxSeu/S3QHENVuJbVvNaxfC+qgvg1lYykKqXQlx/F4LkujlMU41Cca2Jqc4mA8q//NExCoQqS64AHvOcXi00oapjnJtRf/3Z0UdID4lF2jRXMIZNY3dcKxY4X0aFLncnn0n3LFmGErC9H2iDBLYrRNR/k9KxHHyrTdblCaBtgNCwYDxoh5Io7nL6O/+iW9R//NExDoSESasAMPOcKoPBwiJnnR4YDa///9iVbijphYgkTSaw1ltIChmtbtuzeBsrOSMQDMEwSHw4TiQwJKIqCMTAyENltitougYm95rITet3eZC3DO8SlmflZhSkg+c//NExEQSKVqkAMMElP9P//yq0quA2ohqww/Sw/UlkPxyOUTAkojm5Hgotq1QQFREOmA2uC/BAyCQPl0IJhsL6jyfheXFO5y8v7r7J02CGmoQLHQ2FHtO0////JC9kpDN//NExE4SqRakAMPScCRKAx25MZxaO1owbRoARBXA0NBUDMCC2kWrKyUXIVSDBKAoH4FC70CiFfHJt1BiN05fARmQVcPdKkv////91iPR/qXoEElSkhA0OySG4jFK0yWH//NExFYRYPagAMJScMyF0JMIDZKabcwpclYV40vrriFJiUA6fKsmuIzlQulz27tnbT7qFaOoHLmUBUjQKX////zPbSrEypUxIgujlFb0Tuy9/C+lWcqAYWnLdWNI/kta//NExGMRmQqcAMJYcLnXtaUtjdQNLSbQWGdFmSN5azCHw74RtZxtSY4yJlAYIgdH////Q7///0V+DkRhYkxqkghyLSmH5lyn/hxaroW4NooZzz1+HbM/s8/8bV+1eCpd//NExG8RqRKYAMPScOeDQBSwJiwJAqPhVEySSHCAUpszVSn2xcMjCRUBHTVn////pvX29P+UPPDM4HNw/TEZVLxQGpgXdRNjmgcfaU02He+SJPJVIcJhz54mlxax8Lmp//NExHsUQR6QAVhIACczCuCXAKIZYXQTwE/AgKzIyWcF8DOBGi6J6MMLQXygkPUexk7VLMiEamwww9lj2JUpGxK0tfmrLrSqrQuzf/91oqN0klHupa0Eta//1MnP9kTY//NExH0hEqJ4AZpoAdb/bIFpG9ZVgkPqlevVgL5Om9klcaBqFjLNI5RxmxKalnDHdnn/tMvtZtMc5Nevu7ekBeYHYRUIxFqupOqVicgAsbol8L5rXO29ad0wct7aU91A//NExEsbMWoUAdhgAGtcIFUxp9qDKHvUTbKkhEQJE6mXVi1Jo8oDXLJJUKKYp61BEa1KIwLTSqjjMMxqmrTCrDVCpUKoHway4xry8rjHfHNj8lKcSElSCwqRKCoVPQoc//NExDEYwUYAAMJScJaWBIEg0TJiklrylcY+TSjxUioGn15INPLA1iIeCrhMDT+uIpGdeInnmDXM5Iqtj6gaCYhmCuKPnnWWtyq4hGg+XJD7LTKIhLHF2NyeSiqtdXJV//NExCESkbWMAGJElCTXhrOxioh2//oq/KiqjtuUyKn/3KGBgwTMmQEK/xUW/+Kijf6haoWFVUxBTTXYUNNntBQ28i7Tc/GCN14Jo3UyUTcUPONmtTU0xF9lFfBVi5jj//NExCkAAANIAAAAAF5UP5IJoGgaCohx+SxSiw7F3fQXPuixe0kFAeGFnkGIji9wn/yWLDv6Abn5/oiIiIn//T4iJXcO9dw4GLeaF13d3Qrz+Cw8PH+8/4AH8AQnAABH//NExHwAAANIAAAAAIAYe072jOCP8zxCBSiPGaUSFnSoXydOnhkDLKzVx9ejtbWzWtGjkgVKZkCDo6C/j/4q5LBRR++nDZYbjvm2VZFRfG7hdWSy/Oacyi/v//lRJuX+//NExMwH4CQAAPe8AEuqxZZf4+F5V3m/Kb/6/GoAqLBUhFduI/76O27EYo8cL+NGlM7PUnCRQo8y4djSij4dpOEgQEfDtqiL/9nKinb5TBlI7OVP/+YoYGDIfULC4rFR//NExP8Y6f3sAHoGmVEj//rFcVFjVbP4qKcWTEFNRTMuMTAwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//NExO4V0LIAAHpMTaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//NExOkUQbmYAMGElKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
20 changes: 20 additions & 0 deletions python/text-to-speech/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import main
import test_main
import secret

req = test_main.MyRequest({
"payload": {
"provider": "google",
"text": "hi",
"language": "en-US",
},
"variables": {
"API_KEY": secret.GOOGLE_API_KEY,
"PROJECT_ID": secret.GOOGLE_PROJECT_ID,
}
})

res = test_main.MyResponse()

main.main(req, res)
print(res.json())
106 changes: 59 additions & 47 deletions python/text-to-speech/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,23 @@
import requests
from parameterized import parameterized
from google.cloud import texttospeech
import boto3

# Local imports
import main

RESULT_GOOGLE = (
pathlib.Path("python/text-to-speech/results/google.txt").
pathlib.Path("results/google.txt").
read_text(encoding="utf-8"))

# Path to krakenio encoded result (str).
RESULT_AZURE = (
pathlib.Path("python/text-to-speech/results/azure.txt").
pathlib.Path("results/azure.txt").
read_text(encoding="utf-8"))

RESULT_AWS = (
pathlib.Path("results/aws.txt").
read_text(encoding="utf-8"))

def get_instance(provider, key, project_id):
IMPLEMENTATIONS = {
Expand Down Expand Up @@ -143,71 +147,79 @@ def test_speech_key_exception(self, text, language):

class AWSTest(unittest.TestCase):
"""AWS API Test Cases"""
def test_validate_request(self, req):
"""Test validate_request method when all required fields are present."""
pass

def test_validate_request_missing_aws_access_key_id(self, req):
"""Test validate_request method when 'AWS_ACCESS_KEY_ID' is missing."""
pass

def test_validate_request_missing_aws_secret_access_key(self, req):
"""Test validate_request method when 'AWS_SECRET_ACCESS_KEY' is missing."""
pass

def test_speech(self):
"""Test speech method for successful text-to-speech synthesis."""
def get_instance(self, key, secret_key):
req = MyRequest({
"payload": {
"provider": "aws",
"text": "hi",
"language": "en-US",
},
"variables": {
"API_KEY": "123",
"PROJECT_ID": "123",
"API_KEY": key,
"SECRET_API_KEY": secret_key,
}
})
# Create an instance of Google Class
aws_instance = main.AWS(req)
# Variables
text = "hello"
language = "en-US"
# Set up mock
with patch.object(texttospeech, "TextToSpeechClient") as mock_client:
mock_response = mock_client.return_value
mock_response.synthesize_speech.return_value.audio_content = base64.b64decode("RESULT_AWS")

# Call the speech method
audio_stream = aws_instance.speech(text, language)

# Assert that the mock client was called with the correct arguments
mock_client.assert_called_once_with(client_options={"api_key": "123", "secret_api_key": "123"})
return main.AWS(req)

# Assert that the synthesize_speech method was called with the correct arguments
mock_response.synthesize_speech.assert_called_once_with(VoiceId="Joanna", OutputFormat="mp3", Text=text, LanguageCode=language)
@parameterized.expand([
(None, "123"), # Missing API KEY
("123", None), # Missing SECRET API KEY
(None, None), # Missing Both
])
def test_validate_request(self, key, secret_key):
self.assertRaises(ValueError, self.get_instance, key, secret_key)

def test_speech_happy(self):
"""Test speech method for successful text-to-speech synthesis."""
instance = self.get_instance("123", "123")
# Set up mock
with patch.object(boto3.Session, "client") as mock_client:
mock_response = {"Audiostream": base64.b64decode(RESULT_AWS)}
mock_client.return_value.synthesize_speech.return_value = mock_response
got = instance.speech("hi", "en-US")
want = base64.b64decode(RESULT_AWS)
# Assert the result
self.assertEqual(audio_stream, base64.b64decode("RESULT_AWS"))
self.assertEqual(got, want)

def test_speech_key_exception(self, text, language):
def test_speech_key_exception(self):
"""Test speech method for handling exceptions during text-to-speech synthesis."""
pass
instance = self.get_instance("123", "123")
self.assertRaises(Exception, instance.speech, "hi", "en-US")


class ValidateCommonTest(unittest.TestCase):
"""Test Cases for validate_common function"""
def test_validate_common(self, req):
"""Test validate_common function with valid input."""
pass
def get_req(self, payload, variables, provider, text, language):
return MyRequest({
payload: {
"provider": provider,
"text": text,
"language": language,
},
variables: {
"key": "123",
}
})

def test_missing_text(self, req):
"""Test validate_common function when 'text' is missing."""
pass
def test_validate_common_happy(self):
"""Test validate common method happy path."""
want = ("google", "hi", "en-US")
req = self.get_req("payload", "variables", "google", "hi", "en-US")
got = main.validate_common(req)
self.assertEquals(got, want)

def test_missing_language(self, req):
"""Test validate_common function when 'language' is missing."""
pass
@parameterized.expand([
("", "variables", "aws", "hi", "en-US"), # Missing payload
("payload", "", "aws", "hi", "en-US"), # Missing variables
("payload", "variables", "", "hi", "en-US"), # Missing provider
("payload", "variables", "awss", "hi", "en-US"), # Invalid provider
("payload", "variables", "aws", "", "en-US"), # Missing text
("payload", "variables", "aws", "hi", ""), # Missing language
])
def test_validate_common_errors(self, payload, variables, provider, text, language):
"""Test validate common method when it raises value errors."""
req = self.get_req(payload, variables, provider, text, language)
self.assertRaises(ValueError, main.validate_common, req)


if __name__ == "__main__":
Expand Down