Improve FE for no-retrieval personas

This commit is contained in:
Weves
2024-02-17 19:44:11 -08:00
committed by Chris Weaver
parent 927e85319c
commit 61e2e68cf9
7 changed files with 143 additions and 95 deletions

View File

@@ -5,7 +5,7 @@ personas:
# this is for DanswerBot to use when tagged in a non-configured channel # this is for DanswerBot to use when tagged in a non-configured channel
# Careful setting specific IDs, this won't autoincrement the next ID value for postgres # Careful setting specific IDs, this won't autoincrement the next ID value for postgres
- id: 0 - id: 0
name: "Knowledge Assistant" name: "Danswer"
description: > description: >
Assistant with access to documents from your Connected Sources. Assistant with access to documents from your Connected Sources.
# Default Prompt objects attached to the persona, see prompts.yaml # Default Prompt objects attached to the persona, see prompts.yaml
@@ -40,7 +40,7 @@ personas:
- id: 1 - id: 1
name: "AI Assistant (No Sources)" name: "GPT"
description: > description: >
Assistant with no access to documents. Chat with just the Language Model. Assistant with no access to documents. Chat with just the Language Model.
prompts: prompts:
@@ -53,7 +53,7 @@ personas:
- id: 2 - id: 2
name: "Paraphrase Assistant" name: "Paraphrase"
description: > description: >
Assistant that is heavily constrained and only provides exact quotes from Connected Sources. Assistant that is heavily constrained and only provides exact quotes from Connected Sources.
prompts: prompts:

View File

