Skip to content

Commit

Permalink
Merge pull request open-webui#9445 from open-webui/dev
Browse files Browse the repository at this point in the history
0.5.10
  • Loading branch information
tjbck authored Feb 5, 2025
2 parents ab94468 + b8fe949 commit e9d6ada
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 68 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.5.10] - 2025-02-05

### Fixed

- **⚙️ System Prompts Now Properly Templated via API**: Resolved an issue where system prompts were not being correctly processed when used through the API, ensuring template variables now function as expected.
- **📝 '<thinking>' Tag Display Issue Fixed**: Fixed a bug where the 'thinking' tag was disrupting content rendering, ensuring clean and accurate text display.
- **💻 Code Interpreter Stability with Custom Functions**: Addressed failures when using the Code Interpreter with certain custom functions like Anthropic, ensuring smoother execution and better compatibility.

## [0.5.9] - 2025-02-05

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion backend/open_webui/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1337,7 +1337,7 @@ class BannerModel(BaseModel):
- 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.
- If a link is provided for an image, audio, or any file, include it in the response exactly as given to ensure the user has access to the original resource.
- All responses should be communicated in the chat's primary language, ensuring seamless understanding. If the chat is multilingual, default to English for clarity.
- **If a link to an image, audio, or any file is provided in markdown format, explicitly display it as part of the response to ensure the user can access it easily, do NOT change the link.**
- **If a link to an image, audio, or any file is provided in markdown format, ALWAYS regurgitate explicitly display it as part of the response to ensure the user can access it easily, do NOT change the link.**
Ensure that the tools are effectively utilized to achieve the highest-quality analysis for the user."""

Expand Down
2 changes: 1 addition & 1 deletion backend/open_webui/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def get_function_params(function_module, form_data, user, extra_params=None):

params = model_info.params.model_dump()
form_data = apply_model_params_to_body_openai(params, form_data)
form_data = apply_model_system_prompt_to_body(params, form_data, user)
form_data = apply_model_system_prompt_to_body(params, form_data, metadata, user)

pipe_id = get_pipe_id(form_data)
function_module = get_function_module_by_id(request, pipe_id)
Expand Down
6 changes: 4 additions & 2 deletions backend/open_webui/routers/ollama.py
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,7 @@ async def generate_chat_completion(
payload["options"] = apply_model_params_to_body_ollama(
params, payload["options"]
)
payload = apply_model_system_prompt_to_body(params, payload, metadata)
payload = apply_model_system_prompt_to_body(params, payload, metadata, user)

# Check if user has access to the model
if not bypass_filter and user.role == "user":
Expand Down Expand Up @@ -1160,6 +1160,8 @@ async def generate_openai_chat_completion(
url_idx: Optional[int] = None,
user=Depends(get_verified_user),
):
metadata = form_data.pop("metadata", None)

try:
completion_form = OpenAIChatCompletionForm(**form_data)
except Exception as e:
Expand All @@ -1186,7 +1188,7 @@ async def generate_openai_chat_completion(

if params:
payload = apply_model_params_to_body_openai(params, payload)
payload = apply_model_system_prompt_to_body(params, payload, user)
payload = apply_model_system_prompt_to_body(params, payload, metadata, user)

# Check if user has access to the model
if user.role == "user":
Expand Down
2 changes: 1 addition & 1 deletion backend/open_webui/routers/openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ async def generate_chat_completion(

params = model_info.params.model_dump()
payload = apply_model_params_to_body_openai(params, payload)
payload = apply_model_system_prompt_to_body(params, payload, metadata)
payload = apply_model_system_prompt_to_body(params, payload, metadata, user)

# Check if user has access to the model
if not bypass_filter and user.role == "user":
Expand Down
76 changes: 61 additions & 15 deletions backend/open_webui/utils/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -1172,7 +1172,7 @@ def serialize_content_blocks(content_blocks, raw=False):

reasoning_duration = block.get("duration", None)

if reasoning_duration:
if reasoning_duration is not None:
if raw:
content = f'{content}\n<{block["tag"]}>{block["content"]}</{block["tag"]}>\n'
else:
Expand Down Expand Up @@ -1205,14 +1205,16 @@ def serialize_content_blocks(content_blocks, raw=False):
block_content = str(block["content"]).strip()
content = f"{content}{block['type']}: {block_content}\n"

return content
return content.strip()

def tag_content_handler(content_type, tags, content, content_blocks):
end_flag = False

def extract_attributes(tag_content):
"""Extract attributes from a tag if they exist."""
attributes = {}
if not tag_content: # Ensure tag_content is not None
return attributes
# Match attributes in the format: key="value" (ignores single quotes for simplicity)
matches = re.findall(r'(\w+)\s*=\s*"([^"]+)"', tag_content)
for key, value in matches:
Expand All @@ -1222,16 +1224,32 @@ def extract_attributes(tag_content):
if content_blocks[-1]["type"] == "text":
for tag in tags:
# Match start tag e.g., <tag> or <tag attr="value">
start_tag_pattern = rf"<{tag}(.*?)>"
start_tag_pattern = rf"<{tag}(\s.*?)?>"
match = re.search(start_tag_pattern, content)
if match:
# Extract attributes in the tag (if present)
attributes = extract_attributes(match.group(1))
attr_content = (
match.group(1) if match.group(1) else ""
) # Ensure it's not None
attributes = extract_attributes(
attr_content
) # Extract attributes safely

# Capture everything before and after the matched tag
before_tag = content[
: match.start()
] # Content before opening tag
after_tag = content[
match.end() :
] # Content after opening tag

# Remove the start tag from the currently handling text block
content_blocks[-1]["content"] = content_blocks[-1][
"content"
].replace(match.group(0), "")

if before_tag:
content_blocks[-1]["content"] = before_tag

if not content_blocks[-1]["content"]:
content_blocks.pop()

Expand All @@ -1245,12 +1263,17 @@ def extract_attributes(tag_content):
"started_at": time.time(),
}
)

if after_tag:
content_blocks[-1]["content"] = after_tag

break
elif content_blocks[-1]["type"] == content_type:
tag = content_blocks[-1]["tag"]
# Match end tag e.g., </tag>
end_tag_pattern = rf"</{tag}>"

# Check if the content has the end tag
if re.search(end_tag_pattern, content):
end_flag = True

Expand All @@ -1274,23 +1297,32 @@ def extract_attributes(tag_content):
split_content[1].strip() if len(split_content) > 1 else ""
)

print(f"block_content: {block_content}")
print(f"leftover_content: {leftover_content}")

if block_content:
content_blocks[-1]["content"] = block_content
content_blocks[-1]["ended_at"] = time.time()
content_blocks[-1]["duration"] = int(
content_blocks[-1]["ended_at"]
- content_blocks[-1]["started_at"]
)

# Reset the content_blocks by appending a new text block
content_blocks.append(
{
"type": "text",
"content": leftover_content,
}
)
if content_type != "code_interpreter":
if leftover_content:

content_blocks.append(
{
"type": "text",
"content": leftover_content,
}
)
else:
content_blocks.append(
{
"type": "text",
"content": "",
}
)

else:
# Remove the block if content is empty
content_blocks.pop()
Expand All @@ -1302,6 +1334,13 @@ def extract_attributes(tag_content):
"content": leftover_content,
}
)
else:
content_blocks.append(
{
"type": "text",
"content": "",
}
)

# Clean processed content
content = re.sub(
Expand Down Expand Up @@ -1332,7 +1371,14 @@ def extract_attributes(tag_content):
"code_interpreter", False
)

reasoning_tags = ["think", "reason", "reasoning", "thought", "Thought"]
reasoning_tags = [
"think",
"thinking",
"reason",
"reasoning",
"thought",
"Thought",
]
code_interpreter_tags = ["code_interpreter"]

try:
Expand Down
20 changes: 16 additions & 4 deletions backend/open_webui/utils/payload.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from open_webui.utils.task import prompt_variables_template
from open_webui.utils.task import prompt_template, prompt_variables_template
from open_webui.utils.misc import (
add_or_update_system_message,
)
Expand All @@ -8,16 +8,28 @@

# inplace function: form_data is modified
def apply_model_system_prompt_to_body(
params: dict, form_data: dict, metadata: Optional[dict] = None
params: dict, form_data: dict, metadata: Optional[dict] = None, user=None
) -> dict:
system = params.get("system", None)
if not system:
return form_data

# Legacy (API Usage)
if user:
template_params = {
"user_name": user.name,
"user_location": user.info.get("location") if user.info else None,
}
else:
template_params = {}

system = prompt_template(system, **template_params)

# Metadata (WebUI Usage)
if metadata:
print("apply_model_system_prompt_to_body: metadata", metadata)
variables = metadata.get("variables", {})
system = prompt_variables_template(system, variables)
if variables:
system = prompt_variables_template(system, variables)

form_data["messages"] = add_or_update_system_message(
system, form_data.get("messages", [])
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "open-webui",
"version": "0.5.9",
"version": "0.5.10",
"private": true,
"scripts": {
"dev": "npm run pyodide:fetch && vite dev --host",
Expand Down
Loading

0 comments on commit e9d6ada

Please sign in to comment.