Restart a conversation in Dialogflow - python

Hello stack overflow community,
I would like your help in the following problem:
Currently I am running a Dialogflow chatbot that has some intents and gives back some responses. The chat bot works perfectly until now. For your information, I use webhook to get back responses.
Here is a screenshot of my intents flow: dialogflow chatbot
What I struggle to do is to give the user the opportunity to rerun the whole conversation from the start. Do you know how can I achieve this in Dialogflow?
Python code snippet to run webhook:
app = Flask(__name__)
# default route
#app.route('/')
def index():
return 'Chatbot is online and running!'
#app.route('/webhook', methods=['GET', 'POST'])
def webhook():
# return response
req = request.get_json(force=True, silent = True)
action = req.get('queryResult').get('action')
intent_name = req.get('queryResult').get('intent').get('displayName')
if action == "get_results" and intent_name == 'KellyMovieBot':
return make_response(jsonify(suggest_movie(req)))
elif action == "ask_question" and intent_name == 'ask_first_time':
return make_response(jsonify(propose_second_movie(req)))
elif action == "thanks_giving_end" and intent_name == "thanks_giving":
return make_response(jsonify(thanks(req)))
elif action == "rerun_conversation" and intent_name == "rerun_conversation":
user_answer = req.get('queryResult').get('parameters').get('user_answer')
if user_answer == "No" or user_answer == "no":
return {'fulfillmentText': "Enjoy your film!"}
elif user_answer == "Yes" or user_answer == "yes":
return {'fulfillmentText': "Let's start again..."}
# run the app
if __name__ == '__main__':
app.run()
Note: The functions suggest_movie(), propose_second_movie(), thanks() are three functions that have been created in order to return 3 different outputs based on the communication flow.
What I want is find the correct syntax that will allow me to RERUN the whole conversation again if the user says 'Yes' else Dialogflow should end the conversation.
I would appreciate any help or advise you can give me!

You can do this by sending a follow-up event rather than a response. In this case when the user responds with yes, in your code, you'd return:
{
"followupEventInput": {
"name": "KellyMovieBot",
"languageCode": "en-US"
}
}
Make sure your KellyMovieBot intent has the same event name. You don't have to use the specified value, but the event name as sent in the response should also match the event name as configured on the intent.
https://cloud.google.com/dialogflow/docs/events-custom#invoke_event_from_webhook

Related

extend dialogflow webhook deadline time for gpt api call

