How to extract variables from sentences with node-nlp - node.js

I'm trying to extract variable(s) from sentences with node-nlp using the following code:
const { NlpManager, ConversationContext } = require('node-nlp');
const manager = new NlpManager({ languages: ['en'] });
const context = new ConversationContext();
(async () => {
manager.addDocument('en', 'Hello my name is %name%', 'greeting.hello');
manager.addDocument('en', 'I have to go', 'greeting.bye');
manager.addAnswer('en', 'greeting.hello', 'Hey there!');
manager.addAnswer('en', 'greeting.bye', 'Till next time, {{name}}!');
manager.train();
const result1 = await manager.process('en', 'Hello my name is Thierry', context);
console.log(result1);
console.log(context);
const result2 = await manager.process('en', 'I have to go', context);
console.log(result2);
})();
The context doesn't contain a name variable...
I opened an issue directly on the github project page but the answer suggested to add this:
manager.addNamedEntityText(
'name',
'John',
['en'],
['john', 'John'],
);
But it's not exactly what I want because a variable name is added only if there is either "John" or "john" for the name in the sentence.
I also saw in this issue https://github.com/axa-group/nlp.js/issues/133#issuecomment-503223171 what there are restrictions on variable names.
Thanks for your help!
Thierry

Is an error in the documentation.
This can be implemented, but the problem is the "limitations" or the misanderstanding of how it will work.
I mean, it can be implemented that way: when training, it can detect entities present in the utterances that are not in the NER, then detect if the entities are the last part of a sentence, and then build a new Trim entity based on the words before the entity. So given "hello my name is %name%" it can resolve that given this intent, it should try to search the word "is" and the things after can be the entity.
But now then are problems, and are the reasons why is not implemented:
- Someone can write "Hello my name is John and I want a beer", then the chatbot can extract the entity and think that the name is "John and I want a beer".
- If to avoid that you think on extracting only one word, then "Hello my name is Paul Henri" will think that the name is "Paul".
- If it's searching by the word "is" then "Hello today is a wonderfull day and my name is John" will think that the name is "a wonderfull day and my name is John".
So to achieve what you want I recommend you to take a look here: https://github.com/axa-group/nlp.js/blob/master/docs/ner-manager.md#trim-named-entities
This tell you how to implement trim named entities based on the position to another words.
By the way, I'll fix the error in the docs.

Related

How do I query the vimeo api for a specific video title?

