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'}],...
}
Related
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.
Code:
import requests
import json
key = 'key' #api key
url = 'https://www.googleapis.com/youtube/v3/channels?part=statistics&key='+ key +'&forUsername='
youtuber = input('What\'s the name of the youtuber: ') #get youtuber name
url += youtuber.lower() #youtuber name all lowercase
r = requests.get(url) #get data from youtuber channel webpage
try:
subs = json.loads(r.text)['items'][0]['statistics']['subscriberCount']
except:
print('Your youtuber doesn\'t exist ):')
exit()
print(youtuber,"has",subs,"subscribers! Woohoo!")
This is okay:
Input: Google
Output: Google has 9640000 subscribers! Woohoo!
This is not:
Input: Markiplier
Output: Markiplier has 84900 subscribers! Woohoo! (Actually, his main channel has 27.8M subscribers)
I run into the unfortunate issue of channels with the same name. How do I prevent this?
You have to acknowledge the following peculiarity of YouTube site: it permits (by design) that the very same name -- in your case Markiplier -- to be a channel's custom URL and, at the same time, to be the (legacy) user name of another channel.
Please read the first few paragraphs of my answer to a very much related question. From there, you'll get a pretty good idea about the difference between the two (sometimes confusing) concepts: channel user name and channel custom URL.
Concretely, if you'll make use of my Python3 public script youtube-search.py, you'll see that there are two different channels that exhibit the behavior I just described w.r.t. the name Markiplier:
$ python3 youtube-search.py --user-name Markiplier
UCxubOASK0482qC5psq89MsQ
$ python3 youtube-search.py --custom-url Markiplier
UC7_YxT-KID8kRbqZo7MyscQ
Note that youtube-search.py requires a valid API key to be passed to it as argument of the command line option --app-key or, otherwise, passed on as the environment variable YOUTUBE_DATA_APP_KEY. (Use the command line option --help for brief helping info.)
A further Channels.list API endpoint query on the following URL:
https://www.googleapis.com/youtube/v3/channels?id=UCxubOASK0482qC5psq89MsQ,UC7_YxT-KID8kRbqZo7MyscQ&part=id,snippet,statistics&fields=items(id,snippet(title,description,customUrl),statistics(subscriberCount))&maxResults=2&key=...
will confirm the difference you've experienced:
{
"items": [
{
"id": "UCxubOASK0482qC5psq89MsQ",
"snippet": {
"title": "markiplier",
"description": "I will no longer be updating this channel! All my new videos with be uploaded to markiplierGAME! Please re-subscribe on that channel to stay up-to-date on my videos!"
},
"statistics": {
"subscriberCount": "85000"
}
},
{
"id": "UC7_YxT-KID8kRbqZo7MyscQ",
"snippet": {
"title": "Markiplier",
"description": "Welcome to Markiplier! Here you'll find some hilarious gaming videos, original comedy sketches, animated parodies, and other bits of entertainment! If this sounds like your kind of channel then please Subscribe Today!\n\nTotal Charity Raised ▶ $3,000,000+",
"customUrl": "markiplier"
},
"statistics": {
"subscriberCount": "27800000"
}
}
]
}
Now, to make a summary of my points w.r.t. your question -- I run into the unfortunate issue of channels with the same name. How do I prevent this? --, I note the following:
Be sure what is that you look to obtain from the API: custom URLs and user names are different API concepts.
If you're trying to obtain info about a channel for which you have its user name, then use Channel.list endpoint queried with an appropriate forUsername parameter.
If you're trying to obtain info about a channel of given custom URL, then use the procedure and Python code I described in my answer to this question Obtaining a channel id from a youtube.com/c/xxxx link. Also be prepared for possible failure of that procedure (due to way the API is currently implemented, it may well happen that the procedure fails on certain valid custom URLs).
I have an intent called ContinueIntent and its event is named ContinueEvent.
I also have an intent called DummyIntent. I'm using Dialogflow V2.
I want the user to invoke DummyIntent. This then links to the webhook which returns a parameter value and then invokes ContinueIntent.
Please respond with the python/JSON which should be returned from the webhook. The question then is how do I change my existing webhook and JSON (shown below) to allow me to:
Invoke another intent
pass through a value
Current JSON:
{
"fulfillmentText": text,
"source": source
}
I read somewhere to add (but I don't know where and can't get it to work):
CLIENT_ACCESS_TOKEN = 'sdfghjkl34notreal567890dfghjkl'
ai = apiai.ApiAI(CLIENT_ACCESS_TOKEN)
req = ai.event_request(apiai.events.Event("ContinueEvent"))
response = req.getResponse().read()
The solution was to change the JSON to the following:
"followupEventInput":{
"name":"ContinueEvent",
"parameters":{
"param": param_value
}
},
I'm migrating Parse to Firebase and I'm having trouble with the enhanced push notification.
Parse data (iOS side) was like:
{"ast":
{"alert": {
{"body": "body_test",
"title": "title_test",
"description": "description",
"endpoint-proposal": "https://.."
"launch-image": "https://..."
},
"sound": "chime",
...
}
Working with Firebase API the ast tag is the ['notification']['body'].
If I send
['notification']['body'] = 'Hello'
It works perfectly and generate the following push:
{"ast":
{"alert": "Hello"}
}...
So, here the problem, I need to send a dictionary in that tag (alert) and I cannot do that because firebase set the value as string.
Example in python:
alert = dict()
alert['title'] = 'title'
alert['description'] = 'description'
alert['endpoint-proposal'] = 'https://..'
alert['launch-image'] = 'https://..'
fcm_payload['notification']['body'] = alert
send_push()
And in the iOS side I get:
[AnyHashable("gcm.message_id"): 0:123456789,
AnyHashable("aps"): {
alert = "{\"body\": \"body\",
\"launch-image\": \"https://...\",
\"endpoint-proposal\": \"https://...\",
\"description\": \"description\",
\"title\": \"title\"}";
}]
Always as string :S
Is there any way to send that alert as dict?
The notification body parameter will always be treated by FCM as a String. It's just the behavior. What you'll have to do is make use of the data payload and put in your custom key-value pairs:
On iOS, if the message is sent via APNS, it represents the custom data fields. If it is sent via FCM connection server, it would be represented as key value dictionary in AppDelegate application:didReceiveRemoteNotification:.
More details can be seen in this Receiving Messages in iOS doc. I think for your case, you just have to use the notification and data parameters together in your payload.
json.loads() should get you a dict.
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.