From f82cf0d014a441a7628119454023951c904d634f Mon Sep 17 00:00:00 2001 From: Louis Date: Tue, 9 Jan 2024 16:21:14 +0700 Subject: [PATCH] chore: error message update (#1473) --- core/src/types/message/messageEntity.ts | 2 + .../inference-nitro-extension/src/index.ts | 12 +-- web/containers/Providers/EventHandler.tsx | 5 +- web/screens/Chat/ChatBody/index.tsx | 69 ++------------ web/screens/Chat/ErrorMessage/index.tsx | 93 +++++++++++++++++++ web/screens/Chat/SimpleTextMessage/index.tsx | 5 +- 6 files changed, 107 insertions(+), 79 deletions(-) create mode 100644 web/screens/Chat/ErrorMessage/index.tsx diff --git a/core/src/types/message/messageEntity.ts b/core/src/types/message/messageEntity.ts index a74f059a0..199743796 100644 --- a/core/src/types/message/messageEntity.ts +++ b/core/src/types/message/messageEntity.ts @@ -61,6 +61,8 @@ export enum MessageStatus { Pending = 'pending', /** Message loaded with error. **/ Error = 'error', + /** Message is cancelled streaming */ + Stopped = "stopped" } /** diff --git a/extensions/inference-nitro-extension/src/index.ts b/extensions/inference-nitro-extension/src/index.ts index 34e95667b..9af2230dc 100644 --- a/extensions/inference-nitro-extension/src/index.ts +++ b/extensions/inference-nitro-extension/src/index.ts @@ -240,19 +240,11 @@ export default class JanInferenceNitroExtension implements InferenceExtension { }, error: async (err) => { if (instance.isCancelled || message.content.length) { - message.status = MessageStatus.Error; + message.status = MessageStatus.Stopped; events.emit(EventName.OnMessageUpdate, message); return; } - const messageContent: ThreadContent = { - type: ContentType.Text, - text: { - value: "Error occurred: " + err.message, - annotations: [], - }, - }; - message.content = [messageContent]; - message.status = MessageStatus.Ready; + message.status = MessageStatus.Error; events.emit(EventName.OnMessageUpdate, message); }, }); diff --git a/web/containers/Providers/EventHandler.tsx b/web/containers/Providers/EventHandler.tsx index 2c81f4c23..aafbbb787 100644 --- a/web/containers/Providers/EventHandler.tsx +++ b/web/containers/Providers/EventHandler.tsx @@ -92,10 +92,7 @@ export default function EventHandler({ children }: { children: ReactNode }) { message.content, message.status ) - if ( - message.status === MessageStatus.Ready || - message.status === MessageStatus.Error - ) { + if (message.status !== MessageStatus.Pending) { // Mark the thread as not waiting for response updateThreadWaiting(message.thread_id, false) diff --git a/web/screens/Chat/ChatBody/index.tsx b/web/screens/Chat/ChatBody/index.tsx index d2a34388e..f56e13845 100644 --- a/web/screens/Chat/ChatBody/index.tsx +++ b/web/screens/Chat/ChatBody/index.tsx @@ -2,17 +2,9 @@ import { Fragment } from 'react' import ScrollToBottom from 'react-scroll-to-bottom' -import { - ChatCompletionRole, - ConversationalExtension, - ExtensionType, - InferenceEngine, - MessageStatus, -} from '@janhq/core' +import { InferenceEngine, MessageStatus } from '@janhq/core' import { Button } from '@janhq/uikit' -import { useAtomValue, useSetAtom } from 'jotai' - -import { RefreshCcw } from 'lucide-react' +import { useAtomValue } from 'jotai' import LogoMark from '@/containers/Brand/Logo/Mark' @@ -22,45 +14,16 @@ import { useGetDownloadedModels } from '@/hooks/useGetDownloadedModels' import { useMainViewState } from '@/hooks/useMainViewState' -import useSendChatMessage from '@/hooks/useSendChatMessage' - import ChatItem from '../ChatItem' -import { extensionManager } from '@/extension' -import { - deleteMessageAtom, - getCurrentChatMessagesAtom, -} from '@/helpers/atoms/ChatMessage.atom' -import { activeThreadAtom } from '@/helpers/atoms/Thread.atom' +import ErrorMessage from '../ErrorMessage' + +import { getCurrentChatMessagesAtom } from '@/helpers/atoms/ChatMessage.atom' const ChatBody: React.FC = () => { const messages = useAtomValue(getCurrentChatMessagesAtom) const { downloadedModels } = useGetDownloadedModels() const { setMainViewState } = useMainViewState() - const thread = useAtomValue(activeThreadAtom) - const deleteMessage = useSetAtom(deleteMessageAtom) - const { resendChatMessage } = useSendChatMessage() - - const regenerateMessage = async () => { - const lastMessageIndex = messages.length - 1 - const message = messages[lastMessageIndex] - if (message.role !== ChatCompletionRole.User) { - // Delete last response before regenerating - deleteMessage(message.id ?? '') - if (thread) { - await extensionManager - .get(ExtensionType.Conversational) - ?.writeMessages( - thread.id, - messages.filter((msg) => msg.id !== message.id) - ) - } - const targetMessage = messages[lastMessageIndex - 1] - if (targetMessage) resendChatMessage(targetMessage) - } else { - resendChatMessage(message) - } - } if (downloadedModels.length === 0) return ( @@ -118,26 +81,10 @@ const ChatBody: React.FC = () => { {messages.map((message, index) => (
- {message.status === MessageStatus.Error && + {(message.status === MessageStatus.Error || + message.status === MessageStatus.Stopped) && index === messages.length - 1 && ( -
- - Oops! The generation was interrupted. Let's give it - another go! - - -
+ )}
))} diff --git a/web/screens/Chat/ErrorMessage/index.tsx b/web/screens/Chat/ErrorMessage/index.tsx new file mode 100644 index 000000000..f4c5fc45a --- /dev/null +++ b/web/screens/Chat/ErrorMessage/index.tsx @@ -0,0 +1,93 @@ +import { + ChatCompletionRole, + ConversationalExtension, + ExtensionType, + MessageStatus, + ThreadMessage, +} from '@janhq/core' +import { Button } from '@janhq/uikit' +import { useAtomValue, useSetAtom } from 'jotai' +import { RefreshCcw } from 'lucide-react' + +import useSendChatMessage from '@/hooks/useSendChatMessage' + +import { extensionManager } from '@/extension' +import { + deleteMessageAtom, + getCurrentChatMessagesAtom, +} from '@/helpers/atoms/ChatMessage.atom' +import { activeThreadAtom } from '@/helpers/atoms/Thread.atom' + +const ErrorMessage = ({ message }: { message: ThreadMessage }) => { + const messages = useAtomValue(getCurrentChatMessagesAtom) + const thread = useAtomValue(activeThreadAtom) + const deleteMessage = useSetAtom(deleteMessageAtom) + const { resendChatMessage } = useSendChatMessage() + + const regenerateMessage = async () => { + const lastMessageIndex = messages.length - 1 + const message = messages[lastMessageIndex] + if (message.role !== ChatCompletionRole.User) { + // Delete last response before regenerating + deleteMessage(message.id ?? '') + if (thread) { + await extensionManager + .get(ExtensionType.Conversational) + ?.writeMessages( + thread.id, + messages.filter((msg) => msg.id !== message.id) + ) + } + const targetMessage = messages[lastMessageIndex - 1] + if (targetMessage) resendChatMessage(targetMessage) + } else { + resendChatMessage(message) + } + } + + return ( + <> + {message.status === MessageStatus.Stopped && ( +
+ + Oops! The generation was interrupted. Let's give it another go! + + +
+ )} + {message.status === MessageStatus.Error && ( +
+ +

Apologies, something's amiss!

+ Jan's in beta. Find troubleshooting guides{' '} + + here + {' '} + or reach out to us on{' '} + + Discord + {' '} + for assistance. +
+
+ )} + + ) +} +export default ErrorMessage diff --git a/web/screens/Chat/SimpleTextMessage/index.tsx b/web/screens/Chat/SimpleTextMessage/index.tsx index 11e34442a..7ebc0ebb1 100644 --- a/web/screens/Chat/SimpleTextMessage/index.tsx +++ b/web/screens/Chat/SimpleTextMessage/index.tsx @@ -104,10 +104,7 @@ const SimpleTextMessage: React.FC = (props) => { }, []) useEffect(() => { - if ( - props.status === MessageStatus.Ready || - props.status === MessageStatus.Error - ) { + if (props.status !== MessageStatus.Pending) { return } const currentTimestamp = new Date().getTime() // Get current time in milliseconds