I'm using slackbots (https://github.com/mishk0/slack-bot-api) to create an interactive bot.
I can, as a user, send message in chat and having my bot giving me an answer depending on what i wrote. Like if I type : !weekend, my bot will answer if weekend is close or not by fetching an API.
It's working this way
bot.on('message', data => {
if (data.type !== 'message') {
return;
}
handleMessage(data.text);
});
function handleMessage(message) {
switch (message) {
case '!weekend':
case '!we':
fetchWeekendData();
break;
case '!apero':
case '!biere':
case '!pastis':
fetchAperoData();
break;
case '!meteo':
fetchWeatherData();
break;
case '!metro':
fetchMetroData('A');
fetchMetroData('R');
break;
case '!features':
getFeatures();
break;
}
}
function fetchWeekendData() {
axios.get('https://estcequecestbientotleweekend.fr/api',
).then(res => {
const weText = res.data.text;
postToChannel(`_Bientôt le week end ?_ : *${weText}*`);
});
}
function postToChannel(message) {
bot.postMessageToChannel(
'général',
message,
params
)
}
I have another function calling, this time, a weather api. The api respond with many infos and
a link to a png depending on the weather. A little weather icon.
Problem is, when i send back my message to chat, it send the image link and i just can't figure out how to get this link as an image in chat.
function fetchWeatherData() {
axios.get('http://api.weatherstack.com/current?access_key=myAPIkey&query=Paris&units=m',
).then(res => {
const location = res.data.location.name;
const icon = res.data.current.weather_icons;
const temperature = res.data.current.temperature;
const feelslike = res.data.current.feelslike;
const humidity = res.data.current.humidity;
postToChannel(`Météo à *${location}* : ${icon} \n>_Température_ : *${temperature}* °C _Ressenti_ : *${feelslike}* °C\n\n>_Humidité_ : *${humidity}* %`)
});
}
If anyone has already used slack-bot-api and posted images with his bot, I'd like to know how you did this cause I'm running out of idea, slack api docs is showing JSON attachments for images but I don't know how to use it with this package.
EDIT : Alright it's solved, this way
function postToChannelWithImage() {
bot.postMessageToChannel(
'général',
'yikes itis working',
params = {
"icon_url": "https://avatars.slack-edge.com/2020-02-04/935676215584_38623245747b942874b5_192.jpg",
"attachments":
[
{
"fallback": "this did not work",
"image_url": "https://a.slack-edge.com/80588/img/blocks/bkb_template_images/beagle.png"
}
]
}
)
}
I added the array and it worked perfectly, I just have to add other params into the same array to keep my config the way it is.
Thanks a lot to #Erik Kalkoken !!
This library seams to just forward parameters to the respective Slack API method, which is chat.postMessage.
To post an image with Slack you need to include an image URL either within an attachment (outmoded) or blocks.
e.g. to attach an image wit attachments you would add this array via params:
{
"attachments":
[
{
"fallback": "this did not work",
"image_url": "https://a.slack-edge.com/80588/img/blocks/bkb_template_images/beagle.png"
}
]
}
Related
I am using NodeJs API of Microsoft Bot Framework v4. And my dialogs are not hardcoded in the ActivityHandler, I just call from there. I am using Waterfall dialogs. So when I try to show Carousel card on messenger (which is HeroCard on Microsoft bot framework), it shows up successfully but when I click any button on cards, there is no response for next dialog.
I tried to handle on onMessage hook but, it just tries to validate the response and throw errors.
....
ListItems extends ComponentDialog {
constructor(userProfileState, conversionStateAccessor) {
super(LIST_ITEMS);
this.userState = userProfileState;
this.conversionState = conversionStateAccessor;
this.addDialog(new WaterfallDialog(LIST_ITEMS_DIALOG, [
this.sendItems.bind(this),
this.handleItems.bind(this)
]
));
this.initialDialogId = LIST_ITEMS_DIALOG;
}
async sendItems(step) {
.......
await step.context.sendActivity({ attachments: cards }); // this line is working
}
async handleItems(step) {
console.log(step.result) // the response is not in 'step.result.value' if i click a button on cards
}
Thanks for your help
---- I added more detail -----
I am using this template to create cards
const card = CardFactory.heroCard('title', 'subtitle', ['imagelink'], [
{ type: ActionTypes.PostBack,
title: 'product 1',
value: 'product_1'
},
{ type: ActionTypes.PostBack,
title: 'product 1',
value: 'product_1'
},
]);
await context.sendActivity({ attachments: [card] });
Cars can be created successfully but the problem is, after that, I send a prompt to let the user turn the main menu if the user wants.
so I send them like that
await context.sendActivity({ attachments: [card] });
await step.prompt(LIST_ITEMS_MENU_PROMPT, menuPromptPayload);
And if the user clicks a button on cards, an error is thrown because I think the framework waits for prompt's answers. Couldn't catch the card's button's payload/
You need to instruct your bot to wait for and return a response following the sendActivity in sendItems. Similarly, you will encounter an error in the handleItems if you don't tell the bot to continue on since there is nothing happening other than console logging.
async sendItems(step) {
.......
await step.context.sendActivity({ attachments: cards });
// Tells the bot to wait. Normally, on `sendActivity`, it continues on to the next step.
// "DialogTurnStatus" can be found in the `botbuilder-dialogs` package.
return { status: DialogTurnStatus.waiting };
}
async handleItems(step) {
console.log(step.result);
return step.next(); // Tells the bot to continue to the next step.
}
Hope of help!
I am trying to send a postBack text message to my bot but I don't know the right syntax.
Here is my code:
if (postback.payload == "WHAT_IS_MENTAL_HEALTH") {
await turnContext.sendActivity("TO-DO: Forward on 'What Is Mental Health?' to Bot Handler");
ActionTypes.postBack("What Is Mental Health?");
}
I'm trying to forward on the text "What Is Mental Health?" to my bot so it will pull back the QnA Maker response for that question.
The steps for this are as follows:
User clicks a button on a Facebook Messenger Generic Template Card (e.g. “What Is Mental Health?” Button)
The button sends a postBack payload to the bot (e.g. “WHAT_IS_MENTAL_HEALTH”)
I am detecting the postBack payload from Facebook Messenger (e.g if (postBack.payload == “WHAT_IS_MENTAL_HEALTH”))
Once that particular postBack payload is detected I then want to send an additional postBack to my bot as text (e.g. “What Is Mental Health?”) so it can be interpreted by my QnA and respond with the correct answer which has been programmed into my QnA Knowledge Base.
Facebook Events and the Bot Framework
When Facebook sends an event to your bot, it sends an Activity with an Event ActivityType. For some events, the event data is in the Activity.Value property. For other events, like a PostBack from a Quick Reply, the activity will be a Message and the data will be in Activity.ChannelData. For example, your bot might receive a postBack event as an activity like this:
{
channelId: 'facebook',
[...]
type: 'message',
channelData: {
recipient: {...},
sender: {...},
message: {
[...],
quick_reply: {
[...],
payload: '<your payload>'
}
}
}
}
Handling Facebook Events
This answer is going to pull heavily from the Facebook Events Sample. I highly recommend looking at that for additional help.
Capture Messages and Events
First, you want to capture the facebook messages and events with onMessage() and onEvent():
this.onMessage(async (turnContext) => {
console.log('Processing a Message Activity.');
// Show choices if the Facebook Payload from ChannelData is not handled
if (!await this.processFacebookPayload(turnContext, turnContext.activity.channelData)) {
if (turnContext.activity.channelId !== 'facebook') {
await turnContext.sendActivity('This sample is intended to be used with a Facebook bot.');
}
await this.showChoices(turnContext);
}
});
this.onEvent(async (turnContext) => {
console.log('Processing an Event Activity.');
// Analyze Facebook payload from EventActivity.Value
await this.processFacebookPayload(turnContext, turnContext.activity.value);
});
Process the Messages/Events
Facebook can send many types of events. You may want to use an if or switch statement to handle each type:
async processFacebookPayload(turnContext, data) {
// At this point we know we are on Facebook channel, and can consume the Facebook custom payload present in channelData.
const facebookPayload = data;
if (facebookPayload) {
if (facebookPayload.postback) {
// Postback
await this.onFacebookPostback(turnContext, facebookPayload.postback);
return true;
} else if (facebookPayload.optin) {
// Optin
await this.onFacebookOptin(turnContext, facebookPayload.optin);
return true;
[...]
}
return false;
}
Specifically, Handle a PostBack
The sample just does:
async onFacebookPostback(turnContext, postback) {
console.log('Postback message received.');
// TODO: Your postBack handling logic here...
// Answer the postback and show choices
await turnContext.sendActivity('Are you sure?');
await this.showChoices(turnContext);
}
As you want to route the question to QnA Maker, you might (using the QnA Maker Sample as guidance):
async onFacebookPostback(turnContext, postback) {
// qnaMaker.getAnswers doesn't accept string input, so we need to adjust our turnContext
// to match what it expects, which is a string in Activity.Text
turnContext.activity.text = postback.payload;
const qnaResults = await this.qnaMaker.getAnswers(turnContext);
// If an answer was received from QnA Maker, send the answer back to the user.
if (qnaResults[0]) {
await turnContext.sendActivity(qnaResults[0].answer);
// If no answers were returned from QnA Maker, reply with help.
} else {
await turnContext.sendActivity('No QnA Maker answers were found.');
}
}
I'm writing Telegram bot (nodejs) which will collect all images sent to it between "start" and "end" messages. I learned how to start bot.onText(/\/start/, but how to react on "end" message from user to start reacting after that?
You need to maintain state for every user who is going to send you the /start and /end command. You can persist the state in a Key/Value store (e.g. { userid: xxx, end: false }. You can then check against the database store every time a picture is sent. An example of how your code would look like is:
bot.onText(/\/start/, msg => {
//saveToDb({chat_id: msg.chat.id, completed: false});
});
bot.onText(/\/end/, msg => {
//saveToDb({chat_id: msg.chat.id, completed: true});
});
bot.on("message", msg => {
// most of this code is just for logical purposes to explain the concept
if (typeof msg.image === "object") {
//const completed = checkDb(msg.chat.id);
if (completed !== true) {
// work with the image
}
}
});
Alternatively you can look into mau its aim is to solve this issue. It works well with node-telegram-bot-api, check the examples folder to get started on how it works.
I am having problems trying to upload a photo from my frontend.
I have an input file where I can select a file from my computer.
What I want It is send that photo to my backend and store it as a Blob.
First I try to get the file and save as Blob:
foto: Blob;
setFoto(event){
this.foto = event.target.files[0];
}
But I don't know if this It is correct.
Second I send "this.foto" to the server using HTTP post and save in my db as blob. I think that my problem is that i am not sending the correct information about the photo.
In resume, what I want is send an image that I select from my computer to the server but I am having problems getting the correct information of the photo.
Solution founded
First, here is my input:
<input type="file" (change)="setFoto($event)">
Second, here is the method that you call when you select a photo.
setFoto(event) {
const foto = new Blob([event.target.files[0]]);
var reader = new FileReader();
reader.readAsDataURL(foto);
reader.onloadend = () => {
this.foto = reader.result;
}
}
this.foto is a string.
Then when i click on update button i send the new photo as url and save it in my db (Mysql) as TEXT.
updateApuesta() {
this.userService.updateBet(this.url, {
id: this.userService.getIdbet(),
coste: this.coste,
beneficio: this.beneficio,
foto: this.foto
}).subscribe(this.success.bind(this), this.error);
}
When I try to get the photo from my server I use this. I call my http get service and get the photo.
First, the new image is a
image: SafeResourceUrl;
and I assign the dat that I got from my server.
this.image = this.sanitizer.bypassSecurityTrustResourceUrl(data.foto);
You have to import:
import { DomSanitizer, SafeResourceUrl } from '#angular/platform-browser';
and pass it to your constructor:
constructor(private sanitizer:DomSanitizer ) { }
So finally, you got your image in this.image that is a SafeResourceUrl type. To load it in a you have to do this:
<img [src]="bet.foto"/>
where in your case bet.foto will be yout this.image that you have to pass to the template.
this.userService.updateBet(
this.url,{foto:this.foto}).subscribe(this.success.bind(this), this.error);
and the service is:
updateBet(url, body) {
return this.httpRequest.put(url, body, this.options);
}
put(url, body, options) {
return this.http.put(url, body, this.setOptions(options))
.map(this.extractData)
.catch((error: any) => Observable.throw(error.json().error || 'Server error')); //Show errors if any
}
But what i said, i think i am not sending the correct info about the photo.
The Facebook Messenger API is pretty sweet overall. However, whenever an user sends a sticker (The balloon thumb up sticker for example) to my bot, it always freezes for around 20 seconds. If the user sends a lot of stickers, the bot will simply crash and Facebook will send me "Webhook failing" developer alert.
I suspect there is something wrong with my code but I couldn't find any error. Something interesting I found is that when the bot crashed and Facebook sends me the "Webhook failing" alert, the bot will be revived and back to responding to messages if I resubscribe my app to the page by entering the following in the command line.
curl -X POST "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=<PAGE_ACCESS_TOKEN>"
Here is some information that may be helpful to you.
Repo: https://github.com/lorix-lpan/r-score-god
Server.js: https://github.com/lorix-lpan/r-score-god/blob/master/src/server.js
Facebook Page: https://www.facebook.com/rscoregod/
Note: The bot is still not available to the public at the moment, message it so I can add you as a test user.
Thank you very much!
Eventually, I figured out the problem myself. There is indeed something wrong with my code (or facebook's getting started code ;) ).
From Messenger platform's getting started page
The post handler is defined as the following
app.post('/webhook/', function (req, res) {
messaging_events = req.body.entry[0].messaging;
for (i = 0; i < messaging_events.length; i++) {
event = req.body.entry[0].messaging[i];
sender = event.sender.id;
if (event.message && event.message.text) {
text = event.message.text;
sendTextMessage(sender, "Text received, echo: "+ text.substring(0, 200));
}
}
res.sendStatus(200);
});
However, when a sticker or GIF is sent to the server, the "message" field of the "event" variable will be empty. Thus, the code inside the following block will not be evaluated and no HTTP request will be made since the sendTextMessage function POST to the Facebook server.
if (event.message && event.message.text) {
text = event.message.text;
sendTextMessage(sender, "Text received, echo: "+ text.substring(0, 200));
}
I solved the issue by simply adding another simple if statement for stickers and GIF (or other attachments). When an attachment is sent by the user (either a GIF or a sticker), the "event" variable will have a "attachments" property. In other words, event.attachments will be defined. My solution is the following:
app.post('/webhook/', function (req, res) {
messaging_events = req.body.entry[0].messaging;
for (i = 0; i < messaging_events.length; i++) {
event = req.body.entry[0].messaging[i];
sender = event.sender.id;
if (event.attachments) {
sendTextMessage(sender, 'I am an attachment');
}
if (event.message && event.message.text) {
text = event.message.text;
sendTextMessage(sender, "Text received, echo: "+ text.substring(0, 200));
}
}
res.sendStatus(200);
});
Check out this commit for more detail