handle response from telegram bot api - node.js

I am using this api: https://github.com/orzFly/node-telegram-bot
It should work like any other.
Now I want my Bot to have an option to update a string he keeps for some reason. so on "/update" the update function is called, where msg is a Message object (https://core.telegram.org/bots/api#message):
link = "something";
function update(msg) {
response = tg.sendMessage({
text: "Send a new URL, please",
chat_id: msg.chat.id,
reply_to_message_id: msg.message_id,
reply_markup: {
force_reply: true,
selective: true
}
});
console.log("response: " + response);
// on reply I want to update link
}
Now this bot asks me to provide a new string. The next answer in telegram is already an answer to the bots request, because of the force_reply.
How would I get this answer? 'response' here is a promise object and I don't know what to do with it.
After reading about Promises objects, I tried something like this:
response.then(function successHandler(result) {
tg.sendMessage({
text: "new URL is: I don't know",
chat_id: msg.chat.id
});
}, function failureHandler(error) {
colsole.log("error: " + error);
});
But it didn't work. In no way.
I just don't know where to get the reply Message object from.
I hope it's clear what I am asking. Otherwise let me know.

If I understood right, you're trying to get the next message from the user and treat it as the new string;
Problem is: response will contain the response from Telegram servers stating the result of the message you tried to send; it has nothing to do with the user's response to your message;
In order to do this, you need to control what was the last message your bot sent to a user and, based on that, decide how to handle that user's next message; it could look something like this:
link = "something";
states = {}
function update(msg) {
if (!states[msg.chat.id] || states[msg.chat.id] == 1) {
tg.sendMessage({
text: "Send a new URL, please",
chat_id: msg.chat.id,
reply_to_message_id: msg.message_id,
reply_markup: {
force_reply: true,
selective: true
}
}).then(() => {
states[msg.chat.id] = 2
console.log(`Asked a question to ${msg.chat.id}`);
});
} else {
link = msg.text;
tg.sendMessage({
text: `New URL is: ${link}`,
chat_id: msg.chat.id,
reply_to_message_id: msg.message_id
})
}
}

It looks like the result in the promise is the entire response from Telegram. So your result will be in result.result.text
The result variable will look like:
{
ok: true
result: {
message_id: x,
from: { ... }
chat: { ... }
date: x,
text: 'message'
}
}
This is unfortunate, I would have suggested the author only returns the result key.
var api = require('telegram-bot');
api = new api(<TOKEN>);
api.sendMessage({ chat_id: 0, text: 'test' }).then(function (result) {
console.log(result);
});
api.on('message', function (msg) {
console.log(msg); // <- will contain the reply
// msg.text
// msg.chat.id
// msg.from.id
});
api.start();

Related

Nojde Telegram API -- how do I use ForceReply?

Hi im new with this type of programming so im triying to do a bot, that allows me to create something like a poll but before that, i wanna know some information from the user (which I'll use later), so i triying to use forceReplay for that, but i dont know how to start to interacting with the user after that
bot.start((ctx) => {
const opts = {
reply_markup: JSON.stringify(
{
force_reply: true,
}
)};
bot.telegram.sendMessage(ctx.chat.id, 'Hi what is your name?', opts);
});
this is my initial code, so, what i need to do from this is wait for the user to write his name and then start a new question...
Note: im using telegraf to create my bot
This is the code I referenced from: Link
bot.onText(/\/start/, async(msg) => {
let listenerReply;
let contentMessage = await bot.sendMessage(msg.chat.id, "Type your name: ", {
"reply_markup": {
"force_reply": true
}
});
listenerReply = (async (replyHandler) => {
bot.removeReplyListener(listenerReply);
await bot.sendMessage(replyHandler.chat.id, `Ohh your name is ${replyHandler.text}`, {"reply_markup": {"force_reply": false}})
});
bot.onReplyToMessage(contentMessage.chat.id, contentMessage.message_id, listenerReply);
});
Hope it helps you

"TypeError: Cannot read property 'me' of undefined"

i'm making two commands for my discord.js v12 bot but it throws error "TypeError: Cannot read property 'me' of undefined" when the first command was used the first command's code:
function generateID() {
let ticketGen = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".split("");
let ticketStr = "";
for(let i = 0; i < 3; i++) {
ticketStr += ticketGen[Math.floor(Math.random() * ticketGen.length)];
}
return ticketStr;
}
const fsn = require("fs-nextra");
const colors = require("colors");
const Discord = require('discord.js');
module.exports = {
name: 'order',
description: 'Ordering something',
args: 'true',
usage: '<order desription>',
aliases: ['o'],
execute(message) {
const client = message.client; //<- Line added right here
let order = message.content.substring(7);
let channel = message.guild.channels.cache.get("746423099871985755");
let customer = message.author.id
fsn.readJSON("./blacklist.json").then((blacklistDB) => {
let entry = blacklistDB[message.guild.id];
// Checks is server is blacklisted or not.
if(entry === undefined) {
// Gets ticket ID.
const ticketID = generateID();
// Sends ticket information to tickets channel.
const exampleEmbed = new Discord.MessageEmbed()
.setColor('#FFFF33')
.setTitle(message.member.user.tag)
.setAuthor(`Order ID: ${ticketID}`)
.setDescription(order)
.setThumbnail(message.author.avatarURL())
.setTimestamp()
.setFooter(`From ${message.guild.name} (${message.guild.id})`);
channel.send(exampleEmbed);
// Sets ticket info.
fsn.readJSON("./orders.json").then(orderDB => {
// Set JSON information.
if (!orderDB[ticketID]) orderDB[ticketID] = {
"orderID": ticketID,
"userID": message.author.id,
"guildID": message.guild.id,
"channelID": message.channel.id,
"order": order,
"status": "Unclaimed",
"ticketChannelMessageID": "not set"
};
// Write JSON information.
fsn.writeJSON("./orders.json", orderDB, {
replacer: null,
spaces: 4
}).then(() => {
// Sends an embed to the customer.
message.channel.send("Your order has been sent and it will be delivered soon.")
// Logs in console.
console.log(colors.green(`${message.author.username} ordered "${order}" in ${message.guild.name} (${message.guild.id}) in ${message.channel.name} (${message.channel.id}).`));
}).catch((err) => {
if(err) {
message.reply(`There was a database error! Show the following message to a developer: \`\`\`${err}\`\`\``);
console.log(colors.red(`Error in order ${ticketID}: ${err}`));
}
});
});
}else {
message.reply("This server is currently blacklisted.");
}
});
}
};
At this part i think something is wrong with how it saves information?
// Sets ticket info.
fsn.readJSON("./orders.json").then(orderDB => {
// Set JSON information.
if (!orderDB[ticketID]) orderDB[ticketID] = {
"orderID": ticketID,
"userID": message.author.id,
"guildID": message.guild.id,
"channelID": message.channel.id,
"order": order,
"status": "Unclaimed",
"ticketChannelMessageID": "not set"
};
// Write JSON information.
fsn.writeJSON("./orders.json", orderDB, {
replacer: null,
spaces: 4
}).then(() => {
// Sends an embed to the customer.
message.channel.send("Your order has been sent and it will be delivered soon.")
the error happens when using the 2nd command which returns error "TypeError: Cannot read property 'me' of undefined" and i think it has to do with the first command
2nd command code:
if (order.status === "Ready") {
// Delete ticket from database.
delete orderDB[ticketID];
// Writes data to JSON.
fsn.writeJSON("./orders.json", orderDB, {
replacer: null,
spaces: 4
}).then(() => {
// If bot has create instant invite permission.
if(client.guilds.cache.get(order.guildID).me.hasPermission("CREATE_INSTANT_INVITE")) {
// Send message to cook.
client.channels.cache.get(order.channelID).send(`${client.users.cache.get(order.userID)}, Here is your taco that you ordered. Remember you can do \`.tip [Amount]\` to give us virtual tips, and \`.feedback [Feedback]\` to give us feedback on how we did. ${order.imageURL}`);
message.reply(`Order has been sent to ${client.guilds.cache.get(order.guildID).name}`);
}else {
// Bot delivers it's self.
client.channels.cache.get(order.channelID).send(`${client.users.cache.get(order.userID)}, Here is your taco that you ordered. Remember you can do \`.tip [Amount]\` to give us virtual tips, and \`.feedback [Feedback]\` to give us feedback on how we did. ${order.imageURL}`);
i have only included the part which i think has the error because order.guildid is undefined but how do i fix that?
As the error message explains, there is no property me of undefined, therefore the guild is undefined/not found. Check that the guild id you're using is a correct guild id and it is a string not a number. It could be worth putting a console.log(client.guilds.cache.get(order.guildID).name)); in there to help pin down the issue.

Coinbase transfer between accounts returns "Not found"

I'm trying to transfer BTC and BCH between accounts. Looking through the documentation I have found the following:
https://developers.coinbase.com/api/v2#transfer-money-between-accounts
First off I believe there is an error in their example, as the "currency" property is mandatory, it gives an error when not providing it.
But after adding the currency, every request I make returns with "Not found".
I'm using the node client, but I think the problem is higher up.
This is the request I'm doing:
const Client = require('coinbase').Client;
let client = new Client({'apiKey': 'xxxx', 'apiSecret': 'xxx'});
client.getAccounts({}, function(err, accounts) {
let btc_account = null;
let bch_account = null;
for(account of accounts) {
if(account.currency == "BTC") {
btc_account = account;
} else if(account.currency == "BCH") {
bch_account = account;
}
}
var options = {'to': bch_account.id, 'amount': btc_account.balance.amount, 'currency': "BTC"};
btc_account.transferMoney(options, function(err, tx) {
if(err) {
console.log("ERROR during transfer", err);
return
}
console.log(tx);
});
});
Doing this returns me with:
ERROR during transfer NotFound: Not found
After doing some debugging, I found it tries to do the request with the following options:
url: 'https://api.coinbase.com/v2/accounts/xxx/transactions'
body: '{"to":"xxx","amount":"0.00072256","currency":"BTC","type":"transfer"}'
(obfuscated the actual account.id's)
And the actual response from their API is:
{"errors":[{"id":"not_found","message":"Not found"}]}
Can anybody tell me what I'm doing wrong here?

Node.js - Combine IBM Watson Discovery and Conversation Services

I know this may seem complicated but I have spent a week and a half trying to do this and can not figure it out. Hopefully someone can point me in the right direction. Thank you so much!
I am working with IBM Watson and Node.js to create a conversation bot. I have created the bot and used one of IBM's example programs (Conversation-Simple) to make a website to interact with the bot. Everything with it works. I am now trying to use Watson's Discovery to search documents and answer a question with the query response. I have Discovery working where you can query it and have a Node.js program to query it.
I am now trying to connect the two! When Conversation is ready to query Discovery it will move to the intent called query.
It looks like this is where Watson gives the response and the variable of the response is currentText. I could be wrong but it looks like it is.
function buildMessageDomElements(newPayload, isUser) {
var textArray = isUser ? newPayload.input.text : newPayload.output.text;
if (Object.prototype.toString.call( textArray ) !== '[object Array]') {
textArray = [textArray];
}
var messageArray = [];
textArray.forEach(function(currentText) {
if (currentText) {
var messageJson = {
// <div class='segments'>
'tagName': 'div',
'classNames': ['segments'],
'children': [{
// <div class='from-user/from-watson latest'>
'tagName': 'div',
'classNames': [(isUser ? 'from-user' : 'from-watson'), 'latest', ((messageArray.length === 0) ? 'top' : 'sub')],
'children': [{
// <div class='message-inner'>
'tagName': 'div',
'classNames': ['message-inner'],
'children': [{
// <p>{messageText}</p>
'tagName': 'p',
'text': currentText
}]
}]
}]
};
messageArray.push(Common.buildDomElement(messageJson));
}
});
return messageArray;
}
When it goes to respond here (or if it is somewhere else) how can I check if the intent is query and if it is query Watson Discovery?
This is how I currently query Discovery:
url2 = 'fakeURL'
var request = require("request");
var myJSON = require("JSON");
global var body1;
function getMyBody(url, callback) {
request(
{
url: url,
auth: {'user': 'fakeUsername','pass': 'fakePassword'},
json: true
},
function (error, response, body) {
if (error || response.statusCode !== 200) {
return callback(error || {statusCode: response.statusCode});
}
else{
callback(null, JSON.parse(JSON.stringify(body.results)));
}
});
}
getMyBody(url2, function test8(err, body) {
body1 = body[0];
console.log(body1)
}
);
This code currently prints:
{ id: 'a3990d05fee380f8d0e9b99fa87188a7',
score: 1.0697575,
os: { OperatingSystem: 'Windows 10 Professional' },
price: '174.99',
text: 'Lenovo ThinkCentre M58 Business Desktop Computer, Intel Core 2 Duo 30 GHz Processor, 8GB RAM, 2TB Hard Drive, DVD, VGA, Display Port, RJ45, Windows 10 Professional (Certified Refurbished)',
url: 'https://www.amazon.com/Lenovo-ThinkCentre-M58-Professional-Refurbished/dp/B01M4MD9C1?SubscriptionId=AKIAJXXNMXU323WLP4SQ&tag=creek0a-20&linkCode=xm2&camp=2025&creative=165953&creativeASIN=B01M4MD9C1',
highlight: { text: [Array] } }
The response to the user I want to be the value of text and the value of URL.
This is the whole program from IBM https://github.com/watson-developer-cloud/conversation-simple
Like this example from IBM Developers: conversation-with-discovery. You can follow the same logic programming. But I really recommend check out the project and the video in the end of this answer.
Summary:
You can see in the workspace, the call for discovery is one action variable inside the Advanced JSON (Dialog node) called call_discovery.
"action":{"call_discovery: ""},
Basically, have one intent with the name out_of_scope, because if the user tells something that doesn't have any answer in the intents or some conditions in the Conversation, the call for discovery will happen and return one object with the documents according to the message from user.
Create one context variable inside the Conversation service:
{
"context": {
"callDiscovery": true
},
"output": {
"text": {
"values": [
"Wait for the response, I'll check out."
],
"selection_policy": "sequential"
}
}
}
After creates one context variable (Example: "callDiscovery": true) inside the Node in your Chatbot in the Advanced JSON for call the discovery service, you need to use code for identify if you arrived at the part where you need to make call for Discovery. Will be something like using the function updateMessage inside the conversation-simple example:
function updateMessage(input, response) {
var callDiscovery ;
if (!response.output) {
response.output = {};
//THE CONTEXT VARIABLE callDiscovery
} else if (response.context.callDiscovery === true){
//CREATE ONE NEW FUNCTION WITH YOUR CODE
getMyBody(url, callback, response); //response parameter for send the message
}
}
And, in your function getMyBody (THE FUNCTION that returns the prints in your Question[id, text, url, etc]), you need to send the message to the user, something like:
url2 = 'fakeURL'
var request = require("request");
var myJSON = require("JSON");
var body1;
function getMyBody(url, callback, response) {
request(
{
url: url,
auth: {'user': 'fakeUsername','pass': 'fakePassword'},
json: true
},
function (error, response, body) {
if (error || response.statusCode !== 200) {
return callback(error || {statusCode: response.statusCode});
}
else{
callback(null, JSON.parse(JSON.stringify(body.results)));
}
});
}
getMyBody(url2, function test8(err, body) {
body1 = body[0];
console.log(body1);
var sendMessage = ("I've find this results: "+ body1.text + "And you can see the url: "+ body1.url)// you said body1.text and body1.url
response.output.text[0] = sendMessage;
return res.json(response);
});
}
Note: According to the project conversation-simple, you need to use the response parameter for sending the message for the user, then, you need to set the parameter in your function that calls for Discovery, and to add the following code above in your function.
See the Official video by IBM Watson talking about this project and showing one good example to call the Discovery service and sends the result for the user.

telegram bot - keep questions and answers

My telegram bot is a dialog and it needs to keep the questions and the answers (like TriviaBot). What is the best (most efficient) method to do this? A database with the user id as key?
There is a lot of telegram bots, but where are examples with the source code to get ideas?
Your question is not really related to the telegram bot API. You are essentially asking: I have an application that has to keep an history of user interactions, how to do this (efficient)?
To answer that: you could use a database and insert an entry for each conversation using an unique identifier. Since telegram has a chat_id for each conversation, you could use that. Depending on what you are exactly trying to store, you should choose how to store it. (an entry for each answer, or for each conversation or ...)
If you program in python, you can use the python wrapper called python-telegram-bot to make things easier
Examples are here:
https://github.com/leandrotoledo/python-telegram-bot#examples
You can use force_reply and frequently ask whatever you want and store answers in any kind of database.
Please refer to its doc : refrence
and a simple answer on : force reply description
Well, I didn't found any example of force_reply, and had to ask an ai about it, honestly I dont know if it works, I just hope that it helps, here we go...
function survey(data) {
var Q1 = {
'chat_id': data.message.chat.id,
'text': 'how are you?'
}
var method = 'sendMessage';
var options = {
'method': 'post',
'contentType': 'application/json',
'payload': JSON.stringify(Q1)
}
var response = UrlFetchApp.fetch('https://api.telegram.org/bot' + telegramToken + '/' + method, options);
var text = data.message.text;
// Start loop
for (var i = 0; i < 3; i++) {
if (i == 0) {
// First iteration
if (text == "") {
// Get response from user
currentstep = '3';
var dataForceReply = {
method: "post",
payload: {
method: "sendMessage",
chat_id: String(data.message.chat.id),
text: "how are you?",
reply_markup: JSON.stringify({
"force_reply": true
})
}
};
UrlFetchApp.fetch(telegramAPIURL + "/", dataForceReply);
}
} else if (i == 1) {
// Second iteration
if (text != "") {
// Get response from user
// Store response in variable
var response1 = text;
var dataForceReply2 = {
method: "post",
payload: {
method: "sendMessage",
chat_id: String(data.message.chat.id),
text: "What do you think about this?",
reply_markup: JSON.stringify({
"force_reply": true
})
}
};
UrlFetchApp.fetch(telegramAPIURL + "/", dataForceReply2);
}
} else if (i == 2) {
// Third iteration
if (text != "") {
// Get response from user
// Store response in variable
var response2 = text;
var dataForceReply3 = {
method: "post",
payload: {
method: "sendMessage",
chat_id: String(data.message.chat.id),
text: "Do you have any suggestions?",
reply_markup: JSON.stringify({
"force_reply": true
})
}
};
UrlFetchApp.fetch(telegramAPIURL + "/", dataForceReply3);
}
} else {
// Get response from user
// Store response in variable
var response3 = text;
// Store all responses in variables
var response1 = response1;
var response2 = response2;
var response3 = response3;
}
}
}

Resources