瀏覽代碼

Merge pull request #13919 from dongfangzan/main

feat: add switching thinking/non-thinking modes to models
Tim Jaeryang Baek 4 月之前
父節點
當前提交
50bc6d9b12

+ 5 - 0
backend/open_webui/utils/middleware.py

@@ -790,6 +790,11 @@ async def process_chat_payload(request, form_data, user, metadata, model):
                 ),
                 form_data["messages"],
             )
+        if "thinking" in features:
+            form_data["enable_thinking"] = features["thinking"]
+            form_data["chat_template_kwargs"] = {
+                "enable_thinking": features["thinking"]
+            }
 
     tool_ids = form_data.pop("tool_ids", None)
     files = form_data.pop("files", None)

+ 13 - 1
src/lib/components/chat/Chat.svelte

@@ -122,6 +122,7 @@
 	let imageGenerationEnabled = false;
 	let webSearchEnabled = false;
 	let codeInterpreterEnabled = false;
+	let thinkingEnabled = false;
 
 	let chat = null;
 	let tags = [];
@@ -147,6 +148,7 @@
 			files = [];
 			selectedToolIds = [];
 			webSearchEnabled = false;
+			thinkingEnabled = false;
 			imageGenerationEnabled = false;
 
 			if (localStorage.getItem(`chat-input${chatIdProp ? `-${chatIdProp}` : ''}`)) {
@@ -160,6 +162,7 @@
 						files = input.files;
 						selectedToolIds = input.selectedToolIds;
 						webSearchEnabled = input.webSearchEnabled;
+						thinkingEnabled = input.thinkingEnabled;
 						imageGenerationEnabled = input.imageGenerationEnabled;
 						codeInterpreterEnabled = input.codeInterpreterEnabled;
 					}
@@ -425,6 +428,7 @@
 			files = [];
 			selectedToolIds = [];
 			webSearchEnabled = false;
+			thinkingEnabled = false;
 			imageGenerationEnabled = false;
 			codeInterpreterEnabled = false;
 
@@ -440,6 +444,7 @@
 					webSearchEnabled = input.webSearchEnabled;
 					imageGenerationEnabled = input.imageGenerationEnabled;
 					codeInterpreterEnabled = input.codeInterpreterEnabled;
+					thinkingEnabled = input.thinkingEnabled;
 				}
 			} catch (e) {}
 		}
@@ -748,6 +753,10 @@
 			webSearchEnabled = true;
 		}
 
+		if ($page.url.searchParams.get('thinking') === 'true') {
+			thinkingEnabled = true;
+		}
+
 		if ($page.url.searchParams.get('image-generation') === 'true') {
 			imageGenerationEnabled = true;
 		}
@@ -1635,7 +1644,8 @@
 						$config?.features?.enable_web_search &&
 						($user?.role === 'admin' || $user?.permissions?.features?.web_search)
 							? webSearchEnabled || ($settings?.webSearch ?? false) === 'always'
-							: false
+							: false,
+					thinking: thinkingEnabled
 				},
 				variables: {
 					...getPromptVariables(
@@ -2061,6 +2071,7 @@
 								bind:imageGenerationEnabled
 								bind:codeInterpreterEnabled
 								bind:webSearchEnabled
+								bind:thinkingEnabled
 								bind:atSelectedModel
 								toolServers={$toolServers}
 								transparentBackground={$settings?.backgroundImageUrl ?? false}
@@ -2117,6 +2128,7 @@
 								bind:imageGenerationEnabled
 								bind:codeInterpreterEnabled
 								bind:webSearchEnabled
+								bind:thinkingEnabled
 								bind:atSelectedModel
 								transparentBackground={$settings?.backgroundImageUrl ?? false}
 								toolServers={$toolServers}

+ 28 - 1
src/lib/components/chat/MessageInput.svelte

@@ -47,6 +47,7 @@
 	import XMark from '../icons/XMark.svelte';
 	import Headphone from '../icons/Headphone.svelte';
 	import GlobeAlt from '../icons/GlobeAlt.svelte';
+	import Thinking from "../icons/Thinking.svelte";
 	import PhotoSolid from '../icons/PhotoSolid.svelte';
 	import Photo from '../icons/Photo.svelte';
 	import CommandLine from '../icons/CommandLine.svelte';
@@ -83,6 +84,7 @@
 	export let imageGenerationEnabled = false;
 	export let webSearchEnabled = false;
 	export let codeInterpreterEnabled = false;
+	export let thinkingEnabled = false;
 
 	$: onChange({
 		prompt,
@@ -90,7 +92,8 @@
 		selectedToolIds,
 		imageGenerationEnabled,
 		webSearchEnabled,
-		codeInterpreterEnabled
+		codeInterpreterEnabled,
+		thinkingEnabled
 	});
 
 	let showTools = false;
@@ -117,6 +120,10 @@
 		(model) => $models.find((m) => m.id === model)?.info?.meta?.capabilities?.vision ?? true
 	);
 
+	let switchThinkingCapableModels = [];
+	$: switchThinkingCapableModels = $models.filter((model) => model.info?.meta?.capabilities?.switch_thinking ?? false)
+			.map((model) => model.id)
+
 	const scrollToBottom = () => {
 		const element = document.getElementById('messages-container');
 		element.scrollTo({
@@ -773,6 +780,7 @@
 														selectedToolIds = [];
 														webSearchEnabled = false;
 														imageGenerationEnabled = false;
+														thinkingEnabled = false;
 													}
 												}}
 												on:paste={async (e) => {
@@ -996,6 +1004,7 @@
 													selectedToolIds = [];
 													webSearchEnabled = false;
 													imageGenerationEnabled = false;
+													thinkingEnabled = false;
 												}
 											}}
 											rows="1"
