I'm having an issue with sending a message to a Discord channel from a fetch.
I'm fetching Time Series Data from a REST API. I then want to send this data if a Discord user types a command.
Code:
require("dotenv").config();
const fetch = require("node-fetch");
const { Client } = require("discord.js");
const PREFIX = "!";
const getPrice = async (ticker) => {
let result = "test";
const request = await fetch(
`https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=${ticker}&interval=5min&apikey=${process.env.API_KEY}`
);
const response = await request.json();
const data = await response;
const obj = await data["Time Series (5min)"];
result = obj[Object.keys(obj)[0]];
return result;
};
client.on("message", (message) => {
if (message.author.bot) return;
if (message.content.startsWith(PREFIX)) {
const [command, ...args] = message.content
.trim()
.substring(PREFIX.length)
.split(/\s+/);
const result = getPrice(`${command.toUpperCase()}`);
message.channel.send(result);
}
});
I get the following error:
UnhandledPromiseRejectionWarning: DiscordAPIError: Cannot send an empty message
If you take a look at the following code and replace it with a console.log - it works. E.g
Original
message.channel.send(result);
Replace with
console.log(result)
Then it works:
{
'1. open': '119.0200',
'2. high': '119.0200',
'3. low': '119.0200',
'4. close': '119.0200',
'5. volume': '302'
}
I suspect it has something to do with Promises, maybe my understanding isn't up to scratch but I've read docs over and over and cannot make sense of it.
I believe the reason that result is empty is because by the time that method is called in the stack, the fetch has not come back with the data, and it attempts to send empty data.
How can I ensure that message.channel.send waits for my fetch to finish before being called?
getPrice is an async function that returns a promise. You need to await the result before you can send it:
client.on("message", async (message) => {
if (message.author.bot) return;
if (message.content.startsWith(PREFIX)) {
const [command, ...args] = message.content
.trim()
.substring(PREFIX.length)
.split(/\s+/);
const result = await getPrice(`${command.toUpperCase()}`);
message.channel.send(result);
}
});
Related
I'm trying to build telegram bot to parse page on use request. My parsing code works fine inside one async function, but completeky falls on its face if I try to put it inside another async function.
Here is the relevant code I have:
const puppeteer = require('puppeteer');
const fs = require('fs/promises');
const { Console } = require('console');
async function start(){
async function searcher(input) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
const url = ; //here is a long url combining logic, that works fine
await page.goto(url);
const currentUrl = requestPage.url();
console.log(currentUrl); //returns nothing.
//here is some long parsing logic
await browser.close();
return combinedResult;
}
//here is a bot code
const { Telegraf } = require('telegraf');
const bot = new Telegraf('my bot ID');
bot.command('start', ctx => {
console.log(ctx.from);
bot.telegram.sendMessage(ctx.chat.id, 'Greatings message', {});
bot.telegram.sendMessage(ctx.chat.id, 'request prompt ', {});
})
bot.on('text', (ctx) => {
console.log(ctx.message.text);
const queryOutput = searcher(ctx.message.text);
bot.telegram.sendMessage(ctx.chat.id, queryOutput, {});
});
bot.launch()
}
start();
Here is an error message:
/Users/a.rassanov/Desktop/Fetch/node_modules/puppeteer/lib/cjs/puppeteer/common/Connection.js:218
return Promise.reject(new Error(`Protocol error (${method}): Session closed. Most likely the ${this._targetType} has been closed.`));
^
Error: Protocol error (Page.navigate): Session closed. Most likely the page has been closed.
I'm very new to this, and your help is really appriciated.
I’m building a Discord bot using the Discord.JS module, and using NodeJS. I’m trying to add a simple crypto-price feature to my bot.
For now, I’m using the following code:
const unirest = require("unirest");
const req = unirest("GET", "https://coinranking1.p.rapidapi.com/coin/Qwsogvtv82FCd/price");
req.query({
"referenceCurrencyUuid": "yhjMzLPhuIDl"
});
req.headers({
"X-RapidAPI-Host": "coinranking1.p.rapidapi.com",
"X-RapidAPI-Key": "X",
"useQueryString": true
});
req.end(function (res) {
if (res.error) throw new Error(res.error);
console.log(res.body);
});
So basically, you have to provide the UUID of the desired crypto coin to request information, but I want my users to be able to do (for example) !price bitcoin or !price btc, but this requires the command to be like !price Qwsogvtv82FCd.
How do I resolve this issue?
If you check the API documentation, you can see that instead of using the coin price endpoint, you could use the search suggestion (https://coinranking1.p.rapidapi.com/search-suggestions), where you can search for a coin by its name or symbol. It returns an object like the one below. If you check the objects in data.coins, they have keys like uuid, name, symbol, and price:
{
"status":"success",
"data":{
"coins":[
{
"uuid":"Qwsogvtv82FCd",
"iconUrl":"https://cdn.coinranking.com/gNsKAuE-W/bitcoin_btc.svg",
"name":"Bitcoin",
"symbol":"BTC",
"price":"65955.43592725793773050345"
},
{...}
],
"exchanges":[
{...},
{...}
],
"markets":[...]
}
}
Your current code doesn't really do anything and it doesn't even have discord.js code. Here is a sample code with some explanation:
const { Client, Intents } = require('discord.js');
// I'm using node-fetch instead of unirest
// make sure you install it using npm i node-fetch
const fetch = require('node-fetch');
const RAPID_API_KEY = 'YOUR RAPID API KEY';
const TOKEN = 'YOUR DISCORD API TOKEN';
const client = new Client({
intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES],
});
const prefix = '!';
client.on('messageCreate', async (message) => {
if (message.author.bot || !message.content.startsWith(prefix)) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
if (command !== 'price') return;
if (!args[0]) return message.reply('Please provide a coin!');
try {
// get the search query
let query = args[0].toLowerCase();
// call the API
let coins = await searchCoin(query);
// if there is no search result, or something went wrong, exit w/ a message
if (!coins || coins.length === 0)
return message.reply(`No result for \`"${query}"\``);
// check the first result only
let coin = coins[0];
// if there is an exact match, send the price returned from the API
if (
coin.name.toLowerCase() === query ||
coin.symbol.toLowerCase() === query
)
return message.reply(
`The current price of **${coin.name} (${coin.symbol})** is **${coin.price} USD**`,
);
// if there is no exact match, just send the coin name and symbol in a message
message.reply(
`No exact result found. Did you mean **${coin.name} (${coin.symbol})**?`,
);
} catch (err) {
console.error(err);
message.reply('Oops, there was an error. Please try again later.');
}
});
client.once('ready', () => {
console.log('Bot is connected...');
});
client.login(TOKEN);
async function searchCoin(query) {
const url = `https://coinranking1.p.rapidapi.com/search-suggestions?query=${query}`;
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Host': 'coinranking1.p.rapidapi.com',
'X-RapidAPI-Key': RAPID_API_KEY,
},
};
try {
const response = await fetch(url, options);
const json = await response.json();
return json.status === 'success' ? json.data?.coins : null;
} catch (err) {
console.error(err);
return null;
}
}
And here is the result:
I'm creating a telegram bot. I want to integrate nlp.js to have a QnA.
At the moment I have this code:
#!/usr/bin/env node
const TelegramBot = require('node-telegram-bot-api');
const process = require('process');
const path = require('path');
const { dockStart } = require('#nlpjs/basic');
const axios = require('axios').default;
//const qnaFile = path.dirname()
let chatId;
let currentUser;
let incomingMessage;
let response;
let dock;
let nlp;
// replace the value below with the Telegram token you receive from #BotFather
const token = process.env.TELEGRAM_BOT_TOKEN || '5252802474:AA';
// Create a bot that uses 'polling' to fetch new updates
const bot = new TelegramBot(token, {polling: true});
bot.onText(/\/echo(.+)/, async (msg, match) => {
// 'msg' is the received Message from Telegram
// 'match' is the result of executing the regexp above on the text content
// of the message
//const chatId = msg.chat.id;
console.log(`CONSOLE LOG onText: \n ${match, msg}`);
});
bot.on('message', async (msg) => {
chatId = msg.chat.id;
currentUser = msg.from.first_name;
incomingMessage = msg.text;
dock = await dockStart();
const nlp = await dock.get('nlp');
await nlp.train();
response = await nlp.process('en', incomingMessage);
// Listen for any kind of message. There are different kinds of messages.
console.log(response);
console.log(msg);
// send a message to the chat acknowledging receipt of their message
await bot.sendMessage(chatId, `${response.answer}`);
});
How I can add new intents and utterances by using the user input incoming messages? From the documentation of the libary I don't see any reference about dynamically updating the corpus file?
So you may have seen this question type somewhere else. but the thing here is I tried all of the things we need to do according to docs and saw other posts with similar errors but still my error is not fixed. So I use keyv and use MongoDB atlas as storage adapter in this code, but the error is from MongoDB. Also, there is no error in the "keyv" because it works for other people, there is error in the MongoDB
So now I will list whatever I tried:
1. Made sure there is IP access
2. The userid and passcode are correct
3. The MongoDB atlas is running
4. Read the docs and code multiple times
5. If u think adding the +srv with the code will fix the error, it won't, it doesn't work with keyql idk why also it is not present in many codes, I already tried it
So this is the code
const { Client, Intents, MessageEmbed, Collection } = require('discord.js');
let client = new Client({ intents: [Intents.FLAGS.GUILDS,Intents.FLAGS.GUILD_MESSAGES] });
const dotenv = require('dotenv');
const Keyv = require('keyv');
const keyv = new Keyv('mongodb://Discord:password#cluster0.auifa.mongodb.net/Cluster0');
dotenv.config();
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.on('messageCreate', async (msg) => {
if (msg.author.bot) return;
let number = msg.content.split(' ')[1];
if (msg.content === '!ping') {
msg.channel.send('ping!')
}
// Use like const prefix = await getGuildPrefix(); `
const getGuildPrefix = async () => {
const prefixMap = await keyv.get('prefix');
return prefixMap ?. [msg.guild.id] || "!"
}
// Sets the prefix to the current guild.
const setGuildPrefix = async (prefix) => {
let prefixMap = await keyv.get('prefix');
if (!prefixMap)
{
prefixMap = "!";
}
prefixMap[msg.guild.id] = prefix;
await keyv.set('prefix', `${prefixMap}`);
}
let prefix = await getGuildPrefix();
// Get prefix command.
if ((msg.content === `${process.env.prefix}prefix`) || (msg.content === `${prefix}prefix`)) {
msg.channel.send(`Your server prefix is ${prefix}`)
}
// Change prefix command
const commandPrefix = await getGuildPrefix();
if ((msg.content.startsWith(`${process.env.prefix}setprefix`)) || (msg.content.startsWith(`${commandPrefix}setprefix`))) {
const newPrefix = number;
if (newPrefix.length === 0) {
msg.channel.send(`Please enter a valid prefix`);
}
await setGuildPrefix(newPrefix)
msg.channel.send(`Your server prefix is now '${newPrefix}'`);
}
})
client.login(process.env.token);
And this is the error message
Keyv connection error: MongoServerSelectionError: getaddrinfo ENOTFOUND cluster0.auifa.mongodb.net
at Timeout._onTimeout (D:\javascript\node_modules\mongojs\node_modules\mongodb\lib\core\sdam\topology.js:438:30)
at listOnTimeout (node:internal/timers:557:17)
at processTimers (node:internal/timers:500:7) {
reason: TopologyDescription
Connection string does not look like an Atlas one.
It has to be something like: mongodb+srv://<username>:<password>#cluster0.auifa.mongodb.net/YOUR-DB
Login to your Atlas account then:
Go to Databases page
Click on Connect button
Choose "Connect your application"
Copy your connection string
Docs about Mongo Atlas connection: https://docs.atlas.mongodb.com/connect-to-cluster/#connect-to-a-cluster
I have a suggest command and I'm trying to make it so that when i react with emoji "x" message get's deleted. Can someone help me?
owner.send(embed).then(m => {
m.react("✅")
m.react('❌')
})
To listen react change on message is sent you need to using createReactionCollector() guide here
This code is what you are looking for
Note: Your exec or run function must be async function
const newMsg = await owner.send(embed);
await newMsg.react('❌');
const filter = (reaction, user) => {
return user.id === msg.author.id; // Note msg is start commands message
};
let collector = await newMsg.createReactionCollector(filter, {
time: 30000,
});
collector.on('collect', async (r) => {
if (r.emoji.name ==='❌') {
collector.stop('delete');
await newMsg.delete();
}
});