Ask questions again if particular intent is triggered by the user - rasa-nlu

I am trying to build a chatbot which mainly comprises of 2 tasks: Task 1. Ask users to share their pincode and choose the category. Fetch results using these two inputs and display the message. Task 2. 1. After the flow ends - If a user says “corona help“ - prompt him asking if he wants to get them for the above given pincode if not - give him a provision to input a new pincode.
Follow similar flow for category as well. For example ( let us say user asked for - Free Food in 600036 )
User : corona help Bot : Do you want to get the resources for - 600036. Press yes to confirm and no to change another pincode User : no Bot: Please share the pincode User : 500081 Bot : Do you want to get “ Free Food” . Press yes to confirm and no to change User : Yes Bot : Show results for 500081 and Free Food
I have already done with task 1 but having difficulty with task 2. I want to know how to ask questions and fill the required slots if a particular intent is triggered.
Here’s my rules.yml:
version: "2.0"
rules:
- rule: trigger corona help
steps:
- intent: corona_help
- action: action_check_user_intent
- rule: Activate form
steps:
- intent: greet
- action: user_details_form
- active_loop: user_details_form
- rule: Submit form
condition:
# Condition that form is active.
- active_loop: user_details_form
steps:
# Form is deactivated
- action: user_details_form
- active_loop: null
- slot_was_set:
- requested_slot: null
# The actions we want to run when the form is submitted.
- action: action_submit
Actions.py:
class ValidateUserDetailsForm(FormValidationAction):
def name(self) -> Text:
return "validate_user_details_form"
def validate_pin_code(self,
slot_value: Any,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: DomainDict,
) -> Dict[Text, Any]:
print("HERE1")
url = f"https://api.postalpincode.in/pincode/{slot_value}"
r = requests.get(url)
data = json.loads(r.content)
status = data[0]['Status']
print(status)
if status == 'Error':
dispatcher.utter_message(text="Invalid PIN code. Enter again.")
return {"pin_code": None}
else:
return {"pin_code": slot_value}
class ActionCheckUserIntent(Action):
def name(self) -> Text:
return "action_check_user_intent"
def run(
self,
dispatcher,
tracker: Tracker,
domain: "DomainDict",
) -> List[Dict[Text, Any]]:
intent = tracker.latest_message['intent'].get('name')
print(intent)
pin_code = tracker.get_slot("pin_code")
print(pin_code)
category = tracker.get_slot("category")
if intent == "corona_help":
dispatcher.utter_message(response="utter_ask_confirm_pin_code")
return {"confirm_pin_code": None, "confirm_category": None}
class ActionSubmit(Action):
def name(self) -> Text:
return "action_submit"
def run(
self,
dispatcher,
tracker: Tracker,
domain: "DomainDict",
) -> List[Dict[Text, Any]]:
pin_code = tracker.get_slot("pin_code")
category = tracker.get_slot("category")
print("HERE2")
pin_code_url = f"https://api.postalpincode.in/pincode/{pin_code}"
r1 = requests.get(pin_code_url)
data1 = json.loads(r1.content)
city = data1[0]['PostOffice'][0]['District']
print("HERE3")
city_url = "http://ec2-3-23-130-174.us-east-2.compute.amazonaws.com:8000/cities"
r2 = requests.get(city_url)
data2 = json.loads(r2.content)
cities = data2['data']
if city in cities:
city = city.replace(" ", "%20")
category = category.replace(" ", "%20")
print("HERE4")
category_url = f"http://ec2-3-23-130-174.us-east-2.compute.amazonaws.com:8000/resource?city={city}&category={category}"
r = requests.get(category_url)
data = json.loads(r.content)
data = data['data']
print(data)
if not data:
print("HERE5")
dispatcher.utter_message(text="No resources found.")
return []
# return [AllSlotsReset()]
contact = data[0]["contact"]
description = data[0]["description"]
organisation = data[0]["organisation"]
phone = data[0]["phone"]
state = data[0]["state"]
category = category.replace("%20", " ")
dispatcher.utter_message(response="utter_submit",
pin_code=pin_code,
category=category,
contact = contact,
description = description,
organisation = organisation,
phone = phone,
state = state
)
# return [AllSlotsReset()]
# elif intent == "corona_help":
else:
dispatcher.utter_message(text="No resources found.")
# return [AllSlotsReset()]
Any ideas how to achieve this?

I'm assuming the pin is most of your user_details_form. If so, one way to handle this would be to restart the user_details_form:
- rule: corona help with previous pin code
steps:
- intent: corona_help
- action: utter_ask_confirm_pin_code
- intent: affirm # they want to use previous code
- action: do_the_thing_with_old_pin_code
- rule: corona help with new pin code
steps:
- intent: corona_help
- action: utter_ask_confirm_pin_code
- intent: deny # they don't want to use previous code
- action: user_details_form
- active_loop: user_details_form
You'll probably need to override required_slots for your form to make sure that the right slot is being re-asked, you can read more about that here.

Related

How to rig a bot's command to only a certain user

