I have been trying to send an automated message from my Facebook page to an open conversation. I have been using Graph API's /me/messages endpoint using Page Access Token, but it doesn't seem to work.
Following is the code
def sendMessage(to_id, msg):
print(f"Sending message to {to_id}")
url = f"https://graph.facebook.com/v13.0/me/messages?access_token={page_access_token}"
payload = {
"messaging_type": "RESPONSE",
"recipient": {
"id": to_id
},
"message":{
"text": msg
}
}
res = requests.post(url, payload)
print(res.content)
After calling this function, when I print the content of the response, it shows this:
b'{"error":{"message":"(#100) param recipient must be non-empty.","type":"OAuthException","code":100,"fbtrace_id":"A4QA9xqFj9Uch12oi6KRPQb"}}'
The error message is quite straightforward.
I think you should check again your param: to_id, it could be empty or undefined/null in your case.
Further check msg if needed.
i have the below posted json response.as shown below in json section, the parametersobject is emitted in this line (this is an angular application)
this._FromInsToSiteDataService.emitOnSubmitButtonClikedBroadcast(parameters)
and it is received in
this.subscriptionBroadcastEmitterOnSubmitButtonClicked = this._FromInsecticidesToSiteMapDataService.getBroascastEmitterOnSubmitButtonClicked().subscribe((response:Object)=>{
response['siteGeometry'] = this.selectedSite.geometry
console.log("response: ", response)
this.sSProvider.startWebServiceFor(response)
});
in the latter code i want to pass the response which is in json format to the webservice and receive it as show in the websrvicepostedbelow`
when i run the code, i expected to see the contents of the json object which is
{
"dist1": d1,
"dist2": d2,
"date1": date1,
"date2": date2,
"ingredient": activeIngredient
}
but i get NONE
please let me know how can i correctly get a json object from a webservice
json
private submit() {
let parameters = {
"dist1": d1,
"dist2": d2,
"date1": date1,
"date2": date2,
"ingredient": activeIngredient
}
this._FromInsToSiteDataService.emitOnSubmitButtonClikedBroadcast(parameters)
receiving the json object
this.subscriptionBroadcastEmitterOnSubmitButtonClicked = this._FromInsecticidesToSiteMapDataService.getBroascastEmitterOnSubmitButtonClicked().subscribe((response:Object)=>{
response['siteGeometry'] = this.selectedSite.geometry
console.log("response: ", response)
this.sSProvider.startWebServiceFor(response)
});
webservice:
#app.route("/insSpecifications/<parameters>", methods=['GET'] )
def insSpecifications(parameters):
# print(request.json())
print(request.get_json())//returns NONE
return "OK"
Intro
There are two parts to your question -
Making a request from JS
Creating a Flask API to handle the request
Both these have extensively answered on SO hence I will only summarize it here, please follow the links for more information
Answer
REST Method:
When sending JSON data from the front end to the backend, you need to make a POST request or PUT depending on the need. Please read up on REST API concepts to understand the methods and purposes.
https://www.w3schools.in/restful-web-services/rest-methods/
Making a request
Depending on which library you use in the front end, the request might look different, but essentially you need to send a request with JSON in the body and HEADERS set appropriately i.e. Content-Type: application/json
Using FETCH this can be achieved by (auto-generated from postman)
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
var raw = JSON.stringify({
"username": "Sample1",
"email": "test2#test.com"
});
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch("localhost:5000/sample", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
But most libraries would have wrappers around this, please look into making a POST request for your respective JS library
Creating Flask API
Finally, you need a Flask API to consume this request. Assuming it's a POST request. You need to create a route with method as POST and get the JSON data using get_json() : https://stackoverflow.com/a/20001283/5236575
So once the HEADERS are correctly set and a post request is made, your code should work fine by changing GET to POST
Note: The parameters field is captured correctly hence I'm leaving it as is, but that is not where your JSON body comes from
#app.route("/insSpecifications/<parameters>", methods=['POST'] )
def insSpecifications(parameters):
# print(request.json())
print(request.get_json())
return "OK"
Testing
You can test your API using Postman or any other API testing tool to see how the API behaves and validate if the issue you have is in the API or in the front-end code.
I'm trying to create a bot using DialogFlow, Twilio and Flask but I'm currently stuck at something that show seem easy but couldn't find a lot of answers.
Basically I fetch de json answer from Dialogflow using the function below:
def fetch_reply(query, session_id):
#gets response from DialogFlow
response = detect_intent_from_text(query, session_id)
resp = {}
#Understading response and seeting it to a dictionary
print(response)
resp['text']=response.fulfillment_text
resp['intent']=response.intent.display_name
resp['parameters'] = response.parameters.fields.values()
return resp
I printed the full response, and it gives me the following:
query_text: "Tim\303\243o"
parameters {
fields {
key: "soccerteams"
value {
string_value: "Corinthians"
}
}
}
all_required_params_present: true
fulfillment_messages {
text {
text: ""
}
}
intent {
name: "projects/whatsappbotsports-ylml/agent/intents/e7bcf0f5-d37f-4c8b-81ad-09579fded36a"
display_name: "Default Team Request"
}
intent_detection_confidence: 1.0
language_code: "pt-br"
but when I print the resp['parameter'] my result is:
ValuesView({'soccerteams': string_value: "Corinthians"
})
All I need to access is "Corinthians", or the value of string_value, but I can't find a way to do it. If I try to use resp['parameter'].value or resp['parameter'].string_value it gives me that ValuesView doesn't have this attributes.
Any idea how to do it?
That's some very strange output that you have. It's not a JSON, since the keys don't have quotes around them.
Can you try something like this?
import json
from google.protobuf.json_format import MessageToJson
def fetch_reply(query, session_id):
#gets response from DialogFlow
response = detect_intent_from_text(query, session_id)
# trying to parse json
soccerteams = response.parameters.fields["soccerteams"]
soccerteams_json = json.loads(MessageToJson(soccerteams))
return soccerteams_json
and then try to get the value from json.
That's just my try to adapt this code: Get Dialogflow context parameters from a follow up intent in Python
Let me know if it worked. If not, please send some output.
I would like to constantly send data using Django WebSockets. At this moment I try in the way shown below.
routing.py:
channel_routing = [
route("websocket.connect", ws_connect),
consumers.py:
def ws_connect(message):
message.reply_channel.send({"accept": True})
while True:
message.reply_channel.send({
"text": json.dumps({
'message': 'My response2'
})
})
Unfortunately it doesn't work properly. Obviously without while True it send data but only once. Any ideas how can I solve it?
I'm trying to get the FB messenger API working using Python's Flask, adapting the following instructions: https://developers.facebook.com/docs/messenger-platform/quickstart
So far, things have been going pretty well. I have verified my callback and am able to receive the messages I send using Messenger on my page, as in the logs in my heroku server indicate the appropriate packets of data are being received by my server. Right now I'm struggling a bit to send responses to the client messenging my app. In particular, I am not sure how to perform the following segment from the tutorial in Flask:
var token = "<page_access_token>";
function sendTextMessage(sender, text) {
messageData = {
text:text
}
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending message: ', error);
} else if (response.body.error) {
console.log('Error: ', response.body.error);
}
});
}
So far, I have this bit in my server-side Flask module:
#app.route('/', methods=["GET", "POST"])
def chatbot_response():
data = json.loads(req_data)
sender_id = data["entry"][0]["messaging"][0]["sender"]["id"]
url = "https://graph.facebook.com/v2.6/me/messages"
qs_value = {"access_token": TOKEN_OMITTED}
json_response = {"recipient": {"id": sender_id}, "message": "this is a test response message"}
response = ("my response text", 200, {"url": url, "qs": qs_value, "method": "POST", "json": json_response})
return response
However, running this, I find that while I can process what someone send my Page, it does not send a response back (i.e. nothing shows up in the messenger chat box). I'm new to Flask so any help would be greatly appreciated in doing the equivalent of the Javascript bit above in Flask.
Thanks!
This is the code that works for me:
data = json.loads(request.data)['entry'][0]['messaging']
for m in data:
resp_id = m['sender']['id']
resp_mess = {
'recipient': {
'id': resp_id,
},
'message': {
'text': m['message']['text'],
}
}
fb_response = requests.post(FB_MESSAGES_ENDPOINT,
params={"access_token": FB_TOKEN},
data=json.dumps(resp_mess),
headers = {'content-type': 'application/json'})
key differences:
message needs a text key for the actual response message, and you need to add the application/json content-type header.
Without the content-type header you get the The parameter recipient is required error response, and without the text key under message you get the param message must be non-empty error response.
This is the Flask example using fbmq library that works for me:
echo example :
from flask import Flask, request
from fbmq import Page
page = fbmq.Page(PAGE_ACCESS_TOKEN)
#app.route('/webhook', methods=['POST'])
def webhook():
page.handle_webhook(request.get_data(as_text=True))
return "ok"
#page.handle_message
def message_handler(event):
page.send(event.sender_id, event.message_text)
In that scenario in your tutorial, the node.js application is sending an HTTP POST request back to Facebook's servers, which then forwards the content on to the client.
So far, sounds like your Flask app is only receiving (AKA serving) HTTP requests. The reason is that that's what the Flask library is all about, and it's the only thing that Flask does.
To send an HTTP request back to Facebook, you can use any Python HTTP client library you like. There is one called urllib in the standard library, but it's a bit clunky to use... try the Requests library.
Since your request handler is delegating to an outgoing HTTP call, you need to look at the response to this sub-request also, to make sure everything went as planned.
Your handler may end up looking something like
import json
import os
from flask import app, request
# confusingly similar name, keep these straight in your head
import requests
FB_MESSAGES_ENDPOINT = "https://graph.facebook.com/v2.6/me/messages"
# good practice: don't keep secrets in files, one day you'll accidentally
# commit it and push it to github and then you'll be sad. in bash:
# $ export FB_ACCESS_TOKEN=my-secret-fb-token
FB_TOKEN = os.environ['FB_ACCESS_TOKEN']
#app.route('/', method="POST")
def chatbot_response():
data = request.json() # flasks's request object
sender_id = data["entry"][0]["messaging"][0]["sender"]["id"]
send_back_to_fb = {
"recipient": {
"id": sender_id,
},
"message": "this is a test response message"
}
# the big change: use another library to send an HTTP request back to FB
fb_response = requests.post(FB_MESSAGES_ENDPOINT,
params={"access_token": FB_TOKEN},
data=json.dumps(send_back_to_fb))
# handle the response to the subrequest you made
if not fb_response.ok:
# log some useful info for yourself, for debugging
print 'jeepers. %s: %s' % (fb_response.status_code, fb_response.text)
# always return 200 to Facebook's original POST request so they know you
# handled their request
return "OK", 200
When doing responses in Flask, you have to be careful. Simply doing a return statement won't return anything to the requester.
In your case, you might want to look at jsonify(). It will take a Python dictionary and return it to your browser as a JSON object.
from flask import jsonify
return jsonify({"url": url, "qs": qs_value, "method": "POST", "json": json_response})
If you want more control over the responses, like setting codes, take a look at make_response()