Twilio whatapp bot not responding to keywords - python

I am trying to build a whatsapp bot on Twilio following the Twilio tutorial.
I have written the flask program to create a test bot:
from flask import Flask, request
import requests
from twilio.twiml.messaging_response import MessagingResponse
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 '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 'cat' in incoming_msg:
# return a cat pic
msg.media('https://cataas.com/cat')
responded = True
if not responded:
msg.body('I only know about famous quotes and cats, sorry!')
return str(resp)
if __name__ == '__main__':
app.run()
The app is running on http://127.0.0.1:5000/
When I click this link this is what I see
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
Installed and run ngrok. I pasted the url under forwarding (there are two I copied the first), pasted this url to my Twilio sandbox (when a message comes in URL) and added /bot to the path.
However when I try and type cat on whatsapp (I have added my whatsapp number to my sandbox) I do not get a response (from my understanding I should be getting a picture of a cat if I type the keyword cat).
Not sure what I am doing wrong.

I copied the same code here from the blog here (is this the blog you used), Build a WhatsApp Chatbot With Python, Flask and Twilio, and updated the WhatsApp sandbox When A Message Comes In URL to point to the Ngrok URL which exposes it to the Internet and it works.
Can you check your Twilio Debugger, to see if there were any errors?
You cannot use your web browser to visit the Flask URL, since it is expecting an HTTP POST and your browser is using an HTTP GET. You can use a tool like Postman to do a POST to your URL, and see what response you get.
You should get this response when visit the URL and sending in the Body POST parameter of cat.
You could also check the Ngrok debug URL, http://127.0.0.1:4040/, to see what you are getting from Twilio when you send an inbound WhatsApp sandbox message, and debug from there.

Related

when I use python for scripting Login response code showing like 400 but in application shows 302 response. how to resolve it in locust

In my script when I login it shows like 400 response code.
from locust import task, SequentialTaskSet, HttpUser, between
import re
class Orange(SequentialTaskSet):
def __init__(self, parent):
super().__init__(parent)
self.csrf1 = ""
self.csrf2 = ""
#task
def launch(self):
with self.client.get("/", name="T01_Launch", catch_response=True) as response:
if "OrangeHRM" in response.text:
response.success()
else:
response.failure("Failed to launch")
try:
csrf1 = re.search(r"_csrf_token\" value=(.+?)\"", response.text)
self.csrf1 = csrf1.group(1)
except AttributeError:
self.csrf1 = "NOT FOUND_CSRF 1"
#task
def login(self):
self.client.cookies.clear()
data = {
"actionID": "",
"hdnUserTimeZoneOffset": 5.5,
"installation": "",
"_csrf_token": self.csrf1,
"txtUsername": "Admin",
"txtPassword": "admin123",
"Submit": "LOGIN"
}
with self.client.post("/index.php/auth/validateCredentials", name="T02_Login",catch_response=True) as response:
print(response.status_code) #THIS LINE SHOWING 400 RESPONSE CODE
class Myuser(HttpUser):
host = "https://opensource-demo.orangehrmlive.com"
wait_time = between(1, 2)
tasks = [Orange] #USER CLASS
When I was checked the application login transanction redirected so it shows 302 code.
Orange HRM application shows like 302 response code for Login. if anyone helps me it would be great...
A 302 is a redirect response code, telling the client to go somewhere else to complete the request. It's possible the server logs you're looking at are logging the 302 and redirecting the client somewhere else which means you may need to look at another log on another server somewhere to find the rest of the request.
Locust's client inherits from Requests, which means you should be able to try things like get_redirect_target or check the Response object for history to see where the request may have been redirected to which may help you in your search for where to look server side for the request handling.
It may also be helpful to take Locust out of the equation and create a standalone Python script that does what you need it to do. Use Requests for your client calls and it should be pretty easy to move everything back over to Locust when you get it working.

Always receiving 400:Bad request when Twilio webhook is configured

I want to maintain seperate twilio phone unsubscribers list and this can be done when webhook is configured via twilio console to receive incoming messages. I would parse only those messages when some one types "STOP". I have successfully configured webhook
Now from my phone when i type "STOP" to my twilio number, I am receiving always bad request. My code looks as follows
#app.route('/twilio/unsubscribes_incremental', methods=['POST', 'GET'])
def phone_unsubscribes_incremental():
print("start")
print("The arguments are ", request.args)
payload = request.get_json(force=True)
print("The payload is ", payload)
#resp = MessagingResponse()
if payload.get('Body') in twilio_unsubscribe_list:
stream_data_to_bq(payload)
#resp.message("")
#return str(resp)
return jsonify({"status":"ok"})
My python console shows as follows
My ngrok console shows as follows
My twilio console logs shows as follows
For some reason iam unable to parse request object sent to my webhook. This account is in free trial. Can any one point out to me right documentation to parse incoming messages.
Twilio developer evangelist here.
As Alan points out, Twilio webhook requests send data in the form application/x-www-form-urlencoded, the same format that a web form will post data. It is not JSON. Twilio also expects your application's response to be application/xml.
So, you should read the data from request.form and, since it doesn't look like you are expecting to tell Twilio to do anything further with the request, return an empty <Response> TwiML element.
Something like this should work:
#app.route('/twilio/unsubscribes_incremental', methods=['POST', 'GET'])
def phone_unsubscribes_incremental():
print("start")
print("The arguments are ", request.args)
payload = request.form
print("The payload is ", payload)
if payload.get('Body') in twilio_unsubscribe_list:
stream_data_to_bq(payload)
resp = MessagingResponse()
return str(resp), { 'Content-Type': 'application/xml' }
The webhook is application/x-www-form-urlencoded
Webhook FAQ
For inbound text messages, Twilio will send an HTTP POST request to
your server with a body that uses the
application/x-www-form-urlencoded encoding. View the list of
parameters sent in that request.

