Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
Copy Markdown
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]

Copy link
Copy Markdown
Contributor

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
2 changes: 2 additions & 0 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.assistant.assistant import handle_feedback
Comment thread
srtaalej marked this conversation as resolved.
Outdated


def register_listeners(app):
# Using assistant middleware is the recommended way.
app.assistant(assistant)
app.action("feedback")(handle_feedback)

# The following event listeners demonstrate how to implement the same on your own.
# from listeners import events
Expand Down
69 changes: 63 additions & 6 deletions listeners/assistant/assistant.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import logging
from typing import List, Dict
from typing import Any, List, Dict
from slack_bolt import Assistant, BoltContext, Say, SetSuggestedPrompts
from slack_bolt.context.get_thread_context import GetThreadContext
from slack_sdk import WebClient
Expand All @@ -10,6 +10,35 @@
assistant = Assistant()


def create_feedback_block(user_id: str) -> Dict[str, Any]:
"""
Create feedback block with thumbs up/down buttons

Args:
user_id: User ID for user-specific controls
Comment thread
srtaalej marked this conversation as resolved.
Outdated

Returns:
Block Kit context_actions block
"""
elements = [
{
"type": "feedback_buttons",
"action_id": "feedback",
"positive_button": {
"text": {"type": "plain_text", "text": "Good Response"},
"accessibility_label": "Submit positive feedback on this response",
"value": "good-feedback",
},
"negative_button": {
"text": {"type": "plain_text", "text": "Bad Response"},
"accessibility_label": "Submit negative feedback on this response",
"value": "bad-feedback",
},
}
]
return [{"type": "context_actions", "elements": elements}]


# This listener is invoked when a human user opened an assistant thread
@assistant.thread_started
def start_assistant_thread(
Expand Down Expand Up @@ -60,6 +89,7 @@ def respond_in_assistant_thread(
say: Say,
):
try:
user_id = payload["user"]
channel_id = payload["channel"]
thread_ts = payload["thread_ts"]

Expand Down Expand Up @@ -97,12 +127,39 @@ def respond_in_assistant_thread(
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,
)
Comment thread
srtaalej marked this conversation as resolved.
feedback_block = create_feedback_block(user_id=user_id)
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}")
say(f":warning: Something went wrong! ({e})")


# Handle feedback buttons (thumbs up/down)
def handle_feedback(ack, body, client, logger):
ack()

try:
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.",
)
Comment thread
srtaalej marked this conversation as resolved.
Outdated
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"Error handling feedback action: {error}")