Watson Assistant API V2 "manages the context automatically" - more details? - ibm-cloud

This is a question about Watson Assistant API V1/V2 difference. The doc says like this:
Note that if your app uses the v1 API, it communicates directly with the dialog skill, bypassing the orchestration and state-management capabilities of the assistant. This means that your application is responsible for maintaining state information. This is done using the context, an object that is passed back and forth between your application and the Watson Assistant service. Your application must maintain the context by saving the context received with each response and sending it back to the service with each new message request.
An application using the v2 API can also use the context to access and store persistent information, but the context is maintained automatically (on a per-session basis) by the assistant.
It seems that in V2, "the context is maintained automatically by the assistant". What does this mean exactly ? If I'd like to pass some data to the dialog flow, I might use context on "/message". Is is allowed in V2?( yes, it seems.) Then in V1 days, I have to receive context from responses and send it back on every request. Does assistant also send the context back in V2? What should my client-app do in V2? Any detailed info is welcomed ..Thanks.

Answering your second question first - If you check the API docs for Watson Assistant V2 here, there is a MessageContext object in the response with Global Context and skill specific context values.
You also have a sample Request where you can manually pass the context (both global and user-defined)
curl -u "apikey:{apikey}" -X POST -H "Content-Type:application/json" -d "{\"input\": {\"text\": \"Hello\"}, \"context\": {\"global\": {\"system\": {\"user_id\": \"my_user_id\"}}}}" "https://gateway.watsonplatform.net/conversation/api/v2/assistants/{assistant_id}/sessions/{session_id}/message?version=2018-11-08"
From the client side, you can use this code
service.message({
assistant_id: '{assistant_id}',
session_id: '{session_id}',
input: {
'message_type': 'text',
'text': 'Hello'
},
context: {
'global': {
'system': {
'user_id': 'my_user_id'
}
},
"skills": {
"main skill": {
"user_defined": {
"my_result_variable": "result_value"
}
}
}
}
}
Reference link
Check the API Methods Summary to understand what is supported in V2 as of today.
There is a new concept in V2 called Session. A session is used to send user input to a skill and receive responses. It also maintains the state of the conversation which is Context automatically for you.
V2 API as of today supports Runtime Methods, methods that enable a client application to interact with (but not modify) an existing assistant or skill. You can use these methods to develop a user-facing client that can be deployed for production use, an application that brokers communication between an assistant and another service (such as a chat service or back-end system), or a testing application.
The complete cURL example that works for me
curl -u "apikey:<API_KEY>" -X POST -H "Content-Type:application/json" -d "{
\"input\": {
\"text\": \"What's the time?\",
\"options\": {
\"alternate_intents\": true,
\"debug\": true,\"return_context\": true
}
},
\"context\": {
\"global\": {
\"system\": {
\"user_id\": \"derp\",\"turn_count\":1
}
}
},
\"skills\": {
\"main_skill\":{\"user_defined\": {
\"chosen_service\": \"dental\"
}}
}
}" "https://gateway.watsonplatform.net/assistant/api/v2/assistants/{ASSISTANT_ID}/sessions/{SESSION_ID}/message?version=2018-11-08"
for session ID, run this command
curl -u "apikey:<API_KEY>" -X POST "https://gateway.watsonplatform.net/assistant/api/v2/assistants/{ASSISTANT_ID}/sessions?version=2018-11-08"
The response includes user_defined skill context
{"output":{"generic":[{"response_type":"text","text":"Hey ! how are you today? Let me know if you need any help or get stuck looking for information."}],"debug":{"nodes_visited":[{"dialog_node":"node_6_1475611948267","title":null,"conditions":"conversation_start"}],"log_messages":[],"branch_exited":true,"branch_exited_reason":"completed"},"intents":[{"intent":"General_Greetings","confidence":0.32179955244064334},{"intent":"General_Jokes","confidence":0.296911633014679},{"intent":"goodbye","confidence":0.2852578103542328},{"intent":"General_Ending","confidence":0.2513303637504578},{"intent":"off_topic","confidence":0.24435781836509707},{"intent":"select_detail","confidence":0.24206179082393647},{"intent":"list_options","confidence":0.22829059958457948},{"intent":"still-here","confidence":0.22606439888477325},{"intent":"select_service","confidence":0.22488142400979996},{"intent":"General_Security_Assurance","confidence":0.2210852071642876}],"entities":[]},"context":{"global":{"system":{"turn_count":1,"user_id":"derp"}},"skills":{"main skill":{"user_defined":{"chosen_service":"dental"}}}}}

