mirror of
https://github.com/onyx-dot-app/onyx.git
synced 2026-04-06 15:32:43 +00:00
Compare commits
4 Commits
cli/v0.2.1
...
file_uploa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afdb597dbb | ||
|
|
b570f41bb8 | ||
|
|
2781898433 | ||
|
|
0c1d6175a7 |
@@ -475,18 +475,27 @@ def stream_chat_message_objects(
|
||||
files = load_all_chat_files(
|
||||
history_msgs, new_msg_req.file_descriptors, db_session
|
||||
)
|
||||
latest_query_files = [
|
||||
file
|
||||
for file in files
|
||||
if file.file_id in [f["id"] for f in new_msg_req.file_descriptors]
|
||||
]
|
||||
|
||||
file_ids = {f["id"] for f in new_msg_req.file_descriptors}
|
||||
latest_query_files = [file for file in files if file.file_id in file_ids]
|
||||
|
||||
latest_query_file_descriptors = list(
|
||||
{
|
||||
file.file_id: file.to_file_descriptor() for file in latest_query_files
|
||||
}.values()
|
||||
)
|
||||
|
||||
print("fiel ids")
|
||||
print(file_ids)
|
||||
print(len(file_ids))
|
||||
print("FILE DESCRIPTORS")
|
||||
print(latest_query_file_descriptors)
|
||||
print(len(latest_query_file_descriptors))
|
||||
|
||||
if user_message:
|
||||
attach_files_to_chat_message(
|
||||
chat_message=user_message,
|
||||
files=[
|
||||
new_file.to_file_descriptor() for new_file in latest_query_files
|
||||
],
|
||||
files=latest_query_file_descriptors,
|
||||
db_session=db_session,
|
||||
commit=False,
|
||||
)
|
||||
|
||||
@@ -39,7 +39,6 @@ from danswer.key_value_store.interface import KvKeyNotFoundError
|
||||
from danswer.natural_language_processing.search_nlp_models import EmbeddingModel
|
||||
from danswer.natural_language_processing.search_nlp_models import warm_up_bi_encoder
|
||||
from danswer.natural_language_processing.search_nlp_models import warm_up_cross_encoder
|
||||
from danswer.seeding.load_docs import seed_initial_documents
|
||||
from danswer.seeding.load_yamls import load_chat_yamls
|
||||
from danswer.server.manage.llm.models import LLMProviderUpsertRequest
|
||||
from danswer.server.settings.store import load_settings
|
||||
@@ -151,7 +150,7 @@ def setup_danswer(
|
||||
# update multipass indexing setting based on GPU availability
|
||||
update_default_multipass_indexing(db_session)
|
||||
|
||||
seed_initial_documents(db_session, tenant_id, cohere_enabled)
|
||||
# seed_initial_documents(db_session, tenant_id, cohere_enabled)
|
||||
|
||||
|
||||
def translate_saved_search_settings(db_session: Session) -> None:
|
||||
|
||||
1
passwords.txt
Normal file
1
passwords.txt
Normal file
@@ -0,0 +1 @@
|
||||
i
|
||||
@@ -59,7 +59,7 @@ import { useDocumentSelection } from "./useDocumentSelection";
|
||||
import { LlmOverride, useFilters, useLlmOverride } from "@/lib/hooks";
|
||||
import { computeAvailableFilters } from "@/lib/filters";
|
||||
import { ChatState, FeedbackType, RegenerationState } from "./types";
|
||||
import { ChatFilters } from "./documentSidebar/ChatFilters";
|
||||
import { ChatFilters } from "./filters/ChatFilters";
|
||||
import { DanswerInitializingLoader } from "@/components/DanswerInitializingLoader";
|
||||
import { FeedbackModal } from "./modal/FeedbackModal";
|
||||
import { ShareChatSessionModal } from "./modal/ShareChatSessionModal";
|
||||
@@ -478,7 +478,7 @@ export function ChatPage({
|
||||
latestMessageId !== undefined ? latestMessageId : null
|
||||
);
|
||||
}
|
||||
|
||||
clearSelectedDocuments();
|
||||
setChatSessionSharedStatus(chatSession.shared_status);
|
||||
|
||||
// go to bottom. If initial load, then do a scroll,
|
||||
@@ -790,7 +790,23 @@ export function ChatPage({
|
||||
toggleDocumentSelection,
|
||||
clearSelectedDocuments,
|
||||
selectedDocumentTokens,
|
||||
selectedUploadedFiles,
|
||||
toggleFileSelection,
|
||||
] = useDocumentSelection();
|
||||
console.log(
|
||||
"the length of selected uploaded files",
|
||||
selectedUploadedFiles.length
|
||||
);
|
||||
|
||||
// selectedDocuments,
|
||||
// toggleDocumentSelection,
|
||||
// clearDocuments,
|
||||
// totalTokens,
|
||||
// selectedFiles,
|
||||
// toggleFileSelection,
|
||||
|
||||
const [selectedFiles, setSelectedFiles] = useState<FileDescriptor[]>([]);
|
||||
|
||||
// just choose a conservative default, this will be updated in the
|
||||
// background on initial load / on persona change
|
||||
const [maxTokens, setMaxTokens] = useState<number>(4096);
|
||||
@@ -1204,11 +1220,12 @@ export function ChatPage({
|
||||
getLastSuccessfulMessageId(currMessageHistory) || systemMessage;
|
||||
|
||||
const stack = new CurrentMessageFIFO();
|
||||
|
||||
updateCurrentMessageFIFO(stack, {
|
||||
signal: controller.signal, // Add this line
|
||||
message: currMessage,
|
||||
alternateAssistantId: currentAssistantId,
|
||||
fileDescriptors: currentMessageFiles,
|
||||
fileDescriptors: selectedUploadedFiles,
|
||||
parentMessageId:
|
||||
regenerationRequest?.parentMessage.messageId ||
|
||||
lastSuccessfulMessageId,
|
||||
@@ -1893,10 +1910,6 @@ export function ChatPage({
|
||||
setSharedChatSession(chatSession);
|
||||
};
|
||||
const [documentSelection, setDocumentSelection] = useState(false);
|
||||
// const toggleDocumentSelectionAspects = () => {
|
||||
// setDocumentSelection((documentSelection) => !documentSelection);
|
||||
// setShowDocSidebar(false);
|
||||
// };
|
||||
|
||||
const toggleDocumentSidebar = () => {
|
||||
if (!documentSidebarToggled) {
|
||||
@@ -1990,10 +2003,12 @@ export function ChatPage({
|
||||
/>
|
||||
)}
|
||||
|
||||
{retrievalEnabled && documentSidebarToggled && settings?.isMobile && (
|
||||
{documentSidebarToggled && settings?.isMobile && (
|
||||
<div className="md:hidden">
|
||||
<Modal noPadding noScroll>
|
||||
<ChatFilters
|
||||
toggleFileSelection={toggleFileSelection}
|
||||
toggledFiles={selectedUploadedFiles}
|
||||
setPresentingDocument={setPresentingDocument}
|
||||
modal={true}
|
||||
filterManager={filterManager}
|
||||
@@ -2006,6 +2021,7 @@ export function ChatPage({
|
||||
setDocumentSidebarToggled(false);
|
||||
}}
|
||||
selectedMessage={aiMessage}
|
||||
selectedFiles={selectedFiles}
|
||||
selectedDocuments={selectedDocuments}
|
||||
toggleDocumentSelection={toggleDocumentSelection}
|
||||
clearSelectedDocuments={clearSelectedDocuments}
|
||||
@@ -2125,7 +2141,7 @@ export function ChatPage({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{!settings?.isMobile && retrievalEnabled && (
|
||||
{!settings?.isMobile && (
|
||||
<div
|
||||
style={{ transition: "width 0.30s ease-out" }}
|
||||
className={`
|
||||
@@ -2133,7 +2149,6 @@ export function ChatPage({
|
||||
fixed
|
||||
right-0
|
||||
z-[1000]
|
||||
|
||||
bg-background
|
||||
h-screen
|
||||
transition-all
|
||||
@@ -2150,6 +2165,9 @@ export function ChatPage({
|
||||
`}
|
||||
>
|
||||
<ChatFilters
|
||||
toggledFiles={selectedUploadedFiles}
|
||||
selectedFiles={selectedFiles}
|
||||
toggleFileSelection={toggleFileSelection}
|
||||
setPresentingDocument={setPresentingDocument}
|
||||
modal={false}
|
||||
filterManager={filterManager}
|
||||
@@ -2341,6 +2359,11 @@ export function ChatPage({
|
||||
const messageMap = currentMessageMap(
|
||||
completeMessageDetail
|
||||
);
|
||||
const files = message.files.filter(
|
||||
(file) =>
|
||||
file.type != "document" &&
|
||||
file.type != "plain_text"
|
||||
);
|
||||
const messageReactComponentKey = `${i}-${currentSessionId()}`;
|
||||
const parentMessage = message.parentMessageId
|
||||
? messageMap.get(message.parentMessageId)
|
||||
@@ -2363,7 +2386,7 @@ export function ChatPage({
|
||||
<HumanMessage
|
||||
stopGenerating={stopGenerating}
|
||||
content={message.message}
|
||||
files={message.files}
|
||||
files={files}
|
||||
messageId={message.messageId}
|
||||
onEdit={(editedContent) => {
|
||||
const parentMessageId =
|
||||
@@ -2446,6 +2469,7 @@ export function ChatPage({
|
||||
}
|
||||
>
|
||||
<AIMessage
|
||||
userFiles={previousMessage?.files}
|
||||
setPresentingDocument={
|
||||
setPresentingDocument
|
||||
}
|
||||
@@ -2505,6 +2529,9 @@ export function ChatPage({
|
||||
setSelectedMessageForDocDisplay(
|
||||
message.messageId
|
||||
);
|
||||
setSelectedFiles(
|
||||
parentMessage?.files || []
|
||||
);
|
||||
}}
|
||||
docs={message.documents}
|
||||
currentPersona={liveAssistant}
|
||||
@@ -2800,11 +2827,7 @@ export function ChatPage({
|
||||
transition-all
|
||||
duration-300
|
||||
ease-in-out
|
||||
${
|
||||
documentSidebarToggled && retrievalEnabled
|
||||
? "w-[400px]"
|
||||
: "w-[0px]"
|
||||
}
|
||||
${documentSidebarToggled ? "w-[400px]" : "w-[0px]"}
|
||||
`}
|
||||
></div>
|
||||
)}
|
||||
|
||||
@@ -8,6 +8,8 @@ import { MetadataBadge } from "@/components/MetadataBadge";
|
||||
import { WebResultIcon } from "@/components/WebResultIcon";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import { ValidSources } from "@/lib/types";
|
||||
import { FileDescriptor } from "../interfaces";
|
||||
import { truncateString } from "@/lib/utils";
|
||||
|
||||
interface DocumentDisplayProps {
|
||||
closeSidebar: () => void;
|
||||
@@ -128,3 +130,63 @@ export function ChatDocumentDisplay({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ChatFileDisplay({
|
||||
closeSidebar,
|
||||
file,
|
||||
modal,
|
||||
isSelected,
|
||||
handleSelect,
|
||||
tokenLimitReached,
|
||||
setPresentingDocument,
|
||||
}: {
|
||||
closeSidebar: () => void;
|
||||
file: FileDescriptor;
|
||||
modal?: boolean;
|
||||
isSelected: boolean;
|
||||
handleSelect: (file: FileDescriptor) => void;
|
||||
tokenLimitReached: boolean;
|
||||
setPresentingDocument?: (document: DanswerDocument) => void;
|
||||
}) {
|
||||
const handleViewFile = () => {
|
||||
if (setPresentingDocument) {
|
||||
setPresentingDocument({
|
||||
document_id: file.id,
|
||||
source_type: ValidSources.File,
|
||||
semantic_identifier: file.name,
|
||||
} as DanswerDocument);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`opacity-100 ${modal ? "w-[90vw]" : "w-full"}`}>
|
||||
<div
|
||||
className={`flex relative flex-col gap-0.5 rounded-xl mx-2 my-1 ${
|
||||
isSelected ? "bg-gray-200" : "hover:bg-background-125"
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
onClick={handleViewFile}
|
||||
className="cursor-pointer text-left flex flex-col px-2 py-1.5"
|
||||
>
|
||||
<div className="line-clamp-1 mb-1 flex h-6 items-center gap-2 text-xs">
|
||||
<SourceIcon sourceType={ValidSources.File} iconSize={18} />
|
||||
<div className="line-clamp-1 text-text-900 text-sm font-semibold">
|
||||
{truncateString(file.name || file.id, modal ? 30 : 40)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="line-clamp-2 text-sm font-normal leading-snug text-gray-600">
|
||||
{file.type}
|
||||
</div>
|
||||
<div className="absolute top-2 right-2">
|
||||
<DocumentSelector
|
||||
isSelected={isSelected}
|
||||
handleSelect={() => handleSelect(file)}
|
||||
isDisabled={tokenLimitReached && !isSelected}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DanswerDocument } from "@/lib/search/interfaces";
|
||||
import { ChatDocumentDisplay } from "./ChatDocumentDisplay";
|
||||
import { ChatDocumentDisplay, ChatFileDisplay } from "./ChatDocumentDisplay";
|
||||
import { usePopup } from "@/components/admin/connectors/Popup";
|
||||
import { removeDuplicateDocs } from "@/lib/documentUtils";
|
||||
import { Message } from "../interfaces";
|
||||
import { FileDescriptor, Message } from "../interfaces";
|
||||
import {
|
||||
Dispatch,
|
||||
ForwardedRef,
|
||||
@@ -15,6 +15,7 @@ import { FilterManager } from "@/lib/hooks";
|
||||
import { CCPairBasicInfo, DocumentSet, Tag } from "@/lib/types";
|
||||
import { SourceSelector } from "../shared_chat_search/SearchFilters";
|
||||
import { XIcon } from "@/components/icons/icons";
|
||||
import FileSourceCard from "@/components/chat_search/sources/FileSource";
|
||||
|
||||
interface ChatFiltersProps {
|
||||
filterManager: FilterManager;
|
||||
@@ -22,6 +23,7 @@ interface ChatFiltersProps {
|
||||
selectedMessage: Message | null;
|
||||
selectedDocuments: DanswerDocument[] | null;
|
||||
toggleDocumentSelection: (document: DanswerDocument) => void;
|
||||
toggleFileSelection: (file: FileDescriptor) => void;
|
||||
clearSelectedDocuments: () => void;
|
||||
selectedDocumentTokens: number;
|
||||
maxTokens: number;
|
||||
@@ -33,6 +35,8 @@ interface ChatFiltersProps {
|
||||
documentSets: DocumentSet[];
|
||||
showFilters: boolean;
|
||||
setPresentingDocument: Dispatch<SetStateAction<DanswerDocument | null>>;
|
||||
selectedFiles: FileDescriptor[];
|
||||
toggledFiles: FileDescriptor[];
|
||||
}
|
||||
|
||||
export const ChatFilters = forwardRef<HTMLDivElement, ChatFiltersProps>(
|
||||
@@ -44,6 +48,7 @@ export const ChatFilters = forwardRef<HTMLDivElement, ChatFiltersProps>(
|
||||
selectedDocuments,
|
||||
filterManager,
|
||||
toggleDocumentSelection,
|
||||
toggleFileSelection,
|
||||
clearSelectedDocuments,
|
||||
selectedDocumentTokens,
|
||||
maxTokens,
|
||||
@@ -52,6 +57,8 @@ export const ChatFilters = forwardRef<HTMLDivElement, ChatFiltersProps>(
|
||||
ccPairs,
|
||||
tags,
|
||||
setPresentingDocument,
|
||||
selectedFiles,
|
||||
toggledFiles,
|
||||
documentSets,
|
||||
showFilters,
|
||||
},
|
||||
@@ -72,8 +79,12 @@ export const ChatFilters = forwardRef<HTMLDivElement, ChatFiltersProps>(
|
||||
return () => clearTimeout(timer);
|
||||
}, [selectedDocuments]);
|
||||
|
||||
const selectedDocumentIds =
|
||||
selectedDocuments?.map((document) => document.document_id) || [];
|
||||
const selectedDocumentIds = (
|
||||
selectedDocuments?.map((document) => document.document_id) || []
|
||||
).concat(toggledFiles?.map((file) => file.id) || []);
|
||||
|
||||
console.log("SELECTED DOCUMENT IDS", selectedDocumentIds);
|
||||
console.log("toggled files", toggledFiles);
|
||||
|
||||
const currentDocuments = selectedMessage?.documents || null;
|
||||
const dedupedDocuments = removeDuplicateDocs(currentDocuments || []);
|
||||
@@ -132,38 +143,49 @@ export const ChatFilters = forwardRef<HTMLDivElement, ChatFiltersProps>(
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{dedupedDocuments.length > 0 ? (
|
||||
dedupedDocuments.map((document, ind) => (
|
||||
<div
|
||||
key={document.document_id}
|
||||
className={`${
|
||||
ind === dedupedDocuments.length - 1
|
||||
? ""
|
||||
: "border-b border-border-light w-full"
|
||||
}`}
|
||||
>
|
||||
<ChatDocumentDisplay
|
||||
setPresentingDocument={setPresentingDocument}
|
||||
{dedupedDocuments.length > 0
|
||||
? dedupedDocuments.map((document, ind) => (
|
||||
<div
|
||||
key={document.document_id}
|
||||
className={`${
|
||||
ind === dedupedDocuments.length - 1
|
||||
? ""
|
||||
: "border-b border-border-light w-full"
|
||||
}`}
|
||||
>
|
||||
<ChatDocumentDisplay
|
||||
setPresentingDocument={setPresentingDocument}
|
||||
closeSidebar={closeSidebar}
|
||||
modal={modal}
|
||||
document={document}
|
||||
isSelected={selectedDocumentIds.includes(
|
||||
document.document_id
|
||||
)}
|
||||
handleSelect={(documentId) => {
|
||||
toggleDocumentSelection(
|
||||
dedupedDocuments.find(
|
||||
(doc) => doc.document_id === documentId
|
||||
)!
|
||||
);
|
||||
}}
|
||||
tokenLimitReached={tokenLimitReached}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
: selectedFiles.map((file) => (
|
||||
<ChatFileDisplay
|
||||
file={file}
|
||||
key={file.id}
|
||||
closeSidebar={closeSidebar}
|
||||
modal={modal}
|
||||
document={document}
|
||||
isSelected={selectedDocumentIds.includes(
|
||||
document.document_id
|
||||
)}
|
||||
handleSelect={(documentId) => {
|
||||
toggleDocumentSelection(
|
||||
dedupedDocuments.find(
|
||||
(doc) => doc.document_id === documentId
|
||||
)!
|
||||
);
|
||||
}}
|
||||
isSelected={selectedDocumentIds.includes(file.id)}
|
||||
handleSelect={(d: FileDescriptor) =>
|
||||
toggleFileSelection(d)
|
||||
}
|
||||
tokenLimitReached={tokenLimitReached}
|
||||
setPresentingDocument={setPresentingDocument}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="mx-3" />
|
||||
)}
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@@ -184,7 +206,10 @@ export const ChatFilters = forwardRef<HTMLDivElement, ChatFiltersProps>(
|
||||
delayedSelectedDocumentCount > 0
|
||||
? delayedSelectedDocumentCount
|
||||
: ""
|
||||
} Source${delayedSelectedDocumentCount > 1 ? "s" : ""}`}
|
||||
}
|
||||
${selectedFiles ? "Document" : "Source"}${
|
||||
delayedSelectedDocumentCount > 1 ? "s" : ""
|
||||
}`}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
FiChevronLeft,
|
||||
FiTool,
|
||||
FiGlobe,
|
||||
FiBook,
|
||||
} from "react-icons/fi";
|
||||
import { FeedbackType } from "../types";
|
||||
import React, {
|
||||
@@ -72,6 +73,8 @@ import CsvContent from "../../../components/tools/CSVContent";
|
||||
import SourceCard, {
|
||||
SeeMoreBlock,
|
||||
} from "@/components/chat_search/sources/SourceCard";
|
||||
import { FileSeeMoreBlock } from "@/components/chat_search/sources/FileSource";
|
||||
import FileSourceCard from "@/components/chat_search/sources/FileSource";
|
||||
|
||||
const TOOLS_WITH_CUSTOM_HANDLING = [
|
||||
SEARCH_TOOL_NAME,
|
||||
@@ -167,6 +170,7 @@ export const AIMessage = ({
|
||||
overriddenModel,
|
||||
selectedMessageForDocDisplay,
|
||||
continueGenerating,
|
||||
userFiles,
|
||||
shared,
|
||||
isActive,
|
||||
toggleDocumentSelection,
|
||||
@@ -193,6 +197,7 @@ export const AIMessage = ({
|
||||
setPresentingDocument,
|
||||
index,
|
||||
}: {
|
||||
userFiles?: FileDescriptor[];
|
||||
index?: number;
|
||||
selectedMessageForDocDisplay?: number | null;
|
||||
shared?: boolean;
|
||||
@@ -391,7 +396,8 @@ export const AIMessage = ({
|
||||
<div className="max-w-message-max break-words">
|
||||
<div className="w-full ml-4">
|
||||
<div className="max-w-message-max break-words">
|
||||
{!toolCall || toolCall.tool_name === SEARCH_TOOL_NAME ? (
|
||||
{!userFiles &&
|
||||
(!toolCall || toolCall.tool_name === SEARCH_TOOL_NAME) ? (
|
||||
<>
|
||||
{query !== undefined &&
|
||||
handleShowRetrieved !== undefined &&
|
||||
@@ -459,6 +465,54 @@ export const AIMessage = ({
|
||||
/>
|
||||
)}
|
||||
|
||||
{userFiles && userFiles.length > 0 && (
|
||||
<div>
|
||||
<div className="flex mb-auto">
|
||||
<FiBook
|
||||
className="my-auto flex-none mr-2"
|
||||
size={14}
|
||||
/>
|
||||
<div className="my-auto cursor-default">
|
||||
<span className="mobile:hidden">
|
||||
Used context from the following files:
|
||||
</span>
|
||||
<span className="desktop:hidden">Files used:</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className=" -mx-8 w-full mb-4 flex relative">
|
||||
<div className="w-full">
|
||||
<div className="px-8 flex gap-x-2">
|
||||
{!settings?.isMobile &&
|
||||
userFiles.length > 0 &&
|
||||
userFiles
|
||||
.slice(0, 2)
|
||||
.map((doc, ind) => (
|
||||
<FileSourceCard
|
||||
file={doc}
|
||||
key={ind}
|
||||
setPresentingDocument={
|
||||
setPresentingDocument
|
||||
}
|
||||
/>
|
||||
))}
|
||||
<FileSeeMoreBlock
|
||||
documentSelectionToggled={
|
||||
(documentSelectionToggled &&
|
||||
selectedMessageForDocDisplay ===
|
||||
messageId) ||
|
||||
false
|
||||
}
|
||||
toggleDocumentSelection={
|
||||
toggleDocumentSelection
|
||||
}
|
||||
uniqueSources={uniqueSources}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{docs && docs.length > 0 && (
|
||||
<div className="mt-2 -mx-8 w-full mb-4 flex relative">
|
||||
<div className="w-full">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DanswerDocument } from "@/lib/search/interfaces";
|
||||
import { useState } from "react";
|
||||
import { FileDescriptor } from "./interfaces";
|
||||
|
||||
interface DocumentInfo {
|
||||
num_chunks: number;
|
||||
@@ -22,15 +23,28 @@ export function useDocumentSelection(): [
|
||||
(document: DanswerDocument) => void,
|
||||
() => void,
|
||||
number,
|
||||
FileDescriptor[],
|
||||
(file: FileDescriptor) => void,
|
||||
] {
|
||||
const [selectedDocuments, setSelectedDocuments] = useState<DanswerDocument[]>(
|
||||
[]
|
||||
);
|
||||
const [totalTokens, setTotalTokens] = useState(0);
|
||||
const [selectedFiles, setSelectedFiles] = useState<FileDescriptor[]>([]);
|
||||
const selectedDocumentIds = selectedDocuments.map(
|
||||
(document) => document.document_id
|
||||
);
|
||||
const documentIdToLength = new Map<string, number>();
|
||||
function toggleFileSelection(file: FileDescriptor) {
|
||||
const isAdding = !selectedFiles.includes(file);
|
||||
console.log("is adding", isAdding);
|
||||
console.log("selected files", selectedFiles);
|
||||
if (!isAdding) {
|
||||
setSelectedFiles(selectedFiles.filter((f) => f.id !== file.id));
|
||||
} else {
|
||||
setSelectedFiles([...selectedFiles, file]);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleDocumentSelection(document: DanswerDocument) {
|
||||
const documentId = document.document_id;
|
||||
@@ -57,6 +71,7 @@ export function useDocumentSelection(): [
|
||||
|
||||
function clearDocuments() {
|
||||
setSelectedDocuments([]);
|
||||
setSelectedFiles([]);
|
||||
setTotalTokens(0);
|
||||
}
|
||||
|
||||
@@ -65,5 +80,7 @@ export function useDocumentSelection(): [
|
||||
toggleDocumentSelection,
|
||||
clearDocuments,
|
||||
totalTokens,
|
||||
selectedFiles,
|
||||
toggleFileSelection,
|
||||
];
|
||||
}
|
||||
|
||||
33
web/src/components/Switch.tsx
Normal file
33
web/src/components/Switch.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import React from "react";
|
||||
|
||||
interface SwitchProps {
|
||||
checked: boolean;
|
||||
onChange: () => void;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const Switch: React.FC<SwitchProps> = ({ checked, onChange, label }) => {
|
||||
return (
|
||||
<label className="flex items-center cursor-pointer">
|
||||
<div className="relative">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="sr-only"
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<div
|
||||
className={`block w-14 h-8 rounded-full ${
|
||||
checked ? "bg-blue-600" : "bg-gray-600"
|
||||
}`}
|
||||
></div>
|
||||
<div
|
||||
className={`dot absolute left-1 top-1 bg-white w-6 h-6 rounded-full transition ${
|
||||
checked ? "transform translate-x-6" : ""
|
||||
}`}
|
||||
></div>
|
||||
</div>
|
||||
<div className="ml-3 text-gray-700 font-medium">{label}</div>
|
||||
</label>
|
||||
);
|
||||
};
|
||||
@@ -54,7 +54,9 @@ export default function TextView({
|
||||
const fileId = presentingDocument.document_id.split("__")[1];
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/chat/file/${encodeURIComponent(fileId)}`,
|
||||
`/api/chat/file/${encodeURIComponent(
|
||||
fileId || presentingDocument.document_id
|
||||
)}`,
|
||||
{
|
||||
method: "GET",
|
||||
}
|
||||
|
||||
86
web/src/components/chat_search/sources/FileSource.tsx
Normal file
86
web/src/components/chat_search/sources/FileSource.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import { WebResultIcon } from "@/components/WebResultIcon";
|
||||
import { SourceIcon } from "@/components/SourceIcon";
|
||||
import { DanswerDocument } from "@/lib/search/interfaces";
|
||||
import { truncateString } from "@/lib/utils";
|
||||
import { SetStateAction } from "react";
|
||||
import { Dispatch } from "react";
|
||||
import { ValidSources } from "@/lib/types";
|
||||
import { FileDescriptor } from "@/app/chat/interfaces";
|
||||
|
||||
export default function FileSourceCard({
|
||||
file,
|
||||
setPresentingDocument,
|
||||
}: {
|
||||
file: FileDescriptor;
|
||||
setPresentingDocument?: (document: DanswerDocument) => void;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
key={file.id}
|
||||
onClick={() => {
|
||||
if (setPresentingDocument) {
|
||||
setPresentingDocument({
|
||||
document_id: file.id,
|
||||
source_type: ValidSources.File,
|
||||
semantic_identifier: file.name,
|
||||
} as DanswerDocument);
|
||||
}
|
||||
}}
|
||||
className="cursor-pointer text-left overflow-hidden flex flex-col gap-0.5 rounded-sm px-3 py-2.5 hover:bg-background-125 bg-background-100 w-[200px]"
|
||||
>
|
||||
<div className="line-clamp-1 font-semibold text-ellipsis text-text-900 flex h-6 items-center gap-2 text-sm">
|
||||
<SourceIcon sourceType={ValidSources.File} iconSize={18} />
|
||||
<p>{truncateString(file.name || file.id || "", 12)}</p>
|
||||
</div>
|
||||
<div className="line-clamp-2 text-sm font-semibold"></div>
|
||||
<div className="line-clamp-2 text-sm font-normal leading-snug text-text-700">
|
||||
{file.type}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface SeeMoreBlockProps {
|
||||
documentSelectionToggled: boolean;
|
||||
toggleDocumentSelection?: () => void;
|
||||
uniqueSources: DanswerDocument["source_type"][];
|
||||
}
|
||||
|
||||
export function FileSeeMoreBlock({
|
||||
documentSelectionToggled,
|
||||
toggleDocumentSelection,
|
||||
uniqueSources,
|
||||
}: SeeMoreBlockProps) {
|
||||
return (
|
||||
<div
|
||||
onClick={toggleDocumentSelection}
|
||||
className={`
|
||||
${documentSelectionToggled ? "border-border-100 border" : ""}
|
||||
cursor-pointer w-[150px] rounded-sm flex-none transition-all duration-500 hover:bg-background-125 bg-text-100 px-3 py-2.5
|
||||
`}
|
||||
>
|
||||
<div className="line-clamp-1 font-semibold text-ellipsis text-text-900 flex h-6 items-center justify-between text-sm">
|
||||
<p className="mr-0 flex-shrink-0">
|
||||
{documentSelectionToggled ? "Hide sources" : "See context"}
|
||||
</p>
|
||||
<div className="flex -space-x-3 flex-shrink-0 overflow-hidden">
|
||||
{uniqueSources.map((sourceType, ind) => (
|
||||
<div
|
||||
key={ind}
|
||||
className="inline-block bg-background-100 rounded-full p-0.5"
|
||||
style={{ zIndex: uniqueSources.length - ind }}
|
||||
>
|
||||
<div className="bg-background-100 rounded-full">
|
||||
<SourceIcon sourceType={sourceType} iconSize={20} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="line-clamp-2 text-sm font-semibold"></div>
|
||||
<div className="line-clamp-2 text-sm font-normal leading-snug text-text-700">
|
||||
See more
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import { useContext, useEffect, useState } from "react";
|
||||
import { DateRangePickerValue } from "@/app/ee/admin/performance/DateRangeSelector";
|
||||
import { SourceMetadata } from "./search/interfaces";
|
||||
import { destructureValue } from "./llm/utils";
|
||||
import { ChatSession } from "@/app/chat/interfaces";
|
||||
import { ChatSession, FileDescriptor } from "@/app/chat/interfaces";
|
||||
import { UsersResponse } from "./users/interfaces";
|
||||
import { Credential } from "./connectors/credentials";
|
||||
import { SettingsContext } from "@/components/settings/SettingsProvider";
|
||||
@@ -116,9 +116,12 @@ export interface FilterManager {
|
||||
setSelectedDocumentSets: React.Dispatch<React.SetStateAction<string[]>>;
|
||||
selectedTags: Tag[];
|
||||
setSelectedTags: React.Dispatch<React.SetStateAction<Tag[]>>;
|
||||
fileDescriptors: FileDescriptor[];
|
||||
setFileDescriptors: React.Dispatch<React.SetStateAction<FileDescriptor[]>>;
|
||||
}
|
||||
|
||||
export function useFilters(): FilterManager {
|
||||
const [fileDescriptors, setFileDescriptors] = useState<FileDescriptor[]>([]);
|
||||
const [timeRange, setTimeRange] = useTimeRange();
|
||||
const [selectedSources, setSelectedSources] = useState<SourceMetadata[]>([]);
|
||||
const [selectedDocumentSets, setSelectedDocumentSets] = useState<string[]>(
|
||||
@@ -135,6 +138,8 @@ export function useFilters(): FilterManager {
|
||||
setSelectedDocumentSets,
|
||||
selectedTags,
|
||||
setSelectedTags,
|
||||
fileDescriptors,
|
||||
setFileDescriptors,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user