Skip to content

Commit c4ba883

Browse files
authored
feat: feedback block (#13)
adds feedback block to llm responses
1 parent b4b2539 commit c4ba883

7 files changed

Lines changed: 85 additions & 12 deletions

File tree

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ pip install -r requirements.txt
5151
python3 app.py
5252
```
5353

54+
Start talking to the bot! Start a new DM or thread and click the feedback button when it responds.
55+
5456
#### Linting
5557
```zsh
5658
# Run flake8 from root directory for linting
@@ -74,8 +76,8 @@ black .
7476

7577
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.
7678

77-
:::info[The `listeners/events` folder is purely educational and demonstrates alternative approaches to implementation]
78-
These listeners are **not registered** and are not used in the actual application. For the working implementation, refer to `listeners/assistant.py`.
79+
> [!NOTE]
80+
> 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`.
7981
8082
**`/listeners/assistant`**
8183

listeners/__init__.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
from listeners.assistant import assistant
1+
from listeners import actions
2+
from listeners import assistant
23

34

45
def register_listeners(app):
5-
# Using assistant middleware is the recommended way.
6-
app.assistant(assistant)
6+
7+
actions.register(app)
8+
assistant.register(app)
79

810
# The following event listeners demonstrate how to implement the same on your own.
911
# from listeners import events

listeners/actions/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from slack_bolt import App
2+
from .actions import handle_feedback
3+
4+
5+
def register(app: App):
6+
app.action("feedback")(handle_feedback)

listeners/actions/actions.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import logging
2+
3+
4+
# Handle feedback buttons (thumbs up/down)
5+
def handle_feedback(ack, body, client, logger: logging.Logger):
6+
try:
7+
ack()
8+
message_ts = body["message"]["ts"]
9+
channel_id = body["channel"]["id"]
10+
feedback_type = body["actions"][0]["value"]
11+
is_positive = feedback_type == "good-feedback"
12+
13+
if is_positive:
14+
client.chat_postEphemeral(
15+
channel=channel_id,
16+
user=body["user"]["id"],
17+
thread_ts=message_ts,
18+
text="We're glad you found this useful.",
19+
)
20+
else:
21+
client.chat_postEphemeral(
22+
channel=channel_id,
23+
user=body["user"]["id"],
24+
thread_ts=message_ts,
25+
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.",
26+
)
27+
28+
logger.debug(f"Handled feedback: type={feedback_type}, message_ts={message_ts}")
29+
except Exception as error:
30+
logger.error(f":warning: Something went wrong! {error}")

listeners/assistant/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from slack_bolt import App
12
from .assistant import assistant
23

3-
__all__ = ["assistant"]
4+
5+
def register(app: App):
6+
app.assistant(assistant)

listeners/assistant/assistant.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,43 @@
33
from slack_bolt import Assistant, BoltContext, Say, SetSuggestedPrompts
44
from slack_bolt.context.get_thread_context import GetThreadContext
55
from slack_sdk import WebClient
6+
from slack_sdk.models.blocks import Block, ContextActionsBlock, FeedbackButtonsElement, FeedbackButtonObject
67

78
from ..llm_caller import call_llm
89

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

1213

14+
def create_feedback_block() -> List[Block]:
15+
"""
16+
Create feedback block with thumbs up/down buttons
17+
18+
Returns:
19+
Block Kit context_actions block
20+
"""
21+
blocks: List[Block] = [
22+
ContextActionsBlock(
23+
elements=[
24+
FeedbackButtonsElement(
25+
action_id="feedback",
26+
positive_button=FeedbackButtonObject(
27+
text="Good Response",
28+
accessibility_label="Submit positive feedback on this response",
29+
value="good-feedback",
30+
),
31+
negative_button=FeedbackButtonObject(
32+
text="Bad Response",
33+
accessibility_label="Submit negative feedback on this response",
34+
value="bad-feedback",
35+
),
36+
)
37+
]
38+
)
39+
]
40+
return blocks
41+
42+
1343
# This listener is invoked when a human user opened an assistant thread
1444
@assistant.thread_started
1545
def start_assistant_thread(
@@ -83,25 +113,26 @@ def respond_in_assistant_thread(
83113
messages_in_thread.append({"role": role, "content": message["text"]})
84114

85115
returned_message = call_llm(messages_in_thread)
116+
86117
client.assistant_threads_setStatus(
87118
channel_id=channel_id, thread_ts=thread_ts, status="Bolt is typing", loading_messages=loading_messages
88119
)
120+
89121
stream_response = client.chat_startStream(
90122
channel=channel_id,
91123
thread_ts=thread_ts,
92124
)
93125
stream_ts = stream_response["ts"]
126+
94127
# use of this for loop is specific to openai response method
95128
for event in returned_message:
96129
if event.type == "response.output_text.delta":
97130
client.chat_appendStream(channel=channel_id, ts=stream_ts, markdown_text=f"{event.delta}")
98131
else:
99132
continue
100133

101-
client.chat_stopStream(
102-
channel=channel_id,
103-
ts=stream_ts,
104-
)
134+
feedback_block = create_feedback_block()
135+
client.chat_stopStream(channel=channel_id, ts=stream_ts, blocks=feedback_block)
105136

106137
except Exception as e:
107138
logger.exception(f"Failed to handle a user message event: {e}")

requirements.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
--extra-index-url=https://test.pypi.org/simple/
2-
slack_sdk==3.36.0.dev2
1+
slack-sdk==3.36.0.dev3
32
slack-bolt>=1.21,<2
43

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

0 commit comments

Comments
 (0)