Skip to content

Commit bbeae2c

Browse files
committed
Render chat completions in markdown
1 parent d490d2a commit bbeae2c

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

core/completion/litellm_completion.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def get_system_message() -> Dict[str, str]:
3030
3. Be clear and concise in your answers
3131
4. When relevant, cite specific parts of the context to support your answers
3232
5. For image-based queries, analyze the visual content in conjunction with any text context provided
33+
6. Format your responses using Markdown.
3334
3435
Remember: Your primary goal is to provide accurate, context-aware responses that help users understand
3536
and utilize the information in their documents effectively.""",

ee/ui-component/components/chat/ChatMessages.tsx

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import { Badge } from "@/components/ui/badge";
44
import { Spin } from "./icons";
55
import Image from "next/image";
66
import { Source } from "@/components/types";
7+
import ReactMarkdown from "react-markdown";
8+
import remarkGfm from "remark-gfm";
9+
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
10+
import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism";
11+
import type { Options } from "react-markdown";
712

813
// Define interface for the UIMessage - matching what our useMorphikChat hook returns
914
export interface UIMessage {
@@ -76,7 +81,50 @@ export function PreviewMessage({ message }: Pick<MessageProps, "message">) {
7681
message.role === "user" ? "ml-auto bg-primary text-primary-foreground" : "bg-muted"
7782
}`}
7883
>
79-
<div className="prose prose-sm dark:prose-invert break-words">{message.content}</div>
84+
<div className="prose prose-sm dark:prose-invert max-w-none break-words">
85+
{message.role === "assistant" ? (
86+
<ReactMarkdown
87+
remarkPlugins={[remarkGfm]}
88+
components={
89+
{
90+
code(props) {
91+
const { children, className, node, ...rest } = props;
92+
const inline = !className?.includes("language-");
93+
const match = /language-(\w+)/.exec(className || "");
94+
95+
if (!inline && match) {
96+
const language = match[1];
97+
return (
98+
<div className="my-4 overflow-hidden rounded-md">
99+
<SyntaxHighlighter style={oneDark} language={language} PreTag="div" className="!my-0">
100+
{String(children).replace(/\n$/, "")}
101+
</SyntaxHighlighter>
102+
</div>
103+
);
104+
} else if (!inline) {
105+
return (
106+
<div className="my-4 overflow-hidden rounded-md">
107+
<SyntaxHighlighter style={oneDark} language="text" PreTag="div" className="!my-0">
108+
{String(children).replace(/\n$/, "")}
109+
</SyntaxHighlighter>
110+
</div>
111+
);
112+
}
113+
return (
114+
<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-sm" {...rest}>
115+
{children}
116+
</code>
117+
);
118+
},
119+
} as Options["components"]
120+
}
121+
>
122+
{message.content}
123+
</ReactMarkdown>
124+
) : (
125+
message.content // User messages rendered as plain text within prose-styled div
126+
)}
127+
</div>
80128
</div>
81129

82130
{sources && sources.length > 0 && message.role === "assistant" && (

0 commit comments

Comments
 (0)