소스 검색

refac: user valves

Timothy Jaeryang Baek 1 주 전
부모
커밋
b77848244b

+ 6 - 0
backend/open_webui/functions.py

@@ -86,6 +86,10 @@ async def get_function_models(request):
         try:
             function_module = get_function_module_by_id(request, pipe.id)
 
+            has_user_valves = False
+            if hasattr(function_module, "UserValves"):
+                has_user_valves = True
+
             # Check if function is a manifold
             if hasattr(function_module, "pipes"):
                 sub_pipes = []
@@ -124,6 +128,7 @@ async def get_function_models(request):
                             "created": pipe.created_at,
                             "owned_by": "openai",
                             "pipe": pipe_flag,
+                            "has_user_valves": has_user_valves,
                         }
                     )
             else:
@@ -141,6 +146,7 @@ async def get_function_models(request):
                         "created": pipe.created_at,
                         "owned_by": "openai",
                         "pipe": pipe_flag,
+                        "has_user_valves": has_user_valves,
                     }
                 )
         except Exception as e:

+ 1 - 0
backend/open_webui/utils/models.py

@@ -263,6 +263,7 @@ async def get_all_models(request, refresh: bool = False, user: UserModel = None)
                 "icon": function.meta.manifest.get("icon_url", None)
                 or getattr(module, "icon_url", None)
                 or getattr(module, "icon", None),
+                "has_user_valves": hasattr(module, "UserValves"),
             }
         ]
 

+ 40 - 0
src/lib/components/chat/MessageInput.svelte

@@ -78,6 +78,8 @@
 
 	import { getSuggestionRenderer } from '../common/RichTextInput/suggestions';
 	import CommandSuggestionList from './MessageInput/CommandSuggestionList.svelte';
+	import Knobs from '../icons/Knobs.svelte';
+	import ValvesModal from '../workspace/common/ValvesModal.svelte';
 
 	const i18n = getContext('i18n');
 
@@ -112,6 +114,10 @@
 	let inputVariables = {};
 	let inputVariableValues = {};
 
