From 43e29d6f9b05b3aa0058d4a1ab3f9a9c85bda606 Mon Sep 17 00:00:00 2001 From: Sean Hatfield <seanhatfield5@gmail.com> Date: Wed, 19 Feb 2025 12:55:56 +0800 Subject: [PATCH] Markdown support in custom messages (#3267) * add md support to appearance custom messages * break out dompurify to util --------- Co-authored-by: Timothy Carambat <rambat1010@gmail.com> --- frontend/src/components/ChatBubble/index.jsx | 13 ++++++++----- frontend/src/components/EditingChatBubble/index.jsx | 11 ++++++++--- .../ChatHistory/HistoricalMessage/index.jsx | 7 +------ frontend/src/utils/chat/purify.js | 8 ++++++++ 4 files changed, 25 insertions(+), 14 deletions(-) create mode 100644 frontend/src/utils/chat/purify.js diff --git a/frontend/src/components/ChatBubble/index.jsx b/frontend/src/components/ChatBubble/index.jsx index 4ffc3d085..7b37cd5d1 100644 --- a/frontend/src/components/ChatBubble/index.jsx +++ b/frontend/src/components/ChatBubble/index.jsx @@ -1,6 +1,8 @@ import React from "react"; import UserIcon from "../UserIcon"; import { userFromStorage } from "@/utils/request"; +import renderMarkdown from "@/utils/chat/markdown"; +import DOMPurify from "@/utils/chat/purify"; export default function ChatBubble({ message, type, popMsg }) { const isUser = type === "user"; @@ -16,11 +18,12 @@ export default function ChatBubble({ message, type, popMsg }) { role={type} /> - <span - className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`} - > - {message} - </span> + <div + className={`markdown whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`} + dangerouslySetInnerHTML={{ + __html: DOMPurify.sanitize(renderMarkdown(message)), + }} + /> </div> </div> </div> diff --git a/frontend/src/components/EditingChatBubble/index.jsx b/frontend/src/components/EditingChatBubble/index.jsx index feabd4c6e..652297c79 100644 --- a/frontend/src/components/EditingChatBubble/index.jsx +++ b/frontend/src/components/EditingChatBubble/index.jsx @@ -1,6 +1,8 @@ import React, { useState } from "react"; import { X } from "@phosphor-icons/react"; import { useTranslation } from "react-i18next"; +import renderMarkdown from "@/utils/chat/markdown"; +import DOMPurify from "@/utils/chat/purify"; export default function EditingChatBubble({ message, @@ -57,9 +59,12 @@ export default function EditingChatBubble({ /> ) : ( tempMessage && ( - <p className=" font-[500] md:font-semibold text-sm md:text-base break-words light:invert"> - {tempMessage} - </p> + <div + className="markdown font-[500] md:font-semibold text-sm md:text-base break-words light:invert" + dangerouslySetInnerHTML={{ + __html: DOMPurify.sanitize(renderMarkdown(tempMessage)), + }} + /> ) )} </div> diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx index a5d60db4e..5a5454bb2 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx @@ -6,7 +6,7 @@ import renderMarkdown from "@/utils/chat/markdown"; import { userFromStorage } from "@/utils/request"; import Citations from "../Citation"; import { v4 } from "uuid"; -import createDOMPurify from "dompurify"; +import DOMPurify from "@/utils/chat/purify"; import { EditMessageForm, useEditMessage } from "./Actions/EditMessage"; import { useWatchDeleteMessage } from "./Actions/DeleteMessage"; import TTSMessage from "./Actions/TTSButton"; @@ -17,11 +17,6 @@ import { ThoughtChainComponent, } from "../ThoughtContainer"; -const DOMPurify = createDOMPurify(window); -DOMPurify.setConfig({ - ADD_ATTR: ["target", "rel"], -}); - const HistoricalMessage = ({ uuid = v4(), message, diff --git a/frontend/src/utils/chat/purify.js b/frontend/src/utils/chat/purify.js new file mode 100644 index 000000000..a6cf85206 --- /dev/null +++ b/frontend/src/utils/chat/purify.js @@ -0,0 +1,8 @@ +import createDOMPurify from "dompurify"; + +const DOMPurify = createDOMPurify(window); +DOMPurify.setConfig({ + ADD_ATTR: ["target", "rel"], +}); + +export default DOMPurify; -- GitLab