From e150dc5a91f2fd268ba59d86c0dd1435b82b7ebe Mon Sep 17 00:00:00 2001 From: Debanjum Date: Mon, 25 Aug 2025 12:36:15 -0700 Subject: [PATCH] Improve copying message with math, file links to clipboard on web app --- .../components/chatMessage/chatMessage.tsx | 39 ++++++++++--------- src/interface/web/package.json | 2 +- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/interface/web/app/components/chatMessage/chatMessage.tsx b/src/interface/web/app/components/chatMessage/chatMessage.tsx index b6afff76..ec8a90cc 100644 --- a/src/interface/web/app/components/chatMessage/chatMessage.tsx +++ b/src/interface/web/app/components/chatMessage/chatMessage.tsx @@ -466,23 +466,9 @@ const ChatMessage = forwardRef((props, ref) => setMermaidjsData(props.chatMessage.mermaidjsDiagram); } - // Replace LaTeX delimiters with placeholders - message = message - .replace(/\\\(/g, "LEFTPAREN") - .replace(/\\\)/g, "RIGHTPAREN") - .replace(/\\\[/g, "LEFTBRACKET") - .replace(/\\\]/g, "RIGHTBRACKET"); - // Replace file links with base64 data message = renderCodeGenImageInline(message, props.chatMessage.codeContext); - // Preprocess file:// links so markdown-it processes them - // We convert them to a custom scheme (filelink://) and handle in the plugin - message = message.replace(/\[([^\]]+)\]\(file:\/\/([^)]+)\)/g, (match, text, path) => { - // Use a special scheme that markdown-it will process - return `[${text}](filelink://${path})`; - }); - // Add code context files to the message if (props.chatMessage.codeContext) { Object.entries(props.chatMessage.codeContext).forEach(([key, value]) => { @@ -497,7 +483,7 @@ const ChatMessage = forwardRef((props, ref) => }); } - // Handle user attached images rendering + // Handle rendering user attached or khoj generated images let messageForClipboard = message; let messageToRender = message; if (props.chatMessage.images && props.chatMessage.images.length > 0) { @@ -509,12 +495,12 @@ const ChatMessage = forwardRef((props, ref) => }); const imagesInMd = sanitizedImages .map((sanitizedImage, index) => { - return `![uploaded image ${index + 1}](${sanitizedImage})`; + return `![rendered image ${index + 1}](${sanitizedImage})`; }) .join("\n"); const imagesInHtml = sanitizedImages .map((sanitizedImage, index) => { - return `
uploaded image ${index + 1}
`; + return `
rendered image ${index + 1}
`; }) .join(""); const userImagesInHtml = `
${imagesInHtml}
`; @@ -525,10 +511,27 @@ const ChatMessage = forwardRef((props, ref) => // Set the message text setTextRendered(messageForClipboard); + // Replace LaTeX delimiters with placeholders + messageToRender = messageToRender + .replace(/\\\(/g, "LEFTPAREN") + .replace(/\\\)/g, "RIGHTPAREN") + .replace(/\\\[/g, "LEFTBRACKET") + .replace(/\\\]/g, "RIGHTBRACKET"); + + // Preprocess file:// links so markdown-it processes them + // We convert them to a custom scheme (filelink://) and handle in the plugin + messageToRender = messageToRender.replace( + /\[([^\]]+)\]\(file:\/\/([^)]+)\)/g, + (match, text, path) => { + // Use a special scheme that markdown-it will process + return `[${text}](filelink://${path})`; + }, + ); + // Render the markdown let markdownRendered = md.render(messageToRender); - // Replace placeholders with LaTeX delimiters + // Revert placeholders with LaTeX delimiters markdownRendered = markdownRendered .replace(/LEFTPAREN/g, "\\(") .replace(/RIGHTPAREN/g, "\\)") diff --git a/src/interface/web/package.json b/src/interface/web/package.json index 5f2332d2..8574124e 100644 --- a/src/interface/web/package.json +++ b/src/interface/web/package.json @@ -55,7 +55,7 @@ "input-otp": "^1.2.4", "intl-tel-input": "^23.8.1", "jszip": "^3.10.1", - "katex": "^0.16.21", + "katex": "^0.16.22", "libphonenumber-js": "^1.11.4", "lucide-react": "^0.468.0", "markdown-it": "^14.1.0",