mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-03-29 11:12:02 +01:00
Cancelling searches when submitting a new one, no longer truncating at 7 docs, showing a warning message when no quotes are found
This commit is contained in:
parent
cb59e77278
commit
af329d31fb
@ -34,6 +34,7 @@ export const SearchBar: React.FC<SearchBarProps> = ({
|
||||
<div className="flex items-center w-full border-2 border-gray-600 rounded px-4 py-2 focus-within:border-blue-500">
|
||||
<MagnifyingGlass className="text-gray-400" />
|
||||
<textarea
|
||||
autoFocus
|
||||
className="flex-grow ml-2 h-6 bg-transparent outline-none placeholder-gray-400 overflow-hidden whitespace-normal resize-none"
|
||||
role="textarea"
|
||||
aria-multiline
|
||||
|
@ -86,21 +86,34 @@ export const SearchResultsDisplay: React.FC<SearchResultsDisplayProps> = ({
|
||||
<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-[280px] hover:bg-gray-800"
|
||||
href={quoteInfo.link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{getSourceIcon(quoteInfo.source_type, "20")}
|
||||
<p className="truncate break-all ml-2">
|
||||
{quoteInfo.semantic_identifier ||
|
||||
quoteInfo.document_id}
|
||||
</p>
|
||||
</a>
|
||||
))}
|
||||
{dedupedQuotes.length > 0 ? (
|
||||
dedupedQuotes.map((quoteInfo) => (
|
||||
<a
|
||||
key={quoteInfo.document_id}
|
||||
className="p-2 ml-1 border border-gray-800 rounded-lg text-sm flex max-w-[280px] hover:bg-gray-800"
|
||||
href={quoteInfo.link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{getSourceIcon(quoteInfo.source_type, "20")}
|
||||
<p className="truncate break-all ml-2">
|
||||
{quoteInfo.semantic_identifier ||
|
||||
quoteInfo.document_id}
|
||||
</p>
|
||||
</a>
|
||||
))
|
||||
) : (
|
||||
<div className="flex">
|
||||
<InfoIcon
|
||||
size="20"
|
||||
className="text-red-500 my-auto flex flex-shrink-0"
|
||||
/>
|
||||
<div className="text-red-500 text-sm my-auto ml-1">
|
||||
Did not find any exact quotes to support the above
|
||||
answer.
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
@ -126,30 +139,28 @@ export const SearchResultsDisplay: React.FC<SearchResultsDisplayProps> = ({
|
||||
<div className="font-bold border-b mb-4 pb-1 border-gray-800">
|
||||
Results
|
||||
</div>
|
||||
{removeDuplicateDocs(documents)
|
||||
.slice(0, 7)
|
||||
.map((doc) => (
|
||||
<div
|
||||
key={doc.semantic_identifier}
|
||||
className="text-sm border-b border-gray-800 mb-3"
|
||||
{removeDuplicateDocs(documents).map((doc) => (
|
||||
<div
|
||||
key={doc.semantic_identifier}
|
||||
className="text-sm border-b border-gray-800 mb-3"
|
||||
>
|
||||
<a
|
||||
className={
|
||||
"rounded-lg flex font-bold " +
|
||||
(doc.link ? "" : "pointer-events-none")
|
||||
}
|
||||
href={doc.link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<a
|
||||
className={
|
||||
"rounded-lg flex font-bold " +
|
||||
(doc.link ? "" : "pointer-events-none")
|
||||
}
|
||||
href={doc.link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{getSourceIcon(doc.source_type, "20")}
|
||||
<p className="truncate break-all ml-2">
|
||||
{doc.semantic_identifier || doc.document_id}
|
||||
</p>
|
||||
</a>
|
||||
<p className="pl-1 py-3 text-gray-200">{doc.blurb}</p>
|
||||
</div>
|
||||
))}
|
||||
{getSourceIcon(doc.source_type, "20")}
|
||||
<p className="truncate break-all ml-2">
|
||||
{doc.semantic_identifier || doc.document_id}
|
||||
</p>
|
||||
</a>
|
||||
<p className="pl-1 py-3 text-gray-200">{doc.blurb}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useRef, useState } from "react";
|
||||
import { SearchBar } from "./SearchBar";
|
||||
import { SearchResultsDisplay } from "./SearchResultsDisplay";
|
||||
import { SourceSelector } from "./Filters";
|
||||
@ -19,6 +19,7 @@ import {
|
||||
import { searchRequestStreamed } from "@/lib/search/streaming";
|
||||
import Cookies from "js-cookie";
|
||||
import { SearchHelper } from "./SearchHelper";
|
||||
import { CancellationToken, cancellable } from "@/lib/search/cancellable";
|
||||
|
||||
const SEARCH_DEFAULT_OVERRIDES_START: SearchDefaultOverrides = {
|
||||
forceDisplayQA: false,
|
||||
@ -88,21 +89,43 @@ export const SearchSection: React.FC<SearchSectionProps> = ({
|
||||
suggestedFlowType,
|
||||
}));
|
||||
|
||||
let lastSearchCancellationToken = useRef<CancellationToken | null>(null);
|
||||
const onSearch = async ({
|
||||
searchType,
|
||||
offset,
|
||||
}: SearchRequestOverrides = {}) => {
|
||||
// cancel the prior search if it hasn't finished
|
||||
if (lastSearchCancellationToken.current) {
|
||||
lastSearchCancellationToken.current.cancel();
|
||||
}
|
||||
lastSearchCancellationToken.current = new CancellationToken();
|
||||
|
||||
setIsFetching(true);
|
||||
setSearchResponse(initialSearchResponse);
|
||||
|
||||
await searchRequestStreamed({
|
||||
query,
|
||||
sources,
|
||||
updateCurrentAnswer,
|
||||
updateQuotes,
|
||||
updateDocs,
|
||||
updateSuggestedSearchType,
|
||||
updateSuggestedFlowType,
|
||||
updateCurrentAnswer: cancellable({
|
||||
cancellationToken: lastSearchCancellationToken.current,
|
||||
fn: updateCurrentAnswer,
|
||||
}),
|
||||
updateQuotes: cancellable({
|
||||
cancellationToken: lastSearchCancellationToken.current,
|
||||
fn: updateQuotes,
|
||||
}),
|
||||
updateDocs: cancellable({
|
||||
cancellationToken: lastSearchCancellationToken.current,
|
||||
fn: updateDocs,
|
||||
}),
|
||||
updateSuggestedSearchType: cancellable({
|
||||
cancellationToken: lastSearchCancellationToken.current,
|
||||
fn: updateSuggestedSearchType,
|
||||
}),
|
||||
updateSuggestedFlowType: cancellable({
|
||||
cancellationToken: lastSearchCancellationToken.current,
|
||||
fn: updateSuggestedFlowType,
|
||||
}),
|
||||
selectedSearchType: searchType ?? selectedSearchType,
|
||||
offset: offset ?? defaultOverrides.offset,
|
||||
});
|
||||
|
42
web/src/lib/search/cancellable.ts
Normal file
42
web/src/lib/search/cancellable.ts
Normal file
@ -0,0 +1,42 @@
|
||||
export class CancellationToken {
|
||||
private shouldCancel = false;
|
||||
|
||||
cancel() {
|
||||
this.shouldCancel = true;
|
||||
}
|
||||
|
||||
get isCancellationRequested() {
|
||||
return this.shouldCancel;
|
||||
}
|
||||
}
|
||||
|
||||
interface CancellableArgs {
|
||||
cancellationToken: CancellationToken;
|
||||
fn: (...args: any[]) => any;
|
||||
}
|
||||
|
||||
export const cancellable = ({ cancellationToken, fn }: CancellableArgs) => {
|
||||
return (...args: any[]): any => {
|
||||
if (cancellationToken.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
return fn(...args);
|
||||
};
|
||||
};
|
||||
|
||||
interface AsyncCancellableArgs {
|
||||
cancellationToken: CancellationToken;
|
||||
fn: (...args: any[]) => Promise<any>;
|
||||
}
|
||||
|
||||
export const asyncCancellable = ({
|
||||
cancellationToken,
|
||||
fn,
|
||||
}: AsyncCancellableArgs) => {
|
||||
return async (...args: any[]): Promise<any> => {
|
||||
if (cancellationToken.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
return await fn(...args);
|
||||
};
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user