diff --git a/.env.enc b/.env.enc index 2540a4f17..5903c8874 100644 Binary files a/.env.enc and b/.env.enc differ diff --git a/.travis.yml b/.travis.yml index 91744d29b..cbc1b4be4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,8 @@ python: - '3.6' cache: pip before_install: -- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && openssl aes-256-cbc -K $encrypted_6e98b3e8e789_key -iv $encrypted_6e98b3e8e789_iv -in .env.enc -out .env -d || true' +- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && openssl aes-256-cbc -K $encrypted_cebf25e6c525_key + -iv $encrypted_cebf25e6c525_iv -in .env.enc -out .env -d || true' install: pip install tox-travis script: tox before_deploy: diff --git a/README.md b/README.md index 736bc57b1..f73ca49ec 100755 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # Watson Developer Cloud Python SDK -[![Build Status](https://travis-ci.org/watson-developer-cloud/python-sdk.svg)](https://travis-ci.org/watson-developer-cloud/python-sdk) +[![Build Status](https://travis-ci.org/watson-developer-cloud/python-sdk.svg?branch=master)](https://travis-ci.org/watson-developer-cloud/python-sdk) [![Slack](https://wdc-slack-inviter.mybluemix.net/badge.svg)](https://wdc-slack-inviter.mybluemix.net) [![codecov.io](https://codecov.io/github/watson-developer-cloud/python-sdk/coverage.svg?branch=master)](https://codecov.io/github/watson-developer-cloud/python-sdk?branch=master) [![Latest Stable Version](https://img.shields.io/pypi/v/watson-developer-cloud.svg)](https://pypi.python.org/pypi/watson-developer-cloud) -Python client library to quickly get started with the various [Watson Developer Cloud][wdc] services. +Python client library to quickly get started with the various [Watson APIs][wdc] services. ## Installation @@ -37,24 +37,24 @@ The [examples][examples] folder has basic and advanced examples. Service credentials are required to access the APIs. -If you run your app in Bluemix, you don't need to specify the username and password. In that case, the SDK uses the `VCAP_SERVICES` environment variable to load the credentials. +If you run your app in IBM Cloud, you don't need to specify the username and password. In that case, the SDK uses the `VCAP_SERVICES` environment variable to load the credentials. -To run locally or outside of Bluemix you need the `username` and `password` credentials for each service. (Service credentials are different from your Bluemix account email and password.) +To run locally or outside of IBM Cloud you need the `username` and `password` credentials for each service. (Service credentials are different from your IBM Cloud account email and password.) To create an instance of the service: -1. Log in to [Bluemix][bluemix]. +1. Log in to [IBM Cloud][ibm_cloud]. 1. Create an instance of the service: - 1. In the Bluemix **Catalog**, select the Watson service you want to use. For example, select the Conversation service. + 1. In the IBM Cloud **Catalog**, select the Watson service you want to use. For example, select the Conversation service. 1. Type a unique name for the service instance in the **Service name** field. For example, type `my-service-name`. Leave the default values for the other options. 1. Click **Create**. To get your service credentials: -Copy your credentials from the **Service details** page. To find the the Service details page for an existing service, navigate to your Bluemix dashboard and click the service name. +Copy your credentials from the **Service details** page. To find the the Service details page for an existing service, navigate to your IBM Cloud dashboard and click the service name. 1. On the **Service Details** page, click **Service Credentials**, and then **View credentials**. -1. Copy `username` and `password`. +1. Copy `username`, `password`, and `url`. ## Python Version @@ -82,9 +82,6 @@ response = conversation.message(workspace_id=workspace_id, input={ 'text': 'What\'s the weather like?'}) print(json.dumps(response, indent=2)) ``` -## Known Issues - -See [issues](https://github.com/watson-developer-cloud/python-sdk/issues). ## Dependencies @@ -104,7 +101,7 @@ See [CONTRIBUTING.md][CONTRIBUTING]. This library is licensed under the [Apache 2.0 license][license]. [wdc]: http://www.ibm.com/watson/developercloud/ -[bluemix]: https://console.bluemix.net +[ibm_cloud]: https://console.bluemix.net [responses]: https://github.com/getsentry/responses [requests]: http://docs.python-requests.org/en/latest/ [examples]: https://github.com/watson-developer-cloud/python-sdk/tree/master/examples diff --git a/examples/README.md b/examples/README.md index 9b8a7056d..fcc43978b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,12 +1,11 @@ ## Examples -To run the examples, you will need the `username` and `password` credentials. To get your service credentials, follow these steps: - 1. Log in to Bluemix at https://bluemix.net. +To run the examples, you will need a `username`, `password`, and `url`. To get your service credentials, follow these steps: + 1. Log in to IBM Cloud at https://console.bluemix.net. 1. Create an instance of the service: - 1. In the Bluemix **Catalog**, select the Natural Language Classifier service. - 1. Under **Add Service**, type a unique name for the service instance in the Service name field. For example, type `my-service-name`. Leave the default values for the other options. - 1. Click **Use**. + 1. In the IBM Cloud **Catalog**, select the Natural Language Classifier service. + 1. Click **Create**. 1. Copy your credentials: 1. On the left side of the page, click **Service Credentials** to view your service credentials. - 1. Copy `username` and `password` from these service credentials. + 1. Copy `username`, `password`, and `url` from these service credentials. diff --git a/examples/conversation_tone_analyzer_integration/README.md b/examples/conversation_tone_analyzer_integration/README.md index ccff19fe3..4aa14bd66 100644 --- a/examples/conversation_tone_analyzer_integration/README.md +++ b/examples/conversation_tone_analyzer_integration/README.md @@ -9,8 +9,8 @@ This example provides sample code for integrating [Tone Analyzer][tone_analyzer] Requirements to run the sample code - * [Tone Analyzer Service credentials][bluemix_tone_analyzer_service] - * [Conversation Service credentials][bluemix_conversation_service] + * [Tone Analyzer Service credentials][ibm_cloud_tone_analyzer_service] + * [Conversation Service credentials][ibm_cloud_conversation_service] * [Conversation Workspace ID][conversation_simple_workspace] Credentials & the Workspace ID can be set in environment properties, a .env file, or directly in the code. @@ -24,8 +24,8 @@ Command to run the sample code [conversation]: https://www.ibm.com/watson/developercloud/conversation.html [tone_analyzer]: http://www.ibm.com/watson/developercloud/tone-analyzer.html -[bluemix_conversation_service]: https://console.ng.bluemix.net/catalog/services/conversation/ -[bluemix_tone_analyzer_service]: https://console.ng.bluemix.net/catalog/services/tone-analyzer/ +[ibm_cloud_conversation_service]: https://console.ng.bluemix.net/catalog/services/conversation/ +[ibm_cloud_tone_analyzer_service]: https://console.ng.bluemix.net/catalog/services/tone-analyzer/ [conversation_simple_workspace]: https://github.com/watson-developer-cloud/conversation-simple#workspace [tone_conversation_integration_example]: https://github.com/watson-developer-cloud/python-sdk/tree/master/examples/tone_conversation_integration.v1.py [tone_conversation_integration_example_tone_detection]: https://github.com/watson-developer-cloud/python-sdk/tree/master/examples/conversation_addons/tone_detection.py diff --git a/examples/conversation_v1.py b/examples/conversation_v1.py index 2f48acddd..1ac66200a 100644 --- a/examples/conversation_v1.py +++ b/examples/conversation_v1.py @@ -3,24 +3,11 @@ import os from watson_developer_cloud import ConversationV1 -######################### -# message -######################### - conversation = ConversationV1( username='YOUR SERVICE USERNAME', password='YOUR SERVICE PASSWORD', version='2017-04-21') -# replace with your own workspace_id -workspace_id = '506e4a2e-3d5d-4dca-b374-38edbb4139ab' -if os.getenv("conversation_workspace_id") is not None: - workspace_id = os.getenv("conversation_workspace_id") - -response = conversation.message(workspace_id=workspace_id, input={ - 'text': 'What\'s the weather like?'}) -print(json.dumps(response, indent=2)) - # When you send multiple requests for the same conversation, include the # context object from the previous response. # response = conversation.message(workspace_id=workspace_id, message_input={ @@ -43,6 +30,11 @@ response = conversation.get_workspace(workspace_id=workspace_id, export=True) print(json.dumps(response, indent=2)) +# message +response = conversation.message(workspace_id=workspace_id, input={ + 'text': 'What\'s the weather like?'}) +print(json.dumps(response, indent=2)) + response = conversation.list_workspaces() print(json.dumps(response, indent=2)) diff --git a/examples/dialog_v1.py b/examples/dialog_v1.py deleted file mode 100644 index ea774b3ea..000000000 --- a/examples/dialog_v1.py +++ /dev/null @@ -1,49 +0,0 @@ -# coding=utf-8 -from __future__ import print_function -import json -from watson_developer_cloud import DialogV1 - -dialog = DialogV1( - username='YOUR SERVICE USERNAME', - password='YOUR SERVICE PASSWORD') - -print(json.dumps(dialog.get_dialogs(), indent=2)) - -# print(json.dumps(dialog.get_dialog('6250d170-41d6-468a-a697-5675578c8012'), -# indent=2)) - -# CREATE A DIALOG -# with open(join(dirname(__file__), '../resources/dialog.xml') as dialog_file: -# print(json.dumps(dialog.create_dialog( -# dialog_file=dialog_file, name='pizza_test_9'), indent=2)) - -# dialog_id = '98734721-8952-4a1c-bb72-ef9957d4be93' - -# with open(join(dirname(__file__), '../resources/dialog.xml') as dialog_file: -# print(json.dumps(dialog.update_dialog(dialog_file=dialog_file, -# dialog_id=dialog_id), indent=2)) - -# print(json.dumps(dialog.get_content(dialog_id), indent=2)) -# -# initial_response = dialog.conversation(dialog_id) -# -# print(json.dumps(initial_response, indent=2)) -# -# print(json.dumps(dialog.conversation(dialog_id=dialog_id, -# dialog_input='What type of toppings do -# you have?', -# conversation_id=initial_response[ -# 'conversation_id'], -# client_id=initial_response['client_id']), indent=2)) - -# print(json.dumps(dialog.delete_dialog( -# dialog_id='63b0489c-cd97-45ef-8800-4e7c310eeb19'), indent=2)) - -# print(json.dumps(dialog.update_profile( -# dialog_id='6250d170-41d6-468a-a697-5675578c8012', client_id=123, -# name_values=[{'name': 'test', 'value': 'v1'}]), -# indent=2)) -# -# print(json.dumps(dialog.get_profile( -# dialog_id='6250d170-41d6-468a-a697-5675578c8012', client_id=123), -# indent=2)) diff --git a/examples/natural_language_classifier_v1.py b/examples/natural_language_classifier_v1.py index 95954d550..783ead19e 100644 --- a/examples/natural_language_classifier_v1.py +++ b/examples/natural_language_classifier_v1.py @@ -4,10 +4,6 @@ # from os.path import join, dirname from watson_developer_cloud import NaturalLanguageClassifierV1 -# replace with your own classifier_id -classifier_id = 'e552ebx250-nlc-13834' -if os.getenv("natural_language_classifier_classifier_id") is not None: - classifier_id = os.getenv("natural_language_classifier_classifier_id") natural_language_classifier = NaturalLanguageClassifierV1( username='YOUR SERVICE USERNAME', @@ -17,13 +13,14 @@ print(json.dumps(classifiers, indent=2)) # create a classifier -# with open('../resources/weather_data_train.csv', 'rb') as training_data: -# metadata = json.dumps({'name': 'my-classifier', 'language': 'en'}) -# classifier = natural_language_classifier.create_classifier( -# metadata=metadata, -# training_data=training_data -# ) -# print(json.dumps(classifier, indent=2)) +with open(os.path.join(os.path.dirname(__file__), '../resources/weather_data_train.csv'), 'rb') as training_data: + metadata = json.dumps({'name': 'my-classifier', 'language': 'en'}) + classifier = natural_language_classifier.create_classifier( + metadata=metadata, + training_data=training_data + ) + classifier_id = classifier['classifier_id'] + print(json.dumps(classifier, indent=2)) status = natural_language_classifier.get_classifier(classifier_id) print(json.dumps(status, indent=2)) @@ -34,8 +31,8 @@ 'tomorrow?') print(json.dumps(classes, indent=2)) -# delete = natural_language_classifier.delete_classifier('2374f9x68-nlc-2697') -# print(json.dumps(delete, indent=2)) +delete = natural_language_classifier.delete_classifier(classifier_id) +print(json.dumps(delete, indent=2)) # example of raising a ValueError # print(json.dumps( diff --git a/examples/retrieve_and_rank_v1.py b/examples/retrieve_and_rank_v1.py deleted file mode 100644 index 6863d63a0..000000000 --- a/examples/retrieve_and_rank_v1.py +++ /dev/null @@ -1,79 +0,0 @@ -from __future__ import print_function -import json -from watson_developer_cloud import RetrieveAndRankV1 -import os - - -retrieve_and_rank = RetrieveAndRankV1( - username='YOUR SERVICE USERNAME', - password='YOUR SERVICE PASSWORD') - -# Solr clusters - -solr_clusters = retrieve_and_rank.list_solr_clusters() -print(json.dumps(solr_clusters, indent=2)) - -# created_cluster = retrieve_and_rank.create_solr_cluster(cluster_name='Test -# Cluster', cluster_size='1') -# print(json.dumps(created_cluster, indent=2)) - -# Replace with your own solr_cluster_id -solr_cluster_id = 'sc1264f746_d0f7_4840_90be_07164e6ed04b' -if os.getenv("retrieve_and_rank_solr_cluster_id") is not None: - solr_cluster_id = os.getenv("retrieve_and_rank_solr_cluster_id") - -status = retrieve_and_rank.get_solr_cluster_status( - solr_cluster_id=solr_cluster_id) -print(json.dumps(status, indent=2)) - -# Solr cluster config -# with open('../resources/solr_config.zip', 'rb') as config: -# config_status = retrieve_and_rank.create_config(solr_cluster_id, -# 'test-config', config) -# print(json.dumps(config_status, indent=2)) - -# deleted_response = retrieve_and_rank.delete_config(solr_cluster_id, -# 'test-config') -# print(json.dumps(deleted_response, indent=2)) - -configs = retrieve_and_rank.list_configs(solr_cluster_id=solr_cluster_id) -print(json.dumps(configs, indent=2)) - -# collection = retrieve_and_rank.create_collection(solr_cluster_id, -# 'test-collection', 'test-config') -# print(json.dumps(collection, indent=2)) - -if not configs['solr_configs']: - collections = retrieve_and_rank.list_collections( - solr_cluster_id=solr_cluster_id) - print(json.dumps(collections, indent=2)) - - pysolr_client = retrieve_and_rank.get_pysolr_client(solr_cluster_id, - collections[ - 'collections'][0]) - # Can also refer to config by name - - results = pysolr_client.search('bananas') - print('{0} documents found'.format(len(results.docs))) - -# Rankers - -# rankers = retrieve_and_rank.list_rankers() -# print(json.dumps(rankers, indent=2)) - -# create a ranker -# with open('../resources/ranker_training_data.csv', 'rb') as training_data: -# print(json.dumps(retrieve_and_rank.create_ranker( -# training_data=training_data, name='Ranker Test'), indent=2)) - -# replace YOUR RANKER ID -# status = retrieve_and_rank.get_ranker_status('42AF7Ex10-rank-47') -# print(json.dumps(status, indent=2)) - -# delete_results = retrieve_and_rank.delete_ranker('YOUR RANKER ID') -# print(json.dumps(delete_results)) - -# replace '42AF7Ex10-rank-47' with your ranker_id -# with open('../resources/ranker_answer_data.csv', 'rb') as answer_data: -# ranker_results = retrieve_and_rank.rank('42AF7Ex10-rank-47', answer_data) -# print(json.dumps(ranker_results, indent=2)) diff --git a/examples/text_to_speech_v1.py b/examples/text_to_speech_v1.py index b20382caf..34f0fa1c9 100644 --- a/examples/text_to_speech_v1.py +++ b/examples/text_to_speech_v1.py @@ -6,22 +6,19 @@ text_to_speech = TextToSpeechV1( username='YOUR SERVICE USERNAME', - password='YOUR SERVICE PASSWORD', - x_watson_learning_opt_out=True) # Optional flag + password='YOUR SERVICE PASSWORD') -print(json.dumps(text_to_speech.voices(), indent=2)) +print(json.dumps(text_to_speech.list_voices(), indent=2)) with open(join(dirname(__file__), '../resources/output.wav'), 'wb') as audio_file: audio_file.write( text_to_speech.synthesize('Hello world!', accept='audio/wav', - voice="en-US_AllisonVoice")) + voice="en-US_AllisonVoice").content) -print( - json.dumps(text_to_speech.pronunciation( - 'Watson', pronunciation_format='spr'), indent=2)) +print(json.dumps(text_to_speech.get_pronunciation('Watson', format='spr'), indent=2)) -print(json.dumps(text_to_speech.customizations(), indent=2)) +print(json.dumps(text_to_speech.list_voice_models(), indent=2)) # print(json.dumps(text_to_speech.create_customization('test-customization'), # indent=2)) diff --git a/examples/tradeoff_analytics_v1.py b/examples/tradeoff_analytics_v1.py deleted file mode 100755 index 7e92fd4bd..000000000 --- a/examples/tradeoff_analytics_v1.py +++ /dev/null @@ -1,16 +0,0 @@ -from __future__ import print_function -import json -import os -from watson_developer_cloud import TradeoffAnalyticsV1 - -tradeoff_analytics = TradeoffAnalyticsV1( - username='YOUR SERVICE USERNAME', - password='YOUR SERVICE PASSWORD') - -with open(os.path.join(os.path.dirname(__file__), - '../resources/problem.json')) as problem_json: - dilemma = tradeoff_analytics.dilemmas(json.load(problem_json), - generate_visualization=True, - find_preferable_options=True) - -print(json.dumps(dilemma, indent=2)) diff --git a/test/__init__.py b/test/__init__.py index 6dbd8572e..b8c9cd96b 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -11,3 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +from dotenv import load_dotenv, find_dotenv + +# load the .env file containing your environment variables for the required +load_dotenv(find_dotenv()) \ No newline at end of file diff --git a/test/integration/__init__.py b/test/integration/__init__.py new file mode 100644 index 000000000..b8c9cd96b --- /dev/null +++ b/test/integration/__init__.py @@ -0,0 +1,17 @@ +# Copyright 2015 IBM All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from dotenv import load_dotenv, find_dotenv + +# load the .env file containing your environment variables for the required +load_dotenv(find_dotenv()) \ No newline at end of file diff --git a/test/test_integration_speech_to_text_v1.py b/test/integration/test_integration_speech_to_text_v1.py similarity index 100% rename from test/test_integration_speech_to_text_v1.py rename to test/integration/test_integration_speech_to_text_v1.py diff --git a/test/integration/test_integration_text_to_speech_v1.py b/test/integration/test_integration_text_to_speech_v1.py new file mode 100644 index 000000000..aa474eb80 --- /dev/null +++ b/test/integration/test_integration_text_to_speech_v1.py @@ -0,0 +1,60 @@ +import pytest +import unittest +import watson_developer_cloud +import os + +class TestIntegrationTextToSpeechV1(unittest.TestCase): + def setUp(self): + self.text_to_speech = watson_developer_cloud.TextToSpeechV1() + self.original_customizations = self.text_to_speech.list_voice_models() + self.created_customization = self.text_to_speech.create_voice_model( + name="test_integration_customization", + description="customization for tests") + + def tearDown(self): + custid = self.created_customization['customization_id'] + self.text_to_speech.delete_voice_model(customization_id=custid) + + def test_voices(self): + output = self.text_to_speech.list_voices() + assert output['voices'] is not None + voice = self.text_to_speech.get_voice(output['voices'][0]['name']) + assert voice is not None + + def test_speak(self): + output = self.text_to_speech.synthesize( + text="my voice is my passport", + accept='audio/wav', + voice='en-US_AllisonVoice') + output.content is not None + + def test_pronunciation(self): + output = self.text_to_speech.get_pronunciation('hello') + output['pronunciation'] is not None + + def test_customizations(self): + old_length = len(self.original_customizations['customizations']) + new_length = len( + self.text_to_speech.list_voice_models()['customizations']) + assert new_length - old_length == 1 + + def test_custom_words(self): + customization_id = self.created_customization['customization_id'] + words = self.text_to_speech.list_words(customization_id)['words'] + assert len(words) == 0 + self.text_to_speech.add_word( + customization_id, + word="ACLs", + translation="ackles") + + words = [ + { + "word": "MACLs", + "translation": "mackles" + } + ] + + self.text_to_speech.add_words(customization_id, words) + self.text_to_speech.delete_word(customization_id, 'ACLs') + word = self.text_to_speech.get_word(customization_id, 'MACLs') + assert word['translation'] == 'mackles' diff --git a/test/test_integration_visual_recognition.py b/test/integration/test_integration_visual_recognition.py similarity index 100% rename from test/test_integration_visual_recognition.py rename to test/integration/test_integration_visual_recognition.py diff --git a/test/test_integration_text_to_speech_v1.py b/test/test_integration_text_to_speech_v1.py deleted file mode 100644 index ea0d88b22..000000000 --- a/test/test_integration_text_to_speech_v1.py +++ /dev/null @@ -1,27 +0,0 @@ -import pytest -import unittest -import watson_developer_cloud -import os - -@pytest.mark.skip("These are destructive, so run them manually") -class TestIntegrationTextToSpeechV1(unittest.TestCase): - - def setUp(self): - self.text_to_speech = watson_developer_cloud.TextToSpeechV1(username=os.getenv('TEXT_TO_SPEECH_USERNAME'), - password=os.getenv('TEXT_TO_SPEECH_PASSWORD')) - self.original_customizations = self.text_to_speech.customizations() - self.created_customization = self.text_to_speech.create_customization(name="test_integration_customization", - description="customization for tests") - - def tearDown(self): - custid = self.created_customization['customization_id'] - self.text_to_speech.delete_customization(customization_id=custid) - - def test_customizations(self): - old_length = len(self.original_customizations['customizations']) - new_length = len(self.text_to_speech.customizations()['customizations']) - assert new_length - old_length == 1 - - def test_speak(self): - output = self.text_to_speech.synthesize(text="my voice is my passport") - assert not output diff --git a/test/test_text_to_speech_v1.py b/test/test_text_to_speech_v1.py index 0bafceae7..bb18e4e46 100644 --- a/test/test_text_to_speech_v1.py +++ b/test/test_text_to_speech_v1.py @@ -1,126 +1,229 @@ # coding=utf-8 import responses import watson_developer_cloud +import json @responses.activate def test_success(): voices_url = 'https://stream.watsonplatform.net/text-to-speech/api/v1/voices' - voices_response = '{"voices": [{"url": "https://stream.watsonplatform.net/text-to-speech/api/v1/voices/' \ - 'VoiceEnUsLisa", "gender": "female", "name": "VoiceEnUsLisa", "language": "en-US"}, {"url": ' \ - '"https://stream.watsonplatform.net/text-to-speech/api/v1/voices/VoiceEsEsEnrique", ' \ - '"gender": "male", "name": "VoiceEsEsEnrique", "language": "es-ES"}, {"url": ' \ - '"https://stream.watsonplatform.net/text-to-speech/api/v1/voices/VoiceEnUsMichael", ' \ - '"gender": "male", "name": "VoiceEnUsMichael", "language": "en-US"}, {"url": ' \ - '"https://stream.watsonplatform.net/text-to-speech/api/v1/voices/VoiceEnUsAllison", ' \ - '"gender": "female", "name": "VoiceEnUsAllison", "language": "en-US"}]}' - - responses.add(responses.GET, voices_url, body=voices_response, - status=200, content_type='application/json') + voices_response = { + "voices": [{ + "url": + "https://stream.watsonplatform.net/text-to-speech/api/v1/voices/VoiceEnUsLisa", + "gender": + "female", + "name": + "VoiceEnUsLisa", + "language": + "en-US" + }, { + "url": + "https://stream.watsonplatform.net/text-to-speech/api/v1/voices/VoiceEsEsEnrique", + "gender": + "male", + "name": + "VoiceEsEsEnrique", + "language": + "es-ES" + }, { + "url": + "https://stream.watsonplatform.net/text-to-speech/api/v1/voices/VoiceEnUsMichael", + "gender": + "male", + "name": + "VoiceEnUsMichael", + "language": + "en-US" + }, { + "url": + "https://stream.watsonplatform.net/text-to-speech/api/v1/voices/VoiceEnUsAllison", + "gender": + "female", + "name": + "VoiceEnUsAllison", + "language": + "en-US" + }] + } + voice_url = 'https://stream.watsonplatform.net/text-to-speech/api/v1/voices/en-us_AllisonVoice' + voice_response = { + "url": + "https://stream.watsonplatform.net/text-to-speech/api/v1/voices/en-US_AllisonVoice", + "name": + "en-US_AllisonVoice", + "language": + "en-US", + "customizable": + True, + "gender": + "female", + "description": + "Allison: American English female voice.", + "supported_features": { + "custom_pronunciation": True, + "voice_transformation": True + } + } + synthesize_url = 'https://stream.watsonplatform.net/text-to-speech/api/v1/synthesize' + synthesize_response_body = '' + + responses.add( + responses.GET, + voices_url, + body=json.dumps(voices_response), + status=200, + content_type='application/json') + responses.add( + responses.GET, + voice_url, + body=json.dumps(voice_response), + status=200, + content_type='application/json') + responses.add( + responses.POST, + synthesize_url, + body=synthesize_response_body, + status=200, + content_type='application/json', + match_querystring=True) text_to_speech = watson_developer_cloud.TextToSpeechV1( username="username", password="password") - text_to_speech.voices() + text_to_speech.list_voices() assert responses.calls[0].request.url == voices_url - assert responses.calls[0].response.text == voices_response - - synthesize_text = 'hello' - synthesize_url = 'https://stream.watsonplatform.net/text-to-speech/api/v1/synthesize' - synthesize_response_body = '' + assert responses.calls[0].response.text == json.dumps(voices_response) - responses.add(responses.POST, synthesize_url, - body=synthesize_response_body, status=200, - content_type='application/json', match_querystring=True) - text_to_speech.synthesize(synthesize_text) + text_to_speech.get_voice('en-us_AllisonVoice') + assert responses.calls[1].request.url == voice_url + assert responses.calls[1].response.text == json.dumps(voice_response) - assert responses.calls[1].request.url == synthesize_url - assert responses.calls[1].response.text == synthesize_response_body + text_to_speech.synthesize('hello') + assert responses.calls[2].request.url == synthesize_url + assert responses.calls[2].response.text == synthesize_response_body - assert len(responses.calls) == 2 + assert len(responses.calls) == 3 @responses.activate -def test_pronounciation(): +def test_get_pronunciation(): - responses.add(responses.GET, 'https://stream.watsonplatform.net/text-to-speech/api/v1/pronunciation', - body='{"pronunciation": "pronunciation info" }', - status=200, content_type='application_json') + responses.add( + responses.GET, + 'https://stream.watsonplatform.net/text-to-speech/api/v1/pronunciation', + body='{"pronunciation": "pronunciation info" }', + status=200, + content_type='application_json') text_to_speech = watson_developer_cloud.TextToSpeechV1( username="username", password="password") - text_to_speech.pronunciation(text="this is some text") - text_to_speech.pronunciation(text="yo", voice="VoiceEnUsLisa") - text_to_speech.pronunciation( - text="yo", voice="VoiceEnUsLisa", pronunciation_format='ipa') + + text_to_speech.get_pronunciation(text="this is some text") + text_to_speech.get_pronunciation(text="yo", voice="VoiceEnUsLisa") + text_to_speech.get_pronunciation( + text="yo", voice="VoiceEnUsLisa", format='ipa') assert len(responses.calls) == 3 @responses.activate -def test_customizations(): - responses.add(responses.GET, 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations', - body='{"customizations": "yep" }', - status=200, content_type='application_json') - responses.add(responses.POST, 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations', - body='{"customizations": "yep" }', - status=200, content_type='application_json') - responses.add(responses.GET, 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations/custid', - body='{"customization": "yep, just one" }', - status=200, content_type='application_json') - responses.add(responses.POST, 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations/custid', - body='{"customizations": "yep" }', - status=200, content_type='application_json') - responses.add(responses.DELETE, 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations/custid', - body='{"customizations": "yep" }', - status=200, content_type='application_json') +def test_custom_voice_models(): + responses.add( + responses.GET, + 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations', + body='{"customizations": "yep" }', + status=200, + content_type='application_json') + responses.add( + responses.POST, + 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations', + body='{"customizations": "yep" }', + status=200, + content_type='application_json') + responses.add( + responses.GET, + 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations/custid', + body='{"customization": "yep, just one" }', + status=200, + content_type='application_json') + responses.add( + responses.POST, + 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations/custid', + body='{"customizations": "yep" }', + status=200, + content_type='application_json') + responses.add( + responses.DELETE, + 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations/custid', + body='{"customizations": "yep" }', + status=200, + content_type='application_json') text_to_speech = watson_developer_cloud.TextToSpeechV1( username="username", password="password") - text_to_speech.customizations() - text_to_speech.customizations(language="en-US") + text_to_speech.list_voice_models() + text_to_speech.list_voice_models(language="en-US") assert len(responses.calls) == 2 - text_to_speech.create_customization(name="name", description="description") - text_to_speech.get_customization(customization_id='custid') - text_to_speech.update_customization( + text_to_speech.create_voice_model(name="name", description="description") + text_to_speech.get_voice_model(customization_id='custid') + text_to_speech.update_voice_model( customization_id="custid", name="name", description="description") - text_to_speech.delete_customization(customization_id="custid") + text_to_speech.delete_voice_model(customization_id="custid") assert len(responses.calls) == 6 @responses.activate -def test_customization_words(): +def test_custom_words(): base_url = 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations' - responses.add(responses.GET, "{0}/{1}/words".format(base_url, "custid"), - body='{"customizations": "yep" }', - status=200, content_type='application_json') - responses.add(responses.POST, "{0}/{1}/words".format(base_url, "custid"), - body='{"customizations": "yep" }', - status=200, content_type='application_json') - responses.add(responses.GET, "{0}/{1}/words/{2}".format(base_url, "custid", "word"), - body='{"customization": "yep, just one" }', - status=200, content_type='application_json') - responses.add(responses.POST, "{0}/{1}/words/{2}".format(base_url, "custid", "word"), - body='{"customizations": "yep" }', - status=200, content_type='application_json') - responses.add(responses.PUT, "{0}/{1}/words/{2}".format(base_url, "custid", "word"), - body='{"customizations": "yep" }', - status=200, content_type='application_json') - responses.add(responses.DELETE, "{0}/{1}/words/{2}".format(base_url, "custid", "word"), - body='{"customizations": "yep" }', - status=200, content_type='application_json') + responses.add( + responses.GET, + "{0}/{1}/words".format(base_url, "custid"), + body='{"customizations": "yep" }', + status=200, + content_type='application_json') + responses.add( + responses.POST, + "{0}/{1}/words".format(base_url, "custid"), + body='{"customizations": "yep" }', + status=200, + content_type='application_json') + responses.add( + responses.GET, + "{0}/{1}/words/{2}".format(base_url, "custid", "word"), + body='{"customization": "yep, just one" }', + status=200, + content_type='application_json') + responses.add( + responses.POST, + "{0}/{1}/words/{2}".format(base_url, "custid", "word"), + body='{"customizations": "yep" }', + status=200, + content_type='application_json') + responses.add( + responses.PUT, + "{0}/{1}/words/{2}".format(base_url, "custid", "word"), + body='{"customizations": "yep" }', + status=200, + content_type='application_json') + responses.add( + responses.DELETE, + "{0}/{1}/words/{2}".format(base_url, "custid", "word"), + body='{"customizations": "yep" }', + status=200, + content_type='application_json') text_to_speech = watson_developer_cloud.TextToSpeechV1( username="username", password="password") - text_to_speech.get_customization_words(customization_id="custid") - text_to_speech.add_customization_words( + + text_to_speech.list_words(customization_id="custid") + text_to_speech.add_words( customization_id="custid", words=["one", "two", "three"]) - text_to_speech.get_customization_word( - customization_id="custid", word="word") - text_to_speech.set_customization_word( + text_to_speech.get_word(customization_id="custid", word="word") + text_to_speech.add_word( customization_id='custid', word="word", translation="I'm translated") - text_to_speech.delete_customization_word( - customization_id="custid", word="word") + text_to_speech.delete_word(customization_id="custid", word="word") + assert len(responses.calls) == 5 diff --git a/watson_developer_cloud/text_to_speech_v1.py b/watson_developer_cloud/text_to_speech_v1.py index 8cbc2ad1b..258b08e05 100644 --- a/watson_developer_cloud/text_to_speech_v1.py +++ b/watson_developer_cloud/text_to_speech_v1.py @@ -1,4 +1,6 @@ -# Copyright 2016 IBM All Rights Reserved. +# coding: utf-8 + +# Copyright 2018 IBM All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,123 +14,1134 @@ # See the License for the specific language governing permissions and # limitations under the License. """ -The v1 Text to Speech service -(https://www.ibm.com/watson/developercloud/text-to-speech.html) +For more information about the service and its various interfaces, see [About Text to +Speech](https://console.bluemix.net/docs/services/text-to-speech/index.html). """ +from __future__ import absolute_import + +import json from .watson_service import WatsonService +from .utils import deprecated + +############################################################################## +# Service +############################################################################## class TextToSpeechV1(WatsonService): - """Client for the Text to Speech service""" - default_url = "https://stream.watsonplatform.net/text-to-speech/api" + """The Text to Speech V1 service.""" + + default_url = 'https://stream.watsonplatform.net/text-to-speech/api' - def __init__(self, url=default_url, **kwargs): + def __init__(self, url=default_url, username=None, password=None): """ - Construct an instance. Fetches service parameters from VCAP_SERVICES - runtime variable for Bluemix, or it defaults to local URLs. + Construct a new client for the Text to Speech service. + + :param str url: The base url to use when contacting the service (e.g. + "https://gateway.watsonplatform.net/text-to-speech/api"). + The base url may differ between Bluemix regions. + + :param str username: The username used to authenticate with the service. + Username and password credentials are only required to run your + application locally or outside of Bluemix. When running on + Bluemix, the credentials will be automatically loaded from the + `VCAP_SERVICES` environment variable. + + :param str password: The password used to authenticate with the service. + Username and password credentials are only required to run your + application locally or outside of Bluemix. When running on + Bluemix, the credentials will be automatically loaded from the + `VCAP_SERVICES` environment variable. + """ - WatsonService.__init__(self, 'text_to_speech', url, **kwargs) - def synthesize(self, text, voice=None, accept=None, customization_id=None): + WatsonService.__init__( + self, + vcap_services_name='text_to_speech', + url=url, + username=username, + password=password, + use_vcap_services=True) + + ######################### + # voices + ######################### + + def get_voice(self, voice, customization_id=None): """ - Returns the get HTTP response by doing a POST to /synthesize with - text, voice, accept + Retrieves a specific voice available for speech synthesis. + + :param str voice: The voice for which information is to be returned. Retrieve available voices with the `GET /v1/voices` method. + :param str customization_id: The GUID of a custom voice model for which information is to be returned. You must make the request with service credentials created for the instance of the service that owns the custom model. Omit the parameter to see information about the specified voice with no customization. + :return: A `dict` containing the `Voice` response. + :rtype: dict """ - params = {'voice': voice, 'accept': accept, - 'customization_id': customization_id} - data = {'text': text} + if voice is None: + raise ValueError('voice must be provided') + params = {'customization_id': customization_id} + url = '/v1/voices/{0}'.format(*self._encode_path_vars(voice)) response = self.request( - method='POST', url='/v1/synthesize', stream=True, params=params, - json=data) - return response.content + method='GET', url=url, params=params, accept_json=True) + return response - def voices(self): + def list_voices(self): """ - Returns the list of available voices to use with synthesize + Retrieves all voices available for speech synthesis. + + :return: A `dict` containing the `Voices` response. + :rtype: dict """ - return self.request(method='GET', url='/v1/voices', accept_json=True) + url = '/v1/voices' + response = self.request(method='GET', url=url, accept_json=True) + return response - def pronunciation(self, text, voice=None, pronunciation_format='ipa'): + @deprecated('Use list_voices() instead') + def voices(self): + return self.list_voices() + + ######################### + # synthesize + ######################### + + def synthesize(self, + text, + accept=None, + voice=None, + customization_id=None): + """ + Streaming speech synthesis of the text in the body parameter. Synthesizes text to spoken audio, returning the synthesized audio stream as an array of bytes. + + :param str text: The text to synthesize. + :param str accept: The requested audio format (MIME type) of the audio. You can use this header or the `accept` query parameter to specify the audio format. (For the `audio/l16` format, you can optionally specify `endianness=big-endian` or `endianness=little-endian`; the default is little endian.). + :param str voice: The voice to use for synthesis. Retrieve available voices with the `GET /v1/voices` method. + :param str customization_id: The GUID of a custom voice model to use for the synthesis. If a custom voice model is specified, it is guaranteed to work only if it matches the language of the indicated voice. You must make the request with service credentials created for the instance of the service that owns the custom model. Omit the parameter to use the specified voice with no customization. + :return: A `Response ` object representing the response. + :rtype: requests.models.Response + """ + if text is None: + raise ValueError('text must be provided') + headers = {'Accept': accept} params = { - 'text': text, 'voice': voice, - 'format': pronunciation_format + 'customization_id': customization_id } - return self.request(method='GET', url='/v1/pronunciation', - params=params, accept_json=True) + data = {'text': text} + url = '/v1/synthesize' + response = self.request( + method='POST', + url=url, + headers=headers, + params=params, + json=data, + accept_json=False) - def customizations(self, language=None): + return response + + ######################### + # pronunciation + ######################### + + def get_pronunciation(self, + text, + voice=None, + format=None, + customization_id=None): + """ + Gets the pronunciation for a word. + + Returns the phonetic pronunciation for the word specified by the `text` parameter. + You can request the pronunciation for a specific format. You can also request the + pronunciation for a specific voice to see the default translation for the language + of that voice or for a specific custom voice model to see the translation for that + voice model. **Note:** This method is currently a beta release. + + :param str text: The word for which the pronunciation is requested. + :param str voice: A voice that specifies the language in which the pronunciation is to be returned. All voices for the same language (for example, `en-US`) return the same translation. Retrieve available voices with the `GET /v1/voices` method. + :param str format: The phoneme format in which to return the pronunciation. Omit the parameter to obtain the pronunciation in the default format. + :param str customization_id: The GUID of a custom voice model for which the pronunciation is to be returned. The language of a specified custom model must match the language of the specified voice. If the word is not defined in the specified custom model, the service returns the default translation for the custom model's language. You must make the request with service credentials created for the instance of the service that owns the custom model. Omit the parameter to see the translation for the specified voice with no customization. + :return: A `dict` containing the `Pronunciation` response. + :rtype: dict + """ + if text is None: + raise ValueError('text must be provided') params = { - 'language': language + 'text': text, + 'voice': voice, + 'format': format, + 'customization_id': customization_id } - return self.request(method='GET', url='/v1/customizations', - params=params, accept_json=True) + url = '/v1/pronunciation' + response = self.request( + method='GET', url=url, params=params, accept_json=True) + return response - def get_customization(self, customization_id): - customization_id = self.unpack_id(customization_id, 'customization_id') - return self.request(method='GET', url='/v1/customizations/{0}'.format( - customization_id), accept_json=True) + @deprecated('Use get_pronunciation() instead') + def pronunciation(self, text, voice=None, pronunciation_format='ipa'): + return self.get_pronunciation(text, voice, pronunciation_format) + + ######################### + # customVoiceModels + ######################### + + def create_voice_model(self, name, language=None, description=None): + """ + Creates a new custom voice model. + + Creates a new empty custom voice model. The model is owned by the instance of the + service whose credentials are used to create it. **Note:** This method is + currently a beta release. + + :param str name: The name of the new custom voice model. + :param str language: The language of the new custom voice model. Omit the parameter to use the the default language, `en-US`. + :param str description: A description of the new custom voice model. Specifying a description is recommended. + :return: A `dict` containing the `VoiceModel` response. + :rtype: dict + """ + if name is None: + raise ValueError('name must be provided') + data = {'name': name, 'language': language, 'description': description} + url = '/v1/customizations' + response = self.request( + method='POST', url=url, json=data, accept_json=True) + return response + @deprecated('Use create_voice_model() instead.') def create_customization(self, name, language=None, description=None): - body = { - 'name': name, - 'language': language, - 'description': description - } - return self.request(method='POST', url='/v1/customizations', json=body, - accept_json=True) + return self.create_voice_model(name, language, description) + + def delete_voice_model(self, customization_id): + """ + Deletes a custom voice model. + + Deletes the custom voice model with the specified `customization_id`. You must use + credentials for the instance of the service that owns a model to delete it. + **Note:** This method is currently a beta release. + + :param str customization_id: The GUID of the custom voice model that is to be deleted. You must make the request with service credentials created for the instance of the service that owns the custom model. + :rtype: None + """ + if customization_id is None: + raise ValueError('customization_id must be provided') + url = '/v1/customizations/{0}'.format( + *self._encode_path_vars(customization_id)) + self.request(method='DELETE', url=url, accept_json=True) + return None + + @deprecated('Use delete_voice_model() instead.') + def delete_customization(self, customization_id): + return self.delete_voice_model(customization_id) + + def get_voice_model(self, customization_id): + """ + Queries the contents of a custom voice model. + + Lists all information about the custom voice model with the specified + `customization_id`. In addition to metadata such as the name and description of + the voice model, the output includes the words in the model and their translations + as defined in the model. **Note:** This method is currently a beta release. + + :param str customization_id: The GUID of the custom voice model that is to be queried. You must make the request with service credentials created for the instance of the service that owns the custom model. + :return: A `dict` containing the `VoiceModel` response. + :rtype: dict + """ + if customization_id is None: + raise ValueError('customization_id must be provided') + url = '/v1/customizations/{0}'.format( + *self._encode_path_vars(customization_id)) + response = self.request(method='GET', url=url, accept_json=True) + return response + + @deprecated('Use get_voice_model instead.') + def get_customization(self, customization_id): + return self.get_voice_model(customization_id) + + def list_voice_models(self, language=None): + """ + Lists all available custom voice models for a language or for all languages. + **Note:** This method is currently a beta release. + + :param str language: The language for which custom voice models that are owned by the requesting service credentials are to be returned. Omit the parameter to see all custom voice models that are owned by the requester. + :return: A `dict` containing the `VoiceModels` response. + :rtype: dict + """ + params = {'language': language} + url = '/v1/customizations' + response = self.request( + method='GET', url=url, params=params, accept_json=True) + return response + + @deprecated('Use list_voice_models() instead.') + def customizations(self, language=None): + return self.list_voice_models(language) + def update_voice_model(self, + customization_id, + name=None, + description=None, + words=None): + """ + Updates information and words for a custom voice model. + + Updates information for the custom voice model with the specified + `customization_id`. You can update the metadata such as the name and description + of the voice model. You can also update the words in the model and their + translations. Adding a new translation for a word that already exists in a custom + model overwrites the word's existing translation. A custom model can contain no + more than 20,000 entries. You must use credentials for the instance of the service + that owns a model to update it. **Note:** This method is currently a beta + release. + + :param str customization_id: The GUID of the custom voice model that is to be updated. You must make the request with service credentials created for the instance of the service that owns the custom model. + :param str name: A new name for the custom voice model. + :param str description: A new description for the custom voice model. + :param list[CustomWord] words: An array of words and their translations that are to be added or updated for the custom voice model. Pass an empty array to make no additions or updates. + :rtype: None + """ + if customization_id is None: + raise ValueError('customization_id must be provided') + if words is not None: + words = [self._convert_model(x) for x in words] + data = {'name': name, 'description': description, 'words': words} + url = '/v1/customizations/{0}'.format( + *self._encode_path_vars(customization_id)) + self.request(method='POST', url=url, json=data, accept_json=True) + return None + + @deprecated('Use update_voice_model() instead') def update_customization(self, customization_id, name=None, description=None, words=None): - body = { - 'name': name, - 'description': description, - 'words': words - } - return self.request(method='POST', url='/v1/customizations/{0}'.format( - customization_id), json=body) + return self.update_voice_model(customization_id, name, description, words) - def delete_customization(self, customization_id): - customization_id = self.unpack_id(customization_id, 'customization_id') - return self.request(method='DELETE', - url='/v1/customizations/{0}'.format( - customization_id)) + ######################### + # customWords + ######################### - def get_customization_words(self, customization_id): - customization_id = self.unpack_id(customization_id, 'customization_id') - return self.request(method='GET', - url='/v1/customizations/{0}/words'.format( - customization_id), accept_json=True) + def add_word(self, customization_id, word, translation, + part_of_speech=None): + """ + Adds a word to a custom voice model. - def add_customization_words(self, customization_id, words): - customization_id = self.unpack_id(customization_id, 'customization_id') - body = { - 'words': words - } - return self.request(method='POST', - url='/v1/customizations/{0}/words'.format( - customization_id), json=body) + Adds a single word and its translation to the custom voice model with the + specified `customization_id`. Adding a new translation for a word that already + exists in a custom model overwrites the word's existing translation. A custom + model can contain no more than 20,000 entries. You must use credentials for the + instance of the service that owns a model to add a word to it. **Note:** This + method is currently a beta release. - def get_customization_word(self, customization_id, word): - customization_id = self.unpack_id(customization_id, 'customization_id') - return self.request(method='GET', - url='/v1/customizations/{0}/words/{1}'.format( - customization_id, word), - accept_json=True) + :param str customization_id: The GUID of the custom voice model that is to be updated. You must make the request with service credentials created for the instance of the service that owns the custom model. + :param str word: The word that is to be added or updated for the custom voice model. + :param str translation: The phonetic or sounds-like translation for the word. A phonetic translation is based on the SSML format for representing the phonetic string of a word either as an IPA translation or as an IBM SPR translation. A sounds-like is one or more words that, when combined, sound like the word. + :param str part_of_speech: **Japanese only.** The part of speech for the word. The service uses the value to produce the correct intonation for the word. You can create only a single entry, with or without a single part of speech, for any word; you cannot create multiple entries with different parts of speech for the same word. For more information, see [Working with Japanese entries](https://console.bluemix.net/docs/services/text-to-speech/custom-rules.html#jaNotes). + :rtype: None + """ + if customization_id is None: + raise ValueError('customization_id must be provided') + if word is None: + raise ValueError('word must be provided') + if translation is None: + raise ValueError('translation must be provided') + data = {'translation': translation, 'part_of_speech': part_of_speech} + url = '/v1/customizations/{0}/words/{1}'.format(*self._encode_path_vars( + customization_id, word)) + self.request(method='PUT', url=url, json=data, accept_json=True) + return None + @deprecated('Use add_word() instead.') def set_customization_word(self, customization_id, word, translation): - customization_id = self.unpack_id(customization_id, 'customization_id') - body = { - 'translation': translation - } - return self.request(method='PUT', - url='/v1/customizations/{0}/words/{1}'.format( - customization_id, word), - json=body) + return self.add_word(customization_id, word, translation) + + def add_words(self, customization_id, words): + """ + Adds one or more words to a custom voice model. + + Adds one or more words and their translations to the custom voice model with the + specified `customization_id`. Adding a new translation for a word that already + exists in a custom model overwrites the word's existing translation. A custom + model can contain no more than 20,000 entries. You must use credentials for the + instance of the service that owns a model to add words to it. **Note:** This + method is currently a beta release. + + :param str customization_id: The GUID of the custom voice model that is to be updated. You must make the request with service credentials created for the instance of the service that owns the custom model. + :param list[CustomWord] words: An array of `CustomWord` objects that provides information about the words and their translations that are to be added or updated for the custom voice model. + :rtype: None + """ + if customization_id is None: + raise ValueError('customization_id must be provided') + if words is None: + raise ValueError('words must be provided') + words = [self._convert_model(x) for x in words] + data = {'words': words} + url = '/v1/customizations/{0}/words'.format( + *self._encode_path_vars(customization_id)) + self.request(method='POST', url=url, json=data, accept_json=True) + return None + + @deprecated('Use add_words() instead.') + def add_customization_words(self, customization_id, words): + return self.add_words(customization_id, words) + def delete_word(self, customization_id, word): + """ + Deletes a word from a custom voice model. + + Deletes a single word from the custom voice model with the specified + `customization_id`. You must use credentials for the instance of the service that + owns a model to delete it. **Note:** This method is currently a beta release. + + :param str customization_id: The GUID of the custom voice model from which to delete a word. You must make the request with service credentials created for the instance of the service that owns the custom model. + :param str word: The word that is to be deleted from the custom voice model. + :rtype: None + """ + if customization_id is None: + raise ValueError('customization_id must be provided') + if word is None: + raise ValueError('word must be provided') + url = '/v1/customizations/{0}/words/{1}'.format(*self._encode_path_vars( + customization_id, word)) + self.request(method='DELETE', url=url, accept_json=True) + return None + + @deprecated('Use delete_word() instead.') def delete_customization_word(self, customization_id, word): - customization_id = self.unpack_id(customization_id, 'customization_id') - return self.request(method='DELETE', - url='/v1/customizations/{0}/words/{1}'.format( - customization_id, word)) + return self.delete_word(customization_id, word) + + def get_word(self, customization_id, word): + """ + Queries details about a word in a custom voice model. + + Returns the translation for a single word from the custom model with the specified + `customization_id`. The output shows the translation as it is defined in the + model. You must use credentials for the instance of the service that owns a model + to query information about its words. **Note:** This method is currently a beta + release. + + :param str customization_id: The GUID of the custom voice model from which to query a word. You must make the request with service credentials created for the instance of the service that owns the custom model. + :param str word: The word that is to be queried from the custom voice model. + :return: A `dict` containing the `Translation` response. + :rtype: dict + """ + if customization_id is None: + raise ValueError('customization_id must be provided') + if word is None: + raise ValueError('word must be provided') + url = '/v1/customizations/{0}/words/{1}'.format(*self._encode_path_vars( + customization_id, word)) + response = self.request(method='GET', url=url, accept_json=True) + return response + + @deprecated('Use get_word() instead.') + def get_customization_word(self, customization_id, word): + return self.get_word(customization_id, word) + + def list_words(self, customization_id): + """ + Queries details about the words in a custom voice model. + + Lists all of the words and their translations for the custom voice model with the + specified `customization_id`. The output shows the translations as they are + defined in the model. You must use credentials for the instance of the service + that owns a model to query information about its words. **Note:** This method is + currently a beta release. + + :param str customization_id: The GUID of the custom voice model that is to be queried. You must make the request with service credentials created for the instance of the service that owns the custom model. + :return: A `dict` containing the `Words` response. + :rtype: dict + """ + if customization_id is None: + raise ValueError('customization_id must be provided') + url = '/v1/customizations/{0}/words'.format( + *self._encode_path_vars(customization_id)) + response = self.request(method='GET', url=url, accept_json=True) + return response + + @deprecated('Use list_words() instead.') + def get_customization_words(self, customization_id): + return self.list_words(customization_id) + + +############################################################################## +# Models +############################################################################## + + +class CustomWord(object): + """ + CustomWord. + + :attr str word: A word that is to be added or updated for the custom voice model. + :attr str translation: The phonetic or sounds-like translation for the word. A phonetic translation is based on the SSML format for representing the phonetic string of a word either as an IPA or IBM SPR translation. A sounds-like translation consists of one or more words that, when combined, sound like the word. + :attr str part_of_speech: (optional) **Japanese only.** The part of speech for the word. The service uses the value to produce the correct intonation for the word. You can create only a single entry, with or without a single part of speech, for any word; you cannot create multiple entries with different parts of speech for the same word. For more information, see [Working with Japanese entries](https://console.bluemix.net/docs/services/text-to-speech/custom-rules.html#jaNotes). + """ + + def __init__(self, word, translation, part_of_speech=None): + """ + Initialize a CustomWord object. + + :param str word: A word that is to be added or updated for the custom voice model. + :param str translation: The phonetic or sounds-like translation for the word. A phonetic translation is based on the SSML format for representing the phonetic string of a word either as an IPA or IBM SPR translation. A sounds-like translation consists of one or more words that, when combined, sound like the word. + :param str part_of_speech: (optional) **Japanese only.** The part of speech for the word. The service uses the value to produce the correct intonation for the word. You can create only a single entry, with or without a single part of speech, for any word; you cannot create multiple entries with different parts of speech for the same word. For more information, see [Working with Japanese entries](https://console.bluemix.net/docs/services/text-to-speech/custom-rules.html#jaNotes). + """ + self.word = word + self.translation = translation + self.part_of_speech = part_of_speech + + @classmethod + def _from_dict(cls, _dict): + """Initialize a CustomWord object from a json dictionary.""" + args = {} + if 'word' in _dict: + args['word'] = _dict['word'] + else: + raise ValueError( + 'Required property \'word\' not present in CustomWord JSON') + if 'translation' in _dict: + args['translation'] = _dict['translation'] + else: + raise ValueError( + 'Required property \'translation\' not present in CustomWord JSON' + ) + if 'part_of_speech' in _dict: + args['part_of_speech'] = _dict['part_of_speech'] + return cls(**args) + + def _to_dict(self): + """Return a json dictionary representing this model.""" + _dict = {} + if hasattr(self, 'word') and self.word is not None: + _dict['word'] = self.word + if hasattr(self, 'translation') and self.translation is not None: + _dict['translation'] = self.translation + if hasattr(self, 'part_of_speech') and self.part_of_speech is not None: + _dict['part_of_speech'] = self.part_of_speech + return _dict + + def __str__(self): + """Return a `str` version of this CustomWord object.""" + return json.dumps(self._to_dict(), indent=2) + + def __eq__(self, other): + """Return `true` when self and other are equal, false otherwise.""" + if not isinstance(other, self.__class__): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Return `true` when self and other are not equal, false otherwise.""" + return not self == other + + +class Pronunciation(object): + """ + Pronunciation. + + :attr str pronunciation: The pronunciation of the requested text in the specified voice and format. + """ + + def __init__(self, pronunciation): + """ + Initialize a Pronunciation object. + + :param str pronunciation: The pronunciation of the requested text in the specified voice and format. + """ + self.pronunciation = pronunciation + + @classmethod + def _from_dict(cls, _dict): + """Initialize a Pronunciation object from a json dictionary.""" + args = {} + if 'pronunciation' in _dict: + args['pronunciation'] = _dict['pronunciation'] + else: + raise ValueError( + 'Required property \'pronunciation\' not present in Pronunciation JSON' + ) + return cls(**args) + + def _to_dict(self): + """Return a json dictionary representing this model.""" + _dict = {} + if hasattr(self, 'pronunciation') and self.pronunciation is not None: + _dict['pronunciation'] = self.pronunciation + return _dict + + def __str__(self): + """Return a `str` version of this Pronunciation object.""" + return json.dumps(self._to_dict(), indent=2) + + def __eq__(self, other): + """Return `true` when self and other are equal, false otherwise.""" + if not isinstance(other, self.__class__): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Return `true` when self and other are not equal, false otherwise.""" + return not self == other + + +class SupportedFeatures(object): + """ + SupportedFeatures. + + :attr bool custom_pronunciation: If `true`, the voice can be customized; if `false`, the voice cannot be customized. (Same as `customizable`.). + :attr bool voice_transformation: If `true`, the voice can be transformed by using the SSML <voice-transformation> element; if `false`, the voice cannot be transformed. + """ + + def __init__(self, custom_pronunciation, voice_transformation): + """ + Initialize a SupportedFeatures object. + + :param bool custom_pronunciation: If `true`, the voice can be customized; if `false`, the voice cannot be customized. (Same as `customizable`.). + :param bool voice_transformation: If `true`, the voice can be transformed by using the SSML <voice-transformation> element; if `false`, the voice cannot be transformed. + """ + self.custom_pronunciation = custom_pronunciation + self.voice_transformation = voice_transformation + + @classmethod + def _from_dict(cls, _dict): + """Initialize a SupportedFeatures object from a json dictionary.""" + args = {} + if 'custom_pronunciation' in _dict: + args['custom_pronunciation'] = _dict['custom_pronunciation'] + else: + raise ValueError( + 'Required property \'custom_pronunciation\' not present in SupportedFeatures JSON' + ) + if 'voice_transformation' in _dict: + args['voice_transformation'] = _dict['voice_transformation'] + else: + raise ValueError( + 'Required property \'voice_transformation\' not present in SupportedFeatures JSON' + ) + return cls(**args) + + def _to_dict(self): + """Return a json dictionary representing this model.""" + _dict = {} + if hasattr(self, 'custom_pronunciation' + ) and self.custom_pronunciation is not None: + _dict['custom_pronunciation'] = self.custom_pronunciation + if hasattr(self, 'voice_transformation' + ) and self.voice_transformation is not None: + _dict['voice_transformation'] = self.voice_transformation + return _dict + + def __str__(self): + """Return a `str` version of this SupportedFeatures object.""" + return json.dumps(self._to_dict(), indent=2) + + def __eq__(self, other): + """Return `true` when self and other are equal, false otherwise.""" + if not isinstance(other, self.__class__): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Return `true` when self and other are not equal, false otherwise.""" + return not self == other + + +class Translation(object): + """ + Translation. + + :attr str translation: The phonetic or sounds-like translation for the word. A phonetic translation is based on the SSML format for representing the phonetic string of a word either as an IPA translation or as an IBM SPR translation. A sounds-like is one or more words that, when combined, sound like the word. + :attr str part_of_speech: (optional) **Japanese only.** The part of speech for the word. The service uses the value to produce the correct intonation for the word. You can create only a single entry, with or without a single part of speech, for any word; you cannot create multiple entries with different parts of speech for the same word. For more information, see [Working with Japanese entries](https://console.bluemix.net/docs/services/text-to-speech/custom-rules.html#jaNotes). + """ + + def __init__(self, translation, part_of_speech=None): + """ + Initialize a Translation object. + + :param str translation: The phonetic or sounds-like translation for the word. A phonetic translation is based on the SSML format for representing the phonetic string of a word either as an IPA translation or as an IBM SPR translation. A sounds-like is one or more words that, when combined, sound like the word. + :param str part_of_speech: (optional) **Japanese only.** The part of speech for the word. The service uses the value to produce the correct intonation for the word. You can create only a single entry, with or without a single part of speech, for any word; you cannot create multiple entries with different parts of speech for the same word. For more information, see [Working with Japanese entries](https://console.bluemix.net/docs/services/text-to-speech/custom-rules.html#jaNotes). + """ + self.translation = translation + self.part_of_speech = part_of_speech + + @classmethod + def _from_dict(cls, _dict): + """Initialize a Translation object from a json dictionary.""" + args = {} + if 'translation' in _dict: + args['translation'] = _dict['translation'] + else: + raise ValueError( + 'Required property \'translation\' not present in Translation JSON' + ) + if 'part_of_speech' in _dict: + args['part_of_speech'] = _dict['part_of_speech'] + return cls(**args) + + def _to_dict(self): + """Return a json dictionary representing this model.""" + _dict = {} + if hasattr(self, 'translation') and self.translation is not None: + _dict['translation'] = self.translation + if hasattr(self, 'part_of_speech') and self.part_of_speech is not None: + _dict['part_of_speech'] = self.part_of_speech + return _dict + + def __str__(self): + """Return a `str` version of this Translation object.""" + return json.dumps(self._to_dict(), indent=2) + + def __eq__(self, other): + """Return `true` when self and other are equal, false otherwise.""" + if not isinstance(other, self.__class__): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Return `true` when self and other are not equal, false otherwise.""" + return not self == other + + +class Voice(object): + """ + Voice. + + :attr str url: The URI of the voice. + :attr str gender: The gender of the voice: `male` or `female`. + :attr str name: The name of the voice. Use this as the voice identifier in all requests. + :attr str language: The language and region of the voice (for example, `en-US`). + :attr str description: A textual description of the voice. + :attr bool customizable: If `true`, the voice can be customized; if `false`, the voice cannot be customized. (Same as `custom_pronunciation`; maintained for backward compatibility.). + :attr SupportedFeatures supported_features: Describes the additional service features supported with the voice. + :attr VoiceModel customization: (optional) Returns information about a specified custom voice model. **Note:** This field is returned only when you list information about a specific voice and specify the GUID of a custom voice model that is based on that voice. + """ + + def __init__(self, + url, + gender, + name, + language, + description, + customizable, + supported_features, + customization=None): + """ + Initialize a Voice object. + + :param str url: The URI of the voice. + :param str gender: The gender of the voice: `male` or `female`. + :param str name: The name of the voice. Use this as the voice identifier in all requests. + :param str language: The language and region of the voice (for example, `en-US`). + :param str description: A textual description of the voice. + :param bool customizable: If `true`, the voice can be customized; if `false`, the voice cannot be customized. (Same as `custom_pronunciation`; maintained for backward compatibility.). + :param SupportedFeatures supported_features: Describes the additional service features supported with the voice. + :param VoiceModel customization: (optional) Returns information about a specified custom voice model. **Note:** This field is returned only when you list information about a specific voice and specify the GUID of a custom voice model that is based on that voice. + """ + self.url = url + self.gender = gender + self.name = name + self.language = language + self.description = description + self.customizable = customizable + self.supported_features = supported_features + self.customization = customization + + @classmethod + def _from_dict(cls, _dict): + """Initialize a Voice object from a json dictionary.""" + args = {} + if 'url' in _dict: + args['url'] = _dict['url'] + else: + raise ValueError( + 'Required property \'url\' not present in Voice JSON') + if 'gender' in _dict: + args['gender'] = _dict['gender'] + else: + raise ValueError( + 'Required property \'gender\' not present in Voice JSON') + if 'name' in _dict: + args['name'] = _dict['name'] + else: + raise ValueError( + 'Required property \'name\' not present in Voice JSON') + if 'language' in _dict: + args['language'] = _dict['language'] + else: + raise ValueError( + 'Required property \'language\' not present in Voice JSON') + if 'description' in _dict: + args['description'] = _dict['description'] + else: + raise ValueError( + 'Required property \'description\' not present in Voice JSON') + if 'customizable' in _dict: + args['customizable'] = _dict['customizable'] + else: + raise ValueError( + 'Required property \'customizable\' not present in Voice JSON') + if 'supported_features' in _dict: + args['supported_features'] = SupportedFeatures._from_dict( + _dict['supported_features']) + else: + raise ValueError( + 'Required property \'supported_features\' not present in Voice JSON' + ) + if 'customization' in _dict: + args['customization'] = VoiceModel._from_dict( + _dict['customization']) + return cls(**args) + + def _to_dict(self): + """Return a json dictionary representing this model.""" + _dict = {} + if hasattr(self, 'url') and self.url is not None: + _dict['url'] = self.url + if hasattr(self, 'gender') and self.gender is not None: + _dict['gender'] = self.gender + if hasattr(self, 'name') and self.name is not None: + _dict['name'] = self.name + if hasattr(self, 'language') and self.language is not None: + _dict['language'] = self.language + if hasattr(self, 'description') and self.description is not None: + _dict['description'] = self.description + if hasattr(self, 'customizable') and self.customizable is not None: + _dict['customizable'] = self.customizable + if hasattr( + self, + 'supported_features') and self.supported_features is not None: + _dict['supported_features'] = self.supported_features._to_dict() + if hasattr(self, 'customization') and self.customization is not None: + _dict['customization'] = self.customization._to_dict() + return _dict + + def __str__(self): + """Return a `str` version of this Voice object.""" + return json.dumps(self._to_dict(), indent=2) + + def __eq__(self, other): + """Return `true` when self and other are equal, false otherwise.""" + if not isinstance(other, self.__class__): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Return `true` when self and other are not equal, false otherwise.""" + return not self == other + + +class VoiceModel(object): + """ + VoiceModel. + + :attr str customization_id: The customization ID (GUID) of the custom voice model. **Note:** When you create a new custom voice model, the service returns only the GUID of the new custom model; it does not return the other fields of this object. + :attr str name: (optional) The name of the custom voice model. + :attr str language: (optional) The language identifier of the custom voice model (for example, `en-US`). + :attr str owner: (optional) The GUID of the service credentials for the instance of the service that owns the custom voice model. + :attr str created: (optional) The date and time in Coordinated Universal Time (UTC) at which the custom voice model was created. The value is provided in full ISO 8601 format (`YYYY-MM-DDThh:mm:ss.sTZD`). + :attr str last_modified: (optional) The date and time in Coordinated Universal Time (UTC) at which the custom voice model was last modified. Equals `created` when a new voice model is first added but has yet to be updated. The value is provided in full ISO 8601 format (`YYYY-MM-DDThh:mm:ss.sTZD`). + :attr str description: (optional) The description of the custom voice model. + :attr list[Word] words: (optional) An array of words and their translations from the custom voice model. The words are listed in alphabetical order, with uppercase letters listed before lowercase letters. The array is empty if the custom model contains no words. **Note:** This field is returned only when you list information about a specific custom voice model. + """ + + def __init__(self, + customization_id, + name=None, + language=None, + owner=None, + created=None, + last_modified=None, + description=None, + words=None): + """ + Initialize a VoiceModel object. + + :param str customization_id: The customization ID (GUID) of the custom voice model. **Note:** When you create a new custom voice model, the service returns only the GUID of the new custom model; it does not return the other fields of this object. + :param str name: (optional) The name of the custom voice model. + :param str language: (optional) The language identifier of the custom voice model (for example, `en-US`). + :param str owner: (optional) The GUID of the service credentials for the instance of the service that owns the custom voice model. + :param str created: (optional) The date and time in Coordinated Universal Time (UTC) at which the custom voice model was created. The value is provided in full ISO 8601 format (`YYYY-MM-DDThh:mm:ss.sTZD`). + :param str last_modified: (optional) The date and time in Coordinated Universal Time (UTC) at which the custom voice model was last modified. Equals `created` when a new voice model is first added but has yet to be updated. The value is provided in full ISO 8601 format (`YYYY-MM-DDThh:mm:ss.sTZD`). + :param str description: (optional) The description of the custom voice model. + :param list[Word] words: (optional) An array of words and their translations from the custom voice model. The words are listed in alphabetical order, with uppercase letters listed before lowercase letters. The array is empty if the custom model contains no words. **Note:** This field is returned only when you list information about a specific custom voice model. + """ + self.customization_id = customization_id + self.name = name + self.language = language + self.owner = owner + self.created = created + self.last_modified = last_modified + self.description = description + self.words = words + + @classmethod + def _from_dict(cls, _dict): + """Initialize a VoiceModel object from a json dictionary.""" + args = {} + if 'customization_id' in _dict: + args['customization_id'] = _dict['customization_id'] + else: + raise ValueError( + 'Required property \'customization_id\' not present in VoiceModel JSON' + ) + if 'name' in _dict: + args['name'] = _dict['name'] + if 'language' in _dict: + args['language'] = _dict['language'] + if 'owner' in _dict: + args['owner'] = _dict['owner'] + if 'created' in _dict: + args['created'] = _dict['created'] + if 'last_modified' in _dict: + args['last_modified'] = _dict['last_modified'] + if 'description' in _dict: + args['description'] = _dict['description'] + if 'words' in _dict: + args['words'] = [Word._from_dict(x) for x in _dict['words']] + return cls(**args) + + def _to_dict(self): + """Return a json dictionary representing this model.""" + _dict = {} + if hasattr(self, + 'customization_id') and self.customization_id is not None: + _dict['customization_id'] = self.customization_id + if hasattr(self, 'name') and self.name is not None: + _dict['name'] = self.name + if hasattr(self, 'language') and self.language is not None: + _dict['language'] = self.language + if hasattr(self, 'owner') and self.owner is not None: + _dict['owner'] = self.owner + if hasattr(self, 'created') and self.created is not None: + _dict['created'] = self.created + if hasattr(self, 'last_modified') and self.last_modified is not None: + _dict['last_modified'] = self.last_modified + if hasattr(self, 'description') and self.description is not None: + _dict['description'] = self.description + if hasattr(self, 'words') and self.words is not None: + _dict['words'] = [x._to_dict() for x in self.words] + return _dict + + def __str__(self): + """Return a `str` version of this VoiceModel object.""" + return json.dumps(self._to_dict(), indent=2) + + def __eq__(self, other): + """Return `true` when self and other are equal, false otherwise.""" + if not isinstance(other, self.__class__): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Return `true` when self and other are not equal, false otherwise.""" + return not self == other + + +class VoiceModels(object): + """ + VoiceModels. + + :attr list[VoiceModel] customizations: An array of `VoiceModel` objects that provides information about each available custom voice model. The array is empty if the requesting service credentials own no custom voice models (if no language is specified) or own no custom voice models for the specified language. + """ + + def __init__(self, customizations): + """ + Initialize a VoiceModels object. + + :param list[VoiceModel] customizations: An array of `VoiceModel` objects that provides information about each available custom voice model. The array is empty if the requesting service credentials own no custom voice models (if no language is specified) or own no custom voice models for the specified language. + """ + self.customizations = customizations + + @classmethod + def _from_dict(cls, _dict): + """Initialize a VoiceModels object from a json dictionary.""" + args = {} + if 'customizations' in _dict: + args['customizations'] = [ + VoiceModel._from_dict(x) for x in _dict['customizations'] + ] + else: + raise ValueError( + 'Required property \'customizations\' not present in VoiceModels JSON' + ) + return cls(**args) + + def _to_dict(self): + """Return a json dictionary representing this model.""" + _dict = {} + if hasattr(self, 'customizations') and self.customizations is not None: + _dict['customizations'] = [ + x._to_dict() for x in self.customizations + ] + return _dict + + def __str__(self): + """Return a `str` version of this VoiceModels object.""" + return json.dumps(self._to_dict(), indent=2) + + def __eq__(self, other): + """Return `true` when self and other are equal, false otherwise.""" + if not isinstance(other, self.__class__): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Return `true` when self and other are not equal, false otherwise.""" + return not self == other + + +class Voices(object): + """ + Voices. + + :attr list[Voice] voices: A list of available voices. + """ + + def __init__(self, voices): + """ + Initialize a Voices object. + + :param list[Voice] voices: A list of available voices. + """ + self.voices = voices + + @classmethod + def _from_dict(cls, _dict): + """Initialize a Voices object from a json dictionary.""" + args = {} + if 'voices' in _dict: + args['voices'] = [Voice._from_dict(x) for x in _dict['voices']] + else: + raise ValueError( + 'Required property \'voices\' not present in Voices JSON') + return cls(**args) + + def _to_dict(self): + """Return a json dictionary representing this model.""" + _dict = {} + if hasattr(self, 'voices') and self.voices is not None: + _dict['voices'] = [x._to_dict() for x in self.voices] + return _dict + + def __str__(self): + """Return a `str` version of this Voices object.""" + return json.dumps(self._to_dict(), indent=2) + + def __eq__(self, other): + """Return `true` when self and other are equal, false otherwise.""" + if not isinstance(other, self.__class__): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Return `true` when self and other are not equal, false otherwise.""" + return not self == other + + +class Word(object): + """ + Word. + + :attr str word: A word from the custom voice model. + :attr str translation: The phonetic or sounds-like translation for the word. A phonetic translation is based on the SSML format for representing the phonetic string of a word either as an IPA or IBM SPR translation. A sounds-like translation consists of one or more words that, when combined, sound like the word. + :attr str part_of_speech: (optional) **Japanese only.** The part of speech for the word. The service uses the value to produce the correct intonation for the word. You can create only a single entry, with or without a single part of speech, for any word; you cannot create multiple entries with different parts of speech for the same word. For more information, see [Working with Japanese entries](https://console.bluemix.net/docs/services/text-to-speech/custom-rules.html#jaNotes). + """ + + def __init__(self, word, translation, part_of_speech=None): + """ + Initialize a Word object. + + :param str word: A word from the custom voice model. + :param str translation: The phonetic or sounds-like translation for the word. A phonetic translation is based on the SSML format for representing the phonetic string of a word either as an IPA or IBM SPR translation. A sounds-like translation consists of one or more words that, when combined, sound like the word. + :param str part_of_speech: (optional) **Japanese only.** The part of speech for the word. The service uses the value to produce the correct intonation for the word. You can create only a single entry, with or without a single part of speech, for any word; you cannot create multiple entries with different parts of speech for the same word. For more information, see [Working with Japanese entries](https://console.bluemix.net/docs/services/text-to-speech/custom-rules.html#jaNotes). + """ + self.word = word + self.translation = translation + self.part_of_speech = part_of_speech + + @classmethod + def _from_dict(cls, _dict): + """Initialize a Word object from a json dictionary.""" + args = {} + if 'word' in _dict: + args['word'] = _dict['word'] + else: + raise ValueError( + 'Required property \'word\' not present in Word JSON') + if 'translation' in _dict: + args['translation'] = _dict['translation'] + else: + raise ValueError( + 'Required property \'translation\' not present in Word JSON') + if 'part_of_speech' in _dict: + args['part_of_speech'] = _dict['part_of_speech'] + return cls(**args) + + def _to_dict(self): + """Return a json dictionary representing this model.""" + _dict = {} + if hasattr(self, 'word') and self.word is not None: + _dict['word'] = self.word + if hasattr(self, 'translation') and self.translation is not None: + _dict['translation'] = self.translation + if hasattr(self, 'part_of_speech') and self.part_of_speech is not None: + _dict['part_of_speech'] = self.part_of_speech + return _dict + + def __str__(self): + """Return a `str` version of this Word object.""" + return json.dumps(self._to_dict(), indent=2) + + def __eq__(self, other): + """Return `true` when self and other are equal, false otherwise.""" + if not isinstance(other, self.__class__): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Return `true` when self and other are not equal, false otherwise.""" + return not self == other + + +class Words(object): + """ + Words. + + :attr list[Word] words: An array of words and their translations from the custom voice model. The words are listed in alphabetical order, with uppercase letters listed before lowercase letters. The array is empty if the custom model contains no words. + """ + + def __init__(self, words): + """ + Initialize a Words object. + + :param list[Word] words: An array of words and their translations from the custom voice model. The words are listed in alphabetical order, with uppercase letters listed before lowercase letters. The array is empty if the custom model contains no words. + """ + self.words = words + + @classmethod + def _from_dict(cls, _dict): + """Initialize a Words object from a json dictionary.""" + args = {} + if 'words' in _dict: + args['words'] = [Word._from_dict(x) for x in _dict['words']] + else: + raise ValueError( + 'Required property \'words\' not present in Words JSON') + return cls(**args) + + def _to_dict(self): + """Return a json dictionary representing this model.""" + _dict = {} + if hasattr(self, 'words') and self.words is not None: + _dict['words'] = [x._to_dict() for x in self.words] + return _dict + + def __str__(self): + """Return a `str` version of this Words object.""" + return json.dumps(self._to_dict(), indent=2) + + def __eq__(self, other): + """Return `true` when self and other are equal, false otherwise.""" + if not isinstance(other, self.__class__): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Return `true` when self and other are not equal, false otherwise.""" + return not self == other diff --git a/watson_developer_cloud/utils.py b/watson_developer_cloud/utils.py index f7abf8d51..92ac98bf5 100644 --- a/watson_developer_cloud/utils.py +++ b/watson_developer_cloud/utils.py @@ -3,10 +3,10 @@ def deprecated(message): def deprecated_decorator(func): def deprecated_func(*args, **kwargs): + warnings.simplefilter('always', DeprecationWarning) warnings.warn("{} is a deprecated function. {}".format(func.__name__, message), category=DeprecationWarning, stacklevel=2) - warnings.simplefilter('default', DeprecationWarning) return func(*args, **kwargs) return deprecated_func return deprecated_decorator \ No newline at end of file