diff --git a/frontend/app/block/block.less b/frontend/app/block/block.less index 7151084aa..f3e172912 100644 --- a/frontend/app/block/block.less +++ b/frontend/app/block/block.less @@ -191,7 +191,7 @@ background-color: transparent; outline: none; border: none; - color: var(--app-text-color); + color: var(--main-text-color); width: 100%; white-space: nowrap; overflow: hidden; diff --git a/frontend/app/view/waveai/waveai.less b/frontend/app/view/waveai/waveai.less index 93d5911e7..ed2ed177c 100644 --- a/frontend/app/view/waveai/waveai.less +++ b/frontend/app/view/waveai/waveai.less @@ -51,7 +51,7 @@ } &.chat-msg-assistant { - color: var(--app-text-color); + color: var(--main-text-color); background-color: rgb(from var(--highlight-bg-color) r g b / 0.1); margin-right: auto; padding: 10px; @@ -77,9 +77,23 @@ } &.chat-msg-error { - color: var(--cmdinput-text-error); - font-family: var(--markdown-font); - font-size: 14px; + color: var(--main-text-color); + background-color: rgb(from var(--error-color) r g b / 0.25); + margin-right: auto; + padding: 10px; + max-width: 85%; + + .markdown { + width: 100%; + + pre { + white-space: pre-wrap; + word-break: break-word; + max-width: 100%; + overflow-x: auto; + margin-left: 0; + } + } } &.typing-indicator { diff --git a/frontend/app/view/waveai/waveai.tsx b/frontend/app/view/waveai/waveai.tsx index c29458bc2..5519b745d 100644 --- a/frontend/app/view/waveai/waveai.tsx +++ b/frontend/app/view/waveai/waveai.tsx @@ -20,9 +20,7 @@ interface ChatMessageType { id: string; user: string; text: string; - isAssistant: boolean; isUpdating?: boolean; - isError?: string; } const outline = "2px solid var(--accent-color)"; @@ -36,7 +34,6 @@ function promptToMsg(prompt: OpenAIPromptMessageType): ChatMessageType { id: crypto.randomUUID(), user: prompt.role, text: prompt.content, - isAssistant: prompt.role == "assistant", }; } @@ -78,7 +75,7 @@ export class WaveAiModel implements ViewModel { this.updateLastMessageAtom = atom(null, (get, set, text: string, isUpdating: boolean) => { const messages = get(this.messagesAtom); const lastMessage = messages[messages.length - 1]; - if (lastMessage.isAssistant && !lastMessage.isError) { + if (lastMessage.user == "assistant") { const updatedMessage = { ...lastMessage, text: lastMessage.text + text, isUpdating }; set(this.messagesAtom, [...messages.slice(0, -1), updatedMessage]); } @@ -94,7 +91,6 @@ export class WaveAiModel implements ViewModel { id: crypto.randomUUID(), user: "assistant", text: "", - isAssistant: true, }; // Add a typing indicator @@ -190,7 +186,6 @@ export class WaveAiModel implements ViewModel { id: crypto.randomUUID(), user, text, - isAssistant: false, }; addMessage(newMessage); // send message to backend and get response @@ -214,7 +209,6 @@ export class WaveAiModel implements ViewModel { id: crypto.randomUUID(), user: "assistant", text: "", - isAssistant: true, }; // Add a typing indicator @@ -225,25 +219,54 @@ export class WaveAiModel implements ViewModel { opts: opts, prompt: [...history, newPrompt], }; - const aiGen = RpcApi.StreamWaveAiCommand(WindowRpcClient, beMsg, { timeout: opts.timeoutms }); let fullMsg = ""; - for await (const msg of aiGen) { - fullMsg += msg.text ?? ""; - globalStore.set(this.updateLastMessageAtom, msg.text ?? "", true); - if (this.cancel) { - if (fullMsg == "") { - globalStore.set(this.removeLastMessageAtom); + try { + const aiGen = RpcApi.StreamWaveAiCommand(WindowRpcClient, beMsg, { timeout: opts.timeoutms }); + for await (const msg of aiGen) { + fullMsg += msg.text ?? ""; + globalStore.set(this.updateLastMessageAtom, msg.text ?? "", true); + if (this.cancel) { + if (fullMsg == "") { + globalStore.set(this.removeLastMessageAtom); + } + break; + } + globalStore.set(this.updateLastMessageAtom, "", false); + if (fullMsg != "") { + const responsePrompt: OpenAIPromptMessageType = { + role: "assistant", + content: fullMsg, + }; + await BlockService.SaveWaveAiData(blockId, [...history, newPrompt, responsePrompt]); } - break; } - } - globalStore.set(this.updateLastMessageAtom, "", false); - if (fullMsg != "") { - const responsePrompt: OpenAIPromptMessageType = { - role: "assistant", - content: fullMsg, + } catch (error) { + const updatedHist = [...history, newPrompt]; + if (fullMsg == "") { + globalStore.set(this.removeLastMessageAtom); + } else { + globalStore.set(this.updateLastMessageAtom, "", false); + const responsePrompt: OpenAIPromptMessageType = { + role: "assistant", + content: fullMsg, + }; + updatedHist.push(responsePrompt); + } + const errMsg: string = (error as Error).message; + const errorMessage: ChatMessageType = { + id: crypto.randomUUID(), + user: "error", + text: errMsg, }; - await BlockService.SaveWaveAiData(blockId, [...history, newPrompt, responsePrompt]); + globalStore.set(this.addMessageAtom, errorMessage); + globalStore.set(this.updateLastMessageAtom, "", false); + const errorPrompt: OpenAIPromptMessageType = { + role: "error", + content: errMsg, + }; + updatedHist.push(errorPrompt); + console.log(updatedHist); + await BlockService.SaveWaveAiData(blockId, updatedHist); } setLocked(false); this.cancel = false; @@ -264,17 +287,26 @@ function makeWaveAiViewModel(blockId): WaveAiModel { } const ChatItem = ({ chatItem }: ChatItemProps) => { - const { isAssistant, text, isError } = chatItem; + const { user, text } = chatItem; const cssVar = "--panel-bg-color"; const panelBgColor = getComputedStyle(document.documentElement).getPropertyValue(cssVar).trim(); - const renderError = (err: string): React.JSX.Element =>