How to create context for the chatbot using twilio - twilio

I am trying to create a bot where when ever someone send a message about a type of food to the bot, then the bot will respond with the location that serves that food. However I am trying to establish context so that the conversation can flow more thoroughly.
I have tried nesting the if statement, and it gets it to display the message, but it would have to rely on the if-statement prior to be true before testing for the ones that comes after.
from flask import Flask, request
from twilio.twiml.messaging_response import MessagingResponse
from intents import fallback_intent, getLocation
import random
app = Flask(__name__)
location_fallback = ['What kind of restaurant are you seeking?', 'What kind? Nearby, Cheap or The best?']
welcome = ['hello', 'what\'s up', 'hey','hi', 'what\'s happening?']
near = ['near', 'nearby']
cheap = ['cheap', 'good for my pockets']
good = ['good', 'top rated']
intro_resp = ['''Hey! Welcome to Crave! This interactive platform connects you to the top foodies in the world! We provide you with the best food places where ever you are. The instructions are simple:
1. Save our number in your Phone as Crave.
2. Text us and tell us what type of food you are craving!
This is from python''', '''
Welcome to Crave! Are you ready to get some food for today?
1. Save our number in your Phone as Crave.
2. Text us and tell us what type of food you are craving!
''']
#app.route('/sms', methods=['GET','POST'])
def sms():
num = request.form['From']
msg = request.form['Body'].lower()
resp = MessagingResponse()
#welcome intent
if any(word in msg for word in welcome):
if any(near_word in msg for near_word in near):
resp.message('These are the location of places near you!')
print(str(msg.split()))
return str(resp)
elif any(cheap_word in msg for cheap_word in cheap):
resp.message('These are the location of places that are low cost to you!')
return str(resp)
elif any(good_word in msg for good_word in good):
resp.message('These are the best places in town!')
return str(resp)
else:
location_fallback[random.randint(0,1)]
resp.message(intro_resp[random.randint(0, 1)])
print(str(msg.split()))
return str(resp)
else:
resp.message(fallback_intent())
print(str(msg))
return str(resp)
if __name__ == '__main__':
app.run(debug=True)
I want the user to say 'hi'' or something related to initiate the bot, then I want the bot to prompt the user to ask what kind of food they would like. Then the bot will ask what parameters for the restaurant they would like(i.e Close, cheap, or good). Then the user will answer accordingly, and then the bot needs to use these parameters to search for the restaurant near them with these attributes.

Twilio developer evangelist here.
You could store this in many places, in cookies as part of the conversation with Twilio, in a database where you use the user's number as a key to look up previous messages, or even just in memory.
If you're looking for a more robust way to achieve this, with better natural language processing, have you checked out Twilio Autopilot? It stores the context of a conversation for you and is built to collect information before giving a response based on the complete set like you are doing.

Related

Is it possible to call an URL passing website parameters?

