+
- {$i18n.t('Default Prompt Suggestions')}
+ {$i18n.t('Banners')}
-
- {#each promptSuggestions as prompt, promptIdx}
-
-
-
-
+
+ {#each banners as banner, bannerIdx}
+
+
+
+
+
-
+
+
+
+
-
-
+
- {#if promptSuggestions.length > 0}
-
- {$i18n.t('Adjusting these settings will apply changes universally to all users.')}
+ {#if $user.role === 'admin'}
+
+
+
+ {$i18n.t('Default Prompt Suggestions')}
+
+
+
- {/if}
-
- {/if}
-
-
-
-
-
-
+
+ {#each promptSuggestions as prompt, promptIdx}
+
+
+
+
+
+ {/each}
+
+
+ {#if promptSuggestions.length > 0}
+
+ {$i18n.t('Adjusting these settings will apply changes universally to all users.')}
+
+ {/if}
+
+ {/if}
+
+
+
+
+
+
+{/if}
diff --git a/src/lib/components/admin/Settings/Models.svelte b/src/lib/components/admin/Settings/Models.svelte
index c807e87c78c..d1d6d2c79a1 100644
--- a/src/lib/components/admin/Settings/Models.svelte
+++ b/src/lib/components/admin/Settings/Models.svelte
@@ -24,6 +24,11 @@
import ModelEditor from '$lib/components/workspace/Models/ModelEditor.svelte';
import { toast } from 'svelte-sonner';
import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
+ import Cog6 from '$lib/components/icons/Cog6.svelte';
+ import ConfigureModelsModal from './Models/ConfigureModelsModal.svelte';
+ import Wrench from '$lib/components/icons/Wrench.svelte';
+ import ArrowDownTray from '$lib/components/icons/ArrowDownTray.svelte';
+ import ManageModelsModal from './Models/ManageModelsModal.svelte';
let importFiles;
let modelsImportInputElement: HTMLInputElement;
@@ -35,12 +40,21 @@
let filteredModels = [];
let selectedModelId = null;
- let showResetModal = false;
+
+ let showConfigModal = false;
+ let showManageModal = false;
$: if (models) {
- filteredModels = models.filter(
- (m) => searchValue === '' || m.name.toLowerCase().includes(searchValue.toLowerCase())
- );
+ filteredModels = models
+ .filter((m) => searchValue === '' || m.name.toLowerCase().includes(searchValue.toLowerCase()))
+ .sort((a, b) => {
+ // // Check if either model is inactive and push them to the bottom
+ // if ((a.is_active ?? true) !== (b.is_active ?? true)) {
+ // return (b.is_active ?? true) - (a.is_active ?? true);
+ // }
+ // If both models' active states are the same, sort alphabetically
+ return a.name.localeCompare(b.name);
+ });
}
let searchValue = '';
@@ -114,12 +128,11 @@
}).catch((error) => {
return null;
});
-
- await init();
} else {
await toggleModelById(localStorage.token, model.id);
}
+ // await init();
_models.set(await getModels(localStorage.token));
};
@@ -128,18 +141,8 @@
});
-
{
- const res = deleteAllModels(localStorage.token);
- if (res) {
- toast.success($i18n.t('All models deleted successfully'));
- init();
- }
- }}
-/>
+
+
{#if models !== null}
{#if selectedModelId === null}
@@ -153,18 +156,28 @@
>
-
-
+
+
+
+
+
+
@@ -186,7 +199,7 @@
{#if models.length > 0}
- {#each filteredModels as model (model.id)}
+ {#each filteredModels as model, modelIdx (model.id)}
+ import { toast } from 'svelte-sonner';
+
+ import { createEventDispatcher, getContext, onMount } from 'svelte';
+ const i18n = getContext('i18n');
+ const dispatch = createEventDispatcher();
+
+ import { models } from '$lib/stores';
+ import { deleteAllModels } from '$lib/apis/models';
+
+ import Modal from '$lib/components/common/Modal.svelte';
+ import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
+ import Tooltip from '$lib/components/common/Tooltip.svelte';
+ import ModelList from './ModelList.svelte';
+ import { getModelsConfig, setModelsConfig } from '$lib/apis/configs';
+ import Spinner from '$lib/components/common/Spinner.svelte';
+ import Minus from '$lib/components/icons/Minus.svelte';
+ import Plus from '$lib/components/icons/Plus.svelte';
+
+ export let show = false;
+ export let initHandler = () => {};
+
+ let config = null;
+
+ let selectedModelId = '';
+ let defaultModelIds = [];
+ let modelIds = [];
+
+ let loading = false;
+ let showResetModal = false;
+
+ $: if (show) {
+ init();
+ }
+
+ $: if (selectedModelId) {
+ onModelSelect();
+ }
+
+ const onModelSelect = () => {
+ if (selectedModelId === '') {
+ return;
+ }
+
+ if (defaultModelIds.includes(selectedModelId)) {
+ selectedModelId = '';
+ return;
+ }
+
+ defaultModelIds = [...defaultModelIds, selectedModelId];
+ selectedModelId = '';
+ };
+
+ const init = async () => {
+ config = await getModelsConfig(localStorage.token);
+
+ if (config?.DEFAULT_MODELS) {
+ defaultModelIds = (config?.DEFAULT_MODELS).split(',').filter((id) => id);
+ } else {
+ defaultModelIds = [];
+ }
+ const modelOrderList = config.MODEL_ORDER_LIST || [];
+ const allModelIds = $models.map((model) => model.id);
+
+ // Create a Set for quick lookup of ordered IDs
+ const orderedSet = new Set(modelOrderList);
+
+ modelIds = [
+ // Add all IDs from MODEL_ORDER_LIST that exist in allModelIds
+ ...modelOrderList.filter((id) => orderedSet.has(id) && allModelIds.includes(id)),
+ // Add remaining IDs not in MODEL_ORDER_LIST, sorted alphabetically
+ ...allModelIds.filter((id) => !orderedSet.has(id)).sort((a, b) => a.localeCompare(b))
+ ];
+ };
+ const submitHandler = async () => {
+ loading = true;
+
+ const res = await setModelsConfig(localStorage.token, {
+ DEFAULT_MODELS: defaultModelIds.join(','),
+ MODEL_ORDER_LIST: modelIds
+ });
+
+ if (res) {
+ toast.success($i18n.t('Models configuration saved successfully'));
+ initHandler();
+ show = false;
+ } else {
+ toast.error($i18n.t('Failed to save models configuration'));
+ }
+
+ loading = false;
+ };
+
+ onMount(async () => {
+ init();
+ });
+
+
+
{
+ const res = deleteAllModels(localStorage.token);
+ if (res) {
+ toast.success($i18n.t('All models deleted successfully'));
+ initHandler();
+ }
+ }}
+/>
+
+
+
+
+
+ {$i18n.t('Settings')}
+
+
+
+
+
+
+ {#if config}
+
+ {:else}
+
+
+
+ {/if}
+
+
+
+
diff --git a/src/lib/components/admin/Settings/Models/Manage/ManageMultipleOllama.svelte b/src/lib/components/admin/Settings/Models/Manage/ManageMultipleOllama.svelte
new file mode 100644
index 00000000000..04cabdd9a43
--- /dev/null
+++ b/src/lib/components/admin/Settings/Models/Manage/ManageMultipleOllama.svelte
@@ -0,0 +1,26 @@
+
+
+{#if ollamaConfig}
+
+
+
+
+
+{/if}
diff --git a/src/lib/components/admin/Settings/Models/Manage/ManageOllama.svelte b/src/lib/components/admin/Settings/Models/Manage/ManageOllama.svelte
new file mode 100644
index 00000000000..3420b669d14
--- /dev/null
+++ b/src/lib/components/admin/Settings/Models/Manage/ManageOllama.svelte
@@ -0,0 +1,1042 @@
+
+
+ {
+ deleteModelHandler();
+ }}
+/>
+
+{#if !loading}
+
+
+
+
+
+
+ {$i18n.t('Pull a model from Ollama.com')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {$i18n.t('To access the available model names for downloading,')}
+
{$i18n.t('click here.')}
+
+
+ {#if updateModelId}
+
+ Updating "{updateModelId}" {updateProgress ? `(${updateProgress}%)` : ''}
+
+ {/if}
+
+ {#if Object.keys($MODEL_DOWNLOAD_POOL).length > 0}
+ {#each Object.keys($MODEL_DOWNLOAD_POOL) as model}
+ {#if 'pullProgress' in $MODEL_DOWNLOAD_POOL[model]}
+
+
{model}
+
+
+
+
+ {$MODEL_DOWNLOAD_POOL[model].pullProgress ?? 0}%
+
+
+
+
+
+
+
+ {#if 'digest' in $MODEL_DOWNLOAD_POOL[model]}
+
+ {$MODEL_DOWNLOAD_POOL[model].digest}
+
+ {/if}
+
+
+ {/if}
+ {/each}
+ {/if}
+
+
+
+
{$i18n.t('Delete a model')}
+
+
+
+
+
+
+
+
+
+
{$i18n.t('Create a model')}
+
+
+
+
+
+
+
+
+
+
+
+
+ {#if createModelDigest !== ''}
+
+
{createModelTag}
+
+
+
+
+ {createModelPullProgress ?? 0}%
+
+
+
+ {#if createModelDigest}
+
+ {createModelDigest}
+
+ {/if}
+
+
+ {/if}
+
+
+
+
+
{$i18n.t('Experimental')}
+
+
+
+
+ {#if showExperimentalOllama}
+
+ {/if}
+
+
+
+{:else if ollamaModels === null}
+
+ {$i18n.t('Failed to fetch models')}
+
+{:else}
+
+
+
+{/if}
diff --git a/src/lib/components/admin/Settings/Models/ManageModelsModal.svelte b/src/lib/components/admin/Settings/Models/ManageModelsModal.svelte
new file mode 100644
index 00000000000..6b53952e157
--- /dev/null
+++ b/src/lib/components/admin/Settings/Models/ManageModelsModal.svelte
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+ {$i18n.t('Manage Models')}
+
+
+
+
+
+
+ {#if selected === ''}
+
+
+ {$i18n.t('No inference engine with management support found')}
+
+
+ {:else if selected !== null}
+
+
+
+
+
+
+
+
+ {#if selected === 'ollama'}
+
+ {/if}
+
+
+ {:else}
+
+
+
+ {/if}
+
+
+
+
diff --git a/src/lib/components/admin/Settings/Models/ModelList.svelte b/src/lib/components/admin/Settings/Models/ModelList.svelte
new file mode 100644
index 00000000000..c54d19ee443
--- /dev/null
+++ b/src/lib/components/admin/Settings/Models/ModelList.svelte
@@ -0,0 +1,58 @@
+
+
+{#if modelIds.length > 0}
+
+ {#each modelIds as modelId, modelIdx (modelId)}
+
+
+
+
+
+
+ {#if $models.find((model) => model.id === modelId)}
+ {$models.find((model) => model.id === modelId).name}
+ {:else}
+ {modelId}
+ {/if}
+
+
+
+
+ {/each}
+
+{:else}
+
+ {$i18n.t('No models found')}
+
+{/if}
diff --git a/src/lib/components/admin/Settings/Pipelines.svelte b/src/lib/components/admin/Settings/Pipelines.svelte
index fb229d9ff0b..e296d9bbc16 100644
--- a/src/lib/components/admin/Settings/Pipelines.svelte
+++ b/src/lib/components/admin/Settings/Pipelines.svelte
@@ -57,7 +57,7 @@
valves,
selectedPipelinesUrlIdx
).catch((error) => {
- toast.error(error);
+ toast.error(`${error}`);
});
if (res) {
@@ -118,7 +118,7 @@
pipelineDownloadUrl,
selectedPipelinesUrlIdx
).catch((error) => {
- toast.error(error);
+ toast.error(`${error}`);
return null;
});
@@ -157,7 +157,7 @@
}
pipelineFiles = null;
- const pipelineUploadInputElement = document.getElementById('pipeline-upload-input');
+ const pipelineUploadInputElement = document.getElementById('pipelines-upload-input');
if (pipelineUploadInputElement) {
pipelineUploadInputElement.value = null;
@@ -172,7 +172,7 @@
pipelines[selectedPipelineIdx].id,
selectedPipelinesUrlIdx
).catch((error) => {
- toast.error(error);
+ toast.error(`${error}`);
return null;
});
diff --git a/src/lib/components/admin/Settings/WebSearch.svelte b/src/lib/components/admin/Settings/WebSearch.svelte
index 7e12694cb7e..58eb09da35e 100644
--- a/src/lib/components/admin/Settings/WebSearch.svelte
+++ b/src/lib/components/admin/Settings/WebSearch.svelte
@@ -16,6 +16,8 @@
'searxng',
'google_pse',
'brave',
+ 'kagi',
+ 'mojeek',
'serpstack',
'serper',
'serply',
@@ -28,13 +30,15 @@
let youtubeLanguage = 'en';
let youtubeTranslation = null;
+ let youtubeProxyUrl = '';
const submitHandler = async () => {
const res = await updateRAGConfig(localStorage.token, {
web: webConfig,
youtube: {
language: youtubeLanguage.split(',').map((lang) => lang.trim()),
- translation: youtubeTranslation
+ translation: youtubeTranslation,
+ proxy_url: youtubeProxyUrl
}
});
};
@@ -47,6 +51,7 @@
youtubeLanguage = res.youtube.language.join(',');
youtubeTranslation = res.youtube.translation;
+ youtubeProxyUrl = res.youtube.proxy_url;
}
});
@@ -151,6 +156,28 @@
bind:value={webConfig.search.brave_search_api_key}
/>
+ {:else if webConfig.search.engine === 'kagi'}
+
+
+ {$i18n.t('Kagi Search API Key')}
+
+
+
+
+ {:else if webConfig.search.engine === 'mojeek'}
+
+
+ {$i18n.t('Mojeek Search API Key')}
+
+
+
+
{:else if webConfig.search.engine === 'serpstack'}
+
+
+
+
{$i18n.t('Proxy URL')}
+
+
+
+
+
{/if}
diff --git a/src/lib/components/admin/Users/Groups.svelte b/src/lib/components/admin/Users/Groups.svelte
index 5911718ba29..bbc7bab4461 100644
--- a/src/lib/components/admin/Users/Groups.svelte
+++ b/src/lib/components/admin/Users/Groups.svelte
@@ -53,10 +53,15 @@
tools: false
},
chat: {
+ controls: true,
file_upload: true,
delete: true,
edit: true,
temporary: true
+ },
+ features: {
+ web_search: true,
+ image_generation: true
}
};
@@ -69,7 +74,7 @@
const addGroupHandler = async (group) => {
const res = await createNewGroup(localStorage.token, group).catch((error) => {
- toast.error(error);
+ toast.error(`${error}`);
return null;
});
@@ -84,7 +89,7 @@
const res = await updateUserDefaultPermissions(localStorage.token, group.permissions).catch(
(error) => {
- toast.error(error);
+ toast.error(`${error}`);
return null;
}
);
diff --git a/src/lib/components/admin/Users/Groups/EditGroupModal.svelte b/src/lib/components/admin/Users/Groups/EditGroupModal.svelte
index 6d28db992a1..9558dbcad5a 100644
--- a/src/lib/components/admin/Users/Groups/EditGroupModal.svelte
+++ b/src/lib/components/admin/Users/Groups/EditGroupModal.svelte
@@ -37,10 +37,15 @@
tools: false
},
chat: {
+ controls: true,
file_upload: true,
delete: true,
edit: true,
temporary: true
+ },
+ features: {
+ web_search: true,
+ image_generation: true
}
};
export let userIds = [];
@@ -65,20 +70,8 @@
if (group) {
name = group.name;
description = group.description;
- permissions = group?.permissions ?? {
- workspace: {
- models: false,
- knowledge: false,
- prompts: false,
- tools: false
- },
- chat: {
- file_upload: true,
- delete: true,
- edit: true,
- temporary: true
- }
- };
+ permissions = group?.permissions ?? {};
+
userIds = group?.user_ids ?? [];
}
};
diff --git a/src/lib/components/admin/Users/Groups/GroupItem.svelte b/src/lib/components/admin/Users/Groups/GroupItem.svelte
index dd2b8c311f2..68586f4e52c 100644
--- a/src/lib/components/admin/Users/Groups/GroupItem.svelte
+++ b/src/lib/components/admin/Users/Groups/GroupItem.svelte
@@ -23,7 +23,7 @@
const updateHandler = async (_group) => {
const res = await updateGroupById(localStorage.token, group.id, _group).catch((error) => {
- toast.error(error);
+ toast.error(`${error}`);
return null;
});
@@ -35,7 +35,7 @@
const deleteHandler = async () => {
const res = await deleteGroupById(localStorage.token, group.id).catch((error) => {
- toast.error(error);
+ toast.error(`${error}`);
return null;
});
diff --git a/src/lib/components/admin/Users/Groups/Permissions.svelte b/src/lib/components/admin/Users/Groups/Permissions.svelte
index 5d67ff76848..430fabaacfd 100644
--- a/src/lib/components/admin/Users/Groups/Permissions.svelte
+++ b/src/lib/components/admin/Users/Groups/Permissions.svelte
@@ -1,11 +1,12 @@
@@ -169,6 +196,14 @@
{$i18n.t('Chat Permissions')}
+
+
+ {$i18n.t('Allow Chat Controls')}
+
+
+
+
+
{$i18n.t('Allow File Upload')}
@@ -201,4 +236,26 @@
+
+
+
+
+
{$i18n.t('Features Permissions')}
+
+
+
+ {$i18n.t('Web Search')}
+
+
+
+
+
+
+
+ {$i18n.t('Image Generation')}
+
+
+
+
+
diff --git a/src/lib/components/admin/Users/UserList.svelte b/src/lib/components/admin/Users/UserList.svelte
index bbf6fb25e22..2ee4297a46e 100644
--- a/src/lib/components/admin/Users/UserList.svelte
+++ b/src/lib/components/admin/Users/UserList.svelte
@@ -44,7 +44,7 @@
const updateRoleHandler = async (id, role) => {
const res = await updateUserRole(localStorage.token, id, role).catch((error) => {
- toast.error(error);
+ toast.error(`${error}`);
return null;
});
@@ -55,7 +55,7 @@
const deleteUserHandler = async (id) => {
const res = await deleteUserById(localStorage.token, id).catch((error) => {
- toast.error(error);
+ toast.error(`${error}`);
return null;
});
if (res) {
diff --git a/src/lib/components/admin/Users/UserList/AddUserModal.svelte b/src/lib/components/admin/Users/UserList/AddUserModal.svelte
index c29a39e826a..99cc5d0c6f5 100644
--- a/src/lib/components/admin/Users/UserList/AddUserModal.svelte
+++ b/src/lib/components/admin/Users/UserList/AddUserModal.svelte
@@ -49,7 +49,7 @@
_user.password,
_user.role
).catch((error) => {
- toast.error(error);
+ toast.error(`${error}`);
});
if (res) {
@@ -114,6 +114,8 @@
toast.error($i18n.t('File not found.'));
}
}
+
+ loading = false;
};
@@ -148,9 +150,13 @@
submitHandler();
}}
>
-
+
+
{#if tab === ''}
-
+
{$i18n.t('Role')}