@@ -1143,6 +1152,24 @@
 											{/if}
 
 											{#if $_user}
+												{#if selectedModels.length > 0 && selectedModels.some((model) => switchThinkingCapableModels.includes(model))}
+													<Tooltip content={$i18n.t('Thinking')} placement="top">
+														<button
+															on:click|preventDefault={() => (thinkingEnabled = !thinkingEnabled)}
+															type="button"
+															class="px-1.5 @xl:px-2.5 py-1.5 flex gap-1.5 items-center text-sm rounded-full font-medium transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden border {thinkingEnabled
+																? 'bg-blue-100 dark:bg-blue-500/20 border-blue-400/20 text-blue-500 dark:text-blue-400'
+																: 'bg-transparent border-transparent text-gray-600 dark:text-gray-300 border-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800'}"
+														>
+															<Thinking className="size-5" strokeWidth="1.75" />
+															<span
+																class="hidden @xl:block whitespace-nowrap overflow-hidden text-ellipsis translate-y-[0.5px]"
+																>{$i18n.t('Thinking')}</span
+															>
+														</button>
+													</Tooltip>
+												{/if}
+
 												{#if $config?.features?.enable_web_search && ($_user.role === 'admin' || $_user?.permissions?.features?.web_search)}
 													<Tooltip content={$i18n.t('Search the internet')} placement="top">
 														<button

+ 2 - 0
src/lib/components/chat/Placeholder.svelte

@@ -37,6 +37,7 @@
 	export let imageGenerationEnabled = false;
 	export let codeInterpreterEnabled = false;
 	export let webSearchEnabled = false;
+	export let thinkingEnabled = false;
 
 	export let toolServers = [];
 
@@ -195,6 +196,7 @@
 					bind:imageGenerationEnabled
 					bind:codeInterpreterEnabled
 					bind:webSearchEnabled
+					bind:thinkingEnabled
 					bind:atSelectedModel
 					{toolServers}
 					{transparentBackground}

+ 19 - 0
src/lib/components/icons/Thinking.svelte

@@ -0,0 +1,19 @@
+<script lang="ts">
+    export let className = 'w-4 h-4';
+    export let strokeWidth = '1.5';
+</script>
+
+<svg
+    xmlns="http://www.w3.org/2000/svg"
+    fill="none"
+    viewBox="0 0 24 24"
+    stroke-width={strokeWidth}
+    stroke="currentColor"
+    class={className}
+>
+    <path
+        stroke-linecap="round"
+        stroke-linejoin="round"
+        d="M12 18v-5.25m0 0a6.01 6.01 0 0 0 1.5-.189m-1.5.189a6.01 6.01 0 0 1-1.5-.189m3.75 7.478a12.06 12.06 0 0 1-4.5 0m3.75 2.383a14.406 14.406 0 0 1-3 0M14.25 18v-.192c0-.983.658-1.823 1.508-2.316a7.5 7.5 0 1 0-7.517 0c.85.493 1.509 1.333 1.509 2.316V18"
+    />
+</svg>

+ 3 - 1
src/lib/components/workspace/Models/Capabilities.svelte

@@ -11,13 +11,15 @@
 		usage: $i18n.t(
 			'Sends `stream_options: { include_usage: true }` in the request.\nSupported providers will return token usage information in the response when set.'
 		),
-		citations: $i18n.t('Displays citations in the response')
+		citations: $i18n.t('Displays citations in the response'),
+		switch_thinking: $i18n.t('Sends `enable_thinking: true` in the request. \nSupported toggle providers will return thinking content')
 	};
 
 	export let capabilities: {
 		vision?: boolean;
 		usage?: boolean;
 		citations?: boolean;
+		switch_thinking?: boolean;
 	} = {};
 </script>
 

+ 2 - 1
src/lib/components/workspace/Models/ModelEditor.svelte

@@ -78,7 +78,8 @@
 	let capabilities = {
 		vision: true,
 		usage: undefined,
-		citations: true
+		citations: true,
+		switch_thinking: false,
 	};
 
 	let knowledge = [];

+ 2 - 0
src/lib/i18n/locales/zh-CN/translation.json

@@ -1045,6 +1045,7 @@
 	"Send a Message": "输入消息",
 	"Send message": "发送消息",
 	"Sends `stream_options: { include_usage: true }` in the request.\nSupported providers will return token usage information in the response when set.": "在请求中发送 `stream_options: { include_usage: true }`。设置后,支持的供应商会在响应中返回 Token 使用信息。",
+	"Sends `enable_thinking: true` in the request. \nSupported toggle providers will return thinking content": "在请求中发送 `enable_thinking: true`。设置后,支持的供应商会返回深度思考的能力",
 	"September": "九月",
 	"SerpApi API Key": "SerpApi API 密钥",
 	"SerpApi Engine": "SerpApi 引擎",
@@ -1148,6 +1149,7 @@
 	"The score should be a value between 0.0 (0%) and 1.0 (100%).": "分值应介于 0.0(0%)和 1.0(100%)之间。",
 	"The temperature of the model. Increasing the temperature will make the model answer more creatively.": "模型的温度。增加温度将使模型的回答更有创意。",
 	"Theme": "主题",
+	"Thinking...": "深度思考",
 	"Thinking...": "正在思考...",
 	"This action cannot be undone. Do you wish to continue?": "此操作无法撤销。是否确认继续?",
 	"This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "此频道创建于{{createdAt}},这里是{{channelName}}频道的开始",