I am writing code for a custom SAP program regarding some Vendor information. In my program flow, there is a possibility of me trying to use a Vendor VAT Number that belongs to an unknown Vendor. There is a Web site (EU Based - https://ec.europa.eu/taxation_customs/vies/) for such purposes that requires a country key and the specified VAT Number in order for it to provide an answer with the available Company information (only works for company VAT numbers of course). My problem is that I cannot seem to find any way to pass those parameters dynamically to the Web site without needing the user to interfere during this process. Manually, the process would be to select a country key, type in a VAT number and press 'Verify'.
Is there any way for me to call this specific Web site URL and "bypass" this process to only display the result page? For now, I'm using the following Function Module to just call the specified URL, in lack of any better choices.
call function 'CALL_INTERNET_ADRESS'
exporting
pi_adress = 'https://ec.europa.eu/taxation_customs/vies/'
exceptions
no_input_data = 1
others = 2.
You can use CL_HTTP_CLIENT class or HTTP_POST/HTPP_GET FM.
You need to install given web page SSL root certificate to your system with STRUST t-code.
Example usage of CL_HTTP_CLIENT below.
DATA: lv_url TYPE string VALUE 'http://mkysoft.com/ip.php'.
DATA: o_client TYPE REF TO if_http_client.
DATA: lv_http_rc TYPE i.
DATA: lv_reason TYPE string.
DATA: lt_fields TYPE tihttpnvp.
TRY.
cl_http_client=>create_by_url( EXPORTING
url = lv_url
IMPORTING
client = o_client
EXCEPTIONS
OTHERS = 0 ).
o_client->request->get_header_fields( CHANGING fields = lt_fields ).
o_client->request->set_header_field( name = '~request_uri' value = '/ip.php' ).
o_client->request->set_header_field( name = '~host' value = 'mkysoft.com' ).
o_client->request->set_method( if_http_request=>co_request_method_get ).
o_client->send( ).
o_client->receive( ).
o_client->response->get_status( IMPORTING
code = lv_http_rc
reason = lv_reason ).
* Error check
IF lv_http_rc = 200.
DATA(lv_xml) = o_client->response->get_cdata( ).
* Handle error
ELSE.
WRITE: / 'Fehler: ', lv_http_rc.
ENDIF.
o_client->close( ).
CATCH cx_root INTO DATA(e_txt).
WRITE: / e_txt->get_text( ).
ENDTRY.
EU Commission has a SOAP service for vat numbers.
See the info page
https://ec.europa.eu/taxation_customs/vies/technicalInformation.html
and that it even supports http
http://ec.europa.eu/taxation_customs/vies/checkVatTestService.wsdl
You have a non screen scrape method, proper interface you should look at.
On the other point of Avoiding SSL.
Make a basic guide for customers to add the European commission cert to their SAP system. If someone is complaining about that, then they are a serious user of the internet. Every sap on premise user, that needs to call the internet adds certs.
Http is dead....

Is there a way to get the last chat massage in shout or say?

I want to search the last message for a few strings and then echo the message back with those strings replaced with other strings.
I searched multiple documentations but didn't find a way to get the last message.
This is the first forum I ask as I already have an account so have no real starting point to give you.
Thanks in advance!
There is no way in the WoW API to get the last chat message of a specific channel. You will have to handle the CHAT_MSG_CHANNEL event (see Event Handling) to read all messages, and store the newest one. Specifically for the say or yell (shout) channels there are the CHAT_MSG_SAY and CHAT_MSG_YELL events respectively.
To do this your addon needs to own a Frame, these frames can register event handlers and you will have to store the last message you receive from that handler in a local variable in your script (let's call it last_message). Then when your other piece of code executes you can read the last_message variable:
local frame = CreateFrame("FRAME", "FooAddonFrame");
local last_message = nil;
frame:RegisterEvent("CHAT_MSG_CHANNEL");
local function eventHandler(self, event, ...)
-- Look up the arguments that are given to your specific event
-- and assign them to variables in order by retrieving them from
-- the `...` variable arguments
local msg, author, language, channel = ...
print("Hello World! Hello " .. event);
last_message = msg
end
frame:SetScript("OnEvent", eventHandler);

How to make a Bot listen to a conversation in the background, but respond only if his name is quoted in a sentence

I am developing a ChatBot for Telegram named "Joker". It works perfectly in a private conversation. Has a whole training set up to answer several questions. But when placed in a group, it responds to all messages sent to the group, creating a chat disorder. It would be nice if my Bot could hear the group talk in the background and intervene only if his name "Joker" is quoted in one sentence. He would normally answer the questions as long as the word "Joker" was contained in the sentence. For this reason, I am trying to implement this feature, but it does not work as it should.
Current Reaction
Gillan: Good morning guys!
Mitzi Dupree: Good morning, Gillan!
... Joker is typing
Gillan: Good morning, Joker!
... Joker is typing
Gillan: Joker?
... Joker is typing
Communication.py
def respond(self, message):
"""
Receive message from user and returns corresponding answer.
"""
if re.search("joker", message, re.IGNORECASE):
joker_in_message = True
else:
joker_in_message = False
message_without_joker = re.sub(r'\bjoker\b', '', message, flags=re.IGNORECASE)
#remove duplicate spaces
message_without_joker = re.sub(r'\s{2,}', ' ', message_without_joker)
if joker_in_message and len(message) > 50 and self.watson_usage:
top_answer = get_analysis(message_without_joker)
return f"Hmm, you're talking about {top_answer}"
if joker_in_message and len(message.strip()) == len("joker"):
return "Something wrong is not right, text me what "\
"you told my creators!" \
"Type /info to learn more."
elif joker_in_message:
return self.comm.get_response(self.clean(message_without_joker))
Application.py
def text_message(self, bot, update):
self.send_type_action(bot, update)
if not self.check_for_emotion(update):
message = update.effective_message.text
answer = self.comm.respond(message)
if answer:
update.effective_message.reply_text(answer)
return 0

getAdGroupBidLandscape returning no campaigns found

I'm trying to use the Google AdWords bid simulator system to try and get some insights out of the AdWords bid simulator. More specifically I'm using the AdGroupBidLandscape() functionality, but it's returning 'No Campaigns Found', but we definitely have campaigns where the Bid Simulator tool works through the AdWords web page interface, so I'm a bit confused. Here is the code I'm running, and yes I know I'm only retrieving a single field - I'm just trying to keep things as simple as possible.
from googleads import adwords
import logging
import time
CHUNK_SIZE = 16 * 1024
PAGE_SIZE = 100
logging.basicConfig(level=logging.INFO)
logging.getLogger('suds.transport').setLevel(logging.DEBUG)
adwords_client = adwords.AdWordsClient.LoadFromStorage()
dataService = adwords_client.GetService('DataService', version='v201710')
offset = 0
selector = {'fields':['Bid'], #'impressions', 'promotedImpressions', 'requiredBudget', 'bidModifier', 'totalLocalImpressions', 'totalLocalClicks', 'totalLocalCost', 'totalLocalPromotedImpressions'],
'paging': {
'startIndex': str(offset),
'numberResults': str(PAGE_SIZE)
}
}
more_pages = True
while more_pages:
page = dataService.getAdGroupBidLandscape(selector)
# Display results.
if 'entries' in page:
for campaign in page['entries']:
print ('Campaign with id "%s", name "%s", and status "%s" was '
'found.' % (campaign['id'], campaign['name'],
campaign['status']))
else:
print 'No campaigns were found.'
offset += PAGE_SIZE
selector['paging']['startIndex'] = str(offset)
more_pages = offset < int(page['totalNumEntries'])
time.sleep(1)
We have several different accounts attachd to AdWords. My account is the only one that has developer API access, so I sort of wonder if the problem is that my account isn't the primary account associated with the campaigns- I just have one of the few administrator accounts. Can anyone provide some insights about this for me?
Thanks,
Brad
The solution I found to this problem was to add a predicate to the selector specifying a particular CampaignId. While that doesn't make any sense to me that it would fix it, because it should really just be filtering the data with that if I understand things correctly, it seems to have. I don't have a good explanation for that, but I thought someone else might find this useful. If I come to realize this wasn't the fix to the problem I had, I will come back and update this answer.

How do I implement non-blocking socket receives with ZeroMQ in Erlang or Elixir?

In Python I have the option of using a "poller" object which polls blocking sockets for messages waiting and unblocks after a specified number of milliseconds (in the case below, 1000, in the while True block):
import zmq
# now open up all the sockets
context = zmq.Context()
outsub = context.socket(zmq.SUB)
outsub.bind("tcp://" + myip + ":" + str(args.outsubport))
outsub.setsockopt(zmq.SUBSCRIBE, b"")
inreq = context.socket(zmq.ROUTER)
inreq.bind("tcp://" + myip + ":" + str(args.inreqport))
outref = context.socket(zmq.ROUTER)
outref.bind("tcp://" + myip + ":" + str(args.outrefport))
req = context.socket(zmq.ROUTER)
req.bind("tcp://" + myip + ":" + str(args.reqport))
repub = context.socket(zmq.PUB)
repub.bind("tcp://" + myip + ":" + str(args.repubport))
# sort out the poller
poller = zmq.Poller()
poller.register(inreq, zmq.POLLIN)
poller.register(outsub, zmq.POLLIN)
poller.register(outref, zmq.POLLIN)
poller.register(req, zmq.POLLIN)
# UDP socket setup for broadcasting this server's address
cs = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
cs.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
cs.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
# housekeeping variables
pulsecheck = datetime.utcnow() + timedelta(seconds = 1)
alivelist = dict()
pulsetimeout = 5
while True:
polls = dict(poller.poll(1000))
if inreq in polls:
msg = inreq.recv_multipart()
if msg[1] == b"pulse": # handle pluse
ansi("cyan", False, textout = " pulse" + "-" + msg[0].decode())
if not msg[0] in alivelist.keys():
handlechange(msg[0])
alivelist[msg[0]] = datetime.utcnow() + timedelta(seconds = pulsetimeout)
if outsub in polls:
msgin = outsub.recv_multipart()[0]
repub.send(msgin) # republish
msg = unpacker(msgin)
if isinstance(msg, dict):
valu = msg.get("value")
print(".", end = "", flush = True)
else:
ansi("green", False, textout = msg)
if req in polls:
msg = req.recv_multipart()
valmsg = validate_request(msg)
if not valmsg[0]:
ansi("red", True); print(valmsg[1]); ansi()
elif len(alivelist) > 0:
targetnode = random.choice(list(alivelist.keys()))
inreq.send_multipart([targetnode, packer(valmsg[1])])
ansi("blue", True, textout = "sent to " + targetnode.decode())
else:
ansi("red", True, textout = "NO CONNECTED NODES TO SEND REQUEST TO")
if outref in polls:
msg = outref.recv_multipart()
destinataire, correlid = msg[1].split(b"/")
req.send_multipart([destinataire, correlid, msg[2]])
I want to implement something analogous in Elixir (or Erlang) but my preferred native library, chumak, doesn't seem to implement polling. How do I implement non-blocking receives in Erlang/Elixir, preferably using Chumak, but I'll move to another Erlang zeroMQ library if necessary? My socket pattern preference is router sends, dealer receives.
EDIT
My use case is the following. I have a third party financial service which serves data based on requests, with answers coming asynchronously. So you can send multiple requests, and you'll get responses back after an unspecified period of time, and not necessarily in the same order you sent them.
So I need to connect this service into Erlang (actually Elixir) and ZeroMQ seems like a good fit. Multiple users connected (via Phoenix) to Erlang/Elixir will send requests, and I need to pass these on to this service.
The problem comes if there is an error in one of the requests, or the third party service has some kind of problem. I will be blocking-waiting for a response, and then unable to service new requests from Phoenix.
Basically I want to listen constantly for new requests, send them over, but if one request doesn't produce a response, I will have one-fewer responses than requests and that will lead to an eternal wait.
I understand that if I send requests separately, then the good ones will produce responses so I don't need to worry about blocking even if, over time, I get quite a big numerical difference between requests sent and responses received. Maybe the design idea is that I shouldn't worry about this? Or should I try to track one-for-one responses to requests and timeout the non-responses somehow? Is this a valid design pattern?
Is your system constantly connected to the asynchronous query resource, or are you making a new connection with each query?
Each situation has its own natural model in Erlang.
The case of: A single (or pool of) long-term connection(s)
Long-term connections that maintain a session with the resource (the way a connection with a database would work) are most naturally modelled as processes within your system that have the sole job of representing that external resource.
The requirements of that process are:
Translate the external resource's messages into internally meaningful messages (not just passing junk through -- don't let raw, external data invade your system unless it is totally opaque to you)
Keep track of timed out requests (and this may require something sort of like polling, but can be done more precisely with erlang:send_after/3
This implies, of course, that the module that implements this process will need to speak the protocol of that resource. But if this is accomplished then there really isn't any need for a messaging broker like an MQ application.
This allows you to have that process be reactive and block on receive while the rest of your program goes off to do whatever its doing to do. Without some arbitrary polling that will surely run you into the Evil Black Swamp of Scheduling Issues.
The case of: A new connection per query
If each query to the resource requires a new connection the model is similar, but in here you spawn a new process per query and it represents the query itself within your system. It blocks waiting for the response (on a timeout), and nothing else matters to it.
That is the easier model, actually, because then you don't have to scrub a list of past, possibly timed out requests that will never return, don't have to interact with a set of staged timeout messages sent via erlang:send_after/3, and you move your abstraction one step closer to the actual model of your problem.
You don't know when these queries will return, and that causes some potential confusion -- so modeling each actual query as a living thing is an optimal way to cut through the logical clutter.
Either way, model the problem naturally: As a concurrent, asynch system
In no case, however, do you want to actually do polling the way you would in Python or C or whatever. This is a concurrent problem, so modelling it as such will provide you a lot more logical freedom and is more likely to result in a correct solution that lacks corners that give rise to weird cases.

Resources