mirror of
https://github.com/open-webui/open-webui
synced 2025-04-20 22:35:03 +00:00
revert: markdown rendering
This commit is contained in:
parent
42bc24a646
commit
9747f1e841
@ -1,16 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Token } from 'marked';
|
import type { Token } from 'marked';
|
||||||
import { unescapeHtml } from '$lib/utils';
|
import { unescapeHtml } from '$lib/utils';
|
||||||
import { onMount } from 'svelte';
|
|
||||||
import { revertSanitizedResponseContent } from '$lib/utils/index.js';
|
|
||||||
import Image from '$lib/components/common/Image.svelte';
|
import Image from '$lib/components/common/Image.svelte';
|
||||||
|
|
||||||
export let id: string;
|
export let id: string;
|
||||||
export let tokens: Token[];
|
export let tokens: Token[];
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
console.log('MarkdownInlineTokens', id, tokens, top);
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#each tokens as token}
|
{#each tokens as token}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { marked } from 'marked';
|
||||||
import type { Token } from 'marked';
|
import type { Token } from 'marked';
|
||||||
import { revertSanitizedResponseContent, unescapeHtml } from '$lib/utils';
|
import { revertSanitizedResponseContent, unescapeHtml } from '$lib/utils';
|
||||||
import CodeBlock from '$lib/components/chat/Messages/CodeBlock.svelte';
|
import CodeBlock from '$lib/components/chat/Messages/CodeBlock.svelte';
|
||||||
@ -13,24 +14,81 @@
|
|||||||
return 'h' + depth;
|
return 'h' + depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
onMount(() => {
|
const renderer = new marked.Renderer();
|
||||||
console.log('MarkdownTokens', id, tokens, top);
|
// For code blocks with simple backticks
|
||||||
});
|
renderer.codespan = (code) => {
|
||||||
|
return `<code class="codespan">${code.replaceAll('&', '&')}</code>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
renderer.code = (code, lang) => {
|
||||||
|
return `<pre><code class="language-${lang}">${code}</code></pre>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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>
|
</script>
|
||||||
|
|
||||||
{#each tokens as token, tokenIdx}
|
{#each tokens as token, tokenIdx (`${id}-${tokenIdx}`)}
|
||||||
{#if token.type === 'hr'}
|
{#if token.type === 'code'}
|
||||||
<hr />
|
{#if token.lang === 'mermaid'}
|
||||||
{:else if token.type === 'heading'}
|
<pre class="mermaid">{revertSanitizedResponseContent(token.text)}</pre>
|
||||||
|
{:else}
|
||||||
|
<CodeBlock
|
||||||
|
id={`${id}-${tokenIdx}`}
|
||||||
|
lang={token?.lang ?? ''}
|
||||||
|
code={revertSanitizedResponseContent(token?.text ?? '')}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
<!-- {:else if token.type === 'heading'}
|
||||||
<svelte:element this={headerComponent(token.depth)}>
|
<svelte:element this={headerComponent(token.depth)}>
|
||||||
<MarkdownInlineTokens id={`${id}-${tokenIdx}-h`} tokens={token.tokens} />
|
<MarkdownInlineTokens id={`${id}-${tokenIdx}-h`} tokens={token.tokens} />
|
||||||
</svelte:element>
|
</svelte:element>
|
||||||
{:else if token.type === 'code'}
|
{:else if token.type === 'hr'}
|
||||||
<CodeBlock
|
<hr />
|
||||||
{id}
|
{:else if token.type === 'blockquote'}
|
||||||
lang={token?.lang ?? ''}
|
<blockquote>
|
||||||
code={revertSanitizedResponseContent(token?.text ?? '')}
|
<svelte:self id={`${id}-${tokenIdx}`} tokens={token.tokens} />
|
||||||
/>
|
</blockquote>
|
||||||
|
{:else if token.type === 'html'}
|
||||||
|
{@html token.text}
|
||||||
|
{:else if token.type === 'paragraph'}
|
||||||
|
<p>
|
||||||
|
<MarkdownInlineTokens id={`${id}-${tokenIdx}-p`} tokens={token.tokens ?? []} />
|
||||||
|
</p>
|
||||||
|
{:else if token.type === 'list'}
|
||||||
|
{#if token.ordered}
|
||||||
|
<ol start={token.start || 1}>
|
||||||
|
{#each token.items as item, itemIdx}
|
||||||
|
<li>
|
||||||
|
<svelte:self
|
||||||
|
id={`${id}-${tokenIdx}-${itemIdx}`}
|
||||||
|
tokens={item.tokens}
|
||||||
|
top={token.loose}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ol>
|
||||||
|
{:else}
|
||||||
|
<ul>
|
||||||
|
{#each token.items as item, itemIdx}
|
||||||
|
<li>
|
||||||
|
<svelte:self
|
||||||
|
id={`${id}-${tokenIdx}-${itemIdx}`}
|
||||||
|
tokens={item.tokens}
|
||||||
|
top={token.loose}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
{:else if token.type === 'table'}
|
{:else if token.type === 'table'}
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
@ -60,44 +118,8 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{:else if token.type === 'blockquote'}
|
{:else if token.type === 'text'} -->
|
||||||
<blockquote>
|
<!-- {#if top}
|
||||||
<svelte:self id={`${id}-${tokenIdx}`} tokens={token.tokens} />
|
|
||||||
</blockquote>
|
|
||||||
{:else if token.type === 'list'}
|
|
||||||
{#if token.ordered}
|
|
||||||
<ol start={token.start || 1}>
|
|
||||||
{#each token.items as item, itemIdx}
|
|
||||||
<li>
|
|
||||||
<svelte:self
|
|
||||||
id={`${id}-${tokenIdx}-${itemIdx}`}
|
|
||||||
tokens={item.tokens}
|
|
||||||
top={token.loose}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</ol>
|
|
||||||
{:else}
|
|
||||||
<ul>
|
|
||||||
{#each token.items as item, itemIdx}
|
|
||||||
<li>
|
|
||||||
<svelte:self
|
|
||||||
id={`${id}-${tokenIdx}-${itemIdx}`}
|
|
||||||
tokens={item.tokens}
|
|
||||||
top={token.loose}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
{/if}
|
|
||||||
{:else if token.type === 'html'}
|
|
||||||
{@html token.text}
|
|
||||||
{:else if token.type === 'paragraph'}
|
|
||||||
<p>
|
|
||||||
<MarkdownInlineTokens id={`${id}-${tokenIdx}-p`} tokens={token.tokens ?? []} />
|
|
||||||
</p>
|
|
||||||
{:else if token.type === 'text'}
|
|
||||||
{#if top}
|
|
||||||
<p>
|
<p>
|
||||||
{#if token.tokens}
|
{#if token.tokens}
|
||||||
<MarkdownInlineTokens id={`${id}-${tokenIdx}-t`} tokens={token.tokens} />
|
<MarkdownInlineTokens id={`${id}-${tokenIdx}-t`} tokens={token.tokens} />
|
||||||
@ -109,10 +131,13 @@
|
|||||||
<MarkdownInlineTokens id={`${id}-${tokenIdx}-p`} tokens={token.tokens ?? []} />
|
<MarkdownInlineTokens id={`${id}-${tokenIdx}-p`} tokens={token.tokens ?? []} />
|
||||||
{:else}
|
{:else}
|
||||||
{unescapeHtml(token.text)}
|
{unescapeHtml(token.text)}
|
||||||
{/if}
|
{/if} -->
|
||||||
{:else if token.type === 'space'}
|
|
||||||
{''}
|
|
||||||
{:else}
|
{:else}
|
||||||
{console.log('Unknown token', token)}
|
{@html marked.parse(token.raw, {
|
||||||
|
...defaults,
|
||||||
|
gfm: true,
|
||||||
|
breaks: true,
|
||||||
|
renderer
|
||||||
|
})}
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -77,9 +77,16 @@
|
|||||||
|
|
||||||
let selectedCitation = null;
|
let selectedCitation = null;
|
||||||
|
|
||||||
$: tokens = marked.lexer(
|
let tokens;
|
||||||
replaceTokens(sanitizeResponseContent(message?.content), model?.name, $user?.name)
|
|
||||||
);
|
$: (async () => {
|
||||||
|
if (message?.content) {
|
||||||
|
tokens = marked.lexer(
|
||||||
|
replaceTokens(sanitizeResponseContent(message?.content), model?.name, $user?.name)
|
||||||
|
);
|
||||||
|
// console.log(message?.content, tokens);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
$: if (message) {
|
$: if (message) {
|
||||||
renderStyling();
|
renderStyling();
|
||||||
@ -413,7 +420,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="prose chat-{message.role} w-full max-w-full dark:prose-invert prose-p:my-0 prose-img:my-1 prose-headings:my-1.5 prose-ol:my-1 prose-ul:my-1 whitespace-pre-line"
|
class="prose chat-{message.role} w-full max-w-full dark:prose-invert prose-p:my-0 prose-img:my-1 prose-headings:my-1.5 prose-ol:my-1 prose-ul:my-1 prose-li:my-0 whitespace-pre-line"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
{#if (message?.statusHistory ?? [...(message?.status ? [message?.status] : [])]).length > 0}
|
{#if (message?.statusHistory ?? [...(message?.status ? [message?.status] : [])]).length > 0}
|
||||||
@ -493,14 +500,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="w-full">
|
<div class="w-full flex flex-col">
|
||||||
{#if message.content === '' && !message.error}
|
{#if message.content === '' && !message.error}
|
||||||
<Skeleton />
|
<Skeleton />
|
||||||
{:else if message.content && message.error !== true}
|
{:else if message.content && message.error !== true}
|
||||||
<!-- always show message contents even if there's an error -->
|
<!-- 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 -->
|
<!-- unless message.error === true which is legacy error handling, where the error message is stored in message.content -->
|
||||||
|
{#key message.id}
|
||||||
{#key tokens}
|
|
||||||
<MarkdownTokens id={message.id} {tokens} />
|
<MarkdownTokens id={message.id} {tokens} />
|
||||||
{/key}
|
{/key}
|
||||||
{/if}
|
{/if}
|
||||||
|
Loading…
Reference in New Issue
Block a user