{#if loaded}
{#if autoScroll === false && history?.currentId}
{/if}
{ if (inputFiles && inputFiles.length > 0) { const _inputFiles = Array.from(inputFiles); inputFilesHandler(_inputFiles); } else { toast.error($i18n.t(`File not found.`)); } filesInputElement.value = ''; }} /> {#if recording} { recording = false; await tick(); document.getElementById('chat-input')?.focus(); }} onConfirm={async (data) => { const { text, filename } = data; recording = false; await tick(); insertTextAtCursor(text); await tick(); document.getElementById('chat-input')?.focus(); if ($settings?.speechAutoSend ?? false) { dispatch('submit', prompt); } }} /> {:else}
{ // check if selectedModels support image input dispatch('submit', prompt); }} >
{#if atSelectedModel !== undefined}
model profile model.id === atSelectedModel.id)?.info?.meta ?.profile_image_url ?? ($i18n.language === 'dg-DG' ? `${WEBUI_BASE_URL}/doge.png` : `${WEBUI_BASE_URL}/static/favicon.png`)} />
{atSelectedModel.name}
{/if} {#if files.length > 0}
{#each files as file, fileIdx} {#if file.type === 'image'}
{#if atSelectedModel ? visionCapableModels.length === 0 : selectedModels.length !== visionCapableModels.length} !visionCapableModels.includes(id)) .join(', ') })} > {/if}
{:else} { // Remove from UI state files.splice(fileIdx, 1); files = files; }} on:click={() => { console.log(file); }} /> {/if} {/each}
{/if}
{#if suggestions} {#key $settings?.richTextInput ?? true} {#key $settings?.showFormattingToolbar ?? false} { prompt = e.md; command = getCommand(); }} json={true} richText={$settings?.richTextInput ?? true} messageInput={true} showFormattingToolbar={$settings?.showFormattingToolbar ?? false} floatingMenuPlacement={'top-start'} insertPromptAsRichText={$settings?.insertPromptAsRichText ?? false} shiftEnter={!($settings?.ctrlEnterToSend ?? false) && (!$mobile || !( 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0 ))} placeholder={placeholder ? placeholder : $i18n.t('Send a Message')} largeTextAsFile={($settings?.largeTextAsFile ?? false) && !shiftKey} autocomplete={$config?.features?.enable_autocomplete_generation && ($settings?.promptAutocomplete ?? false)} generateAutoCompletion={async (text) => { if (selectedModelIds.length === 0 || !selectedModelIds.at(0)) { toast.error($i18n.t('Please select a model first.')); } const res = await generateAutoCompletion( localStorage.token, selectedModelIds.at(0), text, history?.currentId ? createMessagesList(history, history.currentId) : null ).catch((error) => { console.log(error); return null; }); console.log(res); return res; }} {suggestions} oncompositionstart={() => (isComposing = true)} oncompositionend={(e) => { compositionEndedAt = e.timeStamp; isComposing = false; }} on:keydown={async (e) => { e = e.detail.event; const isCtrlPressed = e.ctrlKey || e.metaKey; // metaKey is for Cmd key on Mac const suggestionsContainerElement = document.getElementById('suggestions-container'); if (e.key === 'Escape') { stopResponse(); } // Command/Ctrl + Shift + Enter to submit a message pair if (isCtrlPressed && e.key === 'Enter' && e.shiftKey) { e.preventDefault(); createMessagePair(prompt); } // Check if Ctrl + R is pressed if (prompt === '' && isCtrlPressed && e.key.toLowerCase() === 'r') { e.preventDefault(); console.log('regenerate'); const regenerateButton = [ ...document.getElementsByClassName('regenerate-response-button') ]?.at(-1); regenerateButton?.click(); } if (prompt === '' && e.key == 'ArrowUp') { e.preventDefault(); const userMessageElement = [ ...document.getElementsByClassName('user-message') ]?.at(-1); if (userMessageElement) { userMessageElement.scrollIntoView({ block: 'center' }); const editButton = [ ...document.getElementsByClassName('edit-user-message-button') ]?.at(-1); editButton?.click(); } } if (!suggestionsContainerElement) { if ( !$mobile || !( 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0 ) ) { if (inOrNearComposition(e)) { return; } // Uses keyCode '13' for Enter key for chinese/japanese keyboards. // // Depending on the user's settings, it will send the message // either when Enter is pressed or when Ctrl+Enter is pressed. const enterPressed = ($settings?.ctrlEnterToSend ?? false) ? (e.key === 'Enter' || e.keyCode === 13) && isCtrlPressed : (e.key === 'Enter' || e.keyCode === 13) && !e.shiftKey; if (enterPressed) { e.preventDefault(); if (prompt !== '' || files.length > 0) { dispatch('submit', prompt); } } } } if (e.key === 'Escape') { console.log('Escape'); atSelectedModel = undefined; selectedToolIds = []; selectedFilterIds = []; webSearchEnabled = false; imageGenerationEnabled = false; codeInterpreterEnabled = false; } }} on:paste={async (e) => { e = e.detail.event; console.log(e); const clipboardData = e.clipboardData || window.clipboardData; if (clipboardData && clipboardData.items) { for (const item of clipboardData.items) { if (item.type.indexOf('image') !== -1) { const blob = item.getAsFile(); const reader = new FileReader(); reader.onload = function (e) { files = [ ...files, { type: 'image', url: `${e.target.result}` } ]; }; reader.readAsDataURL(blob); } else if (item?.kind === 'file') { const file = item.getAsFile(); if (file) { const _files = [file]; await inputFilesHandler(_files); e.preventDefault(); } } else if (item.type === 'text/plain') { if (($settings?.largeTextAsFile ?? false) && !shiftKey) { const text = clipboardData.getData('text/plain'); if (text.length > PASTED_TEXT_CHARACTER_LIMIT) { e.preventDefault(); const blob = new Blob([text], { type: 'text/plain' }); const file = new File( [blob], `Pasted_Text_${Date.now()}.txt`, { type: 'text/plain' } ); await uploadFileHandler(file, true); } } } } } }} /> {/key} {/key} {/if}
{ filesInputElement.click(); }} uploadGoogleDriveHandler={async () => { try { const fileData = await createPicker(); if (fileData) { const file = new File([fileData.blob], fileData.name, { type: fileData.blob.type }); await uploadFileHandler(file); } else { console.log('No file was selected from Google Drive'); } } catch (error) { console.error('Google Drive Error:', error); toast.error( $i18n.t('Error accessing Google Drive: {{error}}', { error: error.message }) ); } }} uploadOneDriveHandler={async (authorityType) => { try { const fileData = await pickAndDownloadFile(authorityType); if (fileData) { const file = new File([fileData.blob], fileData.name, { type: fileData.blob.type || 'application/octet-stream' }); await uploadFileHandler(file); } else { console.log('No file was selected from OneDrive'); } } catch (error) { console.error('OneDrive Error:', error); } }} onUpload={async (e) => { dispatch('upload', e); }} onClose={async () => { await tick(); const chatInput = document.getElementById('chat-input'); chatInput?.focus(); }} >
{#if showWebSearchButton || showImageGenerationButton || showCodeInterpreterButton || showToolsButton || (toggleFilters && toggleFilters.length > 0)} { await tick(); const chatInput = document.getElementById('chat-input'); chatInput?.focus(); }} >
{/if}
{#if (selectedToolIds ?? []).length > 0} {/if} {#each selectedFilterIds as filterId} {@const filter = toggleFilters.find((f) => f.id === filterId)} {#if filter} {/if} {/each} {#if webSearchEnabled} {/if} {#if imageGenerationEnabled} {/if} {#if codeInterpreterEnabled} {/if}
{#if (!history?.currentId || history.messages[history.currentId]?.done == true) && ($_user?.role === 'admin' || ($_user?.permissions?.chat?.stt ?? true))} {/if} {#if (taskIds && taskIds.length > 0) || (history.currentId && history.messages[history.currentId]?.done != true) || generating}
{:else if prompt === '' && files.length === 0 && ($_user?.role === 'admin' || ($_user?.permissions?.chat?.call ?? true))}
{:else}
{/if}
{#if $config?.license_metadata?.input_footer}
{@html DOMPurify.sanitize(marked($config?.license_metadata?.input_footer))}
{:else}
{/if} {/if}
{/if}