mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-05-30 09:40:35 +02:00
Just display docs if QA fails
This commit is contained in:
parent
0b8c69ceeb
commit
51e05e3948
@ -9,6 +9,7 @@ import {
|
|||||||
Notebook,
|
Notebook,
|
||||||
Key,
|
Key,
|
||||||
Trash,
|
Trash,
|
||||||
|
Info,
|
||||||
} from "@phosphor-icons/react";
|
} from "@phosphor-icons/react";
|
||||||
|
|
||||||
interface IconProps {
|
interface IconProps {
|
||||||
@ -66,3 +67,10 @@ export const GoogleDriveIcon = ({
|
|||||||
}: IconProps) => {
|
}: IconProps) => {
|
||||||
return <GoogleDriveLogo size={size} className={className} />;
|
return <GoogleDriveLogo size={size} className={className} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const InfoIcon = ({
|
||||||
|
size = "16",
|
||||||
|
className = defaultTailwindCSS,
|
||||||
|
}: IconProps) => {
|
||||||
|
return <Info size={size} className={className} />;
|
||||||
|
};
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Quote, Document } from "./types";
|
import { Quote, Document, SearchResponse } from "./types";
|
||||||
import { getSourceIcon } from "../source";
|
import { getSourceIcon } from "../source";
|
||||||
import { LoadingAnimation } from "../Loading";
|
import { LoadingAnimation } from "../Loading";
|
||||||
|
import { InfoIcon } from "../icons/icons";
|
||||||
|
|
||||||
const removeDuplicateDocs = (documents: Document[]) => {
|
const removeDuplicateDocs = (documents: Document[]) => {
|
||||||
const seen = new Set<string>();
|
const seen = new Set<string>();
|
||||||
@ -19,33 +20,35 @@ const removeDuplicateDocs = (documents: Document[]) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface SearchResultsDisplayProps {
|
interface SearchResultsDisplayProps {
|
||||||
answer: string | null;
|
searchResponse: SearchResponse | null;
|
||||||
quotes: Record<string, Quote> | null;
|
|
||||||
documents: Document[] | null;
|
|
||||||
isFetching: boolean;
|
isFetching: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SearchResultsDisplay: React.FC<SearchResultsDisplayProps> = ({
|
export const SearchResultsDisplay: React.FC<SearchResultsDisplayProps> = ({
|
||||||
answer,
|
searchResponse,
|
||||||
quotes,
|
|
||||||
documents,
|
|
||||||
isFetching,
|
isFetching,
|
||||||
}) => {
|
}) => {
|
||||||
if (!answer) {
|
if (!searchResponse) {
|
||||||
if (isFetching) {
|
|
||||||
return (
|
|
||||||
<div className="flex">
|
|
||||||
<div className="mx-auto">
|
|
||||||
<LoadingAnimation />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (answer === null) {
|
if (isFetching) {
|
||||||
return <div>Unable to find an answer</div>;
|
return (
|
||||||
|
<div className="flex">
|
||||||
|
<div className="mx-auto">
|
||||||
|
<LoadingAnimation />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { answer, quotes, documents } = searchResponse;
|
||||||
|
if (answer === null && documents === null && quotes === null) {
|
||||||
|
return (
|
||||||
|
<div className="text-red-800">
|
||||||
|
Something went wrong, please try again.
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dedupedQuotes: Quote[] = [];
|
const dedupedQuotes: Quote[] = [];
|
||||||
@ -61,38 +64,53 @@ export const SearchResultsDisplay: React.FC<SearchResultsDisplayProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="p-4 border-2 rounded-md border-gray-700">
|
{answer && (
|
||||||
<div className="flex mb-1">
|
<div className="p-4 border-2 rounded-md border-gray-700">
|
||||||
<h2 className="text font-bold my-auto">AI Answer</h2>
|
<div className="flex mb-1">
|
||||||
</div>
|
<h2 className="text font-bold my-auto">AI Answer</h2>
|
||||||
<p className="mb-4">{answer}</p>
|
</div>
|
||||||
|
<p className="mb-4">{answer}</p>
|
||||||
|
|
||||||
|
{quotes !== null && (
|
||||||
|
<>
|
||||||
|
<h2 className="text-sm font-bold mb-2">Sources</h2>
|
||||||
|
{isFetching && dedupedQuotes.length === 0 ? (
|
||||||
|
<LoadingAnimation text="Finding quotes" size="text-sm" />
|
||||||
|
) : (
|
||||||
|
<div className="flex">
|
||||||
|
{dedupedQuotes.map((quoteInfo) => (
|
||||||
|
<a
|
||||||
|
key={quoteInfo.document_id}
|
||||||
|
className="p-2 ml-1 border border-gray-800 rounded-lg text-sm flex max-w-[230px] hover:bg-gray-800"
|
||||||
|
href={quoteInfo.link}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
{getSourceIcon(quoteInfo.source_type, "20")}
|
||||||
|
<p className="truncate break-all ml-0.5">
|
||||||
|
{quoteInfo.semantic_identifier || quoteInfo.document_id}
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!answer && !isFetching && (
|
||||||
|
<div className="flex">
|
||||||
|
<InfoIcon
|
||||||
|
size="20"
|
||||||
|
className="text-red-800 my-auto flex flex-shrink-0"
|
||||||
|
/>
|
||||||
|
<div className="text-red-800 text-xs my-auto ml-1">
|
||||||
|
GPT hurt itself in its confusion :(
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{quotes !== null && (
|
|
||||||
<>
|
|
||||||
<h2 className="text-sm font-bold mb-2">Sources</h2>
|
|
||||||
{isFetching && dedupedQuotes.length === 0 ? (
|
|
||||||
<LoadingAnimation text="Finding quotes" size="text-sm" />
|
|
||||||
) : (
|
|
||||||
<div className="flex">
|
|
||||||
{dedupedQuotes.map((quoteInfo) => (
|
|
||||||
<a
|
|
||||||
key={quoteInfo.document_id}
|
|
||||||
className="p-2 ml-1 border border-gray-800 rounded-lg text-sm flex max-w-[230px] hover:bg-gray-800"
|
|
||||||
href={quoteInfo.link}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
{getSourceIcon(quoteInfo.source_type, "20")}
|
|
||||||
<p className="truncate break-all ml-0.5">
|
|
||||||
{quoteInfo.semantic_identifier || quoteInfo.document_id}
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{/* Only display docs once we're done fetching to avoid distracting from the AI answer*/}
|
{/* Only display docs once we're done fetching to avoid distracting from the AI answer*/}
|
||||||
{!isFetching && documents && documents.length > 0 && (
|
{!isFetching && documents && documents.length > 0 && (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
@ -103,7 +121,7 @@ export const SearchResultsDisplay: React.FC<SearchResultsDisplayProps> = ({
|
|||||||
.slice(0, 7)
|
.slice(0, 7)
|
||||||
.map((doc) => (
|
.map((doc) => (
|
||||||
<div
|
<div
|
||||||
key={doc.document_id}
|
key={doc.semantic_identifier}
|
||||||
className="text-sm border-b border-gray-800 mb-3"
|
className="text-sm border-b border-gray-800 mb-3"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
|
@ -3,7 +3,13 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { SearchBar } from "./SearchBar";
|
import { SearchBar } from "./SearchBar";
|
||||||
import { SearchResultsDisplay } from "./SearchResultsDisplay";
|
import { SearchResultsDisplay } from "./SearchResultsDisplay";
|
||||||
import { Quote, Document } from "./types";
|
import { Quote, Document, SearchResponse } from "./types";
|
||||||
|
|
||||||
|
const initialSearchResponse: SearchResponse = {
|
||||||
|
answer: null,
|
||||||
|
quotes: null,
|
||||||
|
documents: null,
|
||||||
|
};
|
||||||
|
|
||||||
const processSingleChunk = (
|
const processSingleChunk = (
|
||||||
chunk: string,
|
chunk: string,
|
||||||
@ -99,9 +105,6 @@ const searchRequestStreamed = async (
|
|||||||
answer += answerChunk;
|
answer += answerChunk;
|
||||||
updateCurrentAnswer(answer);
|
updateCurrentAnswer(answer);
|
||||||
} else if (chunk.answer_finished) {
|
} else if (chunk.answer_finished) {
|
||||||
// set quotes as non-null to signify that the answer is finished and
|
|
||||||
// we're now looking for quotes
|
|
||||||
updateQuotes({});
|
|
||||||
if (
|
if (
|
||||||
!answer.endsWith(".") &&
|
!answer.endsWith(".") &&
|
||||||
!answer.endsWith("?") &&
|
!answer.endsWith("?") &&
|
||||||
@ -129,9 +132,9 @@ const searchRequestStreamed = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const SearchSection: React.FC<{}> = () => {
|
export const SearchSection: React.FC<{}> = () => {
|
||||||
const [answer, setAnswer] = useState<string | null>("");
|
const [searchResponse, setSearchResponse] = useState<SearchResponse | null>(
|
||||||
const [quotes, setQuotes] = useState<Record<string, Quote> | null>(null);
|
null
|
||||||
const [documents, setDocuments] = useState<Document[] | null>(null);
|
);
|
||||||
const [isFetching, setIsFetching] = useState(false);
|
const [isFetching, setIsFetching] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -139,26 +142,36 @@ export const SearchSection: React.FC<{}> = () => {
|
|||||||
<SearchBar
|
<SearchBar
|
||||||
onSearch={(query) => {
|
onSearch={(query) => {
|
||||||
setIsFetching(true);
|
setIsFetching(true);
|
||||||
setAnswer(null);
|
setSearchResponse({
|
||||||
setQuotes(null);
|
answer: null,
|
||||||
setDocuments(null);
|
quotes: null,
|
||||||
searchRequestStreamed(query, setAnswer, setQuotes, setDocuments).then(
|
documents: null,
|
||||||
({ quotes }) => {
|
});
|
||||||
setIsFetching(false);
|
searchRequestStreamed(
|
||||||
// if no quotes were given, set to empty object so that the SearchResultsDisplay
|
query,
|
||||||
// component knows that the search was successful but no quotes were found
|
(answer) =>
|
||||||
if (!quotes) {
|
setSearchResponse((prevState) => ({
|
||||||
setQuotes({});
|
...(prevState || initialSearchResponse),
|
||||||
}
|
answer,
|
||||||
}
|
})),
|
||||||
);
|
(quotes) =>
|
||||||
|
setSearchResponse((prevState) => ({
|
||||||
|
...(prevState || initialSearchResponse),
|
||||||
|
quotes,
|
||||||
|
})),
|
||||||
|
(documents) =>
|
||||||
|
setSearchResponse((prevState) => ({
|
||||||
|
...(prevState || initialSearchResponse),
|
||||||
|
documents,
|
||||||
|
}))
|
||||||
|
).then(() => {
|
||||||
|
setIsFetching(false);
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<SearchResultsDisplay
|
<SearchResultsDisplay
|
||||||
answer={answer}
|
searchResponse={searchResponse}
|
||||||
quotes={quotes}
|
|
||||||
documents={documents}
|
|
||||||
isFetching={isFetching}
|
isFetching={isFetching}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,6 +17,7 @@ export interface Document {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchResponse {
|
export interface SearchResponse {
|
||||||
answer: string;
|
answer: string | null;
|
||||||
quotes: Record<string, Quote>;
|
quotes: Record<string, Quote> | null;
|
||||||
|
documents: Document[] | null;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user