Facebook Messenger Chatbot Code - UnboundLocalError - python

Using the following code, I've setup a flask app:
https://gist.github.com/ugik/a218a599b1af0ea06b1b38e3a5132078#file-flaskfbmapi-ai-rig
import requests
import json
from flask import Flask, request
import apiai
# FB messenger credentials
ACCESS_TOKEN = "EAAKsKOJ37rUBAKVZAQ21bn...UsZCXx6UWqQ6XuQr7OHnBYL3xD3Sy5u1ZAZCwip0XnTAHq25CsIpxRsbxZALRHOOguKm2unY7I06LRAZDZD"
# api.ai credentials
CLIENT_ACCESS_TOKEN = "78c0e0...d9404a2"
ai = apiai.ApiAI(CLIENT_ACCESS_TOKEN)
app = Flask(__name__)
#app.route('/', methods=['GET'])
def verify():
# our endpoint echos back the 'hub.challenge' value specified when we setup the webhook
if request.args.get("hub.mode") == "subscribe" and request.args.get("hub.challenge"):
if not request.args.get("hub.verify_token") == 'foo':
return "Verification token mismatch", 403
return request.args["hub.challenge"], 200
return 'Hello World (from Flask!)', 200
def reply(user_id, msg):
data = {
"recipient": {"id": user_id},
"message": {"text": msg}
}
resp = requests.post("https://graph.facebook.com/v2.6/me/messages?access_token=" + ACCESS_TOKEN, json=data)
print(resp.content)
#app.route('/', methods=['POST'])
def handle_incoming_messages():
data = request.json
sender = data['entry'][0]['messaging'][0]['sender']['id']
message = data['entry'][0]['messaging'][0]['message']['text']
# prepare API.ai request
req = ai.text_request()
req.lang = 'en' # optional, default value equal 'en'
req.query = message
# get response from API.ai
api_response = req.getresponse()
responsestr = api_response.read().decode('utf-8')
response_obj = json.loads(responsestr)
if 'result' in response_obj:
response = response_obj["result"]["fulfillment"]["speech"]
reply(sender, response)
return "ok"
if __name__ == '__main__':
app.run(debug=True)
However, at line 51 there is an error in my server logs:
UnboundLocalError: local variable 'response' referenced before
assignment
Which I understand the root of the cause is "response" is defined only within the if statement, however, since it is not my code, I'm having trouble defining the variable outside. Will this work if I place this code after line 48:
response = response_obj["result"]["fulfillment"]["speech"]

Related

I am seeing this error in server.py file, " The browser (or proxy) sent a request that this server could not understand."

