Skip to content

Commit 4afb30c

Browse files
committed
refactor: render from output and derive content at save
1 parent 5822c6d commit 4afb30c

4 files changed

Lines changed: 465 additions & 17 deletions

File tree

backend/open_webui/utils/middleware.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3422,13 +3422,20 @@ async def outlet_filter_handler(ctx):
34223422
outlet_message_id = message.get('id')
34233423
if outlet_message_id and outlet_message_id in messages_map:
34243424
original_message = messages_map[outlet_message_id]
3425-
if original_message.get('content') != message.get('content'):
3425+
content_changed = original_message.get('content') != message.get('content')
3426+
output_changed = message.get('output') and message.get('output') != original_message.get('output')
3427+
if content_changed or output_changed:
3428+
# If output was modified, re-derive content from it
3429+
new_content = message.get('content', original_message.get('content', ''))
3430+
if output_changed:
3431+
new_content = serialize_output(message['output'])
34263432
await Chats.upsert_message_to_chat_by_id_and_message_id(
34273433
chat_id,
34283434
outlet_message_id,
34293435
{
3430-
'content': message['content'],
3436+
'content': new_content,
34313437
'originalContent': original_message.get('content'),
3438+
**({'output': message['output']} if output_changed else {}),
34323439
},
34333440
)
34343441

@@ -4069,7 +4076,6 @@ async def flush_pending_delta_data(threshold: int = 0):
40694076

40704077
processed_data = {
40714078
'output': full_output(),
4072-
'content': serialize_output(full_output()),
40734079
}
40744080

40754081
# print(data)

src/lib/components/chat/Chat.svelte

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1805,6 +1805,12 @@
18051805
message.output = output;
18061806
}
18071807
1808+
// When the response is done and content is provided, set it for copy/TTS
1809+
// (the frontend renders from output during streaming, content is the final cache)
1810+
if (done && content) {
1811+
message.content = content;
1812+
}
1813+
18081814
if (error) {
18091815
await handleOpenAIError(error, message);
18101816
}
@@ -1813,7 +1819,9 @@
18131819
message.sources = sources;
18141820
}
18151821
1816-
if (choices) {
1822+
// Only accumulate content from choices when there's no structured output
1823+
// (output-based rendering takes priority — avoids redundant serialize/parse round-trip)
1824+
if (choices && !output) {
18171825
if (choices[0]?.message?.content) {
18181826
// Non-stream response
18191827
message.content += choices[0]?.message?.content;

0 commit comments

Comments
 (0)