I am trying to use a script I found on the internet to extend the maximum time for a webhook request through Google Dialogflow (max 5 seconds to timeout). I need to extend the time because I make an API call to openai and it sometimes takes longer than 5 seconds. My idea was to start the 2 functions in parallel. The broadbridge_webhook_results() function is there to extend the time by triggering a followupEventInput at Dialogflow after 3,5 seconds, so a new call comes through Dialogflow and the 5 seconds start from new. This goes apparently up to 2 times. In the meantime the API call should be made towards openai. As soon as the API call was successful, the answer should be sent back to Dialogflow. Unfortunately, I am currently not getting anywhere and I think that the thread functionality was set up or understood incorrectly by me.
The following code I have so far:
import os
import openai
import time
import backoff
from datetime import datetime, timedelta
from flask import Flask, request, render_template
from threading import Thread
import asyncio
app = Flask(__name__)
conversation_History = ""
user_Input = ""
reply=''
answer = ""
#app.route('/')
def Default():
return render_template('index.html')
#backoff.on_exception(backoff.expo, openai.error.RateLimitError)
def ask(question):
global conversation_History
global answer
global reply
openai.api_key = os.getenv("gtp_Secret_Key")
#start_sequence = "\nAI:"
#restart_sequence = "\nHuman: "
response = openai.Completion.create(
model="text-davinci-003",
prompt="I am a chatbot from OpenAI. I'm happy to answer your questions.\nHuman:" + conversation_History + " "+ question +"\nAI: ",
temperature=0.9,
max_tokens=500,
top_p=1,
frequency_penalty=0,
presence_penalty=0.6,
stop=[" Human:", " AI:"]
)
conversation_History = conversation_History + question + "\nAI" + answer + "\nHuman:"
answer = response.choices[0].text
def broadbridge_webhook_results():
global answer
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
print("Current Time =", current_time)
extended_time = now + timedelta(seconds=3)
print("extended Time =", extended_time.time())
req = request.get_json(force=True)
action = req.get('queryResult').get('action')
reply=''
if action=='input.unknown' or action=='input.welcome':
time.sleep(3.5)
if now<=extended_time and not len(answer) == 0:
reply={
"fulfillmentText": answer,
"source": "webhookdata"
}
reply={
"followupEventInput": {
"name": "extent_webhook_deadline",
"languageCode": "en-US"
}
}
if action=='followupevent':
print("enter into first followup event")
time.sleep(3.5)
if now<=extended_time and not len(answer) == 0:
reply={
"fulfillmentText": answer,
"source": "webhookdata"
}
reply={
"followupEventInput": {
"name": "extent_webhook_deadline_2",
"languageCode": "en-US"
}
}
if action=='followupevent_2':
print("enter into second followup event")
time.sleep(3.5)
reply={
"fulfillmentText": answer,
"source": "webhookdata"
}
print("Final time of execution:=>", now.strftime("%H:%M:%S"))
#app.route('/webhook', methods=['GET', 'POST'])
def webhook():
global answer
global reply
answer=""
req = request.get_json(silent=True, force=True)
user_Input = req.get('queryResult').get('queryText')
Thread(target=broadbridge_webhook_results()).start()
Thread(target=ask(user_Input)).start()
return reply
#conversation_History = conversation_History + user_Input + "\nAI" + answer + "\nHuman:"
#if now<=extended_time and not len(answer) == 0:
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
Dialogflow supports increasing the webhook execution time limit up to 30 seconds by increasing the webhook execution time limit. This is done through the "extend_webhook_deadline" setting in the Dialogflow agent configuration file.
To enable this setting you will need to do the following:
Access the Dialogflow Console
Select the agent for which you want to enable the setting
Click "Settings" on the left sidebar
Click "Export and Import"
Select "Export as ZIP"
Locate the "agent.json" file inside the downloaded ZIP file
Open the "agent.json" file with a text editor
Locate a "greeting" section
Add the following line "extend_webhook_deadline": true
Save the changes and import the "agent.json" file back into Dialogflow
Bear in mind that by enabling this setting, Dialogflow will charge an additional fee to increase the duration of the webhook.

Python Telegram Bot is not Ideling on Heroku

I am using heroku to deploy my telegram bot. I am using free dynos. So, to save dyno hours I want my app to go idle after 30 mins of inactivity which it should.
https://www.heroku.com/dynos
But, my app get random GET requests after 25mins or so. So, my app never goes to idle.
Note:
My app is not yet on production so I cannot figure out why I am getting ping every 25min.
here is my code:
import telegram.ext
import bot
from config import TOKEN,PORT
def start(update,context):
id = update.message.chat.id
if(id == (hidden) or id == (hidden)):
update.message.reply_text("Welcome! to Football Story Bot")
else:
update.message.reply_text("""
We have detected unusual request from your device.
You have been banned from the service until further notice,
""")
def help(update,context):
id = update.message.chat.id
if(id == (hidden) or id == (hidden)):
update.message.reply_text("""
The following commands are available:
/start -> Welcome Message
/help -> This Message
/streams -> list of matches
""")
else:
update.message.reply_text("""
We have detected unusual request from your device.
You have been banned from the service until further notice,
""")
def streams(update,context):
id = update.message.chat.id
if(id == (hidden) or id == (hidden)):
update.message.reply_text("Searching for available matches")
all_matches_name_list = bot.all_matches_name()
link_str=''
if(all_matches_name_list==None):
update.message.reply_text("We are experiencing problem.Try again later, if problem persists then contact admin")
return None
for links in all_matches_name_list:
link_str+=links+'\n'
update.message.reply_text(link_str)
update.message.reply_text("End Of Detected Matches")
else:
update.message.reply_text("""
We have detected unusual request from your device.
You have been banned from the service until further notice,
""")
def handle_message(update,context):
id = update.message.chat.id
if(id == (hidden) or id == (hidden)):
update.message.reply_text("Searching for available streams")
link_str=''
sending_message=''
for chars in update.message.text:
if(chars=='#'):
break
sending_message+=chars
individual_link = bot.selected_match(bot.all_matches_name(),sending_message)
if(individual_link==None):
update.message.reply_text("We are experiencing problem.Try again later, if problem persists then contact admin hai tw")
return None
if(len(individual_link)==0):
update.message.reply_text("No links found. Links are updated 30min before match. If link is not found till Kick Off then contact admin")
return None
for links in individual_link:
link_str+=links+'\n\n'
update.message.reply_text(link_str)
update.message.reply_text("End Of Streaming Links")
else:
update.message.reply_text("""
We have detected unusual request from your device.
You have been banned from the service until further notice,
""")
updater = telegram.ext.Updater(TOKEN,use_context=True)
disp = updater.dispatcher
disp.add_handler(telegram.ext.CommandHandler("start",start))
disp.add_handler(telegram.ext.CommandHandler("help",help))
disp.add_handler(telegram.ext.CommandHandler("streams",streams))
disp.add_handler(telegram.ext.MessageHandler(telegram.ext.Filters.command,handle_message))
updater.start_webhook(listen="0.0.0.0",
port=PORT,
url_path=TOKEN,
webhook_url="(my app link)" + TOKEN)
updater.idle()

