mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-06-04 12:09:53 +02:00
Fix feedback display
This commit is contained in:
parent
37110df2de
commit
d5168deac8
@ -106,13 +106,15 @@ export function ChatDocumentDisplay({
|
||||
{buildDocumentSummaryDisplay(document.match_highlights, document.blurb)}
|
||||
</p>
|
||||
<div className="mb-2">
|
||||
{/*
|
||||
// TODO: find a way to include this
|
||||
{queryEventId && (
|
||||
<DocumentFeedbackBlock
|
||||
documentId={document.document_id}
|
||||
queryId={queryEventId}
|
||||
setPopup={setPopup}
|
||||
/>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -133,14 +133,16 @@ export function DocumentMetadataBlock({
|
||||
|
||||
interface DocumentDisplayProps {
|
||||
document: DanswerDocument;
|
||||
queryEventId: number | null;
|
||||
messageId: number | null;
|
||||
documentRank: number;
|
||||
isSelected: boolean;
|
||||
setPopup: (popupSpec: PopupSpec | null) => void;
|
||||
}
|
||||
|
||||
export const DocumentDisplay = ({
|
||||
document,
|
||||
queryEventId,
|
||||
messageId,
|
||||
documentRank,
|
||||
isSelected,
|
||||
setPopup,
|
||||
}: DocumentDisplayProps) => {
|
||||
@ -219,10 +221,11 @@ export const DocumentDisplay = ({
|
||||
</p>
|
||||
</a>
|
||||
<div className="ml-auto">
|
||||
{isHovered && queryEventId && (
|
||||
{isHovered && messageId && (
|
||||
<DocumentFeedbackBlock
|
||||
documentId={document.document_id}
|
||||
queryId={queryEventId}
|
||||
messageId={messageId}
|
||||
documentRank={documentRank}
|
||||
setPopup={setPopup}
|
||||
/>
|
||||
)}
|
||||
|
@ -5,20 +5,21 @@ type DocumentFeedbackType = "endorse" | "reject" | "hide" | "unhide";
|
||||
|
||||
const giveDocumentFeedback = async (
|
||||
documentId: string,
|
||||
queryId: number,
|
||||
messageId: number,
|
||||
documentRank: number,
|
||||
searchFeedback: DocumentFeedbackType
|
||||
): Promise<string | null> => {
|
||||
const response = await fetch("/api/doc-retrieval-feedback", {
|
||||
const response = await fetch("/api/chat/document-search-feedback", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query_id: queryId,
|
||||
search_feedback: searchFeedback,
|
||||
click: false,
|
||||
document_rank: 0,
|
||||
message_id: messageId,
|
||||
document_id: documentId,
|
||||
document_rank: documentRank,
|
||||
click: false,
|
||||
search_feedback: searchFeedback,
|
||||
}),
|
||||
});
|
||||
return response.ok
|
||||
@ -28,14 +29,16 @@ const giveDocumentFeedback = async (
|
||||
|
||||
interface DocumentFeedbackIconProps {
|
||||
documentId: string;
|
||||
queryId: number;
|
||||
messageId: number;
|
||||
documentRank: number;
|
||||
setPopup: (popupSpec: PopupSpec | null) => void;
|
||||
feedbackType: DocumentFeedbackType;
|
||||
}
|
||||
|
||||
const DocumentFeedback = ({
|
||||
documentId,
|
||||
queryId,
|
||||
messageId,
|
||||
documentRank,
|
||||
setPopup,
|
||||
feedbackType,
|
||||
}: DocumentFeedbackIconProps) => {
|
||||
@ -67,7 +70,8 @@ const DocumentFeedback = ({
|
||||
onClick={async () => {
|
||||
const errorMsg = await giveDocumentFeedback(
|
||||
documentId,
|
||||
queryId,
|
||||
messageId,
|
||||
documentRank,
|
||||
feedbackType
|
||||
);
|
||||
if (!errorMsg) {
|
||||
@ -91,27 +95,31 @@ const DocumentFeedback = ({
|
||||
|
||||
interface DocumentFeedbackBlockProps {
|
||||
documentId: string;
|
||||
queryId: number;
|
||||
messageId: number;
|
||||
documentRank: number;
|
||||
setPopup: (popupSpec: PopupSpec | null) => void;
|
||||
}
|
||||
|
||||
export const DocumentFeedbackBlock = ({
|
||||
documentId,
|
||||
queryId,
|
||||
messageId,
|
||||
documentRank,
|
||||
setPopup,
|
||||
}: DocumentFeedbackBlockProps) => {
|
||||
return (
|
||||
<div className="flex">
|
||||
<DocumentFeedback
|
||||
documentId={documentId}
|
||||
queryId={queryId}
|
||||
messageId={messageId}
|
||||
documentRank={documentRank}
|
||||
setPopup={setPopup}
|
||||
feedbackType="endorse"
|
||||
/>
|
||||
<div className="ml-2">
|
||||
<DocumentFeedback
|
||||
documentId={documentId}
|
||||
queryId={queryId}
|
||||
messageId={messageId}
|
||||
documentRank={documentRank}
|
||||
setPopup={setPopup}
|
||||
feedbackType="reject"
|
||||
/>
|
||||
|
@ -5,30 +5,30 @@ import { ThumbsDownIcon, ThumbsUpIcon } from "../icons/icons";
|
||||
type Feedback = "like" | "dislike";
|
||||
|
||||
const giveFeedback = async (
|
||||
queryId: number,
|
||||
messageId: number,
|
||||
feedback: Feedback
|
||||
): Promise<boolean> => {
|
||||
const response = await fetch("/api/query-feedback", {
|
||||
const response = await fetch("/api/chat/create-chat-message-feedback", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query_id: queryId,
|
||||
feedback,
|
||||
chat_message_id: messageId,
|
||||
is_positive: feedback === "like",
|
||||
}),
|
||||
});
|
||||
return response.ok;
|
||||
};
|
||||
|
||||
interface QAFeedbackIconProps {
|
||||
queryId: number;
|
||||
messageId: number;
|
||||
setPopup: (popupSpec: PopupSpec | null) => void;
|
||||
feedbackType: Feedback;
|
||||
}
|
||||
|
||||
const QAFeedback = ({
|
||||
queryId,
|
||||
messageId,
|
||||
setPopup,
|
||||
feedbackType,
|
||||
}: QAFeedbackIconProps) => {
|
||||
@ -40,7 +40,7 @@ const QAFeedback = ({
|
||||
return (
|
||||
<div
|
||||
onClick={async () => {
|
||||
const isSuccessful = await giveFeedback(queryId, feedbackType);
|
||||
const isSuccessful = await giveFeedback(messageId, feedbackType);
|
||||
if (isSuccessful) {
|
||||
setPopup({
|
||||
message: "Thanks for your feedback!",
|
||||
@ -70,20 +70,24 @@ const QAFeedback = ({
|
||||
};
|
||||
|
||||
interface QAFeedbackBlockProps {
|
||||
queryId: number;
|
||||
messageId: number;
|
||||
setPopup: (popupSpec: PopupSpec | null) => void;
|
||||
}
|
||||
|
||||
export const QAFeedbackBlock = ({
|
||||
queryId,
|
||||
messageId,
|
||||
setPopup,
|
||||
}: QAFeedbackBlockProps) => {
|
||||
return (
|
||||
<div className="flex">
|
||||
<QAFeedback queryId={queryId} setPopup={setPopup} feedbackType="like" />
|
||||
<QAFeedback
|
||||
messageId={messageId}
|
||||
setPopup={setPopup}
|
||||
feedbackType="like"
|
||||
/>
|
||||
<div className="ml-2">
|
||||
<QAFeedback
|
||||
queryId={queryId}
|
||||
messageId={messageId}
|
||||
setPopup={setPopup}
|
||||
feedbackType="dislike"
|
||||
/>
|
||||
|
@ -11,7 +11,6 @@ import {
|
||||
} from "@/lib/search/interfaces";
|
||||
import { QAFeedbackBlock } from "./QAFeedback";
|
||||
import { DocumentDisplay } from "./DocumentDisplay";
|
||||
import { ResponseSection, StatusOptions } from "./results/ResponseSection";
|
||||
import { QuotesSection } from "./results/QuotesSection";
|
||||
import { AnswerSection } from "./results/AnswerSection";
|
||||
import { ThreeDots } from "react-loader-spinner";
|
||||
@ -50,7 +49,7 @@ export const SearchResultsDisplay = ({
|
||||
}
|
||||
|
||||
const isPersona = personaName !== null;
|
||||
const { answer, quotes, documents, error, queryEventId } = searchResponse;
|
||||
const { answer, quotes, documents, error, messageId } = searchResponse;
|
||||
|
||||
if (isFetching && !answer && !documents) {
|
||||
return (
|
||||
@ -147,10 +146,10 @@ export const SearchResultsDisplay = ({
|
||||
isAnswerable={validQuestionResponse.answerable}
|
||||
/>
|
||||
|
||||
{searchResponse.queryEventId !== null && (
|
||||
{searchResponse.messageId !== null && (
|
||||
<div className="absolute right-3 bottom-3">
|
||||
<QAFeedbackBlock
|
||||
queryId={searchResponse.queryEventId}
|
||||
messageId={searchResponse.messageId}
|
||||
setPopup={setPopup}
|
||||
/>
|
||||
</div>
|
||||
@ -166,11 +165,12 @@ export const SearchResultsDisplay = ({
|
||||
<div className="font-bold text-emphasis border-b mb-3 pb-1 border-border text-lg">
|
||||
Results
|
||||
</div>
|
||||
{removeDuplicateDocs(documents).map((document) => (
|
||||
{removeDuplicateDocs(documents).map((document, ind) => (
|
||||
<DocumentDisplay
|
||||
key={document.document_id}
|
||||
document={document}
|
||||
queryEventId={queryEventId}
|
||||
documentRank={ind + 1}
|
||||
messageId={messageId}
|
||||
isSelected={selectedDocumentIds.has(document.document_id)}
|
||||
setPopup={setPopup}
|
||||
/>
|
||||
|
@ -95,7 +95,7 @@ export const SearchSection = ({
|
||||
suggestedFlowType: null,
|
||||
selectedDocIndices: null,
|
||||
error: null,
|
||||
queryEventId: null,
|
||||
messageId: null,
|
||||
};
|
||||
const updateCurrentAnswer = (answer: string) =>
|
||||
setSearchResponse((prevState) => ({
|
||||
@ -132,10 +132,10 @@ export const SearchSection = ({
|
||||
...(prevState || initialSearchResponse),
|
||||
error,
|
||||
}));
|
||||
const updateQueryEventId = (queryEventId: number) =>
|
||||
const updateMessageId = (messageId: number) =>
|
||||
setSearchResponse((prevState) => ({
|
||||
...(prevState || initialSearchResponse),
|
||||
queryEventId,
|
||||
messageId,
|
||||
}));
|
||||
|
||||
let lastSearchCancellationToken = useRef<CancellationToken | null>(null);
|
||||
@ -190,9 +190,9 @@ export const SearchSection = ({
|
||||
cancellationToken: lastSearchCancellationToken.current,
|
||||
fn: updateError,
|
||||
}),
|
||||
updateQueryEventId: cancellable({
|
||||
updateMessageId: cancellable({
|
||||
cancellationToken: lastSearchCancellationToken.current,
|
||||
fn: updateQueryEventId,
|
||||
fn: updateMessageId,
|
||||
}),
|
||||
selectedSearchType: searchType ?? selectedSearchType,
|
||||
offset: offset ?? defaultOverrides.offset,
|
||||
|
@ -62,10 +62,6 @@ export interface LLMRelevanceFilterPacket {
|
||||
relevant_chunk_indices: number[];
|
||||
}
|
||||
|
||||
export interface QueryEventIdPacket {
|
||||
query_event_id: number;
|
||||
}
|
||||
|
||||
export interface SearchResponse {
|
||||
suggestedSearchType: SearchType | null;
|
||||
suggestedFlowType: FlowType | null;
|
||||
@ -74,7 +70,7 @@ export interface SearchResponse {
|
||||
documents: DanswerDocument[] | null;
|
||||
selectedDocIndices: number[] | null;
|
||||
error: string | null;
|
||||
queryEventId: number | null;
|
||||
messageId: number | null;
|
||||
}
|
||||
|
||||
export enum SourceCategory {
|
||||
@ -116,7 +112,7 @@ export interface SearchRequestArgs {
|
||||
updateSuggestedSearchType: (searchType: SearchType) => void;
|
||||
updateSuggestedFlowType: (flowType: FlowType) => void;
|
||||
updateError: (error: string) => void;
|
||||
updateQueryEventId: (queryEventID: number) => void;
|
||||
updateMessageId: (messageId: number) => void;
|
||||
selectedSearchType: SearchType | null;
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { BackendMessage } from "@/app/chat/interfaces";
|
||||
import {
|
||||
AnswerPiecePacket,
|
||||
DanswerDocument,
|
||||
DocumentInfoPacket,
|
||||
ErrorMessagePacket,
|
||||
LLMRelevanceFilterPacket,
|
||||
QueryEventIdPacket,
|
||||
Quote,
|
||||
QuotesInfoPacket,
|
||||
SearchRequestArgs,
|
||||
@ -26,7 +26,7 @@ export const searchRequestStreamed = async ({
|
||||
updateSuggestedFlowType,
|
||||
updateSelectedDocIndices,
|
||||
updateError,
|
||||
updateQueryEventId,
|
||||
updateMessageId,
|
||||
}: SearchRequestArgs) => {
|
||||
let answer = "";
|
||||
let quotes: Quote[] | null = null;
|
||||
@ -78,7 +78,7 @@ export const searchRequestStreamed = async ({
|
||||
| QuotesInfoPacket
|
||||
| DocumentInfoPacket
|
||||
| LLMRelevanceFilterPacket
|
||||
| QueryEventIdPacket
|
||||
| BackendMessage
|
||||
>(decoder.decode(value, { stream: true }), previousPartialChunk);
|
||||
if (!completedChunks.length && !partialChunk) {
|
||||
break;
|
||||
@ -150,9 +150,9 @@ export const searchRequestStreamed = async ({
|
||||
return;
|
||||
}
|
||||
|
||||
// check for query ID section
|
||||
if (Object.hasOwn(chunk, "query_event_id")) {
|
||||
updateQueryEventId((chunk as QueryEventIdPacket).query_event_id);
|
||||
// check for message ID section
|
||||
if (Object.hasOwn(chunk, "message_id")) {
|
||||
updateMessageId((chunk as BackendMessage).message_id);
|
||||
return;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user