mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-10-11 05:36:03 +02:00
Fix assistant swap
This commit is contained in:
@@ -50,7 +50,7 @@ export default async function GalleryPage({
|
|||||||
chatSessions,
|
chatSessions,
|
||||||
availableSources,
|
availableSources,
|
||||||
availableDocumentSets: documentSets,
|
availableDocumentSets: documentSets,
|
||||||
availablePersonas: assistants,
|
availableAssistants: assistants,
|
||||||
availableTags: tags,
|
availableTags: tags,
|
||||||
llmProviders,
|
llmProviders,
|
||||||
folders,
|
folders,
|
||||||
|
@@ -52,7 +52,7 @@ export default async function GalleryPage({
|
|||||||
chatSessions,
|
chatSessions,
|
||||||
availableSources,
|
availableSources,
|
||||||
availableDocumentSets: documentSets,
|
availableDocumentSets: documentSets,
|
||||||
availablePersonas: assistants,
|
availableAssistants: assistants,
|
||||||
availableTags: tags,
|
availableTags: tags,
|
||||||
llmProviders,
|
llmProviders,
|
||||||
folders,
|
folders,
|
||||||
|
@@ -63,7 +63,6 @@ import { SettingsContext } from "@/components/settings/SettingsProvider";
|
|||||||
import Dropzone from "react-dropzone";
|
import Dropzone from "react-dropzone";
|
||||||
import { checkLLMSupportsImageInput, getFinalLLM } from "@/lib/llm/utils";
|
import { checkLLMSupportsImageInput, getFinalLLM } from "@/lib/llm/utils";
|
||||||
import { ChatInputBar } from "./input/ChatInputBar";
|
import { ChatInputBar } from "./input/ChatInputBar";
|
||||||
import { ConfigurationModal } from "./modal/configuration/ConfigurationModal";
|
|
||||||
import { useChatContext } from "@/components/context/ChatContext";
|
import { useChatContext } from "@/components/context/ChatContext";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { orderAssistantsForUser } from "@/lib/assistants/orderAssistants";
|
import { orderAssistantsForUser } from "@/lib/assistants/orderAssistants";
|
||||||
@@ -82,38 +81,29 @@ const SYSTEM_MESSAGE_ID = -3;
|
|||||||
export function ChatPage({
|
export function ChatPage({
|
||||||
toggle,
|
toggle,
|
||||||
documentSidebarInitialWidth,
|
documentSidebarInitialWidth,
|
||||||
defaultSelectedPersonaId,
|
defaultSelectedAssistantId,
|
||||||
toggledSidebar,
|
toggledSidebar,
|
||||||
}: {
|
}: {
|
||||||
toggle: () => void;
|
toggle: () => void;
|
||||||
documentSidebarInitialWidth?: number;
|
documentSidebarInitialWidth?: number;
|
||||||
defaultSelectedPersonaId?: number;
|
defaultSelectedAssistantId?: number;
|
||||||
toggledSidebar: boolean;
|
toggledSidebar: boolean;
|
||||||
}) {
|
}) {
|
||||||
const [configModalActiveTab, setConfigModalActiveTab] = useState<
|
const router = useRouter();
|
||||||
string | null
|
const searchParams = useSearchParams();
|
||||||
>(null);
|
|
||||||
let {
|
let {
|
||||||
user,
|
user,
|
||||||
chatSessions,
|
chatSessions,
|
||||||
availableSources,
|
availableSources,
|
||||||
availableDocumentSets,
|
availableDocumentSets,
|
||||||
availablePersonas,
|
availableAssistants,
|
||||||
llmProviders,
|
llmProviders,
|
||||||
folders,
|
folders,
|
||||||
openedFolders,
|
openedFolders,
|
||||||
} = useChatContext();
|
} = useChatContext();
|
||||||
|
|
||||||
const filteredAssistants = orderAssistantsForUser(availablePersonas, user);
|
// chat session
|
||||||
|
|
||||||
const [selectedAssistant, setSelectedAssistant] = useState<Persona | null>(
|
|
||||||
null
|
|
||||||
);
|
|
||||||
const [alternativeGeneratingAssistant, setAlternativeGeneratingAssistant] =
|
|
||||||
useState<Persona | null>(null);
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const searchParams = useSearchParams();
|
|
||||||
const existingChatIdRaw = searchParams.get("chatId");
|
const existingChatIdRaw = searchParams.get("chatId");
|
||||||
const existingChatSessionId = existingChatIdRaw
|
const existingChatSessionId = existingChatIdRaw
|
||||||
? parseInt(existingChatIdRaw)
|
? parseInt(existingChatIdRaw)
|
||||||
@@ -123,9 +113,51 @@ export function ChatPage({
|
|||||||
);
|
);
|
||||||
const chatSessionIdRef = useRef<number | null>(existingChatSessionId);
|
const chatSessionIdRef = useRef<number | null>(existingChatSessionId);
|
||||||
|
|
||||||
|
// LLM
|
||||||
const llmOverrideManager = useLlmOverride(selectedChatSession);
|
const llmOverrideManager = useLlmOverride(selectedChatSession);
|
||||||
|
|
||||||
const existingChatSessionPersonaId = selectedChatSession?.persona_id;
|
// Assistants
|
||||||
|
const filteredAssistants = orderAssistantsForUser(availableAssistants, user);
|
||||||
|
|
||||||
|
const existingChatSessionAssistantId = selectedChatSession?.persona_id;
|
||||||
|
const [selectedAssistant, setSelectedAssistant] = useState<
|
||||||
|
Persona | undefined
|
||||||
|
>(
|
||||||
|
// NOTE: look through available assistants here, so that even if the user
|
||||||
|
// has hidden this assistant it still shows the correct assistant when
|
||||||
|
// going back to an old chat session
|
||||||
|
existingChatSessionAssistantId !== undefined
|
||||||
|
? availableAssistants.find(
|
||||||
|
(assistant) => assistant.id === existingChatSessionAssistantId
|
||||||
|
)
|
||||||
|
: defaultSelectedAssistantId !== undefined
|
||||||
|
? availableAssistants.find(
|
||||||
|
(assistant) => assistant.id === defaultSelectedAssistantId
|
||||||
|
)
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
const setSelectedAssistantFromId = (assistantId: number) => {
|
||||||
|
// NOTE: also intentionally look through available assistants here, so that
|
||||||
|
// even if the user has hidden an assistant they can still go back to it
|
||||||
|
// for old chats
|
||||||
|
setSelectedAssistant(
|
||||||
|
availableAssistants.find((assistant) => assistant.id === assistantId)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const liveAssistant =
|
||||||
|
selectedAssistant || filteredAssistants[0] || availableAssistants[0];
|
||||||
|
|
||||||
|
// this is for "@"ing assistants
|
||||||
|
const [alternativeAssistant, setAlternativeAssistant] =
|
||||||
|
useState<Persona | null>(null);
|
||||||
|
|
||||||
|
// this is used to track which assistant is being used to generate the current message
|
||||||
|
// for example, this would come into play when:
|
||||||
|
// 1. default assistant is `Danswer`
|
||||||
|
// 2. we "@"ed the `GPT` assistant and sent a message
|
||||||
|
// 3. while the `GPT` assistant message is generating, we "@" the `Paraphrase` assistant
|
||||||
|
const [alternativeGeneratingAssistant, setAlternativeGeneratingAssistant] =
|
||||||
|
useState<Persona | null>(null);
|
||||||
|
|
||||||
// used to track whether or not the initial "submit on load" has been performed
|
// used to track whether or not the initial "submit on load" has been performed
|
||||||
// this only applies if `?submit-on-load=true` or `?submit-on-load=1` is in the URL
|
// this only applies if `?submit-on-load=true` or `?submit-on-load=1` is in the URL
|
||||||
@@ -182,14 +214,10 @@ export function ChatPage({
|
|||||||
async function initialSessionFetch() {
|
async function initialSessionFetch() {
|
||||||
if (existingChatSessionId === null) {
|
if (existingChatSessionId === null) {
|
||||||
setIsFetchingChatMessages(false);
|
setIsFetchingChatMessages(false);
|
||||||
if (defaultSelectedPersonaId !== undefined) {
|
if (defaultSelectedAssistantId !== undefined) {
|
||||||
setSelectedPersona(
|
setSelectedAssistantFromId(defaultSelectedAssistantId);
|
||||||
filteredAssistants.find(
|
|
||||||
(persona) => persona.id === defaultSelectedPersonaId
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
setSelectedPersona(undefined);
|
setSelectedAssistant(undefined);
|
||||||
}
|
}
|
||||||
setCompleteMessageDetail({
|
setCompleteMessageDetail({
|
||||||
sessionId: null,
|
sessionId: null,
|
||||||
@@ -214,12 +242,7 @@ export function ChatPage({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const chatSession = (await response.json()) as BackendChatSession;
|
const chatSession = (await response.json()) as BackendChatSession;
|
||||||
|
setSelectedAssistantFromId(chatSession.persona_id);
|
||||||
setSelectedPersona(
|
|
||||||
filteredAssistants.find(
|
|
||||||
(persona) => persona.id === chatSession.persona_id
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const newMessageMap = processRawChatHistory(chatSession.messages);
|
const newMessageMap = processRawChatHistory(chatSession.messages);
|
||||||
const newMessageHistory = buildLatestMessageChain(newMessageMap);
|
const newMessageHistory = buildLatestMessageChain(newMessageMap);
|
||||||
@@ -373,32 +396,18 @@ export function ChatPage({
|
|||||||
)
|
)
|
||||||
: { aiMessage: null };
|
: { aiMessage: null };
|
||||||
|
|
||||||
const [selectedPersona, setSelectedPersona] = useState<Persona | undefined>(
|
|
||||||
existingChatSessionPersonaId !== undefined
|
|
||||||
? filteredAssistants.find(
|
|
||||||
(persona) => persona.id === existingChatSessionPersonaId
|
|
||||||
)
|
|
||||||
: defaultSelectedPersonaId !== undefined
|
|
||||||
? filteredAssistants.find(
|
|
||||||
(persona) => persona.id === defaultSelectedPersonaId
|
|
||||||
)
|
|
||||||
: undefined
|
|
||||||
);
|
|
||||||
const livePersona =
|
|
||||||
selectedPersona || filteredAssistants[0] || availablePersonas[0];
|
|
||||||
|
|
||||||
const [chatSessionSharedStatus, setChatSessionSharedStatus] =
|
const [chatSessionSharedStatus, setChatSessionSharedStatus] =
|
||||||
useState<ChatSessionSharedStatus>(ChatSessionSharedStatus.Private);
|
useState<ChatSessionSharedStatus>(ChatSessionSharedStatus.Private);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (messageHistory.length === 0 && chatSessionIdRef.current === null) {
|
if (messageHistory.length === 0 && chatSessionIdRef.current === null) {
|
||||||
setSelectedPersona(
|
setSelectedAssistant(
|
||||||
filteredAssistants.find(
|
filteredAssistants.find(
|
||||||
(persona) => persona.id === defaultSelectedPersonaId
|
(persona) => persona.id === defaultSelectedAssistantId
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, [defaultSelectedPersonaId]);
|
}, [defaultSelectedAssistantId]);
|
||||||
|
|
||||||
const [
|
const [
|
||||||
selectedDocuments,
|
selectedDocuments,
|
||||||
@@ -414,7 +423,7 @@ export function ChatPage({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchMaxTokens() {
|
async function fetchMaxTokens() {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`/api/chat/max-selected-document-tokens?persona_id=${livePersona.id}`
|
`/api/chat/max-selected-document-tokens?persona_id=${liveAssistant.id}`
|
||||||
);
|
);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const maxTokens = (await response.json()).max_tokens as number;
|
const maxTokens = (await response.json()).max_tokens as number;
|
||||||
@@ -423,12 +432,12 @@ export function ChatPage({
|
|||||||
}
|
}
|
||||||
|
|
||||||
fetchMaxTokens();
|
fetchMaxTokens();
|
||||||
}, [livePersona]);
|
}, [liveAssistant]);
|
||||||
|
|
||||||
const filterManager = useFilters();
|
const filterManager = useFilters();
|
||||||
const [finalAvailableSources, finalAvailableDocumentSets] =
|
const [finalAvailableSources, finalAvailableDocumentSets] =
|
||||||
computeAvailableFilters({
|
computeAvailableFilters({
|
||||||
selectedPersona,
|
selectedPersona: selectedAssistant,
|
||||||
availableSources,
|
availableSources,
|
||||||
availableDocumentSets,
|
availableDocumentSets,
|
||||||
});
|
});
|
||||||
@@ -624,16 +633,16 @@ export function ChatPage({
|
|||||||
queryOverride,
|
queryOverride,
|
||||||
forceSearch,
|
forceSearch,
|
||||||
isSeededChat,
|
isSeededChat,
|
||||||
alternativeAssistant = null,
|
alternativeAssistantOverride = null,
|
||||||
}: {
|
}: {
|
||||||
messageIdToResend?: number;
|
messageIdToResend?: number;
|
||||||
messageOverride?: string;
|
messageOverride?: string;
|
||||||
queryOverride?: string;
|
queryOverride?: string;
|
||||||
forceSearch?: boolean;
|
forceSearch?: boolean;
|
||||||
isSeededChat?: boolean;
|
isSeededChat?: boolean;
|
||||||
alternativeAssistant?: Persona | null;
|
alternativeAssistantOverride?: Persona | null;
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
setAlternativeGeneratingAssistant(alternativeAssistant);
|
setAlternativeGeneratingAssistant(alternativeAssistantOverride);
|
||||||
|
|
||||||
clientScrollToBottom();
|
clientScrollToBottom();
|
||||||
let currChatSessionId: number;
|
let currChatSessionId: number;
|
||||||
@@ -643,7 +652,7 @@ export function ChatPage({
|
|||||||
|
|
||||||
if (isNewSession) {
|
if (isNewSession) {
|
||||||
currChatSessionId = await createChatSession(
|
currChatSessionId = await createChatSession(
|
||||||
livePersona?.id || 0,
|
liveAssistant?.id || 0,
|
||||||
searchParamBasedChatSessionName
|
searchParamBasedChatSessionName
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -721,9 +730,9 @@ export function ChatPage({
|
|||||||
parentMessage = frozenMessageMap.get(SYSTEM_MESSAGE_ID) || null;
|
parentMessage = frozenMessageMap.get(SYSTEM_MESSAGE_ID) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentAssistantId = alternativeAssistant
|
const currentAssistantId = alternativeAssistantOverride
|
||||||
? alternativeAssistant.id
|
? alternativeAssistantOverride.id
|
||||||
: selectedAssistant?.id;
|
: alternativeAssistant?.id || liveAssistant.id;
|
||||||
|
|
||||||
resetInputBar();
|
resetInputBar();
|
||||||
|
|
||||||
@@ -751,7 +760,7 @@ export function ChatPage({
|
|||||||
fileDescriptors: currentMessageFiles,
|
fileDescriptors: currentMessageFiles,
|
||||||
parentMessageId: lastSuccessfulMessageId,
|
parentMessageId: lastSuccessfulMessageId,
|
||||||
chatSessionId: currChatSessionId,
|
chatSessionId: currChatSessionId,
|
||||||
promptId: livePersona?.prompts[0]?.id || 0,
|
promptId: liveAssistant?.prompts[0]?.id || 0,
|
||||||
filters: buildFilters(
|
filters: buildFilters(
|
||||||
filterManager.selectedSources,
|
filterManager.selectedSources,
|
||||||
filterManager.selectedDocumentSets,
|
filterManager.selectedDocumentSets,
|
||||||
@@ -868,7 +877,7 @@ export function ChatPage({
|
|||||||
files: finalMessage?.files || aiMessageImages || [],
|
files: finalMessage?.files || aiMessageImages || [],
|
||||||
toolCalls: finalMessage?.tool_calls || toolCalls,
|
toolCalls: finalMessage?.tool_calls || toolCalls,
|
||||||
parentMessageId: newUserMessageId,
|
parentMessageId: newUserMessageId,
|
||||||
alternateAssistantID: selectedAssistant?.id,
|
alternateAssistantID: alternativeAssistant?.id,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -964,19 +973,23 @@ export function ChatPage({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPersonaChange = (persona: Persona | null) => {
|
const onAssistantChange = (assistant: Persona | null) => {
|
||||||
if (persona && persona.id !== livePersona.id) {
|
if (assistant && assistant.id !== liveAssistant.id) {
|
||||||
// remove uploaded files
|
// remove uploaded files
|
||||||
setCurrentMessageFiles([]);
|
setCurrentMessageFiles([]);
|
||||||
setSelectedPersona(persona);
|
setSelectedAssistant(assistant);
|
||||||
textAreaRef.current?.focus();
|
textAreaRef.current?.focus();
|
||||||
router.push(buildChatUrl(searchParams, null, persona.id));
|
router.push(buildChatUrl(searchParams, null, assistant.id));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleImageUpload = (acceptedFiles: File[]) => {
|
const handleImageUpload = (acceptedFiles: File[]) => {
|
||||||
const llmAcceptsImages = checkLLMSupportsImageInput(
|
const llmAcceptsImages = checkLLMSupportsImageInput(
|
||||||
...getFinalLLM(llmProviders, livePersona, llmOverrideManager.llmOverride)
|
...getFinalLLM(
|
||||||
|
llmProviders,
|
||||||
|
liveAssistant,
|
||||||
|
llmOverrideManager.llmOverride
|
||||||
|
)
|
||||||
);
|
);
|
||||||
const imageFiles = acceptedFiles.filter((file) =>
|
const imageFiles = acceptedFiles.filter((file) =>
|
||||||
file.type.startsWith("image/")
|
file.type.startsWith("image/")
|
||||||
@@ -1058,23 +1071,23 @@ export function ChatPage({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const includes = checkAnyAssistantHasSearch(
|
const includes = checkAnyAssistantHasSearch(
|
||||||
messageHistory,
|
messageHistory,
|
||||||
availablePersonas,
|
availableAssistants,
|
||||||
livePersona
|
liveAssistant
|
||||||
);
|
);
|
||||||
setRetrievalEnabled(includes);
|
setRetrievalEnabled(includes);
|
||||||
}, [messageHistory, availablePersonas, livePersona]);
|
}, [messageHistory, availableAssistants, liveAssistant]);
|
||||||
|
|
||||||
const [retrievalEnabled, setRetrievalEnabled] = useState(() => {
|
const [retrievalEnabled, setRetrievalEnabled] = useState(() => {
|
||||||
return checkAnyAssistantHasSearch(
|
return checkAnyAssistantHasSearch(
|
||||||
messageHistory,
|
messageHistory,
|
||||||
availablePersonas,
|
availableAssistants,
|
||||||
livePersona
|
liveAssistant
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const innerSidebarElementRef = useRef<HTMLDivElement>(null);
|
const innerSidebarElementRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const currentPersona = selectedAssistant || livePersona;
|
const currentPersona = alternativeAssistant || liveAssistant;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleKeyDown = (event: KeyboardEvent) => {
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
@@ -1176,21 +1189,8 @@ export function ChatPage({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<ConfigurationModal
|
|
||||||
chatSessionId={chatSessionIdRef.current!}
|
|
||||||
activeTab={configModalActiveTab}
|
|
||||||
setActiveTab={setConfigModalActiveTab}
|
|
||||||
onClose={() => setConfigModalActiveTab(null)}
|
|
||||||
filterManager={filterManager}
|
|
||||||
availableAssistants={filteredAssistants}
|
|
||||||
selectedAssistant={livePersona}
|
|
||||||
setSelectedAssistant={onPersonaChange}
|
|
||||||
llmProviders={llmProviders}
|
|
||||||
llmOverrideManager={llmOverrideManager}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="flex h-[calc(100dvh)] flex-col w-full">
|
<div className="flex h-[calc(100dvh)] flex-col w-full">
|
||||||
{livePersona && (
|
{liveAssistant && (
|
||||||
<FunctionalHeader
|
<FunctionalHeader
|
||||||
page="chat"
|
page="chat"
|
||||||
setSharingModalVisible={
|
setSharingModalVisible={
|
||||||
@@ -1239,7 +1239,7 @@ export function ChatPage({
|
|||||||
!isStreaming && (
|
!isStreaming && (
|
||||||
<ChatIntro
|
<ChatIntro
|
||||||
availableSources={finalAvailableSources}
|
availableSources={finalAvailableSources}
|
||||||
selectedPersona={livePersona}
|
selectedPersona={liveAssistant}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
@@ -1319,7 +1319,7 @@ export function ChatPage({
|
|||||||
|
|
||||||
const currentAlternativeAssistant =
|
const currentAlternativeAssistant =
|
||||||
message.alternateAssistantID != null
|
message.alternateAssistantID != null
|
||||||
? availablePersonas.find(
|
? availableAssistants.find(
|
||||||
(persona) =>
|
(persona) =>
|
||||||
persona.id ==
|
persona.id ==
|
||||||
message.alternateAssistantID
|
message.alternateAssistantID
|
||||||
@@ -1342,7 +1342,7 @@ export function ChatPage({
|
|||||||
toggleDocumentSelectionAspects
|
toggleDocumentSelectionAspects
|
||||||
}
|
}
|
||||||
docs={message.documents}
|
docs={message.documents}
|
||||||
currentPersona={livePersona}
|
currentPersona={liveAssistant}
|
||||||
alternativeAssistant={
|
alternativeAssistant={
|
||||||
currentAlternativeAssistant
|
currentAlternativeAssistant
|
||||||
}
|
}
|
||||||
@@ -1352,7 +1352,7 @@ export function ChatPage({
|
|||||||
query={
|
query={
|
||||||
messageHistory[i]?.query || undefined
|
messageHistory[i]?.query || undefined
|
||||||
}
|
}
|
||||||
personaName={livePersona.name}
|
personaName={liveAssistant.name}
|
||||||
citedDocuments={getCitedDocumentsFromMessage(
|
citedDocuments={getCitedDocumentsFromMessage(
|
||||||
message
|
message
|
||||||
)}
|
)}
|
||||||
@@ -1404,7 +1404,7 @@ export function ChatPage({
|
|||||||
messageIdToResend:
|
messageIdToResend:
|
||||||
previousMessage.messageId,
|
previousMessage.messageId,
|
||||||
queryOverride: newQuery,
|
queryOverride: newQuery,
|
||||||
alternativeAssistant:
|
alternativeAssistantOverride:
|
||||||
currentAlternativeAssistant,
|
currentAlternativeAssistant,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1435,7 +1435,7 @@ export function ChatPage({
|
|||||||
messageIdToResend:
|
messageIdToResend:
|
||||||
previousMessage.messageId,
|
previousMessage.messageId,
|
||||||
forceSearch: true,
|
forceSearch: true,
|
||||||
alternativeAssistant:
|
alternativeAssistantOverride:
|
||||||
currentAlternativeAssistant,
|
currentAlternativeAssistant,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -1460,9 +1460,9 @@ export function ChatPage({
|
|||||||
return (
|
return (
|
||||||
<div key={messageReactComponentKey}>
|
<div key={messageReactComponentKey}>
|
||||||
<AIMessage
|
<AIMessage
|
||||||
currentPersona={livePersona}
|
currentPersona={liveAssistant}
|
||||||
messageId={message.messageId}
|
messageId={message.messageId}
|
||||||
personaName={livePersona.name}
|
personaName={liveAssistant.name}
|
||||||
content={
|
content={
|
||||||
<p className="text-red-700 text-sm my-auto">
|
<p className="text-red-700 text-sm my-auto">
|
||||||
{message.message}
|
{message.message}
|
||||||
@@ -1481,13 +1481,13 @@ export function ChatPage({
|
|||||||
key={`${messageHistory.length}-${chatSessionIdRef.current}`}
|
key={`${messageHistory.length}-${chatSessionIdRef.current}`}
|
||||||
>
|
>
|
||||||
<AIMessage
|
<AIMessage
|
||||||
currentPersona={livePersona}
|
currentPersona={liveAssistant}
|
||||||
alternativeAssistant={
|
alternativeAssistant={
|
||||||
alternativeGeneratingAssistant ??
|
alternativeGeneratingAssistant ??
|
||||||
selectedAssistant
|
alternativeAssistant
|
||||||
}
|
}
|
||||||
messageId={null}
|
messageId={null}
|
||||||
personaName={livePersona.name}
|
personaName={liveAssistant.name}
|
||||||
content={
|
content={
|
||||||
<div className="text-sm my-auto">
|
<div className="text-sm my-auto">
|
||||||
<ThreeDots
|
<ThreeDots
|
||||||
@@ -1513,7 +1513,7 @@ export function ChatPage({
|
|||||||
{currentPersona &&
|
{currentPersona &&
|
||||||
currentPersona.starter_messages &&
|
currentPersona.starter_messages &&
|
||||||
currentPersona.starter_messages.length > 0 &&
|
currentPersona.starter_messages.length > 0 &&
|
||||||
selectedPersona &&
|
selectedAssistant &&
|
||||||
messageHistory.length === 0 &&
|
messageHistory.length === 0 &&
|
||||||
!isFetchingChatMessages && (
|
!isFetchingChatMessages && (
|
||||||
<div
|
<div
|
||||||
@@ -1570,32 +1570,25 @@ export function ChatPage({
|
|||||||
<ChatInputBar
|
<ChatInputBar
|
||||||
showDocs={() => setDocumentSelection(true)}
|
showDocs={() => setDocumentSelection(true)}
|
||||||
selectedDocuments={selectedDocuments}
|
selectedDocuments={selectedDocuments}
|
||||||
setSelectedAssistant={onPersonaChange}
|
// assistant stuff
|
||||||
onSetSelectedAssistant={(
|
assistantOptions={filteredAssistants}
|
||||||
alternativeAssistant: Persona | null
|
selectedAssistant={liveAssistant}
|
||||||
) => {
|
setSelectedAssistant={onAssistantChange}
|
||||||
setSelectedAssistant(alternativeAssistant);
|
setAlternativeAssistant={setAlternativeAssistant}
|
||||||
}}
|
alternativeAssistant={alternativeAssistant}
|
||||||
alternativeAssistant={selectedAssistant}
|
// end assistant stuff
|
||||||
personas={filteredAssistants}
|
|
||||||
message={message}
|
message={message}
|
||||||
setMessage={setMessage}
|
setMessage={setMessage}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
isStreaming={isStreaming}
|
isStreaming={isStreaming}
|
||||||
setIsCancelled={setIsCancelled}
|
setIsCancelled={setIsCancelled}
|
||||||
retrievalDisabled={
|
|
||||||
!personaIncludesRetrieval(currentPersona)
|
|
||||||
}
|
|
||||||
filterManager={filterManager}
|
filterManager={filterManager}
|
||||||
llmOverrideManager={llmOverrideManager}
|
llmOverrideManager={llmOverrideManager}
|
||||||
selectedAssistant={livePersona}
|
|
||||||
files={currentMessageFiles}
|
files={currentMessageFiles}
|
||||||
setFiles={setCurrentMessageFiles}
|
setFiles={setCurrentMessageFiles}
|
||||||
handleFileUpload={handleImageUpload}
|
handleFileUpload={handleImageUpload}
|
||||||
setConfigModalActiveTab={setConfigModalActiveTab}
|
|
||||||
textAreaRef={textAreaRef}
|
textAreaRef={textAreaRef}
|
||||||
chatSessionId={chatSessionIdRef.current!}
|
chatSessionId={chatSessionIdRef.current!}
|
||||||
availableAssistants={availablePersonas}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -5,10 +5,10 @@ import { ChatPage } from "./ChatPage";
|
|||||||
import FunctionalWrapper from "./shared_chat_search/FunctionalWrapper";
|
import FunctionalWrapper from "./shared_chat_search/FunctionalWrapper";
|
||||||
|
|
||||||
export default function WrappedChat({
|
export default function WrappedChat({
|
||||||
defaultPersonaId,
|
defaultAssistantId,
|
||||||
initiallyToggled,
|
initiallyToggled,
|
||||||
}: {
|
}: {
|
||||||
defaultPersonaId?: number;
|
defaultAssistantId?: number;
|
||||||
initiallyToggled: boolean;
|
initiallyToggled: boolean;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
@@ -17,7 +17,7 @@ export default function WrappedChat({
|
|||||||
content={(toggledSidebar, toggle) => (
|
content={(toggledSidebar, toggle) => (
|
||||||
<ChatPage
|
<ChatPage
|
||||||
toggle={toggle}
|
toggle={toggle}
|
||||||
defaultSelectedPersonaId={defaultPersonaId}
|
defaultSelectedAssistantId={defaultAssistantId}
|
||||||
toggledSidebar={toggledSidebar}
|
toggledSidebar={toggledSidebar}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@@ -21,7 +21,6 @@ import { IconType } from "react-icons";
|
|||||||
import Popup from "../../../components/popup/Popup";
|
import Popup from "../../../components/popup/Popup";
|
||||||
import { LlmTab } from "../modal/configuration/LlmTab";
|
import { LlmTab } from "../modal/configuration/LlmTab";
|
||||||
import { AssistantsTab } from "../modal/configuration/AssistantsTab";
|
import { AssistantsTab } from "../modal/configuration/AssistantsTab";
|
||||||
import ChatInputAssistant from "./ChatInputAssistant";
|
|
||||||
import { DanswerDocument } from "@/lib/search/interfaces";
|
import { DanswerDocument } from "@/lib/search/interfaces";
|
||||||
import { AssistantIcon } from "@/components/assistants/AssistantIcon";
|
import { AssistantIcon } from "@/components/assistants/AssistantIcon";
|
||||||
import { Tooltip } from "@/components/tooltip/Tooltip";
|
import { Tooltip } from "@/components/tooltip/Tooltip";
|
||||||
@@ -29,7 +28,6 @@ import { Hoverable } from "@/components/Hoverable";
|
|||||||
const MAX_INPUT_HEIGHT = 200;
|
const MAX_INPUT_HEIGHT = 200;
|
||||||
|
|
||||||
export function ChatInputBar({
|
export function ChatInputBar({
|
||||||
personas,
|
|
||||||
showDocs,
|
showDocs,
|
||||||
selectedDocuments,
|
selectedDocuments,
|
||||||
message,
|
message,
|
||||||
@@ -37,34 +35,32 @@ export function ChatInputBar({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
isStreaming,
|
isStreaming,
|
||||||
setIsCancelled,
|
setIsCancelled,
|
||||||
retrievalDisabled,
|
|
||||||
filterManager,
|
filterManager,
|
||||||
llmOverrideManager,
|
llmOverrideManager,
|
||||||
onSetSelectedAssistant,
|
|
||||||
selectedAssistant,
|
|
||||||
files,
|
|
||||||
|
|
||||||
|
// assistants
|
||||||
|
selectedAssistant,
|
||||||
|
assistantOptions,
|
||||||
setSelectedAssistant,
|
setSelectedAssistant,
|
||||||
|
setAlternativeAssistant,
|
||||||
|
|
||||||
|
files,
|
||||||
setFiles,
|
setFiles,
|
||||||
handleFileUpload,
|
handleFileUpload,
|
||||||
setConfigModalActiveTab,
|
|
||||||
textAreaRef,
|
textAreaRef,
|
||||||
alternativeAssistant,
|
alternativeAssistant,
|
||||||
chatSessionId,
|
chatSessionId,
|
||||||
availableAssistants,
|
|
||||||
}: {
|
}: {
|
||||||
showDocs: () => void;
|
showDocs: () => void;
|
||||||
selectedDocuments: DanswerDocument[];
|
selectedDocuments: DanswerDocument[];
|
||||||
availableAssistants: Persona[];
|
assistantOptions: Persona[];
|
||||||
onSetSelectedAssistant: (alternativeAssistant: Persona | null) => void;
|
setAlternativeAssistant: (alternativeAssistant: Persona | null) => void;
|
||||||
setSelectedAssistant: (assistant: Persona) => void;
|
setSelectedAssistant: (assistant: Persona) => void;
|
||||||
personas: Persona[];
|
|
||||||
message: string;
|
message: string;
|
||||||
setMessage: (message: string) => void;
|
setMessage: (message: string) => void;
|
||||||
onSubmit: () => void;
|
onSubmit: () => void;
|
||||||
isStreaming: boolean;
|
isStreaming: boolean;
|
||||||
setIsCancelled: (value: boolean) => void;
|
setIsCancelled: (value: boolean) => void;
|
||||||
retrievalDisabled: boolean;
|
|
||||||
filterManager: FilterManager;
|
filterManager: FilterManager;
|
||||||
llmOverrideManager: LlmOverrideManager;
|
llmOverrideManager: LlmOverrideManager;
|
||||||
selectedAssistant: Persona;
|
selectedAssistant: Persona;
|
||||||
@@ -72,7 +68,6 @@ export function ChatInputBar({
|
|||||||
files: FileDescriptor[];
|
files: FileDescriptor[];
|
||||||
setFiles: (files: FileDescriptor[]) => void;
|
setFiles: (files: FileDescriptor[]) => void;
|
||||||
handleFileUpload: (files: File[]) => void;
|
handleFileUpload: (files: File[]) => void;
|
||||||
setConfigModalActiveTab: (tab: string) => void;
|
|
||||||
textAreaRef: React.RefObject<HTMLTextAreaElement>;
|
textAreaRef: React.RefObject<HTMLTextAreaElement>;
|
||||||
chatSessionId?: number;
|
chatSessionId?: number;
|
||||||
}) {
|
}) {
|
||||||
@@ -136,8 +131,10 @@ export function ChatInputBar({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Update selected persona
|
// Update selected persona
|
||||||
const updateCurrentPersona = (persona: Persona) => {
|
const updatedTaggedAssistant = (assistant: Persona) => {
|
||||||
onSetSelectedAssistant(persona.id == selectedAssistant.id ? null : persona);
|
setAlternativeAssistant(
|
||||||
|
assistant.id == selectedAssistant.id ? null : assistant
|
||||||
|
);
|
||||||
hideSuggestions();
|
hideSuggestions();
|
||||||
setMessage("");
|
setMessage("");
|
||||||
};
|
};
|
||||||
@@ -160,8 +157,8 @@ export function ChatInputBar({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const filteredPersonas = personas.filter((persona) =>
|
const assistantTagOptions = assistantOptions.filter((assistant) =>
|
||||||
persona.name.toLowerCase().startsWith(
|
assistant.name.toLowerCase().startsWith(
|
||||||
message
|
message
|
||||||
.slice(message.lastIndexOf("@") + 1)
|
.slice(message.lastIndexOf("@") + 1)
|
||||||
.split(/\s/)[0]
|
.split(/\s/)[0]
|
||||||
@@ -174,18 +171,18 @@ export function ChatInputBar({
|
|||||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||||
if (
|
if (
|
||||||
showSuggestions &&
|
showSuggestions &&
|
||||||
filteredPersonas.length > 0 &&
|
assistantTagOptions.length > 0 &&
|
||||||
(e.key === "Tab" || e.key == "Enter")
|
(e.key === "Tab" || e.key == "Enter")
|
||||||
) {
|
) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (assistantIconIndex == filteredPersonas.length) {
|
if (assistantIconIndex == assistantTagOptions.length) {
|
||||||
window.open("/assistants/new", "_blank");
|
window.open("/assistants/new", "_blank");
|
||||||
hideSuggestions();
|
hideSuggestions();
|
||||||
setMessage("");
|
setMessage("");
|
||||||
} else {
|
} else {
|
||||||
const option =
|
const option =
|
||||||
filteredPersonas[assistantIconIndex >= 0 ? assistantIconIndex : 0];
|
assistantTagOptions[assistantIconIndex >= 0 ? assistantIconIndex : 0];
|
||||||
updateCurrentPersona(option);
|
updatedTaggedAssistant(option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!showSuggestions) {
|
if (!showSuggestions) {
|
||||||
@@ -195,7 +192,7 @@ export function ChatInputBar({
|
|||||||
if (e.key === "ArrowDown") {
|
if (e.key === "ArrowDown") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setAssistantIconIndex((assistantIconIndex) =>
|
setAssistantIconIndex((assistantIconIndex) =>
|
||||||
Math.min(assistantIconIndex + 1, filteredPersonas.length)
|
Math.min(assistantIconIndex + 1, assistantTagOptions.length)
|
||||||
);
|
);
|
||||||
} else if (e.key === "ArrowUp") {
|
} else if (e.key === "ArrowUp") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -219,35 +216,36 @@ export function ChatInputBar({
|
|||||||
mx-auto
|
mx-auto
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{showSuggestions && filteredPersonas.length > 0 && (
|
{showSuggestions && assistantTagOptions.length > 0 && (
|
||||||
<div
|
<div
|
||||||
ref={suggestionsRef}
|
ref={suggestionsRef}
|
||||||
className="text-sm absolute inset-x-0 top-0 w-full transform -translate-y-full"
|
className="text-sm absolute inset-x-0 top-0 w-full transform -translate-y-full"
|
||||||
>
|
>
|
||||||
<div className="rounded-lg py-1.5 bg-background border border-border-medium shadow-lg mx-2 px-1.5 mt-2 rounded z-10">
|
<div className="rounded-lg py-1.5 bg-background border border-border-medium shadow-lg mx-2 px-1.5 mt-2 rounded z-10">
|
||||||
{filteredPersonas.map((currentPersona, index) => (
|
{assistantTagOptions.map((currentAssistant, index) => (
|
||||||
<button
|
<button
|
||||||
key={index}
|
key={index}
|
||||||
className={`px-2 ${
|
className={`px-2 ${
|
||||||
assistantIconIndex == index && "bg-hover-lightish"
|
assistantIconIndex == index && "bg-hover-lightish"
|
||||||
} rounded rounded-lg content-start flex gap-x-1 py-2 w-full hover:bg-hover-lightish cursor-pointer`}
|
} rounded rounded-lg content-start flex gap-x-1 py-2 w-full hover:bg-hover-lightish cursor-pointer`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
updateCurrentPersona(currentPersona);
|
updatedTaggedAssistant(currentAssistant);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p className="font-bold">{currentPersona.name}</p>
|
<p className="font-bold">{currentAssistant.name}</p>
|
||||||
<p className="line-clamp-1">
|
<p className="line-clamp-1">
|
||||||
{currentPersona.id == selectedAssistant.id &&
|
{currentAssistant.id == selectedAssistant.id &&
|
||||||
"(default) "}
|
"(default) "}
|
||||||
{currentPersona.description}
|
{currentAssistant.description}
|
||||||
</p>
|
</p>
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
<a
|
<a
|
||||||
key={filteredPersonas.length}
|
key={assistantTagOptions.length}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className={`${
|
className={`${
|
||||||
assistantIconIndex == filteredPersonas.length && "bg-hover"
|
assistantIconIndex == assistantTagOptions.length &&
|
||||||
|
"bg-hover"
|
||||||
} rounded rounded-lg px-3 flex gap-x-1 py-2 w-full items-center hover:bg-hover-lightish cursor-pointer"`}
|
} rounded rounded-lg px-3 flex gap-x-1 py-2 w-full items-center hover:bg-hover-lightish cursor-pointer"`}
|
||||||
href="/assistants/new"
|
href="/assistants/new"
|
||||||
>
|
>
|
||||||
@@ -301,7 +299,7 @@ export function ChatInputBar({
|
|||||||
|
|
||||||
<Hoverable
|
<Hoverable
|
||||||
icon={FiX}
|
icon={FiX}
|
||||||
onClick={() => onSetSelectedAssistant(null)}
|
onClick={() => setAlternativeAssistant(null)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -409,7 +407,7 @@ export function ChatInputBar({
|
|||||||
removePadding
|
removePadding
|
||||||
content={(close) => (
|
content={(close) => (
|
||||||
<AssistantsTab
|
<AssistantsTab
|
||||||
availableAssistants={availableAssistants}
|
availableAssistants={assistantOptions}
|
||||||
llmProviders={llmProviders}
|
llmProviders={llmProviders}
|
||||||
selectedAssistant={selectedAssistant}
|
selectedAssistant={selectedAssistant}
|
||||||
onSelect={(assistant) => {
|
onSelect={(assistant) => {
|
||||||
|
@@ -505,7 +505,7 @@ export function removeMessage(
|
|||||||
|
|
||||||
export function checkAnyAssistantHasSearch(
|
export function checkAnyAssistantHasSearch(
|
||||||
messageHistory: Message[],
|
messageHistory: Message[],
|
||||||
availablePersonas: Persona[],
|
availableAssistants: Persona[],
|
||||||
livePersona: Persona
|
livePersona: Persona
|
||||||
): boolean {
|
): boolean {
|
||||||
const response =
|
const response =
|
||||||
@@ -516,8 +516,8 @@ export function checkAnyAssistantHasSearch(
|
|||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const alternateAssistant = availablePersonas.find(
|
const alternateAssistant = availableAssistants.find(
|
||||||
(persona) => persona.id === message.alternateAssistantID
|
(assistant) => assistant.id === message.alternateAssistantID
|
||||||
);
|
);
|
||||||
return alternateAssistant
|
return alternateAssistant
|
||||||
? personaIncludesRetrieval(alternateAssistant)
|
? personaIncludesRetrieval(alternateAssistant)
|
||||||
|
@@ -1,180 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import React, { useEffect } from "react";
|
|
||||||
import { Modal } from "../../../../components/Modal";
|
|
||||||
import { FilterManager, LlmOverrideManager } from "@/lib/hooks";
|
|
||||||
import { FiltersTab } from "./FiltersTab";
|
|
||||||
import { FiCpu, FiFilter, FiX } from "react-icons/fi";
|
|
||||||
import { IconType } from "react-icons";
|
|
||||||
import { FaBrain } from "react-icons/fa";
|
|
||||||
import { AssistantsTab } from "./AssistantsTab";
|
|
||||||
import { Persona } from "@/app/admin/assistants/interfaces";
|
|
||||||
import { LlmTab } from "./LlmTab";
|
|
||||||
import { LLMProviderDescriptor } from "@/app/admin/models/llm/interfaces";
|
|
||||||
import { AssistantsIcon, IconProps } from "@/components/icons/icons";
|
|
||||||
|
|
||||||
const TabButton = ({
|
|
||||||
label,
|
|
||||||
icon: Icon,
|
|
||||||
isActive,
|
|
||||||
onClick,
|
|
||||||
}: {
|
|
||||||
label: string;
|
|
||||||
icon: IconType;
|
|
||||||
isActive: boolean;
|
|
||||||
onClick: () => void;
|
|
||||||
}) => (
|
|
||||||
<button
|
|
||||||
onClick={onClick}
|
|
||||||
className={`
|
|
||||||
pb-4
|
|
||||||
pt-6
|
|
||||||
px-2
|
|
||||||
text-emphasis
|
|
||||||
font-bold
|
|
||||||
${isActive ? "border-b-2 border-accent" : ""}
|
|
||||||
hover:bg-hover-light
|
|
||||||
hover:text-strong
|
|
||||||
transition
|
|
||||||
duration-200
|
|
||||||
ease-in-out
|
|
||||||
flex
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Icon className="inline-block mr-2 my-auto" size="16" />
|
|
||||||
|
|
||||||
<p className="my-auto">{label}</p>
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
|
|
||||||
export function ConfigurationModal({
|
|
||||||
activeTab,
|
|
||||||
setActiveTab,
|
|
||||||
onClose,
|
|
||||||
availableAssistants,
|
|
||||||
selectedAssistant,
|
|
||||||
setSelectedAssistant,
|
|
||||||
filterManager,
|
|
||||||
llmProviders,
|
|
||||||
llmOverrideManager,
|
|
||||||
chatSessionId,
|
|
||||||
}: {
|
|
||||||
activeTab: string | null;
|
|
||||||
setActiveTab: (tab: string | null) => void;
|
|
||||||
onClose: () => void;
|
|
||||||
availableAssistants: Persona[];
|
|
||||||
selectedAssistant: Persona;
|
|
||||||
setSelectedAssistant: (assistant: Persona) => void;
|
|
||||||
filterManager: FilterManager;
|
|
||||||
llmProviders: LLMProviderDescriptor[];
|
|
||||||
llmOverrideManager: LlmOverrideManager;
|
|
||||||
chatSessionId?: number;
|
|
||||||
}) {
|
|
||||||
useEffect(() => {
|
|
||||||
const handleKeyDown = (event: KeyboardEvent) => {
|
|
||||||
if (event.key === "Escape") {
|
|
||||||
onClose();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener("keydown", handleKeyDown);
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener("keydown", handleKeyDown);
|
|
||||||
};
|
|
||||||
}, [onClose]);
|
|
||||||
|
|
||||||
if (!activeTab) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
onOutsideClick={onClose}
|
|
||||||
noPadding
|
|
||||||
className="
|
|
||||||
w-4/6
|
|
||||||
h-4/6
|
|
||||||
flex
|
|
||||||
flex-col
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div className="rounded flex flex-col overflow-hidden">
|
|
||||||
<div className="mb-4">
|
|
||||||
<div className="flex border-b border-border bg-background-emphasis">
|
|
||||||
<div className="flex px-6 gap-x-2">
|
|
||||||
<TabButton
|
|
||||||
label="Assistants"
|
|
||||||
icon={FaBrain}
|
|
||||||
isActive={activeTab === "assistants"}
|
|
||||||
onClick={() => setActiveTab("assistants")}
|
|
||||||
/>
|
|
||||||
<TabButton
|
|
||||||
label="Models"
|
|
||||||
icon={FiCpu}
|
|
||||||
isActive={activeTab === "llms"}
|
|
||||||
onClick={() => setActiveTab("llms")}
|
|
||||||
/>
|
|
||||||
<TabButton
|
|
||||||
label="Filters"
|
|
||||||
icon={FiFilter}
|
|
||||||
isActive={activeTab === "filters"}
|
|
||||||
onClick={() => setActiveTab("filters")}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
className="
|
|
||||||
ml-auto
|
|
||||||
px-1
|
|
||||||
py-1
|
|
||||||
text-xs
|
|
||||||
font-medium
|
|
||||||
rounded
|
|
||||||
hover:bg-hover
|
|
||||||
focus:outline-none
|
|
||||||
focus:ring-2
|
|
||||||
focus:ring-offset-2
|
|
||||||
focus:ring-subtle
|
|
||||||
flex
|
|
||||||
items-center
|
|
||||||
h-fit
|
|
||||||
my-auto
|
|
||||||
mr-5
|
|
||||||
"
|
|
||||||
onClick={onClose}
|
|
||||||
>
|
|
||||||
<FiX size={24} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col overflow-y-auto">
|
|
||||||
<div className="px-8 pt-4">
|
|
||||||
{activeTab === "filters" && (
|
|
||||||
<FiltersTab filterManager={filterManager} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{activeTab === "llms" && (
|
|
||||||
<LlmTab
|
|
||||||
chatSessionId={chatSessionId}
|
|
||||||
llmOverrideManager={llmOverrideManager}
|
|
||||||
currentAssistant={selectedAssistant}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{activeTab === "assistants" && (
|
|
||||||
<div>
|
|
||||||
<AssistantsTab
|
|
||||||
availableAssistants={availableAssistants}
|
|
||||||
llmProviders={llmProviders}
|
|
||||||
selectedAssistant={selectedAssistant}
|
|
||||||
onSelect={(assistant) => {
|
|
||||||
setSelectedAssistant(assistant);
|
|
||||||
onClose();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
@@ -35,7 +35,7 @@ export default async function Page({
|
|||||||
folders,
|
folders,
|
||||||
toggleSidebar,
|
toggleSidebar,
|
||||||
openedFolders,
|
openedFolders,
|
||||||
defaultPersonaId,
|
defaultAssistantId,
|
||||||
finalDocumentSidebarInitialWidth,
|
finalDocumentSidebarInitialWidth,
|
||||||
shouldShowWelcomeModal,
|
shouldShowWelcomeModal,
|
||||||
shouldDisplaySourcesIncompleteModal,
|
shouldDisplaySourcesIncompleteModal,
|
||||||
@@ -58,7 +58,7 @@ export default async function Page({
|
|||||||
chatSessions,
|
chatSessions,
|
||||||
availableSources,
|
availableSources,
|
||||||
availableDocumentSets: documentSets,
|
availableDocumentSets: documentSets,
|
||||||
availablePersonas: assistants,
|
availableAssistants: assistants,
|
||||||
availableTags: tags,
|
availableTags: tags,
|
||||||
llmProviders,
|
llmProviders,
|
||||||
folders,
|
folders,
|
||||||
@@ -66,7 +66,7 @@ export default async function Page({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<WrappedChat
|
<WrappedChat
|
||||||
defaultPersonaId={defaultPersonaId}
|
defaultAssistantId={defaultAssistantId}
|
||||||
initiallyToggled={toggleSidebar}
|
initiallyToggled={toggleSidebar}
|
||||||
/>
|
/>
|
||||||
</ChatProvider>
|
</ChatProvider>
|
||||||
|
@@ -1,111 +0,0 @@
|
|||||||
import { Persona } from "@/app/admin/assistants/interfaces";
|
|
||||||
import { BasicSelectable } from "@/components/BasicClickable";
|
|
||||||
import { AssistantsIcon } from "@/components/icons/icons";
|
|
||||||
import { User } from "@/lib/types";
|
|
||||||
import { Text } from "@tremor/react";
|
|
||||||
import Link from "next/link";
|
|
||||||
import { FaRobot } from "react-icons/fa";
|
|
||||||
import { FiEdit2 } from "react-icons/fi";
|
|
||||||
|
|
||||||
function AssistantDisplay({
|
|
||||||
persona,
|
|
||||||
onSelect,
|
|
||||||
user,
|
|
||||||
}: {
|
|
||||||
persona: Persona;
|
|
||||||
onSelect: (persona: Persona) => void;
|
|
||||||
user: User | null;
|
|
||||||
}) {
|
|
||||||
const isEditable =
|
|
||||||
(!user || user.id === persona.owner?.id) &&
|
|
||||||
!persona.default_persona &&
|
|
||||||
(!persona.is_public || !user || user.role === "admin");
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex">
|
|
||||||
<div className="w-full" onClick={() => onSelect(persona)}>
|
|
||||||
<BasicSelectable selected={false} fullWidth>
|
|
||||||
<div className="flex">
|
|
||||||
<div className="truncate w-48 3xl:w-56 flex">
|
|
||||||
<AssistantsIcon className="mr-2 my-auto" size={16} />{" "}
|
|
||||||
{persona.name}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</BasicSelectable>
|
|
||||||
</div>
|
|
||||||
{isEditable && (
|
|
||||||
<div className="pl-2 my-auto">
|
|
||||||
<Link href={`/assistants/edit/${persona.id}`}>
|
|
||||||
<FiEdit2
|
|
||||||
className="my-auto ml-auto hover:bg-hover p-0.5"
|
|
||||||
size={20}
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AssistantsTab({
|
|
||||||
personas,
|
|
||||||
onPersonaChange,
|
|
||||||
user,
|
|
||||||
}: {
|
|
||||||
personas: Persona[];
|
|
||||||
onPersonaChange: (persona: Persona | null) => void;
|
|
||||||
user: User | null;
|
|
||||||
}) {
|
|
||||||
const globalAssistants = personas.filter((persona) => persona.is_public);
|
|
||||||
const personalAssistants = personas.filter(
|
|
||||||
(persona) =>
|
|
||||||
(!user || persona.users.some((u) => u.id === user.id)) &&
|
|
||||||
!persona.is_public
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="mt-4 pb-1 overflow-y-auto h-full flex flex-col gap-y-1">
|
|
||||||
<Text className="mx-3 text-xs mb-4">
|
|
||||||
Select an Assistant below to begin a new chat with them!
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<div className="mx-3">
|
|
||||||
{globalAssistants.length > 0 && (
|
|
||||||
<>
|
|
||||||
<div className="text-xs text-subtle flex pb-0.5 ml-1 mb-1.5 font-bold">
|
|
||||||
Global
|
|
||||||
</div>
|
|
||||||
{globalAssistants.map((persona) => {
|
|
||||||
return (
|
|
||||||
<AssistantDisplay
|
|
||||||
key={persona.id}
|
|
||||||
persona={persona}
|
|
||||||
onSelect={onPersonaChange}
|
|
||||||
user={user}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{personalAssistants.length > 0 && (
|
|
||||||
<>
|
|
||||||
<div className="text-xs text-subtle flex pb-0.5 ml-1 mb-1.5 mt-5 font-bold">
|
|
||||||
Personal
|
|
||||||
</div>
|
|
||||||
{personalAssistants.map((persona) => {
|
|
||||||
return (
|
|
||||||
<AssistantDisplay
|
|
||||||
key={persona.id}
|
|
||||||
persona={persona}
|
|
||||||
onSelect={onPersonaChange}
|
|
||||||
user={user}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@@ -18,7 +18,7 @@ interface ChatContextProps {
|
|||||||
chatSessions: ChatSession[];
|
chatSessions: ChatSession[];
|
||||||
availableSources: ValidSources[];
|
availableSources: ValidSources[];
|
||||||
availableDocumentSets: DocumentSet[];
|
availableDocumentSets: DocumentSet[];
|
||||||
availablePersonas: Persona[];
|
availableAssistants: Persona[];
|
||||||
availableTags: Tag[];
|
availableTags: Tag[];
|
||||||
llmProviders: LLMProviderDescriptor[];
|
llmProviders: LLMProviderDescriptor[];
|
||||||
folders: Folder[];
|
folders: Folder[];
|
||||||
|
@@ -19,7 +19,7 @@ export function Citation({
|
|||||||
return (
|
return (
|
||||||
<CustomTooltip
|
<CustomTooltip
|
||||||
citation
|
citation
|
||||||
content={<p className="inline-block p-0 m-0 truncate">{link}</p>}
|
content={<div className="inline-block p-0 m-0 truncate">{link}</div>}
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
onClick={() => (link ? window.open(link, "_blank") : undefined)}
|
onClick={() => (link ? window.open(link, "_blank") : undefined)}
|
||||||
|
@@ -30,7 +30,6 @@ import { fetchAssistantsSS } from "../assistants/fetchAssistantsSS";
|
|||||||
interface FetchChatDataResult {
|
interface FetchChatDataResult {
|
||||||
user: User | null;
|
user: User | null;
|
||||||
chatSessions: ChatSession[];
|
chatSessions: ChatSession[];
|
||||||
|
|
||||||
ccPairs: CCPairBasicInfo[];
|
ccPairs: CCPairBasicInfo[];
|
||||||
availableSources: ValidSources[];
|
availableSources: ValidSources[];
|
||||||
documentSets: DocumentSet[];
|
documentSets: DocumentSet[];
|
||||||
@@ -39,7 +38,7 @@ interface FetchChatDataResult {
|
|||||||
llmProviders: LLMProviderDescriptor[];
|
llmProviders: LLMProviderDescriptor[];
|
||||||
folders: Folder[];
|
folders: Folder[];
|
||||||
openedFolders: Record<string, boolean>;
|
openedFolders: Record<string, boolean>;
|
||||||
defaultPersonaId?: number;
|
defaultAssistantId?: number;
|
||||||
toggleSidebar: boolean;
|
toggleSidebar: boolean;
|
||||||
finalDocumentSidebarInitialWidth?: number;
|
finalDocumentSidebarInitialWidth?: number;
|
||||||
shouldShowWelcomeModal: boolean;
|
shouldShowWelcomeModal: boolean;
|
||||||
@@ -150,9 +149,9 @@ export async function fetchChatData(searchParams: {
|
|||||||
console.log(`Failed to fetch tags - ${tagsResponse?.status}`);
|
console.log(`Failed to fetch tags - ${tagsResponse?.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultPersonaIdRaw = searchParams["assistantId"];
|
const defaultAssistantIdRaw = searchParams["assistantId"];
|
||||||
const defaultPersonaId = defaultPersonaIdRaw
|
const defaultAssistantId = defaultAssistantIdRaw
|
||||||
? parseInt(defaultPersonaIdRaw)
|
? parseInt(defaultAssistantIdRaw)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const documentSidebarCookieInitialWidth = cookies().get(
|
const documentSidebarCookieInitialWidth = cookies().get(
|
||||||
@@ -209,7 +208,7 @@ export async function fetchChatData(searchParams: {
|
|||||||
llmProviders,
|
llmProviders,
|
||||||
folders,
|
folders,
|
||||||
openedFolders,
|
openedFolders,
|
||||||
defaultPersonaId,
|
defaultAssistantId,
|
||||||
finalDocumentSidebarInitialWidth,
|
finalDocumentSidebarInitialWidth,
|
||||||
toggleSidebar,
|
toggleSidebar,
|
||||||
shouldShowWelcomeModal,
|
shouldShowWelcomeModal,
|
||||||
|
Reference in New Issue
Block a user