mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-02-02 16:45:08 +08:00
Compare commits
3 Commits
b3b0be832a
...
pipeline
| Author | SHA1 | Date | |
|---|---|---|---|
| 32dbed36e3 | |||
| 7f62ab8eb3 | |||
| e87987785c |
@ -240,6 +240,11 @@ export function ChunkMethodDialog({
|
|||||||
name: 'parseType',
|
name: 'parseType',
|
||||||
defaultValue: pipelineId ? 2 : 1,
|
defaultValue: pipelineId ? 2 : 1,
|
||||||
});
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
if (parseType === 1) {
|
||||||
|
form.setValue('pipeline_id', '');
|
||||||
|
}
|
||||||
|
}, [parseType, form]);
|
||||||
return (
|
return (
|
||||||
<Dialog open onOpenChange={hideModal}>
|
<Dialog open onOpenChange={hideModal}>
|
||||||
<DialogContent className="max-w-[50vw]">
|
<DialogContent className="max-w-[50vw]">
|
||||||
|
|||||||
@ -75,7 +75,7 @@ export function DataFlowSelect(props: IProps) {
|
|||||||
tooltip={t('dataFlowTip')}
|
tooltip={t('dataFlowTip')}
|
||||||
className="text-sm text-text-primary whitespace-wrap "
|
className="text-sm text-text-primary whitespace-wrap "
|
||||||
>
|
>
|
||||||
{t('dataFlow')}
|
{t('dataPipeline')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
{toDataPipeline && (
|
{toDataPipeline && (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -33,7 +33,12 @@ export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
|||||||
export const FormTooltip = ({ tooltip }: { tooltip: React.ReactNode }) => {
|
export const FormTooltip = ({ tooltip }: { tooltip: React.ReactNode }) => {
|
||||||
return (
|
return (
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger tabIndex={-1}>
|
<TooltipTrigger
|
||||||
|
tabIndex={-1}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault(); // Prevent clicking the tooltip from triggering form save
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Info className="size-3 ml-2" />
|
<Info className="size-3 ml-2" />
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
@ -107,7 +112,7 @@ export const AntToolTip: React.FC<AntToolTipProps> = ({
|
|||||||
{visible && title && (
|
{visible && title && (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'absolute z-50 px-2.5 py-2 text-xs text-text-primary bg-muted rounded-sm shadow-sm whitespace-wrap',
|
'absolute z-50 px-2.5 py-2 text-xs text-text-primary bg-muted rounded-sm shadow-sm whitespace-wrap w-max',
|
||||||
getPlacementClasses(),
|
getPlacementClasses(),
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -13,7 +13,9 @@ import {
|
|||||||
} from './logic-hooks';
|
} from './logic-hooks';
|
||||||
import { useGetKnowledgeSearchParams } from './route-hook';
|
import { useGetKnowledgeSearchParams } from './route-hook';
|
||||||
|
|
||||||
export const useFetchNextChunkList = (): ResponseGetType<{
|
export const useFetchNextChunkList = (
|
||||||
|
enabled = true,
|
||||||
|
): ResponseGetType<{
|
||||||
data: IChunk[];
|
data: IChunk[];
|
||||||
total: number;
|
total: number;
|
||||||
documentInfo: IKnowledgeFile;
|
documentInfo: IKnowledgeFile;
|
||||||
@ -37,6 +39,7 @@ export const useFetchNextChunkList = (): ResponseGetType<{
|
|||||||
placeholderData: (previousData: any) =>
|
placeholderData: (previousData: any) =>
|
||||||
previousData ?? { data: [], total: 0, documentInfo: {} }, // https://github.com/TanStack/query/issues/8183
|
previousData ?? { data: [], total: 0, documentInfo: {} }, // https://github.com/TanStack/query/issues/8183
|
||||||
gcTime: 0,
|
gcTime: 0,
|
||||||
|
enabled,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await kbService.chunk_list({
|
const { data } = await kbService.chunk_list({
|
||||||
doc_id: documentId,
|
doc_id: documentId,
|
||||||
|
|||||||
@ -290,9 +290,9 @@ export default {
|
|||||||
linkDataPipeline: 'Link Data Pipeline',
|
linkDataPipeline: 'Link Data Pipeline',
|
||||||
enableAutoGenerate: 'Enable Auto Generate',
|
enableAutoGenerate: 'Enable Auto Generate',
|
||||||
teamPlaceholder: 'Please select a team.',
|
teamPlaceholder: 'Please select a team.',
|
||||||
dataFlowPlaceholder: 'Please select a data flow.',
|
dataFlowPlaceholder: 'Please select a pipeline.',
|
||||||
buildItFromScratch: 'Build it from scratch',
|
buildItFromScratch: 'Build it from scratch',
|
||||||
dataFlow: 'Data Flow',
|
dataFlow: 'Pipeline',
|
||||||
parseType: 'Parse Type',
|
parseType: 'Parse Type',
|
||||||
manualSetup: 'Manual Setup',
|
manualSetup: 'Manual Setup',
|
||||||
builtIn: 'Built-in',
|
builtIn: 'Built-in',
|
||||||
@ -420,7 +420,7 @@ export default {
|
|||||||
<p>In a Tag column, <b>comma</b> is used to separate tags.</p>
|
<p>In a Tag column, <b>comma</b> is used to separate tags.</p>
|
||||||
<i>Lines of texts that fail to follow the above rules will be ignored.</i>
|
<i>Lines of texts that fail to follow the above rules will be ignored.</i>
|
||||||
`,
|
`,
|
||||||
useRaptor: 'Use RAPTOR to enhance retrieval',
|
useRaptor: 'RAPTOR',
|
||||||
useRaptorTip:
|
useRaptorTip:
|
||||||
'Enable RAPTOR for multi-hop question-answering tasks. See https://ragflow.io/docs/dev/enable_raptor for details.',
|
'Enable RAPTOR for multi-hop question-answering tasks. See https://ragflow.io/docs/dev/enable_raptor for details.',
|
||||||
prompt: 'Prompt',
|
prompt: 'Prompt',
|
||||||
@ -466,7 +466,7 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
|
|||||||
topnTags: 'Top-N Tags',
|
topnTags: 'Top-N Tags',
|
||||||
tags: 'Tags',
|
tags: 'Tags',
|
||||||
addTag: 'Add tag',
|
addTag: 'Add tag',
|
||||||
useGraphRag: 'Extract knowledge graph',
|
useGraphRag: 'Knowledge graph',
|
||||||
useGraphRagTip:
|
useGraphRagTip:
|
||||||
'Construct a knowledge graph over file chunks of the current knowledge base to enhance multi-hop question-answering involving nested logic. See https://ragflow.io/docs/dev/construct_knowledge_graph for details.',
|
'Construct a knowledge graph over file chunks of the current knowledge base to enhance multi-hop question-answering involving nested logic. See https://ragflow.io/docs/dev/construct_knowledge_graph for details.',
|
||||||
graphRagMethod: 'Method',
|
graphRagMethod: 'Method',
|
||||||
@ -474,7 +474,7 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
|
|||||||
General: Use prompts provided by github.com/microsoft/graphrag to extract entities and relationships`,
|
General: Use prompts provided by github.com/microsoft/graphrag to extract entities and relationships`,
|
||||||
resolution: 'Entity resolution',
|
resolution: 'Entity resolution',
|
||||||
resolutionTip: `An entity deduplication switch. When enabled, the LLM will combine similar entities - e.g., '2025' and 'the year of 2025', or 'IT' and 'Information Technology' - to construct a more accurate graph`,
|
resolutionTip: `An entity deduplication switch. When enabled, the LLM will combine similar entities - e.g., '2025' and 'the year of 2025', or 'IT' and 'Information Technology' - to construct a more accurate graph`,
|
||||||
community: 'Community reports generation',
|
community: 'Community reports',
|
||||||
communityTip:
|
communityTip:
|
||||||
'In a knowledge graph, a community is a cluster of entities linked by relationships. You can have the LLM generate an abstract for each community, known as a community report. See here for more information: https://www.microsoft.com/en-us/research/blog/graphrag-improving-global-search-via-dynamic-community-selection/',
|
'In a knowledge graph, a community is a cluster of entities linked by relationships. You can have the LLM generate an abstract for each community, known as a community report. See here for more information: https://www.microsoft.com/en-us/research/blog/graphrag-improving-global-search-via-dynamic-community-selection/',
|
||||||
theDocumentBeingParsedCannotBeDeleted:
|
theDocumentBeingParsedCannotBeDeleted:
|
||||||
@ -1065,7 +1065,7 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
|
|||||||
{input}
|
{input}
|
||||||
The above is the content you need to summarize.`,
|
The above is the content you need to summarize.`,
|
||||||
createGraph: 'Create agent',
|
createGraph: 'Create agent',
|
||||||
createFromTemplates: 'Create from templates',
|
createFromTemplates: 'Create from template',
|
||||||
retrieval: 'Retrieval',
|
retrieval: 'Retrieval',
|
||||||
generate: 'Generate',
|
generate: 'Generate',
|
||||||
answer: 'Interact',
|
answer: 'Interact',
|
||||||
@ -1586,9 +1586,12 @@ This delimiter is used to split the input text into several text pieces echo of
|
|||||||
'Write your SQL query here. You can use variables, raw SQL, or mix both using variable syntax.',
|
'Write your SQL query here. You can use variables, raw SQL, or mix both using variable syntax.',
|
||||||
frameworkPrompts: 'Framework',
|
frameworkPrompts: 'Framework',
|
||||||
release: 'Publish',
|
release: 'Publish',
|
||||||
createFromBlank: 'Create from Blank',
|
createFromBlank: 'Create from blank',
|
||||||
createFromTemplate: 'Create from Template',
|
createFromTemplate: 'Create from template',
|
||||||
importJsonFile: 'Import json file',
|
importJsonFile: 'Import JSON file',
|
||||||
|
ceateAgent: 'Agent flow',
|
||||||
|
createPipeline: 'Data pipeline',
|
||||||
|
chooseAgentType: 'Choose Agent Type',
|
||||||
},
|
},
|
||||||
llmTools: {
|
llmTools: {
|
||||||
bad_calculator: {
|
bad_calculator: {
|
||||||
@ -1788,5 +1791,12 @@ Important structured information may include: names, dates, locations, events, k
|
|||||||
summary: 'Augmented Context',
|
summary: 'Augmented Context',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
datasetOverview: {
|
||||||
|
downloadTip: 'Files being downloaded from data sources. ',
|
||||||
|
processingTip: 'Files being processed by data flows.',
|
||||||
|
totalFiles: 'Total Files',
|
||||||
|
downloading: 'Downloading',
|
||||||
|
processing: 'Processing',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1500,6 +1500,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
|||||||
createFromBlank: '从空白创建',
|
createFromBlank: '从空白创建',
|
||||||
createFromTemplate: '从模板创建',
|
createFromTemplate: '从模板创建',
|
||||||
importJsonFile: '导入 JSON 文件',
|
importJsonFile: '导入 JSON 文件',
|
||||||
|
chooseAgentType: '选择智能体类型',
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
profile: 'All rights reserved @ React',
|
profile: 'All rights reserved @ React',
|
||||||
@ -1695,5 +1696,12 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
|||||||
filenameEmbeddingWeight: '文件名嵌入权重',
|
filenameEmbeddingWeight: '文件名嵌入权重',
|
||||||
switchPromptMessage: '提示词将发生变化,请确认是否放弃已有提示词?',
|
switchPromptMessage: '提示词将发生变化,请确认是否放弃已有提示词?',
|
||||||
},
|
},
|
||||||
|
datasetOverview: {
|
||||||
|
downloadTip: '正在从数据源下载文件。',
|
||||||
|
processingTip: '正在由数据流处理文件。',
|
||||||
|
totalFiles: '文件总数',
|
||||||
|
downloading: '正在下载',
|
||||||
|
processing: '正在处理',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export function CreateAgentDialog({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open onOpenChange={hideModal}>
|
<Dialog open onOpenChange={hideModal}>
|
||||||
<DialogContent className="sm:max-w-[425px]">
|
<DialogContent>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{t('flow.createGraph')}</DialogTitle>
|
<DialogTitle>{t('flow.createGraph')}</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|||||||
@ -25,6 +25,7 @@ type FlowTypeCardProps = {
|
|||||||
onChange?: (value: FlowType) => void;
|
onChange?: (value: FlowType) => void;
|
||||||
};
|
};
|
||||||
function FlowTypeCards({ value, onChange }: FlowTypeCardProps) {
|
function FlowTypeCards({ value, onChange }: FlowTypeCardProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(value: FlowType) => () => {
|
(value: FlowType) => () => {
|
||||||
onChange?.(value);
|
onChange?.(value);
|
||||||
@ -59,7 +60,11 @@ function FlowTypeCards({ value, onChange }: FlowTypeCardProps) {
|
|||||||
) : (
|
) : (
|
||||||
<Route className="size-6" />
|
<Route className="size-6" />
|
||||||
)}
|
)}
|
||||||
<p>{val}</p>
|
<p>
|
||||||
|
{t(
|
||||||
|
`flow.${val === FlowType.Agent ? 'createAgent' : 'createPipeline'}`,
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{isActive && <Check />}
|
{isActive && <Check />}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@ -106,7 +111,11 @@ export function CreateAgentForm({
|
|||||||
id={TagRenameId}
|
id={TagRenameId}
|
||||||
>
|
>
|
||||||
{shouldChooseAgent && (
|
{shouldChooseAgent && (
|
||||||
<RAGFlowFormItem required name="type" label={t('common.type')}>
|
<RAGFlowFormItem
|
||||||
|
required
|
||||||
|
name="type"
|
||||||
|
label={t('flow.chooseAgentType')}
|
||||||
|
>
|
||||||
<FlowTypeCards></FlowTypeCards>
|
<FlowTypeCards></FlowTypeCards>
|
||||||
</RAGFlowFormItem>
|
</RAGFlowFormItem>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -16,12 +16,7 @@ export const NameFormSchema = {
|
|||||||
export function NameFormField() {
|
export function NameFormField() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<RAGFlowFormItem
|
<RAGFlowFormItem name="name" required label={t('common.name')}>
|
||||||
name="name"
|
|
||||||
required
|
|
||||||
label={t('common.name')}
|
|
||||||
tooltip={t('flow.sqlStatementTip')}
|
|
||||||
>
|
|
||||||
<Input placeholder={t('common.namePlaceholder')} autoComplete="off" />
|
<Input placeholder={t('common.namePlaceholder')} autoComplete="off" />
|
||||||
</RAGFlowFormItem>
|
</RAGFlowFormItem>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -52,6 +52,7 @@ export const HandleContext = createContext<HandleContextType>(
|
|||||||
export type LogContextType = {
|
export type LogContextType = {
|
||||||
messageId: string;
|
messageId: string;
|
||||||
setMessageId: (messageId: string) => void;
|
setMessageId: (messageId: string) => void;
|
||||||
|
setUploadedFileData: (data: Record<string, any>) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LogContext = createContext<LogContextType>({} as LogContextType);
|
export const LogContext = createContext<LogContextType>({} as LogContextType);
|
||||||
|
|||||||
@ -13,7 +13,7 @@ export function useRunDataflow(
|
|||||||
) {
|
) {
|
||||||
const { send } = useSendMessageBySSE(api.runCanvas);
|
const { send } = useSendMessageBySSE(api.runCanvas);
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const { setMessageId } = useContext(LogContext);
|
const { setMessageId, setUploadedFileData } = useContext(LogContext);
|
||||||
|
|
||||||
const { handleRun: saveGraph, loading } =
|
const { handleRun: saveGraph, loading } =
|
||||||
useSaveGraphBeforeOpeningDebugDrawer(showLogSheet!);
|
useSaveGraphBeforeOpeningDebugDrawer(showLogSheet!);
|
||||||
@ -32,7 +32,7 @@ export function useRunDataflow(
|
|||||||
if (res && res?.response.status === 200 && get(res, 'data.code') === 0) {
|
if (res && res?.response.status === 200 && get(res, 'data.code') === 0) {
|
||||||
// fetch canvas
|
// fetch canvas
|
||||||
hideRunOrChatDrawer();
|
hideRunOrChatDrawer();
|
||||||
|
setUploadedFileData(fileResponseData.file);
|
||||||
const msgId = get(res, 'data.data.message_id');
|
const msgId = get(res, 'data.data.message_id');
|
||||||
if (msgId) {
|
if (msgId) {
|
||||||
setMessageId(msgId);
|
setMessageId(msgId);
|
||||||
@ -43,7 +43,14 @@ export function useRunDataflow(
|
|||||||
message.error(get(res, 'data.message', ''));
|
message.error(get(res, 'data.message', ''));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[hideRunOrChatDrawer, id, saveGraph, send, setMessageId],
|
[
|
||||||
|
hideRunOrChatDrawer,
|
||||||
|
id,
|
||||||
|
saveGraph,
|
||||||
|
send,
|
||||||
|
setMessageId,
|
||||||
|
setUploadedFileData,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return { run, loading: loading };
|
return { run, loading: loading };
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import {
|
|||||||
Settings,
|
Settings,
|
||||||
Upload,
|
Upload,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { ComponentPropsWithoutRef, useCallback } from 'react';
|
import { ComponentPropsWithoutRef, useCallback, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import DataFlowCanvas from './canvas';
|
import DataFlowCanvas from './canvas';
|
||||||
import { DropdownProvider } from './canvas/context';
|
import { DropdownProvider } from './canvas/context';
|
||||||
@ -99,6 +99,9 @@ export default function DataFlow() {
|
|||||||
isLogEmpty,
|
isLogEmpty,
|
||||||
} = useFetchLog(logSheetVisible);
|
} = useFetchLog(logSheetVisible);
|
||||||
|
|
||||||
|
const [uploadedFileData, setUploadedFileData] =
|
||||||
|
useState<Record<string, any>>();
|
||||||
|
|
||||||
const handleRunAgent = useCallback(() => {
|
const handleRunAgent = useCallback(() => {
|
||||||
if (isParsing) {
|
if (isParsing) {
|
||||||
// show log sheet
|
// show log sheet
|
||||||
@ -184,7 +187,9 @@ export default function DataFlow() {
|
|||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<LogContext.Provider value={{ messageId, setMessageId }}>
|
<LogContext.Provider
|
||||||
|
value={{ messageId, setMessageId, setUploadedFileData }}
|
||||||
|
>
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<DropdownProvider>
|
<DropdownProvider>
|
||||||
<DataFlowCanvas
|
<DataFlowCanvas
|
||||||
@ -211,6 +216,8 @@ export default function DataFlow() {
|
|||||||
isLogEmpty={isLogEmpty}
|
isLogEmpty={isLogEmpty}
|
||||||
logs={logs}
|
logs={logs}
|
||||||
handleCancel={handleCancel}
|
handleCancel={handleCancel}
|
||||||
|
messageId={messageId}
|
||||||
|
uploadedFileData={uploadedFileData}
|
||||||
></LogSheet>
|
></LogSheet>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
SheetTitle,
|
SheetTitle,
|
||||||
} from '@/components/ui/sheet';
|
} from '@/components/ui/sheet';
|
||||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
|
import { useFetchAgent } from '@/hooks/use-agent-request';
|
||||||
import { IModalProps } from '@/interfaces/common';
|
import { IModalProps } from '@/interfaces/common';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { PipelineResultSearchParams } from '@/pages/dataflow-result/constant';
|
import { PipelineResultSearchParams } from '@/pages/dataflow-result/constant';
|
||||||
@ -18,6 +19,7 @@ import {
|
|||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import 'react18-json-view/src/style.css';
|
import 'react18-json-view/src/style.css';
|
||||||
|
import { useParams } from 'umi';
|
||||||
import {
|
import {
|
||||||
isEndOutputEmpty,
|
isEndOutputEmpty,
|
||||||
useDownloadOutput,
|
useDownloadOutput,
|
||||||
@ -27,9 +29,10 @@ import { DataflowTimeline } from './dataflow-timeline';
|
|||||||
|
|
||||||
type LogSheetProps = IModalProps<any> & {
|
type LogSheetProps = IModalProps<any> & {
|
||||||
handleCancel(): void;
|
handleCancel(): void;
|
||||||
|
uploadedFileData?: Record<string, any>;
|
||||||
} & Pick<
|
} & Pick<
|
||||||
UseFetchLogReturnType,
|
UseFetchLogReturnType,
|
||||||
'isCompleted' | 'isLogEmpty' | 'isParsing' | 'logs'
|
'isCompleted' | 'isLogEmpty' | 'isParsing' | 'logs' | 'messageId'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export function LogSheet({
|
export function LogSheet({
|
||||||
@ -39,11 +42,16 @@ export function LogSheet({
|
|||||||
handleCancel,
|
handleCancel,
|
||||||
isCompleted,
|
isCompleted,
|
||||||
isLogEmpty,
|
isLogEmpty,
|
||||||
|
messageId,
|
||||||
|
uploadedFileData,
|
||||||
}: LogSheetProps) {
|
}: LogSheetProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { id } = useParams();
|
||||||
|
const { data: agent } = useFetchAgent();
|
||||||
|
|
||||||
const { handleDownloadJson } = useDownloadOutput(logs);
|
const { handleDownloadJson } = useDownloadOutput(logs);
|
||||||
const { navigateToDataflowResult } = useNavigatePage();
|
const { navigateToDataflowResult } = useNavigatePage();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sheet open onOpenChange={hideModal} modal={false}>
|
<Sheet open onOpenChange={hideModal} modal={false}>
|
||||||
<SheetContent
|
<SheetContent
|
||||||
@ -57,14 +65,16 @@ export function LogSheet({
|
|||||||
variant={'ghost'}
|
variant={'ghost'}
|
||||||
disabled={!isCompleted}
|
disabled={!isCompleted}
|
||||||
onClick={navigateToDataflowResult({
|
onClick={navigateToDataflowResult({
|
||||||
id: 'cfc28d6c9c4911f088bf047c16ec874f', // 'log_id',
|
id: messageId, // 'log_id',
|
||||||
[PipelineResultSearchParams.AgentId]:
|
[PipelineResultSearchParams.AgentId]: id, // 'agent_id',
|
||||||
'cfc28d6c9c4911f088bf047c16ec874f', // 'agent_id',
|
[PipelineResultSearchParams.DocumentId]: uploadedFileData?.id, //'doc_id',
|
||||||
[PipelineResultSearchParams.DocumentId]:
|
[PipelineResultSearchParams.AgentTitle]: agent.title, //'title',
|
||||||
'05b0e19a9d9d11f0b674047c16ec874f', //'doc_id',
|
|
||||||
[PipelineResultSearchParams.AgentTitle]: 'full', //'title',
|
|
||||||
[PipelineResultSearchParams.IsReadOnly]: 'true',
|
[PipelineResultSearchParams.IsReadOnly]: 'true',
|
||||||
[PipelineResultSearchParams.Type]: 'dataflow',
|
[PipelineResultSearchParams.Type]: 'dataflow',
|
||||||
|
[PipelineResultSearchParams.CreatedBy]:
|
||||||
|
uploadedFileData?.created_by,
|
||||||
|
[PipelineResultSearchParams.DocumentExtension]:
|
||||||
|
uploadedFileData?.extension,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{t('dataflow.viewResult')} <ArrowUpRight />
|
{t('dataflow.viewResult')} <ArrowUpRight />
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
||||||
import { api_host } from '@/utils/api';
|
import api, { api_host } from '@/utils/api';
|
||||||
import { useSize } from 'ahooks';
|
import { useSize } from 'ahooks';
|
||||||
import { CustomTextRenderer } from 'node_modules/react-pdf/dist/esm/shared/types';
|
import { CustomTextRenderer } from 'node_modules/react-pdf/dist/esm/shared/types';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { useGetPipelineResultSearchParams } from '../../hooks';
|
||||||
|
|
||||||
export const useDocumentResizeObserver = () => {
|
export const useDocumentResizeObserver = () => {
|
||||||
const [containerWidth, setContainerWidth] = useState<number>();
|
const [containerWidth, setContainerWidth] = useState<number>();
|
||||||
@ -44,12 +45,16 @@ export const useHighlightText = (searchText: string = '') => {
|
|||||||
return textRenderer;
|
return textRenderer;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGetDocumentUrl = () => {
|
export const useGetDocumentUrl = (isAgent: boolean) => {
|
||||||
const { documentId } = useGetKnowledgeSearchParams();
|
const { documentId } = useGetKnowledgeSearchParams();
|
||||||
|
const { createdBy, documentId: id } = useGetPipelineResultSearchParams();
|
||||||
|
|
||||||
const url = useMemo(() => {
|
const url = useMemo(() => {
|
||||||
|
if (isAgent) {
|
||||||
|
return api.downloadFile + `?id=${id}&created_by=${createdBy}`;
|
||||||
|
}
|
||||||
return `${api_host}/document/get/${documentId}`;
|
return `${api_host}/document/get/${documentId}`;
|
||||||
}, [documentId]);
|
}, [createdBy, documentId, id, isAgent]);
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,8 +5,8 @@ export const useParserInit = ({
|
|||||||
initialValue,
|
initialValue,
|
||||||
}: {
|
}: {
|
||||||
initialValue:
|
initialValue:
|
||||||
| Pick<IJsonContainerProps, 'initialValue'>
|
| IJsonContainerProps['initialValue']
|
||||||
| Pick<IObjContainerProps, 'initialValue'>;
|
| IObjContainerProps['initialValue'];
|
||||||
}) => {
|
}) => {
|
||||||
const [content, setContent] = useState(initialValue);
|
const [content, setContent] = useState(initialValue);
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { IJsonContainerProps } from './interface';
|
|||||||
export const parserKeyMap = {
|
export const parserKeyMap = {
|
||||||
json: 'text',
|
json: 'text',
|
||||||
chunks: 'text',
|
chunks: 'text',
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
export const ArrayContainer = (props: IJsonContainerProps) => {
|
export const ArrayContainer = (props: IJsonContainerProps) => {
|
||||||
const {
|
const {
|
||||||
@ -33,24 +33,15 @@ export const ArrayContainer = (props: IJsonContainerProps) => {
|
|||||||
editDivRef,
|
editDivRef,
|
||||||
} = useParserInit({ initialValue });
|
} = useParserInit({ initialValue });
|
||||||
|
|
||||||
|
const parserKey = parserKeyMap[content.key as keyof typeof parserKeyMap];
|
||||||
|
|
||||||
const handleEdit = useCallback(
|
const handleEdit = useCallback(
|
||||||
(e?: any, index?: number) => {
|
(e?: any, index?: number) => {
|
||||||
setContent((pre) => ({
|
|
||||||
...pre,
|
|
||||||
value: pre.value.map((item, i) => {
|
|
||||||
if (i === index) {
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
[parserKeyMap[content.key]]: unescapeNewlines(e.target.innerText),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
setActiveEditIndex(index);
|
setActiveEditIndex(index);
|
||||||
},
|
},
|
||||||
[setContent, setActiveEditIndex],
|
[setContent, setActiveEditIndex],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSave = useCallback(
|
const handleSave = useCallback(
|
||||||
(e: any) => {
|
(e: any) => {
|
||||||
const saveData = {
|
const saveData = {
|
||||||
@ -59,7 +50,7 @@ export const ArrayContainer = (props: IJsonContainerProps) => {
|
|||||||
if (index === activeEditIndex) {
|
if (index === activeEditIndex) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
[parserKeyMap[content.key]]: e.target.innerText,
|
[parserKey]: e.target.textContent || '',
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return item;
|
return item;
|
||||||
@ -75,26 +66,28 @@ export const ArrayContainer = (props: IJsonContainerProps) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeEditIndex !== undefined && editDivRef.current) {
|
if (activeEditIndex !== undefined && editDivRef.current) {
|
||||||
editDivRef.current.focus();
|
editDivRef.current.focus();
|
||||||
editDivRef.current.textContent = escapeNewlines(
|
editDivRef.current.textContent =
|
||||||
content.value[activeEditIndex][parserKeyMap[content.key]],
|
content.value[activeEditIndex][parserKey];
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}, [activeEditIndex, content]);
|
}, [editDivRef, activeEditIndex, content, parserKey]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{content.value?.map((item, index) => {
|
{content.value?.map((item, index) => {
|
||||||
if (item[parserKeyMap[content.key]] === '') {
|
if (
|
||||||
|
item[parserKeyMap[content.key as keyof typeof parserKeyMap]] === ''
|
||||||
|
) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
key={index}
|
key={index}
|
||||||
className={
|
className={cn(
|
||||||
isChunck
|
isChunck
|
||||||
? 'bg-bg-card my-2 p-2 rounded-lg flex gap-1 items-start'
|
? 'bg-bg-card my-2 p-2 rounded-lg flex gap-1 items-start'
|
||||||
: ''
|
: '',
|
||||||
}
|
activeEditIndex === index && isChunck ? 'bg-bg-title' : '',
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{isChunck && !isReadonly && (
|
{isChunck && !isReadonly && (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
@ -113,6 +106,7 @@ export const ArrayContainer = (props: IJsonContainerProps) => {
|
|||||||
onBlur={handleSave}
|
onBlur={handleSave}
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full bg-transparent text-text-secondary border-none focus-visible:border-none focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:outline-none p-0',
|
'w-full bg-transparent text-text-secondary border-none focus-visible:border-none focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:outline-none p-0',
|
||||||
|
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
></div>
|
></div>
|
||||||
@ -120,7 +114,7 @@ export const ArrayContainer = (props: IJsonContainerProps) => {
|
|||||||
{activeEditIndex !== index && (
|
{activeEditIndex !== index && (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'text-text-secondary overflow-auto scrollbar-auto whitespace-pre-wrap w-full',
|
'text-text-secondary overflow-auto scrollbar-auto w-full',
|
||||||
{
|
{
|
||||||
[styles.contentEllipsis]:
|
[styles.contentEllipsis]:
|
||||||
textMode === ChunkTextMode.Ellipse,
|
textMode === ChunkTextMode.Ellipse,
|
||||||
@ -134,7 +128,7 @@ export const ArrayContainer = (props: IJsonContainerProps) => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{escapeNewlines(item[parserKeyMap[content.key]])}
|
{item[parserKeyMap[content.key]]}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -25,22 +25,19 @@ export const ObjectContainer = (props: IObjContainerProps) => {
|
|||||||
editDivRef,
|
editDivRef,
|
||||||
} = useParserInit({ initialValue });
|
} = useParserInit({ initialValue });
|
||||||
|
|
||||||
const handleEdit = useCallback(
|
const handleEdit = useCallback(() => {
|
||||||
(e?: any) => {
|
// setContent((pre) => ({
|
||||||
setContent((pre) => ({
|
// ...pre,
|
||||||
...pre,
|
// value: escapeNewlines(e.target.innerText),
|
||||||
value: escapeNewlines(e.target.innerText),
|
// }));
|
||||||
}));
|
setActiveEditIndex(1);
|
||||||
setActiveEditIndex(1);
|
}, [setContent, setActiveEditIndex]);
|
||||||
},
|
|
||||||
[setContent, setActiveEditIndex],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSave = useCallback(
|
const handleSave = useCallback(
|
||||||
(e: any) => {
|
(e: any) => {
|
||||||
const saveData = {
|
const saveData = {
|
||||||
...content,
|
...content,
|
||||||
value: e.target.innerText,
|
value: e.target.textContent,
|
||||||
};
|
};
|
||||||
onSave(saveData);
|
onSave(saveData);
|
||||||
setActiveEditIndex(undefined);
|
setActiveEditIndex(undefined);
|
||||||
@ -51,9 +48,9 @@ export const ObjectContainer = (props: IObjContainerProps) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeEditIndex !== undefined && editDivRef.current) {
|
if (activeEditIndex !== undefined && editDivRef.current) {
|
||||||
editDivRef.current.focus();
|
editDivRef.current.focus();
|
||||||
editDivRef.current.textContent = escapeNewlines(content.value);
|
editDivRef.current.textContent = content.value;
|
||||||
}
|
}
|
||||||
}, [activeEditIndex, content, escapeNewlines]);
|
}, [activeEditIndex, content]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -90,7 +87,7 @@ export const ObjectContainer = (props: IObjContainerProps) => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{escapeNewlines(content.value)}
|
{content.value}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -20,4 +20,6 @@ export enum PipelineResultSearchParams {
|
|||||||
IsReadOnly = 'is_read_only',
|
IsReadOnly = 'is_read_only',
|
||||||
AgentId = 'agent_id',
|
AgentId = 'agent_id',
|
||||||
AgentTitle = 'agent_title',
|
AgentTitle = 'agent_title',
|
||||||
|
CreatedBy = 'created_by', // Who uploaded the file
|
||||||
|
DocumentExtension = 'extension',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import message from '@/components/ui/message';
|
|||||||
import { useCreateChunk, useDeleteChunk } from '@/hooks/chunk-hooks';
|
import { useCreateChunk, useDeleteChunk } from '@/hooks/chunk-hooks';
|
||||||
import { useSetModalState, useShowDeleteConfirm } from '@/hooks/common-hooks';
|
import { useSetModalState, useShowDeleteConfirm } from '@/hooks/common-hooks';
|
||||||
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
||||||
|
import { useFetchMessageTrace } from '@/hooks/use-agent-request';
|
||||||
import { IChunk } from '@/interfaces/database/knowledge';
|
import { IChunk } from '@/interfaces/database/knowledge';
|
||||||
import kbService from '@/services/knowledge-service';
|
import kbService from '@/services/knowledge-service';
|
||||||
import { formatSecondsToHumanReadable } from '@/utils/date';
|
import { formatSecondsToHumanReadable } from '@/utils/date';
|
||||||
@ -10,7 +11,7 @@ import { buildChunkHighlights } from '@/utils/document-util';
|
|||||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { camelCase, upperFirst } from 'lodash';
|
import { camelCase, upperFirst } from 'lodash';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { IHighlight } from 'react-pdf-highlighter';
|
import { IHighlight } from 'react-pdf-highlighter';
|
||||||
import { useParams, useSearchParams } from 'umi';
|
import { useParams, useSearchParams } from 'umi';
|
||||||
import { ITimelineNodeObj, TimelineNodeObj } from './components/time-line';
|
import { ITimelineNodeObj, TimelineNodeObj } from './components/time-line';
|
||||||
@ -21,11 +22,15 @@ import {
|
|||||||
} from './constant';
|
} from './constant';
|
||||||
import { IDslComponent, IPipelineFileLogDetail } from './interface';
|
import { IDslComponent, IPipelineFileLogDetail } from './interface';
|
||||||
|
|
||||||
export const useFetchPipelineFileLogDetail = (props?: {
|
export const useFetchPipelineFileLogDetail = ({
|
||||||
|
isAgent = false,
|
||||||
|
isEdit = true,
|
||||||
|
refreshCount,
|
||||||
|
}: {
|
||||||
isEdit?: boolean;
|
isEdit?: boolean;
|
||||||
refreshCount?: number;
|
refreshCount?: number;
|
||||||
|
isAgent: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const { isEdit = true, refreshCount } = props || { isEdit: true };
|
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const logId = searchParams.get('id') || id;
|
const logId = searchParams.get('id') || id;
|
||||||
@ -39,6 +44,7 @@ export const useFetchPipelineFileLogDetail = (props?: {
|
|||||||
queryKey,
|
queryKey,
|
||||||
initialData: {} as IPipelineFileLogDetail,
|
initialData: {} as IPipelineFileLogDetail,
|
||||||
gcTime: 0,
|
gcTime: 0,
|
||||||
|
enabled: !isAgent,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
const { data } = await kbService.get_pipeline_detail({
|
const { data } = await kbService.get_pipeline_detail({
|
||||||
@ -287,5 +293,39 @@ export const useGetPipelineResultSearchParams = () => {
|
|||||||
currentQueryParameters.get(PipelineResultSearchParams.AgentId) || '',
|
currentQueryParameters.get(PipelineResultSearchParams.AgentId) || '',
|
||||||
agentTitle:
|
agentTitle:
|
||||||
currentQueryParameters.get(PipelineResultSearchParams.AgentTitle) || '',
|
currentQueryParameters.get(PipelineResultSearchParams.AgentTitle) || '',
|
||||||
|
documentExtension:
|
||||||
|
currentQueryParameters.get(
|
||||||
|
PipelineResultSearchParams.DocumentExtension,
|
||||||
|
) || '',
|
||||||
|
createdBy:
|
||||||
|
currentQueryParameters.get(PipelineResultSearchParams.CreatedBy) || '',
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function useFetchPipelineResult({
|
||||||
|
agentId,
|
||||||
|
}: Pick<ReturnType<typeof useGetPipelineResultSearchParams>, 'agentId'>) {
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
const messageId = searchParams.get('id');
|
||||||
|
|
||||||
|
const { data, setMessageId, setISStopFetchTrace } =
|
||||||
|
useFetchMessageTrace(agentId);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (messageId) {
|
||||||
|
setMessageId(messageId);
|
||||||
|
setISStopFetchTrace(true);
|
||||||
|
}
|
||||||
|
}, [agentId, messageId, setISStopFetchTrace, setMessageId]);
|
||||||
|
|
||||||
|
const pipelineResult = useMemo(() => {
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
const latest = data?.at(-1);
|
||||||
|
if (latest?.component_id === 'END' && Array.isArray(latest.trace)) {
|
||||||
|
return latest.trace.at(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
return { pipelineResult };
|
||||||
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import DocumentPreview from './components/document-preview';
|
import DocumentPreview from './components/document-preview';
|
||||||
import {
|
import {
|
||||||
useFetchPipelineFileLogDetail,
|
useFetchPipelineFileLogDetail,
|
||||||
|
useFetchPipelineResult,
|
||||||
useGetChunkHighlights,
|
useGetChunkHighlights,
|
||||||
useGetPipelineResultSearchParams,
|
useGetPipelineResultSearchParams,
|
||||||
useHandleChunkCardClick,
|
useHandleChunkCardClick,
|
||||||
@ -26,28 +27,38 @@ import {
|
|||||||
} from '@/components/ui/breadcrumb';
|
} from '@/components/ui/breadcrumb';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Modal } from '@/components/ui/modal/modal';
|
import { Modal } from '@/components/ui/modal/modal';
|
||||||
|
import { Images } from '@/constants/common';
|
||||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
||||||
import { useGetDocumentUrl } from './components/document-preview/hooks';
|
import { useGetDocumentUrl } from './components/document-preview/hooks';
|
||||||
import TimelineDataFlow from './components/time-line';
|
import TimelineDataFlow from './components/time-line';
|
||||||
import { TimelineNodeType } from './constant';
|
import { TimelineNodeType } from './constant';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
import { IDslComponent } from './interface';
|
import { IDslComponent, IPipelineFileLogDetail } from './interface';
|
||||||
import ParserContainer from './parser';
|
import ParserContainer from './parser';
|
||||||
|
|
||||||
const Chunk = () => {
|
const Chunk = () => {
|
||||||
const { isReadOnly, knowledgeId, agentId, agentTitle } =
|
const { isReadOnly, knowledgeId, agentId, agentTitle, documentExtension } =
|
||||||
useGetPipelineResultSearchParams();
|
useGetPipelineResultSearchParams();
|
||||||
|
|
||||||
|
const isAgent = !!agentId;
|
||||||
|
|
||||||
|
const { pipelineResult } = useFetchPipelineResult({ agentId });
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: { documentInfo },
|
data: { documentInfo },
|
||||||
} = useFetchNextChunkList();
|
} = useFetchNextChunkList(!isAgent);
|
||||||
|
|
||||||
const { selectedChunk, handleChunkCardClick } = useHandleChunkCardClick();
|
const { selectedChunk, handleChunkCardClick } = useHandleChunkCardClick();
|
||||||
const [activeStepId, setActiveStepId] = useState<number | string>(2);
|
const [activeStepId, setActiveStepId] = useState<number | string>(2);
|
||||||
const { data: dataset } = useFetchPipelineFileLogDetail();
|
const { data: dataset } = useFetchPipelineFileLogDetail({
|
||||||
|
isAgent,
|
||||||
|
});
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { timelineNodes } = useTimelineDataFlow(dataset);
|
const { timelineNodes } = useTimelineDataFlow(
|
||||||
|
agentId ? (pipelineResult as IPipelineFileLogDetail) : dataset,
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
navigateToDataset,
|
navigateToDataset,
|
||||||
@ -55,12 +66,17 @@ const Chunk = () => {
|
|||||||
navigateToAgents,
|
navigateToAgents,
|
||||||
navigateToDataflow,
|
navigateToDataflow,
|
||||||
} = useNavigatePage();
|
} = useNavigatePage();
|
||||||
const fileUrl = useGetDocumentUrl();
|
let fileUrl = useGetDocumentUrl(isAgent);
|
||||||
|
|
||||||
const { highlights, setWidthAndHeight } =
|
const { highlights, setWidthAndHeight } =
|
||||||
useGetChunkHighlights(selectedChunk);
|
useGetChunkHighlights(selectedChunk);
|
||||||
|
|
||||||
const fileType = useMemo(() => {
|
const fileType = useMemo(() => {
|
||||||
|
if (isAgent) {
|
||||||
|
return Images.some((x) => x === documentExtension)
|
||||||
|
? 'visual'
|
||||||
|
: documentExtension;
|
||||||
|
}
|
||||||
switch (documentInfo?.type) {
|
switch (documentInfo?.type) {
|
||||||
case 'doc':
|
case 'doc':
|
||||||
return documentInfo?.name.split('.').pop() || 'doc';
|
return documentInfo?.name.split('.').pop() || 'doc';
|
||||||
@ -72,7 +88,7 @@ const Chunk = () => {
|
|||||||
return documentInfo?.type;
|
return documentInfo?.type;
|
||||||
}
|
}
|
||||||
return 'unknown';
|
return 'unknown';
|
||||||
}, [documentInfo]);
|
}, [documentExtension, documentInfo?.name, documentInfo?.type, isAgent]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleReRunFunc,
|
handleReRunFunc,
|
||||||
|
|||||||
@ -77,4 +77,6 @@ export interface NavigateToDataflowResultProps {
|
|||||||
[PipelineResultSearchParams.AgentTitle]?: string;
|
[PipelineResultSearchParams.AgentTitle]?: string;
|
||||||
[PipelineResultSearchParams.IsReadOnly]?: string;
|
[PipelineResultSearchParams.IsReadOnly]?: string;
|
||||||
[PipelineResultSearchParams.Type]: string;
|
[PipelineResultSearchParams.Type]: string;
|
||||||
|
[PipelineResultSearchParams.CreatedBy]: string;
|
||||||
|
[PipelineResultSearchParams.DocumentExtension]: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { FilterCollection } from '@/components/list-filter-bar/interface';
|
import { FilterCollection } from '@/components/list-filter-bar/interface';
|
||||||
import SvgIcon from '@/components/svg-icon';
|
import SvgIcon from '@/components/svg-icon';
|
||||||
import { useIsDarkTheme } from '@/components/theme-provider';
|
import { useIsDarkTheme } from '@/components/theme-provider';
|
||||||
|
import { AntToolTip } from '@/components/ui/tooltip';
|
||||||
import { useFetchDocumentList } from '@/hooks/use-document-request';
|
import { useFetchDocumentList } from '@/hooks/use-document-request';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { CircleQuestionMark } from 'lucide-react';
|
import { CircleQuestionMark } from 'lucide-react';
|
||||||
@ -17,19 +18,30 @@ interface StatCardProps {
|
|||||||
value: number;
|
value: number;
|
||||||
icon: JSX.Element;
|
icon: JSX.Element;
|
||||||
children?: JSX.Element;
|
children?: JSX.Element;
|
||||||
|
tooltip?: string;
|
||||||
}
|
}
|
||||||
interface CardFooterProcessProps {
|
interface CardFooterProcessProps {
|
||||||
success: number;
|
success: number;
|
||||||
failed: number;
|
failed: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StatCard: FC<StatCardProps> = ({ title, value, children, icon }) => {
|
const StatCard: FC<StatCardProps> = ({
|
||||||
|
title,
|
||||||
|
value,
|
||||||
|
children,
|
||||||
|
icon,
|
||||||
|
tooltip,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="bg-bg-card p-4 rounded-lg border border-border flex flex-col gap-2">
|
<div className="bg-bg-card p-4 rounded-lg border border-border flex flex-col gap-2">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h3 className="flex items-center gap-1 text-sm font-medium text-text-secondary">
|
<h3 className="flex items-center gap-1 text-sm font-medium text-text-secondary">
|
||||||
{title}
|
{title}
|
||||||
<CircleQuestionMark size={12} />
|
{tooltip && (
|
||||||
|
<AntToolTip title={tooltip} trigger="hover">
|
||||||
|
<CircleQuestionMark size={12} />
|
||||||
|
</AntToolTip>
|
||||||
|
)}
|
||||||
</h3>
|
</h3>
|
||||||
{icon}
|
{icon}
|
||||||
</div>
|
</div>
|
||||||
@ -51,15 +63,19 @@ const CardFooterProcess: FC<CardFooterProcessProps> = ({
|
|||||||
<div className="w-full flex justify-between gap-4 rounded-lg text-sm font-bold text-text-primary">
|
<div className="w-full flex justify-between gap-4 rounded-lg text-sm font-bold text-text-primary">
|
||||||
<div className="flex items-center justify-between rounded-md w-1/2 p-2 bg-state-success-5">
|
<div className="flex items-center justify-between rounded-md w-1/2 p-2 bg-state-success-5">
|
||||||
<div className="flex items-center rounded-lg gap-1">
|
<div className="flex items-center rounded-lg gap-1">
|
||||||
<div className="w-2 h-2 rounded-full bg-state-success"></div>
|
<div className="w-2 h-2 rounded-full bg-state-success "></div>
|
||||||
<div>{t('knowledgeDetails.success')}</div>
|
<div className="font-normal text-text-secondary text-xs">
|
||||||
|
{t('knowledgeDetails.success')}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>{success || 0}</div>
|
<div>{success || 0}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between rounded-md w-1/2 bg-state-error-5 p-2">
|
<div className="flex items-center justify-between rounded-md w-1/2 bg-state-error-5 p-2">
|
||||||
<div className="flex items-center rounded-lg gap-1">
|
<div className="flex items-center rounded-lg gap-1">
|
||||||
<div className="w-2 h-2 rounded-full bg-state-error"></div>
|
<div className="w-2 h-2 rounded-full bg-state-error"></div>
|
||||||
<div>{t('knowledgeDetails.failed')}</div>
|
<div className="font-normal text-text-secondary text-xs">
|
||||||
|
{t('knowledgeDetails.failed')}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>{failed || 0}</div>
|
<div>{failed || 0}</div>
|
||||||
</div>
|
</div>
|
||||||
@ -189,7 +205,7 @@ const FileLogsPage: FC = () => {
|
|||||||
{/* Stats Cards */}
|
{/* Stats Cards */}
|
||||||
<div className="grid grid-cols-3 md:grid-cols-3 gap-4 mb-6">
|
<div className="grid grid-cols-3 md:grid-cols-3 gap-4 mb-6">
|
||||||
<StatCard
|
<StatCard
|
||||||
title="Total Files"
|
title={t('datasetOverview.totalFiles')}
|
||||||
value={topAllData.totalFiles.value}
|
value={topAllData.totalFiles.value}
|
||||||
icon={
|
icon={
|
||||||
isDark ? (
|
isDark ? (
|
||||||
@ -204,11 +220,13 @@ const FileLogsPage: FC = () => {
|
|||||||
{topAllData.totalFiles.precent > 0 ? '+' : ''}
|
{topAllData.totalFiles.precent > 0 ? '+' : ''}
|
||||||
{topAllData.totalFiles.precent}%{' '}
|
{topAllData.totalFiles.precent}%{' '}
|
||||||
</span>
|
</span>
|
||||||
from last week
|
<span className="font-normal text-text-secondary text-xs">
|
||||||
|
from last week
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</StatCard>
|
</StatCard>
|
||||||
<StatCard
|
<StatCard
|
||||||
title="Downloading"
|
title={t('datasetOverview.downloading')}
|
||||||
value={topAllData.downloads.value}
|
value={topAllData.downloads.value}
|
||||||
icon={
|
icon={
|
||||||
isDark ? (
|
isDark ? (
|
||||||
@ -217,6 +235,7 @@ const FileLogsPage: FC = () => {
|
|||||||
<SvgIcon name="data-flow/data-icon-bri" width={40} />
|
<SvgIcon name="data-flow/data-icon-bri" width={40} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
tooltip={t('datasetOverview.downloadTip')}
|
||||||
>
|
>
|
||||||
<CardFooterProcess
|
<CardFooterProcess
|
||||||
success={topAllData.downloads.success}
|
success={topAllData.downloads.success}
|
||||||
@ -224,7 +243,7 @@ const FileLogsPage: FC = () => {
|
|||||||
/>
|
/>
|
||||||
</StatCard>
|
</StatCard>
|
||||||
<StatCard
|
<StatCard
|
||||||
title="Processing"
|
title={t('datasetOverview.processing')}
|
||||||
value={topAllData.processing.value}
|
value={topAllData.processing.value}
|
||||||
icon={
|
icon={
|
||||||
isDark ? (
|
isDark ? (
|
||||||
@ -233,6 +252,7 @@ const FileLogsPage: FC = () => {
|
|||||||
<SvgIcon name="data-flow/processing-icon-bri" width={40} />
|
<SvgIcon name="data-flow/processing-icon-bri" width={40} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
tooltip={t('datasetOverview.processingTip')}
|
||||||
>
|
>
|
||||||
<CardFooterProcess
|
<CardFooterProcess
|
||||||
success={topAllData.processing.success}
|
success={topAllData.processing.success}
|
||||||
|
|||||||
@ -42,7 +42,7 @@ export function ChunkMethodItem(props: IProps) {
|
|||||||
'w-1/4 whitespace-pre-wrap': line === 1,
|
'w-1/4 whitespace-pre-wrap': line === 1,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{t('chunkMethod')}
|
{t('dataPipeline')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<div className={line === 1 ? 'w-3/4 ' : 'w-full'}>
|
<div className={line === 1 ? 'w-3/4 ' : 'w-full'}>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
|
|||||||
@ -99,7 +99,7 @@ export function ParsingStatusCell({
|
|||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent>
|
<DropdownMenuContent>
|
||||||
<DropdownMenuItem onClick={handleShowChangeParserModal}>
|
<DropdownMenuItem onClick={handleShowChangeParserModal}>
|
||||||
{t('knowledgeDetails.chunkMethod')}
|
{t('knowledgeDetails.dataPipeline')}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={handleShowSetMetaModal}>
|
<DropdownMenuItem onClick={handleShowSetMetaModal}>
|
||||||
{t('knowledgeDetails.setMetaData')}
|
{t('knowledgeDetails.setMetaData')}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { IconFontFill } from '@/components/icon-font';
|
||||||
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
|
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { useSecondPathName } from '@/hooks/route-hook';
|
import { useSecondPathName } from '@/hooks/route-hook';
|
||||||
@ -9,13 +10,7 @@ import { cn, formatBytes } from '@/lib/utils';
|
|||||||
import { Routes } from '@/routes';
|
import { Routes } from '@/routes';
|
||||||
import { formatPureDate } from '@/utils/date';
|
import { formatPureDate } from '@/utils/date';
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
import {
|
import { Banknote, DatabaseZap, FileSearch2, FolderOpen } from 'lucide-react';
|
||||||
Banknote,
|
|
||||||
DatabaseZap,
|
|
||||||
FileSearch2,
|
|
||||||
FolderOpen,
|
|
||||||
GitGraph,
|
|
||||||
} from 'lucide-react';
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHandleMenuClick } from './hooks';
|
import { useHandleMenuClick } from './hooks';
|
||||||
@ -35,29 +30,29 @@ export function SideBar({ refreshCount }: PropType) {
|
|||||||
const items = useMemo(() => {
|
const items = useMemo(() => {
|
||||||
const list = [
|
const list = [
|
||||||
{
|
{
|
||||||
icon: DatabaseZap,
|
icon: <DatabaseZap className="size-4" />,
|
||||||
label: t(`knowledgeDetails.overview`),
|
label: t(`knowledgeDetails.overview`),
|
||||||
key: Routes.DataSetOverview,
|
key: Routes.DataSetOverview,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: FolderOpen,
|
icon: <FolderOpen className="size-4" />,
|
||||||
label: t(`knowledgeDetails.subbarFiles`),
|
label: t(`knowledgeDetails.subbarFiles`),
|
||||||
key: Routes.DatasetBase,
|
key: Routes.DatasetBase,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: FileSearch2,
|
icon: <FileSearch2 className="size-4" />,
|
||||||
label: t(`knowledgeDetails.testing`),
|
label: t(`knowledgeDetails.testing`),
|
||||||
key: Routes.DatasetTesting,
|
key: Routes.DatasetTesting,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: Banknote,
|
icon: <Banknote className="size-4" />,
|
||||||
label: t(`knowledgeDetails.configuration`),
|
label: t(`knowledgeDetails.configuration`),
|
||||||
key: Routes.DataSetSetting,
|
key: Routes.DataSetSetting,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
if (!isEmpty(routerData?.graph)) {
|
if (!isEmpty(routerData?.graph)) {
|
||||||
list.push({
|
list.push({
|
||||||
icon: GitGraph,
|
icon: <IconFontFill name="knowledgegraph" className="size-4" />,
|
||||||
label: t(`knowledgeDetails.knowledgeGraph`),
|
label: t(`knowledgeDetails.knowledgeGraph`),
|
||||||
key: Routes.KnowledgeGraph,
|
key: Routes.KnowledgeGraph,
|
||||||
});
|
});
|
||||||
@ -105,7 +100,7 @@ export function SideBar({ refreshCount }: PropType) {
|
|||||||
)}
|
)}
|
||||||
onClick={handleMenuClick(item.key)}
|
onClick={handleMenuClick(item.key)}
|
||||||
>
|
>
|
||||||
<item.icon className="size-4" />
|
{item.icon}
|
||||||
<span>{item.label}</span>
|
<span>{item.label}</span>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { DataFlowSelect } from '@/components/data-pipeline-select';
|
||||||
import { ButtonLoading } from '@/components/ui/button';
|
import { ButtonLoading } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@ -18,10 +19,10 @@ import { Input } from '@/components/ui/input';
|
|||||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
import { IModalProps } from '@/interfaces/common';
|
import { IModalProps } from '@/interfaces/common';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { useForm, useWatch } from 'react-hook-form';
|
import { useForm, useWatch } from 'react-hook-form';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChunkMethodItem,
|
ChunkMethodItem,
|
||||||
EmbeddingModelItem,
|
EmbeddingModelItem,
|
||||||
@ -94,6 +95,13 @@ export function InputForm({ onOk }: IModalProps<any>) {
|
|||||||
control: form.control,
|
control: form.control,
|
||||||
name: 'parseType',
|
name: 'parseType',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('parseType', parseType);
|
||||||
|
if (parseType === 1) {
|
||||||
|
form.setValue('pipeline_id', '');
|
||||||
|
}
|
||||||
|
}, [parseType, form]);
|
||||||
const { navigateToAgents } = useNavigatePage();
|
const { navigateToAgents } = useNavigatePage();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -177,6 +177,7 @@ export default {
|
|||||||
`${ExternalApi}${api_host}/agentbots/${canvasId}/inputs`,
|
`${ExternalApi}${api_host}/agentbots/${canvasId}/inputs`,
|
||||||
prompt: `${api_host}/canvas/prompts`,
|
prompt: `${api_host}/canvas/prompts`,
|
||||||
cancelDataflow: (id: string) => `${api_host}/canvas/cancel/${id}`,
|
cancelDataflow: (id: string) => `${api_host}/canvas/cancel/${id}`,
|
||||||
|
downloadFile: `${api_host}/canvas/download`,
|
||||||
|
|
||||||
// mcp server
|
// mcp server
|
||||||
listMcpServer: `${api_host}/mcp_server/list`,
|
listMcpServer: `${api_host}/mcp_server/list`,
|
||||||
|
|||||||
Reference in New Issue
Block a user