mirror of
https://github.com/open-webui/open-webui
synced 2025-03-25 15:08:18 +00:00
enh: summary tag support
This commit is contained in:
parent
d255251e5f
commit
ffd598c5d7
@ -1,9 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import { marked } from 'marked';
|
import { marked } from 'marked';
|
||||||
import markedKatex from '$lib/utils/marked/katex-extension';
|
|
||||||
import { replaceTokens, processResponseContent } from '$lib/utils';
|
import { replaceTokens, processResponseContent } from '$lib/utils';
|
||||||
import { user } from '$lib/stores';
|
import { user } from '$lib/stores';
|
||||||
|
|
||||||
|
import markedExtension from '$lib/utils/marked/extension';
|
||||||
|
import markedKatexExtension from '$lib/utils/marked/katex-extension';
|
||||||
|
|
||||||
import MarkdownTokens from './Markdown/MarkdownTokens.svelte';
|
import MarkdownTokens from './Markdown/MarkdownTokens.svelte';
|
||||||
|
|
||||||
export let id;
|
export let id;
|
||||||
@ -16,7 +18,8 @@
|
|||||||
throwOnError: false
|
throwOnError: false
|
||||||
};
|
};
|
||||||
|
|
||||||
marked.use(markedKatex(options));
|
marked.use(markedKatexExtension(options));
|
||||||
|
marked.use(markedExtension(options));
|
||||||
|
|
||||||
$: (async () => {
|
$: (async () => {
|
||||||
if (content) {
|
if (content) {
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
import MarkdownInlineTokens from '$lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte';
|
import MarkdownInlineTokens from '$lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte';
|
||||||
import KatexRenderer from './KatexRenderer.svelte';
|
import KatexRenderer from './KatexRenderer.svelte';
|
||||||
import { WEBUI_BASE_URL } from '$lib/constants';
|
import { WEBUI_BASE_URL } from '$lib/constants';
|
||||||
|
import { stringify } from 'postcss';
|
||||||
|
|
||||||
export let id: string;
|
export let id: string;
|
||||||
export let tokens: Token[];
|
export let tokens: Token[];
|
||||||
@ -94,6 +95,12 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
{/if}
|
{/if}
|
||||||
|
{:else if token.type === 'details'}
|
||||||
|
<details>
|
||||||
|
<summary>{token.summary}</summary>
|
||||||
|
|
||||||
|
<svelte:self id={`${id}-${tokenIdx}-d`} tokens={marked.lexer(token.text)} />
|
||||||
|
</details>
|
||||||
{:else if token.type === 'html'}
|
{:else if token.type === 'html'}
|
||||||
{@const html = DOMPurify.sanitize(token.text)}
|
{@const html = DOMPurify.sanitize(token.text)}
|
||||||
{#if html && html.includes('<video')}
|
{#if html && html.includes('<video')}
|
||||||
|
70
src/lib/utils/marked/extension.ts
Normal file
70
src/lib/utils/marked/extension.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Helper function to find matching closing tag
|
||||||
|
function findMatchingClosingTag(src, openTag, closeTag) {
|
||||||
|
let depth = 1;
|
||||||
|
let index = openTag.length;
|
||||||
|
while (depth > 0 && index < src.length) {
|
||||||
|
if (src.startsWith(openTag, index)) {
|
||||||
|
depth++;
|
||||||
|
} else if (src.startsWith(closeTag, index)) {
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
if (depth > 0) {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return depth === 0 ? index + closeTag.length : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function detailsTokenizer(src) {
|
||||||
|
const detailsRegex = /^<details>\n/;
|
||||||
|
const summaryRegex = /^<summary>(.*?)<\/summary>\n/;
|
||||||
|
|
||||||
|
if (detailsRegex.test(src)) {
|
||||||
|
const endIndex = findMatchingClosingTag(src, '<details>', '</details>');
|
||||||
|
if (endIndex === -1) return;
|
||||||
|
|
||||||
|
const fullMatch = src.slice(0, endIndex);
|
||||||
|
let content = fullMatch.slice(10, -10).trim(); // Remove <details> and </details>
|
||||||
|
|
||||||
|
let summary = '';
|
||||||
|
const summaryMatch = summaryRegex.exec(content);
|
||||||
|
if (summaryMatch) {
|
||||||
|
summary = summaryMatch[1].trim();
|
||||||
|
content = content.slice(summaryMatch[0].length).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'details',
|
||||||
|
raw: fullMatch,
|
||||||
|
summary: summary,
|
||||||
|
text: content
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function detailsStart(src) {
|
||||||
|
return src.match(/^<details>/) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function detailsRenderer(token) {
|
||||||
|
return `<details>
|
||||||
|
${token.summary ? `<summary>${token.summary}</summary>` : ''}
|
||||||
|
${token.text}
|
||||||
|
</details>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function detailsExtension() {
|
||||||
|
return {
|
||||||
|
name: 'details',
|
||||||
|
level: 'block',
|
||||||
|
start: detailsStart,
|
||||||
|
tokenizer: detailsTokenizer,
|
||||||
|
renderer: detailsRenderer
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function (options = {}) {
|
||||||
|
return {
|
||||||
|
extensions: [detailsExtension(options)]
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user