feat: Slack bot (#469)
Co-authored-by: Taranjeet Singh <reachtotj@gmail.com>
This commit is contained in:
@@ -2,27 +2,25 @@
|
|||||||
title: '💼 Slack Bot'
|
title: '💼 Slack Bot'
|
||||||
---
|
---
|
||||||
|
|
||||||
### 🖼️ Template Setup
|
### 🖼️ Setup
|
||||||
|
|
||||||
- Fork [this](https://replit.com/@taranjeetio/EC-Slack-Bot-Template?v=1#README.md) replit template.
|
1. Create a workspace on Slack if you don't have one already by clicking [here](https://slack.com/intl/en-in/).
|
||||||
- Set your `OPENAI_API_KEY` in Secrets.
|
2. Create a new App on your Slack account by going [here](https://api.slack.com/apps).
|
||||||
- Create a workspace on Slack if you don't have one already by clicking [here](https://slack.com/intl/en-in/).
|
3. Select `From Scratch`, then enter the Bot Name and select your workspace.
|
||||||
- Create a new App on your Slack account by going [here](https://api.slack.com/apps).
|
4. On the left Sidebar, go to `OAuth and Permissions` and add the following scopes under `Bot Token Scopes`:
|
||||||
- Select `From Scratch`, then enter the Bot Name and select your workspace.
|
|
||||||
- On the `Basic Information` page copy the `Signing Secret` and set it in your secrets as `SLACK_SIGNING_SECRET`.
|
|
||||||
- On the left Sidebar, go to `OAuth and Permissions` and add the following scopes under `Bot Token Scopes`:
|
|
||||||
```text
|
```text
|
||||||
app_mentions:read
|
app_mentions:read
|
||||||
channels:history
|
channels:history
|
||||||
channels:read
|
channels:read
|
||||||
chat:write
|
chat:write
|
||||||
```
|
```
|
||||||
- Now select the option `Install to Workspace` and after it's done, copy the `Bot User OAuth Token` and set it in your secrets as `SLACK_BOT_TOKEN`.
|
5. Now select the option `Install to Workspace` and after it's done, copy the `Bot User OAuth Token` and set it in your secrets as `SLACK_BOT_TOKEN`.
|
||||||
- Start your replit container now by clicking on `Run`.
|
6. Run your bot now with `python3 -m embedchain.bots.slack`
|
||||||
- On the Slack API website go to `Event Subscriptions` on the left Sidebar and turn on `Enable Events`.
|
7. Expose your bot to the internet. Default port is `5000`, which can be changed by adding `port --8080` to the startup command. You can use your machine's public IP or DNS. Otherwise, employ a proxy server like [ngrok](https://ngrok.com/) to make your local bot accessible.
|
||||||
- Copy the generated server URL in replit, append `/chat` at its end and paste it in `Request URL` box.
|
8. On the Slack API website go to `Event Subscriptions` on the left Sidebar and turn on `Enable Events`.
|
||||||
- After it gets verified, click on `Subscribe to bot events`, add `message.channels` Bot User Event and click on `Save Changes`.
|
9. In `Request URL`, enter your server or ngrok address.
|
||||||
- Now go to your workspace, click on the bot name in the Sidebar and then add the bot to any channel you want.
|
10. After it gets verified, click on `Subscribe to bot events`, add `message.channels` Bot User Event and click on `Save Changes`.
|
||||||
|
11. Now go to your workspace, right click on the bot name in the sidebar, click `view app details`, then `add this app to a channel`.
|
||||||
|
|
||||||
### 🚀 Usage Instructions
|
### 🚀 Usage Instructions
|
||||||
|
|
||||||
|
|||||||
98
embedchain/bots/slack.py
Normal file
98
embedchain/bots/slack.py
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from embedchain import App
|
||||||
|
from embedchain.helper_classes.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
from .base import BaseBot
|
||||||
|
|
||||||
|
try:
|
||||||
|
from flask import Flask, request
|
||||||
|
from slack_sdk import WebClient
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
raise ModuleNotFoundError(
|
||||||
|
"The required dependencies for Slack are not installed." 'Please install with `pip install "embedchain[slack]"`'
|
||||||
|
) from None
|
||||||
|
|
||||||
|
|
||||||
|
SLACK_BOT_TOKEN = os.environ.get("SLACK_BOT_TOKEN")
|
||||||
|
|
||||||
|
|
||||||
|
@register_deserializable
|
||||||
|
class SlackBot(BaseBot):
|
||||||
|
def __init__(self):
|
||||||
|
self.client = WebClient(token=SLACK_BOT_TOKEN)
|
||||||
|
self.chat_bot = App()
|
||||||
|
self.recent_message = {"ts": 0, "channel": ""}
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def handle_message(self, event_data):
|
||||||
|
message = event_data.get("event")
|
||||||
|
if message and "text" in message and message.get("subtype") != "bot_message":
|
||||||
|
text: str = message["text"]
|
||||||
|
if float(message.get("ts")) > float(self.recent_message["ts"]):
|
||||||
|
self.recent_message["ts"] = message["ts"]
|
||||||
|
self.recent_message["channel"] = message["channel"]
|
||||||
|
if text.startswith("query"):
|
||||||
|
_, question = text.split(" ", 1)
|
||||||
|
try:
|
||||||
|
response = self.chat_bot.chat(question)
|
||||||
|
self.send_slack_message(message["channel"], response)
|
||||||
|
logging.info("Query answered successfully!")
|
||||||
|
except Exception as e:
|
||||||
|
self.send_slack_message(message["channel"], "An error occurred. Please try again!")
|
||||||
|
logging.error("Error occurred during 'query' command:", e)
|
||||||
|
elif text.startswith("add"):
|
||||||
|
_, data_type, url_or_text = text.split(" ", 2)
|
||||||
|
if url_or_text.startswith("<") and url_or_text.endswith(">"):
|
||||||
|
url_or_text = url_or_text[1:-1]
|
||||||
|
try:
|
||||||
|
self.chat_bot.add(url_or_text, data_type)
|
||||||
|
self.send_slack_message(message["channel"], f"Added {data_type} : {url_or_text}")
|
||||||
|
except ValueError as e:
|
||||||
|
self.send_slack_message(message["channel"], f"Error: {str(e)}")
|
||||||
|
logging.error("Error occurred during 'add' command:", e)
|
||||||
|
except Exception as e:
|
||||||
|
self.send_slack_message(message["channel"], f"Failed to add {data_type} : {url_or_text}")
|
||||||
|
logging.error("Error occurred during 'add' command:", e)
|
||||||
|
|
||||||
|
def send_slack_message(self, channel, message):
|
||||||
|
response = self.client.chat_postMessage(channel=channel, text=message)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def start(self, host="0.0.0.0", port=5000, debug=True):
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
def signal_handler(sig, frame):
|
||||||
|
logging.info("\nGracefully shutting down the SlackBot...")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
|
||||||
|
@app.route("/", methods=["POST"])
|
||||||
|
def chat():
|
||||||
|
# Check if the request is a verification request
|
||||||
|
if request.json.get("challenge"):
|
||||||
|
return str(request.json.get("challenge"))
|
||||||
|
|
||||||
|
response = self.handle_message(request.json)
|
||||||
|
return str(response)
|
||||||
|
|
||||||
|
app.run(host=host, port=port, debug=debug)
|
||||||
|
|
||||||
|
|
||||||
|
def start_command():
|
||||||
|
parser = argparse.ArgumentParser(description="EmbedChain SlackBot command line interface")
|
||||||
|
parser.add_argument("--host", default="0.0.0.0", help="Host IP to bind")
|
||||||
|
parser.add_argument("--port", default=5000, type=int, help="Port to bind")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
slack_bot = SlackBot()
|
||||||
|
slack_bot.start(host=args.host, port=args.port)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
start_command()
|
||||||
7
examples/slack_bot/.gitignore
vendored
7
examples/slack_bot/.gitignore
vendored
@@ -1,7 +0,0 @@
|
|||||||
__pycache__
|
|
||||||
db
|
|
||||||
database
|
|
||||||
pyenv
|
|
||||||
venv
|
|
||||||
.env
|
|
||||||
trash_files/
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# Slack Bot
|
|
||||||
|
|
||||||
This is a replit template to create your own Slack bot using the embedchain package. To know more about the bot and how to use it, go [here](https://docs.embedchain.ai/examples/slack_bot).
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
flask==2.3.2
|
|
||||||
slackeventsapi==3.0.1
|
|
||||||
slacksdk==3.21.3
|
|
||||||
python-dotenv==1.0.0
|
|
||||||
embedchain
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
from flask import Flask
|
|
||||||
from slack_sdk import WebClient
|
|
||||||
from slackeventsapi import SlackEventAdapter
|
|
||||||
|
|
||||||
from embedchain import App
|
|
||||||
|
|
||||||
load_dotenv()
|
|
||||||
app = Flask(__name__)
|
|
||||||
|
|
||||||
slack_signing_secret = os.environ.get("SLACK_SIGNING_SECRET")
|
|
||||||
slack_events_adapter = SlackEventAdapter(slack_signing_secret, "/chat", app)
|
|
||||||
|
|
||||||
slack_bot_token = os.environ.get("SLACK_BOT_TOKEN")
|
|
||||||
client = WebClient(token=slack_bot_token)
|
|
||||||
|
|
||||||
chat_bot = App()
|
|
||||||
recent_message = {"ts": 0, "channel": ""}
|
|
||||||
|
|
||||||
|
|
||||||
@slack_events_adapter.on("message")
|
|
||||||
def handle_message(event_data):
|
|
||||||
message = event_data["event"]
|
|
||||||
if "text" in message and message.get("subtype") != "bot_message":
|
|
||||||
text = message["text"]
|
|
||||||
if float(message.get("ts")) > float(recent_message["ts"]):
|
|
||||||
recent_message["ts"] = message["ts"]
|
|
||||||
recent_message["channel"] = message["channel"]
|
|
||||||
if text.startswith("query"):
|
|
||||||
_, question = text.split(" ", 1)
|
|
||||||
try:
|
|
||||||
response = chat_bot.chat(question)
|
|
||||||
send_slack_message(message["channel"], response)
|
|
||||||
print("Query answered successfully!")
|
|
||||||
except Exception as e:
|
|
||||||
send_slack_message(message["channel"], "An error occurred. Please try again!")
|
|
||||||
print("Error occurred during 'query' command:", e)
|
|
||||||
elif text.startswith("add"):
|
|
||||||
_, data_type, url_or_text = text.split(" ", 2)
|
|
||||||
if url_or_text.startswith("<") and url_or_text.endswith(">"):
|
|
||||||
url_or_text = url_or_text[1:-1]
|
|
||||||
try:
|
|
||||||
chat_bot.add(data_type, url_or_text)
|
|
||||||
send_slack_message(message["channel"], f"Added {data_type} : {url_or_text}")
|
|
||||||
except Exception as e:
|
|
||||||
send_slack_message(message["channel"], f"Failed to add {data_type} : {url_or_text}")
|
|
||||||
print("Error occurred during 'add' command:", e)
|
|
||||||
|
|
||||||
|
|
||||||
def send_slack_message(channel, message):
|
|
||||||
response = client.chat_postMessage(channel=channel, text=message)
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
app.run(host="0.0.0.0", port=5000, debug=False)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
SLACK_SIGNING_SECRET=""
|
|
||||||
SLACK_BOT_TOKEN=""
|
|
||||||
OPENAI_API_KEY=""
|
|
||||||
@@ -101,6 +101,7 @@ flask = "^2.3.3"
|
|||||||
twilio = "^8.5.0"
|
twilio = "^8.5.0"
|
||||||
fastapi-poe = { version = "0.0.16", optional = true }
|
fastapi-poe = { version = "0.0.16", optional = true }
|
||||||
discord = { version = "^2.3.2", optional = true }
|
discord = { version = "^2.3.2", optional = true }
|
||||||
|
slack-sdk = { version = "3.21.3", optional = true }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -121,6 +122,7 @@ opensource = ["sentence-transformers", "torch", "gpt4all"]
|
|||||||
elasticsearch = ["elasticsearch"]
|
elasticsearch = ["elasticsearch"]
|
||||||
poe = ["fastapi-poe"]
|
poe = ["fastapi-poe"]
|
||||||
discord = ["discord"]
|
discord = ["discord"]
|
||||||
|
slack = ["slack-sdk", "flask"]
|
||||||
|
|
||||||
[tool.poetry.group.docs.dependencies]
|
[tool.poetry.group.docs.dependencies]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user