How do I implement NodeJS "Did you mean" feature? - node.js

How can I implement a "Did you mean" feature in NodeJS? I searched the internet and found a tutorial that uses a webserver but I will be using this for a Discord bot, so I can't really use tutorials that involve web servers, etc.
For example:
User enters command: restrat
Actual command: restart
Bot Message: Command not found, did you mean "restart"?
Is this possible using NodeJS? If so, may I know how I can implement this?
Any help will be greatly appreciated!
Thanks.

Whether in NodeJS or the browser, some code is needed to find a command that most closely resembles the text entered by the user.
This code uses the Levenshtein distance calculation to return the closest match.
const jsLevenshtein = require("js-levenshtein");
function closestCommand (userText, commands) {
let minDistance = Infinity;
return commands.reduce((closest, cmd) => {
const cmdDistance = jsLevenshtein(userText, cmd);
if (cmdDistance < minDistance) {
minDistance = cmdDistance;
return cmd;
}
return closest;
}, '');
}
const myCommands = ['quit', 'login', 'logout', 'restart', 'refresh'];
const userCommand = 'restrat';
console.log(`closest command is '${closestCommand(userCommand, myCommands)}'`);
// closest command is 'restart'
Working code in RunKit.
It should be straightforward to add this to a NodeJS app.

Related

How can I run a Go WASM program using Node.js?

I created a test WASM program using Go. In the program's main, it adds an API to the "global" and waits on a channel to avoid from exiting. It is similar to the typical hello-world Go WASM that you can find anywhere in the internet.
My test WASM program works well in Browsers, however, I hope to run it and call the API using Node.js. If it is possible, I will create some automation tests based on it.
I tried many ways but I just couldn't get it work with Node.js. The problem is that, in Node.js, the API cannot be found in the "global". How can I run a GO WASM program (with an exported API) in Node.js?
(Let me know if you need more details)
Thanks!
More details:
--- On Go's side (pseudo code) ---
func main() {
fmt.Println("My Web Assembly")
js.Global().Set("myEcho", myEcho())
<-make(chan bool)
}
func myEcho() js.Func {
return js.FuncOf(func(this js.Value, apiArgs []js.Value) any {
for arg := range(apiArgs) {
fmt.Println(arg.String())
}
}
}
// build: GOOS=js GOARCH=wasm go build -o myecho.wasm path/to/the/package
--- On browser's side ---
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<p><pre style="font-family:courier;" id="my-canvas"/></p>
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("myecho.wasm"), go.importObject).then((result) => {
go.run(result.instance);
}).then(_ => {
// it also works without "window."
document.getElementById("my-canvas").innerHTML = window.myEcho("hello", "ahoj", "ciao");
})
})
</script>
</body>
</html>
--- On Node.js' side ---
globalThis.require = require;
globalThis.fs = require("fs");
globalThis.TextEncoder = require("util").TextEncoder;
globalThis.TextDecoder = require("util").TextDecoder;
globalThis.performance = {
now() {
const [sec, nsec] = process.hrtime();
return sec * 1000 + nsec / 1000000;
},
};
const crypto = require("crypto");
globalThis.crypto = {
getRandomValues(b) {
crypto.randomFillSync(b);
},
};
require("./wasm_exec");
const go = new Go();
go.argv = process.argv.slice(2);
go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
go.exit = process.exit;
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
go.run(result.instance);
}).then(_ => {
console.log(go.exports.myEcho("hello", "ahoj", "ciao"));
}).catch((err) => {
console.error(err);
process.exit(1);
});
This pseudo code represents 99% content of my real code (only removed business related details). The problem is that I not only need to run the wasm program (myecho.wasm) by Node.js, but I also need to call the "api" (myEcho), and I need to pass it parameters and receive the returned values, because I want to create automation tests for those "api"s. With Node.js, I can launch the test js scripts and validate the outputs all in the command line environment. The browser isn't a handy tool for this case.
Running the program by node wasm_exec.js myecho.wasm isn't enough for my case.
It would be nice to know more details about your environment and what are you actually trying to do. You can post the code itself, compilation commands, and versions for all the tools involved.
Trying to answer the question without these details:
Go WASM is very browser oriented, because the go compiler needs the glue js in wasm_exec.js to run. Nodejs shouldn't have a problem with that, and the following command should work:
node wasm_exec.js main.wasm
where wasm_exec.js is the glue code shipped with your go distribution, usually found at $(go env GOROOT)/misc/wasm/wasm_exec.js, and main.wasm is your compiled code. If this fails, you can post the output as well.
There is another way to compile go code to wasm that bypasses wasm_exec.js, and that way is by using the TinyGo compiler to output wasi-enabled code. You can try following their instructions to compile your code.
For example:
tinygo build -target=wasi -o main.wasm main.go
You can build for example a javascript file wasi.js:
"use strict";
const fs = require("fs");
const { WASI } = require("wasi");
const wasi = new WASI();
const importObject = { wasi_snapshot_preview1: wasi.wasiImport };
(async () => {
const wasm = await WebAssembly.compile(
fs.readFileSync("./main.wasm")
);
const instance = await WebAssembly.instantiate(wasm, importObject);
wasi.start(instance);
})();
Recent versions of node have experimental wasi support:
node --experimental-wasi-unstable-preview1 wasi.js
These are usually the things you would try with Go and WASM, but without further details, it is hard to tell what exactly is not working.
After some struggling, I noticed that the reason is simpler than I expected.
I couldn't get the exported API function in Node.js simply because the API has not been exported yet when I tried to call them!
When the wasm program is loaded and started, it runs in parallel with the caller program (the js running in Node).
WebAssembly.instantiate(...).then(...go.run(result.instance)...).then(/*HERE!*/)
The code at "HERE" is executed too early and the main() of the wasm program hasn't finished exporting the APIs yet.
When I changed the Node script to following, it worked:
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
go.run(result.instance);
}).then(_ => {
let retry = setInterval(function () {
if (typeof(go.exports.myEcho) != "function") {
return;
}
console.log(go.exports.myEcho("hello", "ahoj", "ciao"));
clearInterval(retry);
}, 500);
}).catch((err) => {
console.error(err);
process.exit(1);
});
(only includes the changed part)
I know it doesn't seem to be a perfect solution, but at least it proved my guess about the root cause to be true.
But... why it didn't happen in browser? sigh...

