telegram bot - keep questions and answers - bots

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;
}
}
}

Related

Stop loop when getting a specific text response from server

I'm working with some API server that communicates by XML.
I need to send, let's say: 20 identical POST requests.
I'm writing this in Node JS.
Easy.
BUT - since I'm going to multiply the process, and I want to avoid flooding the server (and getting kicked), I need to break the sending loop IF the (XML) response contains a specific text (a success signal): <code>555</code>, or actually just '555' (the text is wrapped with other XML phrases).
I tried to break the loop based on the success signal AND also tried "exporting" it outside the loop (Thinking it could be nice to address it in the loop's condition).
Guess it's easy but being a newbie, I had to call for some help :)
Attaching the relevant code (simplified).
Many thanks !
const fetch = require("node-fetch");
const url = "https://www.apitest12345.com/API/";
const headers = {
"LOGIN": "abcd",
"PASSWD": "12345"
}
const data = '<xml></xml>'
let i = 0;
do { // the loop
fetch(url, { method: 'POST', headers: headers, body: data})
.then((res) => {
return res.text()
})
.then((text) => {
console.log(text);
if(text.indexOf('555') > 0) { // if the response includes '555' it means SUCCESS, and we can stop the loop
~STOP!~ //help me stop the loop :)
}
});
i += 1;
} while (i < 20);
Use simple for loop with async await.
const fetch = require("node-fetch");
const url = "https://www.apitest12345.com/API/";
const headers = {
"LOGIN": "abcd",
"PASSWD": "12345"
}
const data = '<xml></xml>'
for (let i = 0; i < 20; i++) {
const res = await fetch(url, { method: 'POST', headers: headers, body: data});
if (res.text().indexOf('555') !== -1)
break;
}

Dialog Flow Client Followup Intent

Im wondering if there is a way to keep track of contexts of the intents as they follow. I know that you can use the output context of the previous intent as the input context of the followup intent. but this means i have to keep track of the lifespan as well. Is there another way???
var context = [];
async function TextRecognition(queryText) {
const sessionId = uuid.v4();
const sessionPath = sessionClient.sessionPath(projectId, sessionId);
// The text query request.
const request = {
session: sessionPath,
queryInput: {
text: {
// The query to send to the dialogflow agent
text: queryText,
// The language used by the client (en-US)
languageCode: 'en-US',
},
},
};
if (contextList !== null && contextList.length !== 0) {
console.log(contextList);
request.queryParams = {
contexts: context,
};
}
const responses = await sessionClient.detectIntent(request);
const result = responses[0].queryResult;
if (result.intent) {
if (typeof result.outputContexts[0] !== 'undefined') {
result.outputContexts.forEach(context => {
context.push(context);
});
}
return result.fulfillmentText;
} else {
console.log(`No intent matched.`);
}
}
found the answer :) there wasnt a problem in the first place just make sure to create sessionid for each client you dont need to keep track of anythiing dialogflow does it for you :p

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.

How to get a text / return(JSON ) in my API code with Watson?

In my example,
If the user clicks the button "Yes" Will return a conversation text. But I'd like it to return a value from my output, the return from my AJAX Post example, which is currently only coming from the "alert (output.request.number)".
How to make? Follow the codes:
In the conversation Intents: #goodbye and two entities: #goodbye:yes and #goodbye:no. If my client-side recognize the intent and user clicks the button "yes", will return something.
My JSON Advanced (Conversation Service)
{
"output": {
"text": "You can finish the conversation? \n \n
<button id=\"button-yes\" onclick=\"OneFunction();\">Yes</button>
<button id=\"button-no\" onclick=\"OtherFunction();\">No</button>"
}
}
I need the return of alert(output.request.number) to come in Watson's conversation flows if the user clicks on the button.
The JS code:
function OneFunction(firstParameter, secondParameter){
console.log(firstParameter);
$.ajax({
type: 'POST',
dataType: 'json',
contentType: "application/json",
url: 'http://xxxxxxxxxxxxxxxxxxxxxxxx/request/create',
data: JSON.stringify({
"dataOne":firstParameter,
"synchronize":false,
}
}),
success:function(output, input, response) {
console.log(output);
// alert(output.request.number);
var responseText = null;
var outputTest = {};
outputTest = output.request.number;
var latestResponse = Api.getResponsePayload();
// console.log(latestResponse);
var context = latestResponse.context;
Api.sendRequest = ("Yes", + outputTest); // THIS RETURN one number of request
}
I try it and work, the error is just a , between ("Yes" + outputTest);
But yours information was essential to this, thanks, #Michal Bida and #timd. :
success:function(output, input, response) {
console.log(output);
// alert(output.request.number);
var responseText = null;
var outputTest = {};
outputTest = output.request.number;
var latestResponse = Api.getResponsePayload();
// console.log(latestResponse);
var context = latestResponse.context;
Api.sendRequest = ("Yes" + outputTest); // THIS RETURN one number of request

handle response from telegram bot api

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();

Resources