I'm writing an application in NodeJS with the talkify library. The point of the application is to be a chatbot. Part of the functionality of the bot will be to take code (a closed source language) snippets, process them via a REST API, and return the result.
I've been able to create some trivial skills with talkify and it works fine. My main question is how would I implement my bot to interpret code snippets between single quotes in a given skill?
I'm not tied to talkify by any means. If someone has a suggestion that's better suited for my use case then I'm open to changing.
Code I have so far
// Core dependency
const talkify = require('talkify');
const Bot = talkify.Bot;
// Types dependencies
const BotTypes = talkify.BotTypes;
const Message = BotTypes.Message;
const SingleLineMessage = BotTypes.SingleLineMessage;
const MultiLineMessage = BotTypes.MultiLineMessage;
// Skills dependencies
const Skill = BotTypes.Skill;
// Training dependencies
const TrainingDocument = BotTypes.TrainingDocument;
const bot = new Bot();
bot.trainAll([
new TrainingDocument('how_many_endpoints', 'How many endpoints are there?'),
new TrainingDocument('how_many_endpoints', 'How many endpoints are there')
], function() {});
var howManyAction = function(context, request, response, next) {
response.message = new SingleLineMessage(function() {
var x = someWork();
return x;
});
next();
};
var howSkill = new Skill('how_skill', 'how_are_you', howAction);
bot.addSkill(howSkill);
var resolved = function(err, messages) {
if(err) return console.error(err);
return console.log(messages);
};
bot.resolve(123, TEXT_FROM_CHAT, resolved);
The above works when I ask how many endpoints I want but it won't work for more complex sentences, for example, I might want to say
"execute the following 'this is closed source stuff, I'll parse it server side'"
How would I match "execute the following" to a rule and get the string inside the single quotes as another variable? As I understand it the talkify library training documents must match the text it's parsing.
Example
Training document
execute the following
Text to match
execute the following <~ Match
execute the following 'foo bar' <~ No match
execute the following, <~ No match
You could pre-process the text to extract & remove any quoted phrase using a simple regex:
/\'[^\']*\'/g
See it running here: https://regex101.com/r/eUe7n3/1
hope it helps.
Related
I have been trying to complete this past paper but Im not sure if im on the right lines as to my solution and so wanted some help to see if I am on the right track or whether I need some guidance on getting there!
the question is as follows:
You have been contracted to write part of a RESTful web API for products on an e-commerce platform using Node.js. Another developer had previously been working on the project and had written the following tests using Mocha and Chai.
const expect = require('chai').expect;
const request = require('superagent');
const status = {OK:200,BADREQUEST:400};
const endpointURL =
'http://localhost:3000/api/v1/products/';
describe('Products APIT,function(){
/* Details of below data unnecessary to answer question */
const validId = /* ID of product already in database */;
const invalidId = /* Invalid product ID */;
const validProduct = {/* Valid product object*/};
it('valid GET requests',function(done){
request.get(apiRoot + validId).end(function(err,res){
expect(res.statusCode).to.equal(status.OK);
expect(res.body).to.have.property('price');
expect(res.body).to.have.property('quantity');
done();
});
});
it('invalid GET requests',function(done){
request.get(apiRoot + invalidId).end(function(err,res){
expect(res.statusCode).to.equal(status.BAD_REQUEST);
done();
});
});
it('valid PUT requests',function(done){
request.put(endpointURL + validId).send(validProduct)
.end(function(err,res){
expect(res.statusCode).to.equal(status.OK);
expect(res.body).to.deep.equal(validProduct);
request.get(apiRoot + validID).end(function(err,res){
expect(res.body.price).to.equal(validProduct.price);
expect(res.body.quantity)
.to.equal(validProduct.quantity);
done();
});
});
});
The tests also partially specify the behaviour of the API when responding to a PUT request. It should be possible to update an existing product to take a new (valid) value by making a PUT request to the path /api/vl/products/ followed by the product ID (e.g. /api/vl/products/42 for the product with ID 42). The response to a successful update should have status code 400 (OK) and the body of the response should contain the updated product. Updating the product should not change its ID.
Below is a partial implementation of the API using the express framework
var express = require('express');
var app = express();
var products = require('./lib/products');
app.getC/api/v1/products/:idP,function(req,res,next){
const id = req.params._id;
/*i) Complete for question i) here */
} ) ;
app.putC/api/v1/products/:idP,function(req,res,next){
const id = req.params._id;
/*ii) Complete for question ii) here */
} ) ;
var port = 3000;
app.listen(port,function(){
console.log('Listening on port ' + port);
});
where the products variable contains a data layer with the following methods:
Method Signature
Description
Result
read(id,callback)
reads product with
Product
specified id.
with
specified id
---------------------------
--------------------
------------
update(id,product,callback)
updates product with
updated
specified id to have
product.
value of parameter
product.
In both of these cases, callback will be a function to be called after the database operation has completed (successfully or unsuccessfully) with two arguments. The first argument will be an error object (null if and only if the operation has completed without errors). The second argument will be a result object containing the result of a successfully completed operation as described in the table above.
i) Complete the code above such that the API responds to GET requests as specified in the tests.
ii) Complete the code above such that the API responds to PUT requests as specified in the tests.
I have placed my attempt at question i) here below:
product.read(id,function(err,res)){
if(res.status(status.OK)
return res.sendStatus(status.OK);
return res.body('price' && 'quantity');
if(res.status(status.BAD_REQUEST))
return res.sendStatus(status.BAD_REQUEST);
}
but for ii) im afraid my brain just literally CRASHES, im new to node.js and js so please dumb down the explanation as much as you can for me!! Thank you i very much will appreciate all help since i am a beginner and im finding it hard to wrap my head around this question! Lecture notes do not seem to help much :((
I have a lambda (nodeJs) that reads a file (.ref) in a S3 bucket and publishes its content in a topic inside the AWS IoT-Core broker.
The file contains something like this (50 lines):
model:type
aa;tp1
bb;tpz
cc;tpf
dd;tp1
The code must remove the first line and retrieve the remains 50 lines. This is the code
async function gerRef (BUCKET_NAME) {
const refFile = version + '/file.ref'
const ref = await getObject(FIRMWARE_BUCKET_NAME, refFile)
//Get the file content
const refString = ref.toString('utf8')
//Slip by each line
let arrRef = refString.split('\n')
//Remove the file header
arrRef.shift()
//join the lines
let refString = arrRef.join('\n')
return refString
}
Then I am getting this result and publishing in the AWS IoT-Core Broker like this:
const publishMqtt = (params) =>
new Promise((resolve, reject) =>
iotdata.publish(params, (err, res) => resolve(res)))
...
let refData = await gerRef (bucket1)
let JsonPayload = {
"attr1":"val1",
"machineConfig":`${refData}` //Maybe here is the issue
}
let params = {
topic: 'test/1',
payload: JSON.stringify(JsonPayload) //Maybe here is the issue
qos: '0'
};
await publishMqtt(params)
...
Then it publishes in the broker.
The issue is that the content is being published without a real new line. When I see in the broker I get the follow JSON:
{
"attr1":"val1",
"machineConfig":"aa;tp1\nbb;tpz\ncc;tpf\ndd;tp1"
}
The machine that receives this message is expecting a real new line, something like this:
{
"attr1":"val1",
"machineConfig":"aa;tp1
bb;tpz
cc;tpf
dd;tp1"
}
If I just copy and paste this entire JSON in the AWS IoT-Core interface it will complain about the JSON parse but will publish as string and the machine will accept the data- because the new line is there:
In short, the main point here is that:
We can use the JSON.stringify(JsonPayload) - The broker will accept
I don't know how to stringfy and keep the actual new line
I have tried these solutions but none of then worked: s1, s2, s3
Any guess in how to achieve this?
What that machines is expecting is wrong. In JSON any newline data inside a value must be escaped, and \n in the string is the correct way to do it. This is the fault of the receiver's expectations.
A "real" newline would result in an invalid JSON document and most parsers will flat-out reject it.
On the receiving end JSON deserializer can deal with \n encoded strings. If your receiver requires newlines it's broken and needs repairing. If you can't repair it then you're committed to sending busted up, malformed JSON-ish data that's not actually JSON and your broker is fully justified in trashing it.
My question is simple but i can not find exact solution. All articles have gor below a line of code:
collection.findOne({hello:'world_no_safe'});
Above codes does work and returns to me undefined error.But it is existed. Anyway, My exact solution is above. Please help me and teach me how to use regex by searching inside of the json api. ı want to use %mysearch data% as a regex expression. ı want to make text search which is used all sentences in json.
For example : i have a json:
[{"data":"Andreas Kollegger explains what kinds of questions you can answer with a graph database. It's not only the big sites that "},{"data":"X explains what kinds of questions you can answer with a graph database. It's not only the big sites that "}]
if i use this expression: collection.findOne({hello:'%Andreas%'});
it has to return first data. Below a real sample from my project.
var mongo = require('mongodb');
var Server = mongo.Server;
var Db = mongo.Db;
var server = new Server('ds053479.mongolab.com', 53479, {auto_reconnect : true});
var db = new Db('orient', server);
db.open(function(err, client) {
client.authenticate('testname', 'fsfsff', function(err, success) {
var collection = db.collection('Models');
collection.insert({Name:'test1'});
// Fetch the document
collection.findOne({Name:'%world_no_safe%'});
});
According to the MongoDB Manual you can use the $regex operator:
collection.findOne({Name: { $regex: '.*world_no_safe.*' }});
Recently I had a idea for a Slack Bot that would filter what a user says. I.E User says (a bad word). PFBot would see that message and change the word to "##%$&" depending on how long the word is.
Now I am fairly new to this but I knew what needed to happen.
The bot would need to read the message.
The bot would compare that message to a list of bad words.
If the bot finds one then the message is filtered. (Turning the word into "##%$".
The new message with filtered words would be reposted as that user.
I started work on it but since I am new with the Slack API and NodeJS I hit a rode block and I have no clue on how to get it working.
My first specific problem is: I can't find a way for the Bot to read a new message posted in chat.
Here is my code: https://github.com/wiredbrother/Slack-PFBot
You will be interested in the Skills/hears.js file. That is where the magic happens. Or just look here >
var fs = require('fs');
var path = require('path');
var readStream = fs.createReadStream(path.join(__dirname,
'../profanity-filter') + '/swears.txt', 'utf8');
var data = '';
readStream.on('data', function(chunk) {
data += chunk;
}).on('end', function() {
console.log(data);
});
module.exports = function(controller) {
controller.hears(['^hello$'], 'direct_message,direct_mention', function(bot, message) {
bot.reply(message, "Hi there, you're on workspace: " + message.team)
});
controller.hears([data], 'direct_message,direct_mention', function(bot, message) {
var filter = require('../profanity-filter/lib/filter.js');
filter.setReplacementMethod('grawlix');
filter.setGrawlixChars(['!', '#', '#', '$', '%', '&']);
var thing = filter.clean(data);
bot.reply(message, "The bad word is now: " + thing)
});
};
I also found a utility online for NodeJS that filters words. That is in the Profanity-Filter folder.
You would be interested in Profanity-Filter/lib/filter.js.
I would love some guidance on this as a new coder.
Thank you for any advice you can give!
~ wiredbrother
Getting new messages
To get new messages you need to enable events for your bot. Once enables your bots will automatically receive every new message, which is send to a channel that your bot user is a member of.
I have never used botkit myself, but apparently you can check the documentation here (#6) for how to enable events for the botkit.
Removing profanity
To me knowledge is not possible, to change the message from another user. There is chat.udpate, which updates a messages. But that only works for your own messages.
Instead you could delete messages form other users with chat.delete, that contains profanity (and inform the user with a direct message about his transgression).
I have defined a dictionary here
var dict = {'English 101?': 'Room 205', 'English 102?': 'Room 309',
'Math 301': 'Room 705', 'Math 302': 'Room 704'};
I want the bot to reply "in Room 205" when the user ask "where is English 101".
I hardcoded it the following way:
var builder = require('botbuilder');
var helloBot = new builder.TextBot();
var dialog = new builder.CommandDialog();
dialog.matches('^Where is English 101?', builder.DialogAction.send('In Room 205'));
dialog.matches('^Where is English 102?', builder.DialogAction.send('In Room 309'));
dialog.matches('^Where is Math 301?', builder.DialogAction.send('In Room 705'));
dialog.matches('^Where is Math 302?', builder.DialogAction.send('In Room 704'));
dialog.onDefault(builder.DialogAction.send("I'm sorry. I didn't understand."));
helloBot.listenStdin();
Instead of hardcoding each question i want to pass some Regular Expression to the dialog.matches() functions first parameter and using it as a key the Bot should be able to get value from the dictionary and send back to the user
I tried the following, but it didn't work:
var str = ""
dialog.matches(str = ? , builder.DialogAction.send(dict[str.slice(9)]))
How could I be able to pass standard input to "str" and get the value from dictionary?
You want to use intents or trigger action matching.
For intents, first, initialize your intents:
var intents = new builder.IntentDialog();
Then pass the intent dialog to your bot:
bot.dialog('/', intents);
Then you can construct your matches using regular expressions:
intents.matches(/English 101/i, (session) => {
//
});
You'll want to make sure to have something to handle messages with no matches too:
intents.onDefault([
(session, args, next) => {
//Do something by default
}]);
Another way would be to use a triggerAction on a dialog (which also uses regular expressions):
bot.dialog("/English", (sess, args, next) => {
//Handle English 101
}).triggerAction({
matches: /English 101/i
});
With either, you'll be able to use standard JavaScript regular expressions to capture user data, and provide an appropriate dialog.
You can also look for just /where is/i, and then get the message from the session with session.message.text, and then parse that to get the target.
Ideally, your bot is well suited for using LUIS. You can create a single intent for the class location and a single entity for the class. Then you can train your LUIS app with various phrases, while replacing exact class names with the entity token. Then when LUIS hits your intent, the entity will be available, which you can use to access your dictionary and get the location. I wrote a post on this recently, if you're interested.
(Note: this is written in TypeScript, but you get the gist.)
According to the documentation here you should simply use Javascript regular expression format in your matches method.