I built a whatapp chatbot using flask and Twilio, but seem to getting failed messages on when I check my console. The status appears as failed with an unknown error. When I check my debugger I see the error message
HTTP retrieval failure
I started getting these errors after making a few changes to my flask app. I tried undoing all the changes but now instead of getting received as the status, the status now appears as failed. I tried restarted my ngrok and changing the url on my Twilio but this hasn't changed anything either.
Here is my code:
from flask import Flask, request
import requests
from twilio.twiml.messaging_response import MessagingResponse
import random
app = Flask(__name__)
#app.route('/bot', methods=['POST'])
def bot():
incoming_msg = request.values.get('Body', '').lower()
resp = MessagingResponse()
msg = resp.message()
responded = False
if incoming_msg == 'help':
#return options available
output = 'This is a chatbot designed to send statistics, linear algebra and general programming problem questions. Please type in either "Python", "Statistics" or Linear Algebra" to get a random problem.'
msg.body(output)
responded = True
if 'python' in incoming_msg:
with open("C://Users//User//Downloads//python_test.txt", "r") as f:
lines = f.readlines()
code = random.choice(lines)
msg.body(code)
responded = True
if 'quote' in incoming_msg:
# return a quote
r = requests.get('https://api.quotable.io/random')
if r.status_code == 200:
data = r.json()
quote = f'{data["content"]} ({data["author"]})'
else:
quote = 'I could not retrieve a quote at this time, sorry.'
msg.body(quote)
responded = True
if 'thegradientboost' in incoming_msg:
message = 'Test \
'. Additional text' \
'More text,' \
'end of text.' \
'a bit more text' \
'conclusion.'
msg.body(message)
responded = True
if not responded:
msg.body('Word not included.')
return str(resp)
if __name__ == '__main__':
app.run(debug=True)
Related
I am trying to send a response to Dialogflow Es using webhook written in python-flask.
Integration platform :
digital human --> Uneeq
I tried with the fulfillment library (dialogflow_fulfillment) but it was not working so I tried it without a library like :
if req.get('queryResult').get('action') == 'appointment':
print("ïntent triggered")
return {"fulfillmentText": 'BUDDY!'}
It worked!
Now the issue is before integrating this chatbot to digital human I wrote the whole code using the fulfillment library. Now I need to change the whole code for this purpose.
As I am unable to extract entities using context-based intents (session-vars) like :
case = agent.context.get('session-vars').get('parameters').get('case')
name = agent.context.get('session-vars').get('parameters').get('name')['name']
email = agent.context.get('session-vars').get('parameters').get('email')
phone = agent.context.get('session-vars').get('parameters').get('phone')
So my question is how to accomplish this task successfully?
If I try to use the fulfillment library then how to send a response to Dialogflow so that digital human will understand it since "agent.add" doesn't work.
Or, If I try to do it without a library then how to extract entities(from the session-vars) like (case, name, email, phone).
I need to save all these parameters(entities) in firebase, These output context (only session-vars parameters not other contexts):
This is the response I am getting correctly without library:
Unable to proceed at any cost!
looking forward to your response.
Thanks in advance!
Complete code (with the library):
from dialogflow_fulfillment import WebhookClient
from flask import Flask, request, Response
import json
app = Flask(__name__)
def handler(agent: WebhookClient) :
"""Handle the webhook request.."""
req = request.get_json(force=True)
a= req.get('queryResult').get('action')
if req.get('queryResult').get('action') == 'appointment':
name = agent.context.get('session-vars').get('parameters').get('name')['name']
email = agent.context.get('session-vars').get('parameters').get('email')
phone = agent.context.get('session-vars').get('parameters').get('phone')
print("ïntent triggered")
agent.add('BUDDY!')
#app.route('/webhook', methods=['GET', 'POST'])
def webhook():
req = request.get_json(force=True)
agent = WebhookClient(req)
agent.handle_request(handler)
return agent.response
if __name__ == '__main__':
app.run(debug=True)
Complete code (without library):
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)
res = makeWebhookResult(req)
res = json.dumps(res, indent=4)
r = make_response(res)
#print(res)
r.headers['Content-Type'] = 'application/json'
return r
def makeWebhookResult(req):
intent_name = req.get('queryResult').get('intent').get('displayName')
print(intent_name)
action_name = req['queryResult']['action']
if req.get('queryResult').get('action') == 'input.welcome':
print("intent trigered")
return {"fulfillmentText": 'Hi there'}
if action_name == 'test':
cont = req.get('queryResult').get('outputContexts')[0]['name']
print(type(cont))
x = cont.split("/")
print(x[6])
if x[6] == 'session-vars' :
para = req['queryResult']['outputContexts']
print(para)
print("test intent trigered")
return {"fulfillmentText": 'Bye there'}
if __name__ == '__main__':
app.run(debug=True)
#app.route('/bot', methods=['POST'])
def bot():
content = request.form.get('Body').lower()
resp = MessagingResponse()
msg = resp.message()
responded = False
if 'hi' in content:
msg.media(url_for('static', filename='bonjour.mp3'), content_type='audio/mpeg')
responded = True
if not responded:
msg.body('no')
return str(resp)
That's my code to respond to a Whatsapp message. If you say 'hi', it should send you an mp3 audio that i saved (I checked that the path is correct), and if you say something else it just says 'no'. But when I send a message with 'hi', I get this error in the Twilio debug part :
error 12200
The URL you pass to media() needs to be an absolute URL of a media file which is publicly available, not a relative one.
In your case not /static/bonjour.mp3 but something like https://yourdomain.com/static/bonjour.mp3.
Also omit the content_type.
I am trying to use Dialogflow in my Flask app but I am getting 403 IAM permission 'dialogflow.sessions.detectIntent' I have checked twice my role is project owner in cloud console. I am following this tutorial.
This is my app.py
from flask import Flask
from flask import request, jsonify
import os
import dialogflow
from google.api_core.exceptions import InvalidArgument
import requests
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = 'service_key.json'
DIALOGFLOW_PROJECT_ID = 'whatsappbotagent-gmsl'
DIALOGFLOW_LANGUAGE_CODE = 'en'
SESSION_ID = 'me'
app = Flask(__name__)
app.config["DEBUG"] = True
#app.route('/')
def root():
return "Hello World"
#app.route('/api/getMessage', methods = ['POST'])
def home():
message = request.form.get('Body')
mobnu = request.form.get('From')
session_client = dialogflow.SessionsClient()
session = session_client.session_path(DIALOGFLOW_PROJECT_ID, SESSION_ID)
text_input = dialogflow.types.TextInput(text = message, language_code = DIALOGFLOW_LANGUAGE_CODE)
query_input = dialogflow.types.QueryInput(text = text_input)
try:
response = session_client.detect_intent(session = session, query_input = query_input)
except InvalidArgument:
raise
print("Query text: ", response.query_result.query_text)
# sendMessage()
return response.query_result.fullfilment_text
if __name__ == '__main__':
app.run()
OK, so after a lot of searching and trial and error I found the issue.
Actually while creating a service account the user gets a service email and that email will have access to use the project but I was not adding that email in project permission emails. Adding that email in IAM & Admin > IAM > +ADD will make it work.
Maybe there was a better solution but this is what works for me and hopefully solves others problem if have similar issue like this.
I am building a custom responder for the Cortex/Hive, and I have been unable to get my request response to properly convert into a JSON format. When testing in the local development environment, my code in getCount function works flawlessly, but when adding the cortex responder wrapper to it, my code fails.
Since the responder runs from Cortex, I do not receive an error message beyond "input: null", so I had to write to an error log. Using this log, I determined that the error stems from the line data = json.loads(response.text). I tried using simple json, regex-ing the desired value from response.text, changing encoding methods, and banging my head on the keyboard from the sheer stupidity of it not working.
CODE:
import requests
import json
from cortexutils.responder import Responder
class Search(Responder):
def __init__(self):
# Debug
with open('/xxx/xxx/xxx/xxx/error.log','a') as error_log:
error_log.write('Starting: \n')
error_log.write('\n\n')
# End Debug
Responder.__init__(self)
self.apiuser = self.get_param('config.api_user', None)
self.apikey = self.get_param('config.api_key', None)
self.url = self.get_param('config.api_url', None)
self.ioc_type = self.get_param('data.dataType', None)
self.ioc = self.get_param('data.data', None)
# Debug
with open('/xxx/xxx/xxx/xxx/error.log','a') as error_log:
error_log.write('User ID: \n')
error_log.write(self.apiuser)
error_log.write('\n\nSecret: \n')
error_log.write(self.apikey)
error_log.write('\n\n')
error_log.write('IOC Type: \n')
error_log.write(self.ioc_type)
error_log.write('\n\n')
error_log.write('Value: \n')
error_log.write(self.ioc)
error_log.write('\n\n')
# End Debug
def getCount(self):
with open('/xxx/xxx/xxx/xxx/error.log','a') as error_log:
error_log.write('Starting Count: \n')
error_log.write('\n\n')
url = self.url
headers={'Content-Type': 'application/json'}
params={'type': self.ioc_type, 'value': self.ioc}
response = requests.request("GET", url, headers=headers, params = params, auth=(self.apiuser, self.apikey))
data = json.loads(response.text)
with open('/xxx/xxx/xxx/xxx/error.log','a') as error_log:
error_log.write('Response: ')
error_log.write(data)
deviceCount = data['resources'][0]['device_count']
self.count = deviceCount
def run(self):
Responder.run(self)
self.getCount()
self.operations()
def operations(self):
return [self.build_operation('AddTagToCase', tag= self.count)]
if __name__ == '__main__':
Search().run()
Results from response.text:
{"meta":{"query_time":0.014920091,"trace_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"},
"resources":[{"id":"sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"type":"sha256",
"value":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"device_count":11}],"errors":[]}
Error Logging results:
Starting:
User ID:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Secret:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
IOC Type:
sha256
Value:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
run starting:
Starting Count:
self.count should be equal to device_count, but json.loads fails to format this response. This can be seen in my error log results where Count() starts but abruptly ends before data is written to it.
If you could please provide insight into why this fails to format the response properly, please shed some light.
Thank you
This is my standard way of getting a json response from an API using the requests module
response = requests.get(url, headers=headers, params=params, auth=(self.apiuser, self.apikey)).json()
I lately started using Flask in one of my projects to provide data via a simple route. So far I return a json file containing the data and some other information. When running my Flask app I see the status code of this request in terminal. I would like to return the status code as a part of my final json file. Is it possible to catch the same code I see in terminal?
Some simple might look like this
from flask import Flask
from flask import jsonify
app = Flask(__name__)
#app.route('/test/<int1>/<int2>/')
def test(int1,int2):
int_sum = int1 + int2
return jsonify({"result":int_sum})
if __name__ == '__main__':
app.run(port=8082)
And in terminal I get:
You are who set the response code (by default 200 on success response), you can't catch this value before the response is emited. But if you know the result of your operation you can put it on the final json.
#app.route('/test/<int1>/<int2>/')
def test(int1, int2):
int_sum = int1 + int2
response_data = {
"result": int_sum,
"sucess": True,
"status_code": 200
}
# make sure the status_code on your json and on the return match.
return jsonify(response_data), 200 # <- the status_code displayed code on console
By the way if you access this endpoint from a request library, on the response object you can find the status_code and all the http refered data plus the json you need.
Python requests library example
import requests
req = requests.get('your.domain/test/3/3')
print req.url # your.domain/test/3/3
print req.status_code # 200
print req.json() # {u'result': 6, u'status_code: 200, u'success': True}
You can send HTTP status code as follow:
#app.route('/test')
def test():
status_code = 200
return jsonify({'name': 'Nabin Khadka'}, status_code) # Notice second element of the return tuple(return)
This way you can control what status code to return to the client (typically to web browser.)