Group support for Slack Followup (#951)

This commit is contained in:
Yuhong Sun 2024-01-15 19:21:06 -08:00 committed by GitHub
parent d099b931d8
commit d17426749d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 63 additions and 16 deletions

View File

@ -1,7 +1,9 @@
"""Add api_key table
Revision ID: 79acd316403a
Revises: 904e5138fffb
Create Date: 2024-01-11 17:56:37.934381
"""
from alembic import op
import fastapi_users_db_sqlalchemy

View File

@ -288,12 +288,20 @@ def build_follow_up_block(message_id: int | None) -> ActionsBlock:
)
def build_follow_up_resolved_blocks(tag_ids: list[str]) -> list[Block]:
def build_follow_up_resolved_blocks(
tag_ids: list[str], group_ids: list[str]
) -> list[Block]:
tag_str = " ".join([f"<@{tag}>" for tag in tag_ids])
if tag_str:
tag_str += " "
group_str = " ".join([f"<!subteam^{group}>" for group in group_ids])
if group_str:
group_str += " "
text = (
tag_str
+ group_str
+ "Someone has requested more help.\n\n:point_down:Please mark this resolved after answering!"
)
text_block = SectionBlock(text=text)

View File

@ -17,6 +17,7 @@ from danswer.danswerbot.slack.constants import LIKE_BLOCK_ACTION_ID
from danswer.danswerbot.slack.constants import VIEW_DOC_FEEDBACK_ID
from danswer.danswerbot.slack.utils import build_feedback_id
from danswer.danswerbot.slack.utils import decompose_action_id
from danswer.danswerbot.slack.utils import fetch_groupids_from_names
from danswer.danswerbot.slack.utils import fetch_userids_from_emails
from danswer.danswerbot.slack.utils import get_channel_name_from_id
from danswer.danswerbot.slack.utils import respond_in_thread
@ -140,7 +141,8 @@ def handle_followup_button(
client=client.web_client,
)
tag_ids = []
tag_ids: list[str] = []
group_ids: list[str] = []
with Session(get_sqlalchemy_engine()) as db_session:
channel_name, is_dm = get_channel_name_from_id(
client=client.web_client, channel_id=channel_id
@ -149,11 +151,16 @@ def handle_followup_button(
channel_name=channel_name, db_session=db_session
)
if slack_bot_config:
emails = slack_bot_config.channel_config.get("follow_up_tags")
if emails:
tag_ids = fetch_userids_from_emails(emails, client.web_client)
tag_names = slack_bot_config.channel_config.get("follow_up_tags")
remaining = None
if tag_names:
tag_ids, remaining = fetch_userids_from_emails(
tag_names, client.web_client
)
if remaining:
group_ids, _ = fetch_groupids_from_names(remaining, client.web_client)
blocks = build_follow_up_resolved_blocks(tag_ids=tag_ids)
blocks = build_follow_up_resolved_blocks(tag_ids=tag_ids, group_ids=group_ids)
respond_in_thread(
client=client.web_client,

View File

@ -152,7 +152,7 @@ def handle_message(
return False
if respond_team_member_list:
send_to = fetch_userids_from_emails(respond_team_member_list, client)
send_to, _ = fetch_userids_from_emails(respond_team_member_list, client)
# If configured to respond to team members only, then cannot be used with a /DanswerBot command
# which would just respond to the sender

View File

@ -251,22 +251,48 @@ def get_channel_name_from_id(
raise e
def fetch_userids_from_emails(user_emails: list[str], client: WebClient) -> list[str]:
def fetch_userids_from_emails(
user_emails: list[str], client: WebClient
) -> tuple[list[str], list[str]]:
user_ids: list[str] = []
failed_to_find: list[str] = []
for email in user_emails:
try:
user = client.users_lookupByEmail(email=email)
user_ids.append(user.data["user"]["id"]) # type: ignore
except Exception:
logger.error(f"Was not able to find slack user by email: {email}")
failed_to_find.append(email)
if not user_ids:
raise RuntimeError(
"Was not able to find any Slack users to respond to. "
"No email was parsed into a valid slack account."
)
return user_ids, failed_to_find
return user_ids
def fetch_groupids_from_names(
names: list[str], client: WebClient
) -> tuple[list[str], list[str]]:
group_ids: set[str] = set()
failed_to_find: list[str] = []
try:
response = client.usergroups_list()
if response.get("ok") and "usergroups" in response.data:
all_groups_dicts = response.data["usergroups"] # type: ignore
name_id_map = {d["name"]: d["id"] for d in all_groups_dicts}
handle_id_map = {d["handle"]: d["id"] for d in all_groups_dicts}
for group in names:
if group in name_id_map:
group_ids.add(name_id_map[group])
elif group in handle_id_map:
group_ids.add(handle_id_map[group])
else:
failed_to_find.append(group)
else:
# Most likely a Slack App scope issue
logger.error("Error fetching user groups")
except Exception as e:
logger.error(f"Error fetching user groups: {str(e)}")
return list(group_ids), failed_to_find
def fetch_user_semantic_id_from_id(user_id: str, client: WebClient) -> str | None:

View File

@ -216,8 +216,12 @@ export const SlackBotCreationForm = ({
subtext={
<div>
The full email addresses of the Slack users we should
tag if the user clicks the &quot;Still need help?&quot; button.
For example, &apos;mark@acme.com&apos;.
tag if the user clicks the &quot;Still need help?&quot;
button. For example, &apos;mark@acme.com&apos;.
<br />
Or provide a user group by either the name or the
handle. For example, &apos;Danswer Team&apos; or
&apos;danswer-team&apos;.
<br />
<br />
If no emails are provided, we will not tag anyone and