This commit is contained in:
Timothy J. Baek 2024-08-05 01:03:22 +02:00
parent b414fde6ca
commit bf6c6627e8
3 changed files with 649 additions and 637 deletions

View File

@ -38,6 +38,7 @@
import Spinner from '$lib/components/common/Spinner.svelte';
import WebSearchResults from './ResponseMessage/WebSearchResults.svelte';
import Sparkles from '$lib/components/icons/Sparkles.svelte';
import TokenRenderer from './TokenRenderer.svelte';
export let message;
export let siblings;
@ -80,25 +81,6 @@
replaceTokens(sanitizeResponseContent(message?.content), model?.name, $user?.name)
);
const renderer = new marked.Renderer();
// For code blocks with simple backticks
renderer.codespan = (code) => {
return `<code>${code.replaceAll('&amp;', '&')}</code>`;
};
// Open all links in a new tab/window (from https://github.com/markedjs/marked/issues/655#issuecomment-383226346)
const origLinkRenderer = renderer.link;
renderer.link = (href, title, text) => {
const html = origLinkRenderer.call(renderer, href, title, text);
return html.replace(/^<a /, '<a target="_blank" rel="nofollow" ');
};
const { extensions, ...defaults } = marked.getDefaults() as marked.MarkedOptions & {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
extensions: any;
};
$: if (message) {
renderStyling();
}
@ -417,6 +399,7 @@
{/if}
</Name>
<div>
{#if (message?.files ?? []).filter((f) => f.type === 'image').length > 0}
<div class="my-2.5 w-full flex overflow-x-auto gap-2 flex-wrap">
{#each message.files as file}
@ -517,46 +500,7 @@
<!-- always show message contents even if there's an error -->
<!-- unless message.error === true which is legacy error handling, where the error message is stored in message.content -->
{#each tokens as token, tokenIdx}
{#if token.type === 'code'}
{#if token.lang === 'mermaid'}
<pre class="mermaid">{revertSanitizedResponseContent(token.text)}</pre>
{:else}
<CodeBlock
id={`${message.id}-${tokenIdx}`}
lang={token?.lang ?? ''}
code={revertSanitizedResponseContent(token?.text ?? '')}
/>
{/if}
{:else if token.type === 'paragraph'}
{#if token.tokens}
{#each token.tokens as inlineToken}
{#if inlineToken.type === 'image'}
<Image src={inlineToken.href} alt={inlineToken.text} />
{:else}
{@html marked.parse(inlineToken.raw, {
...defaults,
gfm: true,
breaks: true,
renderer
})}
{/if}
{/each}
{:else}
{@html marked.parse(token.raw, {
...defaults,
gfm: true,
breaks: true,
renderer
})}
{/if}
{:else}
{@html marked.parse(token.raw, {
...defaults,
gfm: true,
breaks: true,
renderer
})}
{/if}
<TokenRenderer {token} {tokenIdx} id={message.id} />
{/each}
{/if}
@ -632,7 +576,12 @@
{/each}
</div>
{/if}
</div>
{/if}
</div>
</div>
{#if !edit}
{#if message.done || siblings.length > 1}
<div
class=" flex justify-start overflow-x-auto buttons text-gray-600 dark:text-gray-500"
@ -786,12 +735,7 @@
cx="12"
cy="12"
r="3"
/><circle
class="spinner_S1WN spinner_JApP"
cx="20"
cy="12"
r="3"
/></svg
/><circle class="spinner_S1WN spinner_JApP" cx="20" cy="12" r="3" /></svg
>
{:else if speaking}
<svg
@ -867,12 +811,7 @@
cx="12"
cy="12"
r="3"
/><circle
class="spinner_S1WN spinner_JApP"
cx="20"
cy="12"
r="3"
/></svg
/><circle class="spinner_S1WN spinner_JApP" cx="20" cy="12" r="3" /></svg
>
{:else}
<svg
@ -1096,12 +1035,10 @@
}}
/>
{/if}
</div>
{/if}
</div>
</div>
</div>
</div>
{/key}
<style>

View File

@ -0,0 +1,75 @@
<script lang="ts">
import { revertSanitizedResponseContent } from '$lib/utils';
import { marked } from 'marked';
import CodeBlock from './CodeBlock.svelte';
import Image from '$lib/components/common/Image.svelte';
import { stringify } from 'postcss';
export let token;
export let tokenIdx = 0;
export let id;
const renderer = new marked.Renderer();
// For code blocks with simple backticks
renderer.codespan = (code) => {
return `<code>${code.replaceAll('&amp;', '&')}</code>`;
};
// 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;
// };
// renderer.image = (href, title, text) => {
// const element = document.createElement('pre');
// new Image({
// target: element,
// props: {
// src: href,
// alt: text
// }
// });
// return element.innerHTML;
// };
// Open all links in a new tab/window (from https://github.com/markedjs/marked/issues/655#issuecomment-383226346)
const origLinkRenderer = renderer.link;
renderer.link = (href, title, text) => {
const html = origLinkRenderer.call(renderer, href, title, text);
return html.replace(/^<a /, '<a target="_blank" rel="nofollow" ');
};
const { extensions, ...defaults } = marked.getDefaults() as marked.MarkedOptions & {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
extensions: any;
};
</script>
{#if token.type === 'code'}
{#if token.lang === 'mermaid'}
<pre class="mermaid">{revertSanitizedResponseContent(token.text)}</pre>
{:else}
<CodeBlock
id={`${id}-${tokenIdx}`}
lang={token?.lang ?? ''}
code={revertSanitizedResponseContent(token?.text ?? '')}
/>
{/if}
{:else}
{@html marked.parse(token.raw, {
...defaults,
gfm: true,
breaks: true,
renderer
})}
{/if}

View File

@ -12,9 +12,7 @@
let showImagePreview = false;
</script>
<ImagePreview bind:show={showImagePreview} src={_src} {alt} />
<div class="w-full">
<div class="w-full py-3">
<button
on:click={() => {
showImagePreview = true;
@ -23,3 +21,5 @@
<img src={_src} {alt} class=" max-h-96 rounded-lg" draggable="false" data-cy="image" />
</button>
</div>
<ImagePreview bind:show={showImagePreview} src={_src} {alt} />