This commit is contained in:
Timothy Jaeryang Baek committed 2026-07-27 02:23:33 -04:00
1 parent 2e4c232807
commit 498cdab9a5
2 files changed
+21 -6

No files matched your search

+8 -5
View File
@@ -39,6 +39,7 @@ from open_webui.tasks import create_task, stop_item_tasks
from open_webui.utils.access_control import has_permission from open_webui.utils.access_control import has_permission
from open_webui.utils.auth import get_verified_user_by_token from open_webui.utils.auth import get_verified_user_by_token
from open_webui.utils.chat_id import is_saved_chat_id from open_webui.utils.chat_id import is_saved_chat_id
from open_webui.utils.misc import get_output_text
from open_webui.utils.redis import ( from open_webui.utils.redis import (
build_sentinel_url, build_sentinel_url,
get_redis_connection, get_redis_connection,
@@ -903,19 +904,20 @@ async def _make_channel_emitter(request_info):
state = {'last_emit_at': 0.0} state = {'last_emit_at': 0.0}
THROTTLE_INTERVAL = 0.15 # ~6 updates/sec THROTTLE_INTERVAL = 0.15 # ~6 updates/sec
async def _emit_channel_update(content: str, done: bool = False): async def _emit_channel_update(content: str, done: bool = False, output: list | None = None):
from open_webui.models.messages import MessageForm, Messages from open_webui.models.messages import MessageForm, Messages
msg = await Messages.get_message_by_id(message_id) msg = await Messages.get_message_by_id(message_id)
if not msg or msg.channel_id != channel_id: if not msg or msg.channel_id != channel_id:
return return
update_form = MessageForm(content=content) update_form = MessageForm(content=content, data={'output': output} if output else None)
if done: if done:
# Merge done flag into existing meta (preserve model_id etc.) # Merge done flag into existing meta (preserve model_id etc.)
existing_meta = msg.meta or {} existing_meta = msg.meta or {}
update_form = MessageForm( update_form = MessageForm(
content=content, content=content,
data={'output': output} if output else None,
meta={**existing_meta, 'done': True}, meta={**existing_meta, 'done': True},
) )
@@ -940,16 +942,17 @@ async def _make_channel_emitter(request_info):
if event_type == 'chat:completion': if event_type == 'chat:completion':
data = event_data.get('data', {}) data = event_data.get('data', {})
content = data.get('content', '') output = data.get('output')
content = data.get('content') or get_output_text(output)
done = data.get('done', False) done = data.get('done', False)
if not content and not done: if not content and not output and not done:
return return
now = __import__('time').time() now = __import__('time').time()
if done or (now - state['last_emit_at']) >= THROTTLE_INTERVAL: if done or (now - state['last_emit_at']) >= THROTTLE_INTERVAL:
state['last_emit_at'] = now state['last_emit_at'] = now
await _emit_channel_update(content, done) await _emit_channel_update(content, done, output if isinstance(output, list) else None)
elif event_type == 'chat:message:error': elif event_type == 'chat:message:error':
error = event_data.get('data', {}).get('error', {}) error = event_data.get('data', {}).get('error', {})
@@ -20,6 +20,8 @@
import { getMessageData } from '$lib/apis/channels'; import { getMessageData } from '$lib/apis/channels';
import Markdown from '$lib/components/chat/Messages/Markdown.svelte'; import Markdown from '$lib/components/chat/Messages/Markdown.svelte';
import StructuredOutputRenderer from '$lib/components/chat/Messages/StructuredOutputRenderer.svelte';
import { buildOutputDisplayItems } from '$lib/components/chat/Messages/structuredOutput';
import ProfileImage from '$lib/components/chat/Messages/ProfileImage.svelte'; import ProfileImage from '$lib/components/chat/Messages/ProfileImage.svelte';
import Name from '$lib/components/chat/Messages/Name.svelte'; import Name from '$lib/components/chat/Messages/Name.svelte';
import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte'; import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
@@ -149,6 +151,9 @@
await loadMessageData(); await loadMessageData();
} }
}); });
$: messageOutput = Array.isArray(message?.data?.output) ? message.data.output : [];
$: hasStructuredOutput = buildOutputDisplayItems(messageOutput).length > 0;
</script> </script>
<ConfirmDialog <ConfirmDialog
@@ -526,7 +531,14 @@
</div> </div>
{:else} {:else}
<div class="min-w-full {pending ? 'opacity-50' : ''}"> <div class="min-w-full {pending ? 'opacity-50' : ''}">
{#if (message?.content ?? '').trim() === '' && message?.meta?.model_id} {#if hasStructuredOutput}
<StructuredOutputRenderer
id={renderedMessageId}
output={messageOutput}
done={message?.meta?.done ?? false}
editCodeBlock={false}
/>
{:else if (message?.content ?? '').trim() === '' && message?.meta?.model_id}
<Skeleton /> <Skeleton />
{:else} {:else}
<span class="markdown-prose"> <span class="markdown-prose">