Python to post and format API response data into Slack channel - python

Working on a script to present data in Slack channel.. I have a script I'm working on to request and return data that I need to post in the channel that gets invoked with a Slash command, but having an issue with presenting the data in the slack channel from where I've executed the Slash command. I've been attempting to work with the Block Kit Builder, but I see no way of presenting that data coming back from my script using the template I created.
Then in the Block kit builder, I can kind of see the format I want and send it to Slack from the Block kit builder, but if I wanted my return response from my Python script to be formatted by the template and respond in the channel, it doesn't seem to work.. I'm thinking I'm definitely doing something wrong, but was looking for suggestions..
I've been searching on possibly how to do it in Flask, which is what I'm using to execute a Slash command in Slack to invoke my Python script to query the API, get the response and send it to Slack..
Thanx.
P.S. Stackflow won't allow me to post a snippet of the json and/or images.. yet... something about a '10 reputation'...

I was able to figure this out. In my code, I reflected this:
for i in pdjson:
t = {}
try:
t["text"] = {
"type": "plain_text",
"text": f'{i["escalation_policy"]["summary"]} - Layer: {i["escalation_level"]}'
}
except (KeyError):
t["text"] = {
"type": "plain_text",
"text": f'{i["escalation_policy"]["summary"]} - Layer: {i["escalation_level"]}'
}
t["value"] = i["user"]["summary"]
Now I can present in the slack workspace with the block kit template. Now I just have to figure out how make the 'value' show up once I select an item in the list.

Related

Flask and jQuery - "onMessage" event not being called

I'm working on a web interface for a project and need to plot a realtime chart with some data I'll get from an API I'm building. The API runs on http://SERVER_IP:5000/signal and my web interface on http://SERVER_IP:80/, both of them with Flask.
I was having CORS issues at the very beginning and then found out about Flask-CORS. I tried to implement that and now I'm getting no errors on the browser console, but no messages either! I've added some console messages for debugging, but it doesn't seem alright.
On my dashboard, I try to reach the API with the following code:
const source = new EventSource("http://SERVER_IP:5000/signal", {withCredentials: true});
console.log ("Things started!!!");
source.onmessage = function (event) {
console.log ("An event's just happened");
// parse data and do stuff
}
and in my API, I set Flask-CORS like this:
self.__cors = CORS(self.__app, supports_credentials = True)
and the route like this:
#self.__app.route('/signal')
def get_signal():
import json
def get_data():
while True:
json_data = json.dumps(...)
yield "{}\n\n".format(json_data)
time.sleep(1)
return Response(get_data(), mimetype='text/event-stream')
Then, when I open my web browser and open console, I can see the "Things started!!!" message, but no "An event's just happened" and no data on the chart.
I was malforming my response. As I found out here, my "get_data" method should yield "data: ...", so after I added the "data: " after my data, things started to work pretty well.

DialogFlow Python3 Webhook - Increase Timeout?

I have a DialogFlow Intent that manages to parse the user's query about an item price. For example, the user asks "How much for a can of sardines?", my DialogFlow is able to get "can of sardines" as the user input.
Once it get's that, it would proceed to fulfilment where it would send a POST request to a WebHook I have. I linked the Fulfilment to my local Python3 Flask App through ngrok.com.
Right now, what my Python App does is it takes in the user input (can of sardines), and uses PDFGrep to look for the user input through the PDF of the pricelist that's in the server. The pricelist has 3 columns: product code, product name, product price. For each instance that the user input appears, the entire line is sent out as an output. This means that if "can of sardines" appears 3 separate times, the row lines would be shown.
An output to the console would be something like this:
10000 Can of Sardines - 6 Cans $5.00
10001 Can of Sardines - 12 Cans $9.00
10002 Can of Sardines - 18 Cans $13.00
This works in the console just fine.
However, the file is rather large with about 348 pages worth of items. So what happens is that my pdfgrep command takes some time to come up with the output, but DialogFlow, from what I understand, seems to expect a server response from it's POST request within a given short amount of time.
Is there a way to adjust the timeout of the Webook for the DialogFlow API?
There is no way of increasing this timeout because it would spoil the conversation experience of the user i.e user would get frustrated if he has to wait for a long time for a response.
What you can do is, send a response to the user that you are checking for the prices, then once you get the data from the database you send another reply using a POST request to the client.
Dialogflow webhooks have a timeout of 5 seconds.You can increase timeout by chaining intents,that is you can use an intent as a trigger to another intent(which can give you 5+5 seconds to send a response)
Here in this code, when actual_intent is hit it will redirect it to demo_intent
which have an event called demo_event
May be you can use multiprocessing with threading module for the time taking task, adjust the sleep times accordingly
if 'action' in request_['queryResult']:
if request_['queryResult']['action']=='actual_intent':
time.sleep(3)
reply={
"followupEventInput": {
"name": "demo_event",
}
}
return jsonify(reply)
if request_['queryResult']['action']=='demo_intent':
time.sleep(3)
reply = {
"fulfillmentMessages": [
{
"text": {
"text": [
"Some message you want to show"
]
}
},
]
}

Slack API: Do Something when button is clicked

