mirror of
https://github.com/open-webui/open-webui
synced 2025-06-26 18:26:48 +00:00
refac: chat transition
This commit is contained in:
parent
4e4b5ab83b
commit
512345f40e
@ -88,6 +88,7 @@
|
||||
import Placeholder from './Placeholder.svelte';
|
||||
import NotificationToast from '../NotificationToast.svelte';
|
||||
import Spinner from '../common/Spinner.svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
export let chatIdProp = '';
|
||||
|
||||
@ -2011,196 +2012,198 @@
|
||||
id="chat-container"
|
||||
>
|
||||
{#if !loading}
|
||||
{#if $settings?.backgroundImageUrl ?? null}
|
||||
<div
|
||||
class="absolute {$showSidebar
|
||||
? 'md:max-w-[calc(100%-260px)] md:translate-x-[260px]'
|
||||
: ''} top-0 left-0 w-full h-full bg-cover bg-center bg-no-repeat"
|
||||
style="background-image: url({$settings.backgroundImageUrl}) "
|
||||
/>
|
||||
|
||||
<div
|
||||
class="absolute top-0 left-0 w-full h-full bg-linear-to-t from-white to-white/85 dark:from-gray-900 dark:to-gray-900/90 z-0"
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<PaneGroup direction="horizontal" class="w-full h-full">
|
||||
<Pane defaultSize={50} class="h-full flex relative max-w-full flex-col">
|
||||
<Navbar
|
||||
bind:this={navbarElement}
|
||||
chat={{
|
||||
id: $chatId,
|
||||
chat: {
|
||||
title: $chatTitle,
|
||||
models: selectedModels,
|
||||
system: $settings.system ?? undefined,
|
||||
params: params,
|
||||
history: history,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
}}
|
||||
{history}
|
||||
title={$chatTitle}
|
||||
bind:selectedModels
|
||||
shareEnabled={!!history.currentId}
|
||||
{initNewChat}
|
||||
<div in:fade={{ duration: 100 }} class="w-full h-full flex flex-col">
|
||||
{#if $settings?.backgroundImageUrl ?? null}
|
||||
<div
|
||||
class="absolute {$showSidebar
|
||||
? 'md:max-w-[calc(100%-260px)] md:translate-x-[260px]'
|
||||
: ''} top-0 left-0 w-full h-full bg-cover bg-center bg-no-repeat"
|
||||
style="background-image: url({$settings.backgroundImageUrl}) "
|
||||
/>
|
||||
|
||||
<div class="flex flex-col flex-auto z-10 w-full @container">
|
||||
{#if $settings?.landingPageMode === 'chat' || createMessagesList(history, history.currentId).length > 0}
|
||||
<div
|
||||
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0 max-w-full z-10 scrollbar-hidden"
|
||||
id="messages-container"
|
||||
bind:this={messagesContainerElement}
|
||||
on:scroll={(e) => {
|
||||
autoScroll =
|
||||
messagesContainerElement.scrollHeight - messagesContainerElement.scrollTop <=
|
||||
messagesContainerElement.clientHeight + 5;
|
||||
}}
|
||||
>
|
||||
<div class=" h-full w-full flex flex-col">
|
||||
<Messages
|
||||
chatId={$chatId}
|
||||
bind:history
|
||||
bind:autoScroll
|
||||
bind:prompt
|
||||
<div
|
||||
class="absolute top-0 left-0 w-full h-full bg-linear-to-t from-white to-white/85 dark:from-gray-900 dark:to-gray-900/90 z-0"
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<PaneGroup direction="horizontal" class="w-full h-full">
|
||||
<Pane defaultSize={50} class="h-full flex relative max-w-full flex-col">
|
||||
<Navbar
|
||||
bind:this={navbarElement}
|
||||
chat={{
|
||||
id: $chatId,
|
||||
chat: {
|
||||
title: $chatTitle,
|
||||
models: selectedModels,
|
||||
system: $settings.system ?? undefined,
|
||||
params: params,
|
||||
history: history,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
}}
|
||||
{history}
|
||||
title={$chatTitle}
|
||||
bind:selectedModels
|
||||
shareEnabled={!!history.currentId}
|
||||
{initNewChat}
|
||||
/>
|
||||
|
||||
<div class="flex flex-col flex-auto z-10 w-full @container">
|
||||
{#if $settings?.landingPageMode === 'chat' || createMessagesList(history, history.currentId).length > 0}
|
||||
<div
|
||||
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0 max-w-full z-10 scrollbar-hidden"
|
||||
id="messages-container"
|
||||
bind:this={messagesContainerElement}
|
||||
on:scroll={(e) => {
|
||||
autoScroll =
|
||||
messagesContainerElement.scrollHeight - messagesContainerElement.scrollTop <=
|
||||
messagesContainerElement.clientHeight + 5;
|
||||
}}
|
||||
>
|
||||
<div class=" h-full w-full flex flex-col">
|
||||
<Messages
|
||||
chatId={$chatId}
|
||||
bind:history
|
||||
bind:autoScroll
|
||||
bind:prompt
|
||||
{selectedModels}
|
||||
{atSelectedModel}
|
||||
{sendPrompt}
|
||||
{showMessage}
|
||||
{submitMessage}
|
||||
{continueResponse}
|
||||
{regenerateResponse}
|
||||
{mergeResponses}
|
||||
{chatActionHandler}
|
||||
{addMessages}
|
||||
bottomPadding={files.length > 0}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" pb-[1rem]">
|
||||
<MessageInput
|
||||
{history}
|
||||
{taskIds}
|
||||
{selectedModels}
|
||||
{atSelectedModel}
|
||||
{sendPrompt}
|
||||
{showMessage}
|
||||
{submitMessage}
|
||||
{continueResponse}
|
||||
{regenerateResponse}
|
||||
{mergeResponses}
|
||||
{chatActionHandler}
|
||||
{addMessages}
|
||||
bottomPadding={files.length > 0}
|
||||
bind:files
|
||||
bind:prompt
|
||||
bind:autoScroll
|
||||
bind:selectedToolIds
|
||||
bind:selectedFilterIds
|
||||
bind:imageGenerationEnabled
|
||||
bind:codeInterpreterEnabled
|
||||
bind:webSearchEnabled
|
||||
bind:atSelectedModel
|
||||
toolServers={$toolServers}
|
||||
transparentBackground={$settings?.backgroundImageUrl ?? false}
|
||||
{stopResponse}
|
||||
{createMessagePair}
|
||||
onChange={(input) => {
|
||||
if (input.prompt !== null) {
|
||||
localStorage.setItem(
|
||||
`chat-input${$chatId ? `-${$chatId}` : ''}`,
|
||||
JSON.stringify(input)
|
||||
);
|
||||
} else {
|
||||
localStorage.removeItem(`chat-input${$chatId ? `-${$chatId}` : ''}`);
|
||||
}
|
||||
}}
|
||||
on:upload={async (e) => {
|
||||
const { type, data } = e.detail;
|
||||
|
||||
if (type === 'web') {
|
||||
await uploadWeb(data);
|
||||
} else if (type === 'youtube') {
|
||||
await uploadYoutubeTranscription(data);
|
||||
} else if (type === 'google-drive') {
|
||||
await uploadGoogleDriveFile(data);
|
||||
}
|
||||
}}
|
||||
on:submit={async (e) => {
|
||||
if (e.detail || files.length > 0) {
|
||||
await tick();
|
||||
submitPrompt(
|
||||
($settings?.richTextInput ?? true)
|
||||
? e.detail.replaceAll('\n\n', '\n')
|
||||
: e.detail
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
class="absolute bottom-1 text-xs text-gray-500 text-center line-clamp-1 right-0 left-0"
|
||||
>
|
||||
<!-- {$i18n.t('LLMs can make mistakes. Verify important information.')} -->
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="overflow-auto w-full h-full flex items-center">
|
||||
<Placeholder
|
||||
{history}
|
||||
{selectedModels}
|
||||
bind:files
|
||||
bind:prompt
|
||||
bind:autoScroll
|
||||
bind:selectedToolIds
|
||||
bind:selectedFilterIds
|
||||
bind:imageGenerationEnabled
|
||||
bind:codeInterpreterEnabled
|
||||
bind:webSearchEnabled
|
||||
bind:atSelectedModel
|
||||
transparentBackground={$settings?.backgroundImageUrl ?? false}
|
||||
toolServers={$toolServers}
|
||||
{stopResponse}
|
||||
{createMessagePair}
|
||||
on:upload={async (e) => {
|
||||
const { type, data } = e.detail;
|
||||
|
||||
if (type === 'web') {
|
||||
await uploadWeb(data);
|
||||
} else if (type === 'youtube') {
|
||||
await uploadYoutubeTranscription(data);
|
||||
}
|
||||
}}
|
||||
on:submit={async (e) => {
|
||||
if (e.detail || files.length > 0) {
|
||||
await tick();
|
||||
submitPrompt(
|
||||
($settings?.richTextInput ?? true)
|
||||
? e.detail.replaceAll('\n\n', '\n')
|
||||
: e.detail
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Pane>
|
||||
|
||||
<div class=" pb-[1rem]">
|
||||
<MessageInput
|
||||
{history}
|
||||
{taskIds}
|
||||
{selectedModels}
|
||||
bind:files
|
||||
bind:prompt
|
||||
bind:autoScroll
|
||||
bind:selectedToolIds
|
||||
bind:selectedFilterIds
|
||||
bind:imageGenerationEnabled
|
||||
bind:codeInterpreterEnabled
|
||||
bind:webSearchEnabled
|
||||
bind:atSelectedModel
|
||||
toolServers={$toolServers}
|
||||
transparentBackground={$settings?.backgroundImageUrl ?? false}
|
||||
{stopResponse}
|
||||
{createMessagePair}
|
||||
onChange={(input) => {
|
||||
if (input.prompt !== null) {
|
||||
localStorage.setItem(
|
||||
`chat-input${$chatId ? `-${$chatId}` : ''}`,
|
||||
JSON.stringify(input)
|
||||
);
|
||||
} else {
|
||||
localStorage.removeItem(`chat-input${$chatId ? `-${$chatId}` : ''}`);
|
||||
}
|
||||
}}
|
||||
on:upload={async (e) => {
|
||||
const { type, data } = e.detail;
|
||||
|
||||
if (type === 'web') {
|
||||
await uploadWeb(data);
|
||||
} else if (type === 'youtube') {
|
||||
await uploadYoutubeTranscription(data);
|
||||
} else if (type === 'google-drive') {
|
||||
await uploadGoogleDriveFile(data);
|
||||
}
|
||||
}}
|
||||
on:submit={async (e) => {
|
||||
if (e.detail || files.length > 0) {
|
||||
await tick();
|
||||
submitPrompt(
|
||||
($settings?.richTextInput ?? true)
|
||||
? e.detail.replaceAll('\n\n', '\n')
|
||||
: e.detail
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
class="absolute bottom-1 text-xs text-gray-500 text-center line-clamp-1 right-0 left-0"
|
||||
>
|
||||
<!-- {$i18n.t('LLMs can make mistakes. Verify important information.')} -->
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="overflow-auto w-full h-full flex items-center">
|
||||
<Placeholder
|
||||
{history}
|
||||
{selectedModels}
|
||||
bind:files
|
||||
bind:prompt
|
||||
bind:autoScroll
|
||||
bind:selectedToolIds
|
||||
bind:selectedFilterIds
|
||||
bind:imageGenerationEnabled
|
||||
bind:codeInterpreterEnabled
|
||||
bind:webSearchEnabled
|
||||
bind:atSelectedModel
|
||||
transparentBackground={$settings?.backgroundImageUrl ?? false}
|
||||
toolServers={$toolServers}
|
||||
{stopResponse}
|
||||
{createMessagePair}
|
||||
on:upload={async (e) => {
|
||||
const { type, data } = e.detail;
|
||||
|
||||
if (type === 'web') {
|
||||
await uploadWeb(data);
|
||||
} else if (type === 'youtube') {
|
||||
await uploadYoutubeTranscription(data);
|
||||
}
|
||||
}}
|
||||
on:submit={async (e) => {
|
||||
if (e.detail || files.length > 0) {
|
||||
await tick();
|
||||
submitPrompt(
|
||||
($settings?.richTextInput ?? true)
|
||||
? e.detail.replaceAll('\n\n', '\n')
|
||||
: e.detail
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Pane>
|
||||
|
||||
<ChatControls
|
||||
bind:this={controlPaneComponent}
|
||||
bind:history
|
||||
bind:chatFiles
|
||||
bind:params
|
||||
bind:files
|
||||
bind:pane={controlPane}
|
||||
chatId={$chatId}
|
||||
modelId={selectedModelIds?.at(0) ?? null}
|
||||
models={selectedModelIds.reduce((a, e, i, arr) => {
|
||||
const model = $models.find((m) => m.id === e);
|
||||
if (model) {
|
||||
return [...a, model];
|
||||
}
|
||||
return a;
|
||||
}, [])}
|
||||
{submitPrompt}
|
||||
{stopResponse}
|
||||
{showMessage}
|
||||
{eventTarget}
|
||||
/>
|
||||
</PaneGroup>
|
||||
<ChatControls
|
||||
bind:this={controlPaneComponent}
|
||||
bind:history
|
||||
bind:chatFiles
|
||||
bind:params
|
||||
bind:files
|
||||
bind:pane={controlPane}
|
||||
chatId={$chatId}
|
||||
modelId={selectedModelIds?.at(0) ?? null}
|
||||
models={selectedModelIds.reduce((a, e, i, arr) => {
|
||||
const model = $models.find((m) => m.id === e);
|
||||
if (model) {
|
||||
return [...a, model];
|
||||
}
|
||||
return a;
|
||||
}, [])}
|
||||
{submitPrompt}
|
||||
{stopResponse}
|
||||
{showMessage}
|
||||
{eventTarget}
|
||||
/>
|
||||
</PaneGroup>
|
||||
</div>
|
||||
{:else if loading}
|
||||
<div class=" flex items-center justify-center h-full w-full">
|
||||
<div class="m-auto">
|
||||
|
Loading…
Reference in New Issue
Block a user