Sfoglia il codice sorgente

enh: html token (allow yt embed)

Timothy Jaeryang Baek 3 mesi fa
parent
commit
6fd082d55f

+ 49 - 0
src/lib/components/chat/Messages/Markdown/HTMLToken.svelte

@@ -0,0 +1,49 @@
+<script lang="ts">
+	import DOMPurify from 'dompurify';
+	import type { Token } from 'marked';
+
+	import { WEBUI_BASE_URL } from '$lib/constants';
+	import Source from './Source.svelte';
+
+	export let id: string;
+	export let token: Token;
+
+	export let onSourceClick: Function = () => {};
+
+	let html: string | null = null;
+
+	$: if (token.type === 'html' && token?.text) {
+		html = DOMPurify.sanitize(token.text);
+	} else {
+		html = null;
+	}
+</script>
+
+{#if token.type === 'html'}
+	{#if html && html.includes('<video')}
+		{@html html}
+	{:else if token.text && token.text.match(/<iframe\s+[^>]*src="https:\/\/www\.youtube\.com\/embed\/([a-zA-Z0-9_-]{11})"[^>]*><\/iframe>/)}
+		{@const match = token.text.match(
+			/<iframe\s+[^>]*src="https:\/\/www\.youtube\.com\/embed\/([a-zA-Z0-9_-]{11})"[^>]*><\/iframe>/
+		)}
+		{@const ytId = match && match[1]}
+		{#if ytId}
+			<iframe
+				class="w-full aspect-video my-2"
+				src={`https://www.youtube.com/embed/${ytId}`}
+				title="YouTube video player"
+				frameborder="0"
+				allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
+				referrerpolicy="strict-origin-when-cross-origin"
+				allowfullscreen
+			>
+			</iframe>
+		{/if}
+	{:else if token.text.includes(`<iframe src="${WEBUI_BASE_URL}/api/v1/files/`)}
+		{@html `${token.text}`}
+	{:else if token.text.includes(`<source_id`)}
+		<Source {id} {token} onClick={onSourceClick} />
+	{:else}
+		{token.text}
+	{/if}
+{/if}

+ 2 - 10
src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte

@@ -13,6 +13,7 @@
 	import Image from '$lib/components/common/Image.svelte';
 	import KatexRenderer from './KatexRenderer.svelte';
 	import Source from './Source.svelte';
+	import HtmlToken from './HTMLToken.svelte';
 
 	export let id: string;
 	export let tokens: Token[];
@@ -23,16 +24,7 @@
 	{#if token.type === 'escape'}
 		{unescapeHtml(token.text)}
 	{:else if token.type === 'html'}
-		{@const html = DOMPurify.sanitize(token.text)}
-		{#if html && html.includes('<video')}
-			{@html html}
-		{:else if token.text.includes(`<iframe src="${WEBUI_BASE_URL}/api/v1/files/`)}
-			{@html `${token.text}`}
-		{:else if token.text.includes(`<source_id`)}
-			<Source {id} {token} onClick={onSourceClick} />
-		{:else}
-			{@html html}
-		{/if}
+		<HtmlToken {id} {token} {onSourceClick} />
 	{:else if token.type === 'link'}
 		{#if token.tokens}
 			<a href={token.href} target="_blank" rel="nofollow" title={token.title}>

+ 2 - 10
src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte

@@ -21,6 +21,7 @@
 
 	import Source from './Source.svelte';
 	import { settings } from '$lib/stores';
+	import HtmlToken from './HTMLToken.svelte';
 
 	export let id: string;
 	export let tokens: Token[];
@@ -266,16 +267,7 @@
 			</div>
 		</Collapsible>
 	{:else if token.type === 'html'}
-		{@const html = DOMPurify.sanitize(token.text)}
-		{#if html && html.includes('<video')}
-			{@html html}
-		{:else if token.text.includes(`<iframe src="${WEBUI_BASE_URL}/api/v1/files/`)}
-			{@html `${token.text}`}
-		{:else if token.text.includes(`<source_id`)}
-			<Source {id} {token} onClick={onSourceClick} />
-		{:else}
-			{token.text}
-		{/if}
+		<HtmlToken {id} {token} {onSourceClick} />
 	{:else if token.type === 'iframe'}
 		<iframe
 			src="{WEBUI_BASE_URL}/api/v1/files/{token.fileId}/content"