I want to retrieve callback query and call another function which also have another buttons - python-telegram-bot

def start(update: Update, context: CallbackContext) -> None:
"""Sends a message with three inline buttons attached."""
keyboard = [
[
InlineKeyboardButton("Option 1", callback_data='1'),
InlineKeyboardButton("Option 2", callback_data='2'),
]
]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text('Please choose:', reply_markup=reply_markup)

Related

Response cards not showing -Amazon lex

I have created a lex chatbot and integrated it into website .Its working fine.I got to know that I have to invoke response cards from lambda .I did that too.Also,I enabled repsonse card checkbox in lex console.After all this,I am not able too see the buttons in the website.Is there any other way to display the buttons other than response cards?
Below is the code:Here,after the fulfillment,I have given the response card which means that after the message "Hey your ticket has been raised",the buttons will be displayed.This displays in lex test chatbot.
import json
import logging
import re
import http.client
import mimetypes
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
def close():
val= {
"dialogAction":
{
"fulfillmentState":"Fulfilled",
"type":"Close",
"message":
{
"contentType":"PlainText",
"content":"Hey your ticket has been raised"
},
'responseCard': {
'version': '0',
'contentType': 'application/vnd.amazonaws.card.generic',
'genericAttachments': [
{
'title': 'title1',
'subTitle': 'subtitle',
"buttons":[
{
"text":"button 1",
"value":"value 1"
},
{
"text":"button 2",
"value":"value 2"
},
{
"text":"button 3",
"value":"value 3"
}
]
}
]
}
}
}
print(val)
return val
def lambda_handler(event, context):
slots = event['currentIntent']['slots']
empidemployee= event['currentIntent']["slots"]["empidemployee"]
latestdesc= event['currentIntent']["slots"]["latestdesc"]
latestservice= event['currentIntent']["slots"]["latestservice"]
latestimpactvalue= event['currentIntent']["slots"]["latestimpactvalue"]
latesturgency= event['currentIntent']["slots"]["latesturgency"]
basicinfo=event['currentIntent']["slots"]["basicinfo"]
val=close()
return val
I believe your problem is the version number. Try setting it to 1 or '1'.
I couldn't find a clear explanation as to why, but here are some evidences at least:
From the AWS example doc: Generating Response Cards Dynamically
responseCard: {
"version": 1,
...
}
I also looked deeper into the lex-web-ui files you are using and in the lex-web-ui.js file it has this:
shouldDisplayResponseCard: function shouldDisplayResponseCard() {
return this.message.responseCard && (this.message.responseCard.version === '1' || this.message.responseCard.version === 1) && this.message.responseCard.contentType === 'application/vnd.amazonaws.card.generic' && 'genericAttachments' in this.message.responseCard && this.message.responseCard.genericAttachments instanceof Array;
},
And that specifically checks for (this.message.responseCard.version === '1' || this.message.responseCard.version === 1) in order to display.

Response cards not displaying in website-lex

