enh: code interpreter toggle

This commit is contained in:
Timothy Jaeryang Baek 2025-02-03 01:14:38 -08:00
parent ca4b839e6d
commit 95c6d0e78c
8 changed files with 79 additions and 2 deletions

View File

@ -1317,6 +1317,20 @@ Your task is to synthesize these responses into a single, high-quality response.
Responses from models: {{responses}}""" 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 # Vector Database
#################################### ####################################

View File

@ -57,6 +57,7 @@ from open_webui.utils.task import (
from open_webui.utils.misc import ( from open_webui.utils.misc import (
get_message_list, get_message_list,
add_or_update_system_message, add_or_update_system_message,
add_or_update_user_message,
get_last_user_message, get_last_user_message,
get_last_assistant_message, get_last_assistant_message,
prepend_to_first_user_message_content, 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.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 ( from open_webui.env import (
SRC_LOG_LEVELS, SRC_LOG_LEVELS,
GLOBAL_LOG_LEVEL, GLOBAL_LOG_LEVEL,
@ -776,6 +780,11 @@ async def process_chat_payload(request, form_data, metadata, user, model):
request, form_data, extra_params, user 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: try:
form_data, flags = await chat_completion_filter_functions_handler( form_data, flags = await chat_completion_filter_functions_handler(
request, form_data, model, extra_params request, form_data, model, extra_params
@ -1359,7 +1368,7 @@ async def process_chat_response(
and retries < MAX_RETRIES and retries < MAX_RETRIES
): ):
retries += 1 retries += 1
log.debug(f"Retrying code interpreter block: {retries}") log.debug(f"Attempt count: {retries}")
try: try:
if content_blocks[-1]["attributes"].get("type") == "code": if content_blocks[-1]["attributes"].get("type") == "code":

View File

@ -131,6 +131,25 @@ def add_or_update_system_message(content: str, messages: list[dict]):
return messages 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]): def append_or_update_assistant_message(content: str, messages: list[dict]):
""" """
Adds a new assistant message at the end of the messages list Adds a new assistant message at the end of the messages list

View File

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

View File

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

View File

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

View File

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

View File

@ -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>