Skip to content

Commit 7fe2ade

Browse files
authored
Improve AI message streaming and error handling
Refactor AI message handling and error streaming.
1 parent 7fad795 commit 7fe2ade

1 file changed

Lines changed: 47 additions & 3 deletions

File tree

src/main.js

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,8 @@ class AIAssistant {
400400
const sendBtn = app.querySelector(".ai-send-btn");
401401
if (sendBtn) sendBtn.innerHTML = stopIconSvg;
402402

403+
let aiMessageElement = null;
404+
403405
try {
404406
const settings = await this.getSettings();
405407
if (!settings.apiKey || !settings.baseUrl || !settings.model) {
@@ -408,11 +410,11 @@ class AIAssistant {
408410
return;
409411
}
410412

411-
const aiMessageElement = this.addMessageToChat("assistant", "", app);
413+
aiMessageElement = this.addMessageToChat("assistant", "", app);
412414

413415
let response = await this.callAI(message, settings);
414416

415-
this.updateMessage(aiMessageElement, response, app);
417+
await this.streamMessage(aiMessageElement, response, app, false);
416418

417419
const chatAreaAfter = app.querySelector("#ai-chat-area");
418420
if (chatAreaAfter) {
@@ -434,8 +436,12 @@ class AIAssistant {
434436

435437
this.saveSession().catch((e) => console.error("saveSession error:", e));
436438
} catch (error) {
439+
const errMsg = "Error: " + (error && error.message ? error.message : String(error));
440+
if (!aiMessageElement) {
441+
aiMessageElement = this.addMessageToChat("assistant", "", app);
442+
}
443+
await this.streamMessage(aiMessageElement, errMsg, app, true);
437444
console.error("Error generating response:", error);
438-
window.toast("Error generating response: " + (error && error.message ? error.message : error), 3000);
439445
} finally {
440446
this.isGenerating = false;
441447
if (sendBtn) sendBtn.innerHTML = sendIconSvg;
@@ -472,6 +478,44 @@ class AIAssistant {
472478
return messageContent;
473479
}
474480

481+
async streamMessage(element, content, app, isError) {
482+
if (!element) return;
483+
const text = String(content || "");
484+
element.classList.remove("ai-error");
485+
element.innerHTML = "";
486+
element.textContent = "";
487+
if (isError) element.classList.add("ai-error");
488+
const total = text.length;
489+
let i = 0;
490+
const large = total > 2000;
491+
const chunk = large ? 8 : 1;
492+
const delay = large ? 20 : 18;
493+
while (i < total) {
494+
const part = text.slice(i, i + chunk);
495+
element.textContent = element.textContent + part;
496+
i += chunk;
497+
await new Promise((r) => setTimeout(r, delay));
498+
const chatArea = app && app.querySelector ? app.querySelector("#ai-chat-area") : null;
499+
if (chatArea) {
500+
requestAnimationFrame(() => {
501+
chatArea.scrollTop = chatArea.scrollHeight;
502+
});
503+
}
504+
}
505+
if (!isError && window.markdownit) {
506+
element.innerHTML = this.formatAIResponse(element.textContent);
507+
this.highlightCode(app);
508+
} else {
509+
element.innerHTML = String(element.textContent).replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/g, "<br>");
510+
}
511+
const chatAreaFinal = app && app.querySelector ? app.querySelector("#ai-chat-area") : null;
512+
if (chatAreaFinal) {
513+
requestAnimationFrame(() => {
514+
chatAreaFinal.scrollTop = chatAreaFinal.scrollHeight;
515+
});
516+
}
517+
}
518+
475519
updateMessage(element, content, app) {
476520
if (!element) return;
477521
element.innerHTML = this.formatAIResponse(content);

0 commit comments

Comments
 (0)