I have created Lex Chatbot and developed a website and integrated this Chatbot. Its working fine.But response cards in the form of buttons are not showing up.I got to know that I have to invoke it from lambda function.So I included the response card code .It works ,but after displaying the buttons it goes back and asks the first slot value again.I dont know where I am wrong
Here is the expected conversation.
User:Hi
Lex:Please provide me your eid
User:e123456
Lex:Choose one of the impact below:
1.low 2.high 3.medium (in form of buttons)
User clicks on low
Lex:Thanks,your ticket has been raised(expected)
What happens:
User:Hi
Lex:Please provide me your eid
User:e123456
Lex:Choose one of the impact below:
1.low 2.high 3.medium
User clicks on low
Lex:Please provide me your eid(goes back and asks the first slot value)
Here is my code:
import json
import logging
import re
import http.client
import mimetypes
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
def elicit_slot_response(output_session_attributes,intent_name,slot_to_elicit,message):
responses= {
'dialogAction': {
'type': 'ElicitSlot',
'slottoElicit':'slot_to_elicit',
'message': {
'contentType': 'PlainText',
'content': message
},
'responseCard': {
'version': '0',
'contentType': 'application/vnd.amazonaws.card.generic',
'genericAttachments': [
{
'title': 'title1',
'subTitle': 'subtitle',
"buttons":[
{
"text":"button 1",
"value":"value 1"
},
{
"text":"button 2",
"value":"value 2"
},
{
"text":"button 3",
"value":"value 3"
}
]
}
]
}
}
}
return responses
def close():
val= {
"dialogAction":
{
"fulfillmentState":"Fulfilled",
"type":"Close",
"message":
{
"contentType":"PlainText",
"content":"Hey your ticket has been raised"
}
}
}
print(val)
return val
def lambda_handler(event, context):
val = ""
slots = event['currentIntent']['slots']
empidemployee= event['currentIntent']["slots"]["empidemployee"]
latestdesc= event['currentIntent']["slots"]["latestdesc"]
latestimpact= event['currentIntent']["slots"]["latestimpact"]
output_session_attributes = event['sessionAttributes'] if event['sessionAttributes'] is not None else {}
elicit_slot_response(output_session_attributes,'latestdetails','latestimpact',"impact")
val=close()
return val
The conversation flow restarts because in the ElicitSlot response from the Lambda function containing the response cards, you are not returning the slots parameter which would contain the slot values already taken as an input from the user.
So, include the slots parameter in the response the value for which could be event['currentIntent']['slots'].

Django REST Group by datetime field as today, yesterday and etc

I have a model Message with related with room
class Message(models.Model):
room = models.ForeignKey(Room, on_delete=False, related_name='messages')
text = models.TextField()
created = models.DateTimeField(auto_now_add=True)
And my Room serializer.
class RoomSerializer(serializers.ModelSerializer):
messages = MessageSerializer(read_only=True, many=True, allow_null=True)
class Meta:
model = Room
fields = '__all__'
When i make get room/10/ i get room with all messages. Its OK. But i need get messages group_by created as today, yesterday and etc.
What about a best practices. Maybe it should be done on Front-end side, because i develop only API?
Example: Now i get
{
"id": 10,
"messages": [{
"room": 10,
"text": "Messsage text",
"created": "2018-03-01T10:15:49.689655Z"
},
{
"room": 10,
"text": "Messsage text 2",
"created": "2018-03-02T10:15:49.689655Z"
}
]
}
I want get something like this
{
"id": 10,
"messages": [{
"today": [{
"room": 10,
"text": "Messsage text",
"created": "2018-03-01T10:15:49.689655Z"
}]
},
{
"yesterday": [{
"room": 10,
"text": "Messsage text 2",
"created": "2018-03-02T10:15:49.689655Z"
}]
}
]
}
I think you best option here is to use a serializers.SerializerMethodField for messages:
import datetime
from itertools import groupby
class RoomSerializer(serializers.ModelSerializer):
messages = serializers.SerializerMethodField()
class Meta:
model = Room
fields = '__all__'
def get_messages(self, obj):
messages = obj.messages.all()
messages_grouped_by_date = groupby(messages.iterator(), lambda m: m.created.date())
messages_dict = {}
for date, group_of_messages in messages_grouped_by_date:
dict_key = date.strftime('%Y-%m-%d')
if date == datetime.date.today():
dict_key = 'today'
elif date == (datetime.date.today() - datetime.timedelta(days=1)):
dict_key = 'yesterday'
messages_dict[dict_key] = MessageSerializer(group_of_messages, many=True).data
return messages_dict

RavenDb 4: Check if a string of an array of strings exists in different array of strings

I am trying to filter my activities based on user roles. The manager is only allowed to see the activities that contain the role Manager. See below for more information.
Data:
var user = new User
{
Roles = [
"Manager"
]
}
var activities = new List<Activity>
{
new Activity
{
Description = "My First Activity",
Roles = [
"Admin",
"Manager"
]
},
new Activity
{
Description = "My Second Activity",
Roles = [
"Admin"
]
},
new Activity
{
Description = "My Third Activity",
Roles = [
"Manager",
"Client"
]
},
}
Query that filters the activity
var filtered = await context.Query<Activity>()
.Where(x => x.Roles.Any(y => user.Roles.Contains(y)))
.ToListAsync();
Expected result of filtered:
[
{
new Activity
{
Description = "My First Activity",
Roles = [
"Admin",
"Manager"
]
}
new Activity
{
Description = "My Third Activity",
Roles = [
"Manager",
"Client"
]
},
}
]
Error from query
System.InvalidOperationException : Can't extract value from expression of type: Parameter
I am getting an error, so obviously I am doing something wrong. Is this the correct way or is there something better?
This requires RavenDB to do computation during query, try this, instead:
.Where(x => x.Roles.In(user.Roles)) (might need to add a using statement for the In extension method, Raven.Client.Linq, IIRC).

