Skip to content

Commit

Permalink
Move chat question, answer and source documents to Search state to av…
Browse files Browse the repository at this point in the history
…oid new Websocket connections when filtering items on the search page

Co-authored-by: Adam J. Arling <[email protected]>
  • Loading branch information
mathewjordan and adamjarling committed May 17, 2024
1 parent c00b0fb commit bcf54c6
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 20 deletions.
39 changes: 25 additions & 14 deletions components/Chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,26 @@ import { Work } from "@nulib/dcapi-types";
import { prepareQuestion } from "@/lib/chat-helpers";
import useChatSocket from "@/hooks/useChatSocket";
import useQueryParams from "@/hooks/useQueryParams";
import { useSearchState } from "@/context/search-context";

const Chat = () => {
const { searchTerm: question } = useQueryParams();
const { searchTerm = "" } = useQueryParams();
const { authToken, isConnected, message, sendMessage } = useChatSocket();
const { searchDispatch, searchState } = useSearchState();
const { chat } = searchState;
const { answer, documents = [], question } = chat;

const sameQuestionExists = !!question && searchTerm === question;

const [isStreamingComplete, setIsStreamingComplete] = useState(false);
const [sourceDocuments, setSourceDocuments] = useState<Work[]>([]);
const [streamedAnswer, setStreamedAnswer] = useState("");

useEffect(() => {
if (question && isConnected && authToken) {
const preparedQuestion = prepareQuestion(question, authToken);
if (!sameQuestionExists && isConnected && authToken) {
const preparedQuestion = prepareQuestion(searchTerm, authToken);
sendMessage(preparedQuestion);
}
}, [authToken, isConnected, question, sendMessage]);
}, [authToken, isConnected, sameQuestionExists, searchTerm, sendMessage]);

useEffect(() => {
if (!message) return;
Expand All @@ -31,21 +36,27 @@ const Chat = () => {
return prev + message.token;
});
} else if (message.answer) {
setStreamedAnswer(message.answer);
setIsStreamingComplete(true);
searchDispatch({
chat: {
answer: message.answer,
documents: sourceDocuments,
question: searchTerm || "",
},
type: "updateChat",
});
}
}, [message]);
}, [message, searchTerm, sourceDocuments, searchDispatch]);

if (!question) return null;
if (!searchTerm) return null;

return (
<ChatResponse
isStreamingComplete={isStreamingComplete}
question={question}
sourceDocuments={sourceDocuments}
streamedAnswer={streamedAnswer}
isStreamingComplete={!!answer}
searchTerm={searchTerm}
sourceDocuments={sameQuestionExists ? documents : sourceDocuments}
streamedAnswer={sameQuestionExists ? answer : streamedAnswer}
/>
);
};

export default Chat;
export default React.memo(Chat);
15 changes: 13 additions & 2 deletions components/Chat/Response/Images.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,29 @@ import GridItem from "@/components/Grid/Item";
import { StyledImages } from "@/components/Chat/Response/Response.styled";
import { Work } from "@nulib/dcapi-types";

const ResponseImages = ({ sourceDocuments }: { sourceDocuments: Work[] }) => {
const ResponseImages = ({
isStreamingComplete,
sourceDocuments,
}: {
isStreamingComplete: boolean;
sourceDocuments: Work[];
}) => {
const [nextIndex, setNextIndex] = useState(0);

useEffect(() => {
if (isStreamingComplete) {
setNextIndex(sourceDocuments.length);
return;
}

if (nextIndex < sourceDocuments.length) {
const timer = setTimeout(() => {
setNextIndex(nextIndex + 1);
}, 382);

return () => clearTimeout(timer);
}
}, [nextIndex, sourceDocuments.length]);
}, [isStreamingComplete, nextIndex, sourceDocuments.length]);

return (
<StyledImages>
Expand Down
11 changes: 7 additions & 4 deletions components/Chat/Response/Response.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ import { Work } from "@nulib/dcapi-types";

interface ChatResponseProps {
isStreamingComplete: boolean;
question: string;
searchTerm: string;
sourceDocuments: Work[];
streamedAnswer?: string;
}

const ChatResponse: React.FC<ChatResponseProps> = ({
isStreamingComplete,
question,
searchTerm,
sourceDocuments,
streamedAnswer,
}) => {
Expand All @@ -31,7 +31,7 @@ const ChatResponse: React.FC<ChatResponseProps> = ({
<Container containerType="wide">
<StyledResponse>
<StyledResponseContent>
<StyledQuestion>{question}</StyledQuestion>
<StyledQuestion>{searchTerm}</StyledQuestion>
{streamedAnswer ? (
<ResponseStreamedAnswer
isStreamingComplete={isStreamingComplete}
Expand All @@ -43,7 +43,10 @@ const ChatResponse: React.FC<ChatResponseProps> = ({
</StyledResponseContent>
{sourceDocuments.length > 0 && (
<StyledResponseAside>
<ResponseImages sourceDocuments={sourceDocuments} />
<ResponseImages
isStreamingComplete={isStreamingComplete}
sourceDocuments={sourceDocuments}
/>
</StyledResponseAside>
)}
</StyledResponse>
Expand Down
20 changes: 20 additions & 0 deletions context/search-context.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import { ApiResponseAggregation } from "@/types/api/response";
import React from "react";
import { SearchContextStore } from "@/types/context/search-context";
import { Work } from "@nulib/dcapi-types";

type Action =
| {
type: "updateAggregations";
aggregations: ApiResponseAggregation | undefined;
}
| {
type: "updateChat";
chat: {
answer: string;
documents: Work[];
question: string;
};
}
| { type: "updateSearch"; q: string }
| { type: "updateSearchFixed"; searchFixed: boolean };

Expand All @@ -19,6 +28,11 @@ type SearchProviderProps = {

const defaultState: SearchContextStore = {
aggregations: {},
chat: {
answer: "",
documents: [],
question: "",
},
searchFixed: false,
};

Expand All @@ -34,6 +48,12 @@ function searchReducer(state: State, action: Action) {
aggregations: action.aggregations,
};
}
case "updateChat": {
return {
...state,
chat: action.chat,
};
}
case "updateSearch": {
return {
...state,
Expand Down
6 changes: 6 additions & 0 deletions types/context/search-context.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { ApiResponseAggregation } from "@/types/api/response";
import { Work } from "@nulib/dcapi-types";

export interface SearchContextStore {
aggregations?: ApiResponseAggregation;
chat: {
answer: string;
documents: Work[];
question: string;
};
searchFixed: boolean;
}

Expand Down

0 comments on commit bcf54c6

Please sign in to comment.