Here I am attaching my server.py and util.py
I have trained a model, and now wish to print the data on user's demand.
server.py
from flask import Flask, request, jsonify
#from waitress import serve
import util
import json
#%run util.ipynb
app = Flask(__name__)
#app.route('/hi')
def hi():
return util.areas()
#app.route('/locations')
def locations():
response = jsonify({
'locations': util.locations()
})
response.headers.add('Access-Control-Allow-Origin', '*')
return response
#app.route('/predict_home_price', methods=['GET', 'POST'])
def predict_home_price():
total_sqft = float(request.form['total_sqft'])
location = request.form['location']
size = int(request.form['size'])
bath = int(request.form['bath'])
area_type = request.form['area_type']
balcony = int(request.form['balcony'])
response = jsonify({
'estimated_price': util.get_estimated_price(area_type, location, size, total_sqft, bath, balcony)
})
response.headers.add('Access-Control-Allow-Origin', '*')
return response
if __name__ == '__main__':
print('python flask started')
app.run()
#serve(app, host='0.0.0.0', port=50100, threads=1)
util.py
import json
import joblib
import numpy as np
__locations = None
__area = None
__model = None
def get_estimated_price(area_type, location, size, total_sqft, bath, balcony):
x = np.zeros(6)
x[0] = __area.index(area_type)
x[1] = __locations.index(location)
x[2] = size
x[3] = total_sqft
x[4] = bath
x[5] = balcony
return round(__model.predict([x])[0][0],2)
def locations():
return __locations
def areas():
return __area
def load_saved_artifacts():
print("loading saved artifacts...start")
global __data_columns
global __locations
global __area
with open('./artifacts/locations.json','r') as f:
__locations = json.load(f)['data_locations']
with open('./artifacts/area.json','r') as f:
__area = json.load(f)['data_area']
global __model
__model = joblib.load('./artifacts/Banglore_Real_State_Price')
print(" loading artifacts is done")
if __name__ == '__main__':
load_saved_artifacts()
#print(locations())
#print(areas())
print(get_estimated_price('Super built-up Area','Electronic City Phase II',2,1056,2,1))
print(get_estimated_price('Built-up Area','Uttarahalli',3,1440,2,3))
print(get_estimated_price('Super built-up Area','Lingadheeranahalli',3,1521,3,1))
print(get_estimated_price('Super built-up Area','Kothanur',2,1200,2,1))
Immediate help is really appreciated
I have trained a model, and now wish to print the data on user's demand.
I am seeing this error in server.py file, " The browser (or proxy) sent a request that this server could not understand." I checked everything works fine if I am sending data to browser but not when asking for the data, I tried Postman for sending the data.
http://127.0.0.1:5000/predict_home_price -> shows bad request.
http://127.0.0.1:5000/locations -> shows correct data
http://127.0.0.1:5000/hi -> shows correct data
As you mentioned, when you're sending data to the server it works, and that's because you're using a POST request and the request has form data in it.
But when you're "asking for data", you're probably using a GET request, which has no form data in it, and that's why the server responses with an error.
You can modify your code so you can decide what you should do for each type of request:
#app.route('/predict_home_price', methods=['GET', 'POST'])
def predict_home_price():
if request.method == "POST":
# get form data and do something with it
elif request.method == "GET":
# return some value, without looking for form data

customize length of the password in dialogflow chatbot using regex entity

length of the password must be at least 6 characters while signing up using Dialogflow chatbot.
I have used system entity "any". But it is so generalized.
Webhook is written in flask python.
Also tried to do it by using [0-9]{6}$ as a regex entity. But unable to find a proper way to perform this task.
from dialogflow_fulfillment import QuickReplies, WebhookClient, Payload
from flask import Flask, request, Response, jsonify , make_response
import json
import requests
app = Flask(__name__)
def handler(agent: WebhookClient) :
"""Handle the webhook request.."""
req = request.get_json(force=True)
intent_name = req.get('queryResult').get('intent').get('displayName')
if intent_name == 'intro':
agent.add('I am the chatbot of this page. Ready to assist you with anything you need. What would you like to do?')
agent.add(QuickReplies(quick_replies=['START NOW','LOGIN']))
if intent_name == 'get_started':
url = 'http://**********.com/create_account'
userid = req.get('queryResult').get('parameters').get('email')
print(userid)
pwd = req.get('queryResult').get('parameters').get('pwd')
print(pwd)
name = req.get('queryResult').get('parameters').get('person')['name']
print(name)
age = req.get('queryResult').get('parameters').get('age')
print(age)
myobj = {'userid': userid, 'pwd': pwd , 'name' : name, 'age' : age}
x = requests.post(url, data = myobj)
result=x.text
agent.add(result)
if intent_name == 'login_screen' :
url = 'http://**********.com/auth_account'
userid = req.get('queryResult').get('parameters').get('email')
print(userid)
pwd = req.get('queryResult').get('parameters').get('pwd')
print(pwd)
myobj = {'userid': userid, 'pwd': pwd }
x = requests.post(url, data = myobj)
result = x.text
agent.add(result)
#app.route('/webhook', methods=['GET', 'POST'])
def webhook():
"""Handle webhook requests from Dialogflow."""
req = request.get_json(force=True)
agent = WebhookClient(req)
agent.handle_request(handler)
return agent.response
if __name__ == '__main__':
app.run(debug=True)
With regex :
Defined regex :
How to do this properly?
How to use regex in it?
Or should i use another approach?

