From 84db798353b88acc3c95cb43b112d02c3d5a8e93 Mon Sep 17 00:00:00 2001
From: Thuc Pham <51660321+thucpn@users.noreply.github.com>
Date: Thu, 16 May 2024 15:25:53 +0700
Subject: [PATCH] feat: support display latex in chat markdown (#88)

---
 .changeset/silent-tomatoes-relax.md           |  5 +++++
 .../app/components/ui/chat/markdown.tsx       | 20 ++++++++++++++++++-
 templates/types/streaming/nextjs/package.json |  1 +
 3 files changed, 25 insertions(+), 1 deletion(-)
 create mode 100644 .changeset/silent-tomatoes-relax.md

diff --git a/.changeset/silent-tomatoes-relax.md b/.changeset/silent-tomatoes-relax.md
new file mode 100644
index 00000000..71df852c
--- /dev/null
+++ b/.changeset/silent-tomatoes-relax.md
@@ -0,0 +1,5 @@
+---
+"create-llama": patch
+---
+
+feat: support display latex in chat markdown
diff --git a/templates/types/streaming/nextjs/app/components/ui/chat/markdown.tsx b/templates/types/streaming/nextjs/app/components/ui/chat/markdown.tsx
index fab4cc57..21ab81dd 100644
--- a/templates/types/streaming/nextjs/app/components/ui/chat/markdown.tsx
+++ b/templates/types/streaming/nextjs/app/components/ui/chat/markdown.tsx
@@ -1,5 +1,7 @@
+import "katex/dist/katex.min.css";
 import { FC, memo } from "react";
 import ReactMarkdown, { Options } from "react-markdown";
+import rehypeKatex from "rehype-katex";
 import remarkGfm from "remark-gfm";
 import remarkMath from "remark-math";
 
@@ -12,11 +14,27 @@ const MemoizedReactMarkdown: FC<Options> = memo(
     prevProps.className === nextProps.className,
 );
 
+const preprocessLaTeX = (content: string) => {
+  // Replace block-level LaTeX delimiters \[ \] with $$ $$
+  const blockProcessedContent = content.replace(
+    /\\\[(.*?)\\\]/gs,
+    (_, equation) => `$$${equation}$$`,
+  );
+  // Replace inline LaTeX delimiters \( \) with $ $
+  const inlineProcessedContent = blockProcessedContent.replace(
+    /\\\((.*?)\\\)/gs,
+    (_, equation) => `$${equation}$`,
+  );
+  return inlineProcessedContent;
+};
+
 export default function Markdown({ content }: { content: string }) {
+  const processedContent = preprocessLaTeX(content);
   return (
     <MemoizedReactMarkdown
       className="prose dark:prose-invert prose-p:leading-relaxed prose-pre:p-0 break-words custom-markdown"
       remarkPlugins={[remarkGfm, remarkMath]}
+      rehypePlugins={[rehypeKatex as any]}
       components={{
         p({ children }) {
           return <p className="mb-2 last:mb-0">{children}</p>;
@@ -53,7 +71,7 @@ export default function Markdown({ content }: { content: string }) {
         },
       }}
     >
-      {content}
+      {processedContent}
     </MemoizedReactMarkdown>
   );
 }
diff --git a/templates/types/streaming/nextjs/package.json b/templates/types/streaming/nextjs/package.json
index 3bcaf0cd..182828a4 100644
--- a/templates/types/streaming/nextjs/package.json
+++ b/templates/types/streaming/nextjs/package.json
@@ -30,6 +30,7 @@
     "remark-code-import": "^1.2.0",
     "remark-gfm": "^3.0.1",
     "remark-math": "^5.1.1",
+    "rehype-katex": "^7.0.0",
     "supports-color": "^8.1.1",
     "tailwind-merge": "^2.1.0"
   },
-- 
GitLab