Attempting to create a Python Chat System with a Lobby, Random Connect Function, and Encryption

EDIT
I am currently working on a chat system based on Python. I posted a question below, however have edited it to be more narrow as to what I am looking for. The system has a default function that whenever is typed in in a LOGGED_IN state, if it is not a command, the menu of the chat system is shown.
My problem is that I am working on a random function, and despite the function existing, the menu keeps appearing, I suspect the client side code to be at fault here but I cannot seem to spot my error, here is an excerpt of the code, the full file is linked below:
elif my_msg[0:6]=="random":
mysend(self.s,json.dumps({"action":"random"}))
allresults = json.loads(myrecv(self.s))["results"]
result = allresults[0]
user=allresults[1]
if result: #==True
self.out_msg+="Peer Found\n"
self.out_msg+="Connecting you now...\n\n"
self.out_msg+='-----------------------------------\n'
if self.connect_to(user) == True:
self.state = S_CHATTING
if my_msg[7:]=="anon":
self.out_msg += 'Connected to anonymous user. Chat away!\n\n'
else:
self.out_msg += 'Connect to ' + user + '. Chat away!\n\n'
self.out_msg += '-----------------------------------\n'
else:
self.out_msg += 'An error occurred, please try again.\n'
else:
self.out_msg+="Peer not found, please try again later"
Any help is greatly appreciated, I am currently debugging but figured someone might see something I don't
END EDIT
I am currently working on a chat system based on Python with some friends just to learn more about the inner workings. Some of the key features we have been trying to implement and work with are: - a lobby (a chatroom that people can always tune into) - a random connection function (that randomly connects users together, sort of like omegle) - and encryption. This last bit does not have to be super sophisticated but if you have any recommendations how to make it better I would be happy to hear them.
The files are located here and I would greatly appreciate any feedback or insight into the bugs that are occurring for the lobby and random functions!
Note: the files to consider are:
chat_lobby.py (Lobby chatroom Class)
chat_group.py (General Group Chat Class)
chat_server_student.py (Server side)
client_state_machine_student.py (Client side)
Below is the random function from the server side
elif msg["action"]=="random":
name=self.logged_sock2name[from_sock]
self.availableUsers = self.group.listloners()
self.consent = False
while (len(self.availableUsers)>0 and self.consent != True):
to_name = random.choice(availableUsers)
to_sock = self.logged_name2sock[to_name]
mysend(to_sock, json.dumps({"action":"consent"}))
#waiting for response
self.consent= json.loads(myrecv(self.s))["consent"]
if self.consent == True:
result= True
user = self.logged_sock2name[to_sock]
else:
result = False
user = ""
self.availableUsers.remove(to_name)
mysend(from_sock, json.dumps({"action":"random", "results":[result,user]}))
and here is the random function from the client side:
elif my_msg[0:6]=="random":
mysend(self.s,json.dumps({"action":"random"}))
allresults = json.loads(myrecv(self.s))["results"]
result = allresults[0]
user=allresults[1]
if result: #==True
self.out_msg+="Peer Found\n"
self.out_msg+="Connecting you now...\n\n"
self.out_msg+='-----------------------------------\n'
if self.connect_to(user) == True:
self.state = S_CHATTING
if my_msg[7:]=="anon":
self.out_msg += 'Connected to anonymous user. Chat away!\n\n'
else:
self.out_msg += 'Connect to ' + user + '. Chat away!\n\n'
self.out_msg += '-----------------------------------\n'
else:
self.out_msg += 'An error occurred, please try again.\n'
else:
self.out_msg+="Peer not found, please try again later"
and
if len(peer_msg) > 0:
peer_msg = json.loads(peer_msg)
consent=False
if peer_msg["action"] == "connect":
self.connect_to(peer_msg["from"])
self.set_state(S_CHATTING)
elif peer_msg["action"]=="consent":
self.out_msg += "A random user wants to connect with you?\n"
self.out_msg += "Would you like to accept the connection? (y or n)\n"
while my_msg != "y" and my_msg!="n":
self.out_msg += "Please only reply with 'y' or 'n'\n"
if my_msg=="y":
self.connect_to(peer_msg["from"])
self.set_state(S_CHATTING)
consent=True
mysend(self.s,json.dumps({"message":consent}))
self.out_msg+="Connecting you now...\n\n"
else:
consent=False
mysend(self.s, json.dumps({"action":"random", "consent":consent}))
My system works normally as is, just these parts are difficult to get around.
Additionally the "lobby" file and functions in the server and client files don't fully function, yet I am having difficulty finding the bug myself.

