Skip to content

Commit

Permalink
Merge pull request #125 from alan-turing-institute/slack-bot-env-vari…
Browse files Browse the repository at this point in the history
…ables

Require api_url for setting up slack bot
  • Loading branch information
rwood-97 authored Nov 2, 2023
2 parents da6a299 + d25fe77 commit 27f5c1e
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 188 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ The Reginald project consists of:

```
├── azure
│   └── Setup REGinald infrastructure on Azure
│   └── scripts to setup Reginald infrastructure on Azure
├── data
│   └── Directory to store llama-index data indexes and other public Turing data
│   └── directory to store llama-index data indexes and other public Turing data
├── docker
│   └── Scripts for building a Docker images for both Reginald app and Slack-bot only app
│   └── scripts for building a Docker images for both Reginald app and Slack-bot only app
├── notebooks
│   └── data processing notebooks
│   └── development notebooks for llama-index REGinald models
│   └── development notebooks for llama-index Reginald models
└── reginald
└── models: scripts for setting up query and chat engines
└── slack_bot: scripts for setting up Slack bot
Expand Down
217 changes: 82 additions & 135 deletions poetry.lock

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ authors = ["Evelina Gabasova <[email protected]>",
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11"
python = ">=3.11,<3.12"
accelerate = "^0.23.0"
bitsandbytes = { version="^0.41.1", optional=true }
datasets = { version="^2.12.0", optional=true }
Expand All @@ -26,10 +26,10 @@ gitpython = "^3.1.36"
gradio = { version="^3.34.0", optional=true }
httpx = { version="^0.25.0", optional=true }
ipykernel = { version="^6.23.2", optional=true }
langchain = "^0.0.294"
llama-cpp-python = "^0.2.7"
llama-index = "^0.8.29.post1"
llama-hub = "^0.0.31"
langchain = "^0.0.327"
llama-cpp-python = "^0.2.11"
llama-index = "^0.8.57"
llama-hub = "^0.0.42"
nbconvert = {version = "^7.8.0", optional = true}
nest_asyncio = "^1.5.8"
openai = "^0.27.8"
Expand Down
4 changes: 2 additions & 2 deletions reginald/models/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ def main():
- /direct_message: for obtaining responses from direct messages
- /channel_mention: for obtaining responses from channel mentions
"""
# Parse command line arguments
# parse command line arguments
parser = Parser()

# pass args to setup_llm
llm_kwargs = vars(parser.parse_args())

# Initialise logging
# initialise logging
logging.basicConfig(
datefmt=r"%Y-%m-%d %H:%M:%S",
format="%(asctime)s [%(levelname)8s] %(message)s",
Expand Down
6 changes: 2 additions & 4 deletions reginald/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@
from reginald.slack_bot.setup_bot import setup_slack_bot, setup_slack_client
from reginald.utils import Parser

API_URL = "http://127.0.0.1:8000"


async def main():
# Parse command line arguments
# parse command line arguments
parser = Parser()

# pass args to setup_llm
llm_kwargs = vars(parser.parse_args())

# Initialise logging
# initialise logging
logging.basicConfig(
datefmt=r"%Y-%m-%d %H:%M:%S",
format="%(asctime)s [%(levelname)8s] %(message)s",
Expand Down
48 changes: 24 additions & 24 deletions reginald/slack_bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ async def __call__(self, client: SocketModeClient, req: SocketModeRequest) -> No
Slack request
"""
if req.type == "events_api":
# Acknowledge the request
# acknowledge the request
logging.info("Received an events_api request")
response = SocketModeResponse(envelope_id=req.envelope_id)
await client.send_socket_mode_response(response)

try:
# Extract event from payload
# extract event from payload
event = req.payload["event"]

# Ignore messages from bots
# ignore messages from bots
if event.get("bot_id") is not None:
logging.info("Ignoring an event triggered by a bot.")
return
Expand Down Expand Up @@ -80,13 +80,13 @@ async def __call__(self, client: SocketModeClient, req: SocketModeRequest) -> No
raise

elif req.type == "slash_commands":
# Acknowledge the request
# acknowledge the request
logging.info("Received an slash_commands request")
response = SocketModeResponse(envelope_id=req.envelope_id)
await client.send_socket_mode_response(response)

try:
# Extract command, user, etc from payload
# extract command, user, etc from payload
command = req.payload["command"]
user_id = req.payload["user_id"]

Expand Down Expand Up @@ -137,7 +137,7 @@ async def worker(self, queue: asyncio.Queue) -> None:
while True:
(client, event) = await queue.get()
await self._process_request(client, event)
# Notify the queue that the "work item" has been processed.
# notify the queue that the "work item" has been processed.
queue.task_done()

async def _process_request(
Expand All @@ -155,13 +155,13 @@ async def _process_request(
req : SocketModeRequest
Slack request
"""
# Extract user and message information
# extract user and message information
message = event["text"]
user_id = event["user"]
event_type = event["type"]
event_subtype = event.get("subtype", None)

# Start processing the message
# start processing the message
logging.info(f"Processing message '{message}' from user '{user_id}'.")

await client.web_client.reactions_remove(
Expand All @@ -170,26 +170,26 @@ async def _process_request(
timestamp=event["ts"],
)

# If this is a direct message to REGinald...
# if this is a direct message to Reginald...
if event_type == "message" and event_subtype is None:
await self.react(client, event["channel"], event["ts"])
model_response = await asyncio.get_running_loop().run_in_executor(
None, self.model.direct_message, message, user_id
)

# If @REGinald is mentioned in a channel
# if @Reginald is mentioned in a channel
elif event_type == "app_mention":
await self.react(client, event["channel"], event["ts"])
model_response = await asyncio.get_running_loop().run_in_executor(
None, self.model.channel_mention, message, user_id
)

# Otherwise
# otherwise
else:
logging.info(f"Received unexpected event of type '{event['type']}'.")
return

# Add a reply as required
# add a reply as required
if model_response and model_response.message:
logging.info(f"Posting reply {model_response.message}.")
await client.web_client.chat_postMessage(
Expand Down Expand Up @@ -256,16 +256,16 @@ async def __call__(self, client: SocketModeClient, req: SocketModeRequest) -> No
Slack request
"""
if req.type == "events_api":
# Acknowledge the request
# acknowledge the request
logging.info("Received an events_api request")
response = SocketModeResponse(envelope_id=req.envelope_id)
await client.send_socket_mode_response(response)

try:
# Extract event from payload
# extract event from payload
event = req.payload["event"]

# Ignore messages from bots
# ignore messages from bots
if event.get("bot_id") is not None:
logging.info("Ignoring an event triggered by a bot.")
return
Expand Down Expand Up @@ -298,13 +298,13 @@ async def __call__(self, client: SocketModeClient, req: SocketModeRequest) -> No
raise

elif req.type == "slash_commands":
# Acknowledge the request
# acknowledge the request
logging.info("Received an slash_commands request")
response = SocketModeResponse(envelope_id=req.envelope_id)
await client.send_socket_mode_response(response)

try:
# Extract command, user, etc from payload
# extract command, user, etc from payload
command = req.payload["command"]
user_id = req.payload["user_id"]

Expand Down Expand Up @@ -355,7 +355,7 @@ async def worker(self, queue: asyncio.Queue) -> None:
while True:
(client, event) = await queue.get()
await self._process_request(client, event)
# Notify the queue that the "work item" has been processed.
# notify the queue that the "work item" has been processed.
queue.task_done()

async def _process_request(
Expand All @@ -373,13 +373,13 @@ async def _process_request(
req : SocketModeRequest
Slack request
"""
# Extract user and message information
# extract user and message information
message = event["text"]
user_id = event["user"]
event_type = event["type"]
event_subtype = event.get("subtype", None)

# Start processing the message
# start processing the message
logging.info(f"Processing message '{message}' from user '{user_id}'.")

await client.web_client.reactions_remove(
Expand All @@ -388,7 +388,7 @@ async def _process_request(
timestamp=event["ts"],
)

# If this is a direct message to REGinald...
# if this is a direct message to Reginald...
if event_type == "message" and event_subtype is None:
await self.react(client, event["channel"], event["ts"])
model_response = await asyncio.get_running_loop().run_in_executor(
Expand All @@ -399,7 +399,7 @@ async def _process_request(
),
)

# If @REGinald is mentioned in a channel
# if @Reginald is mentioned in a channel
elif event_type == "app_mention":
await self.react(client, event["channel"], event["ts"])
model_response = await asyncio.get_running_loop().run_in_executor(
Expand All @@ -410,7 +410,7 @@ async def _process_request(
),
)

# Otherwise
# otherwise
else:
logging.info(f"Received unexpected event of type '{event['type']}'.")
return
Expand All @@ -419,7 +419,7 @@ async def _process_request(
raise ValueError("Unable to get response.")
model_response = model_response.json()

# Add a reply as required
# add a reply as required
if model_response and model_response["message"]:
logging.info(f"Posting reply {model_response['message']}.")
await client.web_client.chat_postMessage(
Expand Down
38 changes: 24 additions & 14 deletions reginald/slack_bot/setup_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
from reginald.models.models.base import ResponseModel
from reginald.slack_bot.bot import ApiBot, Bot

# mb set this as env variable
API_URL = "http://0.0.0.0:8000"


def setup_slack_bot(model: ResponseModel) -> Bot:
"""
Expand All @@ -30,7 +27,7 @@ def setup_slack_bot(model: ResponseModel) -> Bot:
"""
logging.info(f"Initalising bot with model: {model}")

slack_bot = Bot(model)
slack_bot = Bot(model=model)

logging.info("Connecting to Slack...")
if os.environ.get("SLACK_APP_TOKEN") is None:
Expand All @@ -40,7 +37,7 @@ def setup_slack_bot(model: ResponseModel) -> Bot:
return slack_bot


def setup_api_slack_bot(emoji: str) -> ApiBot:
def setup_api_slack_bot(api_url: str, emoji: str) -> ApiBot:
"""
Initialise `ApiBot` with response model.
Expand All @@ -54,11 +51,11 @@ def setup_api_slack_bot(emoji: str) -> ApiBot:
ApiBot
Bot which uses an API for responding to messages
"""
logging.info(f"Initalising bot at {API_URL}")
logging.info(f"Initalising bot at {api_url}")
logging.info(f"Initalising bot with {emoji} emoji")

# set up bot with the API_URL and emoji
slack_bot = ApiBot(API_URL, emoji)
# set up bot with the api_url and emoji
slack_bot = ApiBot(api_url=api_url, emoji=emoji)

logging.info("Connecting to Slack...")
if os.environ.get("SLACK_APP_TOKEN") is None:
Expand Down Expand Up @@ -116,8 +113,14 @@ async def main():
then establishes a WebSocket connection to the
Socket Mode servers and listens for events.
"""
# Parse command line arguments
# parse command line arguments
parser = argparse.ArgumentParser()
parser.add_argument(
"--api-url",
"-a",
help="Select the API URL for the model",
default=os.environ.get("REGINALD_API_URL"),
)
parser.add_argument(
"--emoji",
"-e",
Expand All @@ -126,23 +129,30 @@ async def main():
)
args = parser.parse_args()

# Initialise logging
if args.api_url is None:
logging.error(
"API URL is not set. Please set the REGINALD_API_URL "
"environment variable or pass in the --api-url argument"
)
sys.exit(1)

# initialise logging
logging.basicConfig(
datefmt=r"%Y-%m-%d %H:%M:%S",
format="%(asctime)s [%(levelname)8s] %(message)s",
level=logging.INFO,
)

# set up slack bot
bot = setup_api_slack_bot(args.emoji)
bot = setup_api_slack_bot(api_url=args.api_url, emoji=args.emoji)

# set up slack client
client = setup_slack_client(bot)
client = setup_slack_client(slack_bot=bot)

# Establish a WebSocket connection to the Socket Mode servers
# establish a WebSocket connection to the Socket Mode servers
await client.connect()

# Listen for events
# listen for events
logging.info("Listening for requests...")
await asyncio.sleep(float("inf"))

Expand Down

0 comments on commit 27f5c1e

Please sign in to comment.