diff --git a/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte b/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte
index 9286aaed0..caded99ab 100644
--- a/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte
+++ b/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte
@@ -10,7 +10,7 @@
import { chatCompletion } from '$lib/apis/openai';
import ChatBubble from '$lib/components/icons/ChatBubble.svelte';
- import LightBlub from '$lib/components/icons/LightBlub.svelte';
+ import LightBulb from '$lib/components/icons/LightBulb.svelte';
import Markdown from '../Messages/Markdown.svelte';
import Skeleton from '../Messages/Skeleton.svelte';
@@ -44,7 +44,13 @@
toast.error('Model not selected');
return;
}
- prompt = `${floatingInputValue}\n\`\`\`\n${selectedText}\n\`\`\``;
+ prompt = [
+ // Blockquote each line of the selected text
+ ...selectedText.split('\n').map((line) => `> ${line}`),
+ '',
+ // Then your question
+ floatingInputValue
+ ].join('\n');
floatingInputValue = '';
responseContent = '';
@@ -121,8 +127,11 @@
toast.error('Model not selected');
return;
}
- const explainText = $i18n.t('Explain this section to me in more detail');
- prompt = `${explainText}\n\n\`\`\`\n${selectedText}\n\`\`\``;
+ const quotedText = selectedText
+ .split('\n')
+ .map((line) => `> ${line}`)
+ .join('\n');
+ prompt = `${quotedText}\n\nExplain`;
responseContent = '';
const [res, controller] = await chatCompletion(localStorage.token, {
@@ -256,7 +265,7 @@
explainHandler();
}}
>
-
+
{$i18n.t('Explain')}
diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte
index e1a5b1ea6..987355e3b 100644
--- a/src/lib/components/chat/MessageInput.svelte
+++ b/src/lib/components/chat/MessageInput.svelte
@@ -27,7 +27,6 @@
createMessagesList,
extractCurlyBraceWords
} from '$lib/utils';
- import { transcribeAudio } from '$lib/apis/audio';
import { uploadFile } from '$lib/apis/files';
import { generateAutoCompletion } from '$lib/apis';
import { deleteFileById } from '$lib/apis/files';
@@ -110,7 +109,9 @@
let commandsElement;
let inputFiles;
+
let dragged = false;
+ let shiftKey = false;
let user = null;
export let placeholder = '';
@@ -151,6 +152,30 @@
.map((id) => ($models.find((model) => model.id === id) || {})?.filters ?? [])
.reduce((acc, filters) => acc.filter((f1) => filters.some((f2) => f2.id === f1.id)));
+ let showToolsButton = false;
+ $: showToolsButton = toolServers.length + selectedToolIds.length > 0;
+
+ let showWebSearchButton = false;
+ $: showWebSearchButton =
+ (atSelectedModel?.id ? [atSelectedModel.id] : selectedModels).length ===
+ webSearchCapableModels.length &&
+ $config?.features?.enable_web_search &&
+ ($_user.role === 'admin' || $_user?.permissions?.features?.web_search);
+
+ let showImageGenerationButton = false;
+ $: showImageGenerationButton =
+ (atSelectedModel?.id ? [atSelectedModel.id] : selectedModels).length ===
+ imageGenerationCapableModels.length &&
+ $config?.features?.enable_image_generation &&
+ ($_user.role === 'admin' || $_user?.permissions?.features?.image_generation);
+
+ let showCodeInterpreterButton = false;
+ $: showCodeInterpreterButton =
+ (atSelectedModel?.id ? [atSelectedModel.id] : selectedModels).length ===
+ codeInterpreterCapableModels.length &&
+ $config?.features?.enable_code_interpreter &&
+ ($_user.role === 'admin' || $_user?.permissions?.features?.code_interpreter);
+
const scrollToBottom = () => {
const element = document.getElementById('messages-container');
element.scrollTo({
@@ -225,8 +250,19 @@
files = [...files, fileItem];
try {
+ // If the file is an audio file, provide the language for STT.
+ let metadata = null;
+ if (
+ (file.type.startsWith('audio/') || file.type.startsWith('video/')) &&
+ $settings?.audio?.stt?.language
+ ) {
+ metadata = {
+ language: $settings?.audio?.stt?.language
+ };
+ }
+
// During the file upload, file content is automatically extracted.
- const uploadedFile = await uploadFile(localStorage.token, file);
+ const uploadedFile = await uploadFile(localStorage.token, file, metadata);
if (uploadedFile) {
console.log('File upload completed:', {
@@ -318,13 +354,6 @@
});
};
- const handleKeyDown = (event: KeyboardEvent) => {
- if (event.key === 'Escape') {
- console.log('Escape');
- dragged = false;
- }
- };
-
const onDragOver = (e) => {
e.preventDefault();
@@ -355,6 +384,29 @@
dragged = false;
};
+ const onKeyDown = (e) => {
+ if (e.key === 'Shift') {
+ shiftKey = true;
+ }
+
+ if (e.key === 'Escape') {
+ console.log('Escape');
+ dragged = false;
+ }
+ };
+
+ const onKeyUp = (e) => {
+ if (e.key === 'Shift') {
+ shiftKey = false;
+ }
+ };
+
+ const onFocus = () => {};
+
+ const onBlur = () => {
+ shiftKey = false;
+ };
+
onMount(async () => {
loaded = true;
@@ -363,7 +415,11 @@
chatInput?.focus();
}, 0);
- window.addEventListener('keydown', handleKeyDown);
+ window.addEventListener('keydown', onKeyDown);
+ window.addEventListener('keyup', onKeyUp);
+
+ window.addEventListener('focus', onFocus);
+ window.addEventListener('blur', onBlur);
await tick();
@@ -376,7 +432,11 @@
onDestroy(() => {
console.log('destroy');
- window.removeEventListener('keydown', handleKeyDown);
+ window.removeEventListener('keydown', onKeyDown);
+ window.removeEventListener('keyup', onKeyUp);
+
+ window.removeEventListener('focus', onFocus);
+ window.removeEventListener('blur', onBlur);
const dropzoneElement = document.getElementById('chat-container');
@@ -641,7 +701,7 @@
{#if $settings?.richTextInput ?? true}
0
))}
placeholder={placeholder ? placeholder : $i18n.t('Send a Message')}
- largeTextAsFile={$settings?.largeTextAsFile ?? false}
+ largeTextAsFile={($settings?.largeTextAsFile ?? false) && !shiftKey}
autocomplete={$config?.features?.enable_autocomplete_generation &&
($settings?.promptAutocomplete ?? false)}
generateAutoCompletion={async (text) => {
@@ -839,7 +899,7 @@
reader.readAsDataURL(blob);
} else if (item.type === 'text/plain') {
- if ($settings?.largeTextAsFile ?? false) {
+ if (($settings?.largeTextAsFile ?? false) && !shiftKey) {
const text = clipboardData.getData('text/plain');
if (text.length > PASTED_TEXT_CHARACTER_LIMIT) {
@@ -1070,7 +1130,7 @@
reader.readAsDataURL(blob);
} else if (item.type === 'text/plain') {
- if ($settings?.largeTextAsFile ?? false) {
+ if (($settings?.largeTextAsFile ?? false) && !shiftKey) {
const text = clipboardData.getData('text/plain');
if (text.length > PASTED_TEXT_CHARACTER_LIMIT) {
@@ -1091,8 +1151,8 @@
{/if}
-
-
+
+
-
{#if (!history?.currentId || history.messages[history.currentId]?.done == true) && ($_user?.role === 'admin' || ($_user?.permissions?.chat?.stt ?? true))}
-
+
+
+ {#if document.metadata?.parameters}
+
+ {$i18n.t('Parameters')}
+
+ {JSON.stringify(
+ document.metadata.parameters,
+ null,
+ 2
+ )}
+ {/if}
{#if showRelevance}
{$i18n.t('Relevance')}
diff --git a/src/lib/components/chat/Messages/Markdown/AlertRenderer.svelte b/src/lib/components/chat/Messages/Markdown/AlertRenderer.svelte
index caf1410b1..ae00acb60 100644
--- a/src/lib/components/chat/Messages/Markdown/AlertRenderer.svelte
+++ b/src/lib/components/chat/Messages/Markdown/AlertRenderer.svelte
@@ -24,7 +24,7 @@
TIP: {
border: 'border-emerald-500',
text: 'text-emerald-500',
- icon: LightBlub
+ icon: LightBulb
},
IMPORTANT: {
border: 'border-purple-500',
@@ -65,7 +65,7 @@
- {
+ models.set(
+ await getModels(
+ localStorage.token,
+ $config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+ )
+ );
+ }}
+ type="button"
>
{#if selectedModel}
{selectedModel.label}
@@ -335,7 +364,7 @@
{placeholder}
{/if}
-
+
{item.label}
-
- {#if item.model.owned_by === 'ollama' && (item.model.ollama?.details?.parameter_size ?? '') !== ''}
-
-
- {item.model.ollama?.details?.parameter_size ?? ''}
-
-
- {/if}
+ {#if item.model.owned_by === 'ollama'}
+ {#if (item.model.ollama?.details?.parameter_size ?? '') !== ''}
+
+
+ {item.model.ollama?.details?.parameter_size ?? ''}
+
+
+ {/if}
+ {#if item.model.ollama?.expires_at && new Date(item.model.ollama?.expires_at * 1000) > new Date()}
+
+ {/if}
+ {/if}
+
{#if item.model?.direct}
-
+
- {:else if item.model.owned_by === 'openai'}
-
+ {:else if item.model.connection_type === 'external'}
+
- {#if value === item.value}
-
-
-
- {/if}
+
+ {#if $user?.role === 'admin' && item.model.owned_by === 'ollama' && item.model.ollama?.expires_at && new Date(item.model.ollama?.expires_at * 1000) > new Date()}
+
+ {
+ unloadModelHandler(item.value);
+ }}
+ >
+
+
+
+ {/if}
+
+ {#if value === item.value}
+
+
+
+ {/if}
+
{:else}
@@ -746,7 +811,7 @@
{#if showTemporaryChatControl}
-
+
{
diff --git a/src/lib/components/chat/Navbar.svelte b/src/lib/components/chat/Navbar.svelte
index 4687dd983..12cab4d6e 100644
--- a/src/lib/components/chat/Navbar.svelte
+++ b/src/lib/components/chat/Navbar.svelte
@@ -154,8 +154,9 @@
{#if $user !== undefined && $user !== null}
{
if (e.detail === 'archived-chat') {
showArchivedChats.set(true);
diff --git a/src/lib/components/chat/Placeholder.svelte b/src/lib/components/chat/Placeholder.svelte
index 1b21b4805..28bef5067 100644
--- a/src/lib/components/chat/Placeholder.svelte
+++ b/src/lib/components/chat/Placeholder.svelte
@@ -138,7 +138,7 @@
-
+
{#if models[selectedModelIdx]?.name}
{models[selectedModelIdx]?.name}
{:else}
@@ -221,7 +221,7 @@
-
+
- {$i18n.t('Logit Bias')}
+ {'logit_bias'}
-
-
-
-
- {$i18n.t('Mirostat')}
-
-
{
- params.mirostat = (params?.mirostat ?? null) === null ? 0 : null;
- }}
- >
- {#if (params?.mirostat ?? null) === null}
- {$i18n.t('Default')}
- {:else}
- {$i18n.t('Custom')}
- {/if}
-
-
-
-
- {#if (params?.mirostat ?? null) !== null}
-
- {/if}
-
-
- {$i18n.t('Mirostat Eta')}
+ {'max_tokens'}
+
{
- params.mirostat_eta = (params?.mirostat_eta ?? null) === null ? 0.1 : null;
+ params.max_tokens = (params?.max_tokens ?? null) === null ? 128 : null;
}}
>
- {#if (params?.mirostat_eta ?? null) === null}
+ {#if (params?.max_tokens ?? null) === null}
{$i18n.t('Default')}
{:else}
{$i18n.t('Custom')}
@@ -425,83 +373,26 @@
- {#if (params?.mirostat_eta ?? null) !== null}
+ {#if (params?.max_tokens ?? null) !== null}
- {/if}
-
-
-
-
-
-
- {$i18n.t('Mirostat Tau')}
-
-
-
{
- params.mirostat_tau = (params?.mirostat_tau ?? null) === null ? 5.0 : null;
- }}
- >
- {#if (params?.mirostat_tau ?? null) === null}
- {$i18n.t('Default')}
- {:else}
- {$i18n.t('Custom')}
- {/if}
-
-
-
-
- {#if (params?.mirostat_tau ?? null) !== null}
-
@@ -518,7 +409,7 @@
>
- {$i18n.t('Top K')}
+ {'top_k'}
- {$i18n.t('Top P')}
+ {'top_p'}
- {$i18n.t('Min P')}
+ {'min_p'}
- {$i18n.t('Frequency Penalty')}
+ {'frequency_penalty'}
- {$i18n.t('Presence Penalty')}
+ {'presence_penalty'}
+
+
+
+
+ {'mirostat'}
+
+
{
+ params.mirostat = (params?.mirostat ?? null) === null ? 0 : null;
+ }}
+ >
+ {#if (params?.mirostat ?? null) === null}
+ {$i18n.t('Default')}
+ {:else}
+ {$i18n.t('Custom')}
+ {/if}
+
+
+
+
+ {#if (params?.mirostat ?? null) !== null}
+
+ {/if}
+
+
+
+
+
+
+ {'mirostat_eta'}
+
+
{
+ params.mirostat_eta = (params?.mirostat_eta ?? null) === null ? 0.1 : null;
+ }}
+ >
+ {#if (params?.mirostat_eta ?? null) === null}
+ {$i18n.t('Default')}
+ {:else}
+ {$i18n.t('Custom')}
+ {/if}
+
+
+
+
+ {#if (params?.mirostat_eta ?? null) !== null}
+
+ {/if}
+
+
+
+
+
+
+ {'mirostat_tau'}
+
+
+
{
+ params.mirostat_tau = (params?.mirostat_tau ?? null) === null ? 5.0 : null;
+ }}
+ >
+ {#if (params?.mirostat_tau ?? null) === null}
+ {$i18n.t('Default')}
+ {:else}
+ {$i18n.t('Custom')}
+ {/if}
+
+
+
+
+ {#if (params?.mirostat_tau ?? null) !== null}
+
+ {/if}
+
+
- {$i18n.t('Repeat Last N')}
+ {'repeat_last_n'}
- {$i18n.t('Tfs Z')}
+ {'tfs_z'}
+
+
+
+
+ {'repeat_penalty'}
+
+
+
{
+ params.repeat_penalty = (params?.repeat_penalty ?? null) === null ? 1.1 : null;
+ }}
+ >
+ {#if (params?.repeat_penalty ?? null) === null}
+ {$i18n.t('Default')}
+ {:else}
+ {$i18n.t('Custom')}
+ {/if}
+
+
+
+
+ {#if (params?.repeat_penalty ?? null) !== null}
+
+ {/if}
+
+
+ {#if admin}
+
+
+
+
+ {'use_mmap'}
+
+
{
+ params.use_mmap = (params?.use_mmap ?? null) === null ? true : null;
+ }}
+ >
+ {#if (params?.use_mmap ?? null) === null}
+ {$i18n.t('Default')}
+ {:else}
+ {$i18n.t('Custom')}
+ {/if}
+
+
+
+
+ {#if (params?.use_mmap ?? null) !== null}
+
+
+ {params.use_mmap ? 'Enabled' : 'Disabled'}
+
+
+
+
+
+ {/if}
+
+
+
+
+
+
+ {'use_mlock'}
+
+
+
{
+ params.use_mlock = (params?.use_mlock ?? null) === null ? true : null;
+ }}
+ >
+ {#if (params?.use_mlock ?? null) === null}
+ {$i18n.t('Default')}
+ {:else}
+ {$i18n.t('Custom')}
+ {/if}
+
+
+
+
+ {#if (params?.use_mlock ?? null) !== null}
+
+
+ {params.use_mlock ? 'Enabled' : 'Disabled'}
+
+
+
+
+
+
+ {/if}
+
+ {/if}
+
- {$i18n.t('Tokens To Keep On Context Refresh (num_keep)')}
+ {'num_keep'} ({$i18n.t('Ollama')})
-
-
-
-
- {$i18n.t('Max Tokens (num_predict)')}
-
-
-
{
- params.max_tokens = (params?.max_tokens ?? null) === null ? 128 : null;
- }}
- >
- {#if (params?.max_tokens ?? null) === null}
- {$i18n.t('Default')}
- {:else}
- {$i18n.t('Custom')}
- {/if}
-
-
-
-
- {#if (params?.max_tokens ?? null) !== null}
-
- {/if}
-
-
-
-
-
-
- {$i18n.t('Repeat Penalty (Ollama)')}
-
-
-
{
- params.repeat_penalty = (params?.repeat_penalty ?? null) === null ? 1.1 : null;
- }}
- >
- {#if (params?.repeat_penalty ?? null) === null}
- {$i18n.t('Default')}
- {:else}
- {$i18n.t('Custom')}
- {/if}
-
-
-
-
- {#if (params?.repeat_penalty ?? null) !== null}
-
- {/if}
-
-
- {$i18n.t('Context Length')}
- {$i18n.t('(Ollama)')}
+ {'num_ctx'} ({$i18n.t('Ollama')})
- {$i18n.t('Batch Size (num_batch)')}
+ {'num_batch'} ({$i18n.t('Ollama')})
{#if admin}
-
-
-
-
- {$i18n.t('use_mmap (Ollama)')}
-
-
{
- params.use_mmap = (params?.use_mmap ?? null) === null ? true : null;
- }}
- >
- {#if (params?.use_mmap ?? null) === null}
- {$i18n.t('Default')}
- {:else}
- {$i18n.t('Custom')}
- {/if}
-
-
-
-
- {#if (params?.use_mmap ?? null) !== null}
-
-
- {params.use_mmap ? 'Enabled' : 'Disabled'}
-
-
-
-
-
- {/if}
-
-
-
-
-
-
- {$i18n.t('use_mlock (Ollama)')}
-
-
-
{
- params.use_mlock = (params?.use_mlock ?? null) === null ? true : null;
- }}
- >
- {#if (params?.use_mlock ?? null) === null}
- {$i18n.t('Default')}
- {:else}
- {$i18n.t('Custom')}
- {/if}
-
-
-
-
- {#if (params?.use_mlock ?? null) !== null}
-
-
- {params.use_mlock ? 'Enabled' : 'Disabled'}
-
-
-
-
-
-
- {/if}
-
-
- {$i18n.t('num_thread (Ollama)')}
+ {'num_thread'} ({$i18n.t('Ollama')})
- {$i18n.t('num_gpu (Ollama)')}
+ {'num_gpu'} ({$i18n.t('Ollama')})
{
if (TTSEngine === 'browser-kokoro') {
@@ -90,6 +91,7 @@
responseAutoPlayback = $settings.responseAutoPlayback ?? false;
STTEngine = $settings?.audio?.stt?.engine ?? '';
+ STTLanguage = $settings?.audio?.stt?.language ?? '';
TTSEngine = $settings?.audio?.tts?.engine ?? '';
TTSEngineConfig = $settings?.audio?.tts?.engineConfig ?? {};
@@ -157,7 +159,8 @@
saveSettings({
audio: {
stt: {
- engine: STTEngine !== '' ? STTEngine : undefined
+ engine: STTEngine !== '' ? STTEngine : undefined,
+ language: STTLanguage !== '' ? STTLanguage : undefined
},
tts: {
engine: TTSEngine !== '' ? TTSEngine : undefined,
@@ -190,6 +193,26 @@
+
+
+
{$i18n.t('Language')}
+
+
+
+
+
+
+
{/if}
@@ -270,15 +293,15 @@
{$i18n.t('Speech Playback Speed')}
-
-
+ class=" text-sm text-right bg-transparent dark:text-gray-300 outline-hidden"
+ />
+ x
@@ -293,7 +316,7 @@