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:
Weves 2023-06-29 20:38:34 -07:00 committed by Chris Weaver
parent cb59e77278
commit af329d31fb
4 changed files with 121 additions and 44 deletions

View File

@ -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"> <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" /> <MagnifyingGlass className="text-gray-400" />
<textarea <textarea
autoFocus
className="flex-grow ml-2 h-6 bg-transparent outline-none placeholder-gray-400 overflow-hidden whitespace-normal resize-none" className="flex-grow ml-2 h-6 bg-transparent outline-none placeholder-gray-400 overflow-hidden whitespace-normal resize-none"
role="textarea" role="textarea"
aria-multiline aria-multiline

View File

@ -86,7 +86,8 @@ export const SearchResultsDisplay: React.FC<SearchResultsDisplayProps> = ({
<LoadingAnimation text="Finding quotes" size="text-sm" /> <LoadingAnimation text="Finding quotes" size="text-sm" />
) : ( ) : (
<div className="flex"> <div className="flex">
{dedupedQuotes.map((quoteInfo) => ( {dedupedQuotes.length > 0 ? (
dedupedQuotes.map((quoteInfo) => (
<a <a
key={quoteInfo.document_id} 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" className="p-2 ml-1 border border-gray-800 rounded-lg text-sm flex max-w-[280px] hover:bg-gray-800"
@ -100,7 +101,19 @@ export const SearchResultsDisplay: React.FC<SearchResultsDisplayProps> = ({
quoteInfo.document_id} quoteInfo.document_id}
</p> </p>
</a> </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> </div>
)} )}
</> </>
@ -126,9 +139,7 @@ export const SearchResultsDisplay: React.FC<SearchResultsDisplayProps> = ({
<div className="font-bold border-b mb-4 pb-1 border-gray-800"> <div className="font-bold border-b mb-4 pb-1 border-gray-800">
Results Results
</div> </div>
{removeDuplicateDocs(documents) {removeDuplicateDocs(documents).map((doc) => (
.slice(0, 7)
.map((doc) => (
<div <div
key={doc.semantic_identifier} key={doc.semantic_identifier}
className="text-sm border-b border-gray-800 mb-3" className="text-sm border-b border-gray-800 mb-3"

View File

@ -1,6 +1,6 @@
"use client"; "use client";
import { useState } from "react"; import { useRef, useState } from "react";
import { SearchBar } from "./SearchBar"; import { SearchBar } from "./SearchBar";
import { SearchResultsDisplay } from "./SearchResultsDisplay"; import { SearchResultsDisplay } from "./SearchResultsDisplay";
import { SourceSelector } from "./Filters"; import { SourceSelector } from "./Filters";
@ -19,6 +19,7 @@ import {
import { searchRequestStreamed } from "@/lib/search/streaming"; import { searchRequestStreamed } from "@/lib/search/streaming";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { SearchHelper } from "./SearchHelper"; import { SearchHelper } from "./SearchHelper";
import { CancellationToken, cancellable } from "@/lib/search/cancellable";
const SEARCH_DEFAULT_OVERRIDES_START: SearchDefaultOverrides = { const SEARCH_DEFAULT_OVERRIDES_START: SearchDefaultOverrides = {
forceDisplayQA: false, forceDisplayQA: false,
@ -88,21 +89,43 @@ export const SearchSection: React.FC<SearchSectionProps> = ({
suggestedFlowType, suggestedFlowType,
})); }));
let lastSearchCancellationToken = useRef<CancellationToken | null>(null);
const onSearch = async ({ const onSearch = async ({
searchType, searchType,
offset, offset,
}: SearchRequestOverrides = {}) => { }: SearchRequestOverrides = {}) => {
// cancel the prior search if it hasn't finished
if (lastSearchCancellationToken.current) {
lastSearchCancellationToken.current.cancel();
}
lastSearchCancellationToken.current = new CancellationToken();
setIsFetching(true); setIsFetching(true);
setSearchResponse(initialSearchResponse); setSearchResponse(initialSearchResponse);
await searchRequestStreamed({ await searchRequestStreamed({
query, query,
sources, sources,
updateCurrentAnswer, updateCurrentAnswer: cancellable({
updateQuotes, cancellationToken: lastSearchCancellationToken.current,
updateDocs, fn: updateCurrentAnswer,
updateSuggestedSearchType, }),
updateSuggestedFlowType, 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, selectedSearchType: searchType ?? selectedSearchType,
offset: offset ?? defaultOverrides.offset, offset: offset ?? defaultOverrides.offset,
}); });

View 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);
};
};