I've been making this pp size machine, which is somewhat like dank memer's one
#client.command()
async def pp(ctx,member : discord.Member):
size=random.randint(1,10)
message = "8"
for x in range (size):
message= message + "="
if x == size-1:
message = message + "D"
if member == "PROTATO#6826":
message = "8D"
ppsize = discord.Embed(color=discord.Colour.orange(), title=f"PP size",description=f"""{member}'s penis
{message} """)
await ctx.send(embed = ppsize)
But i want to rig the command for a certain user to only show "8D" instead of the random lengths.
But no matter what it is the
if member == "PROTATO#6826":
message = "8D"
code doesnt run or gets over looked?
Can someone help me out with this?
You can check if the member mentioned has the same id as a specific user. You can either enable developer mode on discord, or you can print the member.id at the very beginning. Do view a code example below.
#client.command()
async def pp(ctx, member: discord.Member):
print(member.id) # this would print a user's unique id
message = "Hey!"
if member.id == 394506589350002688: # replace this id with what was printed at the start
message = "Hello!"
await ctx.send(message)
Similar Questions:
How to check if message was sent by certain user? - SO
How do I detect if the message is sent by a specific user id? - SO

How to detect the end_interaction signal using the dialogflow_cx python library?

I am using the DialogFlow CX python library for an agent integration. Once I send a request through detect_intent, I want to be able to check in the response for a flag that determines if the interaction with the agent has ended.
For this, I found a property within the ResponseMessage data type response called end_interaction. I tested this with one of my agents, and effectively once the interaction ends, I can see the end_interaction within the array of response messages:
# inspecting query_result.response_messages
[
text {
text: "Goodbye."
},
end_interaction {
}
]
Now, the problem is that I want to trigger some actions whenever we receive the signal, but since the end_interaction field is being sent empty whenever I try to check it returns me False:
# Both response messages from the example above return False under a bool
bool(query_result.response_messages[0].end_interaction) == False # text message response
bool(query_result.response_messages[1].end_interaction) == False # end_interaction signal
I have tried many things, such as checking with isinstance and hasattr, but they return True for all scenarios since the ResponseMessage data type always has an end_interaction attr.
Any help for finding how to detect and check for this signal is highly appreciated! Thanks!
To detect and check for the end_interaction field, you can use the following in your detect_intent:
any("end_interaction" in d for d in response.query_result.response_messages)
Please note that this will return True if the end_interaction field is found in the response_messages list and False if not. You can use this to determine if the interaction with the agent has ended.
Here is a python sample code of the detect_intent with the end_interaction field for your reference:
def detect_intent_texts(agent, session_id, texts, language_code):
session_path = f'{agent}/sessions/{session_id}'
print(f"Session path: {session_path}\n")
client_options = None
agent_components = AgentsClient.parse_agent_path(agent)
location_id = agent_components["location"]
if location_id != "global":
api_endpoint = f"{location_id}-dialogflow.googleapis.com:443"
print(f"API Endpoint: {api_endpoint}\n")
client_options = {"api_endpoint": api_endpoint}
session_client = SessionsClient(client_options=client_options)
for text in texts:
text_input = session.TextInput(text=text)
query_input = session.QueryInput(text=text_input, language_code=language_code)
request = session.DetectIntentRequest(
session=session_path, query_input=query_input
)
response = session_client.detect_intent(request=request)
print("=" * 20)
print(f"Query text: {response.query_result.text}")
response_messages = [
" ".join(msg.text.text) for msg in response.query_result.response_messages
]
print(f"Response Messages:\n {response.query_result.response_messages}")
print(f'End of interaction: {any("end_interaction" in d for d in response.query_result.response_messages)}')
Here is the result:

'RawReactionActionEvent' object has no attribute 'author Issue with adding a cooldown on event

