8 |
9 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md
2 | include LICENSE
3 |
4 | recursive-include examples *.py *.md
5 | recursive-include watson_developer_cloud *.py *.md
6 | global-exclude .DS_Store
7 | global-exclude *.pyc
8 |
--------------------------------------------------------------------------------
/resources/tone-example.json:
--------------------------------------------------------------------------------
1 | {
2 | "text": "Team, I know that times are tough! Product sales have been disappointing for the past three quarters. We have a competitive product, but we need to do a better job of selling it!"
3 | }
4 |
--------------------------------------------------------------------------------
/resources/tone-example-html.json:
--------------------------------------------------------------------------------
1 | {
2 | "text": "
Team, I know that times are tough!
Product sales have been disappointing for the past three quarters.
We have a competitive product, but we need to do a better job of selling it!
31 |
39 |
40 | '
41 |
--------------------------------------------------------------------------------
/examples/natural_language_classifier_v1.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import json
3 | import os
4 | # from os.path import join, dirname
5 | from watson_developer_cloud import NaturalLanguageClassifierV1
6 |
7 | # replace with your own classifier_id
8 | classifier_id = 'e552ebx250-nlc-13834'
9 | if os.getenv("natural_language_classifier_classifier_id") is not None:
10 | classifier_id = os.getenv("natural_language_classifier_classifier_id")
11 |
12 | natural_language_classifier = NaturalLanguageClassifierV1(
13 | username='YOUR SERVICE USERNAME',
14 | password='YOUR SERVICE PASSWORD')
15 |
16 | classifiers = natural_language_classifier.list_classifiers()
17 | print(json.dumps(classifiers, indent=2))
18 |
19 | # create a classifier
20 | # with open('../resources/weather_data_train.csv', 'rb') as training_data:
21 | # metadata = json.dumps({'name': 'my-classifier', 'language': 'en'})
22 | # classifier = natural_language_classifier.create_classifier(
23 | # metadata=metadata,
24 | # training_data=training_data
25 | # )
26 | # print(json.dumps(classifier, indent=2))
27 |
28 | status = natural_language_classifier.get_classifier(classifier_id)
29 | print(json.dumps(status, indent=2))
30 |
31 | if status['status'] == 'Available':
32 | classes = natural_language_classifier.classify(classifier_id,
33 | 'How hot will it be '
34 | 'tomorrow?')
35 | print(json.dumps(classes, indent=2))
36 |
37 | # delete = natural_language_classifier.delete_classifier('2374f9x68-nlc-2697')
38 | # print(json.dumps(delete, indent=2))
39 |
40 | # example of raising a ValueError
41 | # print(json.dumps(
42 | # natural_language_classifier.create_classifier(training_data='', name='weather3'),
43 | # indent=2))
44 |
--------------------------------------------------------------------------------
/examples/dialog_v1.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from __future__ import print_function
3 | import json
4 | from watson_developer_cloud import DialogV1
5 |
6 | dialog = DialogV1(
7 | username='YOUR SERVICE USERNAME',
8 | password='YOUR SERVICE PASSWORD')
9 |
10 | print(json.dumps(dialog.get_dialogs(), indent=2))
11 |
12 | # print(json.dumps(dialog.get_dialog('6250d170-41d6-468a-a697-5675578c8012'),
13 | # indent=2))
14 |
15 | # CREATE A DIALOG
16 | # with open(join(dirname(__file__), '../resources/dialog.xml') as dialog_file:
17 | # print(json.dumps(dialog.create_dialog(
18 | # dialog_file=dialog_file, name='pizza_test_9'), indent=2))
19 |
20 | # dialog_id = '98734721-8952-4a1c-bb72-ef9957d4be93'
21 |
22 | # with open(join(dirname(__file__), '../resources/dialog.xml') as dialog_file:
23 | # print(json.dumps(dialog.update_dialog(dialog_file=dialog_file,
24 | # dialog_id=dialog_id), indent=2))
25 |
26 | # print(json.dumps(dialog.get_content(dialog_id), indent=2))
27 | #
28 | # initial_response = dialog.conversation(dialog_id)
29 | #
30 | # print(json.dumps(initial_response, indent=2))
31 | #
32 | # print(json.dumps(dialog.conversation(dialog_id=dialog_id,
33 | # dialog_input='What type of toppings do
34 | # you have?',
35 | # conversation_id=initial_response[
36 | # 'conversation_id'],
37 | # client_id=initial_response['client_id']), indent=2))
38 |
39 | # print(json.dumps(dialog.delete_dialog(
40 | # dialog_id='63b0489c-cd97-45ef-8800-4e7c310eeb19'), indent=2))
41 |
42 | # print(json.dumps(dialog.update_profile(
43 | # dialog_id='6250d170-41d6-468a-a697-5675578c8012', client_id=123,
44 | # name_values=[{'name': 'test', 'value': 'v1'}]),
45 | # indent=2))
46 | #
47 | # print(json.dumps(dialog.get_profile(
48 | # dialog_id='6250d170-41d6-468a-a697-5675578c8012', client_id=123),
49 | # indent=2))
50 |
--------------------------------------------------------------------------------
/examples/text_to_speech_v1.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from __future__ import print_function
3 | import json
4 | from os.path import join, dirname
5 | from watson_developer_cloud import TextToSpeechV1
6 |
7 | text_to_speech = TextToSpeechV1(
8 | username='YOUR SERVICE USERNAME',
9 | password='YOUR SERVICE PASSWORD',
10 | x_watson_learning_opt_out=True) # Optional flag
11 |
12 | print(json.dumps(text_to_speech.voices(), indent=2))
13 |
14 | with open(join(dirname(__file__), '../resources/output.wav'),
15 | 'wb') as audio_file:
16 | audio_file.write(
17 | text_to_speech.synthesize('Hello world!', accept='audio/wav',
18 | voice="en-US_AllisonVoice"))
19 |
20 | print(
21 | json.dumps(text_to_speech.pronunciation(
22 | 'Watson', pronunciation_format='spr'), indent=2))
23 |
24 | print(json.dumps(text_to_speech.customizations(), indent=2))
25 |
26 | # print(json.dumps(text_to_speech.create_customization('test-customization'),
27 | # indent=2))
28 |
29 | # print(text_to_speech.update_customization('YOUR CUSTOMIZATION ID',
30 | # name='new name'))
31 |
32 | # print(json.dumps(text_to_speech.get_customization('YOUR CUSTOMIZATION ID'),
33 | # indent=2))
34 |
35 | # print(json.dumps(text_to_speech.get_customization_words('YOUR CUSTOMIZATION
36 | # ID'), indent=2))
37 |
38 | # print(text_to_speech.add_customization_words('YOUR CUSTOMIZATION ID',
39 | # [{'word': 'resume',
40 | # 'translation': 'rɛzʊmeɪ'}]))
41 |
42 | # print(text_to_speech.set_customization_word('YOUR CUSTOMIZATION ID',
43 | # word='resume',
44 | # translation='rɛzʊmeɪ'))
45 |
46 | # print(json.dumps(text_to_speech.get_customization_word('YOUR CUSTOMIZATION
47 | # ID', 'resume'), indent=2))
48 |
49 | # print(text_to_speech.delete_customization_word('YOUR CUSTOMIZATION ID',
50 | # 'resume'))
51 |
52 | # print(text_to_speech.delete_customization('YOUR CUSTOMIZATION ID'))
53 |
--------------------------------------------------------------------------------
/examples/tone_analyzer_v3.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import json
3 | from os.path import join, dirname
4 | from watson_developer_cloud import ToneAnalyzerV3
5 |
6 | tone_analyzer = ToneAnalyzerV3(
7 | username='YOUR SERVICE USERNAME',
8 | password='YOUR SERVICE PASSWORD',
9 | version='2017-09-26')
10 |
11 | print("\ntone_chat() example 1:\n")
12 | utterances = [{'text': 'I am very happy.', 'user': 'glenn'},
13 | {'text': 'It is a good day.', 'user': 'glenn'}]
14 | print(json.dumps(tone_analyzer.tone_chat(utterances), indent=2))
15 |
16 | print("\ntone() example 1:\n")
17 | print(json.dumps(tone_analyzer.tone(tone_input='I am very happy. It is a good day.',
18 | content_type="text/plain"), indent=2))
19 |
20 | print("\ntone() example 2:\n")
21 | with open(join(dirname(__file__),
22 | '../resources/tone-example.json')) as tone_json:
23 | tone = tone_analyzer.tone(json.load(tone_json)['text'], "text/plain")
24 | print(json.dumps(tone, indent=2))
25 |
26 | print("\ntone() example 3:\n")
27 | with open(join(dirname(__file__),
28 | '../resources/tone-example.json')) as tone_json:
29 | tone = tone_analyzer.tone(tone_input=json.load(tone_json)['text'],
30 | content_type='text/plain', sentences=True)
31 | print(json.dumps(tone, indent=2))
32 |
33 | print("\ntone() example 4:\n")
34 | with open(join(dirname(__file__),
35 | '../resources/tone-example.json')) as tone_json:
36 | tone = tone_analyzer.tone(tone_input=json.load(tone_json),
37 | content_type='application/json')
38 | print(json.dumps(tone, indent=2))
39 |
40 | print("\ntone() example 5:\n")
41 | with open(join(dirname(__file__),
42 | '../resources/tone-example-html.json')) as tone_html:
43 | tone = tone_analyzer.tone(json.load(tone_html)['text'],
44 | content_type='text/html')
45 | print(json.dumps(tone, indent=2))
46 |
--------------------------------------------------------------------------------
/resources/weather_data_train.csv:
--------------------------------------------------------------------------------
1 | How hot is it today?,temperature
2 | Is it hot outside?,temperature
3 | Will it be uncomfortably hot?,temperature
4 | Will it be sweltering?,temperature
5 | How cold is it today?,temperature
6 | Is it cold outside?,temperature
7 | Will it be uncomfortably cold?,temperature
8 | Will it be frigid?,temperature
9 | What is the expected high for today?,temperature
10 | What is the expected temperature?,temperature
11 | Will high temperatures be dangerous?,temperature
12 | Is it dangerously cold?,temperature
13 | When will the heat subside?,temperature
14 | Is it hot?,temperature
15 | Is it cold?,temperature
16 | How cold is it now?,temperature
17 | Will we have a cold day today?,temperature
18 | When will the cold subside?,temperature
19 | What highs are we expecting?,temperature
20 | What lows are we expecting?,temperature
21 | Is it warm?,temperature
22 | Is it chilly?,temperature
23 | What's the current temp in Celsius?,temperature
24 | What is the temperature in Fahrenheit?,temperature
25 | Is it windy?,conditions
26 | Will it rain today?,conditions
27 | What are the chances for rain?,conditions
28 | Will we get snow?,conditions
29 | Are we expecting sunny conditions?,conditions
30 | Is it overcast?,conditions
31 | Will it be cloudy?,conditions
32 | How much rain will fall today?,conditions
33 | How much snow are we expecting?,conditions
34 | Is it windy outside?,conditions
35 | How much snow do we expect?,conditions
36 | Is the forecast calling for snow today?,conditions
37 | Will we see some sun?,conditions
38 | When will the rain subside?,conditions
39 | Is it cloudy?,conditions
40 | Is it sunny now?,conditions
41 | Will it rain?,conditions
42 | Will we have much snow?,conditions
43 | Are the winds dangerous?,conditions
44 | What is the expected snowfall today?,conditions
45 | Will it be dry?,conditions
46 | Will it be breezy?,conditions
47 | Will it be humid?,conditions
48 | What is today's expected humidity?,conditions
49 | Will the blizzard hit us?,conditions
50 | Is it drizzling?,conditions
--------------------------------------------------------------------------------
/watson_developer_cloud/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 IBM All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from .watson_service import WatsonService
16 | from .watson_service import WatsonException
17 | from .watson_service import WatsonApiException
18 | from .watson_service import WatsonInvalidArgument
19 | from .alchemy_data_news_v1 import AlchemyDataNewsV1
20 | from .alchemy_language_v1 import AlchemyLanguageV1
21 | from .alchemy_vision_v1 import AlchemyVisionV1
22 | from .authorization_v1 import AuthorizationV1
23 | from .conversation_v1 import ConversationV1
24 | from .document_conversion_v1 import DocumentConversionV1
25 | from .dialog_v1 import DialogV1
26 | from .language_translation_v2 import LanguageTranslationV2
27 | from .language_translator_v2 import LanguageTranslatorV2
28 | from .natural_language_classifier_v1 import NaturalLanguageClassifierV1
29 | from .natural_language_understanding_v1 import NaturalLanguageUnderstandingV1
30 | from .personality_insights_v2 import PersonalityInsightsV2
31 | from .personality_insights_v3 import PersonalityInsightsV3
32 | from .retrieve_and_rank_v1 import RetrieveAndRankV1
33 | from .speech_to_text_v1 import SpeechToTextV1
34 | from .text_to_speech_v1 import TextToSpeechV1
35 | from .tone_analyzer_v3 import ToneAnalyzerV3
36 | from .tradeoff_analytics_v1 import TradeoffAnalyticsV1
37 | from .visual_recognition_v3 import VisualRecognitionV3
38 | from .discovery_v1 import DiscoveryV1
39 | from .version import __version__
40 |
--------------------------------------------------------------------------------
/resources/speech_to_text/corpus-short-2.txt:
--------------------------------------------------------------------------------
1 | Is there any treatment for Shaken Baby Syndrome
2 | Emergency treatment for a baby who has been shaken usually includes life-sustaining measures such as respiratory support and surgery to stop internal bleeding and bleeding in the brain Doctors may use brain scans such as MRI and CT to make a more definite diagnosis
3 | What is the prognosis for Wernicke-Korsakoff Syndrome
4 | Most symptoms can be reversed if detected and treated promptly However improvement in memory function is slow and usually incomplete Without treatment these disorders can be disabling and life-threatening
5 | Who gets diverticular disease
6 | Many people get diverticular disease Starting at age 40 the chance of getting it increases about every 10 years About half of people between the ages of 60 and 80 have diverticular disease Almost everyone over 80 has it
7 | What is a stoma
8 | During ostomy surgery of the bowel a surgeon creates a stoma by bringing the end of the intestine through an opening in the abdomen and attaching it to the skin to create an opening outside the body A stoma may be three-fourths of an inch to a little less than 2 inches wide The stoma is usually located in the lower part of the abdomen just below the beltline However sometimes the stoma is located in the upper abdomen The surgeon and a wound ostomy and continence WOC nurse or an enterostomal therapist will work together to select the best location for the stoma A removable external collection pouch called an ostomy pouch or ostomy appliance is attached to the stoma and worn outside the body to collect intestinal contents or stool Intestinal contents or stool passes through the stoma instead of passing through the anus The stoma has no muscle so it cannot control the flow of stool and the flow occurs whenever peristalsis occurs Ileostomy and colostomy are the two main types of ostomy surgery of the bowel during which a surgeon creates a stoma
9 | What is A chest x ray
10 | A chest x ray is a painless test that creates pictures of the structures in your chest such as your heart and lungs
11 |
--------------------------------------------------------------------------------
/test/test_examples.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | from __future__ import print_function
4 | import re
5 | import traceback
6 | import pytest
7 | import json as json_import
8 | import os
9 | from os.path import join, dirname
10 | from glob import glob
11 |
12 | # tests to exclude
13 | excludes = ['authorization_v1.py', 'alchemy_data_news_v1.py',
14 | 'alchemy_language_v1.py', 'discovery_v1.ipynb', '__init__.py']
15 |
16 | # examples path. /examples
17 | examples_path = join(dirname(__file__), '../', 'examples', '*.py')
18 |
19 | # environment variables
20 | try:
21 | from dotenv import load_dotenv # pylint: disable=C0413
22 | except:
23 | print ('warning: dotenv module could not be imported')
24 |
25 | try:
26 | dotenv_path = join(dirname(__file__), '../', '.env')
27 | load_dotenv(dotenv_path)
28 | except:
29 | print ('warning: no .env file loaded')
30 |
31 |
32 | @pytest.mark.skipif(os.getenv('VCAP_SERVICES') is None,
33 | reason='requires VCAP_SERVICES')
34 | def test_examples():
35 | vcap_services = json_import.loads(os.getenv('VCAP_SERVICES'))
36 | examples = glob(examples_path)
37 | for example in examples:
38 | name = example.split('/')[-1]
39 |
40 | # exclude some tests cases like authorization
41 | if name in excludes:
42 | continue
43 |
44 | # exclude tests if there are no credentials for that service
45 | service_name = name[:-6] if not name.startswith('visual_recognition')\
46 | else 'watson_vision_combined'
47 |
48 | if service_name not in vcap_services:
49 | print('%s does not have credentials in VCAP_SERVICES',
50 | service_name)
51 | continue
52 |
53 | try:
54 | service_file = open(example).read()
55 | exec(re.sub(r'# coding[:=]\s*utf-8', '', service_file), globals())
56 | except Exception as e:
57 | assert False, 'example in file ' + name + ' failed with error: '\
58 | + str(e) + '\n' + traceback.format_exc()
59 |
--------------------------------------------------------------------------------
/resources/tradeoff-expect2.txt:
--------------------------------------------------------------------------------
1 | {"problem":{"columns":[{"type":"numeric","key":"price","full_name":"Price","range":{"low":0.0,"high":400.0},"format":"number:2","goal":"min","is_objective":true},{"type":"numeric","key":"weight","full_name":"Weight","format":"number:0","goal":"min","is_objective":true},{"type":"categorical","key":"brand","full_name":"Brand","range":["Apple","HTC","Samsung","Sony"],"goal":"min","preference":["Samsung","Apple","HTC"],"is_objective":true},{"type":"datetime","key":"rDate","full_name":"Release Date","format":"date: 'MMM dd, yyyy'","goal":"max","is_objective":false}],"subject":"phones","options":[{"key":"1","name":"Samsung Galaxy S4","values":{"price":249,"weight":130,"brand":"Samsung","rDate":"2013-04-29T00:00:00Z"}},{"key":"2","name":"Apple iPhone 5","values":{"price":349,"weight":112,"brand":"Apple","rDate":"2012-09-21T00:00:00Z"}},{"key":"3","name":"HTC One","values":{"price":299,"weight":112,"brand":"HTC","rDate":"2013-03-01T00:00:00Z"}},{"key":"4","name":"Samsung Galaxy S5","values":{"price":349,"weight":135,"brand":"Samsung","rDate":"2014-04-29T00:00:00Z"}},{"key":"5","name":"Apple iPhone 6","values":{"price":399,"weight":118,"brand":"Apple","rDate":"2013-09-21T00:00:00Z"}},{"key":"6","name":"Apple iPhone 7","values":{"price":499,"weight":118,"brand":"Apple","rDate":"2014-09-21T00:00:00Z"}},{"key":"7","name":"Sony Xperia","values":{"price":199,"weight":120,"brand":"Sony","rDate":"2014-08-21T00:00:00Z"}}]},"resolution":{"solutions":[{"solution_ref":"1","status":"FRONT"},{"solution_ref":"2","status":"FRONT"},{"solution_ref":"3","status":"FRONT"},{"solution_ref":"4","status":"EXCLUDED"},{"solution_ref":"5","status":"EXCLUDED"},{"solution_ref":"6","status":"INCOMPLETE","status_cause":{"message":"A column of a option is out of range. Option \"6\" has a value in column \"price\" which is:\"499\" while the column range\" is: [0.0,400.0]","error_code":"RANGE_MISMATCH","tokens":["price","499","[0.0,400.0]"]}},{"solution_ref":"7","status":"DOES_NOT_MEET_PREFERENCE","status_cause":{"message":"Option \"7\" has a value that does not meet preference for column \"brand\"","error_code":"DOES_NOT_MEET_PREFERENCE","tokens":["brand"]}}]}}
2 |
--------------------------------------------------------------------------------
/watson_developer_cloud/authorization_v1.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 IBM All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """
16 | The v1 Authorization "service" that enables developers to
17 | retrieve a temporary access token
18 | """
19 |
20 | from watson_developer_cloud.watson_service import WatsonService
21 |
22 | try:
23 | import urllib.parse as urlparse # Python 3
24 | except ImportError:
25 | import urlparse # Python 2
26 |
27 |
28 | class AuthorizationV1(WatsonService):
29 | """
30 | Generates tokens, which can be used client-side to avoid exposing the
31 | service credentials.
32 | Tokens are valid for 1 hour and are sent using the
33 | `X-Watson-Authorization-Token` header.
34 | """
35 | default_url = "https://stream.watsonplatform.net/authorization/api"
36 |
37 | def __init__(self, url=default_url,
38 | username=None, password=None, use_vcap_services=True):
39 | WatsonService.__init__(
40 | self, 'authorization', url, username, password, use_vcap_services)
41 |
42 | def get_token(self, url):
43 | """
44 | Retrieves a temporary access token
45 | """
46 | # A hack to avoid url-encoding the url, since the authorization service
47 | # doesn't work with correctly encoded urls
48 |
49 | parsed_url = urlparse.urlsplit(url)
50 | parsed_url = parsed_url._replace(path='/authorization/api')
51 | self.url = urlparse.urlunsplit(parsed_url)
52 |
53 | response = self.request(method='GET', url='/v1/token?url=' + url)
54 | return response.text
55 |
--------------------------------------------------------------------------------
/watson_developer_cloud/tradeoff_analytics_v1.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 IBM All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | The v1 Tradeoff Analytics service
16 | (https://www.ibm.com/watson/developercloud/tradeoff-analytics.html)
17 | """
18 |
19 | from .watson_service import WatsonService
20 |
21 |
22 | class TradeoffAnalyticsV1(WatsonService):
23 | """Wrapper for the Tradeoff Analytics service"""
24 | default_url = 'https://gateway.watsonplatform.net/tradeoff-analytics/api'
25 |
26 | def __init__(self, url=default_url, **kwargs):
27 | WatsonService.__init__(self, 'tradeoff_analytics', url, **kwargs)
28 |
29 | def dilemmas(self, params,
30 | generate_visualization=True,
31 | find_preferable_options=False):
32 | """
33 | :param params: The JSON problem (subject, columns, and options)
34 | :param generate_visualization: If True, returns the map visualization
35 | used by the Tradeoff Analytics widget
36 | :param find_preferable_options: If True, returns a refined subset of
37 | best candidate options that will most likely satisfy the greatest number
38 | of users
39 | :return: A dilemma that contains the problem and its resolution
40 | """
41 |
42 | parameters = {
43 | 'generate_visualization': generate_visualization,
44 | 'find_preferable_options': find_preferable_options
45 | }
46 |
47 | return self.request(method='POST', url='/v1/dilemmas', json=params,
48 | params=parameters, accept_json=True)
49 |
--------------------------------------------------------------------------------
/test/test_document_conversion_v1.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | import os
3 | import responses
4 | import watson_developer_cloud
5 |
6 |
7 | @responses.activate
8 | def test_success():
9 | convert_url = 'https://gateway.watsonplatform.net/document-conversion/api/v1/convert_document'
10 | convert_response = '' \
11 | 'Simple HTML Page' \
12 | '
Chapter 1
The content of the first chapter.
'
13 | document_conversion = watson_developer_cloud.DocumentConversionV1(
14 | username="username", password="password", version='2015-12-15')
15 |
16 | responses.add(responses.POST, convert_url,
17 | body=convert_response, status=200,
18 | content_type='application/json')
19 |
20 | with open(os.path.join(os.path.dirname(__file__), '../resources/simple.html'), 'r') as document:
21 | convertConfig = {'conversion_target': watson_developer_cloud.DocumentConversionV1.NORMALIZED_HTML}
22 | document_conversion.convert_document(document=document, config=convertConfig, media_type='text/html')
23 |
24 | assert responses.calls[0].request.url.startswith(convert_url)
25 | assert responses.calls[0].response.text == convert_response
26 |
27 | index_url = 'https://gateway.watsonplatform.net/document-conversion/api/v1/index_document'
28 | index_response = '{"status": "success"}'
29 |
30 | responses.add(responses.POST, index_url,
31 | body=index_response, status=200,
32 | content_type='application/json')
33 |
34 | with open(os.path.join(os.path.dirname(__file__), '../resources/example.html'), 'r') as document:
35 | indexConfig = {
36 | 'retrieve_and_rank': {
37 | 'dry_run':'false',
38 | 'service_instance_id':'serviceInstanceId',
39 | 'cluster_id':'clusterId',
40 | 'search_collection':'searchCollectionName'
41 | }
42 | }
43 | document_conversion.index_document(config=indexConfig, document=document)
44 |
45 | assert responses.calls[1].request.url.startswith(index_url)
46 | assert responses.calls[1].response.text == index_response
47 |
48 | assert len(responses.calls) == 2
49 |
--------------------------------------------------------------------------------
/watson_developer_cloud/natural_language_understanding/features/v1/__init__.py:
--------------------------------------------------------------------------------
1 | class Feature(object):
2 | def toDict(self):
3 | res = {}
4 | if not hasattr(self, "_dataTuples"):
5 | return res
6 |
7 | for t in self._dataTuples:
8 | self.addKey(t[0], t[1], res)
9 | return res
10 |
11 | def name(self):
12 | return self._name
13 |
14 | def addKey(self, var, name, data_dict):
15 | if var is not None:
16 | data_dict[name] = var
17 | return data_dict
18 |
19 |
20 | class Concepts(Feature):
21 | def __init__(self, limit=None):
22 | self._dataTuples = [(limit, "limit")]
23 | self._name = 'concepts'
24 |
25 |
26 | class Entities(Feature):
27 | def __init__(self, limit=None, model=None, emotion=None, sentiment=None):
28 | self._dataTuples = [(limit, "limit"), (model, "model"),
29 | (emotion, "emotion"), (sentiment, "sentiment")]
30 | self._name = 'entities'
31 |
32 |
33 | class Keywords(Feature):
34 | def __init__(self, limit=None, emotion=None, sentiment=None):
35 | self._dataTuples = [(limit, "limit"), (emotion, "emotion"),
36 | (sentiment, "sentiment")]
37 | self._name = 'keywords'
38 |
39 |
40 | class Categories(Feature):
41 | def __init__(self):
42 | self._name = 'categories'
43 |
44 |
45 | class Emotion(Feature):
46 | def __init__(self, document=None, targets=None):
47 | self._dataTuples = [(document, "document"), (targets, "targets")]
48 | self._name = 'emotion'
49 |
50 |
51 | class MetaData(Feature):
52 | def __init__(self):
53 | self._name = "metadata"
54 |
55 |
56 | class SemanticRoles(Feature):
57 | def __init__(self, limit=None, entities=None, keywords=None):
58 | self._dataTuples = [(limit, "limit"), (entities, "entities"),
59 | (keywords, "keywords")]
60 | self._name = "semantic_roles"
61 |
62 |
63 | class Relations(Feature):
64 | def __init__(self, model=None):
65 | self._dataTuples = [(model, "model")]
66 | self._name = 'relations'
67 |
68 |
69 | class Sentiment(Feature):
70 | def __init__(self, document=None, targets=None):
71 | self._dataTuples = [(document, "document"), (targets, "targets")]
72 | self._name = 'sentiment'
73 |
--------------------------------------------------------------------------------
/examples/conversation_tone_analyzer_integration/README.md:
--------------------------------------------------------------------------------
1 | # Conversation and Tone Analyzer Integration Example
2 |
3 | This example provides sample code for integrating [Tone Analyzer][tone_analyzer] and [Conversation][conversation] in Python 2.6+. All calls are made synchronously. For sample Python 3.5 asynchronous code, please see [https://github.com/aprilwebster/python-sdk][aprilwebster_python_sdk_github].
4 |
5 | * [tone_detection.py][tone_conversation_integration_example_tone_detection] - sample code to initialize a user object in the conversation payload's context (initUser), to call Tone Analyzer to retrieve tone for a user's input (invokeToneAsync), and to update tone in the user object in the conversation payload's context (updateUserTone).
6 |
7 | * [tone_conversation_integration.v1.py][tone_conversation_integration_example] - sample code to use tone_detection.py to get and add tone to the payload and send a request to the Conversation Service's message endpoint both in a synchronous and asynchronous manner.
8 |
9 |
10 | Requirements to run the sample code
11 |
12 | * [Tone Analyzer Service credentials][ibm_cloud_tone_analyzer_service]
13 | * [Conversation Service credentials][ibm_cloud_conversation_service]
14 | * [Conversation Workspace ID][conversation_simple_workspace]
15 |
16 | Credentials & the Workspace ID can be set in environment properties, a .env file, or directly in the code.
17 |
18 | Dependencies provided in
19 | `init.py`
20 |
21 | Command to run the sample code
22 |
23 | `python tone_conversation_integration.v1.py`
24 |
25 | [conversation]: https://www.ibm.com/watson/developercloud/conversation.html
26 | [tone_analyzer]: http://www.ibm.com/watson/developercloud/tone-analyzer.html
27 | [ibm_cloud_conversation_service]: https://console.ng.bluemix.net/catalog/services/conversation/
28 | [ibm_cloud_tone_analyzer_service]: https://console.ng.bluemix.net/catalog/services/tone-analyzer/
29 | [conversation_simple_workspace]: https://github.com/watson-developer-cloud/conversation-simple#workspace
30 | [tone_conversation_integration_example]: https://github.com/watson-developer-cloud/python-sdk/tree/master/examples/tone_conversation_integration.v1.py
31 | [tone_conversation_integration_example_tone_detection]: https://github.com/watson-developer-cloud/python-sdk/tree/master/examples/conversation_addons/tone_detection.py
32 | [aprilwebster_python_sdk_github]: https://github.com/aprilwebster/python-sdk
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Questions
4 |
5 | If you are having difficulties using the APIs or have a question about the IBM Watson Services,
6 | please ask a question on [dW Answers][dw] or [Stack Overflow][stackoverflow].
7 |
8 | ## Issues
9 |
10 | If you encounter an issue with the Python SDK, you are welcome to submit a [bug report](https://github.com/watson-developer-cloud/python-sdk/issues).
11 | Before that, please search for similar issues. It's possible somebody has encountered this issue already.
12 |
13 | ## Pull Requests
14 |
15 | If you want to contribute to the repository, here's a quick guide:
16 |
17 | 1. Fork the repository
18 | 1. Install `virtualenv` and `tox`
19 | 1. Develop and test your code changes with [pytest].
20 | * Respect the original code [style guide][styleguide].
21 | * Only use spaces for indentation.
22 | * Create minimal diffs - disable on save actions like reformat source code or organize imports. If you feel the source code should be reformatted create a separate PR for this change.
23 | * Check for unnecessary whitespace with `git diff --check` before committing.
24 | * Make sure your code supports Python 2.7, 3.4, 3.5 and 3.6. You can use `pyenv` and `tox` for this
25 | 1. Make the test pass
26 | 1. Commit your changes
27 | 1. Push to your fork and submit a pull request to the `dev` branch
28 |
29 | ## Running the tests
30 |
31 | You probably want to set up a [virtualenv].
32 |
33 | 1. Clone this repository:
34 | ```sh
35 | git clone https://github.com/watson-developer-cloud/python-sdk.git
36 | ```
37 | 1. Install the sdk as an editable package using the current source:
38 | ```sh
39 | pip install --editable .
40 | ```
41 | 1. Install the test dependencies with:
42 | ```sh
43 | pip install -r requirements-dev.txt
44 | ```
45 | 1. Run the test cases with:
46 | ```sh
47 | py.test test
48 | ```
49 |
50 | ## Additional Resources
51 |
52 | * [General GitHub documentation](https://help.github.com/)
53 | * [GitHub pull request documentation](https://help.github.com/send-pull-requests/)
54 |
55 | [dw]: https://developer.ibm.com/answers/questions/ask/?topics=watson
56 | [stackoverflow]: http://stackoverflow.com/questions/ask?tags=ibm-watson
57 | [styleguide]: http://google.github.io/styleguide/pyguide.html
58 | [pytest]: http://pytest.org/latest/
59 | [virtualenv]: http://virtualenv.readthedocs.org/en/latest/index.html
60 |
--------------------------------------------------------------------------------
/examples/visual_recognition_v3.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import json
3 | from os.path import join, dirname
4 | from watson_developer_cloud import VisualRecognitionV3
5 |
6 | test_url = 'https://www.ibm.com/ibm/ginni/images' \
7 | '/ginni_bio_780x981_v4_03162016.jpg'
8 |
9 | visual_recognition = VisualRecognitionV3('2016-05-20', api_key='YOUR API KEY')
10 |
11 | # with open(join(dirname(__file__), '../resources/cars.zip'), 'rb') as cars, \
12 | # open(join(dirname(__file__), '../resources/trucks.zip'), 'rb') as
13 | # trucks:
14 | # print(json.dumps(visual_recognition.create_classifier('Cars vs Trucks',
15 | # cars_positive_examples=cars,
16 | #
17 | # negative_examples=trucks), indent=2))
18 |
19 | car_path = join(dirname(__file__), '../resources/cars.zip')
20 | with open(car_path, 'rb') as images_file:
21 | parameters = json.dumps({'threshold': 0.1, 'classifier_ids': ['CarsvsTrucks_1479118188', 'default']})
22 | car_results = visual_recognition.classify(images_file=images_file,
23 | parameters=parameters)
24 | print(json.dumps(car_results, indent=2))
25 |
26 | # print(json.dumps(visual_recognition.get_classifier('YOUR CLASSIFIER ID'),
27 | # indent=2))
28 |
29 | # with open(join(dirname(__file__), '../resources/car.jpg'), 'rb') as
30 | # image_file:
31 | # print(json.dumps(visual_recognition.update_classifier(
32 | # 'CarsvsTrucks_1479118188',
33 | #
34 | # cars_positive_examples=image_file), indent=2))
35 |
36 | url_result = visual_recognition.classify(parameters=json.dumps({'url': test_url}))
37 | print(json.dumps(url_result, indent=2))
38 |
39 | faces_result = visual_recognition.detect_faces(parameters=json.dumps({'url': test_url}))
40 | print(json.dumps(faces_result, indent=2))
41 |
42 | # print(json.dumps(visual_recognition.delete_classifier(classifier_id='YOUR
43 | # CLASSIFIER ID'), indent=2))
44 |
45 | print(json.dumps(visual_recognition.list_classifiers(), indent=2))
46 |
47 | #file_path = join(dirname(__file__), '../resources/text.png')
48 | #with open(file_path, 'rb') as image_file:
49 | # text_results = visual_recognition.recognize_text(images_file=image_file)
50 | # print(json.dumps(text_results, indent=2))
51 |
52 | face_path = join(dirname(__file__), '../resources/face.jpg')
53 | with open(face_path, 'rb') as image_file:
54 | face_result = visual_recognition.detect_faces(images_file=image_file)
55 | print(json.dumps(face_result, indent=2))
56 |
--------------------------------------------------------------------------------
/watson_developer_cloud/alchemy_vision_v1.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 IBM All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | The AlchemyAPI Vision service
16 | (https://www.ibm.com/watson/developercloud/visual-recognition.html)
17 | """
18 | from __future__ import print_function
19 | from .watson_service import WatsonService
20 |
21 |
22 | class AlchemyVisionV1(WatsonService):
23 | """AlchemyVision was deprecated, migrate your application to use
24 | VisualRecognition."""
25 | default_url = 'https://gateway-a.watsonplatform.net/calls'
26 |
27 | def __init__(self, url=default_url, **kwargs):
28 | WatsonService.__init__(self, 'alchemy_api', url, **kwargs)
29 | print(
30 | 'WARNING: The AlchemyVision service was deprecated, '
31 | 'use VisualRecognitionV3 instead')
32 |
33 | def get_image_keywords(self, image_file=None, image_url=None,
34 | knowledge_graph=False, force_show_all=False):
35 | method_name = 'GetRankedImageKeywords'
36 | params = {'knowledgeGraph': knowledge_graph,
37 | 'forceShowAll': force_show_all}
38 | return self._alchemy_image_request(method_name, image_file, image_url,
39 | params)
40 |
41 | def recognize_faces(self, image_file=None, image_url=None,
42 | knowledge_graph=False):
43 | method_name = 'GetRankedImageFaceTags'
44 | params = {'knowledgeGraph': knowledge_graph}
45 | return self._alchemy_image_request(method_name, image_file, image_url,
46 | params)
47 |
48 | def get_image_scene_text(self, image_file=None, image_url=None):
49 | method_name = 'GetRankedImageSceneText'
50 | return self._alchemy_image_request(method_name, image_file, image_url)
51 |
52 | def get_image_links(self, url=None, html=None):
53 | method_name = 'GetImage'
54 | return self._alchemy_html_request(method_name, url=url, html=html)
55 |
--------------------------------------------------------------------------------
/watson_developer_cloud/personality_insights_v2.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 IBM All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | The v2 Personality Insights service
16 | (https://www.ibm.com/watson/developercloud/personality-insights.html)
17 | """
18 |
19 | import json
20 | from .watson_service import WatsonService
21 |
22 |
23 | class PersonalityInsightsV2(WatsonService):
24 | """Wrapper of the Personality Insights service"""
25 | default_url = 'https://gateway.watsonplatform.net/personality-insights/api'
26 |
27 | def __init__(self, url=default_url, **kwargs):
28 | """
29 | Construct an instance. Fetches service parameters from VCAP_SERVICES
30 | runtime variable for Bluemix, or it defaults to local URLs.
31 | """
32 |
33 | WatsonService.__init__(
34 | self, 'personality_insights', url, **kwargs)
35 |
36 | def profile(self, text, content_type='text/plain',
37 | accept='application/json', language=None, csv_headers=False):
38 | """
39 | Returns a personality profile given input text (at least 100 unique
40 | words)
41 | content_type can be 'text/plain', 'application/json' or 'text/html'
42 | if accept is set to 'text/csv', returns csv output (with a header row
43 | if csv_headers is set to True)
44 | """
45 |
46 | if isinstance(text, dict):
47 | text = json.dumps(text)
48 | content_type = 'application/json'
49 |
50 | headers = {'content-type': content_type, 'accept': accept}
51 |
52 | if language:
53 | headers['content-language'] = language
54 |
55 | params = {}
56 | if accept == 'text/csv' and csv_headers:
57 | params['headers'] = 'true'
58 |
59 | response = self.request(
60 | method='POST', url='/v2/profile', data=text, params=params,
61 | headers=headers)
62 | if accept == 'application/json':
63 | return response.json()
64 | return response.text
65 |
--------------------------------------------------------------------------------
/resources/tradeoff-expect3.txt:
--------------------------------------------------------------------------------
1 | {"resolution": {"preferable_solutions": {"solution_refs": ["1", "2"], "score": 0.94}, "solutions": [{"solution_ref": "1", "status": "FRONT"}, {"solution_ref": "2", "status": "FRONT"}, {"solution_ref": "3", "status": "FRONT"}, {"excluded_by": [{"solution_ref": "1", "objectives": [{"key": "price", "difference": 100.0}, {"key": "weight", "difference": 5.0}]}], "solution_ref": "4", "status": "EXCLUDED"}, {"excluded_by": [{"solution_ref": "2", "objectives": [{"key": "price", "difference": 50.0}, {"key": "weight", "difference": 6.0}]}], "solution_ref": "5", "status": "EXCLUDED"}, {"solution_ref": "6", "status": "INCOMPLETE", "status_cause": {"error_code": "RANGE_MISMATCH", "tokens": ["price", "499", "[0.0,400.0]"], "message": "A column of a option is out of range. Option \"6\" has a value in column \"price\" which is:\"499\" while the column range\" is: [0.0,400.0]"}}, {"solution_ref": "7", "status": "DOES_NOT_MEET_PREFERENCE", "status_cause": {"error_code": "DOES_NOT_MEET_PREFERENCE", "tokens": ["brand"], "message": "Option \"7\" has a value that does not meet preference for column \"brand\""}}]}, "problem": {"options": [{"values": {"rDate": "2013-04-29T00:00:00Z", "price": 249, "weight": 130, "brand": "Samsung"}, "key": "1", "name": "Samsung Galaxy S4"}, {"values": {"rDate": "2012-09-21T00:00:00Z", "price": 349, "weight": 112, "brand": "Apple"}, "key": "2", "name": "Apple iPhone 5"}, {"values": {"rDate": "2013-03-01T00:00:00Z", "price": 299, "weight": 112, "brand": "HTC"}, "key": "3", "name": "HTC One"}, {"values": {"rDate": "2014-04-29T00:00:00Z", "price": 349, "weight": 135, "brand": "Samsung"}, "key": "4", "name": "Samsung Galaxy S5"}, {"values": {"rDate": "2013-09-21T00:00:00Z", "price": 399, "weight": 118, "brand": "Apple"}, "key": "5", "name": "Apple iPhone 6"}, {"values": {"rDate": "2014-09-21T00:00:00Z", "price": 499, "weight": 118, "brand": "Apple"}, "key": "6", "name": "Apple iPhone 7"}, {"values": {"rDate": "2014-08-21T00:00:00Z", "price": 199, "weight": 120, "brand": "Sony"}, "key": "7", "name": "Sony Xperia"}], "subject": "phones", "columns": [{"goal": "min", "type": "numeric", "format": "number:2", "key": "price", "full_name": "Price", "range": {"low": 0.0, "high": 400.0}, "is_objective": true}, {"goal": "min", "type": "numeric", "format": "number:0", "is_objective": true, "full_name": "Weight", "key": "weight"}, {"goal": "min", "type": "categorical", "key": "brand", "preference": ["Samsung", "Apple", "HTC"], "full_name": "Brand", "range": ["Apple", "HTC", "Samsung", "Sony"], "is_objective": true}, {"goal": "max", "type": "datetime", "format": "date: 'MMM dd, yyyy'", "is_objective": false, "full_name": "Release Date", "key": "rDate"}]}}
--------------------------------------------------------------------------------
/examples/alchemy_language_v1.py:
--------------------------------------------------------------------------------
1 | import json
2 | from watson_developer_cloud import AlchemyLanguageV1
3 |
4 | alchemy_language = AlchemyLanguageV1(api_key='YOUR API KEY')
5 |
6 | url = 'https://developer.ibm.com/watson/blog/2015/11/03/price-reduction-for' \
7 | '-watson-personality-insights/'
8 |
9 | print(json.dumps(
10 | alchemy_language.targeted_sentiment(text='I love cats! Dogs are smelly.',
11 | targets=['cats', 'dogs'],
12 | language='english'), indent=2))
13 | # print(json.dumps(alchemy_language.targeted_emotion(text='I love apples. I
14 | # hate bananas',
15 | # targets=['apples',
16 | # 'bananas'], language='english'), indent=2))
17 |
18 | # print(json.dumps(alchemy_language.author(url=url), indent=2))
19 | # print(json.dumps(alchemy_language.concepts(max_items=2, url=url), indent=2))
20 | # print(json.dumps(alchemy_language.dates(url=url, anchor_date='2016-03-22
21 | # 00:00:00'), indent=2))
22 | # print(json.dumps(alchemy_language.emotion(url=url), indent=2))
23 | # print(json.dumps(alchemy_language.entities(url=url), indent=2))
24 | # print(json.dumps(alchemy_language.keywords(max_items=5, url=url), indent=2))
25 | # print(json.dumps(alchemy_language.category(url=url), indent=2))
26 | # print(json.dumps(alchemy_language.typed_relations(url=url), indent=2))
27 | # print(json.dumps(alchemy_language.relations(url=url), indent=2))
28 | # print(json.dumps(alchemy_language.language(url=url), indent=2))
29 | # print(json.dumps(alchemy_language.text(url=url), indent=2))
30 | # print(json.dumps(alchemy_language.raw_text(url=url), indent=2))
31 | # print(json.dumps(alchemy_language.title(url=url), indent=2))
32 | # print(json.dumps(alchemy_language.feeds(url=url), indent=2))
33 | # print(json.dumps(alchemy_language.microformats(
34 | # url='http://microformats.org/wiki/hcard-examples'), indent=2))
35 | # print(json.dumps(alchemy_language.publication_date(url=url), indent=2))
36 | # print(json.dumps(alchemy_language.taxonomy(url=url), indent=2))
37 | combined_operations = ['page-image', 'entity', 'keyword', 'title', 'author',
38 | 'taxonomy', 'concept', 'doc-emotion']
39 | print(
40 | json.dumps(alchemy_language.combined(url=url, extract=combined_operations),
41 | indent=2))
42 |
43 | # Get sentiment and emotion information results for detected entities/keywords:
44 | # print(json.dumps(alchemy_language.entities(url=url, sentiment=True,
45 | # emotion=True), indent=2))
46 | # print(json.dumps(alchemy_language.keywords(max_items=5, url=url,
47 | # sentiment=True, emotion=True),
48 | # indent=2))
49 |
--------------------------------------------------------------------------------
/test/test_integration_visual_recognition.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import watson_developer_cloud
3 | import os
4 | from os.path import join, dirname
5 | from unittest import TestCase
6 |
7 | pytestmark = pytest.mark.skip('Run These Manually, they are destructive')
8 |
9 | class IntegrationTestVisualRecognitionV3(TestCase):
10 |
11 | def setUp(self):
12 | self.visual_recognition = watson_developer_cloud.VisualRecognitionV3('2016-05-20', api_key=os.environ.get(
13 | 'VISUAL_RECOGNITION_API_KEY'))
14 | self.collections = self.visual_recognition.list_collections()
15 |
16 | collection_json = self.visual_recognition.create_collection(name="test_integration_collection")
17 | self.collection_id = collection_json['collection_id']
18 |
19 | def tearDown(self):
20 | results = self.visual_recognition.delete_collection(collection_id=self.collection_id)
21 | assert not results
22 |
23 | def test_list_collections(self):
24 | results = self.visual_recognition.list_collections()
25 | assert len(results['collections']) - len(self.collections['collections']) == 1
26 |
27 | def test_add_image_check_metadata_delete_image(self):
28 | with open(join(dirname(__file__), '../resources/face.jpg'), 'rb') as image_file:
29 | self.visual_recognition.add_image(collection_id=self.collection_id, image_file=image_file, metadata={'name': 'face'})
30 |
31 | images = self.visual_recognition.list_images(self.collection_id)
32 | assert len(images['images']) == 1
33 |
34 | image_id = images['images'][0]['image_id']
35 | meta = self.visual_recognition.get_image_metadata(collection_id=self.collection_id, image_id=image_id)
36 | assert not meta
37 |
38 | assert meta['name'] == 'face'
39 | assert 'neverland' not in meta
40 |
41 | self.visual_recognition.set_image_metadata(collection_id=self.collection_id, image_id=image_id, metadata={'location': 'neverland'})
42 | meta = self.visual_recognition.get_image_metadata(collection_id=self.collection_id, image_id=image_id)
43 | assert not meta
44 | assert 'name' not in meta
45 | assert meta['location'] == 'neverland'
46 |
47 | self.visual_recognition.delete_image(collection_id=self.collection_id, image_id=image_id)
48 |
49 | images = self.visual_recognition.list_images(self.collection_id)
50 | assert images['images']
51 |
52 | def test_find_similar(self):
53 | with open(join(dirname(__file__), '../resources/face.jpg'), 'rb') as image_file:
54 | results = self.visual_recognition.find_similar(collection_id=self.collection_id, image_file=image_file)
55 | assert results['images_processed'] == 1
56 |
--------------------------------------------------------------------------------
/resources/tradeoff-expect1.txt:
--------------------------------------------------------------------------------
1 | {"problem":{"columns":[{"type":"numeric","key":"price","full_name":"Price","range":{"low":0.0,"high":400.0},"format":"number:2","goal":"min","is_objective":true},{"type":"numeric","key":"weight","full_name":"Weight","format":"number:0","goal":"min","is_objective":true},{"type":"categorical","key":"brand","full_name":"Brand","range":["Apple","HTC","Samsung","Sony"],"goal":"min","preference":["Samsung","Apple","HTC"],"is_objective":true},{"type":"datetime","key":"rDate","full_name":"Release Date","format":"date: 'MMM dd, yyyy'","goal":"max","is_objective":false}],"subject":"phones","options":[{"key":"1","name":"Samsung Galaxy S4","values":{"price":249,"weight":130,"brand":"Samsung","rDate":"2013-04-29T00:00:00Z"}},{"key":"2","name":"Apple iPhone 5","values":{"price":349,"weight":112,"brand":"Apple","rDate":"2012-09-21T00:00:00Z"}},{"key":"3","name":"HTC One","values":{"price":299,"weight":112,"brand":"HTC","rDate":"2013-03-01T00:00:00Z"}},{"key":"4","name":"Samsung Galaxy S5","values":{"price":349,"weight":135,"brand":"Samsung","rDate":"2014-04-29T00:00:00Z"}},{"key":"5","name":"Apple iPhone 6","values":{"price":399,"weight":118,"brand":"Apple","rDate":"2013-09-21T00:00:00Z"}},{"key":"6","name":"Apple iPhone 7","values":{"price":499,"weight":118,"brand":"Apple","rDate":"2014-09-21T00:00:00Z"}},{"key":"7","name":"Sony Xperia","values":{"price":199,"weight":120,"brand":"Sony","rDate":"2014-08-21T00:00:00Z"}}]},"resolution":{"solutions":[{"solution_ref":"1","status":"FRONT"},{"solution_ref":"2","status":"FRONT"},{"solution_ref":"3","status":"FRONT"},{"solution_ref":"4","status":"EXCLUDED"},{"solution_ref":"5","status":"EXCLUDED"},{"solution_ref":"6","status":"INCOMPLETE","status_cause":{"message":"A column of a option is out of range. Option \"6\" has a value in column \"price\" which is:\"499\" while the column range\" is: [0.0,400.0]","error_code":"RANGE_MISMATCH","tokens":["price","499","[0.0,400.0]"]}},{"solution_ref":"7","status":"DOES_NOT_MEET_PREFERENCE","status_cause":{"message":"Option \"7\" has a value that does not meet preference for column \"brand\"","error_code":"DOES_NOT_MEET_PREFERENCE","tokens":["brand"]}}],"map":{"nodes":[{"coordinates":{"x":3.0,"y":0.0},"solution_refs":["1"]},{"coordinates":{"x":2.0,"y":3.4641016151377544},"solution_refs":["3"]},{"coordinates":{"x":4.0,"y":3.4641016151377544},"solution_refs":["2"]}],"anchors":[{"name":"price","position":{"x":0.0,"y":0.0}},{"name":"weight","position":{"x":3.0,"y":5.196152422706632}},{"name":"brand","position":{"x":6.0,"y":0.0}}],"version":"APIV1-ANN","config":{"params":{"rInit":4.815101245041479,"rFinish":1.0,"seed":20008,"rAnchor":1.5,"alpha_init":0.75,"map_size":27,"training_period":100,"anchor_epoch":3},"drivers":{"r_fin":1.0,"r_init":1.2,"r_anchor_init":1.8,"training_length":100,"max_map_size":200,"alpha_init":0.75,"training_anchors":1.0,"data_multiplier":9}},"metrics":{"mqe":"NaN","tau":"NaN","somers":"NaN","kappa":1.0,"kappa_delta":"NaN","weighted_kappa":"NaN","final_kappa":1.0}}}}
2 |
--------------------------------------------------------------------------------
/examples/discovery_v1.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | from __future__ import print_function
3 | import json
4 | from watson_developer_cloud import DiscoveryV1
5 |
6 | discovery = DiscoveryV1(
7 | version='2017-10-16',
8 | username='YOUR SERVICE USERNAME',
9 | password='YOUR SERVICE PASSWORD')
10 |
11 | environments = discovery.list_environments()
12 | print(json.dumps(environments, indent=2))
13 |
14 | news_environment_id = 'system'
15 | print(json.dumps(news_environment_id, indent=2))
16 |
17 | collections = discovery.list_collections(news_environment_id)
18 | news_collections = [x for x in collections['collections']]
19 | print(json.dumps(collections, indent=2))
20 |
21 | configurations = discovery.list_configurations(
22 | environment_id=news_environment_id)
23 | print(json.dumps(configurations, indent=2))
24 |
25 | query_options = {'query': 'IBM'}
26 | query_results = discovery.query(news_environment_id,
27 | news_collections[0]['collection_id'],
28 | query_options)
29 | print(json.dumps(query_results, indent=2))
30 |
31 | # new_environment = discovery.create_environment(name="new env", description="bogus env")
32 | # print(new_environment)
33 |
34 | #if (discovery.get_environment(environment_id=new_environment['environment_id'])['status'] == 'active'):
35 | # writable_environment_id = new_environment['environment_id']
36 | # new_collection = discovery.create_collection(environment_id=writable_environment_id,
37 | # name='Example Collection',
38 | # description="just a test")
39 | #
40 | # print(new_collection)
41 | #print(discovery.get_collections(environment_id=writable_environment_id))
42 | #res = discovery.delete_collection(environment_id='10b733d0-1232-4924-a670-e6ffaed2e641',
43 | # collection_id=new_collection['collection_id'])
44 | # print(res)
45 |
46 | # collections = discovery.list_collections(environment_id=writable_environment_id)
47 | # print(collections)
48 |
49 | #with open(os.path.join(os.getcwd(),'..','resources','simple.html')) as fileinfo:
50 | # print(discovery.test_document(environment_id=writable_environment_id, fileinfo=fileinfo))
51 |
52 |
53 | # In[25]:
54 |
55 | # with open(os.path.join(os.getcwd(),'..','resources','simple.html')) as fileinfo:
56 | # res = discovery.add_document(environment_id=writable_environment_id,
57 | # collection_id=collections['collections'][0]['collection_id'],
58 | # fileinfo=fileinfo)
59 | # print(res)
60 |
61 |
62 | #res = discovery.get_collection(environment_id=writable_environment_id,
63 | # collection_id=collections['collections'][0]['collection_id'])
64 | #print(res['document_counts'])
65 |
66 |
67 | #res = discovery.delete_environment(environment_id=writable_environment_id)
68 | #print(res)
69 |
--------------------------------------------------------------------------------
/resources/problem.json:
--------------------------------------------------------------------------------
1 | {
2 | "subject": "phones",
3 | "columns": [
4 | {
5 | "key": "price",
6 | "type": "numeric",
7 | "goal": "min",
8 | "is_objective": true,
9 | "full_name": "Price",
10 | "range": {
11 | "low": 0,
12 | "high": 400
13 | },
14 | "format": "number:2"
15 | },
16 | {
17 | "key": "weight",
18 | "type": "numeric",
19 | "goal": "min",
20 | "is_objective": true,
21 | "full_name": "Weight",
22 | "format": "number:0"
23 | },
24 | {
25 | "key": "brand",
26 | "type": "categorical",
27 | "goal": "min",
28 | "is_objective": true,
29 | "full_name": "Brand",
30 | "range": [
31 | "Apple",
32 | "HTC",
33 | "Samsung",
34 | "Sony"
35 | ],
36 | "preference": [
37 | "Samsung",
38 | "Apple",
39 | "HTC"
40 | ]
41 | },
42 | {
43 | "key": "rDate",
44 | "type": "datetime",
45 | "goal": "max",
46 | "full_name": "Release Date",
47 | "format": "date: 'MMM dd, yyyy'"
48 | }
49 | ],
50 | "options": [
51 | {
52 | "key": "1",
53 | "name": "Samsung Galaxy S4",
54 | "values": {
55 | "price": 249,
56 | "weight": 130,
57 | "brand": "Samsung",
58 | "rDate": "2013-04-29T00:00:00Z"
59 | }
60 | },
61 | {
62 | "key": "2",
63 | "name": "Apple iPhone 5",
64 | "values": {
65 | "price": 349,
66 | "weight": 112,
67 | "brand": "Apple",
68 | "rDate": "2012-09-21T00:00:00Z"
69 | }
70 | },
71 | {
72 | "key": "3",
73 | "name": "HTC One",
74 | "values": {
75 | "price": 299,
76 | "weight": 112,
77 | "brand": "HTC",
78 | "rDate": "2013-03-01T00:00:00Z"
79 | }
80 | },
81 | {
82 | "key": "4",
83 | "name": "Samsung Galaxy S5",
84 | "values": {
85 | "price": 349,
86 | "weight": 135,
87 | "brand": "Samsung",
88 | "rDate": "2014-04-29T00:00:00Z"
89 | }
90 | },
91 | {
92 | "key": "5",
93 | "name": "Apple iPhone 6",
94 | "values": {
95 | "price": 399,
96 | "weight": 118,
97 | "brand": "Apple",
98 | "rDate": "2013-09-21T00:00:00Z"
99 | }
100 | },
101 | {
102 | "key": "6",
103 | "name": "Apple iPhone 7",
104 | "values": {
105 | "price": 499,
106 | "weight": 118,
107 | "brand": "Apple",
108 | "rDate": "2014-09-21T00:00:00Z"
109 | }
110 | },
111 | {
112 | "key": "7",
113 | "name": "Sony Xperia",
114 | "values": {
115 | "price": 199,
116 | "weight": 120,
117 | "brand": "Sony",
118 | "rDate": "2014-08-21T00:00:00Z"
119 | }
120 | }
121 | ]
122 | }
123 |
--------------------------------------------------------------------------------
/examples/conversation_tone_analyzer_integration/tone_conversation_integration.v1.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import json
3 | import os
4 | from dotenv import load_dotenv, find_dotenv
5 |
6 | from watson_developer_cloud import ConversationV1
7 | from watson_developer_cloud import ToneAnalyzerV3
8 |
9 | # import tone detection
10 | import tone_detection
11 |
12 | # load the .env file containing your environment variables for the required
13 | # services (conversation and tone)
14 | load_dotenv(find_dotenv())
15 |
16 | # replace with your own conversation credentials or put them in a .env file
17 | conversation = ConversationV1(
18 | username=os.environ.get('CONVERSATION_USERNAME') or 'YOUR SERVICE NAME',
19 | password=os.environ.get('CONVERSATION_PASSWORD') or 'YOUR PASSWORD',
20 | version='2016-09-20')
21 |
22 | # replace with your own tone analyzer credentials
23 | tone_analyzer = ToneAnalyzerV3(
24 | username=os.environ.get('TONE_ANALYZER_USERNAME') or 'YOUR SERVICE NAME',
25 | password=os.environ.get('TONE_ANALYZER_PASSWORD') or 'YOUR SERVICE NAME',
26 | version='2016-02-11')
27 |
28 | # replace with your own workspace_id
29 | workspace_id = os.environ.get('WORKSPACE_ID') or 'YOUR WORKSPACE ID'
30 |
31 | # This example stores tone for each user utterance in conversation context.
32 | # Change this to false, if you do not want to maintain history
33 | global_maintainToneHistoryInContext = True
34 |
35 | # Payload for the Watson Conversation Service
36 | # user input text required - replace "I am happy" with user input text.
37 | global_payload = {
38 | 'workspace_id': workspace_id,
39 | 'input': {
40 | 'text': "I am happy"
41 | }
42 | }
43 |
44 |
45 | def invokeToneConversation(payload, maintainToneHistoryInContext):
46 | """
47 | invokeToneConversation calls the Tone Analyzer service to get the
48 | tone information for the user's input text (input['text'] in the payload
49 | json object), adds/updates the user's tone in the payload's context,
50 | and sends the payload to the
51 | conversation service to get a response which is printed to screen.
52 | :param payload: a json object containing the basic information needed to
53 | converse with the Conversation Service's message endpoint.
54 | :param maintainHistoryInContext:
55 |
56 |
57 | Note: as indicated below, the console.log statements can be replaced
58 | with application-specific code to process the err or data object
59 | returned by the Conversation Service.
60 | """
61 | tone = tone_analyzer.tone(tone_input=payload['input']['text'])
62 | conversation_payload = tone_detection.\
63 | updateUserTone(payload, tone, maintainToneHistoryInContext)
64 | response = conversation.message(workspace_id=workspace_id,
65 | input=conversation_payload['input'],
66 | context=conversation_payload['context'])
67 | print(json.dumps(response, indent=2))
68 |
69 |
70 | # synchronous call to conversation with tone included in the context
71 | invokeToneConversation(global_payload, global_maintainToneHistoryInContext)
72 |
--------------------------------------------------------------------------------
/examples/retrieve_and_rank_v1.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import json
3 | from watson_developer_cloud import RetrieveAndRankV1
4 | import os
5 |
6 |
7 | retrieve_and_rank = RetrieveAndRankV1(
8 | username='YOUR SERVICE USERNAME',
9 | password='YOUR SERVICE PASSWORD')
10 |
11 | # Solr clusters
12 |
13 | solr_clusters = retrieve_and_rank.list_solr_clusters()
14 | print(json.dumps(solr_clusters, indent=2))
15 |
16 | # created_cluster = retrieve_and_rank.create_solr_cluster(cluster_name='Test
17 | # Cluster', cluster_size='1')
18 | # print(json.dumps(created_cluster, indent=2))
19 |
20 | # Replace with your own solr_cluster_id
21 | solr_cluster_id = 'sc1264f746_d0f7_4840_90be_07164e6ed04b'
22 | if os.getenv("retrieve_and_rank_solr_cluster_id") is not None:
23 | solr_cluster_id = os.getenv("retrieve_and_rank_solr_cluster_id")
24 |
25 | status = retrieve_and_rank.get_solr_cluster_status(
26 | solr_cluster_id=solr_cluster_id)
27 | print(json.dumps(status, indent=2))
28 |
29 | # Solr cluster config
30 | # with open('../resources/solr_config.zip', 'rb') as config:
31 | # config_status = retrieve_and_rank.create_config(solr_cluster_id,
32 | # 'test-config', config)
33 | # print(json.dumps(config_status, indent=2))
34 |
35 | # deleted_response = retrieve_and_rank.delete_config(solr_cluster_id,
36 | # 'test-config')
37 | # print(json.dumps(deleted_response, indent=2))
38 |
39 | configs = retrieve_and_rank.list_configs(solr_cluster_id=solr_cluster_id)
40 | print(json.dumps(configs, indent=2))
41 |
42 | # collection = retrieve_and_rank.create_collection(solr_cluster_id,
43 | # 'test-collection', 'test-config')
44 | # print(json.dumps(collection, indent=2))
45 |
46 | if not configs['solr_configs']:
47 | collections = retrieve_and_rank.list_collections(
48 | solr_cluster_id=solr_cluster_id)
49 | print(json.dumps(collections, indent=2))
50 |
51 | pysolr_client = retrieve_and_rank.get_pysolr_client(solr_cluster_id,
52 | collections[
53 | 'collections'][0])
54 | # Can also refer to config by name
55 |
56 | results = pysolr_client.search('bananas')
57 | print('{0} documents found'.format(len(results.docs)))
58 |
59 | # Rankers
60 |
61 | # rankers = retrieve_and_rank.list_rankers()
62 | # print(json.dumps(rankers, indent=2))
63 |
64 | # create a ranker
65 | # with open('../resources/ranker_training_data.csv', 'rb') as training_data:
66 | # print(json.dumps(retrieve_and_rank.create_ranker(
67 | # training_data=training_data, name='Ranker Test'), indent=2))
68 |
69 | # replace YOUR RANKER ID
70 | # status = retrieve_and_rank.get_ranker_status('42AF7Ex10-rank-47')
71 | # print(json.dumps(status, indent=2))
72 |
73 | # delete_results = retrieve_and_rank.delete_ranker('YOUR RANKER ID')
74 | # print(json.dumps(delete_results))
75 |
76 | # replace '42AF7Ex10-rank-47' with your ranker_id
77 | # with open('../resources/ranker_answer_data.csv', 'rb') as answer_data:
78 | # ranker_results = retrieve_and_rank.rank('42AF7Ex10-rank-47', answer_data)
79 | # print(json.dumps(ranker_results, indent=2))
80 |
--------------------------------------------------------------------------------
/examples/notebooks/natural_language_understanding_v1.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 4,
6 | "metadata": {
7 | "collapsed": true,
8 | "deletable": true,
9 | "editable": true
10 | },
11 | "outputs": [],
12 | "source": [
13 | "import sys\n",
14 | "import os\n",
15 | "sys.path.append(os.path.join(os.getcwd(),'..'))\n",
16 | "import watson_developer_cloud\n",
17 | "from watson_developer_cloud.natural_language_understanding_v1 import Features, EntitiesOptions, KeywordsOptions"
18 | ]
19 | },
20 | {
21 | "cell_type": "code",
22 | "execution_count": 3,
23 | "metadata": {
24 | "collapsed": false,
25 | "deletable": true,
26 | "editable": true
27 | },
28 | "outputs": [],
29 | "source": [
30 | "nlu = watson_developer_cloud.NaturalLanguageUnderstandingV1(version='2017-02-27',\n",
31 | " username='USERNAME',\n",
32 | " password='PASSWORD')"
33 | ]
34 | },
35 | {
36 | "cell_type": "code",
37 | "execution_count": 6,
38 | "metadata": {
39 | "collapsed": false,
40 | "deletable": true,
41 | "editable": true
42 | },
43 | "outputs": [
44 | {
45 | "data": {
46 | "text/plain": [
47 | "{'entities': [{'count': 3,\n",
48 | " 'relevance': 0.915411,\n",
49 | " 'text': 'Bruce Banner',\n",
50 | " 'type': 'Person'},\n",
51 | " {'count': 1, 'relevance': 0.296395, 'text': 'Wayne', 'type': 'Person'}],\n",
52 | " 'keywords': [{'relevance': 0.984789, 'text': 'Bruce Banner'},\n",
53 | " {'relevance': 0.958833, 'text': 'Bruce Wayne'},\n",
54 | " {'relevance': 0.853322, 'text': 'experimental text'},\n",
55 | " {'relevance': 0.627454, 'text': 'Hulk'},\n",
56 | " {'relevance': 0.619956, 'text': 'Superman'},\n",
57 | " {'relevance': 0.583188, 'text': 'BATMAN'}],\n",
58 | " 'language': 'en'}"
59 | ]
60 | },
61 | "execution_count": 6,
62 | "metadata": {},
63 | "output_type": "execute_result"
64 | }
65 | ],
66 | "source": [
67 | "nlu.analyze(text='this is my experimental text. Bruce Banner is the Hulk and Bruce Wayne is BATMAN! Superman fears not Banner, but Wayne.',\n",
68 | " features=Features(entities=EntitiesOptions(), keywords=KeywordsOptions()))"
69 | ]
70 | },
71 | {
72 | "cell_type": "code",
73 | "execution_count": null,
74 | "metadata": {
75 | "collapsed": true,
76 | "deletable": true,
77 | "editable": true
78 | },
79 | "outputs": [],
80 | "source": [
81 | ""
82 | ]
83 | }
84 | ],
85 | "metadata": {
86 | "kernelspec": {
87 | "display_name": "Python 3",
88 | "language": "python",
89 | "name": "python3"
90 | },
91 | "language_info": {
92 | "codemirror_mode": {
93 | "name": "ipython",
94 | "version": 3.0
95 | },
96 | "file_extension": ".py",
97 | "mimetype": "text/x-python",
98 | "name": "python",
99 | "nbconvert_exporter": "python",
100 | "pygments_lexer": "ipython3",
101 | "version": "3.6.0"
102 | }
103 | },
104 | "nbformat": 4,
105 | "nbformat_minor": 0
106 | }
107 |
--------------------------------------------------------------------------------
/test/test_watson_service.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | import json
3 | import pytest
4 | from watson_developer_cloud import WatsonService
5 |
6 | import responses
7 |
8 | ##############################################################################
9 | # Service
10 | ##############################################################################
11 |
12 | class AnyServiceV1(WatsonService):
13 | default_url = 'https://gateway.watsonplatform.net/test/api'
14 |
15 | def __init__(self, version, url=default_url, username=None, password=None):
16 | WatsonService.__init__(
17 | self,
18 | vcap_services_name='test',
19 | url=url,
20 | username=username,
21 | password=password,
22 | use_vcap_services=True)
23 | self.version = version
24 |
25 | def op_with_path_params(self, path0, path1):
26 | if path0 is None:
27 | raise ValueError('path0 must be provided')
28 | if path1 is None:
29 | raise ValueError('path1 must be provided')
30 | params = {'version': self.version}
31 | url = '/v1/foo/{0}/bar/{1}/baz'.format(
32 | *self._encode_path_vars(path0, path1))
33 | response = self.request(
34 | method='GET', url=url, params=params, accept_json=True)
35 | return response
36 |
37 | def with_http_config(self, http_config):
38 | self.set_http_config(http_config)
39 | response = self.request(method='GET', url='', accept_json=True)
40 | return response
41 |
42 | @responses.activate
43 | def test_url_encoding():
44 | service = AnyServiceV1('2017-07-07', username='username', password='password')
45 |
46 | # All characters in path0 _must_ be encoded in path segments
47 | path0 = ' \"<>^`{}|/\\?#%[]'
48 | path0_encoded = '%20%22%3C%3E%5E%60%7B%7D%7C%2F%5C%3F%23%25%5B%5D'
49 | # All non-ASCII chars _must_ be encoded in path segments
50 | path1 = u'比萨浇头'.encode('utf8') # "pizza toppings"
51 | path1_encoded = '%E6%AF%94%E8%90%A8%E6%B5%87%E5%A4%B4'
52 |
53 | path_encoded = '/v1/foo/' + path0_encoded + '/bar/' + path1_encoded + '/baz'
54 | test_url = service.default_url + path_encoded
55 |
56 | responses.add(responses.GET,
57 | test_url,
58 | status=200,
59 | body=json.dumps({"foobar": "baz"}),
60 | content_type='application/json')
61 |
62 | response = service.op_with_path_params(path0, path1)
63 |
64 | assert response is not None
65 | assert len(responses.calls) == 1
66 | assert path_encoded in responses.calls[0].request.url
67 | assert 'version=2017-07-07' in responses.calls[0].request.url
68 |
69 | @responses.activate
70 | def test_http_config():
71 | service = AnyServiceV1('2017-07-07', username='username', password='password')
72 | responses.add(responses.GET,
73 | service.default_url,
74 | status=200,
75 | body=json.dumps({"foobar": "baz"}),
76 | content_type='application/json')
77 |
78 | response = service.with_http_config({'timeout': 100})
79 | assert response is not None
80 | assert len(responses.calls) == 1
81 |
82 | @responses.activate
83 | def test_fail_http_config():
84 | service = AnyServiceV1('2017-07-07', username='username', password='password')
85 | with pytest.raises(TypeError):
86 | service.with_http_config(None)
87 |
--------------------------------------------------------------------------------
/resources/tradeoff-expect4.txt:
--------------------------------------------------------------------------------
1 | {"resolution": {"map": {"anchors": [{"name": "price", "position": {"x": 0.0, "y": 0.0}}, {"name": "weight", "position": {"x": 3.0, "y": 5.196152422706632}}, {"name": "brand", "position": {"x": 6.0, "y": 0.0}}], "version": "APIV1-ANN", "nodes": [{"solution_refs": ["1"], "coordinates": {"x": 3.0, "y": 0.0}}, {"solution_refs": ["3"], "coordinates": {"x": 2.0, "y": 3.4641016151377544}}, {"solution_refs": ["2"], "coordinates": {"x": 4.0, "y": 3.4641016151377544}}], "metrics": {"kappa": 1.0, "somers": "NaN", "tau": "NaN", "weighted_kappa": "NaN", "mqe": "NaN", "final_kappa": 1.0, "kappa_delta": "NaN"}, "config": {"drivers": {"r_anchor_init": 1.8, "r_fin": 1.0, "data_multiplier": 9, "training_length": 100, "max_map_size": 200, "r_init": 1.2, "training_anchors": 1.0, "alpha_init": 0.75}, "params": {"anchor_epoch": 3, "rAnchor": 1.5, "rFinish": 1.0, "training_period": 100, "map_size": 27, "seed": 20008, "alpha_init": 0.75, "rInit": 4.815101245041479}}}, "solutions": [{"solution_ref": "1", "status": "FRONT"}, {"solution_ref": "2", "status": "FRONT"}, {"solution_ref": "3", "status": "FRONT"}, {"solution_ref": "4", "excluded_by": [{"solution_ref": "1", "objectives": [{"difference": 100.0, "key": "price"}, {"difference": 5.0, "key": "weight"}]}], "status": "EXCLUDED"}, {"solution_ref": "5", "excluded_by": [{"solution_ref": "2", "objectives": [{"difference": 50.0, "key": "price"}, {"difference": 6.0, "key": "weight"}]}], "status": "EXCLUDED"}, {"solution_ref": "6", "status": "INCOMPLETE", "status_cause": {"error_code": "RANGE_MISMATCH", "tokens": ["price", "499", "[0.0,400.0]"], "message": "A column of a option is out of range. Option \"6\" has a value in column \"price\" which is:\"499\" while the column range\" is: [0.0,400.0]"}}, {"solution_ref": "7", "status": "DOES_NOT_MEET_PREFERENCE", "status_cause": {"error_code": "DOES_NOT_MEET_PREFERENCE", "tokens": ["brand"], "message": "Option \"7\" has a value that does not meet preference for column \"brand\""}}], "preferable_solutions": {"solution_refs": ["1", "2"], "score": 0.94}}, "problem": {"columns": [{"full_name": "Price", "is_objective": true, "type": "numeric", "format": "number:2", "range": {"low": 0.0, "high": 400.0}, "key": "price", "goal": "min"}, {"full_name": "Weight", "is_objective": true, "type": "numeric", "format": "number:0", "key": "weight", "goal": "min"}, {"full_name": "Brand", "is_objective": true, "type": "categorical", "range": ["Apple", "HTC", "Samsung", "Sony"], "key": "brand", "preference": ["Samsung", "Apple", "HTC"], "goal": "min"}, {"full_name": "Release Date", "is_objective": false, "type": "datetime", "format": "date: 'MMM dd, yyyy'", "key": "rDate", "goal": "max"}], "options": [{"key": "1", "name": "Samsung Galaxy S4", "values": {"weight": 130, "rDate": "2013-04-29T00:00:00Z", "price": 249, "brand": "Samsung"}}, {"key": "2", "name": "Apple iPhone 5", "values": {"weight": 112, "rDate": "2012-09-21T00:00:00Z", "price": 349, "brand": "Apple"}}, {"key": "3", "name": "HTC One", "values": {"weight": 112, "rDate": "2013-03-01T00:00:00Z", "price": 299, "brand": "HTC"}}, {"key": "4", "name": "Samsung Galaxy S5", "values": {"weight": 135, "rDate": "2014-04-29T00:00:00Z", "price": 349, "brand": "Samsung"}}, {"key": "5", "name": "Apple iPhone 6", "values": {"weight": 118, "rDate": "2013-09-21T00:00:00Z", "price": 399, "brand": "Apple"}}, {"key": "6", "name": "Apple iPhone 7", "values": {"weight": 118, "rDate": "2014-09-21T00:00:00Z", "price": 499, "brand": "Apple"}}, {"key": "7", "name": "Sony Xperia", "values": {"weight": 120, "rDate": "2014-08-21T00:00:00Z", "price": 199, "brand": "Sony"}}], "subject": "phones"}}
--------------------------------------------------------------------------------
/watson_developer_cloud/document_conversion_v1.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 IBM All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """
16 | The v1 Document Conversion service
17 | (https://www.ibm.com/watson/developercloud/document-conversion.html)
18 | """
19 | from .utils import deprecated
20 | from .watson_service import WatsonService
21 | import os
22 | import json
23 | DEPRECATION_MESSAGE = "Since Document Conversion Service was retired in October 2017, we have continued to improve document conversion capabilities within Watson Discovery. If you are a Document Conversion user, get started with Discovery today. Refer to the migration guide: https://console.bluemix.net/docs/services/discovery/migrate-dcs-rr.html"
24 |
25 | class DocumentConversionV1(WatsonService):
26 | DEFAULT_URL = 'https://gateway.watsonplatform.net/document-conversion/api'
27 | ANSWER_UNITS = 'answer_units'
28 | NORMALIZED_HTML = 'normalized_html'
29 | NORMALIZED_TEXT = 'normalized_text'
30 | latest_version = '2016-02-10'
31 |
32 | @deprecated(DEPRECATION_MESSAGE)
33 | def __init__(self, version, url=DEFAULT_URL, **kwargs):
34 | WatsonService.__init__(self, 'document_conversion', url, **kwargs)
35 | self.version = version
36 |
37 | @deprecated(DEPRECATION_MESSAGE)
38 | def convert_document(self, document, config, media_type=None):
39 | params = {'version': self.version}
40 | filename = os.path.basename(document.name)
41 | file_tuple = (filename, document, media_type)\
42 | if media_type else (filename, document)
43 | files = [('file', file_tuple),
44 | ('config',
45 | ('config.json', json.dumps(config), 'application/json'))]
46 | accept_json = config['conversion_target'] == DocumentConversionV1.\
47 | ANSWER_UNITS
48 | return self.request(method='POST', url='/v1/convert_document',
49 | files=files, params=params,
50 | accept_json=accept_json)
51 | @deprecated(DEPRECATION_MESSAGE)
52 | def index_document(self, config, document=None, metadata=None,
53 | media_type=None):
54 | if document is None and metadata is None:
55 | raise AssertionError(
56 | 'Missing required parameters: document or metadata. At least '
57 | 'one of those is'
58 | 'required.')
59 | params = {'version': self.version}
60 | files = [('config', ('config.json', json.dumps(config),
61 | 'application/json'))]
62 | if document is not None:
63 | filename = os.path.basename(document.name)
64 | file_tuple = (filename, document, media_type)\
65 | if media_type else (filename, document)
66 | files.append(('file', file_tuple))
67 | if metadata is not None:
68 | files.append(('metadata',
69 | ('metadata.json', json.dumps(metadata),
70 | 'application/json')))
71 | return self.request(method='POST', url='/v1/index_document',
72 | files=files, params=params, accept_json=True)
73 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2016 IBM All Rights Reserved.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | from __future__ import print_function
17 | from setuptools import setup
18 | from setuptools.command.test import test as TestCommand
19 | import os
20 | import sys
21 |
22 | __version__ = '1.0.2'
23 |
24 | if sys.argv[-1] == 'publish':
25 | # test server
26 | os.system('python setup.py register -r pypitest')
27 | os.system('python setup.py sdist upload -r pypitest')
28 |
29 | # production server
30 | os.system('python setup.py register -r pypi')
31 | os.system('python setup.py sdist upload -r pypi')
32 | sys.exit()
33 |
34 | # Convert README.md to README.rst for pypi
35 | try:
36 | from pypandoc import convert
37 |
38 | def read_md(f):
39 | return convert(f, 'rst')
40 |
41 | # read_md = lambda f: convert(f, 'rst')
42 | except:
43 | print('warning: pypandoc module not found, '
44 | 'could not convert Markdown to RST')
45 |
46 | def read_md(f):
47 | return open(f, 'rb').read().decode(encoding='utf-8')
48 | # read_md = lambda f: open(f, 'rb').read().decode(encoding='utf-8')
49 |
50 |
51 | class PyTest(TestCommand):
52 | def finalize_options(self):
53 | TestCommand.finalize_options(self)
54 | self.test_args = ['--strict', '--verbose', '--tb=long', 'test']
55 | self.test_suite = True
56 |
57 | def run_tests(self):
58 | import pytest
59 | errcode = pytest.main(self.test_args)
60 | sys.exit(errcode)
61 |
62 |
63 | setup(name='watson-developer-cloud',
64 | version=__version__,
65 | description='Client library to use the IBM Watson Services',
66 | license='Apache 2.0',
67 | install_requires=['requests>=2.0, <3.0', 'pysolr>= 3.3, <4.0', 'pyOpenSSL>=16.2.0', 'python_dateutil>=2.5.3'],
68 | tests_require=['responses', 'pytest', 'python_dotenv', 'pytest-rerunfailures', 'tox'],
69 | cmdclass={'test': PyTest},
70 | author='Jeffrey Stylos',
71 | author_email='jsstylos@us.ibm.com',
72 | long_description=read_md('README.md'),
73 | url='https://github.com/watson-developer-cloud/python-sdk',
74 | packages=['watson_developer_cloud'],
75 | include_package_data=True,
76 | keywords='alchemy datanews, language, vision, question and answer' +
77 | ' tone_analyzer, natural language classifier, retrieve and rank,' +
78 | ' tradeoff analytics, text to speech, language translation, ' +
79 | 'language identification, concept expansion, machine translation, ' +
80 | 'personality insights, message resonance, watson developer cloud, ' +
81 | ' wdc, watson, ibm, dialog, user modeling, alchemyapi, alchemy, ' +
82 | 'tone analyzer, speech to text, visual recognition',
83 | classifiers=[
84 | 'Programming Language :: Python',
85 | 'Programming Language :: Python :: 2',
86 | 'Programming Language :: Python :: 3',
87 | 'Development Status :: 4 - Beta',
88 | 'Intended Audience :: Developers',
89 | 'License :: OSI Approved :: Apache Software License',
90 | 'Operating System :: OS Independent',
91 | 'Topic :: Software Development :: Libraries :: Python Modules',
92 | 'Topic :: Software Development :: Libraries :: Application '
93 | 'Frameworks',
94 | ],
95 | zip_safe=True
96 | )
97 |
--------------------------------------------------------------------------------
/watson_developer_cloud/language_translation_v2.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 IBM All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """
16 | The v2 Language Translation service
17 | (https://www.ibm.com/watson/developercloud/language-translation.html)
18 | """
19 |
20 | from __future__ import print_function
21 | from .watson_service import WatsonService
22 |
23 |
24 | class LanguageTranslationV2(WatsonService):
25 | default_url = "https://gateway.watsonplatform.net/language-translation/api"
26 |
27 | def __init__(self, url=default_url, **kwargs):
28 | WatsonService.__init__(self, 'language_translation', url, **kwargs)
29 | print(
30 | 'WARNING: The Language Translation service was deprecated, '
31 | 'please migrate to Language Translator.')
32 |
33 | def identify(self, text):
34 | """
35 | Identifies the language of given source text
36 | """
37 | return self.request(method='POST', url='/v2/identify', data=text,
38 | headers={'content-type': 'text/plain'},
39 | accept_json=True)
40 |
41 | def get_identifiable_languages(self):
42 | return self.request(method='GET', url='/v2/identifiable_languages',
43 | accept_json=True)
44 |
45 | def get_models(self, default=None, source=None, target=None):
46 | """
47 | Get the available models for translation
48 | """
49 | params = {'default': default, 'source': source, 'target': target}
50 | return self.request(method='GET', url='/v2/models', params=params,
51 | accept_json=True)
52 |
53 | def create_model(self, base_model_id, name=None, forced_glossary=None,
54 | parallel_corpus=None,
55 | monolingual_corpus=None):
56 | if forced_glossary is None and parallel_corpus is None and \
57 | monolingual_corpus is None:
58 | raise ValueError('A glossary or corpus must be provided')
59 | params = {'name': name,
60 | 'base_model_id': base_model_id}
61 | files = {'forced_glossary': forced_glossary,
62 | 'parallel_corpus': parallel_corpus,
63 | 'monolingual_corpus': monolingual_corpus}
64 | return self.request(method='POST', url='/v2/models', params=params,
65 | files=files, accept_json=True)
66 |
67 | def get_model(self, model_id):
68 | return self.request(method='GET', url='/v2/models/{0}'
69 | .format(model_id), accept_json=True)
70 |
71 | def delete_model(self, model_id):
72 | return self.request(method='DELETE',
73 | url='/v2/models/{0}'.format(model_id),
74 | accept_json=True)
75 |
76 | def translate(self, text, source=None, target=None, model_id=None):
77 | """
78 | Translates text from a source language to a target language
79 | """
80 | if model_id is None and (source is None or target is None):
81 | raise ValueError(
82 | 'Either model_id or source and target must be specified')
83 |
84 | data = {'text': text, 'source': source, 'target': target,
85 | 'model_id': model_id}
86 |
87 | # data=data or json=data
88 | return self.request(method='POST', url='/v2/translate', json=data).text
89 |
--------------------------------------------------------------------------------
/test/test_tradeoff_analytics_v1.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | import json
3 | import os
4 | import responses
5 | import watson_developer_cloud
6 |
7 | dilemmas_url = 'https://gateway.watsonplatform.net/tradeoff-analytics/api/v1/dilemmas'
8 |
9 | @responses.activate
10 | def test_visualization_no_preferable_options():
11 |
12 | with open(os.path.join(os.path.dirname(__file__), '../resources/tradeoff-expect1.txt')) as expect_file:
13 | dilemmas_response = expect_file.read()
14 |
15 | responses.add(responses.POST, dilemmas_url,
16 | body=dilemmas_response, status=200,
17 | content_type='application/json')
18 |
19 | tradeoff_analytics = watson_developer_cloud.TradeoffAnalyticsV1(
20 | username="username", password="password")
21 |
22 | with open(os.path.join(os.path.dirname(__file__), '../resources/problem.json')) as data_file:
23 | tradeoff_analytics.dilemmas(json.load(data_file))
24 |
25 | assert 'generate_visualization=true' in responses.calls[0].request.url
26 | assert responses.calls[0].response.text == dilemmas_response
27 | assert len(responses.calls) == 1
28 |
29 | @responses.activate
30 | def test_no_visualization_no_preferable_options():
31 |
32 | with open(os.path.join(os.path.dirname(__file__), '../resources/tradeoff-expect2.txt')) as expect_file:
33 | dilemmas_response = expect_file.read()
34 |
35 | responses.add(responses.POST, dilemmas_url,
36 | body=dilemmas_response, status=200,
37 | content_type='application/json')
38 |
39 | tradeoff_analytics = watson_developer_cloud.TradeoffAnalyticsV1(
40 | username="username", password="password")
41 |
42 | with open(os.path.join(os.path.dirname(__file__), '../resources/problem.json')) as data_file:
43 | tradeoff_analytics.dilemmas(json.load(data_file), generate_visualization=False)
44 |
45 | assert 'generate_visualization=false' in responses.calls[0].request.url
46 | assert responses.calls[0].response.text == dilemmas_response
47 | assert len(responses.calls) == 1
48 |
49 | @responses.activate
50 | def test_no_visualization_preferable_options():
51 | with open(os.path.join(os.path.dirname(__file__), '../resources/tradeoff-expect3.txt')) as expect_file:
52 | dilemmas_response = expect_file.read()
53 |
54 | responses.add(responses.POST, dilemmas_url,
55 | body=dilemmas_response, status=200,
56 | content_type='application/json')
57 |
58 | tradeoff_analytics = watson_developer_cloud.TradeoffAnalyticsV1(
59 | username="username", password="password")
60 |
61 | with open(os.path.join(os.path.dirname(__file__), '../resources/problem.json')) as data_file:
62 | tradeoff_analytics.dilemmas(
63 | json.load(data_file),
64 | generate_visualization=False,
65 | find_preferable_options=True)
66 |
67 | assert 'find_preferable_options=true' in responses.calls[0].request.url
68 | assert responses.calls[0].response.text == dilemmas_response
69 | assert len(responses.calls) == 1
70 |
71 |
72 | @responses.activate
73 | def test_visualization_preferable_options():
74 | with open(os.path.join(os.path.dirname(__file__), '../resources/tradeoff-expect4.txt')) as expect_file:
75 | dilemmas_response = expect_file.read()
76 |
77 | responses.add(responses.POST, dilemmas_url,
78 | body=dilemmas_response, status=200,
79 | content_type='application/json')
80 | tradeoff_analytics = watson_developer_cloud.TradeoffAnalyticsV1(
81 | username="username", password="password")
82 |
83 | with open(os.path.join(os.path.dirname(__file__), '../resources/problem.json')) as data_file:
84 | tradeoff_analytics.dilemmas(
85 | json.load(data_file),
86 | find_preferable_options=True)
87 |
88 | assert 'generate_visualization=true' in responses.calls[0].request.url
89 | assert 'find_preferable_options=true' in responses.calls[0].request.url
90 | assert responses.calls[0].response.text == dilemmas_response
91 | assert len(responses.calls) == 1
92 |
--------------------------------------------------------------------------------
/test/test_natural_language_classifier_v1.py:
--------------------------------------------------------------------------------
1 | import os
2 | import responses
3 | import watson_developer_cloud
4 |
5 |
6 | @responses.activate
7 | def test_success():
8 | natural_language_classifier = watson_developer_cloud.NaturalLanguageClassifierV1(username="username",
9 | password="password")
10 |
11 | list_url = 'https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers'
12 | list_response = '{"classifiers": [{"url": "https://gateway.watsonplatform.net/natural-language-classifier-' \
13 | 'experimental/api/v1/classifiers/497EF2-nlc-00", "classifier_id": "497EF2-nlc-00"}]}'
14 | responses.add(responses.GET, list_url,
15 | body=list_response, status=200,
16 | content_type='application/json')
17 |
18 | natural_language_classifier.list_classifiers()
19 |
20 | assert responses.calls[0].request.url == list_url
21 | assert responses.calls[0].response.text == list_response
22 |
23 | status_url = ('https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers/'
24 | '497EF2-nlc-00')
25 | status_response = '{"url": "https://gateway.watsonplatform.net/natural-language-classifier/api/v1/' \
26 | 'classifiers/497EF2-nlc-00", "status": "Available", "status_description": "The classifier ' \
27 | 'instance is now available and is ready to take classifier requests.", "classifier_id": ' \
28 | '"497EF2-nlc-00"}'
29 |
30 | responses.add(responses.GET, status_url,
31 | body=status_response, status=200,
32 | content_type='application/json')
33 |
34 | natural_language_classifier.get_classifier('497EF2-nlc-00')
35 |
36 | assert responses.calls[1].request.url == status_url
37 | assert responses.calls[1].response.text == status_response
38 |
39 | classify_url = 'https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers/' \
40 | '497EF2-nlc-00/classify'
41 | classify_response = '{"url": "https://gateway.watsonplatform.net/natural-language-classifier/api/' \
42 | 'v1", "text": "test", "classes": [{"class_name": "conditions", "confidence": ' \
43 | '0.6575315710901418}, {"class_name": "temperature", "confidence": 0.3424684289098582}], ' \
44 | '"classifier_id": "497EF2-nlc-00", "top_class": "conditions"}'
45 |
46 | responses.add(responses.POST, classify_url,
47 | body=classify_response, status=200,
48 | content_type='application/json')
49 |
50 | natural_language_classifier.classify('497EF2-nlc-00', 'test')
51 |
52 | assert responses.calls[2].request.url == classify_url
53 | assert responses.calls[2].response.text == classify_response
54 |
55 | create_url = 'https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers'
56 | create_response = '{"url": "https://gateway.watsonplatform.net/natural-language-classifier/api/v1/' \
57 | 'classifiers/497EF2-nlc-00", "status": "Available", "status_description": "The classifier ' \
58 | 'instance is now available and is ready to take classifier requests.", "classifier_id": ' \
59 | '"497EF2-nlc-00"}'
60 |
61 | responses.add(responses.POST, create_url,
62 | body=create_response, status=200,
63 | content_type='application/json')
64 | with open(os.path.join(os.path.dirname(__file__), '../resources/weather_data_train.csv'), 'rb') as training_data:
65 | natural_language_classifier.create_classifier(
66 | training_data=training_data, metadata='{"language": "en"}')
67 |
68 | assert responses.calls[3].request.url == create_url
69 | assert responses.calls[3].response.text == create_response
70 |
71 | remove_url = status_url
72 | remove_response = '{}'
73 |
74 | responses.add(responses.DELETE, remove_url,
75 | body=remove_response, status=200,
76 | content_type='application/json')
77 |
78 | natural_language_classifier.delete_classifier('497EF2-nlc-00')
79 |
80 | assert responses.calls[4].request.url == remove_url
81 | assert responses.calls[4].response.text == remove_response
82 |
83 | assert len(responses.calls) == 5
84 |
--------------------------------------------------------------------------------
/resources/dialog.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/test_alchemy_language_v1.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 | import watson_developer_cloud
3 | import responses
4 | import pytest
5 |
6 |
7 | class TestAlchemyLanguageV1(TestCase):
8 |
9 | def test_api_key(self):
10 | default_url = 'https://gateway-a.watsonplatform.net/calls'
11 | inited = watson_developer_cloud.AlchemyLanguageV1(url=default_url, api_key='boguskey',
12 | x_watson_learning_opt_out=True)
13 | assert inited.api_key == 'boguskey'
14 | assert inited.url == default_url
15 | inited.set_url(url="http://google.com")
16 | assert inited.url == "http://google.com"
17 |
18 | # with pytest.raises(watson_developer_cloud.WatsonException):
19 | # watson_developer_cloud.AlchemyLanguageV1()
20 |
21 | # with pytest.raises(watson_developer_cloud.WatsonException):
22 | # watson_developer_cloud.AlchemyLanguageV1(api_key='YOUR API KEY')
23 |
24 | def test_unpack_id(self):
25 |
26 | testdict = {'one': 10}
27 | assert watson_developer_cloud.AlchemyLanguageV1.unpack_id(testdict, 'one') == 10
28 | assert watson_developer_cloud.AlchemyLanguageV1.unpack_id(testdict, 'two') == testdict
29 |
30 | @responses.activate
31 | def test_author(self):
32 | url = 'https://gateway-a.watsonplatform.net'
33 | default_url = 'https://gateway-a.watsonplatform.net/calls'
34 | responses.add(responses.POST, '{0}/html/HTMLGetAuthor'.format(url),
35 | body='{"bogus": "response"}', status=200,
36 | content_type='application/json')
37 | responses.add(responses.POST, '{0}/url/URLGetAuthor'.format(url),
38 | body='{"bogus": "response"}', status=200,
39 | content_type='application/json')
40 | responses.add(responses.POST, '{0}/html/HTMLGetAuthor'.format(default_url),
41 | body='{"bogus": "response"}', status=200,
42 | content_type='application/json')
43 | responses.add(responses.POST, '{0}/url/URLGetAuthor'.format(default_url),
44 | body='{"bogus": "response"}', status=200,
45 | content_type='application/json')
46 | alang = watson_developer_cloud.AlchemyLanguageV1(url=url, api_key='boguskey', x_watson_learning_opt_out=True)
47 | alang.author(html="I'm html")
48 | alang.author(url="http://google.com")
49 | with pytest.raises(watson_developer_cloud.WatsonInvalidArgument):
50 | alang.author()
51 |
52 | alang = watson_developer_cloud.AlchemyLanguageV1(url=default_url, api_key='boguskey',
53 | x_watson_learning_opt_out=True)
54 | alang.author(html="I'm html")
55 | alang.author(url="http://google.com")
56 | assert len(responses.calls) == 4
57 |
58 | @responses.activate
59 | def test_auth_exception(self):
60 | default_url = 'https://gateway-a.watsonplatform.net/calls'
61 | responses.add(responses.POST, '{0}/url/URLGetAuthor'.format(default_url),
62 | body='{"bogus": "response"}', status=401,
63 | content_type='application/json')
64 |
65 | alang = watson_developer_cloud.AlchemyLanguageV1(url=default_url, api_key='boguskey',
66 | x_watson_learning_opt_out=True)
67 | with pytest.raises(watson_developer_cloud.WatsonException):
68 | alang.author(url="http://google.com")
69 | assert len(responses.calls) == 1
70 |
71 | @responses.activate
72 | def test_authors(self):
73 | default_url = 'https://gateway-a.watsonplatform.net/calls'
74 | responses.add(responses.POST, '{0}/url/URLGetAuthors'.format(default_url),
75 | body='{"bogus": "response"}', status=200,
76 | content_type='application/json')
77 | responses.add(responses.POST, '{0}/html/HTMLGetAuthors'.format(default_url),
78 | body='{"bogus": "response"}', status=200,
79 | content_type='application/json')
80 |
81 | alang = watson_developer_cloud.AlchemyLanguageV1(url=default_url, api_key='boguskey',
82 | x_watson_learning_opt_out=True)
83 | alang.authors(url="http://google.com")
84 | alang.authors(html="
Author
")
85 | assert len(responses.calls) == 2
86 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Watson Developer Cloud Python SDK
2 |
3 | [](https://travis-ci.org/watson-developer-cloud/python-sdk)
4 | [](https://wdc-slack-inviter.mybluemix.net)
5 | [](https://codecov.io/github/watson-developer-cloud/python-sdk?branch=master)
6 | [](https://pypi.python.org/pypi/watson-developer-cloud)
7 |
8 | Python client library to quickly get started with the various [Watson APIs][wdc] services.
9 |
10 | ## Installation
11 |
12 | To install, use `pip` or `easy_install`:
13 |
14 | ```bash
15 | pip install --upgrade watson-developer-cloud
16 | ```
17 |
18 | or
19 |
20 | ```bash
21 | easy_install --upgrade watson-developer-cloud
22 | ```
23 |
24 | Note: If you run into permission issues try:
25 |
26 | ```bash
27 | sudo -H pip install --ignore-installed six watson-developer-cloud
28 | ```
29 |
30 | For more details see [#225](https://github.com/watson-developer-cloud/python-sdk/issues/225)
31 |
32 | ## Examples
33 |
34 | The [examples][examples] folder has basic and advanced examples.
35 |
36 | ## Getting the Service Credentials
37 |
38 | Service credentials are required to access the APIs.
39 |
40 | 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.
41 |
42 | 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.)
43 |
44 | To create an instance of the service:
45 |
46 | 1. Log in to [IBM Cloud][ibm_cloud].
47 | 1. Create an instance of the service:
48 | 1. In the IBM Cloud **Catalog**, select the Watson service you want to use. For example, select the Conversation service.
49 | 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.
50 | 1. Click **Create**.
51 |
52 | To get your service credentials:
53 |
54 | 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.
55 |
56 | 1. On the **Service Details** page, click **Service Credentials**, and then **View credentials**.
57 | 1. Copy `username`, `password`, and `url`.
58 |
59 | ## Python Version
60 |
61 | Tested on Python 2.7, 3.4, 3.5, and 3.6.
62 |
63 | ## Changes for v1.0
64 | Version 1.0 focuses on the move to programmatically-generated code for many of the services. See the [changelog](https://github.com/watson-developer-cloud/python-sdk/wiki/Changelog) for the details.
65 |
66 | ## Migration
67 | This version includes many breaking changes as a result of standardizing behavior across the new generated services. Full details on migration from previous versions can be found [here](https://github.com/watson-developer-cloud/python-sdk/wiki/Migration).
68 |
69 | ## Configuring the http client
70 | To set client configs like timeout use the `with_http_config()` function and pass it a dictionary of configs.
71 |
72 | ```python
73 | from watson_developer_cloud import ConversationV1
74 |
75 | conversation = ConversationV1(
76 | username='xxx',
77 | password='yyy',
78 | version='2017-04-21')
79 |
80 | conversation.set_http_config({'timeout': 100})
81 | response = conversation.message(workspace_id=workspace_id, input={
82 | 'text': 'What\'s the weather like?'})
83 | print(json.dumps(response, indent=2))
84 | ```
85 |
86 | ## Dependencies
87 |
88 | * [requests]
89 | * `pysolr` >=3.3, <4.0
90 | * `argparse` >=1.3.0
91 | * `pyOpenSSL` >=16.2.0
92 | * `python_dateutil` >= 2.5.3
93 | * [responses] for testing
94 |
95 | ## Contributing
96 |
97 | See [CONTRIBUTING.md][CONTRIBUTING].
98 |
99 | ## License
100 |
101 | This library is licensed under the [Apache 2.0 license][license].
102 |
103 | [wdc]: http://www.ibm.com/watson/developercloud/
104 | [ibm_cloud]: https://console.bluemix.net
105 | [responses]: https://github.com/getsentry/responses
106 | [requests]: http://docs.python-requests.org/en/latest/
107 | [examples]: https://github.com/watson-developer-cloud/python-sdk/tree/master/examples
108 | [CONTRIBUTING]: https://github.com/watson-developer-cloud/python-sdk/blob/master/CONTRIBUTING.md
109 | [license]: http://www.apache.org/licenses/LICENSE-2.0
110 |
--------------------------------------------------------------------------------
/examples/document_conversion_v1.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | import json
3 | from os.path import join, dirname
4 | from io import open
5 | from watson_developer_cloud import DocumentConversionV1
6 |
7 | document_conversion = DocumentConversionV1(
8 | username='YOUR SERVICE USERNAME',
9 | password='YOUR SERVICE PASSWORD',
10 | version='2016-02-09')
11 |
12 | # Example of retrieving html or plain text
13 | with open(join(dirname(__file__), '../resources/example.html'),
14 | encoding='utf8') as document:
15 | config = {'conversion_target': DocumentConversionV1.NORMALIZED_HTML}
16 | print(document_conversion.convert_document(
17 | document=document, config=config, media_type='text/html').content)
18 |
19 | # Example with JSON
20 | with open(join(dirname(__file__), '../resources/example.html'),
21 | encoding='utf8') as document:
22 | config['conversion_target'] = DocumentConversionV1.ANSWER_UNITS
23 | print(json.dumps(
24 | document_conversion.convert_document(document=document, config=config),
25 | indent=2))
26 |
27 | # Examples of index_document API
28 | print(
29 | "########## Example of a dry run of index_document with only a document "
30 | "##########")
31 | with open(join(dirname(__file__), '../resources/example.html'),
32 | encoding='utf8') as document:
33 | config = {
34 | 'retrieve_and_rank': {
35 | 'dry_run': 'true'
36 | }
37 | }
38 | print(json.dumps(
39 | document_conversion.index_document(config=config, document=document),
40 | indent=2))
41 |
42 | print(
43 | "########## Example of a dry run of index_document with only metadata "
44 | "##########")
45 | config = {
46 | 'retrieve_and_rank': {
47 | 'dry_run': 'true'
48 | }
49 | }
50 | metadata = {
51 | 'metadata': [
52 | {'name': 'id', 'value': '12345'}
53 | ]
54 | }
55 | print(
56 | json.dumps(
57 | document_conversion.index_document(config=config, metadata=metadata),
58 | indent=2))
59 |
60 | print(
61 | "########## Example of a dry run of index_document with document and "
62 | "metadata "
63 | "##########")
64 | with open(join(dirname(__file__), '../resources/example.html'),
65 | encoding='utf8') as document:
66 | config = {
67 | 'retrieve_and_rank': {
68 | 'dry_run': 'true'
69 | }
70 | }
71 | metadata = {
72 | 'metadata': [
73 | {'name': 'id', 'value': '12345'}
74 | ]
75 | }
76 | print(json.dumps(
77 | document_conversion.index_document(config=config, document=document,
78 | metadata=metadata), indent=2))
79 |
80 | print(
81 | "########## Example of a dry run of index_document with document, "
82 | "metadata, "
83 | "and additional config for conversion"
84 | "##########")
85 | with open(join(dirname(__file__), '../resources/example.html'),
86 | encoding='utf8') as document:
87 | config = {
88 | 'convert_document': {
89 | 'normalized_html': {
90 | 'exclude_content': {"xpaths": ["//body/div"]}
91 | }
92 | },
93 | 'retrieve_and_rank': {
94 | 'dry_run': 'true'
95 | }
96 | }
97 | metadata = {
98 | 'metadata': [
99 | {'name': 'id', 'value': '12345'}
100 | ]
101 | }
102 | print(json.dumps(
103 | document_conversion.index_document(config=config, document=document,
104 | metadata=metadata), indent=2))
105 |
106 | # print("########## Example of index_document with document, metadata (A
107 | # service instance id, SOLR cluster id, and "
108 | # "a SOLR collection name must be provided from the Retrieve and Rank
109 | # service in order to index) ##########")
110 | # with open(join(dirname(__file__), '../resources/example.html'), 'r') as
111 | # document:
112 | # config = {
113 | # 'retrieve_and_rank': {
114 | # 'dry_run': 'false',
115 | # 'service_instance_id': 'YOUR RETRIEVE AND RANK SERVICE INSTANCE
116 | # ID',
117 | # 'cluster_id': 'YOUR RETRIEVE AND RANK SERVICE SOLR CLUSTER ID',
118 | # 'search_collection': 'YOUR RETRIEVE AND RANK SERVICE SOLR
119 | # SEARCH COLLECTION NAME'
120 | # }
121 | # }
122 | # metadata = {
123 | # 'metadata': [
124 | # {'name': 'id', 'value': '12345'}
125 | # ]
126 | # }
127 | # print(json.dumps(document_conversion.index_document(config=config,
128 | # document=document,
129 | # metadata=metadata),
130 | # indent=2))
131 |
--------------------------------------------------------------------------------
/test/test_personality_insights_v3.py:
--------------------------------------------------------------------------------
1 | import responses
2 | import watson_developer_cloud
3 | import os
4 | import codecs
5 | from watson_developer_cloud.personality_insights_v3 import Profile
6 |
7 | profile_url = 'https://gateway.watsonplatform.net/personality-insights/api/v3/profile'
8 |
9 | @responses.activate
10 | def test_plain_to_json():
11 |
12 | personality_insights = watson_developer_cloud.PersonalityInsightsV3(
13 | '2016-10-20', username="username", password="password")
14 |
15 | with open(os.path.join(os.path.dirname(__file__), '../resources/personality-v3-expect1.txt')) as expect_file:
16 | profile_response = expect_file.read()
17 |
18 | responses.add(responses.POST, profile_url,
19 | body=profile_response, status=200,
20 | content_type='application/json')
21 |
22 | with open(os.path.join(os.path.dirname(__file__), '../resources/personality-v3.txt')) as personality_text:
23 | response = personality_insights.profile(
24 | personality_text, content_type='text/plain;charset=utf-8')
25 |
26 | assert 'version=2016-10-20' in responses.calls[0].request.url
27 | assert responses.calls[0].response.text == profile_response
28 | assert len(responses.calls) == 1
29 | # Verify that response can be converted to a Profile
30 | Profile._from_dict(response)
31 |
32 | @responses.activate
33 | def test_json_to_json():
34 |
35 | personality_insights = watson_developer_cloud.PersonalityInsightsV3(
36 | '2016-10-20', username="username", password="password")
37 |
38 | with open(os.path.join(os.path.dirname(__file__), '../resources/personality-v3-expect2.txt')) as expect_file:
39 | profile_response = expect_file.read()
40 |
41 | responses.add(responses.POST, profile_url,
42 | body=profile_response, status=200,
43 | content_type='application/json')
44 |
45 | with open(os.path.join(os.path.dirname(__file__), '../resources/personality-v3.json')) as personality_text:
46 | response = personality_insights.profile(
47 | personality_text, content_type='application/json',
48 | raw_scores=True, consumption_preferences=True)
49 |
50 | assert 'version=2016-10-20' in responses.calls[0].request.url
51 | assert 'raw_scores=true' in responses.calls[0].request.url
52 | assert 'consumption_preferences=true' in responses.calls[0].request.url
53 | assert responses.calls[0].response.text == profile_response
54 | assert len(responses.calls) == 1
55 | # Verify that response can be converted to a Profile
56 | Profile._from_dict(response)
57 |
58 | @responses.activate
59 | def test_json_to_csv():
60 |
61 | personality_insights = watson_developer_cloud.PersonalityInsightsV3(
62 | '2016-10-20', username="username", password="password")
63 |
64 | with open(os.path.join(os.path.dirname(__file__), '../resources/personality-v3-expect3.txt')) as expect_file:
65 | profile_response = expect_file.read()
66 |
67 | responses.add(responses.POST, profile_url,
68 | body=profile_response, status=200,
69 | content_type='text/csv')
70 |
71 | with open(os.path.join(os.path.dirname(__file__), '../resources/personality-v3.json')) as personality_text:
72 | personality_insights.profile(
73 | personality_text, content_type='application/json',
74 | accept='text/csv', csv_headers=True,
75 | raw_scores=True, consumption_preferences=True)
76 |
77 | assert 'version=2016-10-20' in responses.calls[0].request.url
78 | assert 'raw_scores=true' in responses.calls[0].request.url
79 | assert 'consumption_preferences=true' in responses.calls[0].request.url
80 | assert 'csv_headers=true' in responses.calls[0].request.url
81 | assert responses.calls[0].response.text == profile_response
82 | assert len(responses.calls) == 1
83 |
84 |
85 | @responses.activate
86 | def test_plain_to_json_es():
87 |
88 | personality_insights = watson_developer_cloud.PersonalityInsightsV3(
89 | '2016-10-20', username="username", password="password")
90 |
91 | with codecs.open(os.path.join(os.path.dirname(__file__), '../resources/personality-v3-expect4.txt'), \
92 | encoding='utf-8') as expect_file:
93 | profile_response = expect_file.read()
94 |
95 | responses.add(responses.POST, profile_url,
96 | body=profile_response, status=200,
97 | content_type='application/json')
98 |
99 | with open(os.path.join(os.path.dirname(__file__), '../resources/personality-v3-es.txt')) as personality_text:
100 | response = personality_insights.profile(
101 | personality_text, content_type='text/plain;charset=utf-8',
102 | content_language='es', accept_language='es')
103 |
104 | assert 'version=2016-10-20' in responses.calls[0].request.url
105 | assert responses.calls[0].response.text == profile_response
106 | assert len(responses.calls) == 1
107 | # Verify that response can be converted to a Profile
108 | Profile._from_dict(response)
109 |
--------------------------------------------------------------------------------
/resources/personality-v3-expect1.txt:
--------------------------------------------------------------------------------
1 | {"word_count":1365,"processed_language":"en","personality":[{"trait_id":"big5_openness","name":"Openness","category":"personality","percentile":0.9970814244982864,"children":[{"trait_id":"facet_adventurousness","name":"Adventurousness","category":"personality","percentile":0.7897453561510369},{"trait_id":"facet_artistic_interests","name":"Artistic interests","category":"personality","percentile":0.9946576519208279},{"trait_id":"facet_emotionality","name":"Emotionality","category":"personality","percentile":0.7671631753694098},{"trait_id":"facet_imagination","name":"Imagination","category":"personality","percentile":0.3116772371947326},{"trait_id":"facet_intellect","name":"Intellect","category":"personality","percentile":0.9965199807027891},{"trait_id":"facet_liberalism","name":"Authority-challenging","category":"personality","percentile":0.797907272149325}]},{"trait_id":"big5_conscientiousness","name":"Conscientiousness","category":"personality","percentile":0.986401677449357,"children":[{"trait_id":"facet_achievement_striving","name":"Achievement striving","category":"personality","percentile":0.8403728912342907},{"trait_id":"facet_cautiousness","name":"Cautiousness","category":"personality","percentile":0.944186945742299},{"trait_id":"facet_dutifulness","name":"Dutifulness","category":"personality","percentile":0.7946276293038717},{"trait_id":"facet_orderliness","name":"Orderliness","category":"personality","percentile":0.7610741506407186},{"trait_id":"facet_self_discipline","name":"Self-discipline","category":"personality","percentile":0.712864917583896},{"trait_id":"facet_self_efficacy","name":"Self-efficacy","category":"personality","percentile":0.6994302718651364}]},{"trait_id":"big5_extraversion","name":"Extraversion","category":"personality","percentile":0.08530058556548259,"children":[{"trait_id":"facet_activity_level","name":"Activity level","category":"personality","percentile":0.962401631341592},{"trait_id":"facet_assertiveness","name":"Assertiveness","category":"personality","percentile":0.9198609213386704},{"trait_id":"facet_cheerfulness","name":"Cheerfulness","category":"personality","percentile":0.2293639969883699},{"trait_id":"facet_excitement_seeking","name":"Excitement-seeking","category":"personality","percentile":0.21024192850794732},{"trait_id":"facet_friendliness","name":"Outgoing","category":"personality","percentile":0.7085191412979603},{"trait_id":"facet_gregariousness","name":"Gregariousness","category":"personality","percentile":0.22458619358372}]},{"trait_id":"big5_agreeableness","name":"Agreeableness","category":"personality","percentile":0.1875352860319472,"children":[{"trait_id":"facet_altruism","name":"Altruism","category":"personality","percentile":0.9713302006331768},{"trait_id":"facet_cooperation","name":"Cooperation","category":"personality","percentile":0.8229934901276204},{"trait_id":"facet_modesty","name":"Modesty","category":"personality","percentile":0.761318814834163},{"trait_id":"facet_morality","name":"Uncompromising","category":"personality","percentile":0.9471478882849421},{"trait_id":"facet_sympathy","name":"Sympathy","category":"personality","percentile":0.9991179451374892},{"trait_id":"facet_trust","name":"Trust","category":"personality","percentile":0.830111046812001}]},{"trait_id":"big5_neuroticism","name":"Emotional range","category":"personality","percentile":0.9438564164580463,"children":[{"trait_id":"facet_anger","name":"Fiery","category":"personality","percentile":0.013938100678608567},{"trait_id":"facet_anxiety","name":"Prone to worry","category":"personality","percentile":0.062025789454073055},{"trait_id":"facet_depression","name":"Melancholy","category":"personality","percentile":0.35285841125133055},{"trait_id":"facet_immoderation","name":"Immoderation","category":"personality","percentile":0.011684379342279061},{"trait_id":"facet_self_consciousness","name":"Self-consciousness","category":"personality","percentile":0.19347068940127837},{"trait_id":"facet_vulnerability","name":"Susceptible to stress","category":"personality","percentile":0.06994539774378672}]}],"needs":[{"trait_id":"need_challenge","name":"Challenge","category":"needs","percentile":0.0032546536914939694},{"trait_id":"need_closeness","name":"Closeness","category":"needs","percentile":0.37022781101806856},{"trait_id":"need_curiosity","name":"Curiosity","category":"needs","percentile":0.845180482624851},{"trait_id":"need_excitement","name":"Excitement","category":"needs","percentile":0.11505596926601303},{"trait_id":"need_harmony","name":"Harmony","category":"needs","percentile":0.4664217424750215},{"trait_id":"need_ideal","name":"Ideal","category":"needs","percentile":0.02263412995273062},{"trait_id":"need_liberty","name":"Liberty","category":"needs","percentile":0.10802987716456186},{"trait_id":"need_love","name":"Love","category":"needs","percentile":0.01189533382101321},{"trait_id":"need_practicality","name":"Practicality","category":"needs","percentile":0.018888178951272983},{"trait_id":"need_self_expression","name":"Self-expression","category":"needs","percentile":0.18489782806561655},{"trait_id":"need_stability","name":"Stability","category":"needs","percentile":0.3946227431440047},{"trait_id":"need_structure","name":"Structure","category":"needs","percentile":0.8880129689346332}],"values":[{"trait_id":"value_conservation","name":"Conservation","category":"values","percentile":0.5065929218618456},{"trait_id":"value_openness_to_change","name":"Openness to change","category":"values","percentile":0.6287516949462554},{"trait_id":"value_hedonism","name":"Hedonism","category":"values","percentile":0.005253658217920731},{"trait_id":"value_self_enhancement","name":"Self-enhancement","category":"values","percentile":0.0011936431143393933},{"trait_id":"value_self_transcendence","name":"Self-transcendence","category":"values","percentile":0.3429609693883737}],"warnings":[]}
2 |
--------------------------------------------------------------------------------
/watson_developer_cloud/dialog_v1.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 IBM All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """
16 | The v1 Dialog service
17 | (https://www.ibm.com/watson/developercloud/dialog.html)
18 | """
19 | from __future__ import print_function
20 | from .watson_service import WatsonService
21 |
22 |
23 | class DialogV1(WatsonService):
24 | default_url = 'https://gateway.watsonplatform.net/dialog/api'
25 | dialog_json_format = 'application/wds+json'
26 | dialog_xml_format = 'application/wds+xml'
27 | dialog_binary_format = 'application/octet-stream'
28 |
29 | def __init__(self, url=default_url, **kwargs):
30 | WatsonService.__init__(self, 'dialog', url, **kwargs)
31 | print(
32 | 'WARNING: The Dialog service was deprecated. Existing instances '
33 | 'of the service stopped functioning on August 9, 2017. '
34 | 'Dialog was replaced by the Conversation service. See '
35 | 'https://console.bluemix.net/docs/services/conversation'
36 | '/index.html#about')
37 |
38 | def get_dialogs(self):
39 | return self.request(method='GET', url='/v1/dialogs', accept_json=True)
40 |
41 | def get_dialog(self, dialog_id, accept='application/wds+json'):
42 | accept_json = accept == self.dialog_json_format
43 | headers = {'accept': accept}
44 | return self.request(method='GET',
45 | url='/v1/dialogs/{0}'.format(dialog_id),
46 | headers=headers,
47 | accept_json=accept_json)
48 |
49 | def create_dialog(self, dialog_file, name):
50 | return self.request(method='POST', url='/v1/dialogs',
51 | files={'file': dialog_file}, accept_json=True,
52 | data={'name': name})
53 |
54 | def update_dialog(self, dialog_id, dialog_file):
55 | dialog_id = self.unpack_id(dialog_id, 'dialog_id')
56 | return self.request(method='PUT',
57 | url='/v1/dialogs/{0}'.format(dialog_id),
58 | files={'file': dialog_file},
59 | accept_json=True)
60 |
61 | def get_content(self, dialog_id):
62 | dialog_id = self.unpack_id(dialog_id, 'dialog_id')
63 | return self.request(method='GET',
64 | url='/v1/dialogs/{0}/content'.format(dialog_id),
65 | accept_json=True)
66 |
67 | def update_content(self, dialog_id, content):
68 | dialog_id = self.unpack_id(dialog_id, 'dialog_id')
69 | return self.request(method='PUT',
70 | url='/v1/dialogs/{0}/content'.format(dialog_id),
71 | json=content,
72 | accept_json=True)
73 |
74 | def conversation(self, dialog_id, dialog_input=None, client_id=None,
75 | conversation_id=None):
76 | dialog_id = self.unpack_id(dialog_id, 'dialog_id')
77 | data = {'input': dialog_input, 'client_id': client_id,
78 | 'conversation_id': conversation_id}
79 | return self.request(method='POST',
80 | url='/v1/dialogs/{0}/conversation'.format(
81 | dialog_id), data=data,
82 | accept_json=True)
83 |
84 | @staticmethod
85 | def _format_date(date):
86 | if date:
87 | return date.strftime('%Y-%m-%d %H:%M:%S')
88 |
89 | def get_conversation(self, dialog_id, date_from, date_to):
90 | dialog_id = self.unpack_id(dialog_id, 'dialog_id')
91 | params = {'date_from': self._format_date(
92 | date_from), 'date_to': self._format_date(date_to)}
93 | return self.request(method='GET',
94 | url='/v1/dialogs/{0}/conversation'.format(
95 | dialog_id), params=params,
96 | accept_json=True)
97 |
98 | def get_profile(self, dialog_id, client_id, name=None):
99 | dialog_id = self.unpack_id(dialog_id, 'dialog_id')
100 | client_id = self.unpack_id(client_id, 'client_id')
101 | params = {'client_id': client_id, 'name': name}
102 | return self.request(method='GET',
103 | url='/v1/dialogs/{0}/profile'.format(dialog_id),
104 | params=params,
105 | accept_json=True)
106 |
107 | def update_profile(self, dialog_id, name_values, client_id=None):
108 | dialog_id = self.unpack_id(dialog_id, 'dialog_id')
109 | client_id = self.unpack_id(client_id, 'client_id')
110 | if isinstance(name_values, dict):
111 | name_values = list({'name': item[0], 'value': item[1]} for item in
112 | name_values.items())
113 | params = {
114 | 'client_id': client_id,
115 | 'name_values': name_values
116 | }
117 | return self.request(method='PUT',
118 | url='/v1/dialogs/{0}/profile'.format(dialog_id),
119 | json=params,
120 | accept_json=True)
121 |
122 | def delete_dialog(self, dialog_id):
123 | dialog_id = self.unpack_id(dialog_id, 'dialog_id')
124 | return self.request(method='DELETE',
125 | url='/v1/dialogs/{0}'.format(dialog_id),
126 | accept_json=True)
127 |
--------------------------------------------------------------------------------
/watson_developer_cloud/text_to_speech_v1.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 IBM All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | The v1 Text to Speech service
16 | (https://www.ibm.com/watson/developercloud/text-to-speech.html)
17 | """
18 |
19 | from .watson_service import WatsonService
20 |
21 |
22 | class TextToSpeechV1(WatsonService):
23 | """Client for the Text to Speech service"""
24 | default_url = "https://stream.watsonplatform.net/text-to-speech/api"
25 |
26 | def __init__(self, url=default_url, **kwargs):
27 | """
28 | Construct an instance. Fetches service parameters from VCAP_SERVICES
29 | runtime variable for Bluemix, or it defaults to local URLs.
30 | """
31 | WatsonService.__init__(self, 'text_to_speech', url, **kwargs)
32 |
33 | def synthesize(self, text, voice=None, accept=None, customization_id=None):
34 | """
35 | Returns the get HTTP response by doing a POST to /synthesize with
36 | text, voice, accept
37 | """
38 | params = {'voice': voice, 'accept': accept,
39 | 'customization_id': customization_id}
40 | data = {'text': text}
41 | response = self.request(
42 | method='POST', url='/v1/synthesize', stream=True, params=params,
43 | json=data)
44 | return response.content
45 |
46 | def voices(self):
47 | """
48 | Returns the list of available voices to use with synthesize
49 | """
50 | return self.request(method='GET', url='/v1/voices', accept_json=True)
51 |
52 | def pronunciation(self, text, voice=None, pronunciation_format='ipa'):
53 | params = {
54 | 'text': text,
55 | 'voice': voice,
56 | 'format': pronunciation_format
57 | }
58 | return self.request(method='GET', url='/v1/pronunciation',
59 | params=params, accept_json=True)
60 |
61 | def customizations(self, language=None):
62 | params = {
63 | 'language': language
64 | }
65 | return self.request(method='GET', url='/v1/customizations',
66 | params=params, accept_json=True)
67 |
68 | def get_customization(self, customization_id):
69 | customization_id = self.unpack_id(customization_id, 'customization_id')
70 | return self.request(method='GET', url='/v1/customizations/{0}'.format(
71 | customization_id), accept_json=True)
72 |
73 | def create_customization(self, name, language=None, description=None):
74 | body = {
75 | 'name': name,
76 | 'language': language,
77 | 'description': description
78 | }
79 | return self.request(method='POST', url='/v1/customizations', json=body,
80 | accept_json=True)
81 |
82 | def update_customization(self, customization_id, name=None,
83 | description=None, words=None):
84 | body = {
85 | 'name': name,
86 | 'description': description,
87 | 'words': words
88 | }
89 | return self.request(method='POST', url='/v1/customizations/{0}'.format(
90 | customization_id), json=body)
91 |
92 | def delete_customization(self, customization_id):
93 | customization_id = self.unpack_id(customization_id, 'customization_id')
94 | return self.request(method='DELETE',
95 | url='/v1/customizations/{0}'.format(
96 | customization_id))
97 |
98 | def get_customization_words(self, customization_id):
99 | customization_id = self.unpack_id(customization_id, 'customization_id')
100 | return self.request(method='GET',
101 | url='/v1/customizations/{0}/words'.format(
102 | customization_id), accept_json=True)
103 |
104 | def add_customization_words(self, customization_id, words):
105 | customization_id = self.unpack_id(customization_id, 'customization_id')
106 | body = {
107 | 'words': words
108 | }
109 | return self.request(method='POST',
110 | url='/v1/customizations/{0}/words'.format(
111 | customization_id), json=body)
112 |
113 | def get_customization_word(self, customization_id, word):
114 | customization_id = self.unpack_id(customization_id, 'customization_id')
115 | return self.request(method='GET',
116 | url='/v1/customizations/{0}/words/{1}'.format(
117 | customization_id, word),
118 | accept_json=True)
119 |
120 | def set_customization_word(self, customization_id, word, translation):
121 | customization_id = self.unpack_id(customization_id, 'customization_id')
122 | body = {
123 | 'translation': translation
124 | }
125 | return self.request(method='PUT',
126 | url='/v1/customizations/{0}/words/{1}'.format(
127 | customization_id, word),
128 | json=body)
129 |
130 | def delete_customization_word(self, customization_id, word):
131 | customization_id = self.unpack_id(customization_id, 'customization_id')
132 | return self.request(method='DELETE',
133 | url='/v1/customizations/{0}/words/{1}'.format(
134 | customization_id, word))
135 |
--------------------------------------------------------------------------------
/test/test_tone_analyzer_v3.py:
--------------------------------------------------------------------------------
1 | import responses
2 | import watson_developer_cloud
3 | from watson_developer_cloud import WatsonException
4 | from watson_developer_cloud import WatsonApiException
5 | import os
6 | import json
7 |
8 |
9 | @responses.activate
10 | # Simple test, just calling tone() with some text
11 | def test_tone():
12 | tone_url = 'https://gateway.watsonplatform.net/tone-analyzer/api/v3/tone'
13 | tone_args = '?version=2016-05-19'
14 | tone_response = None
15 | with open(os.path.join(os.path.dirname(__file__), '../resources/tone-v3-expect1.json')) as response_json:
16 | tone_response = response_json.read()
17 |
18 | responses.add(responses.POST, tone_url,
19 | body=tone_response, status=200,
20 | content_type='application/json')
21 |
22 | with open(os.path.join(os.path.dirname(__file__), '../resources/personality.txt')) as tone_text:
23 | tone_analyzer = watson_developer_cloud.ToneAnalyzerV3("2016-05-19",
24 | username="username", password="password")
25 | tone_analyzer.tone(tone_text.read())
26 |
27 | assert responses.calls[0].request.url == tone_url + tone_args
28 | assert responses.calls[0].response.text == tone_response
29 |
30 | assert len(responses.calls) == 1
31 |
32 |
33 | @responses.activate
34 | # Invoking tone() with some modifiers given in 'params': sentences skipped
35 | def test_tone_with_args():
36 | tone_url = 'https://gateway.watsonplatform.net/tone-analyzer/api/v3/tone'
37 | tone_args = {'version': '2016-05-19', 'sentences': 'false'}
38 | tone_response = None
39 | with open(os.path.join(os.path.dirname(__file__), '../resources/tone-v3-expect1.json')) as response_json:
40 | tone_response = response_json.read()
41 |
42 | responses.add(responses.POST, tone_url,
43 | body=tone_response, status=200,
44 | content_type='application/json')
45 |
46 | with open(os.path.join(os.path.dirname(__file__), '../resources/personality.txt')) as tone_text:
47 | tone_analyzer = watson_developer_cloud.ToneAnalyzerV3("2016-05-19",
48 | username="username", password="password")
49 | tone_analyzer.tone(tone_text.read(), sentences=False)
50 |
51 | assert responses.calls[0].request.url.split('?')[0] == tone_url
52 | # Compare args. Order is not deterministic!
53 | actualArgs = {}
54 | for arg in responses.calls[0].request.url.split('?')[1].split('&'):
55 | actualArgs[arg.split('=')[0]] = arg.split('=')[1]
56 | assert actualArgs == tone_args
57 | assert responses.calls[0].response.text == tone_response
58 | assert len(responses.calls) == 1
59 |
60 |
61 | @responses.activate
62 | # Invoking tone() with some modifiers specified as positional parameters: sentences is false
63 | def test_tone_with_positional_args():
64 | tone_url = 'https://gateway.watsonplatform.net/tone-analyzer/api/v3/tone'
65 | tone_args = {'version': '2016-05-19', 'sentences': 'false'}
66 | tone_response = None
67 | with open(os.path.join(os.path.dirname(__file__), '../resources/tone-v3-expect1.json')) as response_json:
68 | tone_response = response_json.read()
69 |
70 | responses.add(responses.POST, tone_url,
71 | body=tone_response, status=200,
72 | content_type='application/json')
73 |
74 | with open(os.path.join(os.path.dirname(__file__), '../resources/personality.txt')) as tone_text:
75 | tone_analyzer = watson_developer_cloud.ToneAnalyzerV3("2016-05-19",
76 | username="username", password="password")
77 | tone_analyzer.tone(tone_text.read(), 'application/json', False)
78 |
79 | assert responses.calls[0].request.url.split('?')[0] == tone_url
80 | # Compare args. Order is not deterministic!
81 | actualArgs = {}
82 | for arg in responses.calls[0].request.url.split('?')[1].split('&'):
83 | actualArgs[arg.split('=')[0]] = arg.split('=')[1]
84 | assert actualArgs == tone_args
85 | assert responses.calls[0].response.text == tone_response
86 | assert len(responses.calls) == 1
87 |
88 |
89 | @responses.activate
90 | # Invoking tone_chat()
91 | def test_tone_chat():
92 | tone_url = 'https://gateway.watsonplatform.net/tone-analyzer/api/v3/tone_chat'
93 | tone_args = '?version=2016-05-19'
94 | tone_response = None
95 | with open(os.path.join(os.path.dirname(__file__), '../resources/tone-v3-expect2.json')) as response_json:
96 | tone_response = response_json.read()
97 |
98 | responses.add(responses.POST, tone_url,
99 | body=tone_response, status=200,
100 | content_type='application/json')
101 |
102 | tone_analyzer = watson_developer_cloud.ToneAnalyzerV3("2016-05-19",
103 | username="username", password="password")
104 | utterances = [{'text': 'I am very happy', 'user': 'glenn'}]
105 | tone_analyzer.tone_chat(utterances)
106 |
107 | assert responses.calls[0].request.url == tone_url + tone_args
108 | assert responses.calls[0].response.text == tone_response
109 | assert len(responses.calls) == 1
110 |
111 |
112 | #########################
113 | # error response
114 | #########################
115 |
116 |
117 | @responses.activate
118 | def test_error():
119 | tone_url = 'https://gateway.watsonplatform.net/tone-analyzer/api/v3/tone'
120 | error_code = 400
121 | error_message = "Invalid JSON input at line 2, column 12"
122 | tone_response = {
123 | "code": error_code,
124 | "sub_code": "C00012",
125 | "error": error_message
126 | }
127 | responses.add(responses.POST,
128 | tone_url,
129 | body=json.dumps(tone_response),
130 | status=error_code,
131 | content_type='application/json')
132 |
133 | tone_analyzer = watson_developer_cloud.ToneAnalyzerV3("2016-05-19",
134 | username="username", password="password")
135 | text = "Team, I know that times are tough!"
136 | try:
137 | tone_analyzer.tone(text)
138 | except WatsonException as ex:
139 | assert len(responses.calls) == 1
140 | assert isinstance(ex, WatsonApiException)
141 | assert ex.code == error_code
142 | assert ex.message == error_message
143 | assert len(ex.info) == 1
144 | assert ex.info['sub_code'] == 'C00012'
145 |
--------------------------------------------------------------------------------
/watson_developer_cloud/retrieve_and_rank_v1.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 IBM All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """
16 | The v1 Retrieve and Rank service
17 | (https://www.ibm.com/watson/developercloud/retrieve-rank.html)
18 | """
19 |
20 | import json
21 | import pysolr
22 | from watson_developer_cloud.watson_service import WatsonService
23 |
24 |
25 | class RetrieveAndRankV1(WatsonService):
26 | default_url = 'https://gateway.watsonplatform.net/retrieve-and-rank/api'
27 |
28 | def __init__(self, url=default_url, **kwargs):
29 | WatsonService.__init__(self, 'retrieve_and_rank', url, **kwargs)
30 |
31 | def list_solr_clusters(self):
32 | return self.request(method='GET', url='/v1/solr_clusters',
33 | accept_json=True)
34 |
35 | def create_solr_cluster(self, cluster_name=None, cluster_size=None):
36 | if cluster_size:
37 | cluster_size = str(cluster_size)
38 | params = {'cluster_name': cluster_name, 'cluster_size': cluster_size}
39 | return self.request(method='POST', url='/v1/solr_clusters',
40 | accept_json=True, json=params)
41 |
42 | def delete_solr_cluster(self, solr_cluster_id):
43 | return self.request(method='DELETE',
44 | url='/v1/solr_clusters/{0}'.format(
45 | solr_cluster_id),
46 | accept_json=True)
47 |
48 | def get_solr_cluster_status(self, solr_cluster_id):
49 | return self.request(method='GET',
50 | url='/v1/solr_clusters/{0}'.format(
51 | solr_cluster_id),
52 | accept_json=True)
53 |
54 | def list_configs(self, solr_cluster_id):
55 | return self.request(method='GET',
56 | url='/v1/solr_clusters/{0}/config'.format(
57 | solr_cluster_id), accept_json=True)
58 |
59 | # Need to test
60 | def create_config(self, solr_cluster_id, config_name, config):
61 | return self.request(method='POST',
62 | url='/v1/solr_clusters/{0}/config/{1}'.format(
63 | solr_cluster_id, config_name),
64 | files={'body': config},
65 | headers={'content-type': 'application/zip'},
66 | accept_json=True)
67 |
68 | def delete_config(self, solr_cluster_id, config_name):
69 | return self.request(method='DELETE',
70 | url='/v1/solr_clusters/{0}/config/{1}'.format(
71 | solr_cluster_id, config_name),
72 | accept_json=True)
73 |
74 | def get_config(self, solr_cluster_id, config_name):
75 | return self.request(method='GET',
76 | url='/v1/solr_clusters/{0}/config/{1}'.format(
77 | solr_cluster_id, config_name))
78 |
79 | def list_collections(self, solr_cluster_id):
80 | params = {'action': 'LIST', 'wt': 'json'}
81 | return self.request(method='GET',
82 | url='/v1/solr_clusters/{0}/solr/admin/collections'
83 | .format(solr_cluster_id),
84 | params=params, accept_json=True)
85 |
86 | def create_collection(self, solr_cluster_id, collection_name, config_name):
87 | params = {'collection.configName': config_name,
88 | 'name': collection_name,
89 | 'action': 'CREATE', 'wt': 'json'}
90 | return self.request(method='POST',
91 | url='/v1/solr_clusters/{0}/solr/admin/collections'
92 | .format(solr_cluster_id),
93 | params=params, accept_json=True)
94 |
95 | def delete_collection(self, solr_cluster_id, collection_name,
96 | config_name=None):
97 | params = {'name': collection_name, 'action': 'DELETE', 'wt': 'json'}
98 | return self.request(method='POST',
99 | url='/v1/solr_clusters/{0}/solr/admin/collections'
100 | .format(solr_cluster_id),
101 | params=params, accept_json=True)
102 |
103 | def get_pysolr_client(self, solr_cluster_id, collection_name):
104 | base_url = self.url.replace('https://',
105 | 'https://' + self.username + ':' +
106 | self.password + '@')
107 | url = base_url + '/v1/solr_clusters/{0}/solr/{1}'.format(
108 | solr_cluster_id, collection_name)
109 | return pysolr.Solr(url)
110 |
111 | def create_ranker(self, training_data, name=None):
112 | data = None
113 | if name:
114 | data = {'training_metadata': json.dumps({'name': name})}
115 | return self.request(method='POST', url='/v1/rankers', accept_json=True,
116 | files=[('training_data', training_data)],
117 | data=data)
118 |
119 | def list_rankers(self):
120 | return self.request(method='GET', url='/v1/rankers', accept_json=True)
121 |
122 | def get_ranker_status(self, ranker_id):
123 | return self.request(method='GET',
124 | url='/v1/rankers/{0}'.format(ranker_id),
125 | accept_json=True)
126 |
127 | def rank(self, ranker_id, answer_data, top_answers=10):
128 | data = {'answers': + top_answers}
129 | return self.request(method='POST',
130 | url='/v1/rankers/{0}/rank'.format(ranker_id),
131 | files=[('answer_data', answer_data)], data=data,
132 | accept_json=True)
133 |
134 | def delete_ranker(self, ranker_id):
135 | return self.request(method='DELETE',
136 | url='/v1/rankers/{0}'.format(ranker_id),
137 | accept_json=True)
138 |
--------------------------------------------------------------------------------
/resources/personality-v3-expect3.txt:
--------------------------------------------------------------------------------
1 | big5_agreeableness,facet_altruism,facet_cooperation,facet_modesty,facet_morality,facet_sympathy,facet_trust,big5_conscientiousness,facet_achievement_striving,facet_cautiousness,facet_dutifulness,facet_orderliness,facet_self_discipline,facet_self_efficacy,big5_extraversion,facet_activity_level,facet_assertiveness,facet_cheerfulness,facet_excitement_seeking,facet_friendliness,facet_gregariousness,big5_neuroticism,facet_anger,facet_anxiety,facet_depression,facet_immoderation,facet_self_consciousness,facet_vulnerability,big5_openness,facet_adventurousness,facet_artistic_interests,facet_emotionality,facet_imagination,facet_intellect,facet_liberalism,need_liberty,need_ideal,need_love,need_practicality,need_self_expression,need_stability,need_structure,need_challenge,need_closeness,need_curiosity,need_excitement,need_harmony,value_conservation,value_hedonism,value_openness_to_change,value_self_enhancement,value_self_transcendence,behavior_sunday,behavior_monday,behavior_tuesday,behavior_wednesday,behavior_thursday,behavior_friday,behavior_saturday,behavior_0000,behavior_0100,behavior_0200,behavior_0300,behavior_0400,behavior_0500,behavior_0600,behavior_0700,behavior_0800,behavior_0900,behavior_1000,behavior_1100,behavior_1200,behavior_1300,behavior_1400,behavior_1500,behavior_1600,behavior_1700,behavior_1800,behavior_1900,behavior_2000,behavior_2100,behavior_2200,behavior_2300,word_count,processed_language,big5_agreeableness_raw,facet_altruism_raw,facet_cooperation_raw,facet_modesty_raw,facet_morality_raw,facet_sympathy_raw,facet_trust_raw,big5_conscientiousness_raw,facet_achievement_striving_raw,facet_cautiousness_raw,facet_dutifulness_raw,facet_orderliness_raw,facet_self_discipline_raw,facet_self_efficacy_raw,big5_extraversion_raw,facet_activity_level_raw,facet_assertiveness_raw,facet_cheerfulness_raw,facet_excitement_seeking_raw,facet_friendliness_raw,facet_gregariousness_raw,big5_neuroticism_raw,facet_anger_raw,facet_anxiety_raw,facet_depression_raw,facet_immoderation_raw,facet_self_consciousness_raw,facet_vulnerability_raw,big5_openness_raw,facet_adventurousness_raw,facet_artistic_interests_raw,facet_emotionality_raw,facet_imagination_raw,facet_intellect_raw,facet_liberalism_raw,need_liberty_raw,need_ideal_raw,need_love_raw,need_practicality_raw,need_self_expression_raw,need_stability_raw,need_structure_raw,need_challenge_raw,need_closeness_raw,need_curiosity_raw,need_excitement_raw,need_harmony_raw,value_conservation_raw,value_hedonism_raw,value_openness_to_change_raw,value_self_enhancement_raw,value_self_transcendence_raw,consumption_preferences_spur_of_moment,consumption_preferences_credit_card_payment,consumption_preferences_influence_brand_name,consumption_preferences_influence_utility,consumption_preferences_influence_online_ads,consumption_preferences_influence_social_media,consumption_preferences_influence_family_members,consumption_preferences_clothes_quality,consumption_preferences_clothes_style,consumption_preferences_clothes_comfort,consumption_preferences_automobile_ownership_cost,consumption_preferences_automobile_safety,consumption_preferences_automobile_resale_value,consumption_preferences_music_rap,consumption_preferences_music_country,consumption_preferences_music_r_b,consumption_preferences_music_hip_hop,consumption_preferences_music_live_event,consumption_preferences_music_playing,consumption_preferences_music_latin,consumption_preferences_music_rock,consumption_preferences_music_classical,consumption_preferences_gym_membership,consumption_preferences_adventurous_sports,consumption_preferences_outdoor,consumption_preferences_eat_out,consumption_preferences_fast_food_frequency,consumption_preferences_movie_romance,consumption_preferences_movie_adventure,consumption_preferences_movie_horror,consumption_preferences_movie_musical,consumption_preferences_movie_historical,consumption_preferences_movie_science_fiction,consumption_preferences_movie_war,consumption_preferences_movie_drama,consumption_preferences_movie_action,consumption_preferences_movie_documentary,consumption_preferences_read_frequency,consumption_preferences_read_motive_enjoyment,consumption_preferences_read_motive_information,consumption_preferences_read_motive_mandatory,consumption_preferences_read_motive_relaxation,consumption_preferences_books_entertainment_magazines,consumption_preferences_books_non_fiction,consumption_preferences_books_financial_investing,consumption_preferences_books_autobiographies,consumption_preferences_volunteer,consumption_preferences_volunteering_time,consumption_preferences_volunteer_learning,consumption_preferences_concerned_environment,consumption_preferences_start_business
2 | 0.1875352860319472,0.9713302006331768,0.8229934901276204,0.761318814834163,0.9471478882849421,0.9991179451374892,0.830111046812001,0.986401677449357,0.8403728912342907,0.944186945742299,0.7946276293038717,0.7610741506407186,0.712864917583896,0.6994302718651364,0.08530058556548259,0.962401631341592,0.9198609213386704,0.2293639969883699,0.21024192850794732,0.7085191412979603,0.22458619358372,0.9438564164580463,0.013938100678608567,0.062025789454073055,0.35285841125133055,0.011684379342279061,0.19347068940127837,0.06994539774378672,0.9970814244982864,0.7897453561510369,0.9946576519208279,0.7671631753694098,0.3116772371947326,0.9965199807027891,0.797907272149325,0.10802987716456186,0.02263412995273062,0.01189533382101321,0.018888178951272983,0.18489782806561655,0.3946227431440047,0.8880129689346332,0.0032546536914939694,0.37022781101806856,0.845180482624851,0.11505596926601303,0.4664217424750215,0.5065929218618456,0.005253658217920731,0.6287516949462554,0.0011936431143393933,0.3429609693883737,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1365,en,0.7069355244930271,0.7717679751112927,0.6352286286618323,0.4858691141214019,0.702145642516,0.7828928930725229,0.6251288245815745,0.731065896229928,0.7411306938189824,0.5929015783660554,0.6790451583920154,0.5174048448459116,0.5974142772332323,0.7714843433917522,0.4898595875512197,0.6314221244549749,0.7142519242541164,0.5932729161331092,0.5694475628767053,0.5880272412488141,0.4144362156057161,0.5568839124901138,0.41546033577632724,0.489225611469312,0.42452148443292836,0.41344777510142944,0.5011894182219927,0.37357140402417355,0.83666730981323,0.5334674872694041,0.7945583831155767,0.677937382446223,0.7104655052955525,0.7321638770376435,0.5582434731245067,0.6901684496009852,0.5959081695663969,0.6586965498215966,0.6828926516103326,0.6441012500714469,0.7259366269839532,0.7290291261454519,0.6097534338543016,0.7786579590270303,0.8433898277044034,0.5898767782432288,0.8063478875213775,0.6661941759119986,0.5746924423258591,0.7969374222994671,0.5730785322934739,0.8263720901347662,0.0,1.0,0.0,1.0,1.0,0.0,1.0,1.0,0.0,1.0,0.5,0.0,1.0,0.0,0.5,1.0,0.5,0.0,0.0,1.0,0.5,1.0,0.0,0.0,0.5,0.0,0.0,0.0,1.0,0.0,0.0,1.0,1.0,0.0,0.0,1.0,1.0,1.0,1.0,1.0,0.0,1.0,0.0,1.0,0.0,0.0,1.0,1.0,0.0,1.0,0.5
3 |
--------------------------------------------------------------------------------
/test/test_text_to_speech_v1.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | import responses
3 | import watson_developer_cloud
4 |
5 |
6 | @responses.activate
7 | def test_success():
8 | voices_url = 'https://stream.watsonplatform.net/text-to-speech/api/v1/voices'
9 | voices_response = '{"voices": [{"url": "https://stream.watsonplatform.net/text-to-speech/api/v1/voices/' \
10 | 'VoiceEnUsLisa", "gender": "female", "name": "VoiceEnUsLisa", "language": "en-US"}, {"url": ' \
11 | '"https://stream.watsonplatform.net/text-to-speech/api/v1/voices/VoiceEsEsEnrique", ' \
12 | '"gender": "male", "name": "VoiceEsEsEnrique", "language": "es-ES"}, {"url": ' \
13 | '"https://stream.watsonplatform.net/text-to-speech/api/v1/voices/VoiceEnUsMichael", ' \
14 | '"gender": "male", "name": "VoiceEnUsMichael", "language": "en-US"}, {"url": ' \
15 | '"https://stream.watsonplatform.net/text-to-speech/api/v1/voices/VoiceEnUsAllison", ' \
16 | '"gender": "female", "name": "VoiceEnUsAllison", "language": "en-US"}]}'
17 |
18 | responses.add(responses.GET, voices_url, body=voices_response,
19 | status=200, content_type='application/json')
20 |
21 | text_to_speech = watson_developer_cloud.TextToSpeechV1(
22 | username="username", password="password")
23 | text_to_speech.voices()
24 |
25 | assert responses.calls[0].request.url == voices_url
26 | assert responses.calls[0].response.text == voices_response
27 |
28 | synthesize_text = 'hello'
29 | synthesize_url = 'https://stream.watsonplatform.net/text-to-speech/api/v1/synthesize'
30 | synthesize_response_body = ''
31 |
32 | responses.add(responses.POST, synthesize_url,
33 | body=synthesize_response_body, status=200,
34 | content_type='application/json', match_querystring=True)
35 | text_to_speech.synthesize(synthesize_text)
36 |
37 | assert responses.calls[1].request.url == synthesize_url
38 | assert responses.calls[1].response.text == synthesize_response_body
39 |
40 | assert len(responses.calls) == 2
41 |
42 |
43 | @responses.activate
44 | def test_pronounciation():
45 |
46 | responses.add(responses.GET, 'https://stream.watsonplatform.net/text-to-speech/api/v1/pronunciation',
47 | body='{"pronunciation": "pronunciation info" }',
48 | status=200, content_type='application_json')
49 |
50 | text_to_speech = watson_developer_cloud.TextToSpeechV1(
51 | username="username", password="password")
52 | text_to_speech.pronunciation(text="this is some text")
53 | text_to_speech.pronunciation(text="yo", voice="VoiceEnUsLisa")
54 | text_to_speech.pronunciation(
55 | text="yo", voice="VoiceEnUsLisa", pronunciation_format='ipa')
56 |
57 | assert len(responses.calls) == 3
58 |
59 |
60 | @responses.activate
61 | def test_customizations():
62 | responses.add(responses.GET, 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations',
63 | body='{"customizations": "yep" }',
64 | status=200, content_type='application_json')
65 | responses.add(responses.POST, 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations',
66 | body='{"customizations": "yep" }',
67 | status=200, content_type='application_json')
68 | responses.add(responses.GET, 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations/custid',
69 | body='{"customization": "yep, just one" }',
70 | status=200, content_type='application_json')
71 | responses.add(responses.POST, 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations/custid',
72 | body='{"customizations": "yep" }',
73 | status=200, content_type='application_json')
74 | responses.add(responses.DELETE, 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations/custid',
75 | body='{"customizations": "yep" }',
76 | status=200, content_type='application_json')
77 |
78 | text_to_speech = watson_developer_cloud.TextToSpeechV1(
79 | username="username", password="password")
80 | text_to_speech.customizations()
81 | text_to_speech.customizations(language="en-US")
82 | assert len(responses.calls) == 2
83 |
84 | text_to_speech.create_customization(name="name", description="description")
85 | text_to_speech.get_customization(customization_id='custid')
86 | text_to_speech.update_customization(
87 | customization_id="custid", name="name", description="description")
88 | text_to_speech.delete_customization(customization_id="custid")
89 |
90 | assert len(responses.calls) == 6
91 |
92 |
93 | @responses.activate
94 | def test_customization_words():
95 | base_url = 'https://stream.watsonplatform.net/text-to-speech/api/v1/customizations'
96 | responses.add(responses.GET, "{0}/{1}/words".format(base_url, "custid"),
97 | body='{"customizations": "yep" }',
98 | status=200, content_type='application_json')
99 | responses.add(responses.POST, "{0}/{1}/words".format(base_url, "custid"),
100 | body='{"customizations": "yep" }',
101 | status=200, content_type='application_json')
102 | responses.add(responses.GET, "{0}/{1}/words/{2}".format(base_url, "custid", "word"),
103 | body='{"customization": "yep, just one" }',
104 | status=200, content_type='application_json')
105 | responses.add(responses.POST, "{0}/{1}/words/{2}".format(base_url, "custid", "word"),
106 | body='{"customizations": "yep" }',
107 | status=200, content_type='application_json')
108 | responses.add(responses.PUT, "{0}/{1}/words/{2}".format(base_url, "custid", "word"),
109 | body='{"customizations": "yep" }',
110 | status=200, content_type='application_json')
111 | responses.add(responses.DELETE, "{0}/{1}/words/{2}".format(base_url, "custid", "word"),
112 | body='{"customizations": "yep" }',
113 | status=200, content_type='application_json')
114 |
115 | text_to_speech = watson_developer_cloud.TextToSpeechV1(
116 | username="username", password="password")
117 | text_to_speech.get_customization_words(customization_id="custid")
118 | text_to_speech.add_customization_words(
119 | customization_id="custid", words=["one", "two", "three"])
120 | text_to_speech.get_customization_word(
121 | customization_id="custid", word="word")
122 | text_to_speech.set_customization_word(
123 | customization_id='custid', word="word", translation="I'm translated")
124 | text_to_speech.delete_customization_word(
125 | customization_id="custid", word="word")
126 | assert len(responses.calls) == 5
127 |
--------------------------------------------------------------------------------
/watson_developer_cloud/alchemy_data_news_v1.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 IBM All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | The AlchemyData News service
16 | (https://www.ibm.com/watson/developercloud/alchemy-data-news.html)
17 | """
18 |
19 | from .watson_service import WatsonService
20 |
21 |
22 | class AlchemyDataNewsV1(WatsonService):
23 | default_url = 'https://gateway-a.watsonplatform.net/calls'
24 |
25 | def __init__(self, url=default_url, **kwargs):
26 | WatsonService.__init__(self, 'alchemy_api', url, **kwargs)
27 |
28 | def get_news_documents(self, start, end, max_results=10, query_fields=None,
29 | return_fields=None, time_slice=None,
30 | next_page=None, dedup=None, dedup_threshold=None,
31 | rank=None):
32 | """
33 | :param start: The time (in UTC seconds) of the beginning date and time
34 | of the query. Valid values are UTC times and relative times:
35 | now (current time), now-{time value}, s (seconds), m (minutes),
36 | h (hours), d (days), M (months), and y (years)
37 |
38 | :param end: The time (in UTC seconds) of the end date and time of the
39 | query. Valid values are UTC times and relative times:
40 | now (current time), now-{time value}, s (seconds), m (minutes),
41 | h (hours), d (days), M (months), and y (years)
42 |
43 | :param max_results: The maximum number of results that are returned
44 | from your query. If None, all matching results are returned
45 |
46 | :param query_fields: There are nearly 400 variations of entity,
47 | taxonomy, sentiment analysis, concepts, and keywords. The full list
48 | of parameters is available in the Developer Cloud API documentation.
49 | Common fields include q.enriched.url.enrichedTitle.relations.relation,
50 | q.enriched.url.enrichedTitle.entities.entity,
51 | q.enriched.url.enrichedTitle.taxonomy.taxonomy,
52 | q.enriched.url.enrichedTitle.docSentiment.type,
53 | q.enriched.url.concepts.concept.text,
54 | q.enriched.url.enrichedTitle.keywords.keyword.text
55 |
56 | :param return fields: A comma-separated list of document fields to
57 | return for each matching document. Any available document fields can
58 | be retrieved. To return multiple fields, use a comma separated list.
59 | Common fields to return are enriched.url.url (URL), enriched.url.title
60 | (title), enriched.url.text(full article text), and enriched.url.author
61 | (author name). If you do not specify fields to be returned or a
62 | timeSlice, the AlchemyData News API only returns the total number of
63 | matching results within the start and end date range
64 |
65 | :param time_slice: The interval to divide the returned data. The
66 | default is that the query engine returns the total count over the time
67 | duration specified with start and end. If you specify a value, it
68 | returns a time series representing the count (max 1000) in each slice
69 | of time: now (current time), s (seconds), m (minutes), h (hours),
70 | d (days), M (months), and y (years)
71 |
72 | :param next_page: If a query is too broad or spans a long time period,
73 | the number of results can be very large and more results may be
74 | available than those which were returned. If there are more matching
75 | results available, a next parameter is returned in the response. To
76 | get the next page of results, execute the query again and append the
77 | next parameter to your query
78 |
79 | :param dedup: Many news articles are published by a single source,
80 | such as Associated Press, and then syndicated widely across the web.
81 | dedup removes duplicate results based on a comparison of their cleaned
82 | titles: False (Default) turns off dudup, True turns on dedup
83 |
84 | :param dedup_threshold: Defines how strictly the algorithm defines a
85 | duplicate. Valid values are between 0 and 1. The default value is 0.4.
86 | A value of 0.0 allows only titles that exactly match those of other
87 | articles to be tagged as duplicate. 0.4 allows articles that are very
88 | similar but not necessarily identical to be tagged as duplicates. A
89 | value of 1.0 allows articles to be aggressively labeled as duplicates,
90 | sometimes even when the titles are very dissimilar
91 |
92 | :param rank: The News API monitors and ranks 60,000 top-level domains,
93 | each with a varying range of page views. rank allows you to specify to
94 | only return articles from well-known, high-traffic publishers. If the
95 | rank parameter is not specified, articles of all ranks are returned:
96 | high, medium, low, or unknown
97 |
98 | :return: result elements depend on the parameters that you passed to
99 | the query. If return fields are requested, the result element contains
100 | a docs element that contains the matching documents, a next element
101 | that contains an identifier for the next matching result in the
102 | AlchemyData News data set, and a status element that provides status
103 | information about retrieving the requested number of results. If no
104 | return fields are requested in your query, the result element contains
105 | a count of matching news items and the status of querying the
106 | AlchemyData News data set.
107 | """
108 |
109 | if isinstance(return_fields, list):
110 | return_fields = ','.join(return_fields)
111 | params = {'start': start,
112 | 'end': end,
113 | 'maxResults': max_results,
114 | 'return': return_fields,
115 | 'timeSlice': time_slice,
116 | 'next': next_page,
117 | 'dedup': dedup,
118 | 'dedupThreshold': dedup_threshold,
119 | 'rank': rank}
120 | if isinstance(query_fields, dict):
121 | for key in query_fields:
122 | params[key if key.startswith('q.') else 'q.' + key] = \
123 | query_fields[key]
124 | return self._alchemy_html_request(method_url='/data/GetNews',
125 | method='GET', params=params)
126 |
--------------------------------------------------------------------------------
/test/test_natural_language_understanding.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 | from watson_developer_cloud import NaturalLanguageUnderstandingV1
3 | from watson_developer_cloud.natural_language_understanding_v1 import \
4 | Features, ConceptsOptions, EntitiesOptions, KeywordsOptions, CategoriesOptions, \
5 | EmotionOptions, MetadataOptions, SemanticRolesOptions, RelationsOptions, \
6 | SentimentOptions
7 |
8 | import os
9 | import pytest
10 | import responses
11 |
12 |
13 | base_url = 'https://gateway.watsonplatform.net'
14 | default_url = '{0}/natural-language-understanding/api'.format(base_url)
15 |
16 |
17 | class TestFeatures(TestCase):
18 | def test_concepts(self):
19 | c = Features(concepts=ConceptsOptions())
20 | assert c._to_dict() == {'concepts': {}}
21 | c = Features(concepts=ConceptsOptions(limit=10))
22 | assert c._to_dict() == {'concepts': {'limit': 10}}
23 |
24 | def test_entities(self):
25 | e = Features(entities=EntitiesOptions())
26 | assert e._to_dict() == {'entities': {}}
27 |
28 | def test_keywords(self):
29 | k = Features(keywords=KeywordsOptions())
30 | assert k._to_dict() == {'keywords': {}}
31 |
32 | def test_categories(self):
33 | c = Features(categories=CategoriesOptions())
34 | assert c._to_dict() == {'categories': {}}
35 |
36 | def test_emotion(self):
37 | e = Features(emotion=EmotionOptions())
38 | assert e._to_dict() == {'emotion': {}}
39 |
40 | def test_metadata(self):
41 | m = Features(metadata=MetadataOptions())
42 | assert m._to_dict() == {'metadata': {}}
43 |
44 | def test_semantic_roles(self):
45 | s = Features(semantic_roles=SemanticRolesOptions())
46 | assert s._to_dict() == {'semantic_roles': {}}
47 |
48 | def test_relations(self):
49 | r = Features(relations=RelationsOptions())
50 | assert r._to_dict() == {'relations': {}}
51 |
52 | def test_sentiment(self):
53 | s = Features(sentiment=SentimentOptions())
54 | assert s._to_dict() == {'sentiment': {}}
55 |
56 |
57 | class TestNaturalLanguageUnderstanding(TestCase):
58 | def test_version_date(self):
59 | with pytest.raises(TypeError):
60 | NaturalLanguageUnderstandingV1() # pylint: disable=E1120
61 | nlu = NaturalLanguageUnderstandingV1(version='2016-01-23',
62 | url='http://bogus.com',
63 | username='username',
64 | password='password')
65 | assert nlu
66 |
67 | @pytest.mark.skipif(os.getenv('VCAP_SERVICES') is not None,
68 | reason='credentials may come from VCAP_SERVICES')
69 | def test_missing_credentials(self):
70 | with pytest.raises(ValueError):
71 | NaturalLanguageUnderstandingV1(version='2016-01-23')
72 | with pytest.raises(ValueError):
73 | NaturalLanguageUnderstandingV1(version='2016-01-23',
74 | url='https://bogus.com')
75 |
76 | def test_analyze_throws(self):
77 | nlu = NaturalLanguageUnderstandingV1(version='2016-01-23',
78 | url='http://bogus.com',
79 | username='username',
80 | password='password')
81 | with pytest.raises(ValueError):
82 | nlu.analyze(None, text="this will not work")
83 |
84 | @responses.activate
85 | def test_text_analyze(self):
86 | nlu_url = "http://bogus.com/v1/analyze"
87 | responses.add(responses.POST, nlu_url,
88 | body="{\"resulting_key\": true}", status=200,
89 | content_type='application/json')
90 | nlu = NaturalLanguageUnderstandingV1(version='2016-01-23',
91 | url='http://bogus.com',
92 | username='username',
93 | password='password')
94 | nlu.analyze(Features(sentiment=SentimentOptions()), text="hello this is a test")
95 | assert len(responses.calls) == 1
96 |
97 | @responses.activate
98 | def test_html_analyze(self):
99 | nlu_url = "http://bogus.com/v1/analyze"
100 | responses.add(responses.POST, nlu_url,
101 | body="{\"resulting_key\": true}", status=200,
102 | content_type='application/json')
103 | nlu = NaturalLanguageUnderstandingV1(version='2016-01-23',
104 | url='http://bogus.com',
105 | username='username',
106 | password='password')
107 | nlu.analyze(Features(sentiment=SentimentOptions(),
108 | emotion=EmotionOptions(document=False)),
109 | html="hello this is a test")
110 | assert len(responses.calls) == 1
111 |
112 | @responses.activate
113 | def test_url_analyze(self):
114 | nlu_url = "http://bogus.com/v1/analyze"
115 | responses.add(responses.POST, nlu_url,
116 | body="{\"resulting_key\": true}", status=200,
117 | content_type='application/json')
118 | nlu = NaturalLanguageUnderstandingV1(version='2016-01-23',
119 | url='http://bogus.com',
120 | username='username',
121 | password='password')
122 | nlu.analyze(Features(sentiment=SentimentOptions(),
123 | emotion=EmotionOptions(document=False)),
124 | url="http://cnn.com",
125 | xpath="/bogus/xpath", language="en")
126 | assert len(responses.calls) == 1
127 |
128 | @responses.activate
129 | def test_list_models(self):
130 | nlu_url = "http://bogus.com/v1/models"
131 | responses.add(responses.GET, nlu_url, status=200,
132 | body="{\"resulting_key\": true}",
133 | content_type='application/json')
134 | nlu = NaturalLanguageUnderstandingV1(version='2016-01-23',
135 | url='http://bogus.com',
136 | username='username',
137 | password='password')
138 | nlu.list_models()
139 | assert len(responses.calls) == 1
140 |
141 | @responses.activate
142 | def test_delete_model(self):
143 | model_id = "invalid_model_id"
144 | nlu_url = "http://bogus.com/v1/models/" + model_id
145 | responses.add(responses.DELETE, nlu_url, status=200,
146 | body="{}", content_type='application/json')
147 | nlu = NaturalLanguageUnderstandingV1(version='2016-01-23',
148 | url='http://bogus.com',
149 | username='username',
150 | password='password')
151 | nlu.delete_model(model_id)
152 | assert len(responses.calls) == 1
153 |
--------------------------------------------------------------------------------
/resources/personality-v3.txt:
--------------------------------------------------------------------------------
1 | Vice President Johnson, Mr. Speaker, Mr. Chief Justice, President Eisenhower,
2 | Vice President Nixon, President Truman, Reverend Clergy, fellow citizens:
3 |
4 | We observe today not a victory of party but a celebration of freedom --
5 | symbolizing an end as well as a beginning -- signifying renewal as well as
6 | change. For I have sworn before you and Almighty God the same solemn oath our
7 | forbears prescribed nearly a century and three-quarters ago.
8 |
9 | The world is very different now. For man holds in his mortal hands the power
10 | to abolish all forms of human poverty and all forms of human life. And yet
11 | the same revolutionary beliefs for which our forebears fought are still at
12 | issue around the globe -- the belief that the rights of man come not from the
13 | generosity of the state but from the hand of God.
14 |
15 | We dare not forget today that we are the heirs of that first revolution. Let
16 | the word go forth from this time and place, to friend and foe alike, that the
17 | torch has been passed to a new generation of Americans -- born in this century,
18 | tempered by war, disciplined by a hard and bitter peace, proud of our ancient
19 | heritage -- and unwilling to witness or permit the slow undoing of those human
20 | rights to which this nation has always been committed, and to which we are
21 | committed today at home and around the world.
22 |
23 | Let every nation know, whether it wishes us well or ill, that we shall pay
24 | any price, bear any burden, meet any hardship, support any friend, oppose
25 | any foe to assure the survival and the success of liberty.
26 |
27 | This much we pledge -- and more.
28 |
29 | To those old allies whose cultural and spiritual origins we share, we pledge
30 | the loyalty of faithful friends. United there is little we cannot do in a host
31 | of cooperative ventures. Divided there is little we can do -- for we dare not
32 | meet a powerful challenge at odds and split asunder.
33 |
34 | To those new states whom we welcome to the ranks of the free, we pledge our
35 | word that one form of colonial control shall not have passed away merely to
36 | be replaced by a far more iron tyranny. We shall not always expect to find
37 | them supporting our view. But we shall always hope to find them strongly
38 | supporting their own freedom -- and to remember that, in the past, those who
39 | foolishly sought power by riding the back of the tiger ended up inside.
40 |
41 | To those people in the huts and villages of half the globe struggling to
42 | break the bonds of mass misery, we pledge our best efforts to help them help
43 | themselves, for whatever period is required -- not because the communists may
44 | be doing it, not because we seek their votes, but because it is right. If a
45 | free society cannot help the many who are poor, it cannot save the few who
46 | are rich.
47 |
48 | To our sister republics south of our border, we offer a special pledge -- to
49 | convert our good words into good deeds -- in a new alliance for progress --
50 | to assist free men and free governments in casting off the chains of poverty.
51 | But this peaceful revolution of hope cannot become the prey of hostile powers.
52 | Let all our neighbors know that we shall join with them to oppose aggression
53 | or subversion anywhere in the Americas. And let every other power know that
54 | this Hemisphere intends to remain the master of its own house.
55 |
56 | To that world assembly of sovereign states, the United Nations, our last best
57 | hope in an age where the instruments of war have far outpaced the instruments
58 | of peace, we renew our pledge of support -- to prevent it from becoming merely
59 | a forum for invective -- to strengthen its shield of the new and the weak --
60 | and to enlarge the area in which its writ may run.
61 |
62 | Finally, to those nations who would make themselves our adversary, we offer
63 | not a pledge but a request: that both sides begin anew the quest for peace,
64 | before the dark powers of destruction unleashed by science engulf all humanity
65 | in planned or accidental self-destruction.
66 |
67 | We dare not tempt them with weakness. For only when our arms are sufficient
68 | beyond doubt can we be certain beyond doubt that they will never be employed.
69 |
70 | But neither can two great and powerful groups of nations take comfort from
71 | our present course -- both sides overburdened by the cost of modern weapons,
72 | both rightly alarmed by the steady spread of the deadly atom, yet both racing
73 | to alter that uncertain balance of terror that stays the hand of mankind's
74 | final war.
75 |
76 | So let us begin anew -- remembering on both sides that civility is not a sign
77 | of weakness, and sincerity is always subject to proof. Let us never negotiate
78 | out of fear. But let us never fear to negotiate.
79 |
80 | Let both sides explore what problems unite us instead of belaboring those
81 | problems which divide us.
82 |
83 | Let both sides, for the first time, formulate serious and precise proposals
84 | for the inspection and control of arms -- and bring the absolute power to
85 | destroy other nations under the absolute control of all nations.
86 |
87 | Let both sides seek to invoke the wonders of science instead of its terrors.
88 | Together let us explore the stars, conquer the deserts, eradicate disease,
89 | tap the ocean depths and encourage the arts and commerce.
90 |
91 | Let both sides unite to heed in all corners of the earth the command of
92 | Isaiah -- to "undo the heavy burdens ... (and) let the oppressed go free."
93 |
94 | And if a beachhead of cooperation may push back the jungle of suspicion, let
95 | both sides join in creating a new endeavor, not a new balance of power, but
96 | a new world of law, where the strong are just and the weak secure and the
97 | peace preserved.
98 |
99 | All this will not be finished in the first one hundred days. Nor will it be
100 | finished in the first one thousand days, nor in the life of this
101 | Administration, nor even perhaps in our lifetime on this planet. But let us
102 | begin.
103 |
104 | In your hands, my fellow citizens, more than mine, will rest the final success
105 | or failure of our course. Since this country was founded, each generation of
106 | Americans has been summoned to give testimony to its national loyalty. The
107 | graves of young Americans who answered the call to service surround the globe.
108 |
109 | Now the trumpet summons us again -- not as a call to bear arms, though arms we
110 | need -- not as a call to battle, though embattled we are -- but a call to bear
111 | the burden of a long twilight struggle, year in and year out, "rejoicing in
112 | hope, patient in tribulation" -- a struggle against the common enemies of man:
113 | tyranny, poverty, disease and war itself.
114 |
115 | Can we forge against these enemies a grand and global alliance, North and
116 | South, East and West, that can assure a more fruitful life for all mankind?
117 | Will you join in that historic effort?
118 |
119 | In the long history of the world, only a few generations have been granted
120 | the role of defending freedom in its hour of maximum danger. I do not shrink
121 | from this responsibility -- I welcome it. I do not believe that any of us
122 | would exchange places with any other people or any other generation. The
123 | energy, the faith, the devotion which we bring to this endeavor will light
124 | our country and all who serve it -- and the glow from that fire can truly
125 | light the world.
126 |
127 | And so, my fellow Americans: ask not what your country can do for you -- ask
128 | what you can do for your country.
129 |
130 | My fellow citizens of the world: ask not what America will do for you, but
131 | what together we can do for the freedom of man.
132 |
133 | Finally, whether you are citizens of America or citizens of the world, ask of
134 | us here the same high standards of strength and sacrifice which we ask of you.
135 | With a good conscience our only sure reward, with history the final judge of
136 | our deeds, let us go forth to lead the land we love, asking His blessing and
137 | His help, but knowing that here on earth God's work must truly be our own.
138 |
--------------------------------------------------------------------------------