Bläddra i källkod

enh: code interpreter toggle

Timothy Jaeryang Baek 2 månader sedan
förälder
incheckning
95c6d0e78c

+ 14 - 0
backend/open_webui/config.py

@@ -1317,6 +1317,20 @@ Your task is to synthesize these responses into a single, high-quality response.
 
 Responses from models: {{responses}}"""
 
+
+DEFAULT_CODE_INTERPRETER_PROMPT = """
+#### Tools Available
+
+1. **Code Interpreter**: `<code_interpreter type="code" lang="python"></code_interpreter>`
+   - You have access to a Python shell that runs directly in the user's browser, enabling fast execution of code for analysis, calculations, or problem-solving.  Use it in this response.
+   - The Python code you write can incorporate a wide array of libraries, handle data manipulation or visualization, perform API calls for web-related tasks, or tackle virtually any computational challenge. Use this flexibility to **think outside the box, craft elegant solutions, and harness Python's full potential**.
+   - To use it, **you must enclose your code within `<code_interpreter type="code" lang="python">` tags** and stop right away. If you don't, the code won't execute. Do NOT use triple backticks.
+   - When coding, **always aim to print meaningful outputs** (e.g., results, tables, summaries, or visuals) to better interpret and verify the findings. Avoid relying on implicit outputs; prioritize explicit and clear print statements so the results are effectively communicated to the user.  
+   - After obtaining the printed output, **always provide a concise analysis, interpretation, or next steps to help the user understand the findings or refine the outcome further.**  
+   - If the results are unclear, unexpected, or require validation, refine the code and execute it again as needed. Always aim to deliver meaningful insights from the results, iterating if necessary.  
+
+Ensure that the tools are effectively utilized to achieve the highest-quality analysis for the user."""
+
 ####################################
 # Vector Database
 ####################################

+ 11 - 2
backend/open_webui/utils/middleware.py

@@ -57,6 +57,7 @@ from open_webui.utils.task import (
 from open_webui.utils.misc import (
     get_message_list,
     add_or_update_system_message,
+    add_or_update_user_message,
     get_last_user_message,
     get_last_assistant_message,
     prepend_to_first_user_message_content,
@@ -67,7 +68,10 @@ from open_webui.utils.plugin import load_function_module_by_id
 
 from open_webui.tasks import create_task
 
-from open_webui.config import DEFAULT_TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE
+from open_webui.config import (
+    DEFAULT_TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE,
+    DEFAULT_CODE_INTERPRETER_PROMPT,
+)
 from open_webui.env import (
     SRC_LOG_LEVELS,
     GLOBAL_LOG_LEVEL,
@@ -776,6 +780,11 @@ async def process_chat_payload(request, form_data, metadata, user, model):
                 request, form_data, extra_params, user
             )
 
+        if "code_interpreter" in features and features["code_interpreter"]:
+            form_data["messages"] = add_or_update_user_message(
+                DEFAULT_CODE_INTERPRETER_PROMPT, form_data["messages"]
+            )
+
     try:
         form_data, flags = await chat_completion_filter_functions_handler(
             request, form_data, model, extra_params
@@ -1359,7 +1368,7 @@ async def process_chat_response(
                     and retries < MAX_RETRIES
                 ):
                     retries += 1
-                    log.debug(f"Retrying code interpreter block: {retries}")
+                    log.debug(f"Attempt count: {retries}")
 
                     try:
                         if content_blocks[-1]["attributes"].get("type") == "code":

+ 19 - 0
backend/open_webui/utils/misc.py

@@ -131,6 +131,25 @@ def add_or_update_system_message(content: str, messages: list[dict]):
     return messages
 
 
+def add_or_update_user_message(content: str, messages: list[dict]):
+    """
+    Adds a new user message at the end of the messages list
+    or updates the existing user message at the end.
+
+    :param msg: The message to be added or appended.
+    :param messages: The list of message dictionaries.
+    :return: The updated list of message dictionaries.
+    """
+
+    if messages and messages[-1].get("role") == "user":
+        messages[-1]["content"] = f"{messages[-1]['content']}\n{content}"
+    else:
+        # Insert at the end
+        messages.append({"role": "user", "content": content})
+
+    return messages
+
+
 def append_or_update_assistant_message(content: str, messages: list[dict]):
     """
     Adds a new assistant message at the end of the messages list

+ 4 - 0
src/lib/components/chat/Chat.svelte