I'm trying to add a cooldown to a on_raw_reaction_add event in discord.py. I'm trying to do this by using cooldown mapping. The result should be to limit how many times this message
embed.description = f"It looks like you're joining us on a newly registered account. Verification requires accounts to be atleast a day old so please stick around and try again at {test_time.time().strftime(format)}."
is sent to a user if they don't meet the account age upon adding a reaction, which should be one reaction before the cooldown kicks in.
The error I get is 'RawReactionActionEvent' object has no attribute 'author not sure why this is happening.
Here is the full code I'm working with:
#commands.Cog.listener()
async def on_raw_reaction_add(self, payload): # Will be dispatched every time a user adds a reaction to a message the bot can se
general = self.bot.get_channel(701547632354525249)
introductions = self.bot.get_channel(705068046267580566)
botroom = self.bot.get_channel(706610280032894996)
if not payload.guild_id:
# In this case, the reaction was added in a DM channel with the bot
return
guild = self.bot.get_guild(payload.guild_id)
author = guild.get_member(payload.user_id)
bucket = self._cd.get_bucket(payload)
retry_after = bucket.update_rate_limit()
seconds = bucket.update_rate_limit()
seconds = round(seconds, 2)
hours, remainder = divmod(int(seconds), 3600)
minutes, seconds = divmod(remainder, 60)
if retry_after:
verification_error = f"You can do that again in **{minutes}m {seconds}s**."
embed = discord.Embed(title="You have already verified.", description=verification_error, colour=discord.Colour(0xff8100))
await message.channel.send(embed=embed)
pass
if payload.message_id != 743841858727444550:
return
else:
guild = self.bot.get_guild(payload.guild_id) # You need the guild to get the member who reacted
member = guild.get_member(payload.user_id) # Now you have the key part, the member who should receive the role
if payload.emoji.id != 743077610115956816:
reaction = payload.emoji.id
role = discord.utils.get(guild.roles, name="Members")
newbies = discord.utils.get(guild.roles, name="Newbies")
restricted_role = discord.utils.get(guild.roles, name="Restricted")
role = discord.Object(743840972068356116) # Pass the role's ID here
else:
return
if restricted_role in member.roles:
return
if member.created_at + dt.timedelta(days=30) <= dt.datetime.today():
await member.add_roles(role, reason='New member verified') # Finally add the role to the member
await member.add_roles(newbies, reason='New member verified') # Finally add the role to the member
welcome = f'Welcome {member.mention}! feel free to get started with adding some <#706648361196978177>'
intros = f'Hey {member.mention}! now that you\'re a member of our group, maybe you\'d like to tell us a bit about yourself. Tell us an interesting fact about yourself and so on... As always keep it sensible and fun.'
await general.send(welcome)
sent = await introductions.send(intros)
await asyncio.sleep(900)
await sent.delete()
else:
format = '%I:%M%p'
member1 = member.created_at.strftime("%I:%M%p")
dt3 = dt.datetime.strptime(member1, format)
test_time = dt3 + dt.timedelta(minutes = 1500)
embed = discord.Embed(colour=discord.Color(0x7289DA))
embed.title = f"Hey there {member.display_name}!"
embed.description = f"It looks like you're joining us on a newly registered account. Verification requires accounts to be atleast a day old so please stick around and try again at {test_time.time().strftime(format)}."
await member.send(embed=embed)
Help would be appreciated.
Under your #client.command statement just add
#commands.cooldown(1, 30, commands.BucketType.user)
This example will give a single user a cool down of 30 seconds for 1 use. You can configure BuckType to channel and server as well.

How to take input inside a running action in RASA

Suppose I’ve a running action that generates a list of dynamic buttons to the user. Generally, the button inputted from the user is going to NLU. But I want to know which button the user just picked and act accordingly in this running action. For example, If the user chose “Toyota” I want to call another action from this running action. All I want is not to go to NLU and not to check there. I want everything in my running action. Is it possible? If so, can someone provide the way I can approach?
My action class is given below.
> class ActionVehicleManufacture(Action):
> def name(self):
> return "action_vehicle_manufacturer"
>
> def run(self, dispatcher: CollectingDispatcher,
> tracker: Tracker,
> domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
>
> r = requests.get('http://mind.zantrik.com/api/A1/GetVehicleManufacturer')
> response = r.text
> json_data = json.loads(response)
> l = []
> buttons = []
> for i in json_data["data"]:
> l.append(i["manufacturerName"])
> for i in l:
> buttons.append({"title": i, "payload": i})
>
> dispatcher.utter_message(text="Please let me know you car manufacturer name:", buttons=buttons)
> # I want to apply some condition here according to users inputted button.
> return []
To call an action after a new user message (e.g, selection of a button or free text) you need to include a story in you storied.md. Which action is arbitrary. For example:
## story example
* ask_about_manufacturers
- action_vehicle_manufacturer
* inform{"manufacturer": "toyota"}
- action_execute
If you have defined manufacturer as a slot, the type of the slot influences the stories. If you have seen Slots Set By Clicking Buttons, to set the slot manufacturer you need to do instead of
buttons.append({"title": i, "payload": i})
the following, where intent is the intent that captures the message "toyota", in the story example above "inform".
buttons.append({"title": i, "payload": f"""/{intent}{{"manufacturer": "i"}}""")

How to get the JIRA ticket number using Jenkins Declarative script

How to get the JIRA ticket number using Jenkins Pipeline script Example:
CICD-34
The following command gives complete info about the ticket, but how do we get just the ID and store in a variable?
def issue = jiraJqlSearch jql: 'PROJECT = CICD AND description~"New JIRA Created from Jenkins through Declarative PL script"', site: 'MyLocalJira'”
echo issue.data.toString()
I have the same problem and find a solution.
I share with you my answer :)
def testExecutionSearch = jiraJqlSearch jql: "project=${project} and issuetype = 'Test Execution' and summary ~ '${summary}'", site: 'myjira', failOnError: true
if (testExecutionSearch != null){
//Get all issues
def issues = testExecutionSearch.data.issues
//Get the key of the first result
def key = issues[0].key
}
Here I take the first element of my jql search (def key = issues[0].key) but you can choose what you want :)

Resources