Can't receive update messages from user

I am trying to create a bot that receives a response from the user and asks again if needed. The problem is that after:
update.reply_text("Did you report all you working hour on freshdesk for this week?, ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
I can't get the new updates. The message text remains /start in the first print, and the second print doesn't work at all.
How can I get correctly the response from the user? Can it be an issue related to ReplyMarkup?
def check_the_week(bot, update):
agent_username = update.message.from_user['username']
parameters = {"username": agent_username}
url = "{}/weekly_hours/".format(API_URL)
report = get_request_forwarder(url=url, method="GET", parameters=parameters)["messages"]
reply_keyboard = [['YES', 'NO']]
bot.send_message(
chat_id=update.message.chat_id,
text=report,
reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)) # sends the total nr of hours
print update.message.text
update.reply_text("Did you report all you working hour on freshdesk for this week?",
ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
print update.message.text
if update.message.text == "YES":
update.message.reply_text(text="Are you sure?", reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
# Asks confirmation
if update.message.text == "YES":
update.message.reply_text(text="Thank you for reporting your working hours in time!")
elif update.message.text == "NO":
update.message.reply_text(text="Please, check you time reports and add missing")
elif update.message.text == "NO":
update.message.reply_text(text="Please, check you time reports and add missing")
def main():
# Create the EventHandler and pass it your bot's token.
updater = Updater(TELEGRAM_TOKEN)
j = updater.job_queue
# # Get the dispatcher to register handlers
dp = updater.dispatcher
# # Start the Bot
dp.add_handler(CommandHandler("start", check_the_week))
# Send information to manager by command
updater.start_polling()
updater.idle()
print("bot started")
if __name__ == '__main__':
main()
Because you are using a CommandHandler, which is only used to capture a single command at a time.
What you want to do can be achieved by using a ConversationHandler. Please read the example scripts here and here. Also you can read more details on the handler here.

Getting request.form to act like raw_input in a text adventure game (twilio)

----------------------- EDIT -----------------------
I still am not sure how to get the request.form['Body'] working properly. I am likely not using this request properly, but I'm not sure how else to use it. One suggestion was make a listener, but am not sure where to start on that.
So I guess now its:
1) where am I totally buggering up?
2) Any suggestions on how to make a listener?
Here's a skeleton of my set up:
from flask import Flask, request, redirect
import twilio.twiml
from twilio.rest import TwilioRestClient
from sys import exit
twil_number = "XXXXXXXXX"
sid = "XXXXXXXXXXXXXXXXXXXX"
token = "XXXXXXXXXXXXXXXXX"
tos = "XXXXXXXXXX"
client = TwilioRestClient(sid,token)
app = Flask(__name__)
#app.route("/", methods=['GET', 'POST'])
##### get the SMS ####
def smsGet():
try:
action = request.form['Body']
except RuntimeError:
action = raw_input("> ")
return action.lower()
### Snd the SMS ####
def smsSend(bods):
client.sms.messages.create(to=tos, from_=twil_number, body= bods)
class TestClass(object):
def doStuff(self):
smsSend("Intro Text")
## I don't know why this is buggering up. ###
go = smsGet()
if go == "yes":
smsSend("yes")
exit(1)
else:
pass
exit(1)
a = TestClass()
a.doStuff()
#### running the app ###
if __name__ == "__main__":
app.run(debug=True)
----------------------- older -----------------------
I'm making a text adventure game in twilio/python. There's no database or anything, Its just a python based text adventure that I run locally out of a shell.
All the sending SMS things are fine, but how do I get something like this:
request.form['Body'].lower()
to work like this:
raw_input("> ").lower()
So far most things I've tried just have Flask throwing this error:
RuntimeError('working outside of request context')
So for context. A lot of my scenes are set up like this:
class Hallway(Scene):
def enter(self):
hall = "You pause in the Hallway. You could: Go to the bedroom. Go to the kitchen to see if there's food. Check on your human in the office."
send_sms(hall)
#action = raw_input("> ").lower()
#would like this to work like raw _input()
action = request.form['Body'].lower()
if action == "kitchen":
return 'kitchen'
elif action == "bedroom":
return 'bedroom'
elif action == "office":
return 'office'
else:
nope = "But I don't want to hang in the hallway..."
send_sms(nope)
return 'hallway'
And send_sms() is just this:
def send_sms(bods):
client.sms.messages.create(body=bods,to=tos,from_=froms)
Any suggestions on where I'm totally mucking up?
Thanks! :)
So, if I understand what you're trying to do correctly, you probably want something like this (note that I haven't run this, so it may have some small bugs, but the idea should be sound):
listener.py
from flask import Flask, request
from twilio.rest import TwilioRestClient
import twilio.twiml
import game
account_sid = "ACXXXXXXXXXXXXXXXXX"
auth_token = "YYYYYYYYYYYYYYYYYY"
twilio_client = TwilioRestClient(account_sid, auth_token)
app = Flask(__name__)
games = {}
#app.route("/", methods=['GET', 'POST'])
def accept_response():
from_number = request.values.get('From')
body = request.values.get('Body')
try:
games[from_number].queue.put(body)
except KeyError:
games[from_number] = game.Game(twilio_client, from_number, "your number goes here")
games[from_number].start()
return str(twilio.twiml.Response())
if __name__ == "__main__":
app.run(debug=True)
game.py
import queue
from threading import Thread
class Game(Thread)
def __init__(self, twilio, to_number, from_number):
Thread.__init__(self, name=to_number)
self.twilio = twilio
self.from_number = from_number
self.to_number = to_number
self.queue = queue.Queue()
def run(self):
# Game logic goes here, e.g.:
action = self.send_sms("You're being chased by a thing!", wait_for_response=True)
if action == "stop":
self.send_sms("That was silly. The thing eats you, you die.")
elif action == "run":
self.send_sms("You're too slow! The thing eats you, you die.")
else:
self.send_sms("I don't know what you're trying to do, but the thing eats you, you die.")
def send_sms(self, body, wait_for_response=False):
self.twilio.messages.create(body=body, to=self.to_number, from_=self.from_number)
if wait_for_response:
response = self.queue.get()
return response
So, you run the listener, and with the correct configuration on the Twilio side it just sits there and listens for SMSs. When it receives one it checks to see if a game is already running for the user. If so, it sends the body of the SMS to the game, to be used as input. Otherwise, it kicks off a new game for that user.
Each Game instance is running in it's own thread, and you can use the send_sms method of a Game instance just like raw_input, that is, the user for that game will receive the string argument as an SMS, and their reply will be the return value.
I don't know what the rest of your game logic looks like, but to integrate this with something like the Scene class in your question, you would probably want to have Scene's consructor take a Game as an argument and assign it to an attribute. So, then, in enter() you could write something like action = this.game.send_sms('foo').
It appears you can get the current thread object using threading.current_thread() (which in this case is the Game instance), so there's no need to pass it around. You can either call threading.current_thread().send_sms from anywhere, or wire it up in the constructor of your scenes.
If you want to run that code from either inside Flask or from the command line, you'll need to write a function which will get the action, either from the request or using raw_input. It could look something like this:
from flask import request
def get_action():
try:
action = request.form['Body']
except RuntimeError:
action = raw_input("> ")
return action.lower()

Categories

Resources