Thanks, #Vidyasagar Machupalli #data_henrik.
(I created "answer" section to paste the images below .)
1) Now it worked fine. I set the variable reference in dialog editor like this.
Then I post user-variable in context like this.
context={
"skills": {
"main skill": {
"user_defined": {
"myname": "ishida"
}
}
}
}
then the response was:
{'output': {'generic': [{'response_type': 'text', 'text': 'Hi, ishida .'}], 'intents': [], 'entities': []}}
It seems that "skills"->"main skill"->"user_defined" section is a case-sensitive / FIXED keyword.
From what I see, if I change one of them, I cannot read the variable on dialog editor.
2) I also found the documentation issue. The starting point of my question was : "API V2 doc says that I should use "skills" entry to handle the user variables, but no detailed info more than that .. ". #Vidyasagar Machupalli says "As per the V2 API documentation, user_defined is arbitrary variables ".. but I cannot find the paragraph in the API doc.
Then I found that
a) when I select "curl" tab, "user_defined" explanation appears.
b) when I select other(Java/Node/Python) tab, no explanation appears.
I knew that the info was not there as I refered the "Python" tab. I'd appreciate this be fixed soon to avoid same confusion. And I think that the fact of "skills->main skill->user_defined section is a case-sensitive / FIXED keyword" should be noted, as it is not clear in the current description. Thanks!

Related

Getting response from API - DialogFlow Chatbot