+	let showValvesModal = false;
+	let selectedValvesType = 'tool'; // 'tool' or 'function'
+	let selectedValvesItemId = null;
+
 	$: onChange({
 		prompt,
 		files: files
@@ -932,6 +938,16 @@
 	onSave={inputVariablesModalCallback}
 />
 
+<ValvesModal
+	bind:show={showValvesModal}
+	userValves={true}
+	type={selectedValvesType}
+	id={selectedValvesItemId ?? null}
+	on:save={async () => {
+		await tick();
+	}}
+/>
+
 {#if loaded}
 	<div class="w-full font-primary">
 		<div class=" mx-auto inset-x-0 bg-transparent flex justify-center">
@@ -1449,6 +1465,12 @@
 												bind:webSearchEnabled
 												bind:imageGenerationEnabled
 												bind:codeInterpreterEnabled
+												onShowValves={(e) => {
+													const { type, id } = e;
+													selectedValvesType = type;
+													selectedValvesItemId = id;
+													showValvesModal = true;
+												}}
 												onClose={async () => {
 													await tick();
 
@@ -1465,6 +1487,24 @@
 											</IntegrationsMenu>
 										{/if}
 
+										{#if selectedModelIds.length === 1 && $models.find((m) => m.id === selectedModelIds[0])?.has_user_valves}
+											<div class="ml-1 flex gap-1.5">
+												<Tooltip content={$i18n.t('Valves')} placement="top">
+													<button
+														id="model-valves-button"
+														class="bg-transparent hover:bg-gray-100 text-gray-700 dark:text-white dark:hover:bg-gray-800 rounded-full size-8 flex justify-center items-center outline-hidden focus:outline-hidden"
+														on:click={() => {
+															selectedValvesType = 'function';
+															selectedValvesItemId = selectedModelIds[0]?.split('.')[0];
+															showValvesModal = true;
+														}}
+													>
+														<Knobs className="size-4" strokeWidth="1.5" />
+													</button>
+												</Tooltip>
+											</div>
+										{/if}
+
 										<div class="ml-1 flex gap-1.5">
 											{#if (selectedToolIds ?? []).length > 0}
 												<Tooltip

+ 26 - 19
src/lib/components/chat/MessageInput/IntegrationsMenu.svelte

@@ -21,7 +21,6 @@
 	import Terminal from '$lib/components/icons/Terminal.svelte';
 	import ChevronRight from '$lib/components/icons/ChevronRight.svelte';
 	import ChevronLeft from '$lib/components/icons/ChevronLeft.svelte';
-	import ValvesModal from '$lib/components/workspace/common/ValvesModal.svelte';
 
 	const i18n = getContext('i18n');
 
@@ -41,16 +40,12 @@
 	export let showCodeInterpreterButton = false;
 	export let codeInterpreterEnabled = false;
 
+	export let onShowValves: Function;
 	export let onClose: Function;
 
 	let show = false;
 	let tab = '';
 
-	let showValvesModal = false;
-
-	let selectedValvesType = 'tool';
-	let selectedValvesItemId = null;
-
 	let tools = null;
 
 	$: if (show) {
@@ -96,16 +91,6 @@
 	};
 </script>
 
-<ValvesModal
-	bind:show={showValvesModal}
-	userValves={true}
-	type={selectedValvesType}
-	id={selectedValvesItemId ?? null}
-	on:save={async () => {
-		await tick();
-	}}
-/>
-
 <Dropdown
 	bind:show
 	on:change={(e) => {
@@ -192,6 +177,27 @@
 										</div>
 									</div>
 
+									{#if filter?.has_user_valves}
+										<div class=" shrink-0">
+											<Tooltip content={$i18n.t('Valves')}>
+												<button
+													class="self-center w-fit text-sm text-gray-600 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition rounded-full"
+													type="button"
+													on:click={(e) => {
+														e.stopPropagation();
+														e.preventDefault();
+														onShowValves({
+															type: 'function',
+															id: filter.id
+														});
+													}}
+												>
+													<Knobs />
+												</button>
+											</Tooltip>
+										</div>
+									{/if}
+
 									<div class=" shrink-0">
 										<Switch
 											state={selectedFilterIds.includes(filter.id)}
@@ -364,9 +370,10 @@
 											on:click={(e) => {
 												e.stopPropagation();
 												e.preventDefault();
-												selectedValvesType = 'tool';
-												selectedValvesItemId = toolId;
-												showValvesModal = true;
+												onShowValves({
+													type: 'tool',
+													id: toolId
+												});
 											}}
 										>
 											<Knobs />

+ 3 - 2
src/lib/components/chat/Navbar.svelte

@@ -37,6 +37,7 @@
 	import EllipsisHorizontal from '../icons/EllipsisHorizontal.svelte';
 	import ChatPlus from '../icons/ChatPlus.svelte';
 	import ChatCheck from '../icons/ChatCheck.svelte';
+	import Knobs from '../icons/Knobs.svelte';
 
 	const i18n = getContext('i18n');
 
@@ -210,7 +211,7 @@
 								aria-label="Controls"
 							>
 								<div class=" m-auto self-center">
-									<AdjustmentsHorizontal className=" size-5" strokeWidth="1" />
+									<Knobs className=" size-5" strokeWidth="1" />
 								</div>
 							</button>
 						</Tooltip>
@@ -255,7 +256,7 @@
 
 	<div class="absolute top-[100%] left-0 right-0 h-fit">
 		{#if !history.currentId && !$chatId && ($banners.length > 0 || ($config?.license_metadata?.type ?? null) === 'trial' || (($config?.license_metadata?.seats ?? null) !== null && $config?.user_count > $config?.license_metadata?.seats))}
-			<div class=" w-full z-30 mt-4">
+			<div class=" w-full z-30">
 				<div class=" flex flex-col gap-1 w-full">
 					{#if ($config?.license_metadata?.type ?? null) === 'trial'}
 						<Banner

+ 6 - 6
src/lib/components/icons/Knobs.svelte

@@ -13,12 +13,12 @@
 	viewBox="0 0 24 24"
 >
 	<!-- Top horizontal knob (left biased) -->
-	<line x1="3" y1="8" x2="6" y2="8" stroke-linecap="round" />
-	<line x1="12" y1="8" x2="21" y2="8" stroke-linecap="round" />
-	<circle cx="9" cy="8" r="2.5" stroke="currentColor" fill="none" />
+	<line x1="2" y1="7.5" x2="6" y2="7.5" stroke-linecap="round" />
+	<line x1="12" y1="7.5" x2="22" y2="7.5" stroke-linecap="round" />
+	<circle cx="9" cy="7.5" r="3" stroke="currentColor" fill="none" />
 
 	<!-- Bottom horizontal knob (right biased) -->
-	<line x1="3" y1="16" x2="12" y2="16" stroke-linecap="round" />
-	<line x1="18" y1="16" x2="21" y2="16" stroke-linecap="round" />
-	<circle cx="15" cy="16" r="2.5" stroke="currentColor" fill="none" />
+	<line x1="2" y1="16.5" x2="12" y2="16.5" stroke-linecap="round" />
+	<line x1="18" y1="16.5" x2="22" y2="16.5" stroke-linecap="round" />
+	<circle cx="15" cy="16.5" r="3" stroke="currentColor" fill="none" />
 </svg>

+ 1 - 1
src/routes/(app)/admin/functions/create/+page.svelte

@@ -91,7 +91,7 @@
 
 {#if mounted}
 	{#key func?.content}
-		<div class="px-[16px]">
+		<div class="px-[16px] h-full">
 			<FunctionEditor
 				id={func?.id ?? ''}
 				name={func?.name ?? ''}

+ 1 - 1
src/routes/(app)/admin/functions/edit/+page.svelte

@@ -76,7 +76,7 @@
 </script>
 
 {#if func}
-	<div class="px-[16px]">
+	<div class="px-[16px] h-full">
 		<FunctionEditor
 			edit={true}
 			id={func.id}