Skip to content

Commit 17b9b9a

Browse files
adds streaming
1 parent 8e86d26 commit 17b9b9a

File tree

1 file changed

+139
-0
lines changed

1 file changed

+139
-0
lines changed
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import logging
2+
from typing import List, Dict
3+
from slack_bolt import Assistant, BoltContext, Say, SetSuggestedPrompts
4+
from slack_bolt.context.get_thread_context import GetThreadContext
5+
from slack_sdk import WebClient
6+
from slack_sdk.models.blocks import Block, ContextActionsBlock, FeedbackButtonsElement, FeedbackButtonObject
7+
8+
from ..llm_caller import call_llm
9+
10+
# Refer to https://tools.slack.dev/bolt-python/concepts/assistant/ for more details
11+
assistant = Assistant()
12+
13+
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+
43+
# This listener is invoked when a human user opened an assistant thread
44+
@assistant.thread_started
45+
def start_assistant_thread(
46+
say: Say,
47+
get_thread_context: GetThreadContext,
48+
set_suggested_prompts: SetSuggestedPrompts,
49+
logger: logging.Logger,
50+
):
51+
try:
52+
say("How can I help you?")
53+
54+
prompts: List[Dict[str, str]] = [
55+
{
56+
"title": "What does Slack stand for?",
57+
"message": "Slack, a business communication service, was named after an acronym. Can you guess what it stands for?",
58+
},
59+
{
60+
"title": "Write a draft announcement",
61+
"message": "Can you write a draft announcement about a new feature my team just released? It must include how impactful it is.",
62+
},
63+
{
64+
"title": "Suggest names for my Slack app",
65+
"message": "Can you suggest a few names for my Slack app? The app helps my teammates better organize information and plan priorities and action items.",
66+
},
67+
]
68+
69+
thread_context = get_thread_context()
70+
if thread_context is not None and thread_context.channel_id is not None:
71+
summarize_channel = {
72+
"title": "Summarize the referred channel",
73+
"message": "Can you generate a brief summary of the referred channel?",
74+
}
75+
prompts.append(summarize_channel)
76+
77+
set_suggested_prompts(prompts=prompts)
78+
except Exception as e:
79+
logger.exception(f"Failed to handle an assistant_thread_started event: {e}", e)
80+
say(f":warning: Something went wrong! ({e})")
81+
82+
83+
# This listener is invoked when the human user sends a reply in the assistant thread
84+
@assistant.user_message
85+
def respond_in_assistant_thread(
86+
payload: dict,
87+
logger: logging.Logger,
88+
context: BoltContext,
89+
client: WebClient,
90+
say: Say,
91+
):
92+
try:
93+
channel_id = payload["channel"]
94+
thread_ts = payload["thread_ts"]
95+
96+
loading_messages = [
97+
"Teaching the hamsters to type faster…",
98+
"Untangling the internet cables…",
99+
"Consulting the office goldfish…",
100+
"Polishing up the response just for you…",
101+
"Convincing the AI to stop overthinking…",
102+
]
103+
104+
replies = client.conversations_replies(
105+
channel=context.channel_id,
106+
ts=context.thread_ts,
107+
oldest=context.thread_ts,
108+
limit=10,
109+
)
110+
messages_in_thread: List[Dict[str, str]] = []
111+
for message in replies["messages"]:
112+
role = "user" if message.get("bot_id") is None else "assistant"
113+
messages_in_thread.append({"role": role, "content": message["text"]})
114+
115+
returned_message = call_llm(messages_in_thread)
116+
117+
client.assistant_threads_setStatus(
118+
channel_id=channel_id, thread_ts=thread_ts, status="Bolt is typing", loading_messages=loading_messages
119+
)
120+
121+
stream_response = client.chat_startStream(
122+
channel=channel_id,
123+
thread_ts=thread_ts,
124+
)
125+
stream_ts = stream_response["ts"]
126+
127+
# use of this for loop is specific to openai response method
128+
for event in returned_message:
129+
if event.type == "response.output_text.delta":
130+
client.chat_appendStream(channel=channel_id, ts=stream_ts, markdown_text=f"{event.delta}")
131+
else:
132+
continue
133+
134+
feedback_block = create_feedback_block()
135+
client.chat_stopStream(channel=channel_id, ts=stream_ts, blocks=feedback_block)
136+
137+
except Exception as e:
138+
logger.exception(f"Failed to handle a user message event: {e}")
139+
say(f":warning: Something went wrong! ({e})")

0 commit comments

Comments
 (0)