Fix feedback display

This commit is contained in:
Weves
2024-02-10 00:15:41 -08:00
committed by Chris Weaver
parent 37110df2de
commit d5168deac8
8 changed files with 65 additions and 52 deletions

View File

@@ -106,13 +106,15 @@ export function ChatDocumentDisplay({
{buildDocumentSummaryDisplay(document.match_highlights, document.blurb)} {buildDocumentSummaryDisplay(document.match_highlights, document.blurb)}
</p> </p>
<div className="mb-2"> <div className="mb-2">
{/*
// TODO: find a way to include this
{queryEventId && ( {queryEventId && (
<DocumentFeedbackBlock <DocumentFeedbackBlock
documentId={document.document_id} documentId={document.document_id}
queryId={queryEventId} queryId={queryEventId}
setPopup={setPopup} setPopup={setPopup}
/> />
)} )} */}
</div> </div>
</div> </div>
); );

View File

@@ -133,14 +133,16 @@ export function DocumentMetadataBlock({
interface DocumentDisplayProps { interface DocumentDisplayProps {
document: DanswerDocument; document: DanswerDocument;
queryEventId: number | null; messageId: number | null;
documentRank: number;
isSelected: boolean; isSelected: boolean;
setPopup: (popupSpec: PopupSpec | null) => void; setPopup: (popupSpec: PopupSpec | null) => void;
} }
export const DocumentDisplay = ({ export const DocumentDisplay = ({
document, document,
queryEventId, messageId,
documentRank,
isSelected, isSelected,
setPopup, setPopup,
}: DocumentDisplayProps) => { }: DocumentDisplayProps) => {
@@ -219,10 +221,11 @@ export const DocumentDisplay = ({
</p> </p>
</a> </a>
<div className="ml-auto"> <div className="ml-auto">
{isHovered && queryEventId && ( {isHovered && messageId && (
<DocumentFeedbackBlock <DocumentFeedbackBlock
documentId={document.document_id} documentId={document.document_id}
queryId={queryEventId} messageId={messageId}
documentRank={documentRank}
setPopup={setPopup} setPopup={setPopup}
/> />
)} )}

View File

@@ -5,20 +5,21 @@ type DocumentFeedbackType = "endorse" | "reject" | "hide" | "unhide";
const giveDocumentFeedback = async ( const giveDocumentFeedback = async (
documentId: string, documentId: string,
queryId: number, messageId: number,
documentRank: number,
searchFeedback: DocumentFeedbackType searchFeedback: DocumentFeedbackType
): Promise<string | null> => { ): Promise<string | null> => {
const response = await fetch("/api/doc-retrieval-feedback", { const response = await fetch("/api/chat/document-search-feedback", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify({ body: JSON.stringify({
query_id: queryId, message_id: messageId,
search_feedback: searchFeedback,
click: false,
document_rank: 0,
document_id: documentId, document_id: documentId,
document_rank: documentRank,
click: false,
search_feedback: searchFeedback,
}), }),
}); });
return response.ok return response.ok
@@ -28,14 +29,16 @@ const giveDocumentFeedback = async (
interface DocumentFeedbackIconProps { interface DocumentFeedbackIconProps {
documentId: string; documentId: string;
queryId: number; messageId: number;
documentRank: number;
setPopup: (popupSpec: PopupSpec | null) => void; setPopup: (popupSpec: PopupSpec | null) => void;
feedbackType: DocumentFeedbackType; feedbackType: DocumentFeedbackType;
} }
const DocumentFeedback = ({ const DocumentFeedback = ({
documentId, documentId,
queryId, messageId,
documentRank,
setPopup, setPopup,
feedbackType, feedbackType,
}: DocumentFeedbackIconProps) => { }: DocumentFeedbackIconProps) => {
@@ -67,7 +70,8 @@ const DocumentFeedback = ({
onClick={async () => { onClick={async () => {
const errorMsg = await giveDocumentFeedback( const errorMsg = await giveDocumentFeedback(
documentId, documentId,
queryId, messageId,
documentRank,
feedbackType feedbackType
); );
if (!errorMsg) { if (!errorMsg) {
@@ -91,27 +95,31 @@ const DocumentFeedback = ({
interface DocumentFeedbackBlockProps { interface DocumentFeedbackBlockProps {
documentId: string; documentId: string;
queryId: number; messageId: number;
documentRank: number;
setPopup: (popupSpec: PopupSpec | null) => void; setPopup: (popupSpec: PopupSpec | null) => void;
} }
export const DocumentFeedbackBlock = ({ export const DocumentFeedbackBlock = ({
documentId, documentId,
queryId, messageId,
documentRank,
setPopup, setPopup,
}: DocumentFeedbackBlockProps) => { }: DocumentFeedbackBlockProps) => {
return ( return (
<div className="flex"> <div className="flex">
<DocumentFeedback <DocumentFeedback
documentId={documentId} documentId={documentId}
queryId={queryId} messageId={messageId}
documentRank={documentRank}
setPopup={setPopup} setPopup={setPopup}
feedbackType="endorse" feedbackType="endorse"
/> />
<div className="ml-2"> <div className="ml-2">
<DocumentFeedback <DocumentFeedback
documentId={documentId} documentId={documentId}
queryId={queryId} messageId={messageId}
documentRank={documentRank}
setPopup={setPopup} setPopup={setPopup}
feedbackType="reject" feedbackType="reject"
/> />

View File

@@ -5,30 +5,30 @@ import { ThumbsDownIcon, ThumbsUpIcon } from "../icons/icons";
type Feedback = "like" | "dislike"; type Feedback = "like" | "dislike";
const giveFeedback = async ( const giveFeedback = async (
queryId: number, messageId: number,
feedback: Feedback feedback: Feedback
): Promise<boolean> => { ): Promise<boolean> => {
const response = await fetch("/api/query-feedback", { const response = await fetch("/api/chat/create-chat-message-feedback", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify({ body: JSON.stringify({
query_id: queryId, chat_message_id: messageId,
feedback, is_positive: feedback === "like",
}), }),
}); });
return response.ok; return response.ok;
}; };
interface QAFeedbackIconProps { interface QAFeedbackIconProps {
queryId: number; messageId: number;
setPopup: (popupSpec: PopupSpec | null) => void; setPopup: (popupSpec: PopupSpec | null) => void;
feedbackType: Feedback; feedbackType: Feedback;
} }
const QAFeedback = ({ const QAFeedback = ({
queryId, messageId,
setPopup, setPopup,
feedbackType, feedbackType,
}: QAFeedbackIconProps) => { }: QAFeedbackIconProps) => {
@@ -40,7 +40,7 @@ const QAFeedback = ({
return ( return (
<div <div
onClick={async () => { onClick={async () => {
const isSuccessful = await giveFeedback(queryId, feedbackType); const isSuccessful = await giveFeedback(messageId, feedbackType);
if (isSuccessful) { if (isSuccessful) {
setPopup({ setPopup({
message: "Thanks for your feedback!", message: "Thanks for your feedback!",
@@ -70,20 +70,24 @@ const QAFeedback = ({
}; };
interface QAFeedbackBlockProps { interface QAFeedbackBlockProps {
queryId: number; messageId: number;
setPopup: (popupSpec: PopupSpec | null) => void; setPopup: (popupSpec: PopupSpec | null) => void;
} }
export const QAFeedbackBlock = ({ export const QAFeedbackBlock = ({
queryId, messageId,
setPopup, setPopup,
}: QAFeedbackBlockProps) => { }: QAFeedbackBlockProps) => {
return ( return (
<div className="flex"> <div className="flex">
<QAFeedback queryId={queryId} setPopup={setPopup} feedbackType="like" /> <QAFeedback
messageId={messageId}
setPopup={setPopup}
feedbackType="like"
/>
<div className="ml-2"> <div className="ml-2">
<QAFeedback <QAFeedback
queryId={queryId} messageId={messageId}
setPopup={setPopup} setPopup={setPopup}
feedbackType="dislike" feedbackType="dislike"
/> />

View File

@@ -11,7 +11,6 @@ import {
} from "@/lib/search/interfaces"; } from "@/lib/search/interfaces";
import { QAFeedbackBlock } from "./QAFeedback"; import { QAFeedbackBlock } from "./QAFeedback";
import { DocumentDisplay } from "./DocumentDisplay"; import { DocumentDisplay } from "./DocumentDisplay";
import { ResponseSection, StatusOptions } from "./results/ResponseSection";
import { QuotesSection } from "./results/QuotesSection"; import { QuotesSection } from "./results/QuotesSection";
import { AnswerSection } from "./results/AnswerSection"; import { AnswerSection } from "./results/AnswerSection";
import { ThreeDots } from "react-loader-spinner"; import { ThreeDots } from "react-loader-spinner";
@@ -50,7 +49,7 @@ export const SearchResultsDisplay = ({
} }
const isPersona = personaName !== null; const isPersona = personaName !== null;
const { answer, quotes, documents, error, queryEventId } = searchResponse; const { answer, quotes, documents, error, messageId } = searchResponse;
if (isFetching && !answer && !documents) { if (isFetching && !answer && !documents) {
return ( return (
@@ -147,10 +146,10 @@ export const SearchResultsDisplay = ({
isAnswerable={validQuestionResponse.answerable} isAnswerable={validQuestionResponse.answerable}
/> />
{searchResponse.queryEventId !== null && ( {searchResponse.messageId !== null && (
<div className="absolute right-3 bottom-3"> <div className="absolute right-3 bottom-3">
<QAFeedbackBlock <QAFeedbackBlock
queryId={searchResponse.queryEventId} messageId={searchResponse.messageId}
setPopup={setPopup} setPopup={setPopup}
/> />
</div> </div>
@@ -166,11 +165,12 @@ export const SearchResultsDisplay = ({
<div className="font-bold text-emphasis border-b mb-3 pb-1 border-border text-lg"> <div className="font-bold text-emphasis border-b mb-3 pb-1 border-border text-lg">
Results Results
</div> </div>
{removeDuplicateDocs(documents).map((document) => ( {removeDuplicateDocs(documents).map((document, ind) => (
<DocumentDisplay <DocumentDisplay
key={document.document_id} key={document.document_id}
document={document} document={document}
queryEventId={queryEventId} documentRank={ind + 1}
messageId={messageId}
isSelected={selectedDocumentIds.has(document.document_id)} isSelected={selectedDocumentIds.has(document.document_id)}
setPopup={setPopup} setPopup={setPopup}
/> />

View File

@@ -95,7 +95,7 @@ export const SearchSection = ({
suggestedFlowType: null, suggestedFlowType: null,
selectedDocIndices: null, selectedDocIndices: null,
error: null, error: null,
queryEventId: null, messageId: null,
}; };
const updateCurrentAnswer = (answer: string) => const updateCurrentAnswer = (answer: string) =>
setSearchResponse((prevState) => ({ setSearchResponse((prevState) => ({
@@ -132,10 +132,10 @@ export const SearchSection = ({
...(prevState || initialSearchResponse), ...(prevState || initialSearchResponse),
error, error,
})); }));
const updateQueryEventId = (queryEventId: number) => const updateMessageId = (messageId: number) =>
setSearchResponse((prevState) => ({ setSearchResponse((prevState) => ({
...(prevState || initialSearchResponse), ...(prevState || initialSearchResponse),
queryEventId, messageId,
})); }));
let lastSearchCancellationToken = useRef<CancellationToken | null>(null); let lastSearchCancellationToken = useRef<CancellationToken | null>(null);
@@ -190,9 +190,9 @@ export const SearchSection = ({
cancellationToken: lastSearchCancellationToken.current, cancellationToken: lastSearchCancellationToken.current,
fn: updateError, fn: updateError,
}), }),
updateQueryEventId: cancellable({ updateMessageId: cancellable({
cancellationToken: lastSearchCancellationToken.current, cancellationToken: lastSearchCancellationToken.current,
fn: updateQueryEventId, fn: updateMessageId,
}), }),
selectedSearchType: searchType ?? selectedSearchType, selectedSearchType: searchType ?? selectedSearchType,
offset: offset ?? defaultOverrides.offset, offset: offset ?? defaultOverrides.offset,

View File

@@ -62,10 +62,6 @@ export interface LLMRelevanceFilterPacket {
relevant_chunk_indices: number[]; relevant_chunk_indices: number[];
} }
export interface QueryEventIdPacket {
query_event_id: number;
}
export interface SearchResponse { export interface SearchResponse {
suggestedSearchType: SearchType | null; suggestedSearchType: SearchType | null;
suggestedFlowType: FlowType | null; suggestedFlowType: FlowType | null;
@@ -74,7 +70,7 @@ export interface SearchResponse {
documents: DanswerDocument[] | null; documents: DanswerDocument[] | null;
selectedDocIndices: number[] | null; selectedDocIndices: number[] | null;
error: string | null; error: string | null;
queryEventId: number | null; messageId: number | null;
} }
export enum SourceCategory { export enum SourceCategory {
@@ -116,7 +112,7 @@ export interface SearchRequestArgs {
updateSuggestedSearchType: (searchType: SearchType) => void; updateSuggestedSearchType: (searchType: SearchType) => void;
updateSuggestedFlowType: (flowType: FlowType) => void; updateSuggestedFlowType: (flowType: FlowType) => void;
updateError: (error: string) => void; updateError: (error: string) => void;
updateQueryEventId: (queryEventID: number) => void; updateMessageId: (messageId: number) => void;
selectedSearchType: SearchType | null; selectedSearchType: SearchType | null;
} }

View File

@@ -1,10 +1,10 @@
import { BackendMessage } from "@/app/chat/interfaces";
import { import {
AnswerPiecePacket, AnswerPiecePacket,
DanswerDocument, DanswerDocument,
DocumentInfoPacket, DocumentInfoPacket,
ErrorMessagePacket, ErrorMessagePacket,
LLMRelevanceFilterPacket, LLMRelevanceFilterPacket,
QueryEventIdPacket,
Quote, Quote,
QuotesInfoPacket, QuotesInfoPacket,
SearchRequestArgs, SearchRequestArgs,
@@ -26,7 +26,7 @@ export const searchRequestStreamed = async ({
updateSuggestedFlowType, updateSuggestedFlowType,
updateSelectedDocIndices, updateSelectedDocIndices,
updateError, updateError,
updateQueryEventId, updateMessageId,
}: SearchRequestArgs) => { }: SearchRequestArgs) => {
let answer = ""; let answer = "";
let quotes: Quote[] | null = null; let quotes: Quote[] | null = null;
@@ -78,7 +78,7 @@ export const searchRequestStreamed = async ({
| QuotesInfoPacket | QuotesInfoPacket
| DocumentInfoPacket | DocumentInfoPacket
| LLMRelevanceFilterPacket | LLMRelevanceFilterPacket
| QueryEventIdPacket | BackendMessage
>(decoder.decode(value, { stream: true }), previousPartialChunk); >(decoder.decode(value, { stream: true }), previousPartialChunk);
if (!completedChunks.length && !partialChunk) { if (!completedChunks.length && !partialChunk) {
break; break;
@@ -150,9 +150,9 @@ export const searchRequestStreamed = async ({
return; return;
} }
// check for query ID section // check for message ID section
if (Object.hasOwn(chunk, "query_event_id")) { if (Object.hasOwn(chunk, "message_id")) {
updateQueryEventId((chunk as QueryEventIdPacket).query_event_id); updateMessageId((chunk as BackendMessage).message_id);
return; return;
} }