Add additional links response to knowledge base in DialogFlow - dialogflow-es

With knowledge bases in DialogFlow you can have a basic FAQ upload. First column is the question and second is the answer. Often we need to have the answer provide an additional link. e.g., "The answer to your question is no, pineapple does not go on pizza". More info
What I want to provide is the answer followed by a rich response link. Since you cannot have a 3rd column in the spreadsheet to add a link, how can I do this cleanly? Sure, I can just have the link as part of the answer text, but that's not as pretty.
I was able to duplicate the question and then provide a link as the second answer (i.e., $Knowledge.Answer(2)) but then some answers don't have links and I can't make this conditional.
I assume I can do this in Fulfilment but I'm not sure of the actual code that can return the answer ($Knowledge.Answer(1)) and then conditionally add a rich response with a link.

I finally worked it out.
First, I used some delimiter in my answer (here just 'Z$Z').
For example, in the csv file I put the following in a second column:
The answer to your question is no, pineapple does not go on pizza$Z$More Info$Z$https://www.mashed.com/183299/the-most-controversial-pizza-toppings-explained/
This way when I get to the fulfillment I can just parse the answer.
Here's a cut of the code:
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
// save off the answer to parse
let answer = JSON.stringify(request.body.queryResult.fulfillmentText);
function faqHandler(agent) {
let answerAlt = answer.slice(1,-1); // remove first and last double quote
let answerParse = answerAlt.split("Z$Z"); // parse the answer
if( answerParse.length == 1) {
// no links
agent.add(answerParse[0].toString());
} else {
// display the content with the text and links
// you can use different ways here to display but you have access to
// the answer, title, and url as follows
// answerParse[0].toString(), answerParse[1].toString(), answerParse[1].toString()
}
}
...
intentMap.set('Knowledge.KnowledgeBase.ID_OF_KNOWLEDGEBASE',faqHandler);

Related

Construct form-data with duplicate keys in Nodejs client post request body

I am trying to make a post request which body consists of form-data. But the API rest spec, says the form data should look like this :
names[]= company name 1&names[]=company name 2
I tried
form: {'names[]': "google" ,'names[]': "kraft", 'fields[]': "Country",
'fields[]':"ISIN"}
But the server receives only the first names[] and fields[]. The second ones are cut.
Server: Post data: {"names"=>["kraft"], "fields"=>["ISIN"]}
Then I tried to add array as value:
form: {'names[]': ["google", "kraft"], 'fields[]': ["Country","ISIN"] }
Server: Post data: {"names"=>[{"0"=>"google", "1"=>"kraft"}], "fields"=>[{"0"=>"Country", "1"=>"ISIN"}]}
Looking at the server request, I see that it accepts body in this format:
BODY: names[]=google&names[]=kraft&fields[]=ISIN&fields[]=Country
But I cant construct such form in my node-client side.
I am using this library: https://www.npmjs.com/package/request
********* EDIT ********
This one actually woked:
form: "names[]=google&names[]=kraft&fields[]=Country&fields[]=ISIN"
Now the question is how to form this string using https://github.com/form-data/form-data
No append doesn't work I tried.
It's recommended for keys to be unique and not have brackets in their naming. In your case, names[] and fields[] repeat themselves
const form = {
form: {
names: ['google', 'kraft'],
fields: ['Country', 'ISIN']
}
};
request.post('http://yourwebsite.com', form);
EDIT
names[]=google&names[]=kraft&fields[]=ISIN&fields[]=Country
May be valid, but depending on framework/language, only one entry will be taken into consideration (first or last). So it is equivalent to
names[]=google&fields[]=ISIN // considering first are chosen
Also as you can see
Server: Post data: {"names"=>["kraft"], "fields"=>["ISIN"]}
The brackets were filtered out, so this will be again the same thing
names=google&fields=ISIN // considering first are chosen

Dialogflow node.js fulfilment with multiple entities

