- {#if $settings?.backgroundImageUrl ?? null}
+ {#if $settings?.backgroundImageUrl ?? $config?.license_metadata?.background_image_url ?? null}
- {#if $settings?.landingPageMode === 'chat' || createMessagesList(history, history.currentId).length > 0}
+
+ {#if ($settings?.landingPageMode === 'chat' && !$selectedFolder) || createMessagesList(history, history.currentId).length > 0}
{
+ messageInput?.setText(text);
+ }}
{selectedModels}
{atSelectedModel}
{sendPrompt}
@@ -2156,7 +2168,9 @@
bind:atSelectedModel
bind:showCommands
toolServers={$toolServers}
- transparentBackground={$settings?.backgroundImageUrl ?? false}
+ transparentBackground={$settings?.backgroundImageUrl ??
+ $config?.license_metadata?.background_image_url ??
+ false}
{stopResponse}
{createMessagePair}
onChange={(input) => {
@@ -2201,7 +2215,7 @@
{:else}
-
+
{};
+
export let sendPrompt: Function;
export let continueResponse: Function;
export let regenerateResponse: Function;
@@ -426,6 +428,7 @@
messageId={message.id}
idx={messageIdx}
{user}
+ {setInputText}
{gotoMessage}
{showPreviousMessage}
{showNextMessage}
diff --git a/src/lib/components/chat/Messages/ContentRenderer.svelte b/src/lib/components/chat/Messages/ContentRenderer.svelte
index 613c1670a0..54cd2a5aab 100644
--- a/src/lib/components/chat/Messages/ContentRenderer.svelte
+++ b/src/lib/components/chat/Messages/ContentRenderer.svelte
@@ -20,6 +20,7 @@
export let history;
export let selectedModels = [];
+ export let done = true;
export let model = null;
export let sources = null;
@@ -133,6 +134,7 @@
{model}
{save}
{preview}
+ {done}
sourceIds={(sources ?? []).reduce((acc, s) => {
let ids = [];
s.document.forEach((document, index) => {
diff --git a/src/lib/components/chat/Messages/Markdown.svelte b/src/lib/components/chat/Messages/Markdown.svelte
index 0130718334..96ec6e06ba 100644
--- a/src/lib/components/chat/Messages/Markdown.svelte
+++ b/src/lib/components/chat/Messages/Markdown.svelte
@@ -10,6 +10,7 @@
export let id = '';
export let content;
+ export let done = true;
export let model = null;
export let save = false;
export let preview = false;
@@ -47,6 +48,7 @@
{};
@@ -28,7 +31,7 @@
{:else if token.type === 'link'}
{#if token.tokens}
-
+
{:else}
{token.text}
@@ -40,15 +43,7 @@
{:else if token.type === 'em'}
{:else if token.type === 'codespan'}
-
-
- {
- copyToClipboard(unescapeHtml(token.text));
- toast.success($i18n.t('Copied to clipboard'));
- }}>{unescapeHtml(token.text)}
+
{:else if token.type === 'br'}
{:else if token.type === 'del'}
@@ -66,6 +61,6 @@
onload="this.style.height=(this.contentWindow.document.body.scrollHeight+20)+'px';"
>
{:else if token.type === 'text'}
- {token.raw}
+
{/if}
{/each}
diff --git a/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/CodespanToken.svelte b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/CodespanToken.svelte
new file mode 100644
index 0000000000..c0b1ec327c
--- /dev/null
+++ b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/CodespanToken.svelte
@@ -0,0 +1,33 @@
+
+
+
+
+{#if done}
+ {
+ copyToClipboard(unescapeHtml(token.text));
+ toast.success($i18n.t('Copied to clipboard'));
+ }}>{unescapeHtml(token.text)}
+{:else}
+ {
+ copyToClipboard(unescapeHtml(token.text));
+ toast.success($i18n.t('Copied to clipboard'));
+ }}>{unescapeHtml(token.text)}
+{/if}
diff --git a/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/TextToken.svelte b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/TextToken.svelte
new file mode 100644
index 0000000000..d5ae387afe
--- /dev/null
+++ b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/TextToken.svelte
@@ -0,0 +1,19 @@
+
+
+{#if done}
+ {token?.raw}
+{:else}
+ {#each texts as text}
+
+ {text}
+
+ {/each}
+{/if}
diff --git a/src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte b/src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte
index e989d408ed..70626a44d4 100644
--- a/src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte
+++ b/src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte
@@ -28,6 +28,8 @@
export let top = true;
export let attributes = {};
+ export let done = true;
+
export let save = false;
export let preview = false;
@@ -85,7 +87,12 @@
{:else if token.type === 'heading'}
-
+
{:else if token.type === 'code'}
{#if token.raw.includes('```')}
@@ -132,6 +139,7 @@
@@ -152,6 +160,7 @@
@@ -183,7 +192,13 @@
{:else}
-
+
{/if}
{:else if token.type === 'list'}
@@ -213,6 +228,7 @@
id={`${id}-${tokenIdx}-${itemIdx}`}
tokens={item.tokens}
top={token.loose}
+ {done}
{onTaskClick}
{onSourceClick}
/>
@@ -245,6 +261,7 @@
id={`${id}-${tokenIdx}-${itemIdx}`}
tokens={item.tokens}
top={token.loose}
+ {done}
{onTaskClick}
{onSourceClick}
/>
@@ -254,6 +271,7 @@
id={`${id}-${tokenIdx}-${itemIdx}`}
tokens={item.tokens}
top={token.loose}
+ {done}
{onTaskClick}
{onSourceClick}
/>
@@ -275,6 +293,7 @@
id={`${id}-${tokenIdx}-d`}
tokens={marked.lexer(token.text)}
attributes={token?.attributes}
+ {done}
{onTaskClick}
{onSourceClick}
/>
@@ -295,6 +314,7 @@
@@ -302,7 +322,12 @@
{#if top}
{#if token.tokens}
-
+
{:else}
{unescapeHtml(token.text)}
{/if}
@@ -311,6 +336,7 @@
{:else}
diff --git a/src/lib/components/chat/Messages/Message.svelte b/src/lib/components/chat/Messages/Message.svelte
index 8d7896ccb8..7dc7125598 100644
--- a/src/lib/components/chat/Messages/Message.svelte
+++ b/src/lib/components/chat/Messages/Message.svelte
@@ -21,6 +21,7 @@
export let user;
+ export let setInputText: Function = () => {};
export let gotoMessage;
export let showPreviousMessage;
export let showNextMessage;
@@ -74,6 +75,7 @@
{selectedModels}
isLastMessage={messageId === history.currentId}
siblings={history.messages[history.messages[messageId].parentId]?.childrenIds ?? []}
+ {setInputText}
{gotoMessage}
{showPreviousMessage}
{showNextMessage}
@@ -96,6 +98,7 @@
{messageId}
{selectedModels}
isLastMessage={messageId === history?.currentId}
+ {setInputText}
{updateChat}
{editMessage}
{saveMessage}
diff --git a/src/lib/components/chat/Messages/MultiResponseMessages.svelte b/src/lib/components/chat/Messages/MultiResponseMessages.svelte
index 52c430e4d8..3b3dd9b194 100644
--- a/src/lib/components/chat/Messages/MultiResponseMessages.svelte
+++ b/src/lib/components/chat/Messages/MultiResponseMessages.svelte
@@ -28,6 +28,7 @@
export let isLastMessage;
export let readOnly = false;
+ export let setInputText: Function = () => {};
export let updateChat: Function;
export let editMessage: Function;
export let saveMessage: Function;
@@ -259,6 +260,7 @@
gotoMessage={(message, messageIdx) => gotoMessage(modelIdx, messageIdx)}
showPreviousMessage={() => showPreviousMessage(modelIdx)}
showNextMessage={() => showNextMessage(modelIdx)}
+ {setInputText}
{updateChat}
{editMessage}
{saveMessage}
diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte
index 8d186df909..6924fc755c 100644
--- a/src/lib/components/chat/Messages/ResponseMessage.svelte
+++ b/src/lib/components/chat/Messages/ResponseMessage.svelte
@@ -117,6 +117,7 @@
export let siblings;
+ export let setInputText: Function = () => {};
export let gotoMessage: Function = () => {};
export let showPreviousMessage: Function;
export let showNextMessage: Function;
@@ -165,7 +166,7 @@
text = `${text}\n\n${$config?.ui?.response_watermark}`;
}
- const res = await _copyToClipboard(text, $settings?.copyFormatted ?? false);
+ const res = await _copyToClipboard(text, null, $settings?.copyFormatted ?? false);
if (res) {
toast.success($i18n.t('Copying to clipboard was successful!'));
}
@@ -804,6 +805,9 @@
floatingButtons={message?.done && !readOnly}
save={!readOnly}
preview={!readOnly}
+ done={($settings?.chatFadeStreamingText ?? true)
+ ? (message?.done ?? false)
+ : true}
{model}
onTaskClick={async (e) => {
console.log(e);
@@ -1461,12 +1465,18 @@
/>
{/if}
- {#if isLastMessage && message.done && !readOnly && (message?.followUps ?? []).length > 0}
+ {#if (isLastMessage || ($settings?.keepFollowUpPrompts ?? false)) && message.done && !readOnly && (message?.followUps ?? []).length > 0}
{
- submitMessage(message?.id, prompt);
+ if ($settings?.insertFollowUpPrompt ?? false) {
+ // Insert the follow-up prompt into the input box
+ setInputText(prompt);
+ } else {
+ // Submit the follow-up prompt directly
+ submitMessage(message?.id, prompt);
+ }
}}
/>
diff --git a/src/lib/components/chat/Placeholder.svelte b/src/lib/components/chat/Placeholder.svelte
index 5854b7f52f..5f9f1cb658 100644
--- a/src/lib/components/chat/Placeholder.svelte
+++ b/src/lib/components/chat/Placeholder.svelte
@@ -12,7 +12,9 @@
user,
models as _models,
temporaryChatEnabled,
- selectedFolder
+ selectedFolder,
+ chats,
+ currentChatPage
} from '$lib/stores';
import { sanitizeResponseContent, extractCurlyBraceWords } from '$lib/utils';
import { WEBUI_BASE_URL } from '$lib/constants';
@@ -21,9 +23,9 @@
import Tooltip from '$lib/components/common/Tooltip.svelte';
import EyeSlash from '$lib/components/icons/EyeSlash.svelte';
import MessageInput from './MessageInput.svelte';
- import FolderOpen from '../icons/FolderOpen.svelte';
- import XMark from '../icons/XMark.svelte';
- import Folder from '../icons/Folder.svelte';
+ import FolderPlaceholder from './Placeholder/FolderPlaceholder.svelte';
+ import FolderTitle from './Placeholder/FolderTitle.svelte';
+ import { getChatList } from '$lib/apis/chats';
const i18n = getContext('i18n');
@@ -87,29 +89,21 @@
>
{#if $selectedFolder}
-
-
-
-
-
+
{
+ selectedFolder.set(folder);
-
- {$selectedFolder?.name}
-
-
+ await chats.set(await getChatList(localStorage.token, $currentChatPage));
+ currentChatPage.set(1);
+ }}
+ onDelete={async () => {
+ await chats.set(await getChatList(localStorage.token, $currentChatPage));
+ currentChatPage.set(1);
-
-
-
-
+ selectedFolder.set(null);
+ }}
+ />
{:else}
-
-
-
+
+ {#if $selectedFolder}
+
+
-
+ {:else}
+
+ {/if}
diff --git a/src/lib/components/chat/Placeholder/ChatList.svelte b/src/lib/components/chat/Placeholder/ChatList.svelte
new file mode 100644
index 0000000000..1e48298ec5
--- /dev/null
+++ b/src/lib/components/chat/Placeholder/ChatList.svelte
@@ -0,0 +1,103 @@
+
+
+{#if chatList}
+
+ {#if chatList.length === 0}
+
+ {$i18n.t('No chats found')}
+
+ {/if}
+
+ {#each chatList as chat, idx (chat.id)}
+ {#if (idx === 0 || (idx > 0 && chat.time_range !== chatList[idx - 1].time_range)) && chat?.time_range}
+
+ {$i18n.t(chat.time_range)}
+
+
+ {/if}
+
+
(show = false)}
+ >
+
+ {chat?.title}
+
+
+
+
+ {dayjs(chat?.updated_at * 1000).calendar()}
+
+
+
+ {/each}
+
+
+
+{/if}
diff --git a/src/lib/components/chat/Placeholder/FolderKnowledge.svelte b/src/lib/components/chat/Placeholder/FolderKnowledge.svelte
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/lib/components/chat/Placeholder/FolderPlaceholder.svelte b/src/lib/components/chat/Placeholder/FolderPlaceholder.svelte
new file mode 100644
index 0000000000..057dd7018d
--- /dev/null
+++ b/src/lib/components/chat/Placeholder/FolderPlaceholder.svelte
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+ {#if selectedTab === 'knowledge'}
+
+ {:else if selectedTab === 'chats'}
+
+ {/if}
+
+
diff --git a/src/lib/components/chat/Placeholder/FolderTitle.svelte b/src/lib/components/chat/Placeholder/FolderTitle.svelte
new file mode 100644
index 0000000000..18f4bd0c96
--- /dev/null
+++ b/src/lib/components/chat/Placeholder/FolderTitle.svelte
@@ -0,0 +1,147 @@
+
+
+{#if folder}
+
+
+
{
+ deleteHandler();
+ }}
+ >
+
+ {@html DOMPurify.sanitize(
+ $i18n.t(
+ 'This will delete {{NAME}} and all its contents.',
+ {
+ NAME: folder.name
+ }
+ )
+ )}
+
+
+
+
+
+
+
+
+
+
+ {folder.name}
+
+
+
+
+ {
+ showFolderModal = true;
+ }}
+ onDelete={() => {
+ showDeleteConfirm = true;
+ }}
+ onExport={() => {
+ exportHandler();
+ }}
+ >
+
+
+
+
+{/if}
diff --git a/src/lib/components/chat/Settings/Interface.svelte b/src/lib/components/chat/Settings/Interface.svelte
index bf5ad3db9e..2b517471a9 100644
--- a/src/lib/components/chat/Settings/Interface.svelte
+++ b/src/lib/components/chat/Settings/Interface.svelte
@@ -43,12 +43,16 @@
let largeTextAsFile = false;
+ let keepFollowUpPrompts = false;
+ let insertFollowUpPrompt = false;
+
let landingPageMode = '';
let chatBubble = true;
let chatDirection: 'LTR' | 'RTL' | 'auto' = 'auto';
let ctrlEnterToSend = false;
let copyFormatted = false;
+ let chatFadeStreamingText = true;
let collapseCodeBlocks = false;
let expandDetails = false;
@@ -159,6 +163,11 @@
saveSettings({ imageCompression });
};
+ const toggleChatFadeStreamingText = async () => {
+ chatFadeStreamingText = !chatFadeStreamingText;
+ saveSettings({ chatFadeStreamingText: chatFadeStreamingText });
+ };
+
const toggleHapticFeedback = async () => {
hapticFeedback = !hapticFeedback;
saveSettings({ hapticFeedback: hapticFeedback });
@@ -224,6 +233,16 @@
saveSettings({ insertPromptAsRichText });
};
+ const toggleKeepFollowUpPrompts = async () => {
+ keepFollowUpPrompts = !keepFollowUpPrompts;
+ saveSettings({ keepFollowUpPrompts });
+ };
+
+ const toggleInsertFollowUpPrompt = async () => {
+ insertFollowUpPrompt = !insertFollowUpPrompt;
+ saveSettings({ insertFollowUpPrompt });
+ };
+
const toggleLargeTextAsFile = async () => {
largeTextAsFile = !largeTextAsFile;
saveSettings({ largeTextAsFile });
@@ -313,10 +332,15 @@
showEmojiInCall = $settings?.showEmojiInCall ?? false;
voiceInterruption = $settings?.voiceInterruption ?? false;
+ chatFadeStreamingText = $settings?.chatFadeStreamingText ?? true;
+
richTextInput = $settings?.richTextInput ?? true;
insertPromptAsRichText = $settings?.insertPromptAsRichText ?? false;
promptAutocomplete = $settings?.promptAutocomplete ?? false;
+ keepFollowUpPrompts = $settings?.keepFollowUpPrompts ?? false;
+ insertFollowUpPrompt = $settings?.insertFollowUpPrompt ?? false;
+
largeTextAsFile = $settings?.largeTextAsFile ?? false;
copyFormatted = $settings?.copyFormatted ?? false;
@@ -746,6 +770,75 @@