├── watson_developer_cloud ├── version.py ├── natural_language_understanding │ ├── __init__.py │ └── features │ │ ├── __init__.py │ │ └── v1 │ │ └── __init__.py ├── utils.py ├── __init__.py ├── authorization_v1.py ├── tradeoff_analytics_v1.py ├── alchemy_vision_v1.py ├── personality_insights_v2.py ├── document_conversion_v1.py ├── language_translation_v2.py ├── dialog_v1.py ├── text_to_speech_v1.py ├── retrieve_and_rank_v1.py └── alchemy_data_news_v1.py ├── .env.enc ├── resources ├── car.jpg ├── cars.zip ├── face.jpg ├── test.jpg ├── text.png ├── images.zip ├── speech.wav ├── trucks.zip ├── solr_config.zip ├── sample-docx.docx ├── simple.html ├── tone-example.json ├── tone-example-html.json ├── language_translator_model.tmx ├── tone-v3-expect2.json ├── ranker_answer_data.csv ├── speech_to_text │ ├── corpus-short-1.txt │ └── corpus-short-2.txt ├── weather_data_train.csv ├── tradeoff-expect2.txt ├── tradeoff-expect3.txt ├── tradeoff-expect1.txt ├── problem.json ├── tradeoff-expect4.txt ├── dialog.xml ├── personality-v3-expect1.txt ├── personality-v3-expect3.txt └── personality-v3.txt ├── docs ├── _static │ └── favicon.ico ├── _templates │ └── sidebarintro.html ├── index.rst ├── publish.sh └── generate_index_html.sh ├── requirements.txt ├── MIGRATION.md ├── CHANGELOG.md ├── MANIFEST.in ├── .github └── issue_template.md ├── pylint.sh ├── examples ├── conversation_tone_analyzer_integration │ ├── .env.example │ ├── __init__.py │ ├── README.md │ └── tone_conversation_integration.v1.py ├── authorization_v1.py ├── README.md ├── __init__.py ├── tradeoff_analytics_v1.py ├── natural_language_understanding_v1.py ├── speech_to_text_v1.py ├── personality_insights_v3.py ├── alchemy_data_news_v1.py ├── personality_insights_v2.py ├── language_translator_v2.py ├── natural_language_classifier_v1.py ├── dialog_v1.py ├── text_to_speech_v1.py ├── tone_analyzer_v3.py ├── visual_recognition_v3.py ├── alchemy_language_v1.py ├── discovery_v1.py ├── retrieve_and_rank_v1.py ├── notebooks │ └── natural_language_understanding_v1.ipynb └── document_conversion_v1.py ├── requirements-dev.txt ├── .bumpversion.cfg ├── .pylintrc ├── tox.ini ├── .gitattributes ├── .travis.yml ├── test ├── __init__.py ├── test_integration_speech_to_text_v1.py ├── test_integration_text_to_speech_v1.py ├── test_personality_insights_v2.py ├── test_examples.py ├── test_document_conversion_v1.py ├── test_integration_visual_recognition.py ├── test_watson_service.py ├── test_tradeoff_analytics_v1.py ├── test_natural_language_classifier_v1.py ├── test_alchemy_language_v1.py ├── test_personality_insights_v3.py ├── test_tone_analyzer_v3.py ├── test_text_to_speech_v1.py └── test_natural_language_understanding.py ├── .gitignore ├── RELEASES.md ├── CONTRIBUTING.md ├── setup.py └── README.md /watson_developer_cloud/version.py: -------------------------------------------------------------------------------- 1 | __version__ = '1.0.2' 2 | -------------------------------------------------------------------------------- /watson_developer_cloud/natural_language_understanding/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.env.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0101011/python-sdk/develop/.env.enc -------------------------------------------------------------------------------- /watson_developer_cloud/natural_language_understanding/features/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/car.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0101011/python-sdk/develop/resources/car.jpg -------------------------------------------------------------------------------- /resources/cars.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0101011/python-sdk/develop/resources/cars.zip -------------------------------------------------------------------------------- /resources/face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0101011/python-sdk/develop/resources/face.jpg -------------------------------------------------------------------------------- /resources/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0101011/python-sdk/develop/resources/test.jpg -------------------------------------------------------------------------------- /resources/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0101011/python-sdk/develop/resources/text.png -------------------------------------------------------------------------------- /resources/images.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0101011/python-sdk/develop/resources/images.zip -------------------------------------------------------------------------------- /resources/speech.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0101011/python-sdk/develop/resources/speech.wav -------------------------------------------------------------------------------- /resources/trucks.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0101011/python-sdk/develop/resources/trucks.zip -------------------------------------------------------------------------------- /docs/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0101011/python-sdk/develop/docs/_static/favicon.ico -------------------------------------------------------------------------------- /resources/solr_config.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0101011/python-sdk/develop/resources/solr_config.zip -------------------------------------------------------------------------------- /resources/sample-docx.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0101011/python-sdk/develop/resources/sample-docx.docx -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests>=2.0,<3.0 2 | pysolr>=3.3,<4.0 3 | argparse>=1.3.0 4 | pyOpenSSL>=16.2.0 5 | python_dateutil>=2.5.3 6 | -------------------------------------------------------------------------------- /MIGRATION.md: -------------------------------------------------------------------------------- 1 | Moved to [https://github.com/watson-developer-cloud/python-sdk/wiki/Migration](https://github.com/watson-developer-cloud/python-sdk/wiki/Migration) -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Moved to [https://github.com/watson-developer-cloud/python-sdk/wiki/Changelog](https://github.com/watson-developer-cloud/python-sdk/wiki/Changelog) 2 | -------------------------------------------------------------------------------- /resources/simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Simple HTML Page 4 | 5 | 6 |

Chapter 1

7 |

The content of the first chapter.

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!

" 3 | } 4 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | #### Expected behavior 2 | 3 | #### Actual behavior 4 | 5 | #### Steps to reproduce the problem 6 | 7 | #### Code snippet (Note: Do not paste your credentials) 8 | 9 | #### python sdk version 10 | 11 | #### python version 12 | 13 | -------------------------------------------------------------------------------- /pylint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Runs pylint only for Python 2.7.X 4 | PYTHON_VERSION=$(python -c 'import sys; print(".".join(map(str, sys.version_info[:2])))') 5 | echo "Python version: $PYTHON_VERSION" 6 | if [ $PYTHON_VERSION = '2.7' ]; then 7 | pylint watson_developer_cloud test examples 8 | fi 9 | -------------------------------------------------------------------------------- /examples/conversation_tone_analyzer_integration/.env.example: -------------------------------------------------------------------------------- 1 | # see README.md for details 2 | 3 | CONVERSATION_USERNAME= 4 | CONVERSATION_PASSWORD= 5 | WORKSPACE_ID= 6 | 7 | TONE_ANALYZER_USERNAME= 8 | TONE_ANALYZER_PASSWORD= -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | # test dependencies 2 | pytest>=2.8.2 3 | responses>=0.4.0 4 | python_dotenv>=0.1.5;python_version!='3.2' 5 | pylint>=1.4.4 6 | tox>=2.9.1 7 | pytest-rerunfailures>=3.1 8 | 9 | # code coverage 10 | coverage<4 11 | codecov>=1.6.3 12 | pytest-cov>=2.2.1 13 | 14 | # documentation 15 | recommonmark>=0.2.0 16 | Sphinx>=1.3.1 17 | bumpversion>=0.5.3 18 | -------------------------------------------------------------------------------- /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 1.0.2 3 | commit = True 4 | tag = True 5 | 6 | [bumpversion:file:watson_developer_cloud/version.py] 7 | search = __version__ = '{current_version}' 8 | replace = __version__ = '{new_version}' 9 | 10 | [bumpversion:file:setup.py] 11 | search = __version__ = '{current_version}' 12 | replace = __version__ = '{new_version}' 13 | 14 | -------------------------------------------------------------------------------- /examples/authorization_v1.py: -------------------------------------------------------------------------------- 1 | import json 2 | from watson_developer_cloud import AuthorizationV1 3 | from watson_developer_cloud import SpeechToTextV1 4 | 5 | authorization = AuthorizationV1( 6 | username='YOUR SERVICE USERNAME', 7 | password='YOUR SERVICE PASSWORD') 8 | 9 | print(json.dumps(authorization.get_token(url=SpeechToTextV1.default_url), 10 | indent=2)) 11 | -------------------------------------------------------------------------------- /docs/_templates/sidebarintro.html: -------------------------------------------------------------------------------- 1 |

Useful Links

2 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | # lint Python modules using external checkers. 2 | [MASTER] 3 | ignore=SVN 4 | disable=R0903,R0912,R0913,R0914,R0915,W0141,C0111,C0103,W0603,W0703,R0911,C0301,C0302,R0902,R0904,W0142,W0212,E1101,E1103,R0201,W0201,W0122,W0232,RP0001,RP0003,RP0101,RP0002,RP0401,RP0701,RP0801,F0401,E0611,R0801,I0011,F0401,E0611,E1004,C0111,I0011,I0012,W0704,W0142,W0212,W0232,W0613,W0702,R0201,W0614,R0914,R0912,R0915,R0913,R0904,R0801,C0301,C0411,R0204,W0622 5 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = lint, py27, py34, py35, py36 3 | 4 | [testenv:lint] 5 | basepython = python2.7 6 | deps = pylint 7 | commands = pylint watson_developer_cloud 8 | 9 | [testenv] 10 | passenv = TOXENV CI TRAVIS* 11 | commands = 12 | py.test --reruns 3 --cov=watson_developer_cloud 13 | codecov -e TOXENV 14 | deps = 15 | -r{toxinidir}/requirements.txt 16 | -r{toxinidir}/requirements-dev.txt 17 | exclude = .venv,.git,.tox,docs -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly declare text files you want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.csv text 7 | 8 | # Declare files that will always have CRLF line endings on checkout. 9 | *.sln text eol=crlf 10 | 11 | # Denote all files that are truly binary and should not be modified. 12 | *.png binary 13 | *.jpg binary 14 | -------------------------------------------------------------------------------- /watson_developer_cloud/utils.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | def deprecated(message): 4 | def deprecated_decorator(func): 5 | def deprecated_func(*args, **kwargs): 6 | warnings.warn("{} is a deprecated function. {}".format(func.__name__, message), 7 | category=DeprecationWarning, 8 | stacklevel=2) 9 | warnings.simplefilter('default', DeprecationWarning) 10 | return func(*args, **kwargs) 11 | return deprecated_func 12 | return deprecated_decorator -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | ## Examples 2 | To run the examples, you will need a `username`, `password`, and `url`. To get your service credentials, follow these steps: 3 | 1. Log in to IBM Cloud at https://console.bluemix.net. 4 | 5 | 1. Create an instance of the service: 6 | 1. In the IBM Cloud **Catalog**, select the Natural Language Classifier service. 7 | 1. Click **Create**. 8 | 9 | 1. Copy your credentials: 10 | 1. On the left side of the page, click **Service Credentials** to view your service credentials. 11 | 1. Copy `username`, `password`, and `url` from these service credentials. 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | sudo: false 3 | python: 4 | - '2.7' 5 | - '3.4' 6 | - '3.5' 7 | - '3.6' 8 | cache: pip 9 | before_install: 10 | - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && openssl aes-256-cbc -K $encrypted_6e98b3e8e789_key -iv $encrypted_6e98b3e8e789_iv -in .env.enc -out .env -d || true' 11 | install: pip install tox-travis 12 | script: tox 13 | before_deploy: 14 | - pip install -r requirements.txt 15 | - pip install -r requirements-dev.txt 16 | - pip install --editable . 17 | deploy: 18 | provider: script 19 | script: docs/publish.sh 20 | skip_cleanup: true 21 | on: 22 | python: '2.7' 23 | all_branches: true 24 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 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 | -------------------------------------------------------------------------------- /examples/__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 | -------------------------------------------------------------------------------- /examples/tradeoff_analytics_v1.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import json 3 | import os 4 | from watson_developer_cloud import TradeoffAnalyticsV1 5 | 6 | tradeoff_analytics = TradeoffAnalyticsV1( 7 | username='YOUR SERVICE USERNAME', 8 | password='YOUR SERVICE PASSWORD') 9 | 10 | with open(os.path.join(os.path.dirname(__file__), 11 | '../resources/problem.json')) as problem_json: 12 | dilemma = tradeoff_analytics.dilemmas(json.load(problem_json), 13 | generate_visualization=True, 14 | find_preferable_options=True) 15 | 16 | print(json.dumps(dilemma, indent=2)) 17 | -------------------------------------------------------------------------------- /resources/language_translator_model.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
6 | 7 | 8 | 9 | International Business Machines 10 | 11 | 12 | International Business Machines 13 | 14 | 15 | 16 | 17 | patent 18 | 19 | 20 | brevent 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /resources/tone-v3-expect2.json: -------------------------------------------------------------------------------- 1 | { 2 | "utterances_tone": [ 3 | { 4 | "utterance_id": 0, 5 | "utterance_text": "I am very happy", 6 | "tones": [ 7 | { 8 | "score": 0.875529, 9 | "tone_id": "polite", 10 | "tone_name": "polite" 11 | }, 12 | { 13 | "score": 0.838693, 14 | "tone_id": "satisfied", 15 | "tone_name": "satisfied" 16 | }, 17 | { 18 | "score": 0.844135, 19 | "tone_id": "sympathetic", 20 | "tone_name": "sympathetic" 21 | }, 22 | { 23 | "score": 0.916255, 24 | "tone_id": "excited", 25 | "tone_name": "excited" 26 | } 27 | ] 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /examples/natural_language_understanding_v1.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import json 3 | from watson_developer_cloud import NaturalLanguageUnderstandingV1 4 | from watson_developer_cloud.natural_language_understanding_v1 import Features, EntitiesOptions, KeywordsOptions 5 | 6 | 7 | natural_language_understanding = NaturalLanguageUnderstandingV1( 8 | version='2017-02-27', 9 | username='YOUR SERVICE USERNAME', 10 | password='YOUR SERVICE PASSWORD') 11 | 12 | response = natural_language_understanding.analyze( 13 | text='Bruce Banner is the Hulk and Bruce Wayne is BATMAN! ' 14 | 'Superman fears not Banner, but Wayne.', 15 | features=Features(entities=EntitiesOptions(), keywords=KeywordsOptions())) 16 | 17 | print(json.dumps(response, indent=2)) 18 | -------------------------------------------------------------------------------- /examples/speech_to_text_v1.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import json 3 | from os.path import join, dirname 4 | from watson_developer_cloud import SpeechToTextV1 5 | 6 | speech_to_text = SpeechToTextV1( 7 | username='YOUR SERVICE USERNAME', 8 | password='YOUR SERVICE PASSWORD', 9 | x_watson_learning_opt_out=False 10 | ) 11 | 12 | print(json.dumps(speech_to_text.models(), indent=2)) 13 | 14 | print(json.dumps(speech_to_text.get_model('en-US_BroadbandModel'), indent=2)) 15 | 16 | with open(join(dirname(__file__), '../resources/speech.wav'), 17 | 'rb') as audio_file: 18 | print(json.dumps(speech_to_text.recognize( 19 | audio_file, content_type='audio/wav', timestamps=True, 20 | word_confidence=True), 21 | indent=2)) 22 | -------------------------------------------------------------------------------- /examples/personality_insights_v3.py: -------------------------------------------------------------------------------- 1 | """ 2 | The example returns a JSON response whose content is the same as that in 3 | ../resources/personality-v3-expect2.txt 4 | """ 5 | from __future__ import print_function 6 | import json 7 | from os.path import join, dirname 8 | from watson_developer_cloud import PersonalityInsightsV3 9 | 10 | personality_insights = PersonalityInsightsV3( 11 | version='2016-10-20', 12 | username='YOUR SERVICE USERNAME', 13 | password='YOUR SERVICE PASSWORD') 14 | 15 | with open(join(dirname(__file__), '../resources/personality-v3.json')) as \ 16 | profile_json: 17 | profile = personality_insights.profile( 18 | profile_json.read(), content_type='application/json', 19 | raw_scores=True, consumption_preferences=True) 20 | 21 | print(json.dumps(profile, indent=2)) 22 | -------------------------------------------------------------------------------- /examples/alchemy_data_news_v1.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import json 3 | from watson_developer_cloud import AlchemyDataNewsV1 4 | 5 | alchemy_data_news = AlchemyDataNewsV1(api_key='YOUR API KEY') 6 | 7 | results = alchemy_data_news.get_news_documents(start='now-7d', end='now', 8 | time_slice='12h') 9 | print(json.dumps(results, indent=2)) 10 | 11 | results = alchemy_data_news.get_news_documents( 12 | start='1453334400', 13 | end='1454022000', 14 | return_fields=['enriched.url.title', 15 | 'enriched.url.url', 16 | 'enriched.url.author', 17 | 'enriched.url.publicationDate'], 18 | query_fields={ 19 | 'q.enriched.url.enrichedTitle.entities.entity': 20 | '|text=IBM,type=company|'}) 21 | print(json.dumps(results, indent=2)) 22 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Python SDK |version| 2 | -------------------- 3 | 4 | Python client library to quickly get started with the various 5 | `Watson Developer Cloud `__ 6 | services. 7 | 8 | Installation 9 | ------------ 10 | 11 | To install, use ``pip`` or ``easy_install``: 12 | 13 | .. code:: bash 14 | 15 | $ pip install --upgrade watson-developer-cloud 16 | 17 | or 18 | 19 | .. code:: bash 20 | 21 | $ easy_install --upgrade watson-developer-cloud 22 | 23 | Modules 24 | ------- 25 | .. toctree:: 26 | :maxdepth: 2 27 | :glob: 28 | 29 | apis/* 30 | 31 | Examples 32 | -------- 33 | The `examples `__ 34 | folder has basic and advanced examples. 35 | 36 | Indices and tables 37 | ------------------ 38 | 39 | * :ref:`genindex` 40 | * :ref:`modindex` 41 | * :ref:`search` -------------------------------------------------------------------------------- /examples/conversation_tone_analyzer_integration/__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 .conversation_v1 import ConversationV1 18 | from .tone_analyzer_v3 import ToneAnalyzerV3 19 | 20 | 21 | from .version import __version__ 22 | -------------------------------------------------------------------------------- /test/test_integration_speech_to_text_v1.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | import pytest 3 | import os 4 | import watson_developer_cloud 5 | 6 | @pytest.mark.skip("These are destructive, so run them manually") 7 | class TestSpeechToTextV1(TestCase): 8 | def setUp(self): 9 | self.speech_to_text = watson_developer_cloud.SpeechToTextV1(username=os.getenv('SPEECH_TO_TEXT_USERNAME'), 10 | password=os.getenv('SPEECH_TO_TEXT_PASSWORD')) 11 | self.custom_models = self.speech_to_text.list_custom_models() 12 | self.create_custom_model = self.speech_to_text.create_custom_model(name="integration_test_model") 13 | 14 | def tearDown(self): 15 | self.speech_to_text.delete_custom_model(modelid=self.create_custom_model['customization_id']) 16 | 17 | def test_create_custom_model(self): 18 | current_custom_models = self.speech_to_text.list_custom_models() 19 | assert len(current_custom_models['customizations']) - len(self.custom_models['customizations']) == 1 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE OS 2 | .DS_Store 3 | .idea 4 | 5 | # Byte-compiled / optimized / DLL files 6 | __pycache__/ 7 | *.py[cod] 8 | *$py.class 9 | 10 | # Distribution / packaging 11 | .Python 12 | env/ 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | 47 | .vscode 48 | 49 | # virtual env 50 | venv/ 51 | # python 3 virtual env 52 | python3/ 53 | 54 | .env 55 | 56 | # resources 57 | resources/output.wav 58 | 59 | docs/_build/ 60 | deploy.sh 61 | docs/apis 62 | docs/gh-pages 63 | test/__init__.py 64 | *~ 65 | 66 | .sfdx/tools/apex.db 67 | -------------------------------------------------------------------------------- /docs/publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # checking the build/job numbers allows it to only 3 | # publish once even though we test against multiple python versions 4 | 5 | [[ -z "$TRAVIS_BRANCH" ]] && { echo "TRAVIS_BRANCH cannot be null" ; exit 1; } 6 | [[ -z "$GH_TOKEN" ]] && { echo "GH_TOKEN cannot be null" ; exit 1; } 7 | 8 | cd $(dirname $0) 9 | pwd 10 | 11 | echo "Create Docs" 12 | make document 13 | echo "Publishing Docs..." 14 | 15 | git config --global user.email "travis@travis-ci.org" 16 | git config --global user.name "travis-ci" 17 | git clone --quiet --branch=gh-pages https://${GH_TOKEN}@github.com/watson-developer-cloud/python-sdk.git gh-pages > /dev/null 18 | 19 | pushd gh-pages 20 | # on tagged builds, $TRAVIS_BRANCH is the tag (e.g. v1.2.3), otherwise it's the branch name (e.g. master) 21 | rm -rf $TRAVIS_BRANCH 22 | cp -Rf ../_build/html/ $TRAVIS_BRANCH 23 | ../generate_index_html.sh > index.html 24 | 25 | git add -f . 26 | git commit -m "Docs for $TRAVIS_BRANCH ($TRAVIS_COMMIT)" 27 | git push -fq origin gh-pages > /dev/null 28 | popd 29 | 30 | echo -e "Published Docs for $TRAVIS_BRANCH to gh-pages.\n" 31 | 32 | -------------------------------------------------------------------------------- /resources/ranker_answer_data.csv: -------------------------------------------------------------------------------- 1 | answer_id,feature0,feature1,feature2,feature3,feature4,feature5,feature6,feature7,feature8,feature9 2 | aid_1,0.2960355199,0.0844879644,0.4340235268,0.4839266521,0.2746252382,0.642192871,0.9654896781,0.7987089299,0.1892474972,0.0143581738 3 | aid_2,0.6894903365,0.2734805428,0.4736626379,0.8769168666,0.6194027473,0.1059122154,0.5717225113,0.7624298477,0.9188716848,0.4163821484 4 | aid_3,0.1975906638,0.0644695155,0.065994171,0.2684539604,0.6651181645,0.7949564899,0.8030567464,0.4105414985,0.7671972441,0.0826649587 5 | aid_4,0.5438677548,0.0965945192,0.2441482485,0.4360877661,0.4919027259,0.794489744,0.4246573072,0.0574812153,0.2446547886,0.9709169842 6 | aid_5,0.8878434581,0.2707510054,0.9081286697,0.6287693004,0.3083288303,0.0648188807,0.894781248,0.2555629816,0.0064226539,0.4723479587 7 | aid_6,0.4448963439,0.7190639201,0.7250673535,0.9181000016,0.1126992497,0.3972209865,0.4236358264,0.2348545176,0.8029545832,0.1904381348 8 | aid_7,0.3025047274,0.1340954407,0.6676969173,0.3298260566,0.1429457782,0.8589704624,0.5242530225,0.6064094542,0.2072144687,0.3600261426 9 | aid_8,0.0250756093,0.2155435607,0.4849311567,0.9526619408,0.8479345776,0.9661302239,0.6219053717,0.0707481922,0.6969152819,0.0639757399 10 | aid_9,0.0230332253,0.7011622232,0.9356776696,0.0226188579,0.1879502296,0.4092896767,0.7685509587,0.0483934289,0.2942156776,0.5968637532 -------------------------------------------------------------------------------- /examples/personality_insights_v2.py: -------------------------------------------------------------------------------- 1 | import json 2 | from os.path import join, dirname 3 | from watson_developer_cloud import PersonalityInsightsV2 4 | 5 | 6 | personality_insights = PersonalityInsightsV2( 7 | username='YOUR SERVICE USERNAME', 8 | password='YOUR SERVICE PASSWORD') 9 | 10 | with open(join(dirname(__file__), '../resources/personality.txt')) as \ 11 | personality_text: 12 | print(json.dumps(personality_insights.profile( 13 | text=personality_text.read()), indent=2)) 14 | 15 | # with open(join(dirname(__file__), '../resources/personality.txt')) as \ 16 | # personality_text: 17 | # personality_insights_json = {"contentItems": [ 18 | # {"id": "245160944223793152", "userid": "bob", "sourceid": "twitter", 19 | # "created": 1427720427, "updated": 1427720427, 20 | # "contenttype": "text/plain", "charset": "UTF-8", 21 | # "language": "en-us", "content": personality_text.read(), 22 | # "parentid": "", "reply": "false", "forward": "false"}]} 23 | # print(json.dumps(personality_insights.profile( 24 | # text=personality_insights_json), indent=2)) 25 | # 26 | # with open(join(dirname(__file__), '../resources/personality.es.txt')) as \ 27 | # personality_text: 28 | # print(json.dumps(personality_insights.profile( 29 | # text=personality_text.read(), language='es'), indent=2)) 30 | -------------------------------------------------------------------------------- /test/test_integration_text_to_speech_v1.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import unittest 3 | import watson_developer_cloud 4 | import os 5 | 6 | @pytest.mark.skip("These are destructive, so run them manually") 7 | class TestIntegrationTextToSpeechV1(unittest.TestCase): 8 | 9 | def setUp(self): 10 | self.text_to_speech = watson_developer_cloud.TextToSpeechV1(username=os.getenv('TEXT_TO_SPEECH_USERNAME'), 11 | password=os.getenv('TEXT_TO_SPEECH_PASSWORD')) 12 | self.original_customizations = self.text_to_speech.customizations() 13 | self.created_customization = self.text_to_speech.create_customization(name="test_integration_customization", 14 | description="customization for tests") 15 | 16 | def tearDown(self): 17 | custid = self.created_customization['customization_id'] 18 | self.text_to_speech.delete_customization(customization_id=custid) 19 | 20 | def test_customizations(self): 21 | old_length = len(self.original_customizations['customizations']) 22 | new_length = len(self.text_to_speech.customizations()['customizations']) 23 | assert new_length - old_length == 1 24 | 25 | def test_speak(self): 26 | output = self.text_to_speech.synthesize(text="my voice is my passport") 27 | assert not output 28 | -------------------------------------------------------------------------------- /RELEASES.md: -------------------------------------------------------------------------------- 1 | # Release process 2 | 3 | Standard practice with pypi libraries is to commit all of the changes for a release except updating the version. We use [bumpversion] to update the version file, commit, and tag the changes. 4 | 5 | ## 1. Updating the version 6 | 7 | A small command line tool to simplify releasing software by updating all version strings in your source code by the correct increment. 8 | 9 | Install it with: 10 | 11 | ```bash 12 | pip install bumpversion 13 | ``` 14 | 15 | ## 2. Doing a release 16 | 17 | (The pypandoc module should be installed on the system doing the release, to generate the documentation for pip.) 18 | 19 | ```sh 20 | bumpversion major|minor|patch 21 | git push origin master 22 | git push origin --tags 23 | python setup.py publish 24 | ``` 25 | 26 | `bumpversion *` will update the version field appropriately, create a git commit and tag for the version, and publish the tag to github. 27 | 28 | `git push origin master` will publish the changes to package.json. 29 | 30 | `git push origin --tags` will publish the tag to github., and then immediately. 31 | 32 | `python setup.py publish` will publish the module to pypi. 33 | 34 | The reason for this is that it allows someone to easily view the source code (and readme) for whatever version they happen to have downloaded from pypi. This is particularly helpful when github is ahead of pypi. 35 | 36 | [bumpversion]: https://pypi.python.org/pypi/bumpversion 37 | -------------------------------------------------------------------------------- /test/test_personality_insights_v2.py: -------------------------------------------------------------------------------- 1 | import responses 2 | import watson_developer_cloud 3 | import os 4 | 5 | 6 | @responses.activate 7 | def test_success(): 8 | profile_url = 'https://gateway.watsonplatform.net/personality-insights/api/v2/profile' 9 | profile_response = '{"tree":{"children":[{"children":[{"category":"personality","percentage":0.9493716242287923,' \ 10 | '"children":[{"category":"personality","name":"Openness","sampling_error":0.14430105599999998,' \ 11 | '"id":"Openness","percentage":0.9493716242287923,"children":[{"category":"personality",' \ 12 | '"percentage":0.7224550516937974,"id":"Adventurousness","sampling_error":0.11646272,"name":' \ 13 | '"Adventurousness"}]}]}]}]}}' 14 | 15 | responses.add(responses.POST, profile_url, 16 | body=profile_response, status=200, 17 | content_type='application/json') 18 | 19 | with open(os.path.join(os.path.dirname(__file__), '../resources/personality.txt')) as personality_text: 20 | personality_insights = watson_developer_cloud.PersonalityInsightsV2( 21 | username="username", password="password") 22 | personality_insights.profile(personality_text) 23 | 24 | assert responses.calls[0].request.url == profile_url 25 | assert responses.calls[0].response.text == profile_response 26 | 27 | assert len(responses.calls) == 1 28 | -------------------------------------------------------------------------------- /examples/language_translator_v2.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | from __future__ import print_function 3 | import json 4 | from watson_developer_cloud import LanguageTranslatorV2 5 | 6 | language_translator = LanguageTranslatorV2( 7 | username='YOUR SERVICE USERNAME', 8 | password='YOUR SERVICE PASSWORD') 9 | 10 | # create new custom model 11 | # with open('../resources/language_translator_model.tmx', 'rb') as \ 12 | # custom_model: 13 | # print(json.dumps(language_translator.create_model( 14 | # base_model_id='en-fr', name='test_glossary', 15 | # forced_glossary=custom_model), indent=2)) 16 | 17 | print(json.dumps(language_translator.list_models(), indent=2)) 18 | 19 | print( 20 | json.dumps(language_translator.get_model('en-es-conversational'), 21 | indent=2)) 22 | 23 | # delete custom model 24 | # print(json.dumps(language_translator.delete_model( 25 | # '13860c86-ec3f-4e60-8cbe-3ef0048f92af'), indent=2)) 26 | 27 | print(json.dumps( 28 | language_translator.translate('Hola, cómo estás? €', source='es', 29 | target='en'), indent=2, 30 | ensure_ascii=False)) 31 | 32 | print(json.dumps( 33 | language_translator.translate('Messi is the best ever', 34 | model_id='en-es-conversational'), 35 | indent=2)) 36 | 37 | print(json.dumps(language_translator.identify('你好'), indent=2)) 38 | 39 | print(json.dumps(language_translator.list_identifiable_languages(), indent=2)) 40 | -------------------------------------------------------------------------------- /resources/speech_to_text/corpus-short-1.txt: -------------------------------------------------------------------------------- 1 | Am I at risk for health problems during travel 2 | Some people are more likely to have health problems when traveling outside the United States Visit your doctor before planning a trip to another country especially if you 3 | How Is Coronary Microvascular Disease Treated 4 | If youre diagnosed with coronary MVD and also have anemia you may benefit from treatment for that condition Anemia is thought to slow the growth of cells needed to repair damaged blood vessels 5 | What causes autoimmune hepatitis 6 | A combination of autoimmunity environmental triggers and a genetic predisposition can lead to autoimmune hepatitis 7 | What research is being done for Spinal Cord Injury 8 | The National Institute of Neurological Disorders and Stroke NINDS conducts spinal cord research in its laboratories at the National Institutes of Health NIH and also supports additional research through grants to major research institutions across the country Advances in research are giving doctors and patients hope that repairing injured spinal cords is a reachable goal Advances in basic research are also being matched by progress in clinical research especially in understanding the kinds of physical rehabilitation that work best to restore function Some of the more promising rehabilitation techniques are helping spinal cord injury patients become more mobile 9 | What is Osteogenesis imperfecta OI 10 | Osteogenesis imperfecta OI is a rare genetic disorder that like juvenile osteoporosis is characterized by bones that break easily often from little or no apparent cause 11 | -------------------------------------------------------------------------------- /docs/generate_index_html.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # based on https://odoepner.wordpress.com/2012/02/17/shell-script-to-generate-simple-index-html/ 4 | 5 | echo ' 6 | 7 | 8 | 9 | 10 | 11 | IBM Watson Developer Cloud 12 | 13 | 14 | 15 |
16 | 19 | 20 |

Info 21 | | Documentation 22 | | GitHub 23 | | pypi 24 |

25 | 26 |

Documentation by branch/tag:

27 | 30 |
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 | 2 | 3 | 4 | 5 | 6 | Hello, welcome to Mike’s Pizza 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | I am sorry, I did not understand your question. Please try asking another one. 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | What type of toppings do you have? 28 | $ What type of toppings do you have? 29 | $ list of toppings 30 | What * toppings * have 31 | $ list toppings * available 32 | $ what toppings do you have 33 | 34 | 35 | 36 | We have Pepperoni, Mushrooms, and Sausage 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 69810 54 | mwacho@gmail.com 55 | mct:f972618f697988c5f1808da2115a54f0 56 | Matthew 57 | james Wachowiak 58 | US 59 | 60 | New York 61 | 1 62 | 1 63 | 2001 64 | Male 65 | Matthew 66 | false 67 | 68 | false 69 | 0 70 | 2015-03-30 15:08:32.0 71 | 2015-03-30 15:08:32.0 72 | 1 73 | -100 74 | 2 75 | 6 76 | true 77 | true 78 | 79 | 80 | true 81 | true 82 | false 83 | 3 84 | false 85 | EN 86 | 0 87 | 0 88 | 0 89 | Australia/Sydney 90 | 0 91 | 0 92 | 0 93 | 0 94 | 0 95 | 96 | -------------------------------------------------------------------------------- /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 | [![Build Status](https://travis-ci.org/watson-developer-cloud/python-sdk.svg)](https://travis-ci.org/watson-developer-cloud/python-sdk) 4 | [![Slack](https://wdc-slack-inviter.mybluemix.net/badge.svg)](https://wdc-slack-inviter.mybluemix.net) 5 | [![codecov.io](https://codecov.io/github/watson-developer-cloud/python-sdk/coverage.svg?branch=master)](https://codecov.io/github/watson-developer-cloud/python-sdk?branch=master) 6 | [![Latest Stable Version](https://img.shields.io/pypi/v/watson-developer-cloud.svg)](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 | --------------------------------------------------------------------------------