mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-02-03 00:55:10 +08:00
Compare commits
5 Commits
8d8a5f73b6
...
370c8bc25b
| Author | SHA1 | Date | |
|---|---|---|---|
| 370c8bc25b | |||
| e90a959b4d | |||
| ca320a8c30 | |||
| ae505e6165 | |||
| 63b5c2292d |
@ -532,6 +532,48 @@
|
||||
"tags": "LLM,TEXT EMBEDDING,SPEECH2TEXT,MODERATION",
|
||||
"status": "1",
|
||||
"llm": [
|
||||
{
|
||||
"llm_name": "glm-4.5v",
|
||||
"tags": "LLM,CHAT,IMAGE2TEXT,",
|
||||
"max_tokens": 128000,
|
||||
"model_type": "image2text",
|
||||
"is_tools": true
|
||||
},
|
||||
{
|
||||
"llm_name": "glm-4.5",
|
||||
"tags": "LLM,CHAT,128K,",
|
||||
"max_tokens": 128000,
|
||||
"model_type": "chat",
|
||||
"is_tools": true
|
||||
},
|
||||
{
|
||||
"llm_name": "glm-4.5-x",
|
||||
"tags": "LLM,CHAT,128K,",
|
||||
"max_tokens": 128000,
|
||||
"model_type": "chat",
|
||||
"is_tools": true
|
||||
},
|
||||
{
|
||||
"llm_name": "glm-4.5-air",
|
||||
"tags": "LLM,CHAT,128K,",
|
||||
"max_tokens": 128000,
|
||||
"model_type": "chat",
|
||||
"is_tools": true
|
||||
},
|
||||
{
|
||||
"llm_name": "glm-4.5-airx",
|
||||
"tags": "LLM,CHAT,128K,",
|
||||
"max_tokens": 128000,
|
||||
"model_type": "chat",
|
||||
"is_tools": true
|
||||
},
|
||||
{
|
||||
"llm_name": "glm-4.5-flash",
|
||||
"tags": "LLM,CHAT,128K,",
|
||||
"max_tokens": 128000,
|
||||
"model_type": "chat",
|
||||
"is_tools": true
|
||||
},
|
||||
{
|
||||
"llm_name": "glm-4-plus",
|
||||
"tags": "LLM,CHAT,",
|
||||
|
||||
@ -44,14 +44,17 @@ class Base(ABC):
|
||||
raise NotImplementedError("Please implement encode method!")
|
||||
|
||||
def total_token_count(self, resp):
|
||||
try:
|
||||
return resp.usage.total_tokens
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
return resp["usage"]["total_tokens"]
|
||||
except Exception:
|
||||
pass
|
||||
if hasattr(resp, "usage") and hasattr(resp.usage, "total_tokens"):
|
||||
try:
|
||||
return resp.usage.total_tokens
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if 'usage' in resp and 'total_tokens' in resp['usage']:
|
||||
try:
|
||||
return resp["usage"]["total_tokens"]
|
||||
except Exception:
|
||||
pass
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@ -34,6 +34,7 @@ interface IProps {
|
||||
createConversationBeforeUploadDocument?(message: string): Promise<any>;
|
||||
stopOutputMessage?(): void;
|
||||
onUpload?: NonNullable<FileUploadProps['onUpload']>;
|
||||
removeFile?(file: File): void;
|
||||
}
|
||||
|
||||
export function NextMessageInput({
|
||||
@ -47,6 +48,7 @@ export function NextMessageInput({
|
||||
onInputChange,
|
||||
stopOutputMessage,
|
||||
onPressEnter,
|
||||
removeFile,
|
||||
}: IProps) {
|
||||
const [files, setFiles] = React.useState<File[]>([]);
|
||||
|
||||
@ -77,6 +79,13 @@ export function NextMessageInput({
|
||||
[submit],
|
||||
);
|
||||
|
||||
const handleRemoveFile = React.useCallback(
|
||||
(file: File) => () => {
|
||||
removeFile?.(file);
|
||||
},
|
||||
[removeFile],
|
||||
);
|
||||
|
||||
return (
|
||||
<FileUpload
|
||||
value={files}
|
||||
@ -121,6 +130,7 @@ export function NextMessageInput({
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
className="-top-1 -right-1 absolute size-4 shrink-0 cursor-pointer rounded-full"
|
||||
onClick={handleRemoveFile(file)}
|
||||
>
|
||||
<X className="size-2.5" />
|
||||
</Button>
|
||||
|
||||
@ -8,7 +8,7 @@ const Table = React.forwardRef<
|
||||
>(({ className, rootClassName, ...props }, ref) => (
|
||||
<div
|
||||
className={cn(
|
||||
'relative w-full overflow-auto rounded-2xl bg-bg-card',
|
||||
'relative w-full overflow-auto rounded-2xl bg-bg-card scrollbar-none',
|
||||
rootClassName,
|
||||
)}
|
||||
>
|
||||
@ -27,7 +27,7 @@ const TableHeader = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<thead
|
||||
ref={ref}
|
||||
className={cn('[&_tr]:border-b top-0 sticky', className)}
|
||||
className={cn('[&_tr]:border-b top-0 sticky bg-bg-title z-10', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
@ -67,7 +67,7 @@ const TableRow = React.forwardRef<
|
||||
<tr
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
|
||||
'border-b border-border-button transition-colors hover:bg-bg-card data-[state=selected]:bg-bg-card',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
@ -82,7 +82,7 @@ const TableHead = React.forwardRef<
|
||||
<th
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'h-12 px-4 text-left align-middle font-normal text-text-secondary [&:has([role=checkbox])]:pr-0',
|
||||
'h-12 px-4 text-left align-middle font-normal text-text-secondary [&:has([role=checkbox])]:pr-0 ',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@ -390,7 +390,7 @@ export const useUploadCanvasFileWithProgress = (
|
||||
files.forEach((file) => {
|
||||
onError(file, error as Error);
|
||||
});
|
||||
message.error('error', error?.message);
|
||||
message.error(error?.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { FileUploadProps } from '@/components/file-upload';
|
||||
import message from '@/components/ui/message';
|
||||
import { ChatSearchParams } from '@/constants/chat';
|
||||
import {
|
||||
@ -14,7 +15,7 @@ import { buildMessageListWithUuid, getConversationId } from '@/utils/chat';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useDebounce } from 'ahooks';
|
||||
import { has } from 'lodash';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useCallback, useMemo, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useParams, useSearchParams } from 'umi';
|
||||
import {
|
||||
@ -395,9 +396,14 @@ export const useDeleteMessage = () => {
|
||||
return { data, loading, deleteMessage: mutateAsync };
|
||||
};
|
||||
|
||||
type UploadParameters = Parameters<NonNullable<FileUploadProps['onUpload']>>;
|
||||
|
||||
type X = { file: UploadParameters[0][0]; options: UploadParameters[1] };
|
||||
|
||||
export function useUploadAndParseFile() {
|
||||
const { conversationId } = useGetChatSearchParams();
|
||||
const { t } = useTranslation();
|
||||
const controller = useRef(new AbortController());
|
||||
|
||||
const {
|
||||
data,
|
||||
@ -405,22 +411,48 @@ export function useUploadAndParseFile() {
|
||||
mutateAsync,
|
||||
} = useMutation({
|
||||
mutationKey: [ChatApiAction.UploadAndParse],
|
||||
mutationFn: async (file: File) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('conversation_id', conversationId);
|
||||
mutationFn: async ({
|
||||
file,
|
||||
options: { onProgress, onSuccess, onError },
|
||||
}: X) => {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('conversation_id', conversationId);
|
||||
|
||||
const { data } = await chatService.uploadAndParse(formData);
|
||||
const { data } = await chatService.uploadAndParse(
|
||||
{
|
||||
signal: controller.current.signal,
|
||||
data: formData,
|
||||
onUploadProgress: ({ progress }) => {
|
||||
onProgress(file, (progress || 0) * 100 - 1);
|
||||
},
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
if (data.code === 0) {
|
||||
message.success(t(`message.uploaded`));
|
||||
onProgress(file, 100);
|
||||
|
||||
if (data.code === 0) {
|
||||
onSuccess(file);
|
||||
message.success(t(`message.uploaded`));
|
||||
} else {
|
||||
onError(file, new Error(data.message));
|
||||
}
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
onError(file, error as Error);
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
return { data, loading, uploadAndParseFile: mutateAsync };
|
||||
const cancel = useCallback(() => {
|
||||
controller.current.abort();
|
||||
controller.current = new AbortController();
|
||||
}, [controller]);
|
||||
|
||||
return { data, loading, uploadAndParseFile: mutateAsync, cancel };
|
||||
}
|
||||
|
||||
export const useFetchExternalChatInfo = () => {
|
||||
|
||||
@ -837,7 +837,7 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
|
||||
fileManager: {
|
||||
name: 'Name',
|
||||
uploadDate: 'Upload Date',
|
||||
knowledgeBase: 'Knowledge Base',
|
||||
knowledgeBase: 'Dataset',
|
||||
size: 'Size',
|
||||
action: 'Action',
|
||||
addToKnowledge: 'Link to Knowledge Base',
|
||||
|
||||
@ -50,9 +50,10 @@ export function DatasetActionCell({
|
||||
}, [record, showRenameModal]);
|
||||
|
||||
return (
|
||||
<section className="flex gap-4 items-center text-text-sub-title-invert">
|
||||
<section className="flex gap-4 items-center text-text-sub-title-invert opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
variant="transparent"
|
||||
className="border-none hover:bg-bg-card text-text-primary"
|
||||
size={'sm'}
|
||||
disabled={isRunning}
|
||||
onClick={handleRename}
|
||||
@ -61,7 +62,12 @@ export function DatasetActionCell({
|
||||
</Button>
|
||||
<HoverCard>
|
||||
<HoverCardTrigger>
|
||||
<Button variant="ghost" disabled={isRunning} size={'sm'}>
|
||||
<Button
|
||||
variant="transparent"
|
||||
className="border-none hover:bg-bg-card text-text-primary"
|
||||
disabled={isRunning}
|
||||
size={'sm'}
|
||||
>
|
||||
<Eye />
|
||||
</Button>
|
||||
</HoverCardTrigger>
|
||||
@ -88,7 +94,8 @@ export function DatasetActionCell({
|
||||
|
||||
{isVirtualDocument || (
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
variant="transparent"
|
||||
className="border-none hover:bg-bg-card text-text-primary"
|
||||
onClick={onDownloadDocument}
|
||||
disabled={isRunning}
|
||||
size={'sm'}
|
||||
@ -97,7 +104,12 @@ export function DatasetActionCell({
|
||||
</Button>
|
||||
)}
|
||||
<ConfirmDeleteDialog onOk={handleRemove}>
|
||||
<Button variant={'ghost'} size={'sm'} disabled={isRunning}>
|
||||
<Button
|
||||
variant="transparent"
|
||||
className="border-none hover:bg-bg-card text-text-primary"
|
||||
size={'sm'}
|
||||
disabled={isRunning}
|
||||
>
|
||||
<Trash2 />
|
||||
</Button>
|
||||
</ConfirmDeleteDialog>
|
||||
|
||||
@ -119,7 +119,7 @@ export function DatasetTable({
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<Table rootClassName="max-h-[82vh]">
|
||||
<Table rootClassName="max-h-[calc(100vh-222px)]">
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
@ -144,6 +144,7 @@ export function DatasetTable({
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && 'selected'}
|
||||
className="group"
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell
|
||||
|
||||
@ -15,9 +15,9 @@ import { Progress } from '@/components/ui/progress';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { IDocumentInfo } from '@/interfaces/database/document';
|
||||
import { CircleX, RefreshCw } from 'lucide-react';
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { RunningStatus } from './constant';
|
||||
import { DocumentType, RunningStatus } from './constant';
|
||||
import { ParsingCard, PopoverContent } from './parsing-card';
|
||||
import { UseChangeDocumentParserShowType } from './use-change-document-parser';
|
||||
import { useHandleRunDocumentByIds } from './use-run-document';
|
||||
@ -61,6 +61,10 @@ export function ParsingStatusCell({
|
||||
showSetMetaModal(record);
|
||||
}, [record, showSetMetaModal]);
|
||||
|
||||
const showParse = useMemo(() => {
|
||||
return record.type !== DocumentType.Virtual;
|
||||
}, [record]);
|
||||
|
||||
return (
|
||||
<section className="flex gap-8 items-center">
|
||||
<div className="w-fit flex items-center justify-between">
|
||||
@ -80,38 +84,42 @@ export function ParsingStatusCell({
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
<ConfirmDeleteDialog
|
||||
title={t(`knowledgeDetails.redo`, { chunkNum: chunk_num })}
|
||||
hidden={isZeroChunk || isRunning}
|
||||
onOk={handleOperationIconClick(true)}
|
||||
onCancel={handleOperationIconClick(false)}
|
||||
>
|
||||
<div
|
||||
className="cursor-pointer flex items-center gap-3"
|
||||
onClick={
|
||||
isZeroChunk || isRunning
|
||||
? handleOperationIconClick(false)
|
||||
: () => {}
|
||||
}
|
||||
>
|
||||
<Separator orientation="vertical" className="h-2.5" />
|
||||
{operationIcon}
|
||||
</div>
|
||||
</ConfirmDeleteDialog>
|
||||
{isParserRunning(run) ? (
|
||||
<HoverCard>
|
||||
<HoverCardTrigger asChild>
|
||||
<div className="flex items-center gap-1">
|
||||
<Progress value={p} className="h-1 flex-1 min-w-10" />
|
||||
{p}%
|
||||
{showParse && (
|
||||
<>
|
||||
<ConfirmDeleteDialog
|
||||
title={t(`knowledgeDetails.redo`, { chunkNum: chunk_num })}
|
||||
hidden={isZeroChunk || isRunning}
|
||||
onOk={handleOperationIconClick(true)}
|
||||
onCancel={handleOperationIconClick(false)}
|
||||
>
|
||||
<div
|
||||
className="cursor-pointer flex items-center gap-3"
|
||||
onClick={
|
||||
isZeroChunk || isRunning
|
||||
? handleOperationIconClick(false)
|
||||
: () => {}
|
||||
}
|
||||
>
|
||||
<Separator orientation="vertical" className="h-2.5" />
|
||||
{operationIcon}
|
||||
</div>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent className="w-[40vw]">
|
||||
<PopoverContent record={record}></PopoverContent>
|
||||
</HoverCardContent>
|
||||
</HoverCard>
|
||||
) : (
|
||||
<ParsingCard record={record}></ParsingCard>
|
||||
</ConfirmDeleteDialog>
|
||||
{isParserRunning(run) ? (
|
||||
<HoverCard>
|
||||
<HoverCardTrigger asChild>
|
||||
<div className="flex items-center gap-1">
|
||||
<Progress value={p} className="h-1 flex-1 min-w-10" />
|
||||
{p}%
|
||||
</div>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent className="w-[40vw]">
|
||||
<PopoverContent record={record}></PopoverContent>
|
||||
</HoverCardContent>
|
||||
</HoverCard>
|
||||
) : (
|
||||
<ParsingCard record={record}></ParsingCard>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
|
||||
@ -61,24 +61,40 @@ export function ActionCell({
|
||||
}, [record, showMoveFileModal]);
|
||||
|
||||
return (
|
||||
<section className="flex gap-4 items-center text-text-sub-title-invert">
|
||||
<section className="flex gap-4 items-center text-text-sub-title-invert opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<Button
|
||||
variant="ghost"
|
||||
variant="transparent"
|
||||
className="border-none hover:bg-bg-card text-text-primary"
|
||||
size={'sm'}
|
||||
onClick={handleShowConnectToKnowledgeModal}
|
||||
>
|
||||
<Link2 />
|
||||
</Button>
|
||||
<Button variant="ghost" size={'sm'} onClick={handleShowMoveFileModal}>
|
||||
<Button
|
||||
variant="transparent"
|
||||
className="border-none hover:bg-bg-card text-text-primary"
|
||||
size={'sm'}
|
||||
onClick={handleShowMoveFileModal}
|
||||
>
|
||||
<FolderInput />
|
||||
</Button>
|
||||
|
||||
<Button variant="ghost" size={'sm'} onClick={handleShowFileRenameModal}>
|
||||
<Button
|
||||
variant="transparent"
|
||||
className="border-none hover:bg-bg-card text-text-primary"
|
||||
size={'sm'}
|
||||
onClick={handleShowFileRenameModal}
|
||||
>
|
||||
<FolderPen />
|
||||
</Button>
|
||||
|
||||
{isFolder || (
|
||||
<Button variant={'ghost'} size={'sm'} onClick={onDownloadDocument}>
|
||||
<Button
|
||||
variant="transparent"
|
||||
className="border-none hover:bg-bg-card text-text-primary"
|
||||
size={'sm'}
|
||||
onClick={onDownloadDocument}
|
||||
>
|
||||
<ArrowDownToLine />
|
||||
</Button>
|
||||
)}
|
||||
@ -89,7 +105,11 @@ export function ActionCell({
|
||||
documentName={record.name}
|
||||
className="text-text-sub-title-invert"
|
||||
>
|
||||
<Button variant={'ghost'} size={'sm'}>
|
||||
<Button
|
||||
variant="transparent"
|
||||
className="border-none hover:bg-bg-card text-text-primary"
|
||||
size={'sm'}
|
||||
>
|
||||
<Eye />
|
||||
</Button>
|
||||
</NewDocumentLink>
|
||||
@ -97,7 +117,8 @@ export function ActionCell({
|
||||
|
||||
{/* <DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size={'sm'}>
|
||||
<Button variant="transparent"
|
||||
className="border-none" size={'sm'}>
|
||||
<EllipsisVertical />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
@ -118,7 +139,11 @@ export function ActionCell({
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu> */}
|
||||
<ConfirmDeleteDialog>
|
||||
<Button variant="ghost" size={'sm'}>
|
||||
<Button
|
||||
variant="transparent"
|
||||
className="border-none hover:bg-bg-card text-text-primary"
|
||||
size={'sm'}
|
||||
>
|
||||
<Trash2 />
|
||||
</Button>
|
||||
</ConfirmDeleteDialog>
|
||||
|
||||
@ -213,6 +213,7 @@ export function FilesTable({
|
||||
id: 'actions',
|
||||
header: t('action'),
|
||||
enableHiding: false,
|
||||
enablePinning: true,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<ActionCell
|
||||
@ -259,51 +260,56 @@ export function FilesTable({
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext(),
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{loading ? (
|
||||
<TableSkeleton columnsLength={columns.length}></TableSkeleton>
|
||||
) : table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && 'selected'}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
className={cell.column.columnDef.meta?.cellClassName}
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
<>
|
||||
<div className="w-full">
|
||||
<Table rootClassName="max-h-[calc(100vh-242px)] overflow-auto">
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext(),
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableEmpty columnsLength={columns.length}></TableEmpty>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody className="max-h-96 overflow-y-auto">
|
||||
{loading ? (
|
||||
<TableSkeleton columnsLength={columns.length}></TableSkeleton>
|
||||
) : table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && 'selected'}
|
||||
className="group"
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
className={cell.column.columnDef.meta?.cellClassName}
|
||||
>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext(),
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableEmpty columnsLength={columns.length}></TableEmpty>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<div className="flex items-center justify-end py-4">
|
||||
<div className="space-x-2">
|
||||
<RAGFlowPagination
|
||||
@ -331,6 +337,6 @@ export function FilesTable({
|
||||
loading={fileRenameLoading}
|
||||
></RenameDialog>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ export function SingleChatBox({ controller }: IProps) {
|
||||
removeMessageById,
|
||||
stopOutputMessage,
|
||||
handleUploadFile,
|
||||
removeFile,
|
||||
} = useSendMessage(controller);
|
||||
const { data: userInfo } = useFetchUserInfo();
|
||||
const { data: currentDialog } = useFetchDialog();
|
||||
@ -97,6 +98,7 @@ export function SingleChatBox({ controller }: IProps) {
|
||||
stopOutputMessage={stopOutputMessage}
|
||||
onUpload={handleUploadFile}
|
||||
isUploading={isUploading}
|
||||
removeFile={removeFile}
|
||||
/>
|
||||
{visible && (
|
||||
<PdfDrawer
|
||||
|
||||
@ -138,7 +138,7 @@ export const useSendMessage = (controller: AbortController) => {
|
||||
const { conversationId, isNew } = useGetChatSearchParams();
|
||||
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
||||
|
||||
const { handleUploadFile, fileIds, clearFileIds, isUploading } =
|
||||
const { handleUploadFile, fileIds, clearFileIds, isUploading, removeFile } =
|
||||
useUploadFile();
|
||||
|
||||
const { send, answer, done } = useSendMessageWithSse(
|
||||
@ -287,5 +287,6 @@ export const useSendMessage = (controller: AbortController) => {
|
||||
stopOutputMessage,
|
||||
handleUploadFile,
|
||||
isUploading,
|
||||
removeFile,
|
||||
};
|
||||
};
|
||||
|
||||
@ -3,16 +3,21 @@ import { useUploadAndParseFile } from '@/hooks/use-chat-request';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
export function useUploadFile() {
|
||||
const { uploadAndParseFile, loading } = useUploadAndParseFile();
|
||||
const { uploadAndParseFile, loading, cancel } = useUploadAndParseFile();
|
||||
const [fileIds, setFileIds] = useState<string[]>([]);
|
||||
const [fileMap, setFileMap] = useState<Map<File, string>>(new Map());
|
||||
|
||||
const handleUploadFile: NonNullable<FileUploadProps['onUpload']> =
|
||||
useCallback(
|
||||
async (files) => {
|
||||
async (files, options) => {
|
||||
if (Array.isArray(files) && files.length) {
|
||||
const ret = await uploadAndParseFile(files[0]);
|
||||
const ret = await uploadAndParseFile({ file: files[0], options });
|
||||
if (ret.code === 0 && Array.isArray(ret.data)) {
|
||||
setFileIds((list) => [...list, ...ret.data]);
|
||||
setFileMap((map) => {
|
||||
map.set(files[0], ret.data[0]);
|
||||
return map;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -21,7 +26,28 @@ export function useUploadFile() {
|
||||
|
||||
const clearFileIds = useCallback(() => {
|
||||
setFileIds([]);
|
||||
setFileMap(new Map());
|
||||
}, []);
|
||||
|
||||
return { handleUploadFile, clearFileIds, fileIds, isUploading: loading };
|
||||
const removeFile = useCallback(
|
||||
(file: File) => {
|
||||
if (loading) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
const id = fileMap.get(file);
|
||||
if (id) {
|
||||
setFileIds((list) => list.filter((item) => item !== id));
|
||||
}
|
||||
},
|
||||
[cancel, fileMap, loading],
|
||||
);
|
||||
|
||||
return {
|
||||
handleUploadFile,
|
||||
clearFileIds,
|
||||
fileIds,
|
||||
isUploading: loading,
|
||||
removeFile,
|
||||
};
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ module.exports = {
|
||||
'input-border': 'var(--input-border)',
|
||||
|
||||
/* design colors */
|
||||
|
||||
'bg-title': 'var(--bg-title)',
|
||||
'bg-base': 'var(--bg-base)',
|
||||
'bg-card': 'var(--bg-card)',
|
||||
'bg-component': 'var(--bg-component)',
|
||||
|
||||
@ -91,6 +91,8 @@
|
||||
--input-border: rgba(22, 22, 24, 0.2);
|
||||
|
||||
--metallic: #46464a;
|
||||
|
||||
--bg-title: #f6f6f7;
|
||||
/* design colors */
|
||||
|
||||
--bg-base: #ffffff;
|
||||
@ -235,6 +237,8 @@
|
||||
--input-border: rgba(255, 255, 255, 0.2);
|
||||
|
||||
--metallic: #fafafa;
|
||||
|
||||
--bg-title: #38383a;
|
||||
/* design colors */
|
||||
|
||||
--bg-base: #161618;
|
||||
|
||||
Reference in New Issue
Block a user