From 91f547ba9c8995afc1fe9b860ddf3d4dab9aa2bc Mon Sep 17 00:00:00 2001 From: Phil Szalay Date: Tue, 25 Mar 2025 16:03:25 +0100 Subject: [PATCH] Link citation numbers generated by Perplexity models in UI --- src/app.css | 5 ++++ .../chat/Messages/ContentRenderer.svelte | 1 + .../components/chat/Messages/Markdown.svelte | 23 ++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/app.css b/src/app.css index dadfda78f..c15d18748 100644 --- a/src/app.css +++ b/src/app.css @@ -64,6 +64,11 @@ math { @apply underline; } +/* Remove underline for citation links */ +.markdown-prose a[title="citation"] { + @apply no-underline; +} + .font-primary { font-family: 'Archivo', sans-serif; } diff --git a/src/lib/components/chat/Messages/ContentRenderer.svelte b/src/lib/components/chat/Messages/ContentRenderer.svelte index 04634ba2e..0fd086a9c 100644 --- a/src/lib/components/chat/Messages/ContentRenderer.svelte +++ b/src/lib/components/chat/Messages/ContentRenderer.svelte @@ -115,6 +115,7 @@ {content} {model} {save} + {sources} sourceIds={(sources ?? []).reduce((acc, s) => { let ids = []; s.document.forEach((document, index) => { diff --git a/src/lib/components/chat/Messages/Markdown.svelte b/src/lib/components/chat/Messages/Markdown.svelte index 99ad77190..7eb07087f 100644 --- a/src/lib/components/chat/Messages/Markdown.svelte +++ b/src/lib/components/chat/Messages/Markdown.svelte @@ -15,6 +15,7 @@ export let content; export let model = null; export let save = false; + export let sources = null; export let sourceIds = []; export let onSourceClick = () => {}; @@ -25,13 +26,33 @@ throwOnError: false }; + // Function to handle citation linking + function linkifyCitations(content, sources) { + if (!content || !sources || sources.length === 0) return content; + + // Regex to match citation markers like [1], [2], etc. + const citationRegex = /\[(\d+)]/g; + + // Replace markers with special tokens that can be processed by the markdown renderer + return content.replace(citationRegex, (match, number) => { + const citationIndex = parseInt(number, 10) - 1; // Convert to 0-based index + if (sources[citationIndex]) { + // Create a special token with a data-citation attribute that will be recognized by the renderer + return ` [${match}](${sources[citationIndex].source.name} "citation")`; + } + return match; // If no citation exists, keep it as is + }); + } + marked.use(markedKatexExtension(options)); marked.use(markedExtension(options)); $: (async () => { if (content) { + // Process citations before passing to marked lexer + const processedContent = sources ? linkifyCitations(content, sources) : content; tokens = marked.lexer( - replaceTokens(processResponseContent(content), sourceIds, model?.name, $user?.name) + replaceTokens(processResponseContent(processedContent), sourceIds, model?.name, $user?.name) ); } })();