Skip to content

Commit 9c69b02

Browse files
committed
fix: throttle streaming renders via rAF batching
- Batch Svelte reactivity triggers during streaming to ~60fps using requestAnimationFrame, reducing rendering overhead for fast models - Throttle TTS content parsing to every 150ms instead of every token - Remove per-token console.log, await tick(), and scrollToBottom calls - Keep immediate rendering for done events and non-streaming events
1 parent 4251eaf commit 9c69b02

1 file changed

Lines changed: 65 additions & 50 deletions

File tree

src/lib/components/chat/Chat.svelte

Lines changed: 65 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@
154154
155155
let taskIds = null;
156156
157+
// Streaming render state
158+
let renderRafId = null;
159+
let lastTtsProcessTime = 0;
160+
157161
// Chat Input
158162
let prompt = '';
159163
let chatFiles = [];
@@ -382,8 +386,6 @@
382386
};
383387
384388
const chatEventHandler = async (event, cb) => {
385-
console.log(event);
386-
387389
if (event.chat_id === $chatId) {
388390
await tick();
389391
let message = history.messages[event.message_id];
@@ -508,7 +510,21 @@
508510
console.log('Unknown message type', data);
509511
}
510512
511-
history.messages[event.message_id] = message;
513+
// Batch reactivity updates to animation frame rate during streaming
514+
if (type === 'chat:completion' && !data?.done) {
515+
if (!renderRafId) {
516+
const msgId = event.message_id;
517+
renderRafId = requestAnimationFrame(() => {
518+
renderRafId = null;
519+
history.messages[msgId] = history.messages[msgId];
520+
if (autoScroll) {
521+
scrollToBottom();
522+
}
523+
});
524+
}
525+
} else {
526+
history.messages[event.message_id] = message;
527+
}
512528
}
513529
}
514530
};
@@ -1479,27 +1495,31 @@
14791495
navigator.vibrate(5);
14801496
}
14811497
1482-
// Emit chat event for TTS
1483-
const messageContentParts = getMessageContentParts(
1484-
removeAllDetails(message.content),
1485-
$config?.audio?.tts?.split_on ?? 'punctuation'
1486-
);
1487-
messageContentParts.pop();
1498+
// Throttle TTS processing
1499+
const now = Date.now();
1500+
if (now - lastTtsProcessTime >= 150) {
1501+
lastTtsProcessTime = now;
14881502
1489-
// dispatch only last sentence and make sure it hasn't been dispatched before
1490-
if (
1491-
messageContentParts.length > 0 &&
1492-
messageContentParts[messageContentParts.length - 1] !== message.lastSentence
1493-
) {
1494-
message.lastSentence = messageContentParts[messageContentParts.length - 1];
1495-
eventTarget.dispatchEvent(
1496-
new CustomEvent('chat', {
1497-
detail: {
1498-
id: message.id,
1499-
content: messageContentParts[messageContentParts.length - 1]
1500-
}
1501-
})
1503+
const messageContentParts = getMessageContentParts(
1504+
removeAllDetails(message.content),
1505+
$config?.audio?.tts?.split_on ?? 'punctuation'
15021506
);
1507+
messageContentParts.pop();
1508+
1509+
if (
1510+
messageContentParts.length > 0 &&
1511+
messageContentParts[messageContentParts.length - 1] !== message.lastSentence
1512+
) {
1513+
message.lastSentence = messageContentParts[messageContentParts.length - 1];
1514+
eventTarget.dispatchEvent(
1515+
new CustomEvent('chat', {
1516+
detail: {
1517+
id: message.id,
1518+
content: messageContentParts[messageContentParts.length - 1]
1519+
}
1520+
})
1521+
);
1522+
}
15031523
}
15041524
}
15051525
}
@@ -1513,27 +1533,31 @@
15131533
navigator.vibrate(5);
15141534
}
15151535
1516-
// Emit chat event for TTS
1517-
const messageContentParts = getMessageContentParts(
1518-
removeAllDetails(message.content),
1519-
$config?.audio?.tts?.split_on ?? 'punctuation'
1520-
);
1521-
messageContentParts.pop();
1536+
// Throttle TTS processing
1537+
const now = Date.now();
1538+
if (now - lastTtsProcessTime >= 150) {
1539+
lastTtsProcessTime = now;
15221540
1523-
// dispatch only last sentence and make sure it hasn't been dispatched before
1524-
if (
1525-
messageContentParts.length > 0 &&
1526-
messageContentParts[messageContentParts.length - 1] !== message.lastSentence
1527-
) {
1528-
message.lastSentence = messageContentParts[messageContentParts.length - 1];
1529-
eventTarget.dispatchEvent(
1530-
new CustomEvent('chat', {
1531-
detail: {
1532-
id: message.id,
1533-
content: messageContentParts[messageContentParts.length - 1]
1534-
}
1535-
})
1541+
const messageContentParts = getMessageContentParts(
1542+
removeAllDetails(message.content),
1543+
$config?.audio?.tts?.split_on ?? 'punctuation'
15361544
);
1545+
messageContentParts.pop();
1546+
1547+
if (
1548+
messageContentParts.length > 0 &&
1549+
messageContentParts[messageContentParts.length - 1] !== message.lastSentence
1550+
) {
1551+
message.lastSentence = messageContentParts[messageContentParts.length - 1];
1552+
eventTarget.dispatchEvent(
1553+
new CustomEvent('chat', {
1554+
detail: {
1555+
id: message.id,
1556+
content: messageContentParts[messageContentParts.length - 1]
1557+
}
1558+
})
1559+
);
1560+
}
15371561
}
15381562
}
15391563
@@ -1546,8 +1570,6 @@
15461570
message.usage = usage;
15471571
}
15481572
1549-
history.messages[message.id] = message;
1550-
15511573
if (done) {
15521574
message.done = true;
15531575
@@ -1596,13 +1618,6 @@
15961618
createMessagesList(history, message.id)
15971619
);
15981620
}
1599-
1600-
console.log(data);
1601-
await tick();
1602-
1603-
if (autoScroll) {
1604-
scrollToBottom();
1605-
}
16061621
};
16071622
16081623
//////////////////////////

0 commit comments

Comments
 (0)