I hope someone can help me with this.
I have built an application that uses node.js to fulfil my intent in dialogflow.
For example, I have an intent with one required action:
It goes to my fulfilment:
// Handle the Dialogflow intent named 'Default Welcome Intent'.
app.intent(DEFAULT_INTENT, (conv, params) => {
let categoryId = params.category;
let options = {
'method': 'GET',
'url': apiUrl + 'questions/categories/' + categoryId + '/scenario',
'json': true
};
return request(options).then(response => {
// TODO: What happens if there is more than one question?
let question = response[0];
conv.ask(question.text);
}, error => {
conv.ask('There was an issue with the request: ' + options.url);
});
});
As you can see, this asks a question based on the category sent to the fulfilment.
The problem I have is that the response I want from the user is different for each question.
Once they have responded, it will also have a fulfilment that will ask another question.
Is it possible to do it this way and if so, can someone give me an example of how? If not, can someone help me work out what the alternative is?
The approach you're using makes sense. The key thing to remember is that Intents capture what the user says, not how you handle what they say. You can influence which Intent gets triggered by setting an Input Context, and making sure you have previously set an Output Context for it.
One possible approach would be that for each question you're asking, you set a corresponding Output Context for that question. You can then have one or more Intents that take this as the Input Context. These are otherwise regular Intents, so you'd handle them normally. You might want to clear the context (by setting its lifespan to 0) after it matches, so you don't accidentally match it later.
For example, if your question contains, not only the text of the question, but also the context name of the question, the code might look something like this:
conv.ask( question.text );
conv.contexts.set( question.contextName, 5 );
Let's say that the question object looks something like this
{
text: "What is your favorite color?",
contextName: "color-favorite"
}
You might have a Dialogflow Intent that handles this that looks something like this
Note that the Output Context has explicitly set it to 0, which will remove it. You can also do this in your fulfillment code with something like
conv.contexts.delete( 'color-favorite' );

Post to SMF Forum via PHP

I am building a CMS that supports a website which also contains an SMF forum (2.0.11). One of the modules in the CMS involves a "report" that tracks attendance. That data is queried to tables outside of smf, but in the same database. In addition to what it does now, I would also like for a post to be made in a specific board on the SMF forum containing the formatted content. As all of the posts are contained by the database, surely this is possible, but it seems there is more to it than a single row in a table.
To put it in the simplest code possible, below is what I want to happen when I click Submit on my page.
$title = "2015-03-04 - Attendance";
$author = "KGrimes";
$body = "Attendance was good.";
$SQL = "INSERT INTO smf_some_table (title, author, body) VALUES ($title, $author, $body)";
$result = mysqli_query($db_handle, $SQL);
Having dug through the smf DB tables and the post() and post2() functions, it seems there is more than one table involved when a post is made. Has anyone outlined this before?
I've looked into solutions such as the Custom Form Mod, but these forms and templates are not what I am looking for. I already have the data inputted and POST'ed to variables, I just need the right table(s) to INSERT it into so that it appears on the forum.
Thank you in advance for any help!
Source: http://www.simplemachines.org/community/index.php?topic=542521.0
Code where you want to create post:
//Define variables
//msgOptions
$smf_subject = "Test Title";
//Handle & escape
$smf_subject = htmlspecialchars($smf_subject);
$smf_subject = quote_smart($smf_subject, $db_handle);
$smf_body = "This is a test.";
//Handle & escape
$smf_body = htmlspecialchars($smf_body);
$smf_body = quote_smart($smf_body, $db_handle);
//topicOptions
$smf_board = 54; //Any board id, found in URL
//posterOptions
$smf_id = 6; //any id, this is found as ID in memberlist
//SMF Post function
require_once('../../forums/SSI.php');
require_once('../../forums/Sources/Subs-Post.php');
//createPost($msgOptions, $topicOptions, $posterOptions);
// Create a post, either as new topic (id_topic = 0) or in an existing one.
// The input parameters of this function assume:
// - Strings have been escaped.
// - Integers have been cast to integer.
// - Mandatory parameters are set.
// Collect all parameters for the creation or modification of a post.
$msgOptions = array(
'subject' => $smf_subject,
'body' => $smf_body,
//'smileys_enabled' => !isset($_POST['ns']),
);
$topicOptions = array(
//'id' => empty($topic) ? 0 : $topic,
'board' => $smf_board,
'mark_as_read' => true,
);
$posterOptions = array(
'id' => $smf_id,
);
//Execute SMF post
createPost($msgOptions, $topicOptions, $posterOptions);
This will create the simplest of posts with title and body defined by you, along with location and who the author is. More parameters can be found in the SMF functions database for createPost. The SSI and Subs-Post.php includes must be the original directly, copying them over doesn't do the trick.