How Can I Replace https://google.com/test TO https://google.com? NodeJS

ok so basically I want to replace https://google.com/test to https://google.com without knowing the path of it...
here an example how I want it to looks like
meg1 = "Hi, i found a cool website https://google.com/test And https://discord.gg/test you should watch it"
function links() {
return meg1.replace(/https:\/\/[^/]+/g, function(url1) {
url = url1.replace(/$/,"")
//Start Here The Script
console.log(url)
})
}
links()
You should read up on Node's URL API(s). The documentation, it is your friend.
https://nodejs.org/dist/latest-v14.x/docs/api/url.html

Not receiving DistributedNotificationCenter in Swift Command Line Tool

I'm building a small app in node.js that uses execa to read print statements coming from a compiled Swift application. The idea is similar to Sindre Sorhus' (who else!?) do-not-disturb
Although I'm no Swift-programmer, I put together a pretty straightforward solution. The binary is compiled by running swift build --configuration=release from the CL to be used in a node-app. It also compiles fine (without the CLI-part) in a Swift playground from XCode and I can see the correct print statements coming in.
import Cocoa
var isLocked:Bool = false
DistributedNotificationCenter.default().addObserver(forName: .init("com.apple.isScreenLocked"), object: nil, queue: nil) { notification in
print("Screen is locked")
isLocked = true
}
DistributedNotificationCenter.default().addObserver(forName: .init("com.apple.isScreenUnlocked"), object: nil, queue: nil) { notification in
print("Screen is unlocked")
isLocked = false
}
struct CLI {
static var standardInput = FileHandle.standardInput
static var standardOutput = FileHandle.standardOutput
static var standardError = FileHandle.standardError
static let arguments = Array(CommandLine.arguments.dropFirst(1))
}
switch CLI.arguments.first {
case "status":
print(isLocked)
default:
print("Unsupported command", to: .standardError)
exit(1)
}
// Some other functions omitted for brevity
Now, when I run the code below from Node.js, everything seems to be working fine. However for some reason, the observer doesn't receive the notification.
'use strict';
const execa = require('execa');
const electronUtil = require('electron-util/node');
const binary = path.join(electronUtil.fixPathForAsarUnpack(__dirname), 'IsLockedOrNot');
setInterval(async () => {
const {stdout} = await execa(binary, ['status']);
console.log(stdout) // keeps logging false, also when screen is locked
}, 1000)
Does anyone have any idea WHY the notifications are not being received in this scenario? I tried various things, like explicitly disabling sleep mode shell.exec('sudo pmset -a disablesleep 1')and compiling the app with the --disable-sandbox flag. No luck however until know..
Use spawn from the base child_process library not execa, make sure you are following stdout, and the most important part for nodejs and swift is that you flush the buffer after every line. Otherwise you have to wait for the program to die before you receive any output. Use "import Darwin.C" and "fflush(stdout)" after every "print" where you want a 'newline'

Slack node js program running session shut down