Python flask returns 405 error when using twitter api

I am using python and I apologize as this is probably a very simple concept that I am not grasping but I am not very familiar with the flask framework. Right now I'm making a server with flask but run into a 405 error every time I try to do something with the twitter api shortly after. Right now my code looks something like this
In a separate file:
from flask import Flask
from threading import Thread
app = Flask('')
#app.route('/', methods=['GET', 'POST', 'DELETE'])
def home():
return "Hello world!"
def run():
app.run(host='0.0.0.0',port=8080)
app.run(debug=True, host="0.0.0.0")
def keep_alive():
t = Thread(target=run)
t.start()
Then I call my code in the main file:
from flaskfile import flask_file
flask_file()
MEDIA_ENDPOINT_URL = 'https://upload.twitter.com/1.1/media/upload.json'
POST_TWEET_URL = 'https://api.twitter.com/1.1/statuses/update.json'
CONSUMER_KEY = consumerkey
CONSUMER_SECRET = secret
ACCESS_TOKEN = accesstoken
ACCESS_TOKEN_SECRET = tokensecret
#fileName = check_and_download()
VIDEO_FILENAME = (filename)
oauth = OAuth1(CONSUMER_KEY,
client_secret=CONSUMER_SECRET,
resource_owner_key=ACCESS_TOKEN,
resource_owner_secret=ACCESS_TOKEN_SECRET)
class VideoTweet(object):
def __init__(self, file_name):
'''
Defines video tweet properties
'''
self.video_filename = file_name
self.total_bytes = os.path.getsize(self.video_filename)
self.media_id = None
self.processing_info = None
def upload_init(self):
'''
Initializes Upload
'''
print('INIT')
request_data = {
'command': 'INIT',
'media_type': 'video/mp4',
'total_bytes': self.total_bytes,
'media_category': 'tweet_video'
}
req = requests.post(url=MEDIA_ENDPOINT_URL, data=request_data, auth=oauth)
media_id = req.json()['media_id']
self.media_id = media_id
print('Media ID: %s' % str(media_id))
def upload_append(self):
'''
Uploads media in chunks and appends to chunks uploaded
'''
segment_id = 0
bytes_sent = 0
file = open(self.video_filename, 'rb')
while bytes_sent < self.total_bytes:
chunk = file.read(4*1024*1024)
print('APPEND')
request_data = {
'command': 'APPEND',
'media_id': self.media_id,
'segment_index': segment_id
}
files = {
'media':chunk
}
req = requests.post(url=MEDIA_ENDPOINT_URL, data=request_data, files=files, auth=oauth)
if req.status_code < 200 or req.status_code > 299:
print(req.status_code)
print(req.text)
sys.exit(0)
segment_id = segment_id + 1
bytes_sent = file.tell()
print('%s of %s bytes uploaded' % (str(bytes_sent), str(self.total_bytes)))
print('Upload chunks complete.')
def upload_finalize(self):
'''
Finalizes uploads and starts video processing
'''
print('FINALIZE')
request_data = {
'command': 'FINALIZE',
'media_id': self.media_id
}
req = requests.post(url=MEDIA_ENDPOINT_URL, data=request_data, auth=oauth)
print(req.json())
self.processing_info = req.json().get('processing_info', None)
self.check_status()
def check_status(self):
'''
Checks video processing status
'''
if self.processing_info is None:
return
state = self.processing_info['state']
print('Media processing status is %s ' % state)
if state == u'succeeded':
return
if state == u'failed':
sys.exit(0)
check_after_secs = self.processing_info['check_after_secs']
print('Checking after %s seconds' % str(check_after_secs))
time.sleep(check_after_secs)
print('STATUS')
request_params = {
'command': 'STATUS',
'media_id': self.media_id
}
req = requests.get(url=MEDIA_ENDPOINT_URL, params=request_params, auth=oauth)
self.processing_info = req.json().get('processing_info', None)
self.check_status()
def tweet(self):
'''
Publishes Tweet with attached video
'''
request_data = {
#leave status blank
'status': '',
'media_ids': self.media_id
}
req = requests.post(url=POST_TWEET_URL, data=request_data, auth=oauth)
print(req.json())
if __name__ == '__main__':
videoTweet = VideoTweet(VIDEO_FILENAME)
videoTweet.upload_init()
videoTweet.upload_append()
videoTweet.upload_finalize()
videoTweet.tweet()
The error returned states the following:
"Error response
Error code: 405
Message: Method Not Allowed.
Error code explanation: 405 - Specified method is invalid for this resource."
Basically I call the flask file then use twitter api to upload a file, but for some reason using the twitter api always results in a 405 error and my flask server is no longer accessible. How can I adjust my flask file to allow me to upload using the api?
405 errors are thrown when the wrong request method is used. For example a POST request being sent when a GET request was expected, or a GET request being sent when a POST request was expected.
In your check_status function you have
req = requests.get(url=MEDIA_ENDPOINT_URL, ...
But according to Twitter's documentation you should be using a post request here
req = requests.post(url=MEDIA_ENDPOINT_URL, ...

Can't get the response from webhook

I created a webhook using python ( using this example) for my project in api.ai
My code is here :
#!/usr/bin/env python
import urllib
import json
import os
from flask import Flask
from flask import request
from flask import make_response
# Flask app should start in global layout
app = Flask(__name__)
#app.route('/webhook', methods=['POST'])
def webhook():
req = request.get_json(silent=True, force=True)
print("Request:")
print(json.dumps(req, indent=4))
res = makeWebhookResult(req)
res = json.dumps(res, indent=4)
print(res)
r = make_response(res)
r.headers['Content-Type'] = 'application/json'
return r
def makeWebhookResult(req):
if req.get("result").get("action") != "delivery.info":
return {}
result = req.get("result")
parameters = result.get("parameters")
parcelnr = parameters.get("parcelnumber")
parcelinfo = {'5000':'your parcel has been shipped', '5001':'your parcel has
not been shipped', '5002':'should be delivered on three days', '5003':'your
parcel has not been shipped', '5004':'your parcel has been shipped'}
speech = "Parcel with numner" + parcelnr + " is " +
str(parcelinfo[parcelnr]) "
print("Response:")
print(speech)
return {
"speech": speech,
"displayText": speech,
#"data": {},
# "contextOut": [],
"source": "apiai-debot"
}
if __name__ == '__main__':
port = int(os.getenv('PORT', 5000))
print "Starting app on port %d" % port
app.run(debug=True, port=port, host='0.0.0.0')
Api agent is :
image1
image2
I don't understand where i'm wrong.
My agent work ok, but when i ask the bot to get info from the webhook i get the text response from api.ai not from webhook.
Can you help me please ?
The following is working for me. request.data will be receiving message alerts from the TradingView webhook message.
#app.route('/webhook', methods=['POST'])
def webhook():
print("\nrequest.data={}".format(request.data))
return request.data
In TradingView Alert Message, I am using following...
exchange = {{exchange}}, ticker = {{ticker}}, price = {{close}}, volume = {{volume}}
...and I am getting following message in logs:
$ heroku logs --tail
2022-01-12T20:38:00.510006+00:00 app[web.1]: request.data=b'exchange = BINANCE, ticker = BTCUSDT, price = 43671.85, volume = 10.70612'
2022-01-12T20:38:00.510512+00:00 app[web.1]: 10.1.58.75 - - [12/Jan/2022:20:38:00 +0000] "POST /webhook HTTP/1.1" 200 73 "-" "Go-http-client/1.1"
You are using the wrong url for the webhook in the fulfillment.
Your code is mapping the request to /webhook, while your url is https://your-domain.com/debotwebhook.
Either change #app.route('/webhook', methods=['POST']) to #app.route('/debotwebhook', methods=['POST']) or change the url in api.ai to https://your-domain.com/webhook
Also, I see an extra " in your speech variable after str(parcelinfo[parcelnr]).
Here is the agent I tested with your code and on the right you can see the answer:

Python Token based authentication error

I am using token based authentication to restrict the access to user for my site, I am getting following error
{"_status": "ERR", "_error": {"message": "Please provide proper credentials", "code": 401}}weber#weber-desktop:/var/www/lunar-cloud-web-ui/kukunako$
my sample code shown below.
class TokenAuth(TokenAuth):
def check_auth(self, token, allowed_roles, resource, method):
accounts = app.data.driver.db['people']
return accounts.find_one({'token': token})
app = Eve(__name__,static_url_path='/static', auth = TokenAuth)
app.debug = True,
app.config.update(
DEBUG=True,
#EMAIL SETTINGS
MAIL_SERVER='smtp.gmail.com',
MAIL_PORT=465,
MAIL_USE_SSL=True,
MAIL_USERNAME = '<username>',
MAIL_PASSWORD = '<password>'
)
mail=Mail(app)
socketio = SocketIO(app)
def create_token(user):
payload = {
'sub': str(user['_id']),
'iat': datetime.now(),
'exp': datetime.now() + timedelta(days=14)
}
token = jwt.encode(payload, TOKEN_SECRET)
return token.decode('unicode_escape')
def login_required(f):
#wraps(f)
def decorated_function(*args, **kwargs):
if not request.headers.get('Authorization'):
response = jsonify(error='Missing authorization header')
response.status_code = 401
return response
payload = parse_token(request)
if datetime.fromtimestamp(payload['exp']) < datetime.now():
response = jsonify(error='Token has expired')
response.status_code = 401
return response
g.user_id = payload['sub']
return f(*args, **kwargs)
return decorated_function
#app.route('/auth/login', methods=['POST'])
def login():
accounts = app.data.driver.db['people']
user = accounts.find_one({'email': request.json['email']})
if not user:
response = jsonify(error='Your email does not exist')
response.status_code = 401
return response
if not user['email_confirmed'] == True:
response = jsonify(error='Email is not confirmed')
response.status_code = 401
return response
if not user or not check_password_hash(user['password']['password'], request.json['password']):
response = jsonify(error='Wrong Email or Password')
response.status_code = 401
return response
token = create_token(user)
return jsonify(token=token)
my all code is show in following for settings file and server code file
settings file
server code file
How are you testing it?
I can think of two possible problems.
JWT token needs to be base64 encoded
You may have forgotten : at the end
e.g. If your token is as follows (Taken from jwt.io site)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
You need to do the following:
$ echo 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ:' | base64
ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnpkV0lpT2lJeE1qTTBOVFkzT0Rrd0lpd2libUZ0WlNJNklrcHZhRzRnUkc5bElpd2lZV1J0YVc0aU9uUnlkV1Y5LlRKVkE5NU9yTTdFMmNCYWIzMFJNSHJIRGNFZnhqb1laZ2VGT05GaDdIZ1E6Cg==
Now use this as follows (with curl)
curl -H "Authorization Basic ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnpkV0lpT2lJeE1qTTBOVFkzT0Rrd0lpd2libUZ0WlNJNklrcHZhRzRnUkc5bElpd2lZV1J0YVc0aU9uUnlkV1Y5LlRKVkE5NU9yTTdFMmNCYWIzMFJNSHJIRGNFZnhqb1laZ2VGT05GaDdIZ1E6Cg==" http://127.0.0.1:5000/my_secure_endpoint

Categories