Skip to content

Commit 5659e1c

Browse files
committed
initial commit
1 parent c44fb25 commit 5659e1c

File tree

3 files changed

+289
-0
lines changed

3 files changed

+289
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
# TODO: are these needed?
16+
from .watson_developer_cloud_service import WatsonDeveloperCloudService
17+
from .watson_developer_cloud_service import WatsonException
18+
from .watson_developer_cloud_service import WatsonInvalidArgument
19+
from .conversation_v1 import ConversationV1
20+
from .tone_analyzer_v3 import ToneAnalyzerV3
21+
22+
# TODO: do I need the version library?
23+
from .version import __version__
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import json
2+
from watson_developer_cloud import ConversationV1
3+
from watson_developer_cloud import ToneAnalyzerV3
4+
5+
# import tone detection
6+
import tone_detection
7+
8+
# replace with your own conversation credentials
9+
conversation = ConversationV1(
10+
username='YOUR SERVICE NAME', # YOUR SERVICE NAME
11+
password='YOUR PASSWORD',
12+
version='2016-07-11')
13+
14+
# replace with your own tone analyzer credentials
15+
tone_analyzer = ToneAnalyzerV3(
16+
username='YOUR SERVICE NAME',
17+
password='YOUR PASSWORD',
18+
version='2016-02-11')
19+
20+
# replace with your own workspace_id
21+
# the process.env probably won't work with python
22+
workspace_id = process.env.WORKSPACE_ID or 'YOUR WORKSPACE ID'
23+
24+
# This example stores tone for each user utterance in conversation context.
25+
# Change this to false, if you do not want to maintain history
26+
maintainToneHistoryInContext = true
27+
28+
# Payload for the Watson Conversation Service
29+
# <workspace-id> and user input text required.
30+
payload = {
31+
'workspace_id':workspace_id,
32+
'input': {
33+
'text': "I am not happy today :("
34+
}
35+
}
36+
37+
def invokeToneConversation (payload, maintainToneHistoryInContext):
38+
'''
39+
invokeToneConversation calls the the Tone Analyzer service to get the tone information for the user's
40+
input text (input['text'] in the payload json object), adds/updates the user's tone in the payload's context,
41+
and sends the payload to the conversation service to get a response which is printed to screen.
42+
:param payload: a json object containing the basic information needed to converse with the Conversation Service's message endpoint.
43+
:param maintainHistoryInContext:
44+
45+
46+
Note: as indicated below, the console.log statements can be replaced with application-specific code to process the err or data object returned by the Conversation Service.
47+
'''
48+
49+
tone = tone_analyzer.tone({'text': payload['input']['text']})
50+
conversation_payload = tone_detection.updateUserTone(payload, tone, maintainToneHistoryInContext)
51+
response = conversation.message(workspace_id=workspace_id, message_input=conversation_payload)
52+
print(json.dumps(response, indent=2))
53+
54+
invokeToneConversation(payload,maintainToneHistoryInContext);
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
import json
2+
3+
"""
4+
* Copyright 2015 IBM Corp. All Rights Reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
"""
18+
19+
"""
20+
* Thresholds for identifying meaningful tones returned by the Watson Tone Analyzer. Current values are
21+
* based on the recommendations made by the Watson Tone Analyzer at
22+
* https://www.ibm.com/watson/developercloud/doc/tone-analyzer/understanding-tone.shtml
23+
* These thresholds can be adjusted to client/domain requirements.
24+
"""
25+
PRIMARY_EMOTION_SCORE_THRESHOLD = 0.5
26+
LANGUAGE_HIGH_SCORE_THRESHOLD = 0.75
27+
LANGUAGE_NO_SCORE_THRESHOLD = 0.0
28+
SOCIAL_HIGH_SCORE_THRESHOLD = 0.75
29+
SOCIAL_LOW_SCORE_THRESHOLD = 0.25
30+
31+
# Labels for the tone categories returned by the Watson Tone Analyzer
32+
EMOTION_TONE_LABEL = 'emotion_tone'
33+
LANGUAGE_TONE_LABEL = 'language_tone'
34+
SOCIAL_TONE_LABEL = 'social_tone'
35+
36+
'''
37+
* updateUserTone processes the Tone Analyzer payload to pull out the emotion, language and social
38+
* tones, and identify the meaningful tones (i.e., those tones that meet the specified thresholds).
39+
* The conversationPayload json object is updated to include these tones.
40+
* @param conversationPayload json object returned by the Watson Conversation Service
41+
* @param toneAnalyzerPayload json object returned by the Watson Tone Analyzer Service
42+
* @returns conversationPayload where the user object has been updated with tone information from the toneAnalyzerPayload
43+
'''
44+
def updateUserTone (conversationPayload, toneAnalyzerPayload, maintainHistory):
45+
46+
emotionTone = None
47+
languageTone = None
48+
socialTone = None
49+
50+
# if there is no context in a
51+
if conversationPayload.context == None:
52+
conversationPayload.context = {};
53+
54+
if conversationPayload.context.user == None:
55+
conversationPayload.context = initUser()
56+
57+
# For convenience sake, define a variable for the user object
58+
user = conversationPayload['context']['user'];
59+
60+
# Extract the tones - emotion, language and social
61+
if toneAnalyzerPayload and toneAnalyzerPayload['document_tone']:
62+
for toneCategory in toneAnalyzerPayload['document_tone']['tone_categories']:
63+
if toneCategory['category_id'] == EMOTION_TONE_LABEL:
64+
emotionTone = toneCategory
65+
if toneCategory['category_id'] == LANGUAGE_TONE_LABEL:
66+
languageTone = toneCategory
67+
if toneCategory['category_id'] == SOCIAL_TONE_LABEL:
68+
socialTone = toneCategory
69+
70+
updateEmotionTone(user, emotionTone, maintainHistory)
71+
updateLanguageTone(user, languageTone, maintainHistory)
72+
updateSocialTone(user, socialTone, maintainHistory)
73+
74+
conversationPayload['context']['user'] = user
75+
76+
return conversationPayload;
77+
78+
'''
79+
initToneContext initializes a user object containing tone data (from the Watson Tone Analyzer)
80+
@returns user json object with the emotion, language and social tones. The current
81+
tone identifies the tone for a specific conversation turn, and the history provides the conversation for
82+
all tones up to the current tone for a conversation instance with a user.
83+
'''
84+
def initUser():
85+
return {
86+
'user': {
87+
'tone': {
88+
'emotion': {
89+
'current': null
90+
},
91+
'language': {
92+
'current': null
93+
},
94+
'social': {
95+
'current': null
96+
}
97+
}
98+
}
99+
}
100+
101+
'''
102+
updateEmotionTone updates the user emotion tone with the primary emotion - the emotion tone that has
103+
a score greater than or equal to the EMOTION_SCORE_THRESHOLD; otherwise primary emotion will be 'neutral'
104+
@param user a json object representing user information (tone) to be used in conversing with the Conversation Service
105+
@param emotionTone a json object containing the emotion tones in the payload returned by the Tone Analyzer
106+
'''
107+
def updateEmotionTone(user, emotionTone, maintainHistory):
108+
109+
maxScore = 0.0
110+
primaryEmotion = None
111+
primaryEmotionScore = None
112+
113+
for tone in emotionTone['tones']:
114+
if tone['score'] > maxScore:
115+
maxScore = tone['score']
116+
primaryEmotion = tone['tone_name'].lower()
117+
primaryEmotionScore = tone['score']
118+
119+
if maxScore <= PRIMARY_EMOTION_SCORE_THRESHOLD:
120+
primaryEmotion = 'neutral'
121+
primaryEmotionScore = None
122+
123+
# update user emotion tone
124+
user['tone']['emotion']['current'] = primaryEmotion;
125+
126+
if maintainHistory:
127+
if not user['tone']['emotion']['history']:
128+
user['tone']['emotion']['history'] = []
129+
user['tone']['emotion']['history'].append({
130+
'tone_name': primaryEmotion,
131+
'score': primaryEmotionScore
132+
})
133+
134+
'''
135+
updateLanguageTone updates the user with the language tones interpreted based on the specified thresholds
136+
@param: user a json object representing user information (tone) to be used in conversing with the Conversation Service
137+
@param: languageTone a json object containing the language tones in the payload returned by the Tone Analyzer
138+
'''
139+
def updateLanguageTone (user, languageTone, maintainHistory):
140+
141+
currentLanguage = [];
142+
currentLanguageObject = [];
143+
144+
# Process each language tone and determine if it is high or low
145+
for tone in languageTone['tones']:
146+
if tone['score'] >= LANGUAGE_HIGH_SCORE_THRESHOLD:
147+
currentLanguage.append(tone['tone_name'].lower() + '_high')
148+
currentLanguageObject.append({
149+
'tone_name': tone['tone_name'].lower(),
150+
'score': tone['score'],
151+
'interpretation': 'likely high'
152+
})
153+
elif tone['score'] <= LANGUAGE_NO_SCORE_THRESHOLD:
154+
currentLanguageObject.append({
155+
'tone_name': tone['tone_name'].lower(),
156+
'score': tone['score'],
157+
'interpretation': 'no evidence'
158+
})
159+
else:
160+
currentLanguageObject.append({
161+
'tone_name': tone['tone_name'].lower(),
162+
'score': tone['score'],
163+
'interpretation': 'likely medium'
164+
})
165+
166+
# update user language tone
167+
user['tone']['language']['current'] = currentLanguage
168+
if maintainHistory:
169+
if not user['tone']['language']['history']:
170+
user['tone']['language']['history'] = []
171+
user['tone']['language']['history'].append(currentLanguageObject) #TODO - is this the correct location??? AW
172+
173+
'''
174+
updateSocialTone updates the user with the social tones interpreted based on the specified thresholds
175+
@param user a json object representing user information (tone) to be used in conversing with the Conversation Service
176+
@param socialTone a json object containing the social tones in the payload returned by the Tone Analyzer
177+
'''
178+
def updateSocialTone (user, socialTone, maintainHistory):
179+
180+
currentSocial = []
181+
currentSocialObject = []
182+
183+
# Process each social tone and determine if it is high or low
184+
for tone in socialTone['tones']:
185+
if tone['score'] >= SOCIAL_HIGH_SCORE_THRESHOLD:
186+
currentSocial.append(tone['tone_name'].lower() + '_high')
187+
currentSocialObject.append({
188+
'tone_name': tone['tone_name'].lower(),
189+
'score': tone['score'],
190+
'interpretation': 'likely high'
191+
})
192+
elif tone['score'] <= SOCIAL_LOW_SCORE_THRESHOLD:
193+
currentSocial.append(tone['tone_name'].lower() + '_low');
194+
currentSocialObject.append({
195+
'tone_name': tone['tone_name'].lower(),
196+
'score': tone['score'],
197+
'interpretation': 'likely low'
198+
})
199+
else:
200+
currentSocialObject.append({
201+
'tone_name': tone['tone_name'].lower(),
202+
'score': tone['score'],
203+
'interpretation': 'likely medium'
204+
})
205+
206+
# update user social tone
207+
user['tone']['social']['current'] = currentSocial
208+
if maintainHistory:
209+
if not user['tone']['social']['current']:
210+
user['tone']['social']['current'] = [];
211+
user['tone']['social']['current'].append(currentSocialObject);
212+

0 commit comments

Comments
 (0)