Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ pip install -r requirements.txt
python3 app.py
```

Start talking to the bot! Start a new DM or thread and click the feedback button when it responds.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lukegalbraithrussell me trying to check items off of @mwbrooks wishlist 🆘


#### Linting
```zsh
# Run flake8 from root directory for linting
Expand All @@ -74,8 +76,8 @@ black .

Every incoming request is routed to a "listener". This directory groups each listener based on the Slack Platform feature used, so `/listeners/events` handles incoming events, `/listeners/shortcuts` would handle incoming [Shortcuts](https://docs.slack.dev/interactivity/implementing-shortcuts/) requests, and so on.

:::info[The `listeners/events` folder is purely educational and demonstrates alternative approaches to implementation]
These listeners are **not registered** and are not used in the actual application. For the working implementation, refer to `listeners/assistant.py`.
> [!NOTE]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is good! i have no idea why i suggested to use our docs syntax in a readme - i got mixed up with which repo i was commenting on probably

> The `listeners/events` folder is purely educational and demonstrates alternative approaches to implementation. These listeners are **not registered** and are not used in the actual application. For the working implementation, refer to `listeners/assistant/assistant.py`.

**`/listeners/assistant`**

Expand Down
8 changes: 5 additions & 3 deletions listeners/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from listeners.assistant import assistant
from listeners import actions
from listeners import assistant


def register_listeners(app):
# Using assistant middleware is the recommended way.
app.assistant(assistant)

actions.register(app)
assistant.register(app)

# The following event listeners demonstrate how to implement the same on your own.
# from listeners import events
Expand Down
6 changes: 6 additions & 0 deletions listeners/actions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from slack_bolt import App
from .actions import handle_feedback


def register(app: App):
app.action("feedback")(handle_feedback)
30 changes: 30 additions & 0 deletions listeners/actions/actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import logging


# Handle feedback buttons (thumbs up/down)
def handle_feedback(ack, body, client, logger: logging.Logger):
try:
ack()
message_ts = body["message"]["ts"]
channel_id = body["channel"]["id"]
feedback_type = body["actions"][0]["value"]
is_positive = feedback_type == "good-feedback"

if is_positive:
client.chat_postEphemeral(
channel=channel_id,
user=body["user"]["id"],
thread_ts=message_ts,
text="We're glad you found this useful.",
)
else:
client.chat_postEphemeral(
channel=channel_id,
user=body["user"]["id"],
thread_ts=message_ts,
text="Sorry to hear that response wasn't up to par :slightly_frowning_face: Starting a new chat may help with AI mistakes and hallucinations.",
)

logger.debug(f"Handled feedback: type={feedback_type}, message_ts={message_ts}")
except Exception as error:
logger.error(f":warning: Something went wrong! {error}")
5 changes: 4 additions & 1 deletion listeners/assistant/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from slack_bolt import App
from .assistant import assistant

__all__ = ["assistant"]

def register(app: App):
app.assistant(assistant)
39 changes: 35 additions & 4 deletions listeners/assistant/assistant.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,43 @@
from slack_bolt import Assistant, BoltContext, Say, SetSuggestedPrompts
from slack_bolt.context.get_thread_context import GetThreadContext
from slack_sdk import WebClient
from slack_sdk.models.blocks import Block, ContextActionsBlock, FeedbackButtonsElement, FeedbackButtonObject

from ..llm_caller import call_llm

# Refer to https://tools.slack.dev/bolt-python/concepts/assistant/ for more details
assistant = Assistant()


def create_feedback_block() -> List[Block]:
"""
Create feedback block with thumbs up/down buttons

Returns:
Block Kit context_actions block
"""
blocks: List[Block] = [
ContextActionsBlock(
elements=[
FeedbackButtonsElement(
action_id="feedback",
positive_button=FeedbackButtonObject(
text="Good Response",
accessibility_label="Submit positive feedback on this response",
value="good-feedback",
),
negative_button=FeedbackButtonObject(
text="Bad Response",
accessibility_label="Submit negative feedback on this response",
value="bad-feedback",
),
)
]
)
]
return blocks


# This listener is invoked when a human user opened an assistant thread
@assistant.thread_started
def start_assistant_thread(
Expand Down Expand Up @@ -83,25 +113,26 @@ def respond_in_assistant_thread(
messages_in_thread.append({"role": role, "content": message["text"]})

returned_message = call_llm(messages_in_thread)

client.assistant_threads_setStatus(
channel_id=channel_id, thread_ts=thread_ts, status="Bolt is typing", loading_messages=loading_messages
)

stream_response = client.chat_startStream(
channel=channel_id,
thread_ts=thread_ts,
)
stream_ts = stream_response["ts"]

# use of this for loop is specific to openai response method
for event in returned_message:
if event.type == "response.output_text.delta":
client.chat_appendStream(channel=channel_id, ts=stream_ts, markdown_text=f"{event.delta}")
else:
continue

client.chat_stopStream(
channel=channel_id,
ts=stream_ts,
)
feedback_block = create_feedback_block()
client.chat_stopStream(channel=channel_id, ts=stream_ts, blocks=feedback_block)

except Exception as e:
logger.exception(f"Failed to handle a user message event: {e}")
Expand Down
3 changes: 1 addition & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
--extra-index-url=https://test.pypi.org/simple/
slack_sdk==3.36.0.dev2
slack-sdk==3.36.0.dev3
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Thank you! 🙏🏻

slack-bolt>=1.21,<2

# If you use a different LLM vendor, replace this dependency
Expand Down