diff --git a/backend/open_webui/models/functions.py b/backend/open_webui/models/functions.py index 2bb6d60889..e8ce3aa811 100644 --- a/backend/open_webui/models/functions.py +++ b/backend/open_webui/models/functions.py @@ -37,6 +37,7 @@ class Function(Base): class FunctionMeta(BaseModel): description: Optional[str] = None manifest: Optional[dict] = {} + model_config = ConfigDict(extra="allow") class FunctionModel(BaseModel): @@ -260,6 +261,29 @@ class FunctionsTable: except Exception: return None + def update_function_metadata_by_id( + self, id: str, metadata: dict + ) -> Optional[FunctionModel]: + with get_db() as db: + try: + function = db.get(Function, id) + + if function: + if function.meta: + function.meta = {**function.meta, **metadata} + else: + function.meta = metadata + + function.updated_at = int(time.time()) + db.commit() + db.refresh(function) + return self.get_function_by_id(id) + else: + return None + except Exception as e: + log.exception(f"Error updating function metadata by id {id}: {e}") + return None + def get_user_valves_by_id_and_user_id( self, id: str, user_id: str ) -> Optional[dict]: diff --git a/backend/open_webui/routers/functions.py b/backend/open_webui/routers/functions.py index 9ef6915709..9f0651fd3f 100644 --- a/backend/open_webui/routers/functions.py +++ b/backend/open_webui/routers/functions.py @@ -192,6 +192,9 @@ async def create_new_function( function_cache_dir = CACHE_DIR / "functions" / form_data.id function_cache_dir.mkdir(parents=True, exist_ok=True) + if function_type == "filter" and getattr(function_module, "toggle", None): + Functions.update_function_metadata_by_id(id, {"toggle": True}) + if function: return function else: @@ -308,6 +311,9 @@ async def update_function_by_id( function = Functions.update_function_by_id(id, updated) + if function_type == "filter" and getattr(function_module, "toggle", None): + Functions.update_function_metadata_by_id(id, {"toggle": True}) + if function: return function else: diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 10651f55d8..92098c8520 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -37,6 +37,7 @@ showArtifacts, tools, toolServers, + functions, selectedFolder, pinnedChats } from '$lib/stores'; @@ -88,6 +89,7 @@ import Spinner from '../common/Spinner.svelte'; import Tooltip from '../common/Tooltip.svelte'; import Sidebar from '../icons/Sidebar.svelte'; + import { getFunctions } from '$lib/apis/functions'; export let chatIdProp = ''; @@ -236,33 +238,62 @@ }; const resetInput = () => { - console.debug('resetInput'); - setToolIds(); - + selectedToolIds = []; selectedFilterIds = []; webSearchEnabled = false; imageGenerationEnabled = false; codeInterpreterEnabled = false; + + setDefaults(); }; - const setToolIds = async () => { + const setDefaults = async () => { if (!$tools) { tools.set(await getTools(localStorage.token)); } - + if (!$functions) { + functions.set(await getFunctions(localStorage.token)); + } if (selectedModels.length !== 1 && !atSelectedModel) { return; } const model = atSelectedModel ?? $models.find((m) => m.id === selectedModels[0]); - if (model && model?.info?.meta?.toolIds) { - selectedToolIds = [ - ...new Set( - [...(model?.info?.meta?.toolIds ?? [])].filter((id) => $tools.find((t) => t.id === id)) - ) - ]; - } else { - selectedToolIds = []; + if (model) { + if (model?.info?.meta?.toolIds) { + selectedToolIds = [ + ...new Set( + [...(model?.info?.meta?.toolIds ?? [])].filter((id) => $tools.find((t) => t.id === id)) + ) + ]; + } else { + selectedToolIds = []; + } + + if (model?.info?.meta?.defaultFilterIds) { + console.log('model.info.meta.defaultFilterIds', model.info.meta.defaultFilterIds); + selectedFilterIds = model.info.meta.defaultFilterIds; + console.log('selectedFilterIds', selectedFilterIds); + } else { + selectedFilterIds = []; + } + + if (model?.info?.meta?.defaultFeatureIds) { + console.log('model.info.meta.defaultFeatureIds', model.info.meta.defaultFeatureIds); + imageGenerationEnabled = model.info.meta.defaultFeatureIds.includes('image_generation'); + webSearchEnabled = model.info.meta.defaultFeatureIds.includes('web_search'); + codeInterpreterEnabled = model.info.meta.defaultFeatureIds.includes('code_interpreter'); + + console.log({ + imageGenerationEnabled, + webSearchEnabled, + codeInterpreterEnabled + }); + } else { + imageGenerationEnabled = false; + webSearchEnabled = false; + codeInterpreterEnabled = false; + } } }; diff --git a/src/lib/components/workspace/Models/ActionsSelector.svelte b/src/lib/components/workspace/Models/ActionsSelector.svelte index 8335455eda..4b3b52d4e8 100644 --- a/src/lib/components/workspace/Models/ActionsSelector.svelte +++ b/src/lib/components/workspace/Models/ActionsSelector.svelte @@ -22,18 +22,14 @@ }); -
-
-
{$i18n.t('Actions')}
-
+{#if actions.length > 0} +
+
+
{$i18n.t('Actions')}
+
-
- {$i18n.t('To select actions here, add them to the "Functions" workspace first.')} -
- -
- {#if actions.length > 0} -
+
+
{#each Object.keys(_actions) as action, actionIdx}
@@ -54,6 +50,6 @@
{/each}
- {/if} +
-
+{/if} diff --git a/src/lib/components/workspace/Models/DefaultFeatures.svelte b/src/lib/components/workspace/Models/DefaultFeatures.svelte new file mode 100644 index 0000000000..a64d48a0e4 --- /dev/null +++ b/src/lib/components/workspace/Models/DefaultFeatures.svelte @@ -0,0 +1,54 @@ + + +
+
+
{$i18n.t('Default Features')}
+
+
+ {#each availableFeatures as feature} +
+ { + if (e.detail === 'checked') { + featureIds = [...featureIds, feature]; + } else { + featureIds = featureIds.filter((id) => id !== feature); + } + }} + /> + +
+ + {$i18n.t(featureLabels[feature].label)} + +
+
+ {/each} +
+
diff --git a/src/lib/components/workspace/Models/DefaultFiltersSelector.svelte b/src/lib/components/workspace/Models/DefaultFiltersSelector.svelte new file mode 100644 index 0000000000..91ef20d79a --- /dev/null +++ b/src/lib/components/workspace/Models/DefaultFiltersSelector.svelte @@ -0,0 +1,62 @@ + + +
+
+
{$i18n.t('Default Filters')}
+
+ +
+ {#if filters.length > 0} +
+ {#each Object.keys(_filters) as filter, filterIdx} +
+
+ { + if (!_filters[filter].is_global) { + _filters[filter].selected = e.detail === 'checked'; + selectedFilterIds = Object.keys(_filters).filter((t) => _filters[t].selected); + } + }} + /> +
+ +
+ + {_filters[filter].name} + +
+
+ {/each} +
+ {/if} +
+
diff --git a/src/lib/components/workspace/Models/FiltersSelector.svelte b/src/lib/components/workspace/Models/FiltersSelector.svelte index fa595d6f82..0c92419bb6 100644 --- a/src/lib/components/workspace/Models/FiltersSelector.svelte +++ b/src/lib/components/workspace/Models/FiltersSelector.svelte @@ -22,19 +22,15 @@ }); -
-
-
{$i18n.t('Filters')}
-
+{#if filters.length > 0} +
+
+
{$i18n.t('Filters')}
+
-
- {$i18n.t('To select filters here, add them to the "Functions" workspace first.')} -
- - -
- {#if filters.length > 0} -
+ +
+
{#each Object.keys(_filters) as filter, filterIdx}
@@ -62,6 +58,6 @@
{/each}
- {/if} +
-
+{/if} diff --git a/src/lib/components/workspace/Models/ModelEditor.svelte b/src/lib/components/workspace/Models/ModelEditor.svelte index fc9c167e9b..c123dfa98a 100644 --- a/src/lib/components/workspace/Models/ModelEditor.svelte +++ b/src/lib/components/workspace/Models/ModelEditor.svelte @@ -1,8 +1,14 @@