Dynamically refresh a div without a straightful DOM manipulation

I have to update for example a table, a list if some values. I can insert new values and try to reload a entire page to show table or list values again.
If I give a try on Ajax updates I have to manipulate DOM, creating a bunch of new tags, concatenate and inject the new HTML on old one. This not a painful way, you even must re-type the code created before to exhibit new entries.
E.g: this is a fictitious example and illustrates what I mean:
$.ajax({
url: '/post/addComment/',
type: 'POST',
data: 'comment=' + comment,
beforeSend : function() {
//waiting message
$('#some_information_div').html('<strong>Updating...</strong>');
}
}).done(function(data) {
//new data comes here (by JSON, plain text, whatever...)
if (data.status == 'OK') {
//OHHH MAN WE HAVE TO POPULATE MANUALLY IT AGAIN
var c = '';
c = '<table>'
data.content.forEach(function(e) {
c += '<tr><td>' + e.name + '</td></tr>';
});
c += '</table>'
//update with new values
$('#some_information_div').html('');
$('#destination_table').html(c);
}
});
Unfortunately I have to do all the time with my lists and tables and somehow I have to re-type codes and manipulate it all by the javascript. I figured out something might be useful like does jQuery.load(), maybe it can fit what I want to, I have not tried it.
Some other languages and frameworks like JSF do it easily with "render technique", you directly update content without have to create and manipulate DOM in manually way.
Please, any kind of suggestion, any clue to this approach will be very helpful.
P.S.: The code sample tag doesn't work well here.
This can be done by using .load() jquery function. I have illustrated for some page 1.php and some table having id mytable
$('table#mytable').load('./1.php #mytable');
for constant refreshing --
setInterval(function() {
$('tablev#mytable').load('./1.php #mytable');
}, 5000);

modified innerHTML does not show on page

I am writing a Google extension. Here my content script modifies a page based on a list of keywords requested from background. But the new innerHTML does not show up on the screen. I've kluged it with an alert so I can see the keywords before deciding to actually send a message, but it is not how the routine should work. Here's the code:
// MESSAGE.JS //
//alert("Message Page");
var keyWordList= new Array();
var firstMessage="Hello!";
var contentMessage=document.getElementById("message");
contentMessage.value=firstMessage;
var msgComments=document.getElementsByClassName("comment");
msgComments[1].value="Hello Worlds!";//marker to see what happens
chrome.extension.sendRequest({cmd: "sendKeyWords"}, function(response) {
keyWordList=response.keyWordsFound;
//alert(keyWordList.length+" key words.");//did we get any keywords back?
var keyWords="";
for (var i = 0; i<keyWordList.length; ++i)
{
keyWords=keyWords+" "+keyWordList[i];
}
//alert (keyWords);//let's see what we got
document.getElementsByClassName("comment")[1].firstChild.innerHTML=keyWords;
alert (document.getElementsByClassName("comment")[1].firstChild.innerHTML);// this is a band aid - keyWords does not show up in tab
});
document.onclick= function(event) {
//only one button to click in page
document.onload=self.close();
};
What do I have to do so that the text area that is modified actually appears in the tab?
(Answering my own question) This problem really has two parts. The simplest part is that I was trying to modify a text node by setting its value like this:
msgComments1.value="Hello Worlds!"; //marker to see what happens
To make it work, simply set the innerHTML to a string value like this:
msgComment1.innerHTML="Hello Worlds!"; //now it works.
The second part of the problem is that the asynchronous call to chrome.extension.sendRequest requires a callback to update the innerHTML when the reply is received. I posted a question in this regard earlier and have answered it myself after finding a solution in an previous post by #serg.

Resources