diff --git a/src/api/streaming.ts b/src/api/streaming.ts index 9993d0e..21e5ac2 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -46,17 +46,35 @@ export const getDataFromStream = (sseUrl: string, setterFn: any) => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error window.GooeyEventSource = evtSource; + + evtSource.addEventListener("close", () => { + // close the event source + evtSource.close(); + // set the state to null + setterFn(null); + }); + + evtSource.addEventListener("error", (event: MessageEvent) => { + // parse the error message as JSON + const { detail } = JSON.parse(event.data); + // display the error message + setterFn({ + type: STREAM_MESSAGE_TYPES.MESSAGE_PART, + text: `
${detail}
`, + }); + // close the event source + evtSource.close(); + }); + evtSource.onmessage = (event) => { // parse the message as JSON const data = JSON.parse(event.data); + // update the state with the streamed message + setterFn(data); // check if the message is the final response if (data.type === STREAM_MESSAGE_TYPES.FINAL_RESPONSE) { // close the stream - setterFn(data); evtSource.close(); - } else { - // update the state with the streamed message - setterFn(data); } }; }; diff --git a/src/contexts/MessagesContext.tsx b/src/contexts/MessagesContext.tsx index 16f1a54..284b640 100644 --- a/src/contexts/MessagesContext.tsx +++ b/src/contexts/MessagesContext.tsx @@ -68,7 +68,7 @@ const MessagesContextProvider = (props: any) => { const conversationId = lastResponse?.conversation_id; setIsSendingMessage(true); const newQuery = createNewQuery(payload); - sendPrompt({ + sendPayload({ ...payload, conversation_id: conversationId, citation_style: CITATION_STYLE, @@ -109,6 +109,21 @@ const MessagesContextProvider = (props: any) => { const updateStreamedMessage = useCallback( (payload: any) => { setMessages((prev: any) => { + // stream close + if (!payload) { + const newMessages = new Map(prev); + const lastResponseId: any = Array.from(prev.keys()).pop(); // last message id + const prevMessage = prev.get(lastResponseId); + newMessages.set(lastResponseId, { + ...prevMessage, + output_text: [prevMessage?.text ?? ""], + type: STREAM_MESSAGE_TYPES.FINAL_RESPONSE, + status: "completed", + }); + setIsReceiving(false); + return newMessages; + } + // stream start if (payload?.type === STREAM_MESSAGE_TYPES.CONVERSATION_START) { setIsSendingMessage(false); @@ -167,11 +182,16 @@ const MessagesContextProvider = (props: any) => { const lastResponseId: any = Array.from(prev.keys()).pop(); // last messages id const prevMessage = prev.get(lastResponseId); const text = (prevMessage?.text || "") + (payload.text || ""); + const buttons = [ + ...(prevMessage?.buttons || []), + ...(payload.buttons || []), + ]; newConversations.set(lastResponseId, { ...prevMessage, ...payload, id: currentStreamRef.current, text, + buttons, }); return newConversations; } @@ -182,17 +202,15 @@ const MessagesContextProvider = (props: any) => { [config?.integration_id, handleAddConversation, scrollToMessage] ); - const sendPrompt = async (payload: IncomingMsg) => { + const sendPayload = async (payload: IncomingMsg) => { try { - let audioUrl = ""; if (payload?.input_audio) { // upload audio file to gooey const file = new File( [payload.input_audio], `gooey-widget-recording-${uuidv4()}.webm` ); - audioUrl = await uploadFileToGooey(file as File); - payload.input_audio = audioUrl; + payload.input_audio = await uploadFileToGooey(file as File); } payload = { ...config?.payload, @@ -207,8 +225,7 @@ const MessagesContextProvider = (props: any) => { ); getDataFromStream(streamUrl, updateStreamedMessage); // setLoading false in updateStreamedMessage - } catch (err) { - console.error("Api Failed!", err); + } finally { setIsSendingMessage(false); } }; @@ -276,35 +293,6 @@ const MessagesContextProvider = (props: any) => { setIsSendingMessage(false); }, [isReceiving, isSending, messages]); - const handleFeedbackClick = (button_id: string, context_msg_id: string) => { - createStreamApi( - { - button_pressed: { - button_id, - context_msg_id, - }, - integration_id: config?.integration_id, - user_id: currentUserId, - }, - apiSource.current - ); - setMessages((prev: any) => { - const newConversations = new Map(prev); - const prevMessage = prev.get(context_msg_id); - const newButtons = prevMessage.buttons.map((button: any) => { - if (button.id === button_id) { - return { ...button, isPressed: true }; - } - return undefined; // hide the other buttons - }); - newConversations.set(context_msg_id, { - ...prevMessage, - buttons: newButtons, - }); - return newConversations; - }); - }; - const setActiveConversation = useCallback( async (conversation: Conversation) => { if (isSending || isReceiving) cancelApiCall(); @@ -348,7 +336,6 @@ const MessagesContextProvider = (props: any) => { }; const valueMessages = { - sendPrompt, messages, isSending, initializeQuery, @@ -357,7 +344,6 @@ const MessagesContextProvider = (props: any) => { scrollMessageContainer, scrollContainerRef, isReceiving, - handleFeedbackClick, conversations, setActiveConversation, currentConversationId: currentConversation.current?.id || null, diff --git a/src/widgets/copilot/components/ChatInput/index.tsx b/src/widgets/copilot/components/ChatInput/index.tsx index 75bccb2..83cfca3 100644 --- a/src/widgets/copilot/components/ChatInput/index.tsx +++ b/src/widgets/copilot/components/ChatInput/index.tsx @@ -179,7 +179,8 @@ const ChatInput = () => { onChange={handleInputChange} onKeyDown={handlePressEnter} className={clsx( - "br-large b-1 font_16_500 bg-white gpt-10 gpb-10 gpr-40 flex-1 gm-0", isLeftButtons ? "gpl-32" : "gpl-12" + "br-large b-1 font_16_500 bg-white gpt-10 gpb-10 gpr-40 flex-1 gm-0", + isLeftButtons ? "gpl-32" : "gpl-12" )} placeholder={`Message ${config.branding.name || ""}`} > @@ -187,7 +188,11 @@ const ChatInput = () => { {/* Left icons */} {isLeftButtons && (