Hi I'm querying for a specific video by title - and at the moment I get mixed results.
my videos are all named with a consecutive number at the end ie ANDNOW2022_00112, ANDNOW2022_00113 etc
When I search /videos/?fields=uri,name&query=ANDNOW2022_00112 I get all of the videos returned
I've also tried the query_fields using
/me/videos?query_fields=title&sort=alphabetical&query=ANDNOW2022_00112
I just want the one I've searched for - or a no results returned.
At the moment I get all of the videos with AN2022 in the title/name. Now 'usually' the one I searched for is at the top of the list but not everytime.
Any tips appreciated.
Okay I'm not going mad :)
This is from Vimeo and is here for those with the same issue - basically to get t to work you need to understand that:
After speaking with our engineers, the current search capability are not "Exact" search.
When adding numbers or underscores the search is split into parts so "ANDNOW2022_00112" is transforming the query into the parts "andnow2022", "andnow", "2022", and "00112". So this is why your seeing these results. Our engineering team are in the process of improving the search capabilities and hope to provide a release in the near future.
Which means for now I'll have to rename my files.
Preface:
Vimeo does not currently offer an API endpoint for exact title search — but even if it did — it's possible to upload multiple videos and assign them identical titles. There's no way to use the API to positively identify a video by title — this is why every uploaded video is assigned a unique ID.
Solution:
Because the API returns data which includes an array of video objects, you can solve this problem in the same way you'd solve any similar problem in JavaScript where you have to find an element in an array: Array.prototype.find()
Here's how you can apply it to your problem:
Query the API using the parameters you described in your question.
You might also be interested in using the sort and direction parameters for greater control over a deterministic sort order.
Find the first item in the returned array of video objects that match your expected text exactly, and return it (or undefined if it doesn't exist)
Here's a code example with some static data from the API that was used to search for the video Mercedes Benz from the user egarage — note that I've omitted quite a few (irrelevant) fields from the response in order to keep the example small:
// Mocking fetch for this example:
function fetch (_requestInfo, _init) {
const staticJson = `{"total":2,"page":1,"per_page":25,"paging":{"next":null,"previous":null,"first":"/users/egarage/videos?query_fields=title&query=Mercedes%20Benz&sort=alphabetical&direction=asc&page=1","last":"/users/egarage/videos?query_fields=title&query=Mercedes%20Benz&sort=alphabetical&direction=asc&page=1"},"data":[{"uri":"/videos/61310450","name":"50th Anniversary of the Pagoda SL -- Mercedes-Benz Classic Vehicles","description":"Penned by designer Paul Bracq, the W113 SL had big shoes to fill: it had the incredible task of succeeding the original and instantly iconic 300 SL Gullwing. But you can't copy a legend, so Bracq designed one of his own. Straight lines replaced curves and a low-slung roof was replaced by a high top design that gave the car its nickname: the Pagoda.\\n\\nMUSIC: Developer Over Time","type":"video","link":"https://vimeo.com/61310450"},{"uri":"/videos/55837293","name":"Mercedes Benz","description":"To celebrate Mercedes Benz 125th birthday, the 2011 Pebble Beach Concours d’Elegance showcased the models that trace the lineage to Benz and Daimler —particularly Mercedes-Benz. This tribute chronicled early racing greats, coachbuilt classics, and preservation cars. Produced in association with DriveCulture.","type":"video","link":"https://vimeo.com/55837293"}]}`;
return Promise.resolve(new Response(staticJson));
}
async function fetchVideoByTitle (token, userId, videoTitle) {
const url = new URL(`https://api.vimeo.com/users/${userId}/videos`);
url.searchParams.set("query_fields", "title");
url.searchParams.set("query", videoTitle);
url.searchParams.set("sort", "alphabetical");
url.searchParams.set("direction", "asc");
const headers = new Headers([
["Authorization", `Bearer ${token}`],
]);
const response = await fetch(url.href, {headers});
const parsedJson = await response.json();
// Find the video that matches (if it exists):
const maybeFirstVideoObj = parsedJson.data.find(video => video.name === videoTitle);
return maybeFirstVideoObj;
}
async function main () {
const video = await fetchVideoByTitle(
"YOU_ACTUAL_TOKEN",
"egarage",
"Mercedes Benz",
);
console.log(video); // {name: "Mercedes Benz", link: "https://vimeo.com/55837293", ...}
}
main();

How to avoid caching of input in JavaScript function in bixby

JavaScript function inputs seem to be caching the arguments if the value is being used earlier.
Example
Use cases
Find students in schools with a name or with their ages or both together.
utterance 1
find students in the school with the name George.
then in it will invoke the function with (name as George and age as null)
utterance 2
find students in the school with ages 10.
then in it will invoke the function with (name as George and age as 10)
How to avoid caching of the variable name as George in the second case?
Solved! issue by adding
features {
transient
}
example of text concept
text (name) {
description (name of the person)
features{
transient
}
}
For DateTimeExpression created CustomDateTimeExpression with role-of viv.time.DateTimeExpression and added transient to features works.
structure (CustomDateTimeExpression) {
role-of (viv.time.DateTimeExpression)
description (wrapper for DateTimeExpression)
features {
transient
}
}
links: https://bixbydevelopers.com/dev/docs/reference/type/text.features

How to use a parameter from a follow-up intent within the Inline Editor in DialogFlow

I'm using the DialogFlow Inline Editor and I need to be able to provide different responses based on the specific values of a parameter within a follow up intent.
Via the UI, I am able to build a follow up intent and refer to an entity in the previous intent, but I can't set up logic based on specific values of that entity, which is why i need to be able to do this via the Online Editor.
Can someone show me an example of how to use an entity within a follow up intent via the Online Editor?
So far, I am able to output a context within a function (function 1 below), but i am unable to use an entity that was provided by the user within function 1 in a function 2 that uses a follow-up intent.
//function 1:
function fruit(agent) {
const fruit = agent.parameters.FruitValue
agent.add(`what fruit do you like`)
agent.setContext({ name: 'cherries-followup', lifespan: 2, parameters: {FruitValue: fruit}})}
//function 2:
function details(agent) {
const context = agent.getContext('cherries-followup');
const fruit = context.parameters.FruitValue;
agent.add(`Good to know you like ${fruit}!`);
}
intentMap.set('CherriesIntent', fruit);
intentMap.set('CherriesDetailIntent', details);
Picture of what I did via the UI which i would like to replicate in the Online Editor
Update (Solved):
I have now rewritten the code to be in line with the DF post (so that it is easier to debug: https://dialogflow.com/docs/getting-started/integrate-services)
function languageHandler(agent) {
const language_spoken = agent.parameters.language;
{agent.add(`Wow! Where did you learn ${language_spoken} and for how long?`);
agent.setContext({
name: 'languages-followup',
lifespan: 2,
parameters:{languages: language_spoken}
});
}
}
function languageCustomHandler(agent) {
const context = agent.getContext('languages-followup');
//const allContexts = agent.contexts; // [{ name: 'languages-followup', ...}]
const language_spoken = context.parameters.language;
const country = agent.parameters.country;
const duration = agent.parameters.duration;
agent.add(`Wow! So cool you learned ${language_spoken} in ${country} for about ${duration.amount} ${duration.unit}!`);
}
intentMap.set('Language', languageHandler);
intentMap.set('Language - custom', languageCustomHandler);
It works now, after making sure that the duration parameter value is either set to duration.original in the UI or after adding .amount and .unit to duration (otherwise you will get: "Wow! So cool you learned German in China for about [object Object]!" instead of "Wow! So cool you learned German in China for about 1 mo!
PARAMETER VALUE
country China
duration {"amount":1,"unit":"mo"}

dynamic prompt choices in bot-framework v4 (node.js)

I've got a prompt for an SMS bot in which the user can make multiple choices. I'm looking for a pattern for a ChoicePrompt that allows me to do this:
show multiple selections
then after the user selects and answer, re-prompt them to answer again
Remove their previous choice(s) and add an "exit" option to move on
Automatically end the step if they've selected everything.
I'd like to avoid creating a new prompt w/switch cases for each answer tier, as this pattern needs to be implemented in a lot of places...
Example:
bot: User, what do you do to relax?
Exercise
Read a book
Nothing
user: Exercise
bot: Exercise, cool. What else?
Read a book
Nothing else
user: Read a book
bot: OK, you've done everything so we're moving on!
The botframework don't have a ListPrompt that I can see, at least for v4. They do however, have Suggested Actions you can use for this!!! The Botbuilder-Samples repo has a Suggested Action sample that shows a list of three colors:
async onTurn(turnContext) {
// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types.
if (turnContext.activity.type === ActivityTypes.Message) {
const text = turnContext.activity.text;
// Create an array with the valid color options.
const validColors = ['Red', 'Blue', 'Yellow'];
// If the `text` is in the Array, a valid color was selected and send agreement.
if (validColors.includes(text)) {
await turnContext.sendActivity(`I agree, ${ text } is the best color.`);
} else {
await turnContext.sendActivity('Please select a color.');
}
// After the bot has responded send the suggested actions.
await this.sendSuggestedActions(turnContext);
} else if (turnContext.activity.type === ActivityTypes.ConversationUpdate) {
await this.sendWelcomeMessage(turnContext);
} else {
await turnContext.sendActivity(`[${ turnContext.activity.type } event detected.]`);
}
}
An option would be to programatically create the array (in the example above, it's "const validColors") and if the reply is in the list of colors, recreate the array however you want without the chosen option.

How to specify the class selector in web scraping using nodejs

Am trying to implement scraping using nodejs. Am sending request to a particular url and when i get the response, using the response am storing each products in a page into an array. For each product am trying to display the product details like product name, price and discount etc. Am doing this by the following code.
var $products = $body.find('.fashion-item');
$products.each(function (i, item) {
var $name = ($(item).find('.info .title').text(),
$price=$(item).find('span.price.regular').text().substr(6),
$discount=$(item).find('span.price.percentoff').text().slice(0,2);
self.items[i] = {
title: $name,
price: $price,
discount: $discount,
};
});
console.log(self.items);
It is working fine. If the class name is like 'fashion-item' or 'fashion-item-first' all this works fine. But if the class name contains the space in between the word, am not getting any products stored in array ($products) i.e. array length of $products is zero. My question is how to do the same thing if class name like this 'fashion-item first'. I tried very much, but i didn't get any idea. Please help me.
Class names cannot have spaces. In your example, 'fashion-item first', are two classes assigned to an element, which can be selected by either .fashion-item or .first selectors.
If you want item who have both info and title classe select them with this :
$(item).find('.info.title')
If you want item one of these classes, use this
$(item).find('.info,.title)

Resources