+
+
+
)
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}
-
-
-
+ {/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}
-
-
-
+ {: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);
+ const res = await generateAutoCompletion(
+ localStorage.token,
+ selectedModelIds.at(0),
+ text,
+ history?.currentId
+ ? createMessagesList(history, history.currentId)
+ : null
+ ).catch((error) => {
+ console.log(error);
+
+ return null;
+ });
- 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;
- 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');
- const isCtrlPressed = e.ctrlKey || e.metaKey; // metaKey is for Cmd key on Mac
- const suggestionsContainerElement =
- document.getElementById('suggestions-container');
+ if (e.key === 'Escape') {
+ stopResponse();
+ }
- if (e.key === 'Escape') {
- stopResponse();
- }
+ if (prompt === '' && e.key == 'ArrowUp') {
+ e.preventDefault();
- if (prompt === '' && e.key == 'ArrowUp') {
- e.preventDefault();
+ const userMessageElement = [
+ ...document.getElementsByClassName('user-message')
+ ]?.at(-1);
- const userMessageElement = [
- ...document.getElementsByClassName('user-message')
+ if (userMessageElement) {
+ userMessageElement.scrollIntoView({ block: 'center' });
+ const editButton = [
+ ...document.getElementsByClassName('edit-user-message-button')
]?.at(-1);
- if (userMessageElement) {
- userMessageElement.scrollIntoView({ block: 'center' });
- const editButton = [
- ...document.getElementsByClassName('edit-user-message-button')
- ]?.at(-1);
+ editButton?.click();
+ }
+ }
- editButton?.click();
+ if (!suggestionsContainerElement) {
+ if (
+ !$mobile ||
+ !(
+ 'ontouchstart' in window ||
+ navigator.maxTouchPoints > 0 ||
+ navigator.msMaxTouchPoints > 0
+ )
+ ) {
+ if (inOrNearComposition(e)) {
+ return;
}
- }
- 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);
- }
+ // 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 = [];
+ 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);
+ webSearchEnabled = false;
+ imageGenerationEnabled = false;
+ codeInterpreterEnabled = false;
+ }
+ }}
+ on:paste={async (e) => {
+ e = e.detail.event;
+ console.log(e);
+
+ const clipboardData = e.clipboardData || window.clipboardData;
- 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();
- 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');
- reader.onload = function (e) {
- files = [
- ...files,
+ 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: 'image',
- url: `${e.target.result}`
+ type: 'text/plain'
}
- ];
- };
-
- 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);
- }
+ );
+
+ await uploadFileHandler(file, true);
}
}
}
}
- }}
- />
- {/key}
+ }
+ }}
+ />
{/key}
- {/if}
-
+ {/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
- })
- );
+
+
+
{
+ 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');
}
- }}
- 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);
+ } 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');
}
- }}
- onUpload={async (e) => {
- dispatch('upload', e);
+ } 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)}
+
+
+
{
+ const { type, id } = e;
+ selectedValvesType = type;
+ selectedValvesItemId = id;
+ showValvesModal = true;
+ integrationsMenuCloseOnOutsideClick = false;
}}
onClose={async () => {
await tick();
@@ -1436,376 +1473,334 @@
}}
>
-
+
+ {/if}
- {#if showWebSearchButton || showImageGenerationButton || showCodeInterpreterButton || showToolsButton || (toggleFilters && toggleFilters.length > 0)}
-
-
-
{
- const { type, id } = e;
- selectedValvesType = type;
- selectedValvesItemId = id;
- showValvesModal = true;
- integrationsMenuCloseOnOutsideClick = false;
- }}
- onClose={async () => {
- await tick();
-
- const chatInput = document.getElementById('chat-input');
- chatInput?.focus();
- }}
- >
-
+ {/if}
+
+
+ {#if (selectedToolIds ?? []).length > 0}
+
+
+
{/if}
-
- {#if (selectedToolIds ?? []).length > 0}
-
+ {#each selectedFilterIds as filterId}
+ {@const filter = toggleFilters.find((f) => f.id === filterId)}
+ {#if filter}
+
{
- showTools = !showTools;
+ on:click|preventDefault={() => {
+ selectedFilterIds = selectedFilterIds.filter((id) => id !== filterId);
}}
- >
-
-
-
- {selectedToolIds.length}
-
-
-
- {/if}
-
- {#each selectedFilterIds as filterId}
- {@const filter = toggleFilters.find((f) => f.id === filterId)}
- {#if filter}
-
- {
- selectedFilterIds = selectedFilterIds.filter(
- (id) => id !== filterId
- );
- }}
- type="button"
- class="group p-[7px] flex gap-1.5 items-center text-sm rounded-full transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden {selectedFilterIds.includes(
- filterId
- )
- ? 'text-sky-500 dark:text-sky-300 bg-sky-50 hover:bg-sky-100 dark:bg-sky-400/10 dark:hover:bg-sky-600/10 border border-sky-200/40 dark:border-sky-500/20'
- : 'bg-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 '} capitalize"
- >
- {#if filter?.icon}
-
-

-
- {:else}
-
- {/if}
-
-
-
-
-
- {/if}
- {/each}
-
- {#if webSearchEnabled}
-
- (webSearchEnabled = !webSearchEnabled)}
- type="button"
- class="group p-[7px] flex gap-1.5 items-center text-sm rounded-full transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden {webSearchEnabled ||
- ($settings?.webSearch ?? false) === 'always'
- ? ' text-sky-500 dark:text-sky-300 bg-sky-50 hover:bg-sky-100 dark:bg-sky-400/10 dark:hover:bg-sky-600/10 border border-sky-200/40 dark:border-sky-500/20'
- : 'bg-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 '}"
- >
-
-
-
-
-
-
- {/if}
-
- {#if imageGenerationEnabled}
-
-
- (imageGenerationEnabled = !imageGenerationEnabled)}
type="button"
- class="group p-[7px] flex gap-1.5 items-center text-sm rounded-full transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden {imageGenerationEnabled
- ? ' text-sky-500 dark:text-sky-300 bg-sky-50 hover:bg-sky-100 dark:bg-sky-400/10 dark:hover:bg-sky-700/10 border border-sky-200/40 dark:border-sky-500/20'
- : 'bg-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 '}"
+ class="group p-[7px] flex gap-1.5 items-center text-sm rounded-full transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden {selectedFilterIds.includes(
+ filterId
+ )
+ ? 'text-sky-500 dark:text-sky-300 bg-sky-50 hover:bg-sky-100 dark:bg-sky-400/10 dark:hover:bg-sky-600/10 border border-sky-200/40 dark:border-sky-500/20'
+ : 'bg-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 '} capitalize"
>
-
+ {#if filter?.icon}
+
+

+
+ {:else}
+
+ {/if}
{/if}
+ {/each}
- {#if codeInterpreterEnabled}
-
-
- (codeInterpreterEnabled = !codeInterpreterEnabled)}
- type="button"
- class=" group p-[7px] flex gap-1.5 items-center text-sm transition-colors duration-300 max-w-full overflow-hidden {codeInterpreterEnabled
- ? ' text-sky-500 dark:text-sky-300 bg-sky-50 hover:bg-sky-100 dark:bg-sky-400/10 dark:hover:bg-sky-700/10 border border-sky-200/40 dark:border-sky-500/20'
- : 'bg-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 '} {($settings?.highContrastMode ??
- false)
- ? 'm-1'
- : 'focus:outline-hidden rounded-full'}"
- >
-
+ {#if webSearchEnabled}
+
+ (webSearchEnabled = !webSearchEnabled)}
+ type="button"
+ class="group p-[7px] flex gap-1.5 items-center text-sm rounded-full transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden {webSearchEnabled ||
+ ($settings?.webSearch ?? false) === 'always'
+ ? ' text-sky-500 dark:text-sky-300 bg-sky-50 hover:bg-sky-100 dark:bg-sky-400/10 dark:hover:bg-sky-600/10 border border-sky-200/40 dark:border-sky-500/20'
+ : 'bg-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 '}"
+ >
+
+
+
+
+
+
+ {/if}
-
-
-
-
-
- {/if}
-
-
+ {#if imageGenerationEnabled}
+
+
+ (imageGenerationEnabled = !imageGenerationEnabled)}
+ type="button"
+ class="group p-[7px] flex gap-1.5 items-center text-sm rounded-full transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden {imageGenerationEnabled
+ ? ' text-sky-500 dark:text-sky-300 bg-sky-50 hover:bg-sky-100 dark:bg-sky-400/10 dark:hover:bg-sky-700/10 border border-sky-200/40 dark:border-sky-500/20'
+ : 'bg-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 '}"
+ >
+
+
+
+
+
+
+ {/if}
-
- {#if (!history?.currentId || history.messages[history.currentId]?.done == true) && ($_user?.role === 'admin' || ($_user?.permissions?.chat?.stt ?? true))}
-
-
+ {#if codeInterpreterEnabled}
+
+ (codeInterpreterEnabled = !codeInterpreterEnabled)}
type="button"
- on:click={async () => {
- try {
- let stream = await navigator.mediaDevices
- .getUserMedia({ audio: true })
- .catch(function (err) {
- toast.error(
- $i18n.t(
- `Permission denied when accessing microphone: {{error}}`,
- {
- error: err
- }
- )
- );
- return null;
- });
+ class=" group p-[7px] flex gap-1.5 items-center text-sm transition-colors duration-300 max-w-full overflow-hidden {codeInterpreterEnabled
+ ? ' text-sky-500 dark:text-sky-300 bg-sky-50 hover:bg-sky-100 dark:bg-sky-400/10 dark:hover:bg-sky-700/10 border border-sky-200/40 dark:border-sky-500/20'
+ : 'bg-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 '} {($settings?.highContrastMode ??
+ false)
+ ? 'm-1'
+ : 'focus:outline-hidden rounded-full'}"
+ >
+
- if (stream) {
- recording = true;
- const tracks = stream.getTracks();
- tracks.forEach((track) => track.stop());
- }
- stream = null;
- } catch {
- toast.error($i18n.t('Permission denied when accessing microphone'));
+
+
+
+
+
+ {/if}
+
+
+
+
+ {#if (!history?.currentId || history.messages[history.currentId]?.done == true) && ($_user?.role === 'admin' || ($_user?.permissions?.chat?.stt ?? true))}
+
+
+ {
+ try {
+ let stream = await navigator.mediaDevices
+ .getUserMedia({ audio: true })
+ .catch(function (err) {
+ toast.error(
+ $i18n.t(
+ `Permission denied when accessing microphone: {{error}}`,
+ {
+ error: err
+ }
+ )
+ );
+ return null;
+ });
+
+ if (stream) {
+ recording = true;
+ const tracks = stream.getTracks();
+ tracks.forEach((track) => track.stop());
}
+ stream = null;
+ } catch {
+ toast.error($i18n.t('Permission denied when accessing microphone'));
+ }
+ }}
+ aria-label="Voice Input"
+ >
+
+
+
+ {/if}
+
+ {#if (taskIds && taskIds.length > 0) || (history.currentId && history.messages[history.currentId]?.done != true) || generating}
+
+
+ {
+ stopResponse();
}}
- aria-label="Voice Input"
>
- {/if}
+
+ {:else if prompt === '' && files.length === 0 && ($_user?.role === 'admin' || ($_user?.permissions?.chat?.call ?? true))}
+
+
+
+ {
+ if (selectedModels.length > 1) {
+ toast.error($i18n.t('Select only one model to call'));
- {#if (taskIds && taskIds.length > 0) || (history.currentId && history.messages[history.currentId]?.done != true) || generating}
-
-
- {
- stopResponse();
- }}
- >
-
-
-
-
- {:else if prompt === '' && files.length === 0 && ($_user?.role === 'admin' || ($_user?.permissions?.chat?.call ?? true))}
-
-
-
- {
- if (selectedModels.length > 1) {
- toast.error($i18n.t('Select only one model to call'));
+ return;
+ }
- return;
- }
+ if ($config.audio.stt.engine === 'web') {
+ toast.error(
+ $i18n.t('Call feature is not supported when using Web STT engine')
+ );
- if ($config.audio.stt.engine === 'web') {
- toast.error(
- $i18n.t('Call feature is not supported when using Web STT engine')
- );
+ return;
+ }
+ // check if user has access to getUserMedia
+ try {
+ let stream = await navigator.mediaDevices.getUserMedia({
+ audio: true
+ });
+ // If the user grants the permission, proceed to show the call overlay
- return;
+ if (stream) {
+ const tracks = stream.getTracks();
+ tracks.forEach((track) => track.stop());
}
- // check if user has access to getUserMedia
- try {
- let stream = await navigator.mediaDevices.getUserMedia({
- audio: true
- });
- // If the user grants the permission, proceed to show the call overlay
-
- if (stream) {
- const tracks = stream.getTracks();
- tracks.forEach((track) => track.stop());
- }
- stream = null;
+ stream = null;
- if ($settings.audio?.tts?.engine === 'browser-kokoro') {
- // If the user has not initialized the TTS worker, initialize it
- if (!$TTSWorker) {
- await TTSWorker.set(
- new KokoroWorker({
- dtype: $settings.audio?.tts?.engineConfig?.dtype ?? 'fp32'
- })
- );
+ if ($settings.audio?.tts?.engine === 'browser-kokoro') {
+ // If the user has not initialized the TTS worker, initialize it
+ if (!$TTSWorker) {
+ await TTSWorker.set(
+ new KokoroWorker({
+ dtype: $settings.audio?.tts?.engineConfig?.dtype ?? 'fp32'
+ })
+ );
- await $TTSWorker.init();
- }
+ await $TTSWorker.init();
}
-
- showCallOverlay.set(true);
- showControls.set(true);
- } catch (err) {
- // If the user denies the permission or an error occurs, show an error message
- toast.error(
- $i18n.t('Permission denied when accessing media devices')
- );
}
- }}
- aria-label={$i18n.t('Voice mode')}
- >
-
-
-
-
- {:else}
-
-
-
+
+
+
+
+ {:else}
+
- {/if}
-
+
+
+
+
+
+ {/if}
+
- {#if $config?.license_metadata?.input_footer}
-
- {@html DOMPurify.sanitize(marked($config?.license_metadata?.input_footer))}
-
- {:else}
-
- {/if}
-
- {/if}
+ {#if $config?.license_metadata?.input_footer}
+
+ {@html DOMPurify.sanitize(marked($config?.license_metadata?.input_footer))}
+
+ {:else}
+
+ {/if}
+