diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index a5f848b62..19e949e88 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -311,6 +311,11 @@ RESET_CONFIG_ON_START = ( os.environ.get("RESET_CONFIG_ON_START", "False").lower() == "true" ) + +ENABLE_REALTIME_CHAT_SAVE = ( + os.environ.get("ENABLE_REALTIME_CHAT_SAVE", "True").lower() == "true" +) + #################################### # REDIS #################################### diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 7d79e1d0b..bb6c56a3b 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -65,6 +65,7 @@ from open_webui.env import ( SRC_LOG_LEVELS, GLOBAL_LOG_LEVEL, BYPASS_MODEL_ACCESS_CONTROL, + ENABLE_REALTIME_CHAT_SAVE, ) from open_webui.constants import TASKS @@ -928,6 +929,10 @@ async def process_chat_response( # Handle as a background task async def post_response_handler(response, events): + + assistant_message = get_last_assistant_message(form_data["messages"]) + content = assistant_message if assistant_message else "" + try: for event in events: await event_emitter( @@ -946,9 +951,6 @@ async def process_chat_response( }, ) - assistant_message = get_last_assistant_message(form_data["messages"]) - content = assistant_message if assistant_message else "" - async for line in response.body_iterator: line = line.decode("utf-8") if isinstance(line, bytes) else line data = line @@ -977,7 +979,6 @@ async def process_chat_response( ) else: - value = ( data.get("choices", [])[0] .get("delta", {}) @@ -987,6 +988,28 @@ async def process_chat_response( if value: content = f"{content}{value}" + if ENABLE_REALTIME_CHAT_SAVE: + # Save message in the database + Chats.upsert_message_to_chat_by_id_and_message_id( + metadata["chat_id"], + metadata["message_id"], + { + "content": content, + }, + ) + else: + data = { + "content": content, + } + + except Exception as e: + done = "data: [DONE]" in line + title = Chats.get_chat_title_by_id(metadata["chat_id"]) + + if done: + data = {"done": True, "content": content, "title": title} + + if not ENABLE_REALTIME_CHAT_SAVE: # Save message in the database Chats.upsert_message_to_chat_by_id_and_message_id( metadata["chat_id"], @@ -996,13 +1019,6 @@ async def process_chat_response( }, ) - except Exception as e: - done = "data: [DONE]" in line - title = Chats.get_chat_title_by_id(metadata["chat_id"]) - - if done: - data = {"done": True, "content": content, "title": title} - # Send a webhook notification if the user is not active if ( get_user_id_from_session_pool(metadata["session_id"]) @@ -1036,6 +1052,16 @@ async def process_chat_response( print("Task was cancelled!") await event_emitter({"type": "task-cancelled"}) + if not ENABLE_REALTIME_CHAT_SAVE: + # Save message in the database + Chats.upsert_message_to_chat_by_id_and_message_id( + metadata["chat_id"], + metadata["message_id"], + { + "content": content, + }, + ) + if response.background is not None: await response.background() diff --git a/src/lib/components/channel/Messages.svelte b/src/lib/components/channel/Messages.svelte index 3614263a1..deb2d93fb 100644 --- a/src/lib/components/channel/Messages.svelte +++ b/src/lib/components/channel/Messages.svelte @@ -66,7 +66,7 @@ {($settings?.widescreenMode ?? null) ? 'max-w-full' : 'max-w-5xl'} mx-auto" > {#if channel} -
+
{channel.name}
diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 9bec3934d..6c3d610ad 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -1053,7 +1053,7 @@ }; const chatCompletionEventHandler = async (data, message, chatId) => { - const { id, done, choices, sources, selected_model_id, error, usage } = data; + const { id, done, choices, content, sources, selected_model_id, error, usage } = data; if (error) { await handleOpenAIError(error, message); @@ -1105,6 +1105,38 @@ } } + if (content) { + // REALTIME_CHAT_SAVE is disabled + message.content = content; + + if (navigator.vibrate && ($settings?.hapticFeedback ?? false)) { + navigator.vibrate(5); + } + + // Emit chat event for TTS + const messageContentParts = getMessageContentParts( + message.content, + $config?.audio?.tts?.split_on ?? 'punctuation' + ); + messageContentParts.pop(); + + // dispatch only last sentence and make sure it hasn't been dispatched before + if ( + messageContentParts.length > 0 && + messageContentParts[messageContentParts.length - 1] !== message.lastSentence + ) { + message.lastSentence = messageContentParts[messageContentParts.length - 1]; + eventTarget.dispatchEvent( + new CustomEvent('chat', { + detail: { + id: message.id, + content: messageContentParts[messageContentParts.length - 1] + } + }) + ); + } + } + if (selected_model_id) { message.selectedModelId = selected_model_id; message.arena = true; diff --git a/src/lib/components/common/SVGPanZoom.svelte b/src/lib/components/common/SVGPanZoom.svelte index 9a2b0fd6e..08f620d62 100644 --- a/src/lib/components/common/SVGPanZoom.svelte +++ b/src/lib/components/common/SVGPanZoom.svelte @@ -29,12 +29,12 @@ zoomSpeed: 0.065 }); } - function resetPanZoomViewport() { - console.log('Reset View'); - instance.moveTo(0, 0); - instance.zoomAbs(0, 0, 1); - console.log(instance.getTransform()); - } +function resetPanZoomViewport() { + console.log('Reset View'); + instance.moveTo(0, 0); + instance.zoomAbs(0, 0, 1); + console.log(instance.getTransform()); +}
diff --git a/src/lib/components/icons/Reset.svelte b/src/lib/components/icons/Reset.svelte index c1263fd38..f57a6aaa2 100644 --- a/src/lib/components/icons/Reset.svelte +++ b/src/lib/components/icons/Reset.svelte @@ -2,8 +2,8 @@ export let className = 'size-4'; - - - + + + \ No newline at end of file diff --git a/update_ollama_models.sh b/update_ollama_models.sh old mode 100644 new mode 100755