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..a289b2c59 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 @@ -977,7 +978,6 @@ async def process_chat_response( ) else: - value = ( data.get("choices", [])[0] .get("delta", {}) @@ -987,6 +987,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 +1018,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"]) 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;