I am using Python and it's Slacker API to post messages to a slack channel and it's posting the messages nicely.
Now what I want to do is create a button that says, More Info and when it's clicked, I want to show a list of items.
But when the button is clicked, slackbot says oh no, something weng wrong, Please try that again
Here is an example: link
Below is my json and the code
msg = "<!here> Hello guys! "
moreInfo = ['person', 'person2', 'person3']
message = [{
"title": "Lunch time has been decided",
"text": "You will also be joining",
"actions": [
{
"name": "buttonName",
"text": "More Info",
"type": "button",
"value": moreInfo
}]
}]
slack.chat.post_message('#teamChannel', msg, username='my_username', attachments=message)
And this is the what it looks like in Slack when I click on More info button.
Any help is appreciated! Thanks :)
Do you have a button endpoint setup already? If not, you will see that error message.
Or if you made the same mistake I did, you are using the incorrect token. This is non-obvious from the Slack docs. You can post a message with a custom integration bot token, including using attachments (i.e. interactive buttons). However, if you want to actually respond to a button press, you need to post the message with a full-fledged Slack app token (even if you don't intend on releasing your app into the wild). That means creating an endpoint for your oauth2 flow to add your app to a Slack team, and acquiring your bot token there.
Create a Slack app if you haven't already.
Create an oauth GET endpoint (e.g. /slack/authorize)
Set your Slack app's "Redirect URI" to your auth endpoint
Your endpoint should expect a code in its query parameters. Call the Slack API oauth.access with your app's client_id, client_secret, and that code to exchange for aforementioned app token. To post your interactive message from a bot, you will need the bot token (prefixed "xoxo-").

Sending Notifications in to multiple users FCM

I am configuring my mobile applications with firebase cloud messaging.
I've finally figured out how to send these annoying to configure notifications.
My python code looks like this
url = 'https://fcm.googleapis.com/fcm/send'
body = {
"data":{
"title":"mytitle",
"body":"mybody",
"url":"myurl"
},
"notification":{
"title":"My web app name",
"body":"message",
"content_available": "true"
},
"to":"device_id_here"
}
headers = {"Content-Type":"application/json",
"Authorization": "key=api_key_here"}
requests.post(url, data=json.dumps(body), headers=headers)
I would think that putting this in a for loop and swapping device ids to send thousands of notifications would be an immense strain on the server and a bad programming practice. (Correct me if i'm wrong)
now the documentation tells me to create "device groups" https://firebase.google.com/docs/cloud-messaging/notifications which store device_id's to send in bulk....this is annoying and inefficient. As my groups for my web application are constantly changing.
Plain and Simple
How do I send the notification above to an array of device id's that I specify in my python code so that i can make only 1 post to FCM instead of thousands.
To send FCM to multiple device you use the key "registration_ids" instead of "to"
"registration_ids": ["fcm_token1", "fcm_token2"]
Have a look at this package and see how they implemented it.
Instead of "to":"device_id" you should use "to":"topic" ,
topic is use from group messaging in FCM or GCM
https://developers.google.com/cloud-messaging/topic-messaging

Google Glass callbackUrl POST from Mirror API is empty?

Apologies because the only web development I know is of the django/python kind and am probably guilty of mixing my code idioms ( REST vs django URL dispatch workflow)
I have a URL handler which serves as a callbackUrl to a subscription for my Glassware. I am getting a POST to the handler , but the request object seems empty.
I am sure I am understanding this wrong but can someone point me in the direction of getting the "REPLY" information from a POST notification to a callbackURL.
My URL Handler is
class A600Handler(webapp2.RequestHandler):
def post(self):
"""Process the value of A600 received and return a plot"""
# I am seeing this in my logs proving that I am getting a POST when glass replies
logging.info("Received POST to logA600")
# This is returning None
my_collection = self.request.get("collection")
logging.info(my_collection)
# I also tried this but self.sequest.POST is empty '[]' and of type UnicodeMultiDict
# json_request_data = json.loads(self.request.POST)
#util.auth_required
def get(self):
"""Process the value of A600 received and return a plot"""
logging.info("Received GET to this logA600")
I have the following URL Handler defined and can verify that the post function is getting a "ping" when the user hits reply by looking at the app-engine logs.
MAIN_ROUTES = [
('/', MainHandler),('/logA600',A600Handler),
]
How do I extract the payload in the form of the voice transcribed text sent by the user?. I am not understanding The "parse_notification" example given in the docs
Did you try request.body? The docs for request.POST state
"If you need to access raw or non-form data posted in the request, access this through the HttpRequest.body attribute instead."
If the API isn't using form data in its post, you'll likely find the contents in request.body. The docs to which you linked indicate that the content will be placed as JSON in the body instead of form data ("containing a JSON request body"). I would try json.loads(request.body).
I am also having this issue of Mirror API calling my application for notifications, and those notifications are empty. My app runs on tomcat so its a java stack. All the samples process the notification like this:
BufferedReader notificationReader = new BufferedReader(
new InputStreamReader(request.getInputStream()));
String notificationString = "";
// Count the lines as a very basic way to prevent Denial of Service
// attacks
int lines = 0;
while (notificationReader.ready()) {
notificationString += notificationReader.readLine();
lines++;
// No notification would ever be this long. Something is very wrong.
if (lines > 1000) {
throw new IOException(
"Attempted to parse notification payload that was unexpectedly long.");
}
}
log.info("got raw notification " + notificationString);
For me this is always logging as empty. Since a notification url must be https, and for testing I could not use an IP address, I have setup dyndns service to point to my localhost:8080 running service. This all seems to work but I suspect how dyndns works is some type of forward or redirect here post data is removed.
How can I work around this for local development?
Updated:
Solved for me.
I found closing the response before reading request caused issue that request.inputStream was already closed. MOving this
response.setContentType("text/html");
Writer writer = response.getWriter();
writer.append("OK");
writer.close();
To after I fully read in request notification into a String solved the issue.

Categories

Resources