@@ -214,9 +214,27 @@ function smallerNumberFirstComparator(a: number, b: number) {
return a > b ? 1 : -1; return a > b ? 1 : -1;
} }
function closerToZeroNegativesFirstComparator(a: number, b: number) {
if (a < 0 && b > 0) {
return -1;
}
if (a > 0 && b < 0) {
return 1;
}
const absA = Math.abs(a);
const absB = Math.abs(b);
if (absA === absB) {
return a > b ? 1 : -1;
}
return absA > absB ? 1 : -1;
}
export function personaComparator(a: Persona, b: Persona) { export function personaComparator(a: Persona, b: Persona) {
if (a.display_priority === null && b.display_priority === null) { if (a.display_priority === null && b.display_priority === null) {
return smallerNumberFirstComparator(a.id, b.id); return closerToZeroNegativesFirstComparator(a.id, b.id);
} }
if (a.display_priority !== b.display_priority) { if (a.display_priority !== b.display_priority) {
@@ -230,5 +248,5 @@ export function personaComparator(a: Persona, b: Persona) {
return smallerNumberFirstComparator(a.display_priority, b.display_priority); return smallerNumberFirstComparator(a.display_priority, b.display_priority);
} }
return smallerNumberFirstComparator(a.id, b.id); return closerToZeroNegativesFirstComparator(a.id, b.id);
} }

View File

@@ -22,6 +22,7 @@ import {
handleAutoScroll, handleAutoScroll,
handleChatFeedback, handleChatFeedback,
nameChatSession, nameChatSession,
personaIncludesRetrieval,
processRawChatHistory, processRawChatHistory,
sendMessage, sendMessage,
} from "./lib"; } from "./lib";
@@ -172,7 +173,7 @@ export const Chat = ({
const livePersona = selectedPersona || availablePersonas[0]; const livePersona = selectedPersona || availablePersonas[0];
useEffect(() => { useEffect(() => {
if (messageHistory.length === 0) { if (messageHistory.length === 0 && chatSessionId === null) {
setSelectedPersona( setSelectedPersona(
availablePersonas.find( availablePersonas.find(
(persona) => persona.id === defaultSelectedPersonaId (persona) => persona.id === defaultSelectedPersonaId
@@ -480,6 +481,10 @@ export const Chat = ({
} }
}; };
const retrievalDisabled = selectedPersona
? !personaIncludesRetrieval(selectedPersona)
: false;
return ( return (
<div className="flex w-full overflow-x-hidden" ref={masterFlexboxRef}> <div className="flex w-full overflow-x-hidden" ref={masterFlexboxRef}>
{popup} {popup}
@@ -510,6 +515,7 @@ export const Chat = ({
onPersonaChange={(persona) => { onPersonaChange={(persona) => {
if (persona) { if (persona) {
setSelectedPersona(persona); setSelectedPersona(persona);
textareaRef.current?.focus();
router.push(`/chat?personaId=${persona.id}`); router.push(`/chat?personaId=${persona.id}`);
} }
}} }}
@@ -527,6 +533,7 @@ export const Chat = ({
selectedPersona={selectedPersona} selectedPersona={selectedPersona}
handlePersonaSelect={(persona) => { handlePersonaSelect={(persona) => {
setSelectedPersona(persona); setSelectedPersona(persona);
textareaRef.current?.focus();
router.push(`/chat?personaId=${persona.id}`); router.push(`/chat?personaId=${persona.id}`);
}} }}
/> />
@@ -630,6 +637,7 @@ export const Chat = ({
}); });
} }
}} }}
retrievalDisabled={retrievalDisabled}
/> />
</div> </div>
); );
@@ -682,6 +690,7 @@ export const Chat = ({
<div className="absolute bottom-0 z-10 w-full bg-background border-t border-border"> <div className="absolute bottom-0 z-10 w-full bg-background border-t border-border">
<div className="w-full pb-4 pt-2"> <div className="w-full pb-4 pt-2">
{!retrievalDisabled && (
<div className="flex"> <div className="flex">
<div className="w-searchbar-xs 2xl:w-searchbar-sm 3xl:w-searchbar mx-auto px-4 pt-1 flex"> <div className="w-searchbar-xs 2xl:w-searchbar-sm 3xl:w-searchbar mx-auto px-4 pt-1 flex">
{selectedDocuments.length > 0 ? ( {selectedDocuments.length > 0 ? (
@@ -698,6 +707,7 @@ export const Chat = ({
)} )}
</div> </div>
</div> </div>
)}
<div className="flex justify-center py-2 max-w-screen-lg mx-auto mb-2"> <div className="flex justify-center py-2 max-w-screen-lg mx-auto mb-2">
<div className="w-full shrink relative px-4 w-searchbar-xs 2xl:w-searchbar-sm 3xl:w-searchbar mx-auto"> <div className="w-full shrink relative px-4 w-searchbar-xs 2xl:w-searchbar-sm 3xl:w-searchbar mx-auto">
@@ -785,6 +795,7 @@ export const Chat = ({
</div> </div>
</div> </div>
{!retrievalDisabled ? (
<ResizableSection <ResizableSection
intialWidth={documentSidebarInitialWidth} intialWidth={documentSidebarInitialWidth}
minWidth={400} minWidth={400}
@@ -800,6 +811,10 @@ export const Chat = ({
isLoading={isFetchingChatMessages} isLoading={isFetchingChatMessages}
/> />
</ResizableSection> </ResizableSection>
) : // Another option is to use a div with the width set to the initial width, so that the
// chat section appears in the same place as before
// <div style={documentSidebarInitialWidth ? {width: documentSidebarInitialWidth} : {}}></div>
null}
</> </>
) : ( ) : (
<div className="mx-auto h-full flex flex-col"> <div className="mx-auto h-full flex flex-col">

View File

@@ -124,9 +124,11 @@ export function ChatIntro({
</div> </div>
</div> </div>
{selectedPersona && selectedPersona.num_chunks !== 0 && (
<>
<Divider /> <Divider />
<div> <div>
{selectedPersona && selectedPersona.document_sets.length > 0 && ( {selectedPersona.document_sets.length > 0 && (
<div className="mt-2"> <div className="mt-2">
<p className="font-bold mb-1 mt-4 text-emphasis"> <p className="font-bold mb-1 mt-4 text-emphasis">
Knowledge Sets:{" "} Knowledge Sets:{" "}
@@ -181,6 +183,8 @@ export function ChatIntro({
</div> </div>
)} )}
</div> </div>
</>
)}
</div> </div>
) : ( ) : (
<div className="px-12 w-searchbar-xs 2xl:w-searchbar-sm 3xl:w-searchbar"> <div className="px-12 w-searchbar-xs 2xl:w-searchbar-sm 3xl:w-searchbar">

View File

@@ -14,6 +14,7 @@ import {
RetrievalType, RetrievalType,
StreamingError, StreamingError,
} from "./interfaces"; } from "./interfaces";
import { Persona } from "../admin/personas/interfaces";
export async function createChatSession(personaId: number): Promise<number> { export async function createChatSession(personaId: number): Promise<number> {
const createChatSessionResponse = await fetch( const createChatSessionResponse = await fetch(
@@ -349,3 +350,7 @@ export function processRawChatHistory(rawMessages: BackendMessage[]) {
return messages; return messages;
} }
export function personaIncludesRetrieval(selectedPersona: Persona) {
return selectedPersona.num_chunks !== 0;
}

View File

@@ -14,7 +14,6 @@ import { SearchSummary, ShowHideDocsButton } from "./SearchSummary";
import { SourceIcon } from "@/components/SourceIcon"; import { SourceIcon } from "@/components/SourceIcon";
import { ThreeDots } from "react-loader-spinner"; import { ThreeDots } from "react-loader-spinner";
import { SkippedSearch } from "./SkippedSearch"; import { SkippedSearch } from "./SkippedSearch";
import { SelectedDocuments } from "../modifiers/SelectedDocuments";
export const Hoverable: React.FC<{ export const Hoverable: React.FC<{
children: JSX.Element; children: JSX.Element;
@@ -42,6 +41,7 @@ export const AIMessage = ({
handleShowRetrieved, handleShowRetrieved,
handleSearchQueryEdit, handleSearchQueryEdit,
handleForceSearch, handleForceSearch,
retrievalDisabled,
}: { }: {
messageId: number | null; messageId: number | null;
content: string | JSX.Element; content: string | JSX.Element;
@@ -54,6 +54,7 @@ export const AIMessage = ({
handleShowRetrieved?: (messageNumber: number | null) => void; handleShowRetrieved?: (messageNumber: number | null) => void;
handleSearchQueryEdit?: (query: string) => void; handleSearchQueryEdit?: (query: string) => void;
handleForceSearch?: () => void; handleForceSearch?: () => void;
retrievalDisabled?: boolean;
}) => { }) => {
const [copyClicked, setCopyClicked] = useState(false); const [copyClicked, setCopyClicked] = useState(false);
return ( return (
@@ -72,7 +73,8 @@ export const AIMessage = ({
{query === undefined && {query === undefined &&
hasDocs && hasDocs &&
handleShowRetrieved !== undefined && handleShowRetrieved !== undefined &&
isCurrentlyShowingRetrieved !== undefined && ( isCurrentlyShowingRetrieved !== undefined &&
!retrievalDisabled && (
<div className="flex w-message-xs 2xl:w-message-sm 3xl:w-message-default absolute ml-8"> <div className="flex w-message-xs 2xl:w-message-sm 3xl:w-message-default absolute ml-8">
<div className="ml-auto"> <div className="ml-auto">
<ShowHideDocsButton <ShowHideDocsButton
@@ -88,7 +90,8 @@ export const AIMessage = ({
<div className="w-message-xs 2xl:w-message-sm 3xl:w-message-default break-words mt-1 ml-8"> <div className="w-message-xs 2xl:w-message-sm 3xl:w-message-default break-words mt-1 ml-8">
{query !== undefined && {query !== undefined &&
handleShowRetrieved !== undefined && handleShowRetrieved !== undefined &&
isCurrentlyShowingRetrieved !== undefined && ( isCurrentlyShowingRetrieved !== undefined &&
!retrievalDisabled && (
<div className="my-1"> <div className="my-1">
<SearchSummary <SearchSummary
query={query} query={query}
@@ -103,7 +106,8 @@ export const AIMessage = ({
{handleForceSearch && {handleForceSearch &&
content && content &&
query === undefined && query === undefined &&
!hasDocs && ( !hasDocs &&
!retrievalDisabled && (
<div className="my-1"> <div className="my-1">
<SkippedSearch handleForceSearch={handleForceSearch} /> <SkippedSearch handleForceSearch={handleForceSearch} />
</div> </div>

View File

@@ -95,6 +95,8 @@ export default async function Home() {
} }
// remove those marked as hidden by an admin // remove those marked as hidden by an admin
personas = personas.filter((persona) => persona.is_visible); personas = personas.filter((persona) => persona.is_visible);
// hide personas with no retrieval
personas = personas.filter((persona) => persona.num_chunks !== 0);
// sort them in priority order // sort them in priority order
personas.sort(personaComparator); personas.sort(personaComparator);