@@ -116,6 +116,7 @@
 
 	let selectedToolIds = [];
 	let imageGenerationEnabled = false;
+	let codeInterpreterEnabled = false;
 	let webSearchEnabled = false;
 
 	let chat = null;
@@ -1562,6 +1563,7 @@
 
 				features: {
 					image_generation: imageGenerationEnabled,
+					code_interpreter: codeInterpreterEnabled,
 					web_search: webSearchEnabled
 				},
 				variables: {
@@ -1971,6 +1973,7 @@
 								bind:autoScroll
 								bind:selectedToolIds
 								bind:imageGenerationEnabled
+								bind:codeInterpreterEnabled
 								bind:webSearchEnabled
 								bind:atSelectedModel
 								transparentBackground={$settings?.backgroundImageUrl ?? false}
@@ -2022,6 +2025,7 @@
 								bind:autoScroll
 								bind:selectedToolIds
 								bind:imageGenerationEnabled
+								bind:codeInterpreterEnabled
 								bind:webSearchEnabled
 								bind:atSelectedModel
 								transparentBackground={$settings?.backgroundImageUrl ?? false}

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

@@ -65,6 +65,7 @@
 
 	export let imageGenerationEnabled = false;
 	export let webSearchEnabled = false;
+	export let codeInterpreterEnabled = false;
 
 	$: onChange({
 		prompt,
@@ -660,6 +661,7 @@
 									<div class="ml-1 self-end mb-1.5 flex space-x-1">
 										<InputMenu
 											bind:imageGenerationEnabled
+											bind:codeInterpreterEnabled
 											bind:webSearchEnabled
 											bind:selectedToolIds
 											{screenCaptureHandler}

+ 16 - 0
src/lib/components/chat/MessageInput/InputMenu.svelte

@@ -15,6 +15,7 @@
 	import WrenchSolid from '$lib/components/icons/WrenchSolid.svelte';
 	import CameraSolid from '$lib/components/icons/CameraSolid.svelte';
 	import PhotoSolid from '$lib/components/icons/PhotoSolid.svelte';
+	import CommandLineSolid from '$lib/components/icons/CommandLineSolid.svelte';
 
 	const i18n = getContext('i18n');
 
@@ -26,6 +27,7 @@
 
 	export let webSearchEnabled: boolean;
 	export let imageGenerationEnabled: boolean;
+	export let codeInterpreterEnabled: boolean;
 
 	export let onClose: Function;
 
@@ -148,6 +150,20 @@
 				</button>
 			{/if}
 
+			<button
+				class="flex w-full justify-between gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer rounded-xl"
+				on:click={() => {
+					codeInterpreterEnabled = !codeInterpreterEnabled;
+				}}
+			>
+				<div class="flex-1 flex items-center gap-2">
+					<CommandLineSolid />
+					<div class=" line-clamp-1">{$i18n.t('Code Intepreter')}</div>
+				</div>
+
+				<Switch state={codeInterpreterEnabled} />
+			</button>
+
 			{#if showWebSearch}
 				<button
 					class="flex w-full justify-between gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer rounded-xl"

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

@@ -35,6 +35,7 @@
 
 	export let selectedToolIds = [];
 	export let imageGenerationEnabled = false;
+	export let codeInterpreterEnabled = false;
 	export let webSearchEnabled = false;
 
 	let models = [];
@@ -196,6 +197,7 @@
 					bind:autoScroll
 					bind:selectedToolIds
 					bind:imageGenerationEnabled
+					bind:codeInterpreterEnabled
 					bind:webSearchEnabled
 					bind:atSelectedModel
 					{transparentBackground}

+ 11 - 0
src/lib/components/icons/CommandLineSolid.svelte

@@ -0,0 +1,11 @@
+<script lang="ts">
+	export let className = 'size-4';
+</script>
+
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class={className}>
+	<path
+		fill-rule="evenodd"
+		d="M2.25 6a3 3 0 0 1 3-3h13.5a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3V6Zm3.97.97a.75.75 0 0 1 1.06 0l2.25 2.25a.75.75 0 0 1 0 1.06l-2.25 2.25a.75.75 0 0 1-1.06-1.06l1.72-1.72-1.72-1.72a.75.75 0 0 1 0-1.06Zm4.28 4.28a.75.75 0 0 0 0 1.5h3a.75.75 0 0 0 0-1.5h-3Z"
+		clip-rule="evenodd"
+	/>
+</svg>