I'm setting up a Twilio-Dialogflow WhatsApp Chatbot following this tutorial: https://www.youtube.com/watch?v=r5EMHIQiGWE
code as below:
from http.client import responses
from flask import Flask, request, jsonify
import os, dialogflow
from flask.globals import session
from google.api_core.exceptions import InvalidArgument
import requests
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = 'private_key.json'
DIALOGFLOW_PROJECT_ID = 'whatsapp-twilio-flask-dia-svau'
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')
mobnum = 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
sendMessage(mobnum,response.query_result.fulfillment_text)
return response.query_result.fulfillment_text
def sendMessage(mobnum,message):
url = "https://api.twilio.com/2010-04-01/Accounts/XXXXXXXXXX/Messages.json"
payload = {'From': 'whatsapp:+14155238886', 'Body': message, 'To': mobnum}
headers = {'Authorization': 'Basic XXXXXXXXXXXXXXXXXXXXXXXXXXX' }
response = requests.request("POST", url, headers = headers, data=payload)
print(response.text.encode('utf8'))
return ""
if __name__ == '__main__':
app.run()
running the code gives this error at Twilio, because of this I'm not getting a reply in the WhatsApp
Warning - 12200
Schema validation warning
The provided XML does not conform to the Twilio Markup XML schema.
response.text returns this :
print(response.text.encode('utf8')) :
b'{"sid": "XXX", "date_created": "XXX", "date_updated": "XXX", "date_sent": null, "account_sid": "XXX", "to": "whatsapp:+XXX", "from": "whatsapp:+XXX", "messaging_service_sid": null, "body": "Good day! What can I do for you today?", "status": "queued", "num_segments": "1", "num_media": "0", "direction": "outbound-api", "api_version": "2010-04-01", "price": null, "price_unit": null, "error_code": null, "error_message": null, "uri": "XXX", "subresource_uris": {"media": "XXX"}}'
Anybody can help, please? Am I getting the above error from Twilio because I did not use twilio.twiml libraries? But from the tutorial video, I don't see this library being used.
Twilio developer evangelist here.
The way that you (and the video tutorial) have set up the response is not quite right. You have the WhatsApp sandbox webhook pointed at your /api/getMessage
endpoint, which is correct, but the way you respond to that request is not right for Twilio.
When Twilio makes a webhook request to your application it expects the response to be an XML response, containing TwiML. You can even use TwiML to respond with a message, so you don't need to make requests to the REST API to send the message.
Another thing you can do, to make things easier, is to install and use the Twilio Python helper library. You can use it to make requests to the API and also to build TwiML responses.
So, I would recommend that you install the Twilio Python library:
pip install twilio
Then use the library in your app to build up and return a TwiML response, like this:
from http.client import responses
from flask import Flask, request, jsonify, Response
import os, dialogflow
from flask.globals import session
from google.api_core.exceptions import InvalidArgument
from twilio.twiml.messaging_response import MessagingResponse
import requests
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = 'private_key.json'
DIALOGFLOW_PROJECT_ID = 'whatsapp-twilio-flask-dia-svau'
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')
mobnum = 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:
intent = session_client.detect_intent(session=session, query_input=query_input)
except InvalidArgument:
raise
response = MessagingResponse()
response.message(intent.query_result.fulfillment_text)
return Response(str(response), mimetype="application/xml")
if __name__ == '__main__':
app.run()
In this code, instead of calling the original sendMessage
function we import MessagingResponse
from twilio.twiml.messaging_response
and create a response that we return as XML, using the Response
object to set both the content and the mimetype.
Response(str(response), mimetype="application/xml")
This will both simplify your code and get rid of the schema validation warning. Check this blog post on building with Twilio and Flask for more information.