Context: My company uses receives messages of new leads in a slack channel. They indiciate whether it is qualified or not by using a emoji/reactions on the message.
I'm trying to create a Slack App/Bot that can count the various reactions in a given week (Monday-Sunday range) to automate our report on this. I have the basic bot strucutre up and running, but I don't know how to count the reactions from past messages. (using conversation.history perhaps?)
Please help, how would I go about looking at old messages in a slack channel (not using listening) and counting the emoji/reaction on each message?
import slack
import os
from pathlib import Path
from dotenv import load_dotenv
from flask import Flask
from slackeventsapi import SlackEventAdapter
from slack_sdk.errors import SlackApiError
env_path = Path('.') / '.env'
load_dotenv(dotenv_path=env_path)
app = Flask(__name__)
slack_event_adapter = SlackEventAdapter(os.environ['SLACK_SIGNING_SECRET'], "/slack/events", app)
client = slack.WebClient(token=os.environ['SLACK_API_TOKEN'])
channel_name = "test"
conversation_id = None
try:
# Call the conversations.list method using the WebClient
for result in client.conversations_list():
if conversation_id is None:
break
for channel in result['channels']:
if channel['name'] == channel_name:
conversation_id = channel['id']
# Print result (THIS ISN'T PRINTING ANYTHING)
print(f"\nFound conversation ID {conversation_id}\n")
break
except SlackApiError as e:
print(f"Error: {e}")
if __name__ == "__main__":
app.run(debug=True)
Related
as the title states, I'm writing a Slack Bot in Python and using NGROK to host it locally. I'm not super experienced with decorators, and I can get the bot posting messages in slack, however I can't seem to handle two events at once. For example, I want to handle a message and have the message keep repeating in slack until a thumbs up reaction is added to that message. The issue is I cannot figure out how to handle an event while another event is still running, please see the following code:
rom slack import WebClient
import os
import time
from pathlib import Path
from dotenv import load_dotenv
from flask import Flask
from slackeventsapi import SlackEventAdapter
env_path = Path('.') / '.env'
load_dotenv(dotenv_path=env_path)
app = Flask(__name__)
slack_event_adapter = SlackEventAdapter(
os.environ['SIGNING_SECRET'],'/slack/events',app)
client = WebClient(token=os.environ['SLACK_TOKEN'])
BOT_ID = client.api_call("auth.test")['user_id']
state = {}
#slack_event_adapter.on('message')
def handle_message(event_data):
message = event_data.get('event', {})
channel_id = message.get('channel')
user_id = message.get('user')
text = message.get('text')
messageid = message.get('ts')
state[messageid] = {"channel_id": channel_id, "user_id": user_id, "text": text}
if BOT_ID != user_id:
if text[0:12] == ":red_circle:":
time.sleep(5)
client.chat_postMessage(channel=channel_id, text=text)
if text[0:21] == ":large_yellow_circle:":
client.chat_postMessage(channel=channel_id, text="it's a yellow question!")
if text[0:14] == ":white_circle:":
client.chat_postMessage(channel=channel_id, text="it's a white question!")
#slack_event_adapter.on('reaction_added')
def reaction_added(event_data):
reaction = event_data.get('event',{})
emoji = reaction.get('reaction')
emoji_id = reaction.get('item',{}).get('ts')
emoji_channel_id = reaction.get('item',{}).get('channel')
client.chat_postMessage(channel=emoji_channel_id, text=emoji)
for message_id, message_data in state.items():
channel_id = message_data["channel_id"]
text = message_data["text"]
client.chat_postMessage(channel=channel_id, text=text)
print(message_id,message_data)
if __name__ == "__main__":
app.run(debug=True)
I can handle individual events, but I cannot handle them while another is running. Please help! :)
Flask is a synchronous web framework.
When it's running a view handler, it uses up a web worker thread. If you does something like time.sleep(...), that worker thread will still be occupied and unavailable to handle other requests until the sleep finishes.
There are a couple options you can do here.
You can use Bolt for Python, which is a Python Slack library that natively support asynchronous even processing. Instead of time.sleep(), you can do await asyncio.sleep(...), which returns the thread to the async loop, and allow the worker thread to process other events.
If you already have an existing slack application and don't want to rewrite your entire codebase to Bolt, then you'll need to handle the event processing yourself. You can do this by doing your work in an ThreadLoopExecutor, or by building your own async event Queue mechanism, or use Celery. Or if your slack bot has very low volume, you can probably just add more web workers, and hope for the best that you don't run out of workers.
I created a python slack bot and tested it with Ngrok. I then created an azure function and connected to the code via repository. Now where can I find the URL that will replace the request URL in slack.
Below image is the azure function.
I also attached the code which I tested for slack bot.
import slack
import os
from pathlib import Path
from dotenv import load_dotenv
from flask import Flask
from slackeventsapi import SlackEventAdapter
env_path= Path('.')/'.env'
load_dotenv(dotenv_path=env_path)
app = Flask(__name__)
slack_event_adapter = SlackEventAdapter(
os.environ['SIGNING_SECRET'], '/slack/events', app)
client = slack.WebClient(token=os.environ['SLACK_TOKEN'])
BOT_ID = client.api_call("auth.test")['user_id']
#slack_event_adapter.on('message')
def message(payload):
event = payload.get('event', {})
channel_id = event.get('channel')
user_id = event.get('user')
text = event.get('text')
if BOT_ID != user_id:
client.chat_postMessage(channel=channel_id, text=text)
if __name__ == "__main__":
app.run(debug=True)
I am very new to azure. Thanks in advance.
I tried the following URLs from the azure function but that did not work. I tried
https://demo-flask.azurewebsites.net
https://demo-flask.azurewebsites.net/slack/event
I am at the point where my bot can join a room and reply when a user says something. However, I would like to have my bot join a slack room #room1 and monitor that room and threads for a variation of keywords (0 out of 20, 1 out of 20, 2 out of 20....up to 19 out of 20). Whenever those phrases are seen I would like the bot to send a link of that thread to another room where support staff is waiting #support and they can then take action. Here is my current code:
import slack
import os
from pathlib import Path
from dotenv import load_dotenv
from flask import Flask
from slackeventsapi import SlackEventAdapter
env_path = Path('.') / '.env'
load_dotenv(dotenv_path=env_path)
app = Flask(__name__)
slack_event_adapter = SlackEventAdapter(
os.environ['SIGNING_SECRET'], '/slack/events', app)
client = slack.WebClient(token=os.environ['SLACK_TOKEN'])
BOT_ID = client.api_call("auth.test")['user_id']
#slack_event_adapter.on('message')
def message(payload):
event = payload.get('event', {})
channel_id = event.get('channel')
user_id = event.get('user')
text = event.get('text')
if BOT_ID != user_id:
client.chat_postMessage(channel=channel_id, text=text)
if __name__=="__main__":
app.run(debug=True)
I am trying to use the Slack-bolt API for python to listen to DMs to the slack bot that contain specific text. Here is my file that initiates the Slack-Bolt listener
import os
from server import *
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
# Initializes your app with your bot token and socket mode handler
app = App(token=MY_TOKEN)
# Listens to incoming messages that contain "list"
#app.message("list")
def message_hello(message, say):
# say() sends a message to the channel where the event was triggered
res = requests.get(url + '/api/users/list')
say("The list of users is: ", res.json())
# Start your app
if __name__ == "__main__":
SocketModeHandler(app, "TOKEN").start()
When I send messages to my bot I am getting "127.0.0.1 - - [20/Mar/2022 00:23:47] "POST /api HTTP/1.1" 200 -" but the listener is not executing the code it contains. I cannot get it to say hello back inside of Slack in any way.
Thanks
Instead of setting the app to listen for every word posted, I would suggest using the "app_mention" event which triggers only when the message sent begins with
#your_bot_name followed by your message. This way you will avoid getting random responses from your bot when sending messages which contain specific keywords.
#app.event("app_mention")
def test(ack,event,logger):
ack()
name = event["user"] # gets the name of the user who triggered the event
channel =event["channel"] # gets the channel in which the event was triggered
text = event["text"].lower() # gets the lowercase text of your sent message
ts = event["ts"] # gets the timestamp of the message (this is used for replying in threads)
if any(x in text for x in ("users list","list of users")): # if you need specific combinations of keywords i would recommend using this method)
# if text == "list" :
try:
app.client.chat_postMessage(channel = channel, thread_ts=ts, text = f"*Hi <#{name}>, Here is a random response*")
except:
print(logger.info)
In the end you could trigger a response from your bot app by posting a message like so:
#your_bot_name show me the users list
or
#your_bot_name show me the list of users
I was trying to make a slack bot using slackeventsapi running on ngrok for now.
It can send messages properly but slack events adaptor doesn't seem to be working properly. It gives the code 200 every time a message is sent but the payload doesn't come. I tried printing it but the printing it shows nothing.
There was another post asking a similar question whose solution in the end was to make a new app on slack API but it doesn't seem to fix my issue. I have made another app but the issue persists.
I was following a tutorial so I have tried to match his code exactly but it doesn't seem to work even then. In case it will be helpful - https://www.youtube.com/watch?v=6gHvqXrfjuo&list=PLzMcBGfZo4-kqyzTzJWCV6lyK-ZMYECDc&index=2.
The slack API scopes
Slack API Subscriptions
import slack
import os
from pathlib import Path
from dotenv import load_dotenv
from flask import Flask
from slackeventsapi import SlackEventAdapter
env_path = Path('.')/'.env'
load_dotenv(dotenv_path=env_path)
client = slack.WebClient(token=os.environ['TEST2_SLACK_TOKEN'])
BOT_ID = client.api_call("auth.test")['user_id']
app = Flask(__name__)
slack_event_adaptor = SlackEventAdapter(os.environ['SIGNING_SECRET2'], '/slack/events', app)
client.chat_postMessage(channel=f'#new', text="Hello")
if __name__ == "__main__":
app.run(debug=True)
#slack_event_adaptor.on('message')
def message(payload):
print(payload)
event = payload.get('event',{})
channel_id = event.get('channel')
user_id = event.get('user')
text = event.get('text')
if BOT_ID != user_id:
client.chat_postMessage(channel= channel_id, text = text)
I had similar problem when I used slack_event_adaptor and then I tried slack_bolt and everything works well. Let me share example you may try if you want:
import re
from config import config
from flask import Flask, request
from slack_sdk import WebClient
from slack_bolt import App
from slack_bolt.adapter.flask import SlackRequestHandler
app = Flask(__name__)
slack_token = config.slack_token
client = WebClient(slack_token)
bolt_app = App(token=slack_token, signing_secret=config.signing_secret)
handler = SlackRequestHandler(bolt_app)
#bolt_app.message(re.compile("Hello bot",re.IGNORECASE))
def reply_in_thread(payload: dict):
""" This will reply in thread instead of creating a new thread """
response = client.chat_postMessage(channel=payload.get('channel'),
thread_ts=payload.get('ts'),
text=f"Hello<#{payload['user']}>")
#app.route("/datalake/events", methods=["POST"])
def slack_events():
""" Declaring the route where slack will post a request """
return handler.handle(request)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
When you write "Hello bot" bot will respond you accordingly.