Browse Source

Merge branch 'dev' into playwright

Rory 3 months ago
parent
commit
93cc1a88ee

+ 1 - 1
backend/open_webui/constants.py

@@ -57,7 +57,7 @@ class ERROR_MESSAGES(str, Enum):
     )
 
     FILE_NOT_SENT = "FILE_NOT_SENT"
-    FILE_NOT_SUPPORTED = "Oops! It seems like the file format you're trying to upload is not supported. Please upload a file with a supported format (e.g., JPG, PNG, PDF, TXT) and try again."
+    FILE_NOT_SUPPORTED = "Oops! It seems like the file format you're trying to upload is not supported. Please upload a file with a supported format and try again."
 
     NOT_FOUND = "We could not find what you're looking for :/"
     USER_NOT_FOUND = "We could not find what you're looking for :/"

+ 22 - 4
backend/open_webui/utils/middleware.py

@@ -1101,9 +1101,15 @@ async def process_chat_response(
                         reasoning_duration = block.get("duration", None)
 
                         if reasoning_duration:
-                            content = f'{content}<details type="reasoning" done="true" duration="{reasoning_duration}">\n<summary>Thought for {reasoning_duration} seconds</summary>\n{reasoning_display_content}\n</details>\n'
+                            if raw:
+                                content = f'{content}<{block["tag"]}>{block["content"]}</{block["tag"]}>\n'
+                            else:
+                                content = f'{content}<details type="reasoning" done="true" duration="{reasoning_duration}">\n<summary>Thought for {reasoning_duration} seconds</summary>\n{reasoning_display_content}\n</details>\n'
                         else:
-                            content = f'{content}<details type="reasoning" done="false">\n<summary>Thinking…</summary>\n{reasoning_display_content}\n</details>\n'
+                            if raw:
+                                content = f'{content}<{block["tag"]}>{block["content"]}</{block["tag"]}>\n'
+                            else:
+                                content = f'{content}<details type="reasoning" done="false">\n<summary>Thinking…</summary>\n{reasoning_display_content}\n</details>\n'
 
                     elif block["type"] == "code_interpreter":
                         attributes = block.get("attributes", {})
@@ -1114,11 +1120,14 @@ async def process_chat_response(
                             output = html.escape(json.dumps(output))
 
                             if raw:
-                                content = f'{content}<details type="code_interpreter" done="true" output="{output}">\n<summary>Analyzed</summary>\n```{lang}\n{block["content"]}\n```\n```output\n{output}\n```\n</details>\n'
+                                content = f'{content}<code_interpreter type="code" lang="{lang}">\n{block["content"]}\n</code_interpreter>\n```output\n{output}\n```\n'
                             else:
                                 content = f'{content}<details type="code_interpreter" done="true" output="{output}">\n<summary>Analyzed</summary>\n```{lang}\n{block["content"]}\n```\n</details>\n'
                         else:
-                            content = f'{content}<details type="code_interpreter" done="false">\n<summary>Analyzing...</summary>\n```{lang}\n{block["content"]}\n```\n</details>\n'
+                            if raw:
+                                content = f'{content}<code_interpreter type="code" lang="{lang}">\n{block["content"]}\n</code_interpreter>\n'
+                            else:
+                                content = f'{content}<details type="code_interpreter" done="false">\n<summary>Analyzing...</summary>\n```{lang}\n{block["content"]}\n```\n</details>\n'
 
                     else:
                         block_content = str(block["content"]).strip()
@@ -1349,6 +1358,15 @@ async def process_chat_response(
                         if not content_blocks[-1]["content"]:
                             content_blocks.pop()
 
+                    await event_emitter(
+                        {
+                            "type": "chat:completion",
+                            "data": {
+                                "content": serialize_content_blocks(content_blocks),
+                            },
+                        }
+                    )
+
                     if response.background:
                         await response.background()
 

+ 12 - 12
src/lib/components/chat/Chat.svelte

@@ -45,7 +45,7 @@
 		promptTemplate,
 		splitStream,
 		sleep,
-		removeDetailsWithReasoning,
+		removeDetails,
 		getPromptVariables
 	} from '$lib/utils';
 
@@ -1338,8 +1338,17 @@
 		parentId: string,
 		{ modelId = null, modelIdx = null, newChat = false } = {}
 	) => {
-		const _chatId = JSON.parse(JSON.stringify($chatId));
+		// If modelId is provided, use it, else use selected model
+		let selectedModelIds = modelId
+			? [modelId]
+			: atSelectedModel !== undefined
+				? [atSelectedModel.id]
+				: selectedModels;
+
+		// Create response messages for each selected model
+		const responseMessageIds: Record<PropertyKey, string> = {};
 
+		const _chatId = JSON.parse(JSON.stringify($chatId));
 		// Create new chat if newChat is true and first user message
 		if (
 			newChat &&
@@ -1351,15 +1360,6 @@
 			await saveChatHandler(_chatId);
 		}
 
-		// If modelId is provided, use it, else use selected model
-		let selectedModelIds = modelId
-			? [modelId]
-			: atSelectedModel !== undefined
-				? [atSelectedModel.id]
-				: selectedModels;
-
-		// Create response messages for each selected model
-		const responseMessageIds: Record<PropertyKey, string> = {};
 		for (const [_modelIdx, modelId] of selectedModelIds.entries()) {
 			const model = $models.filter((m) => m.id === modelId).at(0);
 
@@ -1515,7 +1515,7 @@
 				: undefined,
 			...createMessagesList(history, responseMessageId).map((message) => ({
 				...message,
-				content: removeDetailsWithReasoning(message.content)
+				content: removeDetails(message.content, ['reasoning', 'code_interpreter'])
 			}))
 		]
 			.filter((message) => message?.content?.trim())

+ 10 - 3
src/lib/utils/index.ts

@@ -668,8 +668,15 @@ export const cleanText = (content: string) => {
 	return removeFormattings(removeEmojis(content.trim()));
 };
 
-export const removeDetailsWithReasoning = (content) => {
-	return content.replace(/<details\s+type="reasoning"[^>]*>.*?<\/details>/gis, '').trim();
+export const removeDetails = (content, types) => {
+	for (const type of types) {
+		content = content.replace(
+			new RegExp(`<details\\s+type="${type}"[^>]*>.*?<\\/details>`, 'gis'),
+			''
+		);
+	}
+
+	return content;
 };
 
 // This regular expression matches code blocks marked by triple backticks
@@ -741,7 +748,7 @@ export const extractSentencesForAudio = (text: string) => {
 };
 
 export const getMessageContentParts = (content: string, split_on: string = 'punctuation') => {
-	content = removeDetailsWithReasoning(content);
+	content = removeDetails(content, ['reasoning', 'code_interpreter']);
 	const messageContentParts: string[] = [];
 
 	switch (split_on) {