diff --git a/components/Chat/components/Wrapper.tsx b/components/Chat/components/Wrapper.tsx index 91f175e2..0431938f 100644 --- a/components/Chat/components/Wrapper.tsx +++ b/components/Chat/components/Wrapper.tsx @@ -4,16 +4,21 @@ import Chat from "@/components/Chat"; import { ChatConfig } from "@/components/Chat/types/chat"; import axios from "axios"; +const weaviateEndpointt = `https://dcapi-prototype.rdc-staging.library.northwestern.edu/api/v2/chat-endpoint`; +const chatEndpoint = + "https://dcapi.rdc-staging.library.northwestern.edu/api/v2/chat-endpoint"; + const ChatWrapper = () => { const [chatConfig, setChatConfig] = useState(); useEffect(() => { axios({ method: "GET", - url: `https://dcapi-prototype.rdc-staging.library.northwestern.edu/api/v2/chat-endpoint`, + url: chatEndpoint, withCredentials: true, }) .then((response) => { + console.log("Wrapper response.data", response.data); setChatConfig(response.data); }) .catch((error) => { diff --git a/components/Chat/index.tsx b/components/Chat/index.tsx index 472e523e..7b5b734c 100644 --- a/components/Chat/index.tsx +++ b/components/Chat/index.tsx @@ -1,7 +1,7 @@ import * as Accordion from "@radix-ui/react-accordion"; import { Answer, QuestionRendered, StreamingMessage } from "./types/chat"; -import React, { useCallback, useEffect } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { StyledActions, StyledAnswerHeader, @@ -18,6 +18,7 @@ import QuestionInput from "./components/Question/Input"; import SourceDocuments from "./components/Answer/SourceDocuments"; import StreamingAnswer from "./components/Answer/StreamingAnswer"; import useLocalStorageSimple from "./hooks/useLocalStorageSimple"; +import useQueryParams from "@/hooks/useQueryParams"; import useStreamingAnswers from "./hooks/useStreamingAnswers"; const Chat = ({ chatConfig }: { chatConfig: ChatConfig }) => { @@ -27,129 +28,71 @@ const Chat = ({ chatConfig }: { chatConfig: ChatConfig }) => { const [chatSocket, setChatSocket] = React.useState(); const [readyState, setReadyState] = React.useState(); - const [questions, setQuestions] = useLocalStorageSimple( - "nul-chat-search-questions", - [] - ); - - /** - * A pattern to access and update React state within a WebSocket event handler - */ - const [streamAnswers, _setStreamAnswers] = useLocalStorageSimple( - "nul-chat-search-answers", - [] - ); + const [streamedAnswer, setStreamedAnswer] = useState(""); + console.log("streamedAnswer", streamedAnswer); - const streamAnswersRef = React.useRef(streamAnswers); - const setStreamAnswers = useCallback( - (data: Array) => { - streamAnswersRef.current = data; - _setStreamAnswers(data); - }, - [_setStreamAnswers] - ); + const { searchTerm: question } = useQueryParams(); + console.log("question", question); const handleReadyStateChange = (event: Event) => { const target = event.target as WebSocket; + console.log("target.readyState", target.readyState); setReadyState(target.readyState); }; - const handleMessageUpdate = useCallback( - (event: MessageEvent) => { - const data: StreamingMessage = JSON.parse(event.data); - const updatedStreamAnswers = updateStreamAnswers(data, [ - ...streamAnswersRef.current, - ]); - setStreamAnswers(updatedStreamAnswers); - }, - [setStreamAnswers, updateStreamAnswers] - ); + // Handle web socket stream updates + const handleMessageUpdate = (event: MessageEvent) => { + const data: StreamingMessage = JSON.parse(event.data); + console.log("handleMessageUpdate", data); + + if (data.token) { + setStreamedAnswer((prev) => { + console.log("prev, data.token", prev, data.token); + return prev + data.token; + }); + } else if (data.answer) { + setStreamedAnswer(data.answer); + } + }; useEffect(() => { + if (question && chatSocket?.readyState === 1) { + const preparedQuestion = prepareQuestion(question, authToken); + console.log("preparedQuestion", preparedQuestion, chatSocket); + chatSocket?.send(JSON.stringify(preparedQuestion)); + } + }, [authToken, chatSocket, question, prepareQuestion]); + + useEffect(() => { + if (!authToken || !endpoint) return; + + console.log("creating socket", authToken, endpoint); const socket = new WebSocket(endpoint); - setChatSocket(socket); + socket.addEventListener("open", handleReadyStateChange); socket.addEventListener("close", handleReadyStateChange); socket.addEventListener("error", handleReadyStateChange); socket.addEventListener("message", handleMessageUpdate); + setChatSocket(socket); + return () => { socket.removeEventListener("open", handleReadyStateChange); socket.removeEventListener("close", handleReadyStateChange); socket.removeEventListener("error", handleReadyStateChange); socket.removeEventListener("message", handleMessageUpdate); }; - }, [authToken, endpoint, handleMessageUpdate]); - - const handleQuestionSubmission = (questionString: string) => { - // do some basic validation and save the question - if (questionString) { - const question = prepareQuestion(questionString, authToken); - const questionToStore = { - question: question.question, - ref: question.ref, - }; - - // Append question to my questions React state array using prevState - setQuestions((prevQuestions) => [questionToStore, ...prevQuestions]); - chatSocket?.send(JSON.stringify(question)); - } - }; - - const handleDelete = (ref: string) => { - const updatedQuestions = questions.filter((q: any) => q.ref !== ref); - const updatedAnswers = streamAnswers.filter((a: any) => a.ref !== ref); - setQuestions(updatedQuestions); - setStreamAnswers(updatedAnswers); - }; - - const defaultValue = questions.length ? `${questions[0].ref}` : undefined; + }, [authToken, endpoint]); return ( - - {readyState === 1 && ( - + <> + {question && ( + <> + {/* */} + + )} - - {questions.map((question: QuestionRendered) => { - const answer = streamAnswers?.find( - (answer) => question.ref === answer.ref - ); - return ( - - - - {question?.question} - - - - {answer?.answer && } - handleDelete(question.ref)}> - - - - - - - {answer?.answer ? ( - - - - - ) : ( - - )} - - ); - })} - + ); }; diff --git a/package-lock.json b/package-lock.json index 01e3bb89..ad0eae9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,12 +24,8 @@ "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-switch": "^1.0.1", "@radix-ui/react-tabs": "^1.0.1", -<<<<<<< HEAD - "@samvera/clover-iiif": "2.4.0-rc.0", -======= "@radix-ui/react-tooltip": "^1.0.7", - "@samvera/clover-iiif": "^2.2.6", ->>>>>>> 850bca7 (Shift Chat to search screen, rename directory.) + "@samvera/clover-iiif": "2.4.0-rc.0", "@samvera/image-downloader": "^1.1.6", "@stitches/react": "^1.2.6", "axios": "^1.2.2", @@ -15515,6 +15511,126 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.6.tgz", + "integrity": "sha512-6cgBfxg98oOCSr4BckWjLLgiVwlL3vlLj8hXg2b+nDgm4bC/qVXXLfpLB9FHdoDu4057hzywbxKvmYGmi7yUzA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.6.tgz", + "integrity": "sha512-txagBbj1e1w47YQjcKgSU4rRVQ7uF29YpnlHV5xuVUsgCUf2FmyfJ3CPjZUvpIeXCJAoMCFAoGnbtX86BK7+sg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.6.tgz", + "integrity": "sha512-cGd+H8amifT86ZldVJtAKDxUqeFyLWW+v2NlBULnLAdWsiuuN8TuhVBt8ZNpCqcAuoruoSWynvMWixTFcroq+Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.6.tgz", + "integrity": "sha512-Mc2b4xiIWKXIhBy2NBTwOxGD3nHLmq4keFk+d4/WL5fMsB8XdJRdtUlL87SqVCTSaf1BRuQQf1HvXZcy+rq3Nw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.6.tgz", + "integrity": "sha512-CFHvP9Qz98NruJiUnCe61O6GveKKHpJLloXbDSWRhqhkJdZD2zU5hG+gtVJR//tyW897izuHpM6Gtf6+sNgJPQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.6.tgz", + "integrity": "sha512-aFv1ejfkbS7PUa1qVPwzDHjQWQtknzAZWGTKYIAaS4NMtBlk3VyA6AYn593pqNanlicewqyl2jUhQAaFV/qXsg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.6.tgz", + "integrity": "sha512-XqqpHgEIlBHvzwG8sp/JXMFkLAfGLqkbVsyN+/Ih1mR8INb6YCc2x/Mbwi6hsAgUnqQztz8cvEbHJUbSl7RHDg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.6.tgz", + "integrity": "sha512-Cqfe1YmOS7k+5mGu92nl5ULkzpKuxJrP3+4AEuPmrpFZ3BHxTY3TnHmU1On3bFmFFs6FbTcdF58CCUProGpIGQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } }