From f1bc46f67668655108ae85602041c4ab2bdbcac8 Mon Sep 17 00:00:00 2001 From: hagen-danswer Date: Mon, 9 Dec 2024 16:36:58 -0800 Subject: [PATCH 1/4] Fixed slackbot url error --- backend/danswer/danswerbot/slack/utils.py | 45 ++++++++++++++++------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/backend/danswer/danswerbot/slack/utils.py b/backend/danswer/danswerbot/slack/utils.py index 4221b4faf6f..c3136a93c27 100644 --- a/backend/danswer/danswerbot/slack/utils.py +++ b/backend/danswer/danswerbot/slack/utils.py @@ -161,19 +161,38 @@ def respond_in_thread( message_ids: list[str] = [] if not receiver_ids: - slack_call = make_slack_api_rate_limited(client.chat_postMessage) - response = slack_call( - channel=channel, - text=text, - blocks=blocks, - thread_ts=thread_ts, - metadata=metadata, - unfurl_links=unfurl, - unfurl_media=unfurl, - ) - if not response.get("ok"): - raise RuntimeError(f"Failed to post message: {response}") - message_ids.append(response["message_ts"]) + try: + slack_call = make_slack_api_rate_limited(client.chat_postMessage) + response = slack_call( + channel=channel, + text=text, + blocks=blocks, + thread_ts=thread_ts, + metadata=metadata, + unfurl_links=unfurl, + unfurl_media=unfurl, + ) + message_ids.append(response["message_ts"]) + except Exception as e: + logger.warning(f"Failed to post message: {e} \n blocks: {blocks}") + logger.warning("Trying again without blocks that have urls") + blocks_without_urls = [ + block + for block in blocks + if not any( + hasattr(block, attr) for attr in dir(block) if "url" in attr.lower() + ) + ] + response = slack_call( + channel=channel, + text=text, + blocks=blocks_without_urls, + thread_ts=thread_ts, + metadata=metadata, + unfurl_links=unfurl, + unfurl_media=unfurl, + ) + message_ids.append(response["message_ts"]) else: slack_call = make_slack_api_rate_limited(client.chat_postEphemeral) for receiver in receiver_ids: From 8f0d5aea4c6bcc21af5749a341eefd85c3453e2e Mon Sep 17 00:00:00 2001 From: hagen-danswer Date: Mon, 9 Dec 2024 16:53:07 -0800 Subject: [PATCH 2/4] added error block --- backend/danswer/danswerbot/slack/utils.py | 42 ++++++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/backend/danswer/danswerbot/slack/utils.py b/backend/danswer/danswerbot/slack/utils.py index c3136a93c27..2c2478f8cfa 100644 --- a/backend/danswer/danswerbot/slack/utils.py +++ b/backend/danswer/danswerbot/slack/utils.py @@ -11,6 +11,7 @@ from slack_sdk import WebClient from slack_sdk.errors import SlackApiError from slack_sdk.models.blocks import Block +from slack_sdk.models.blocks import SectionBlock from slack_sdk.models.metadata import Metadata from slack_sdk.socket_mode import SocketModeClient @@ -140,6 +141,40 @@ def remove_danswer_bot_tag(message_str: str, client: WebClient) -> str: return re.sub(rf"<@{bot_tag_id}>\s", "", message_str) +def _check_for_url_in_block(block: Block) -> bool: + """ + Check if the block has a key that contains "url" in it + """ + block_dict = block.to_dict() + + def check_dict_for_url(d: dict) -> bool: + for key, value in d.items(): + if "url" in key.lower(): + return True + if isinstance(value, dict): + if check_dict_for_url(value): + return True + elif isinstance(value, list): + for item in value: + if isinstance(item, dict) and check_dict_for_url(item): + return True + return False + + return check_dict_for_url(block_dict) + + +def _build_error_block(error_message: str) -> Block: + """ + Build an error block to display in slack so that the user can see + the error without completely breaking + """ + display_text = ( + "There was an error displaying all of the Onyx answers." + f" Please let an admin or an onyx developer know. Error: {error_message}" + ) + return SectionBlock(text=display_text) + + @retry( tries=DANSWER_BOT_NUM_RETRIES, delay=0.25, @@ -177,12 +212,9 @@ def respond_in_thread( logger.warning(f"Failed to post message: {e} \n blocks: {blocks}") logger.warning("Trying again without blocks that have urls") blocks_without_urls = [ - block - for block in blocks - if not any( - hasattr(block, attr) for attr in dir(block) if "url" in attr.lower() - ) + block for block in blocks if not _check_for_url_in_block(block) ] + blocks_without_urls.append(_build_error_block(str(e))) response = slack_call( channel=channel, text=text, From 1136b3ca0c9bed652205699ffe32e50974b6effa Mon Sep 17 00:00:00 2001 From: hagen-danswer Date: Mon, 9 Dec 2024 16:56:26 -0800 Subject: [PATCH 3/4] properly scoped try/except --- backend/danswer/danswerbot/slack/utils.py | 53 ++++++++++++++++------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/backend/danswer/danswerbot/slack/utils.py b/backend/danswer/danswerbot/slack/utils.py index 2c2478f8cfa..7f663f2904c 100644 --- a/backend/danswer/danswerbot/slack/utils.py +++ b/backend/danswer/danswerbot/slack/utils.py @@ -196,8 +196,8 @@ def respond_in_thread( message_ids: list[str] = [] if not receiver_ids: + slack_call = make_slack_api_rate_limited(client.chat_postMessage) try: - slack_call = make_slack_api_rate_limited(client.chat_postMessage) response = slack_call( channel=channel, text=text, @@ -207,14 +207,16 @@ def respond_in_thread( unfurl_links=unfurl, unfurl_media=unfurl, ) - message_ids.append(response["message_ts"]) except Exception as e: logger.warning(f"Failed to post message: {e} \n blocks: {blocks}") logger.warning("Trying again without blocks that have urls") + blocks_without_urls = [ block for block in blocks if not _check_for_url_in_block(block) ] blocks_without_urls.append(_build_error_block(str(e))) + + # Try again wtihout blocks containing url response = slack_call( channel=channel, text=text, @@ -224,22 +226,43 @@ def respond_in_thread( unfurl_links=unfurl, unfurl_media=unfurl, ) - message_ids.append(response["message_ts"]) + + message_ids.append(response["message_ts"]) else: slack_call = make_slack_api_rate_limited(client.chat_postEphemeral) for receiver in receiver_ids: - response = slack_call( - channel=channel, - user=receiver, - text=text, - blocks=blocks, - thread_ts=thread_ts, - metadata=metadata, - unfurl_links=unfurl, - unfurl_media=unfurl, - ) - if not response.get("ok"): - raise RuntimeError(f"Failed to post message: {response}") + try: + response = slack_call( + channel=channel, + user=receiver, + text=text, + blocks=blocks, + thread_ts=thread_ts, + metadata=metadata, + unfurl_links=unfurl, + unfurl_media=unfurl, + ) + except Exception as e: + logger.warning(f"Failed to post message: {e} \n blocks: {blocks}") + logger.warning("Trying again without blocks that have urls") + + blocks_without_urls = [ + block for block in blocks if not _check_for_url_in_block(block) + ] + blocks_without_urls.append(_build_error_block(str(e))) + + # Try again wtihout blocks containing url + response = slack_call( + channel=channel, + user=receiver, + text=text, + blocks=blocks, + thread_ts=thread_ts, + metadata=metadata, + unfurl_links=unfurl, + unfurl_media=unfurl, + ) + message_ids.append(response["message_ts"]) return message_ids From f0d3bb57b2a577af37371f6e76c9045564a9f837 Mon Sep 17 00:00:00 2001 From: hagen-danswer Date: Mon, 9 Dec 2024 17:20:14 -0800 Subject: [PATCH 4/4] mypy --- backend/danswer/danswerbot/slack/utils.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/backend/danswer/danswerbot/slack/utils.py b/backend/danswer/danswerbot/slack/utils.py index 7f663f2904c..147356b76d1 100644 --- a/backend/danswer/danswerbot/slack/utils.py +++ b/backend/danswer/danswerbot/slack/utils.py @@ -211,6 +211,9 @@ def respond_in_thread( logger.warning(f"Failed to post message: {e} \n blocks: {blocks}") logger.warning("Trying again without blocks that have urls") + if not blocks: + raise e + blocks_without_urls = [ block for block in blocks if not _check_for_url_in_block(block) ] @@ -246,6 +249,9 @@ def respond_in_thread( logger.warning(f"Failed to post message: {e} \n blocks: {blocks}") logger.warning("Trying again without blocks that have urls") + if not blocks: + raise e + blocks_without_urls = [ block for block in blocks if not _check_for_url_in_block(block) ] @@ -256,7 +262,7 @@ def respond_in_thread( channel=channel, user=receiver, text=text, - blocks=blocks, + blocks=blocks_without_urls, thread_ts=thread_ts, metadata=metadata, unfurl_links=unfurl,