ruby - iterating through aws instances/volumes and creating nested hash structure

Using aws-sdk, I need to discover instance_ids and all the attached volumes. I then want to iterate over those volumes.
#instances contains a list of instance id's. This is needed because filtering first needs to be done client side.
#ec2 = Aws::EC2::Client.new
#instances.each do |instance_id|
resp = #ec2.describe_volumes({
filters: [{
name: 'attachment.instance-id',
values: [instance_id]
}]
}).volumes
resp.each do |volumes|
(#volumes[instance_id] ||= []) << volumes.volume_id
end
end
This works fine. My output is something like:
{
"i-11111111": [
"vol-xxxxxxxx",
"vol-xxxxxxxx",
"vol-xxxxxxxx"
],
"i-22222222": [
"vol-xxxxxxxx",
"vol-xxxxxxxx",
"vol-xxxxxxxx",
"vol-xxxxxxxx",
"vol-xxxxxxxx"
],
"i-33333333": [
"vol-xxxxxxxx"
],
"i-44444444": [
"vol-xxxxxxxx",
"vol-xxxxxxxx"
]
}
The problem is that I would like to go deeper, and change the array of volumes to a hash with the volume-id of that key.
https://docs.aws.amazon.com/sdkforruby/api/Aws/EC2/Client.html#describe_volumes-instance_method
It would look like
{
"i-11111111": {
"vol-xxxxxxxx": [
device: "/dev/blah1",
attach_time: "blah"
],
"vol-xxxxxxxx": [
device: "/dev/blah2",
attach_time: "blah"
]
},
"i-22222222": {
"vol-xxxxxxxx": [
device: "/dev/blah1",
attach_time: "blah"
],
"vol-xxxxxxxx": [
device: "/dev/blah2",
attach_time: "blah"
],
"vol-xxxxxxxx": [
device: "/dev/blah3",
attach_time: "blah"
]
}
}
I could then query the hash for the required information (assuming that's possible?)
Any help is appreciated.
I think you could do something like this:
resp.each do |volumes|
volume_ids = volumes.map(&:volume_id)
descriptions = #ec2.describe_volumes(volume_ids: volume_ids)
volume_hash = (#volumes[instance_id] ||= {})
descriptions.each { |desc| volume_hash[desc.volume_id] = desc }
end
This assumes:
that the format of the volume_ids option is an array; I was not clear from the docs whether it should be an array or a string
that none of the other options listed in the describe_volumes API docs are necessary
require 'aws-sdk'
require 'json'
client = Aws::EC2::Client.new
instances = ['i-instanceone', 'i-instancetwo']
volumes = client.describe_volumes({
filters: [{
name: 'attachment.instance-id',
values: instances
}]
}).volumes
list = volumes.flat_map(&:attachments).each_with_object(Hash.new {|k,v| k[v] = {}}) do |vol, hsh|
hsh[vol.instance_id][vol.volume_id] = {
device: vol.device,
attach_time: vol.attach_time
}
end
puts JSON.pretty_generate(list)
# {
# "i-instanceone": {
# "vol-one": {
# "device": "/dev/sda1",
# "attach_time": "2015-02-25 14:24:23 UTC"
# }
# },
# "i-instancetwo": {
# "vol-two": {
# "device": "/dev/sda1",
# "attach_time": "2015-04-27 13:08:14 UTC"
# },
# "vol-three": {
# "device": "/dev/xvdf",
# "attach_time": "2016-04-10 14:45:15 UTC"
# }
# }
# }

Resources