I am creating a chatbot using DialogFlow. Here, I am trying to get response from the API, which has been created by my development team (using python). They provided the API URL and requested to fetch data from it according to the users query. I have created a function in the inline editor and pasted the given API URL.
Below is the API format they have created,
{
“data”: [{
“pincode”: “”,
“location_formatted_address”: “”,
“user_id”: “”,
“department_name”: “Education”,
“locality”: “”,
“status”: “Select_Status”
}]
}
Here, when a user gives a department name, it must respond the user with locality of that specific department.
In the Inline editor, I have applied the following logic to fetch the locality,
function getDatafromApI(agent){
const name = agent.parameters.name;
return getAPIData().then(res => {
res.data.map(issues => {
if(issues.department_name === name)
agent.add(`${name}. ${issues.locality}`);
intentMap.set('Fetch API', APIData);
In the above code, "name" is the parameter given in the intent section.
But, I am not getting any response. Any help?
The inline editor uses Firebase. You will have to upgrade to Firebase "Blaze" OR "Flame" plan as the "Spark"(free) plan does not allow external api calls.
However if you have already upgraded Firebase plan and still seeing this error, you can see the execution logs by clicking "view execution logs" link at bottom of Dialogflow fulfillment window.

Passing Thread Control Facebook messenger bot

I am trying the Handover Protocal for my bot but I am not able to get
about passing thread control though I read the documentation still, I am confused
curl -X POST -H "Content-Type: application/json" -d '{
"recipient":{"id":"<PSID>"},
"target_app_id":123456789,
"metadata":"String to pass to secondary receiver app"
}' "https://graph.facebook.com/v2.6/me/pass_thread_control?access_token=<PAGE_ACCESS_TOKEN>"
Example pass_thread_control Event
{
"sender":{
"id":"<PSID>"
},
"recipient":{
"id":"<PAGE_ID>"
},
"timestamp":1458692752478,
"pass_thread_control":{
"new_owner_app_id":"123456789",
"metadata":"Additional content that the caller wants to set"
}
}
I am trying to know what is PSID here and what can be target_app_id.
can anyone help me with proper example.
It took me a bit to figure out, so I totally understand your frustration! There isn't adequate documentation when it comes to working with the handover protocol.
My current use case is a bot that offers the option to speak to a representative if it's unable to understand the user. This is done through the use of a postback button, which means the handover is activated by the user. After the user clicks on the button, the following code is run:
graph.setAccessToken(<YOUR_APP_ACCESS_TOKEN>);
graph.setAppSecret(<YOUR_APP_SECRET>);
graph.setVersion("2.12");
graph.post(
`me/pass_thread_control?access_token=${functions.config().messenger.token}`,
handoverMessage,
(err, res) => {
if(err) {
console.log('HANDOVER ERROR:', err);
return;
}
console.log('HANDOVER SUCCESS:', res);
});
The handoverMessage variable is where you will place the psid and target_app_id:
let handoverMessage = {
"recipient": {
"id": <PSID>
},
"target_app_id": <YOUR_TARGET_APP_ID>
}
Calling this code will handover the control of the conversation to whatever your target_app_id is.
If you're wondering what 'graph' is, it is a node package called 'fbgraph' that I've found very useful when dealing with the facebook graph api. It's certainly not the only wrapper and there are likely better packages out there, but it has worked for me up to now.

Security of cloudant query from OpenWhisk

I'm building an Angular SPA with a Cloudant data store on Bluemix.
Since the Bluemix implementation of OpenWhisk doesn't use VCAP services, I see 3 options to use OpenWhisk as my api provider for cloudant queries for my Angular app:
Follow the pattern of passing credentials as seen here: https://github.com/IBM-Bluemix/openwhisk-visionapp (very interesting approach btw)
Include the credentials as though I'm running locally as seen here: https://github.com/IBM-Bluemix/nodejs-cloudant/blob/master/app.js
Use the http API as seen here: https://docs.cloudant.com/api.html (which highlights the security problem passing credentials.
Since my service is not intended for publishing (it's intended for my own app) I'm thinking option 2 is my "least of all evils" choice. Am I missing something? My thinking is such that while fragile to changes it would be the most secure since credentials aren't passed in the open. The serverless infrastructure would have to be hacked...
Thanks in advance!
(lengthy) Update: (apologies in advance)
I've gotten a little farther along but still no answer - stuck in execution right now.
To clarify, my objective is for the app to flow from Angular Client -> OpenWhisk -> Cloudant.
In this simplest use case, I want to pass a startTime parameter and an endTime parameter, have OpenWhisk fetch all the records in that time range with all fields, and passing back selected fields. In my example, I have USGS earthquake data in a modified GeoJSON format.
Following information from the following articles below, I've concluded that I can invoke the wsk command line actions and use the bindings I've setup from within my Javascript function and therefore not pass my credentials to the database. This gives me a measure of security (still question the rest endpoint of my OpenWhisk action) but I figure once I get my sample running I think through that part of it.
My command line (that works):
wsk action invoke /my#orgname.com_mybluemixspace/mycfAppName/exec-query-find --blocking --result --param dbname perils --param query {\"selector\":{\"_id\":{\"$gt\":0},\"properties.time\":{\"$gt\":1484190609500,\"$lt\":1484190609700}}}
This successfully returns the following:
{
"docs": [
{
"_id": "eq1484190609589",
"_rev": "1-b4fe3de75d9c5efc0eb05df38f056a65",
"dbSaveTime": 1.484191201099e+12,
"fipsalpha": "AK",
"fipsnumer": "02",
"geometry": {
"coordinates": [
-149.3691,
62.5456,
0
],
"type": "Point"
},
"id": "ak15062242",
"properties": {
"alert": null,
"cdi": null,
"code": "15062242",
"detail": "http://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/ak15062242.geojson",
"dmin": null,
"felt": null,
"gap": null,
"ids": ",ak15062242,",
"mag": 1.4,
"magType": "ml",
"mmi": null,
"net": "ak",
"nst": null,
"place": "45km ENE of Talkeetna, Alaska",
"rms": 0.5,
"sig": 30,
"sources": ",ak,",
"status": "automatic",
"time": 1.484190609589e+12,
"title": "M 1.4 - 45km ENE of Talkeetna, Alaska",
"tsunami": 0,
"type": "earthquake",
"types": ",geoserve,origin,",
"tz": -540,
"updated": 1.484191127265e+12,
"url": "http://earthquake.usgs.gov/earthquakes/eventpage/ak15062242"
},
"type": "Feature"
}
]
}
The action I created in OpenWhisk (below) returns an Internal Server Error. I'm passing the input value as
{
"startTime": "1484161200000",
"endTime": "1484190000000"
}
Here's the code for my action:
`var openWhisk = require('openwhisk');
var ow = openWhisk({
api_key:'im really a host'
});
function main(params) {
return new Promise(function(resolve, reject) {
ow.actions.invoke({
actionName:'/my#orgname.com_mybluemixspace/mycfAppName/exec-query-find',
blocking:true,
parameters:{
dbname: 'perils',
query: {
"selector": {
"_id": {
"$gt": 0
},
"properties.time": {
"$gt": params.startTime,
"$lt": params.endTime
}
}
}
}
}).then(function(res) {
//get the raw result
var raw = res.response.result.rows;
//lets make a new one
var result = [];
raw.forEach(function(c) {
result.push({id:c.docs._id, time:c.docs.properties.time, title:c.docs.properties.title});
});
resolve({result:result});
});
});
}`
Here are the links to my research:
http://infrastructuredevops.com/08-17-2016/news-openwhisk-uniq.html
Useful because of the use of the exec-query-find and selector syntax usage but also cool for the update function I need to build for populating my data!
https://www.raymondcamden.com/2016/12/23/going-serverless-with-openwhisk
The article referenced by #csantanapr
Am I overlooking something?
Thanks!
I'm assuming what you are trying to do is to access your Cloudant DB directly from your angular client side code from the Browser.
If you don't need any business logic, or you can get away by using Cloudant features (design docs, views, map, reduce, etc..) and you are generating Cloudant API keys with certain access (i.e. write vs. read), then you don't need a server or serveless middlewear/tier.
But now let's get real, most people need that tier, and if you are looking a OpenWhisk, then you are in good luck this is very easy to do.
OpenWhisk on Bluemix support VCAP service credentials, but in a different way.
Let's name you have a Bluemix Org carlos#example.com and space dev that would translate to OpenWhisk namespace carlos#example.com_dev
If you add a Cloudant service under the space dev in Bluemix, this will generate service key credentials for this Cloudant Account. This credentials give you super power access meaning you are admin.
If you want to use this Cloudant credentials in OpenWhisk, you can use the automatic binding generated with the cloudant package.
To do this using the OpenWhisk CLI run wsk package refresh this will pull the Cloudant credentials and create you a new package with the credentials binded as default parameter for all the cloudant actions under that package. This is modified version of #1 above
Another alternative is to bind the credentials manually to a package or an action as default parameters, this makes sense when you don't want to use the super power admin credentials, and you generated a Cloudant API key for a specific database. This is option #1 above.
I would not recommend to put the credentials in source code #2
For option #3, what's insecure is to pass your credentials as part of the URL like https://username:password#user.cloudant.com, but passing the username and password in the Authorization header over https is secured.
This is because even if you are using secure transport https everything in the URI/URL is not encrypted anyone can see that value, but passing secrets in body or header is standard practice as this is transfer after secure connection is established.
Then you create actions that use the credentials as parameters in your OpenWhisk actions to build your business logic for your backend.
Then how to do you access this backend from the Browser, well OpenWhisk has a API Gateway feature in experimental that allows your to expose your actions as public APIs with CORS enable.
Only a url is expose, your credentials as default parameters are never expose.
If you want to see an example on check out Raymond Camden Blog posts where he show Ionic/Angular App accessing his Cloudant Database of Cats
https://www.raymondcamden.com/2016/12/23/going-serverless-with-openwhisk

How to give personalised greeting in Watson Conversation?

While Defining the Dialog in the Watson Conversation I'm not able to greet user with his/her name or I'm not able to detect contact number sent by the user and rephrase it to the user. Is it possible to do it in the Watson Conversation Api or not.
Although Mitch's response is correct, here is an example of doing a personalised response.
1. Set your conversation_start node text to "Hello <? context.username ?>".
2. In your code you would do something like this (Python).
import json
from watson_developer_cloud import ConversationV1
conversation = ConversationV1(
username='SERVICE_USERNAME',
password='SERVICE_PASSWORD',
version='2016-07-11')
workspace_id = 'WORKSPACE_ID_CONVERSATION'
response = conversation.message(workspace_id=workspace_id, context= {'username':'Simon'})
print json.dumps(response)
3. When you run this, it should output the following, with the "text" part being what the user sees.
{
"entities":[],
"intents":[],
"output":{
"log_messages":[],
"nodes_visited":["node_1_1472298724972],
"text":["Hello Simon"]
},
"context":{
"username":"Simon",
"conversation_id":"9dc1501b-ac53-4b51-a299-37f5314ebf89",
"system":{
"dialog_turn_counter":1,
"dialog_stack":["root"],
"dialog_request_counter":1
}
},
"input":{}
}
One thing to be aware is that, the context object is used to maintain the state of the conversation. So if you plan to use just REST API's then you need to merge your context variables into the preceding context object before sending it. You do only need to do this at points where you do know the conversation needs that context.
Do you already have access to this information? You can send these values through as context, and refer to them using $context_variable
The same goes for collecting information from a user. You can capture things using regular expressions via your application, or using some Spring Expressions, you can see the text.matches here:
https://www.ibm.com/watson/developercloud/doc/conversation/dialog_reference.shtml
You would store this as context, and then refer to it using $context_variable again.
Information like names and phone numbers is quite open ended, so can be difficult to capture without using an open entity extraction engine, which we are researching best ways to incorporate this.
To get the user's input, use:
"context": {"yourVariable": "<?input.text?>"}
And to show:
"output": {"text": "You entered this $yourVariable"}

IBM Watson Tone Analyzer service credentials

I have been trying to run a query against IBM Watson Tone Analyzer service and keep getting an error that my service credentials are not recognized.
I am sure that I am entering the correct credentials. Here are the steps that I took to get the service credentials:
Signed up with bluemix.net.
Clicked on Tone Analyzer icon.
Clicked on service credentials.
Clicked on add credentials and used the credentials that were obtained from this step.
I followed these steps multiple times but keep running into same error:
watson_developer_cloud.watson_developer_cloud_service.WatsonException: Unauthorized: Access is denied due to invalid credentials
I would really appreciate any insights here.
I was just able to run a test without any errors. Here are the steps I took:
1. Created a new IBM Watson Tone Analyzer instance:
2. Looked at the service credentials page:
(I've changed the username to "abcuser" and the password to "abcpass" for this example.)
3. I ran this curl command to test out my service:
curl -u "{username}":"{password}" -H "Content-Type: application/json" -d "{\"text\": \"Hi Team, I know the times are difficult! Our sales have been disappointing for the past three quarters for our data analytics product suite. We have a competitive data analytics product suite in the industry. But we need to do our job selling it! \"}" "https://gateway.watsonplatform.net/tone-analyzer/api/v3/tone?version=2016-05-19"
so replacing the username and password, I get...
curl -u "abcuser":"abcpass" -H "Content-Type: application/json" -d "{\"text\": \"Hi Team, I know the times are difficult! Our sales have been disappointing for the past three quarters for our data analytics product suite. We have a competitive data analytics product suite in the industry. But we need to do our job selling it! \"}" "https://gateway.watsonplatform.net/tone-analyzer/api/v3/tone?version=2016-05-19"
4. Finally, I got this response:
{
"document_tone":{
"tone_categories":[
{
"tones":[
{
"score":0.455891,
"tone_id":"anger",
"tone_name":"Anger"
},
{
"score":0.156707,
"tone_id":"disgust",
"tone_name":"Disgust"
},
{
"score":0.17315,
"tone_id":"fear",
"tone_name":"Fear"
},
{
"score":0.190073,
"tone_id":"joy",
"tone_nam e":"Joy"
},
{
"score":0.291627,
"tone_id":"sadness",
"tone_name":"Sadness"
}
],
"category_id":"emotion_tone",
"category_name":"Emotion Tone"
},
{
"tones":[
{
"score":0.459,
"tone_id":"analytical",
"tone_name":"Analytical"
},
{
"score":0.0,
"tone_id":"confident",
"tone_name":"Confide nt"
},
{
"score":0.0,
"tone_id":"tentative",
"tone_name":"Tentative"
}
],
"category_id":"language_tone",
"category_name":"Language Tone"
},
{
"tones":[
{
"score":0.03,
"tone_id":"openness_big5",
"tone_name":"Openness"
},
{
"score":0.188,
"tone_id":"conscientiousness_big5",
"tone_nam e":"Conscientiousness"
},
{
"score":0.405,
"tone_id":"extraversion_big5",
"tone_name":"Extraversion"
},
{
"score":0.879,
"tone_id":"agreeableness_big5",
"tone_name":"Agreeableness"
},
{
"score":0.962,
"tone_id":"emotional_range_big5",
"tone_name":"Emotional Range"
}
],
"category_ id":"social_tone",
"category_name":"Social Tone"
}
]
}
}
Edit:
If you are having trouble with the Python SDK, try this:
import json
from watson_developer_cloud import ToneAnalyzerV3Beta
tone_analyzer = ToneAnalyzerV3Beta(
url='https://gateway.watsonplatform.net/tone-analyzer/api',
username='USERNAME',
password='PASSWORD',
version='2016-02-11')
print(json.dumps(tone_analyzer.tone(text='I am very happy'), indent=2))
From your post above it looks you are doing the right thing with credentials, but trying to use them against a Beta instance of Tone Analyzer service.
As some background to understand any comments below: Tone Analyzer became "GA" on May 20th. Previously, it was "Beta". The Beta plan has URL https://gateway.watsonplatform.net/tone-analyzer-beta/api, while GA uses .../tone-analyzer/api (no -beta). Additionally if you are doing Python, there are two wrappers: ToneAnalyzerV3Beta (Beta) and ToneAnalyzerV3 (GA). Since we are still transitioning, some people still use existing instances of Beta plans, and also wrappers for Beta still exist.
Most importantly, credentials for the Beta plan will not work in GA, and vice versa.
That said, you need to make sure you are consistently using the GA or "standard" plan everywhere:
In your app, bind a "Tone Analyzer" (not Beta) plan.
Make sure the API URL contains /tone-analyzer/api (no -beta)
In the wrapper (python, node, java, or your URL if you did your own), use the "GA" (anything without "Beta" suffix).
Another detail (which wrappers will handle for you transparently) is that ?version argument is 2016-05-19 for the last API version. You should be using this one to get the latest features...
Joe's answer is very detailed about the process, just make sure you distinguish this Beta vs GA thing. Please add another comment if you have more questions. I hope this helps!