mirror of
https://git.mirrors.martin98.com/https://github.com/open-webui/open-webui
synced 2025-08-15 06:35:58 +08:00
feat: preview html
This commit is contained in:
parent
07b5e84221
commit
54dc24986f
@ -4,7 +4,7 @@
|
|||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
import { chatId, settings, showArtifacts, showControls } from '$lib/stores';
|
import { artifactCode, chatId, settings, showArtifacts, showControls } from '$lib/stores';
|
||||||
import XMark from '../icons/XMark.svelte';
|
import XMark from '../icons/XMark.svelte';
|
||||||
import { copyToClipboard, createMessagesList } from '$lib/utils';
|
import { copyToClipboard, createMessagesList } from '$lib/utils';
|
||||||
import ArrowsPointingOut from '../icons/ArrowsPointingOut.svelte';
|
import ArrowsPointingOut from '../icons/ArrowsPointingOut.svelte';
|
||||||
@ -180,7 +180,14 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMount(() => {});
|
onMount(() => {
|
||||||
|
artifactCode.subscribe((value) => {
|
||||||
|
if (contents) {
|
||||||
|
const codeIdx = contents.findIndex((content) => content.content.includes(value));
|
||||||
|
selectedContentIdx = codeIdx !== -1 ? codeIdx : 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class=" w-full h-full relative flex flex-col bg-gray-50 dark:bg-gray-850">
|
<div class=" w-full h-full relative flex flex-col bg-gray-50 dark:bg-gray-850">
|
||||||
|
@ -957,8 +957,6 @@
|
|||||||
? (e.key === 'Enter' || e.keyCode === 13) && isCtrlPressed
|
? (e.key === 'Enter' || e.keyCode === 13) && isCtrlPressed
|
||||||
: (e.key === 'Enter' || e.keyCode === 13) && !e.shiftKey;
|
: (e.key === 'Enter' || e.keyCode === 13) && !e.shiftKey;
|
||||||
|
|
||||||
console.log('Enter pressed:', enterPressed);
|
|
||||||
|
|
||||||
if (enterPressed) {
|
if (enterPressed) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import ChevronUp from '$lib/components/icons/ChevronUp.svelte';
|
import ChevronUp from '$lib/components/icons/ChevronUp.svelte';
|
||||||
import ChevronUpDown from '$lib/components/icons/ChevronUpDown.svelte';
|
import ChevronUpDown from '$lib/components/icons/ChevronUpDown.svelte';
|
||||||
import CommandLine from '$lib/components/icons/CommandLine.svelte';
|
import CommandLine from '$lib/components/icons/CommandLine.svelte';
|
||||||
|
import Cube from '$lib/components/icons/Cube.svelte';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@ -24,9 +25,11 @@
|
|||||||
|
|
||||||
export let onSave = (e) => {};
|
export let onSave = (e) => {};
|
||||||
export let onCode = (e) => {};
|
export let onCode = (e) => {};
|
||||||
|
export let onPreview = (e) => {};
|
||||||
|
|
||||||
export let save = false;
|
export let save = false;
|
||||||
export let run = true;
|
export let run = true;
|
||||||
|
export let preview = false;
|
||||||
export let collapsed = false;
|
export let collapsed = false;
|
||||||
|
|
||||||
export let token;
|
export let token;
|
||||||
@ -88,6 +91,10 @@
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const previewCode = () => {
|
||||||
|
onPreview(code);
|
||||||
|
};
|
||||||
|
|
||||||
const checkPythonCode = (str) => {
|
const checkPythonCode = (str) => {
|
||||||
// Check if the string contains typical Python syntax characters
|
// Check if the string contains typical Python syntax characters
|
||||||
const pythonSyntax = [
|
const pythonSyntax = [
|
||||||
@ -430,7 +437,7 @@
|
|||||||
class="flex gap-1 items-center bg-none border-none bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition rounded-md px-1.5 py-0.5"
|
class="flex gap-1 items-center bg-none border-none bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition rounded-md px-1.5 py-0.5"
|
||||||
on:click={collapseCodeBlock}
|
on:click={collapseCodeBlock}
|
||||||
>
|
>
|
||||||
<div>
|
<div class=" -translate-y-[0.5px]">
|
||||||
<ChevronUpDown className="size-3" />
|
<ChevronUpDown className="size-3" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -439,6 +446,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{#if preview && ['html', 'svg'].includes(lang)}
|
||||||
|
<button
|
||||||
|
class="flex gap-1 items-center run-code-button bg-none border-none bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition rounded-md px-1.5 py-0.5"
|
||||||
|
on:click={previewCode}
|
||||||
|
>
|
||||||
|
<div class=" -translate-y-[0.5px]">
|
||||||
|
<Cube className="size-3" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{$i18n.t('Preview')}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if ($config?.features?.enable_code_execution ?? true) && (lang.toLowerCase() === 'python' || lang.toLowerCase() === 'py' || (lang === '' && checkPythonCode(code)))}
|
{#if ($config?.features?.enable_code_execution ?? true) && (lang.toLowerCase() === 'python' || lang.toLowerCase() === 'py' || (lang === '' && checkPythonCode(code)))}
|
||||||
{#if executing}
|
{#if executing}
|
||||||
<div class="run-code-button bg-none border-none p-1 cursor-not-allowed">
|
<div class="run-code-button bg-none border-none p-1 cursor-not-allowed">
|
||||||
@ -453,7 +475,7 @@
|
|||||||
executePython(code);
|
executePython(code);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>
|
<div class=" -translate-y-[0.5px]">
|
||||||
<CommandLine className="size-3" />
|
<CommandLine className="size-3" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onDestroy, onMount, tick, getContext, createEventDispatcher } from 'svelte';
|
import { onDestroy, onMount, tick, getContext } from 'svelte';
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
|
|
||||||
import Markdown from './Markdown.svelte';
|
import Markdown from './Markdown.svelte';
|
||||||
import { chatId, mobile, settings, showArtifacts, showControls, showOverview } from '$lib/stores';
|
import {
|
||||||
|
artifactCode,
|
||||||
|
chatId,
|
||||||
|
mobile,
|
||||||
|
settings,
|
||||||
|
showArtifacts,
|
||||||
|
showControls,
|
||||||
|
showOverview
|
||||||
|
} from '$lib/stores';
|
||||||
import FloatingButtons from '../ContentRenderer/FloatingButtons.svelte';
|
import FloatingButtons from '../ContentRenderer/FloatingButtons.svelte';
|
||||||
import { createMessagesList } from '$lib/utils';
|
import { createMessagesList } from '$lib/utils';
|
||||||
|
|
||||||
@ -15,8 +22,10 @@
|
|||||||
export let sources = null;
|
export let sources = null;
|
||||||
|
|
||||||
export let save = false;
|
export let save = false;
|
||||||
|
export let preview = false;
|
||||||
export let floatingButtons = true;
|
export let floatingButtons = true;
|
||||||
|
|
||||||
|
export let onUpdate = () => {};
|
||||||
export let onSourceClick = () => {};
|
export let onSourceClick = () => {};
|
||||||
export let onTaskClick = () => {};
|
export let onTaskClick = () => {};
|
||||||
|
|
||||||
@ -122,6 +131,7 @@
|
|||||||
{content}
|
{content}
|
||||||
{model}
|
{model}
|
||||||
{save}
|
{save}
|
||||||
|
{preview}
|
||||||
sourceIds={(sources ?? []).reduce((acc, s) => {
|
sourceIds={(sources ?? []).reduce((acc, s) => {
|
||||||
let ids = [];
|
let ids = [];
|
||||||
s.document.forEach((document, index) => {
|
s.document.forEach((document, index) => {
|
||||||
@ -154,8 +164,12 @@
|
|||||||
}, [])}
|
}, [])}
|
||||||
{onSourceClick}
|
{onSourceClick}
|
||||||
{onTaskClick}
|
{onTaskClick}
|
||||||
onUpdate={(value) => {
|
{onUpdate}
|
||||||
dispatch('update', value);
|
onPreview={async (value) => {
|
||||||
|
await artifactCode.set(value);
|
||||||
|
await showControls.set(true);
|
||||||
|
await showArtifacts.set(true);
|
||||||
|
await showOverview.set(false);
|
||||||
}}
|
}}
|
||||||
onCode={(value) => {
|
onCode={(value) => {
|
||||||
const { lang, code } = value;
|
const { lang, code } = value;
|
||||||
|
@ -12,11 +12,13 @@
|
|||||||
export let content;
|
export let content;
|
||||||
export let model = null;
|
export let model = null;
|
||||||
export let save = false;
|
export let save = false;
|
||||||
|
export let preview = false;
|
||||||
|
|
||||||
export let sourceIds = [];
|
export let sourceIds = [];
|
||||||
|
|
||||||
export let onUpdate = () => {};
|
export let onUpdate = () => {};
|
||||||
export let onCode = () => {};
|
export let onCode = () => {};
|
||||||
|
export let onPreview = () => {};
|
||||||
|
|
||||||
export let onSourceClick = () => {};
|
export let onSourceClick = () => {};
|
||||||
export let onTaskClick = () => {};
|
export let onTaskClick = () => {};
|
||||||
@ -40,5 +42,15 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#key id}
|
{#key id}
|
||||||
<MarkdownTokens {tokens} {id} {save} {onTaskClick} {onSourceClick} {onUpdate} {onCode} />
|
<MarkdownTokens
|
||||||
|
{tokens}
|
||||||
|
{id}
|
||||||
|
{save}
|
||||||
|
{preview}
|
||||||
|
{onTaskClick}
|
||||||
|
{onSourceClick}
|
||||||
|
{onUpdate}
|
||||||
|
{onCode}
|
||||||
|
{onPreview}
|
||||||
|
/>
|
||||||
{/key}
|
{/key}
|
||||||
|
@ -29,9 +29,11 @@
|
|||||||
export let attributes = {};
|
export let attributes = {};
|
||||||
|
|
||||||
export let save = false;
|
export let save = false;
|
||||||
|
export let preview = false;
|
||||||
|
|
||||||
export let onUpdate: Function = () => {};
|
export let onUpdate: Function = () => {};
|
||||||
export let onCode: Function = () => {};
|
export let onCode: Function = () => {};
|
||||||
|
export let onPreview: Function = () => {};
|
||||||
|
|
||||||
export let onTaskClick: Function = () => {};
|
export let onTaskClick: Function = () => {};
|
||||||
export let onSourceClick: Function = () => {};
|
export let onSourceClick: Function = () => {};
|
||||||
@ -95,7 +97,9 @@
|
|||||||
code={token?.text ?? ''}
|
code={token?.text ?? ''}
|
||||||
{attributes}
|
{attributes}
|
||||||
{save}
|
{save}
|
||||||
|
{preview}
|
||||||
{onCode}
|
{onCode}
|
||||||
|
{onPreview}
|
||||||
onSave={(value) => {
|
onSave={(value) => {
|
||||||
onUpdate({
|
onUpdate({
|
||||||
raw: token.raw,
|
raw: token.raw,
|
||||||
|
@ -806,6 +806,7 @@
|
|||||||
sources={message.sources}
|
sources={message.sources}
|
||||||
floatingButtons={message?.done && !readOnly}
|
floatingButtons={message?.done && !readOnly}
|
||||||
save={!readOnly}
|
save={!readOnly}
|
||||||
|
preview={!readOnly}
|
||||||
{model}
|
{model}
|
||||||
onTaskClick={async (e) => {
|
onTaskClick={async (e) => {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
@ -840,28 +841,13 @@
|
|||||||
onAddMessages={({ modelId, parentId, messages }) => {
|
onAddMessages={({ modelId, parentId, messages }) => {
|
||||||
addMessages({ modelId, parentId, messages });
|
addMessages({ modelId, parentId, messages });
|
||||||
}}
|
}}
|
||||||
on:update={(e) => {
|
onUpdate={({ raw, oldContent, newContent }) => {
|
||||||
const { raw, oldContent, newContent } = e.detail;
|
|
||||||
|
|
||||||
history.messages[message.id].content = history.messages[
|
history.messages[message.id].content = history.messages[
|
||||||
message.id
|
message.id
|
||||||
].content.replace(raw, raw.replace(oldContent, newContent));
|
].content.replace(raw, raw.replace(oldContent, newContent));
|
||||||
|
|
||||||
updateChat();
|
updateChat();
|
||||||
}}
|
}}
|
||||||
on:select={(e) => {
|
|
||||||
const { type, content } = e.detail;
|
|
||||||
|
|
||||||
if (type === 'explain') {
|
|
||||||
submitMessage(
|
|
||||||
message.id,
|
|
||||||
`Explain this section to me in more detail\n\n\`\`\`\n${content}\n\`\`\``
|
|
||||||
);
|
|
||||||
} else if (type === 'ask') {
|
|
||||||
const input = e.detail?.input ?? '';
|
|
||||||
submitMessage(message.id, `\`\`\`\n${content}\n\`\`\`\n${input}`);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
@ -74,6 +74,8 @@ export const showOverview = writable(false);
|
|||||||
export const showArtifacts = writable(false);
|
export const showArtifacts = writable(false);
|
||||||
export const showCallOverlay = writable(false);
|
export const showCallOverlay = writable(false);
|
||||||
|
|
||||||
|
export const artifactCode = writable(null);
|
||||||
|
|
||||||
export const temporaryChatEnabled = writable(false);
|
export const temporaryChatEnabled = writable(false);
|
||||||
export const scrollPaginationEnabled = writable(false);
|
export const scrollPaginationEnabled = writable(false);
|
||||||
export const currentChatPage = writable(1);
|
export const currentChatPage = writable(1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user