From 7d42a79177aef9fc12ede4f0bbeccfe3ffe53a3f Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Mon, 5 Aug 2024 17:12:41 +0200 Subject: [PATCH] refac: token rendering --- .../chat/Messages/HTMLRenderer.svelte | 30 ++++++ .../chat/Messages/TokenRenderer.svelte | 97 +++++++++++-------- src/lib/components/common/Image.svelte | 4 +- 3 files changed, 90 insertions(+), 41 deletions(-) create mode 100644 src/lib/components/chat/Messages/HTMLRenderer.svelte diff --git a/src/lib/components/chat/Messages/HTMLRenderer.svelte b/src/lib/components/chat/Messages/HTMLRenderer.svelte new file mode 100644 index 000000000..53fad8084 --- /dev/null +++ b/src/lib/components/chat/Messages/HTMLRenderer.svelte @@ -0,0 +1,30 @@ + + +{#each parsedHTML as part} + {@const match = rules.find((rule) => rule.regex.test(part))} + {#if match} + + {@html part} + + {:else} + {@html part} + {/if} +{/each} diff --git a/src/lib/components/chat/Messages/TokenRenderer.svelte b/src/lib/components/chat/Messages/TokenRenderer.svelte index ecef0fcb4..13fd56bea 100644 --- a/src/lib/components/chat/Messages/TokenRenderer.svelte +++ b/src/lib/components/chat/Messages/TokenRenderer.svelte @@ -10,6 +10,9 @@ export let tokenIdx = 0; export let id; + let element; + let content; + const renderer = new marked.Renderer(); // For code blocks with simple backticks @@ -17,30 +20,19 @@ return `${code.replaceAll('&', '&')}`; }; - // renderer.code = (code, lang) => { - // const element = document.createElement('div'); - // new CodeBlock({ - // target: element, - // props: { - // id: `${id}-${tokenIdx}`, - // lang: lang ?? '', - // code: revertSanitizedResponseContent(code ?? '') - // } - // }); - // return element.innerHTML; - // }; + let codes = []; + renderer.code = (code, lang) => { + codes.push({ code, lang, id: codes.length }); + codes = codes; + return `{{@CODE ${codes.length - 1}}}`; + }; - // renderer.image = (href, title, text) => { - // const element = document.createElement('pre'); - // new Image({ - // target: element, - // props: { - // src: href, - // alt: text - // } - // }); - // return element.innerHTML; - // }; + let images = []; + renderer.image = (href, title, text) => { + images.push({ href, title, text }); + images = images; + return `{{@IMAGE ${images.length - 1}}}`; + }; // Open all links in a new tab/window (from https://github.com/markedjs/marked/issues/655#issuecomment-383226346) const origLinkRenderer = renderer.link; @@ -53,23 +45,50 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any extensions: any; }; + + $: if (token) { + images = []; + codes = []; + content = marked + .parse(token.raw, { + ...defaults, + gfm: true, + breaks: true, + renderer + }) + .split(/({{@IMAGE [^}]+}}|{{@CODE [^}]+}})/g); + } -{#if token.type === 'code'} - {#if token.lang === 'mermaid'} -
{revertSanitizedResponseContent(token.text)}
+
+ {#if token.type === 'code'} + {#if token.lang === 'mermaid'} +
{revertSanitizedResponseContent(token.text)}
+ {:else} + + {/if} + {:else if token.type === 'image'} + {token.text} {:else} - + {#each content as part} + {@html part.startsWith('{{@IMAGE ') || part.startsWith('{{@CODE ') ? '' : part} + + {#if images.length > 0 && part.startsWith('{{@IMAGE ')} + {@const img = images[parseInt(part.match(/{{@IMAGE (\d+)}}/)[1])]} + +
+ +
+ {:else if codes.length > 0 && part.startsWith('{{@CODE ')} + {@const _code = codes[parseInt(part.match(/{{@CODE (\d+)}}/)[1])]} +
+ +
+ {/if} + {/each} {/if} -{:else} - {@html marked.parse(token.raw, { - ...defaults, - gfm: true, - breaks: true, - renderer - })} -{/if} +
diff --git a/src/lib/components/common/Image.svelte b/src/lib/components/common/Image.svelte index 435ad64ee..425b9bc4f 100644 --- a/src/lib/components/common/Image.svelte +++ b/src/lib/components/common/Image.svelte @@ -12,14 +12,14 @@ let showImagePreview = false; -
+
-