Streamlabs API 405 response code

I'm trying to use Streamlabs API. Streamlabs API uses Oauth2 for creating apps. So first I send whoever's using my app to an authorization link containing my app's client id and the scopes I want to use.
(Something like this: streamlabs.com/api/v1.0/authorize?client_id=CLIENT-ID-HERE&redirect_uri=REDIRECT-URI&response_type=code&scope=SOME+SCOPES+HERE)
Once I've done that I receive a code at the redirect uri specified. I then use that code to get the access token for permanent access to the connected user's account. I then receive the access token from a POST request that works perfectly... Now I run into the problem. When getting the temporary code before the access token I specified the scopes: "donations.read +donations.create+alerts.write+alerts.create".
When authorizing, the app asks for permission to the different scopes. The scope in focus is "alerts.write" so that I can send test alerts using POST requests. But this doesn't work for some reason. To send a test alert I have to send a POST request to this url: "https://streamlabs.com/api/alerts/send_test_alert"
I've tried doing that in two different ways.
1:
import requests
url = "https://streamlabs.com/api/alerts/send_test_alert"
data = {
"access_token":"UserAccessTokenHere",
"type":"donation"
}
response = requests.post(url=url, data=data)
print(response.text)
2:
import requests
url = "https://streamlabs.com/api/alerts/send_test_alert?access_token=UserAccessTokenHere&type=donation"
response = requests.post(url=url)
print(response.text)
If I do print(response) it prints "Response [405]".
But if I do print(response.text) I get a long HTML document for this page: Error response page
Any ideas what's going wrong with my Python requests? send_test_alert documentation here: Link
I've contacted support and looks like you've made the same error as me.
You're not actually sending a request to the right URL.
You are a sending a request to: "https://streamlabs.com/api/alerts/send_test_alert"
You should be using the URL: "https://streamlabs.com/api/v1.0/alerts/send_test_alert"

Twitter oauth with flask_oauthlib, Failed to generate request token

I tried to use flask_oauthlib to access my twitter api, but all I get is the error : Failed to generate request token. Here is the code.
from flask_oauthlib.client import OAuth
from flask import Flask, url_for, request, jsonify
app = Flask(__name__)
oauth = OAuth()
twitter = oauth.remote_app(
'twitter',
base_url='https://api.twitter.com/1/',
request_token_url='https://api.twitter.com/oauth/request_token',
access_token_url='https://api.twitter.com/oauth/access_token',
authorize_url='https://api.twitter.com/oauth/authorize',
consumer_key='dOJjyxB6gxXWTjdtfPUZcZPjl',
consumer_secret='im not telling you',
)
#app.route('/login')
def login():
return twitter.authorize(callback=url_for('authorized',
next=request.args.get('next') or request.referrer or None))
#app.route('/authorized')
#twitter.authorized_handler
def authorized(resp):
if resp is None:
return 'Access denied: error=%s' % (
request.args['error']
)
if 'oauth_token' in resp:
# session['example_oauth'] = resp
print(resp)
return jsonify(resp)
return str(resp)
if __name__ == '__main__':
app.run(port=8000, debug=True)
This didn't work while using http://term.ie/oauth/example/client.php, I managed to get a request token.
I inspired myself with https://github.com/lepture/example-oauth1-server/blob/master/client.py and http://flask-oauthlib.readthedocs.io/en/latest/client.html
EDIT
Weird fact : I tried the code here : https://github.com/lepture/flask-oauthlib/blob/master/example/twitter.py
I didn't changed the key and secret and it worked.
So I tried to change them for my own credentials, and it stopped working. I really can't understand...
Ok I found the problem. It appears that the callback URL is mandatory when using flask-oauthlib. So I added a fake one since i'm still on localhost, and it solved this problem.
In case anyone found this issue. I'm the author of Flask-OAuthlib. I suggest that you use Authlib instead, browser the source code at https://github.com/lepture/authlib. There are many built-in social connections in https://github.com/authlib/loginpass.

How do I redirect to an external url and then redirect back to my python script using Flask

I am trying to use IMGUR API using Flask. The problem is I am not able to find a way to get the data from the URL when the app redirects back to my script.
For example:
My script creates the auth url for IMGUR
Goes to that URL
Logins to IMGUR manually and then the API redirects back to my script
The url parameters are what I want, but I am not able to find a way to get the details from the URL.
Here is my code:
#imgurupload.route('/')
def routine():
client = ImgurClient('REDACTED-CODE', 'REDACTED-CODE-REDACTED-CODE')
authorization_url = client.get_auth_url('token')
return redirect(authorization_url)
#imgurupload.route('/after')
def after_redirect():
with app.test_request_context():
print url_for('after_redirect')
access_token = request.args.get('access_token')
refresh_token = request.args.get('refresh_token')
return access_token
if __name__ == '__main__':
imgurupload.run()

Categories