mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-10-04 12:58:42 +02:00
Fix feedback display
This commit is contained in:
@@ -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>
|
||||||
);
|
);
|
||||||
|
@@ -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}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@@ -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"
|
||||||
/>
|
/>
|
||||||
|
@@ -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"
|
||||||
/>
|
/>
|
||||||
|
@@ -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}
|
||||||
/>
|
/>
|
||||||
|
@@ -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,
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user