I'm struggling to respond to an action sent by an Adapative card with a Teams bot. The action is being sent like this:
"actions": [
{
"type": "Action.Execute",
"title": "Approve",
"verb": "APPROVE",
"data": {
"USER_ID": 13
}
},
]
This is being handled by the on_adapative_card_invoke method in our bot:
async def on_adaptive_card_invoke(self, turn_context: TurnContext, invoke_value: AdaptiveCardInvokeValue) -> AdaptiveCardInvokeResponse:
return AdaptiveCardInvokeResponse(status_code=200)
However Teams always shows 'Something went wrong. Please try again'
How should the bot respond, is it with another post or an actual returned response. I've tried both with no luck and there are no samples for this method in Python.
TIA
I'm muddling through this with python as well.
According to Microsoft's Universal Action Model the response requires a specific format.
If you're not looking to send or replace the card after the card has been invoked you can return an empty message.
return AdaptiveCardInvokeResponse(
status_code=HTTPStatus.OK,
type="application/vnd.microsoft.activity.message")
In my opinion, to prevent the card from being invoked multiple times, it's best to replace the card once it has been invoked.
return AdaptiveCardInvokeResponse(
status_code=HTTPStatus.OK,
type="application/vnd.microsoft.card.adaptive",
value=card
)
In my case the card was json formatted adaptive card that I deserialized.
Related
hello everyone I almost finished a bot with lex v2 that uses lambda, I did the integration using the kommunicate client to do before, but now I need the chatbot to start with an intent automatically, this is my first problem.
Also I would like to know if on lambda in the answers there is a way to send a response that makes an elicit slot, and then after 5 seconds send another to move to confirmation intent on lex v2.. I tried with time and asyncio, but it seems that the code does not go on, I can only get the first answer with the slot elicit, I wish that after about 5 seconds I refer to confirmation intent on lex v2, this is my code:
if carFound is not None:
# if resp['total'] < 30:
# print('Conferma intento')
# carDialog = {
# "type": "ConfirmIntent"
# }
# else:
# print('Filtri args')
# carDialog ={
# "type": "ElicitSlot",
# "slotToElicit": "Args"
# }
response = {
"sessionState": {
"dialogAction": {
"type": "ElicitSlot",
"slotToElicit": "Args"
},
"intent": {
'name': intent,
'slots': slots,
"state": "Fulfilled",
}
},
"messages": carFound,
}
practically after every call to my api that sends me carFound as a payload with all the machines, I should verify that when resp['total'] and less than 30 I refer in addition to the answers also to confirmation intent after some time.
as i said yet i tried with sleep() function of python, and i still have only the response that has the elicitslot,maybe sleep and asyncio are not well for lexv2...
I verified through the test of lambda, with my inputs that the condition of <30 is true, so the problem is on the response i think.
for the welcome i don't know how i can do, i want that my bot start with the intent Welcome for example, without write nothing on my kommunicate client that is on a website.
I've followed tutorials to setup Lex&Lambda. My lambda function returns
return {
"dialogAction": {
"type": "ConfirmIntent",
"intentName": "GetPersonInfo",
"message": {
"contentType": "PlainText",
"content": ""
}
}
}
and Lex displays it as single message. When I'm building my bot on aws site I can setup multiple messages as answer(without using lambda) and I would like to do that with lambda function just like on img: https://docs.aws.amazon.com/lex/latest/dg/images/default-response-25a.png.
On aws site I've prepared output for multiple messages and it look like this:
{
"dialogState": "Fulfilled",
"intentName": "GetPersonInfo",
"message": "{\"messages\":[{\"type\":\"PlainText\",\"group\":1,\"value\":\"siema siemanko\"},{\"type\":\"CustomPayload\",\"group\":2,\"value\":\"{\\\"moj\\\":\\\"json\\\"}\"}]}",
"messageFormat": "Composite",
...
}
I've noticed that Lex expect "dialogAction" as lambda output and multiple message feature is used in "PostText" and "PostContent". I know, that dialogAction is used to build PostText/PostContent object.
I also would like to send different message to speech, different to display as text and another as a JSON (for my Frontend). Right now my solution is to send everything as PlainText message in dialogAction object and then via my front end execute Polly to read message prepared for speach. Is this possible to do such stuff just with Lex and lambda?
The only way I know to display multiple messages is to do that via Lex configuration on AWS Lex side. As an example:
1. You create an intent with an utterance I want to get information about user {UserEmailAddress}.
2. You create a required slot UserEmailAddress and non-required UserFirstName and UserLastName.
3. Once the first slot is filled by an utterance you send a request to your backend API within Lambda exports function to get information about that user via his email address and fill other slots (the code is applicable to Node 8.10 you may create your own Python version):
`
exports.handler = async (event, context) => {
...
return context.succeed({
event.sessionAttributes,
dialogAction: {
type: "Delegate",
{
...event.currentIntent.slots,
UserFirstName: httpResponse.firstName,
UserLastName: httpResponse.lastName
}
}
})
}
`
4. In "Response" section of your intent you add multiple messages:
Here is the information for the user {UserEmailAddress}
His first name is {UserFirstName} and his last name is {UserLastName}.
5. Add a response card with the question that contains an utterance as one/many of responses. For example, the question "What do you want to do next?" and a button:
Button title: "Get his address",
Button value: ""
Ideally the dialog should look like this:
User: I want to get information about user simon#tech.com
Bot: Here is the information about user simon#tech.com
Bot: His first name is Simon his last name is Anderson
Bot: What do you want to do next?
[Get his address]
And when you click the button it will look the same as the ordinary response for a slot.
You can use multiple messages as an array in your response.
return {...
'message' : [{'contentType': 'PlainText',
'content': 'Something response'}],...
}
I am trying to build a Slack bot in Python. I want my bot to send a message with interactive buttons on it, and then based on which the user clicks on, run a function in Python. I do not seem to find how to do this.
My code now look like this:
message = "message"
attachments = [{"text": "message",
"attachment_type": "default",
"actions": [
{
"name": "list",
"text": "message",
"type": "select",
"options": [
{
"name": "1",
"text": "1",
"type": "button",
"value": "1"
},
{
"name": "1",
"text": "1",
"type": "button",
"value": "2"
}
]}]}]
sc.api_call("chat.postMessage",
channel=channel,
text=message,
attachments=attachments)
So that gives me a message with two buttons. I, however, want to run a function based on the answer the user gives.
So say that if they click 1, function1() runs and when they click 2, function2() runs.
The Slack api documentation is quite confusing about how to do this, and the "listener" they provide rtm_read() does not pick on the user clicking on one of the buttons.
So if anyone could help me with this, it would be much appreciated.
When you click a button in a slack conversation it's basically applying a callback. The callback is sent somewhere that you define in the App's setting, then THAT service decides what to do next with the information that's given.
First you need to create a new Slack App.
After it's created click on the App to go to its Basic Information page.
From there, on the left side under Features find "Interactive Components".
Register the two URLs that will receive the POST data from clicking on a button.
Interpret the data and proceed :)
From the Slack documentation you can find their walkthrough here.
You're going to need a running web server, something simple in Flask will work just fine.
from flask import Flask, request
app = Flask('SlackReceiver')
#app.route('/slack/message', methods=['POST'])
def incoming_slack_message():
req = request.get_json()
# .. do something with the req ..
return 'action successful'
#app.route('/slack/options', methods=['POST', 'OPTIONS'])
def incoming_slack_options():
# .. idk ..
return 'ok'
if __name__ == '__main__':
app.run('0.0.0.0', 8088, debug=False)
...
Lastly, according to the docs you need to host this application on a web server with an HTTPS valid certificate configured. Setting up a server is beyond the scope of this question, the easiest way to get free (valid) HTTPS certs is with Let's Encrypt and certbot.
I started writing a Slack bot in Python and came to a halt when I couldn't find a way to send richly-formatted messages using the either of the two methods:
sc.rtm_send_message("channel_name", my_message)
sc.api_call("chat.postMessage", channel="channel_name", text=my_message, username="username", icon_url="icon_url")
where my_message = json.dumps({'attachments': [{...}]})
I now know that I can do this using the webhook approach but is it possible with the above method?
Both API (method chat.postMessage) and incoming webhook offer the same options for formatting your messages including markup and attachments.
Hint: if you want to use markup in your attachments, make sure to add the field "mrkdwn_in" and name the field your want to use it in or it will be ignored by Slack.
Example:
{
"attachments": [
{
"title": "Title",
"pretext": "Pretext _supports_ mrkdwn",
"text": "Testing *right now!*",
"mrkdwn_in": ["text", "pretext"]
}
]
}
See here for full documentation.
I found out where I was going wrong.
I was passing my message to the wrong argument in the sc.api_call method.
I should've been passing it to sc.api_call(attachments=...) argument, not the text argument.
I am trying to get user's friend list from facebook Graph-api. So after getting access token when I try to open by urlopen by
https://graph.facebook.com/facebook_id/friends?access_token=authentic_accesstoken
this doesn't give friend_list of person(facebook_id) not even when I open it directly on the browser, at least not the entire list. This is what it shows on the browser
{
"data": [
{
"name": "Face_id_name",
"id": "facebook_numeric_id"
}
],
"paging": {
"next": "https://graph.facebook.com/v2.2/facebook_id/friends?access_token=authentic_accesstoken&limit=25&offset=25&__after_id=enc_Some_encrypted_code"
},
"summary": {
"total_count": 263
}
}
In data it doesn't show the entire list and when I use link to paging: next: it doesn't give me anything just total count again.
I am not entirely sure whether my url is right or not.
You canĀ“t get the friends of ANY user, you can only get the friends of the authorized user and only those who authorized the App too - for privacy reasons. So this is the only correct call:
https://graph.facebook.com/me/friends?access_token=authentic_accesstoken
There is no need to use the ID, because you can only use the ID of the authorized user anyway. So you can just use "me" instead.
More information about the limited friend result can be found in countless other threads, for example: Facebook Graph Api v2.0+ - /me/friends returns empty, or only friends who also use my app