Sorry to disturb. I am programming a Slack robot to reply user message by using the API
In the morning, it works totally okay. Then after I returned back from my office it just shut down and show me this error
Jiatongs-MacBook-Pro:news-bot jiatongli$ node index.js
Assertion failed: token must be defined
/Users/jiatongli/Desktop/news-bot/node_modules/vow/lib/vow.js:105
throw e;
^
Error: not_authed
at _api.then.fail (/Users/jiatongli/Desktop/news-bot/node_modules/slackbots/index.js:46:33)
at Array.<anonymous> (/Users/jiatongli/Desktop/news-bot/node_modules/vow/lib/vow.js:773:56)
at callFns (/Users/jiatongli/Desktop/news-bot/node_modules/vow/lib/vow.js:24:35)
at process._tickCallback (internal/process/next_tick.js:61:11)
Emitted 'error' event at:
at _api.then.fail (/Users/jiatongli/Desktop/news-bot/node_modules/slackbots/index.js:46:19)
at Array.<anonymous> (/Users/jiatongli/Desktop/news-bot/node_modules/vow/lib/vow.js:773:56)
at callFns (/Users/jiatongli/Desktop/news-bot/node_modules/vow/lib/vow.js:24:35)
at process._tickCallback (internal/process/next_tick.js:61:11)
Jiatongs-MacBook-Pro:news-bot jiatongli$
I personally have no idea what is going on because it seems like the program itself do not have bug. What i miss?
Here is the code in my index.js file:
var SlackBot = require("slackbots");
var request = require("request");
var NewsAPI = require("newsapi");
var unirest = require("unirest");
var API_KEY = process.env.API_KEY;
var Slack_API = process.env.Slack_API;
// create a bot
var bot = new SlackBot({
token: Slack_API,
name: "aloha-ai"
});
bot.on("message", msg => {
switch (msg.type) {
case "message":
// we only want to listen to direct messages that come from the user
if (msg.channel[0] === "D" && msg.bot_id === undefined) {
getRandomTechNews(postMessage, msg.user)
}
break
}
})
const postMessage = (message, user) => {
bot.postMessage(user, message, {
as_user: true
});
}
const getRandomTechNews = (callback, user) => {
unirest.get("https://nuzzel-news-v1.p.rapidapi.com/news?count=10&q=product")
.header("X-RapidAPI-Host", "nuzzel-news-v1.p.rapidapi.com")
.header("X-RapidAPI-Key", API_KEY)
.end(function (response) {
var newsJSON = response.body;
var news = "*Viral News* in product : \n\n\n\n";
for (i = 0; i < newsJSON.results.stories.length; i++) {
news += "_Excerpt:_ \n" + ">" + newsJSON.results.stories[i].excerpt + "\n"
news += "_Let's see the article!_ \n" + newsJSON.results.stories[i].url + "\n\n\n"
};
callback(news, user);
});
}
Your error message seems to indicate that your program is not authenticated with the Slack API: Error: not_authed
Since you are retrieving your API key and token from environment variables:
var API_KEY = process.env.API_KEY;
var Slack_API = process.env.Slack_API;
my guess is that you have started a new terminal session where you have not yet set that environment variable, or you are on a different computer where it is not set.
Before running your program, try exporting those variables from the command line:
export API_KEY=<my-api-key>
export Slack_API=<my-token>
If you have security concerns about your API keys showing up in your bash history you can do one of two things (these are examples of things that I do, but there are probably better, safer practices out there):
You can put an empty space before your command [space]export API_KEY=<my-api-key> instead of export API_KEY=<my-api-key>. This will make it so the command does not show up in your history.
You can put your export commands in a separate file called e.g., ~/.secrets and then run the command source ~/.secrets which will run your export commands.
Probably these will give you a sense of security rather than actual security though, since you can just echo the value of the environment variables, but I personally like taking one of these steps as an extra precaution.
i use this answer and can solve it.
Add a bot https://my.slack.com/services/new/bot and put the token
do you get token for your bot from above url:
did you set this ?

Unable to use getElementsByTagName("body")

Here's the code that results in an error each time I run it. My goal is to scrap the content from the URL, remove all HTML, and return it:
console.log("Fetching: " + inputData.tweeturl);
fetch(inputData.tweeturl)
.then(function(res) {
return res.text();
}).then(function(body) {
var rawText = body.getElementsByTagName("body")[0].innerHTML;
var output = { id: 100, rawHTML: body, rawText: rawText };
callback(null, output);
})
.catch(callback);
The problem is with var rawText = body.getElementsByTagName("body")[0].innerHTML;
The error I receive is:
Bargle. We hit an error creating a run javascript. :-( Error:
TypeError: body.getElementsByTagName is not a function eval (eval at (/var/task/index.js:52:23), :16:24) process._tickDomainCallback (node.js:407:9)
Unfortunately - there is no JS DOM API in the Code by Zapier triggers or actions (that is because it isn't run in a browser and doesn't have the necessary libraries installed to fake it).
You might look at Python and instead, and https://docs.python.org/2/library/xml.etree.elementtree.html. Decent question and answer is available here Python Requests package: Handling xml response. Good luck!
Any function not supported by Zapier will result in a TypeError. I needed to use a regular expression to achieve this.

Resources