Skip to content

Commit

Permalink
add slack markdown formatting (#2829)
Browse files Browse the repository at this point in the history
* add slack markdown formatting

* nit

* k
  • Loading branch information
pablonyx authored Oct 17, 2024
1 parent 0de4870 commit 137f4b1
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 1 deletion.
66 changes: 66 additions & 0 deletions backend/danswer/danswerbot/slack/formatting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from mistune import Markdown # type: ignore
from mistune import Renderer # type: ignore


def format_slack_message(message: str | None) -> str:
renderer = Markdown(renderer=SlackRenderer())
return renderer.render(message)


class SlackRenderer(Renderer):
SPECIALS: dict[str, str] = {"&": "&amp;", "<": "&lt;", ">": "&gt;"}

def escape_special(self, text: str) -> str:
for special, replacement in self.SPECIALS.items():
text = text.replace(special, replacement)
return text

def header(self, text: str, level: int, raw: str | None = None) -> str:
return f"*{text}*\n"

def emphasis(self, text: str) -> str:
return f"_{text}_"

def double_emphasis(self, text: str) -> str:
return f"*{text}*"

def strikethrough(self, text: str) -> str:
return f"~{text}~"

def list(self, body: str, ordered: bool = True) -> str:
lines = body.split("\n")
count = 0
for i, line in enumerate(lines):
if line.startswith("li: "):
count += 1
prefix = f"{count}. " if ordered else "• "
lines[i] = f"{prefix}{line[4:]}"
return "\n".join(lines)

def list_item(self, text: str) -> str:
return f"li: {text}\n"

def link(self, link: str, title: str | None, content: str | None) -> str:
escaped_link = self.escape_special(link)
if content:
return f"<{escaped_link}|{content}>"
if title:
return f"<{escaped_link}|{title}>"
return f"<{escaped_link}>"

def image(self, src: str, title: str | None, text: str | None) -> str:
escaped_src = self.escape_special(src)
display_text = title or text
return f"<{escaped_src}|{display_text}>" if display_text else f"<{escaped_src}>"

def codespan(self, text: str) -> str:
return f"`{text}`"

def block_code(self, text: str, lang: str | None) -> str:
return f"```\n{text}\n```\n"

def paragraph(self, text: str) -> str:
return f"{text}\n"

def autolink(self, link: str, is_email: bool) -> str:
return link if is_email else self.link(link, None, None)
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from danswer.danswerbot.slack.blocks import build_qa_response_blocks
from danswer.danswerbot.slack.blocks import build_sources_blocks
from danswer.danswerbot.slack.blocks import get_restate_blocks
from danswer.danswerbot.slack.formatting import format_slack_message
from danswer.danswerbot.slack.handlers.utils import send_team_member_message
from danswer.danswerbot.slack.models import SlackMessageInfo
from danswer.danswerbot.slack.utils import respond_in_thread
Expand Down Expand Up @@ -412,10 +413,11 @@ def _get_answer(new_message_request: DirectQARequest) -> OneShotQAResponse | Non

# If called with the DanswerBot slash command, the question is lost so we have to reshow it
restate_question_block = get_restate_blocks(messages[-1].message, is_bot_msg)
formatted_answer = format_slack_message(answer.answer) if answer.answer else None

answer_blocks = build_qa_response_blocks(
message_id=answer.chat_message_id,
answer=answer.answer,
answer=formatted_answer,
quotes=answer.quotes.quotes if answer.quotes else None,
source_filters=retrieval_info.applied_source_filters,
time_cutoff=retrieval_info.applied_time_cutoff,
Expand Down
1 change: 1 addition & 0 deletions backend/requirements/default.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,4 @@ dropbox==11.36.2
boto3-stubs[s3]==1.34.133
ultimate_sitemap_parser==0.5
stripe==10.12.0
mistune==0.8.4

0 comments on commit 137f4b1

Please sign in to comment.