mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-08-01 21:37:33 +08:00
Feat: Add an update button to the graph page of the dataset. (#17571)
### Summary Feat: Add an update button to the graph page of the dataset.
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Modal } from '@/components/ui/modal/modal';
|
||||
import { GenerateType, GenerateTypeMap } from '@/constants/knowledge';
|
||||
import { useUnBindTask } from '@/hooks/use-dataset-generate';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { formatDate } from '@/utils/date';
|
||||
import { lowerFirst } from 'lodash';
|
||||
import { Trash2 } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { GenerateType, GenerateTypeMap } from './constants';
|
||||
import { useUnBindTask } from './hook';
|
||||
|
||||
export type IGenerateLogButtonProps = {
|
||||
finish_at: string;
|
||||
@@ -112,5 +112,3 @@ export function GenerateLogButton(props: IGenerateLogProps) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default GenerateLogButton;
|
||||
@@ -1,19 +1,18 @@
|
||||
import { FormLayout } from '@/constants/form';
|
||||
import { DocumentParserType } from '@/constants/knowledge';
|
||||
import { DocumentParserType, GenerateType } from '@/constants/knowledge';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useKnowledgeBaseContext } from '@/pages/dataset/contexts/knowledge-base-context';
|
||||
import { LLMModelItem } from '@/pages/dataset/dataset-setting/configuration/common-item';
|
||||
import { GenerateType } from '@/pages/dataset/dataset/generate-button/constants';
|
||||
import {
|
||||
GenerateLogButton,
|
||||
IGenerateLogButtonProps,
|
||||
} from '@/pages/dataset/dataset/generate-button/generate-log-button';
|
||||
import { upperFirst } from 'lodash';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useFormContext, useWatch } from 'react-hook-form';
|
||||
import { EntityTypesFormField } from '../entity-types-form-field';
|
||||
import { FormContainer } from '../form-container';
|
||||
import {
|
||||
GenerateLogButton,
|
||||
IGenerateLogButtonProps,
|
||||
} from '../generate-log-button';
|
||||
import { SliderInputFormField } from '../slider-input-form-field';
|
||||
import {
|
||||
FormControl,
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { FormLayout } from '@/constants/form';
|
||||
import { DocumentParserType } from '@/constants/knowledge';
|
||||
import { DocumentParserType, GenerateType } from '@/constants/knowledge';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { GenerateType } from '@/pages/dataset/dataset/generate-button/constants';
|
||||
import {
|
||||
GenerateLogButton,
|
||||
IGenerateLogButtonProps,
|
||||
} from '@/pages/dataset/dataset/generate-button/generate-log-button';
|
||||
import random from 'lodash/random';
|
||||
import { Shuffle } from 'lucide-react';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useFormContext, useWatch } from 'react-hook-form';
|
||||
import {
|
||||
GenerateLogButton,
|
||||
IGenerateLogButtonProps,
|
||||
} from '../generate-log-button';
|
||||
import { SliderInputFormField } from '../slider-input-form-field';
|
||||
import {
|
||||
FormControl,
|
||||
|
||||
@@ -116,3 +116,66 @@ export enum ParseType {
|
||||
BuiltIn = 1,
|
||||
Pipeline = 2,
|
||||
}
|
||||
|
||||
export enum ProcessingType {
|
||||
knowledgeGraph = 'Graph',
|
||||
raptor = 'RAPTOR',
|
||||
artifact = 'Artifact',
|
||||
skill = 'Skill',
|
||||
mindmap = 'Mindmap',
|
||||
timeline = 'Timeline',
|
||||
sessionEssence = 'Session_Essence',
|
||||
sessionGraph = 'Session_Graph',
|
||||
}
|
||||
|
||||
export const ProcessingTypeMap = {
|
||||
[ProcessingType.knowledgeGraph]: 'Knowledge Graph',
|
||||
[ProcessingType.raptor]: 'RAPTOR',
|
||||
[ProcessingType.artifact]: 'Artifact',
|
||||
[ProcessingType.skill]: 'Skill',
|
||||
[ProcessingType.mindmap]: 'Mind Map',
|
||||
[ProcessingType.timeline]: 'Timeline',
|
||||
[ProcessingType.sessionEssence]: 'Session Essence',
|
||||
[ProcessingType.sessionGraph]: 'Session Graph',
|
||||
GraphRAG: 'Knowledge Graph',
|
||||
};
|
||||
|
||||
export enum GenerateStatus {
|
||||
Running = 'running',
|
||||
Completed = 'completed',
|
||||
Start = 'start',
|
||||
Failed = 'failed',
|
||||
}
|
||||
|
||||
export enum GenerateType {
|
||||
KnowledgeGraph = 'KnowledgeGraph',
|
||||
Raptor = 'Raptor',
|
||||
Artifact = 'Artifact',
|
||||
ToSkills = 'ToSkills',
|
||||
MindMap = 'MindMap',
|
||||
Timeline = 'Timeline',
|
||||
SessionEssence = 'SessionEssence',
|
||||
SessionGraph = 'SessionGraph',
|
||||
}
|
||||
|
||||
export enum TraceType {
|
||||
Graph = 'graph',
|
||||
Raptor = 'raptor',
|
||||
Artifact = 'artifact',
|
||||
Skill = 'skill',
|
||||
MindMap = 'mindmap',
|
||||
Timeline = 'timeline',
|
||||
SessionEssence = 'session_essence',
|
||||
SessionGraph = 'session_graph',
|
||||
}
|
||||
|
||||
export const GenerateTypeMap = {
|
||||
[GenerateType.KnowledgeGraph]: ProcessingType.knowledgeGraph,
|
||||
[GenerateType.Raptor]: ProcessingType.raptor,
|
||||
[GenerateType.Artifact]: ProcessingType.artifact,
|
||||
[GenerateType.ToSkills]: ProcessingType.skill,
|
||||
[GenerateType.MindMap]: ProcessingType.mindmap,
|
||||
[GenerateType.Timeline]: ProcessingType.timeline,
|
||||
[GenerateType.SessionEssence]: ProcessingType.sessionEssence,
|
||||
[GenerateType.SessionGraph]: ProcessingType.sessionGraph,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
import message from '@/components/ui/message';
|
||||
import {
|
||||
GenerateStatus,
|
||||
GenerateType,
|
||||
GenerateTypeMap,
|
||||
ProcessingType,
|
||||
TraceType,
|
||||
} from '@/constants/knowledge';
|
||||
import agentService from '@/services/agent-service';
|
||||
import {
|
||||
deletePipelineTask,
|
||||
@@ -6,10 +13,9 @@ import {
|
||||
traceIndex,
|
||||
} from '@/services/knowledge-service';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useParams } from 'react-router';
|
||||
import { ProcessingType } from '../../dataset-overview/dataset-common';
|
||||
import { GenerateType, GenerateTypeMap, TraceType } from './constants';
|
||||
|
||||
enum DatasetKey {
|
||||
generate = 'generate',
|
||||
@@ -111,6 +117,7 @@ export const useUnBindTask = () => {
|
||||
});
|
||||
return { handleUnbindTask };
|
||||
};
|
||||
|
||||
export const useDatasetGenerate = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { id } = useParams();
|
||||
@@ -164,3 +171,32 @@ export const useDatasetGenerate = () => {
|
||||
});
|
||||
return { runGenerate: mutateAsync, pauseGenerate, data, loading };
|
||||
};
|
||||
|
||||
export function useGenerateStatus(data?: ITraceInfo) {
|
||||
const status = useMemo(() => {
|
||||
if (!data) {
|
||||
return GenerateStatus.Start;
|
||||
}
|
||||
if (data.progress >= 1) {
|
||||
return GenerateStatus.Completed;
|
||||
} else if (!data.progress && data.progress !== 0) {
|
||||
return GenerateStatus.Start;
|
||||
} else if (data.progress < 0) {
|
||||
return GenerateStatus.Failed;
|
||||
} else if (data.progress < 1) {
|
||||
return GenerateStatus.Running;
|
||||
}
|
||||
return GenerateStatus.Start;
|
||||
}, [data]);
|
||||
|
||||
const percent = useMemo(() => {
|
||||
if (status === GenerateStatus.Failed) {
|
||||
return 100;
|
||||
} else if (status === GenerateStatus.Running) {
|
||||
return data!.progress * 100;
|
||||
}
|
||||
return 0;
|
||||
}, [status, data]);
|
||||
|
||||
return { status, percent };
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
import { useHandleFilterSubmit } from '@/components/list-filter-bar/use-handle-filter-submit';
|
||||
import message from '@/components/ui/message';
|
||||
import { ParseType } from '@/constants/knowledge';
|
||||
import { GenerateType, ParseType } from '@/constants/knowledge';
|
||||
import { ResponsePostType, ResponseType } from '@/interfaces/database/base';
|
||||
import { GenerateType } from '@/pages/dataset/dataset/generate-button/constants';
|
||||
import { DatasetGenerateKeys } from '@/pages/dataset/dataset/generate-button/hook';
|
||||
import {
|
||||
IArtifact,
|
||||
IArtifactAlteration,
|
||||
@@ -73,6 +71,7 @@ import {
|
||||
isPipelineParserConfig,
|
||||
} from './parser-config-utils';
|
||||
import { useSetPaginationParams } from './route-hook';
|
||||
import { DatasetGenerateKeys } from './use-dataset-generate';
|
||||
|
||||
export const enum KnowledgeApiAction {
|
||||
FetchKnowledgeListByPage = 'fetchKnowledgeListByPage',
|
||||
@@ -450,20 +449,20 @@ export const ArtifactTopicKeys = {
|
||||
};
|
||||
|
||||
export const ArtifactAlterationKeys = {
|
||||
detail: (datasetId: string) =>
|
||||
[KnowledgeApiAction.FetchArtifactAlteration, datasetId] as const,
|
||||
detail: (datasetId: string, kind: string) =>
|
||||
[KnowledgeApiAction.FetchArtifactAlteration, datasetId, kind] as const,
|
||||
};
|
||||
|
||||
export function useFetchArtifactAlteration() {
|
||||
export function useFetchArtifactAlteration(kind: string) {
|
||||
const knowledgeBaseId = useKnowledgeBaseId();
|
||||
|
||||
const { data, isFetching: loading } = useQuery<IArtifactAlteration | null>({
|
||||
queryKey: ArtifactAlterationKeys.detail(knowledgeBaseId),
|
||||
queryKey: ArtifactAlterationKeys.detail(knowledgeBaseId, kind),
|
||||
initialData: null,
|
||||
enabled: !!knowledgeBaseId,
|
||||
enabled: !!knowledgeBaseId && !!kind,
|
||||
gcTime: 0,
|
||||
queryFn: async () => {
|
||||
const { data } = await getArtifactsAlteration(knowledgeBaseId);
|
||||
const { data } = await getArtifactsAlteration(knowledgeBaseId, kind);
|
||||
return data?.data ?? null;
|
||||
},
|
||||
});
|
||||
@@ -953,7 +952,7 @@ export const useClearWiki = () => {
|
||||
return { data, loading, clearWiki: mutateAsync };
|
||||
};
|
||||
|
||||
export const useRunArtifactIndex = () => {
|
||||
export const useRunArtifactIndex = (kind: string) => {
|
||||
const knowledgeBaseId = useKnowledgeBaseId();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
@@ -968,7 +967,7 @@ export const useRunArtifactIndex = () => {
|
||||
if (data?.code === 0) {
|
||||
message.success(i18n.t('message.operated'));
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ArtifactAlterationKeys.detail(knowledgeBaseId),
|
||||
queryKey: ArtifactAlterationKeys.detail(knowledgeBaseId, kind),
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ArtifactKeys.listByDataset(knowledgeBaseId),
|
||||
|
||||
@@ -469,6 +469,9 @@ Example: A 1 KB message with 1024-dim embedding uses ~9 KB. The 5 MB default lim
|
||||
updateTooltip:
|
||||
'{{newlyUploaded}} new, {{removed}} removed documents found. Click to compile and merge into current Wiki.',
|
||||
updateSheetTitle: 'Update Wiki',
|
||||
updateStructureSheetTitle: 'Update {{name}}',
|
||||
updateStructureTooltip:
|
||||
'{{newlyUploaded}} new, {{removed}} removed documents found. Click to update the {{name}}.',
|
||||
viewUpdateLogs: 'View update logs',
|
||||
log: 'Log',
|
||||
noSkills: 'No skills yet',
|
||||
|
||||
@@ -419,6 +419,9 @@ export default {
|
||||
updateTooltip:
|
||||
'发现 {{newlyUploaded}} 个新文档,{{removed}} 个已移除文档。点击编译并合并到当前 Wiki。',
|
||||
updateSheetTitle: '更新 Wiki',
|
||||
updateStructureSheetTitle: '更新{{name}}',
|
||||
updateStructureTooltip:
|
||||
'发现 {{newlyUploaded}} 个新文档,{{removed}} 个已移除文档。点击更新{{name}}。',
|
||||
viewUpdateLogs: '查看更新日志',
|
||||
log: '日志',
|
||||
noSkills: '暂无技能',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { GenerateType } from '@/pages/dataset/dataset/generate-button/constants';
|
||||
import { GenerateType } from '@/constants/knowledge';
|
||||
|
||||
export enum ViewMode {
|
||||
LlmWiki = 'llm-wiki',
|
||||
|
||||
@@ -7,16 +7,20 @@ import { getEntityDisplayName } from '@/components/structure-graph/adapters';
|
||||
import { RepresentationRenderer } from '@/components/structure-graph/representation-renderer';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card } from '@/components/ui/card';
|
||||
import { GenerateStatus } from '@/constants/knowledge';
|
||||
import {
|
||||
useDatasetGenerate,
|
||||
useGenerateStatus,
|
||||
useTraceRunData,
|
||||
} from '@/hooks/use-dataset-generate';
|
||||
import {
|
||||
DatasetStructureKeys,
|
||||
useDeleteDatasetStructure,
|
||||
useFetchArtifactAlteration,
|
||||
useFetchDatasetStructureGraph,
|
||||
useFetchKnowledgeBaseConfiguration,
|
||||
useKnowledgeBaseId,
|
||||
} from '@/hooks/use-knowledge-request';
|
||||
import { GenerateStatus } from '@/pages/dataset/dataset/generate-button/constants';
|
||||
import { useTraceRunData } from '@/pages/dataset/dataset/generate-button/hook';
|
||||
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { Trash2 } from 'lucide-react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
@@ -30,6 +34,8 @@ import {
|
||||
} from './constants';
|
||||
import CompilationEmptyState from './empty-state';
|
||||
import { CompilationLoadingCard } from './loading-card';
|
||||
import { CompilationUpdateButton } from './update-button';
|
||||
import { UpdateLogSheet } from './update-log-sheet';
|
||||
|
||||
interface DatasetStructureViewProps {
|
||||
kind: StructureKind;
|
||||
@@ -47,13 +53,21 @@ export function DatasetStructureView({ kind }: DatasetStructureViewProps) {
|
||||
const { deleteDatasetStructure, loading: deleting } =
|
||||
useDeleteDatasetStructure();
|
||||
|
||||
const { data: structureRunData } = useTraceRunData(
|
||||
ViewModeGenerateTypeMap[kind],
|
||||
);
|
||||
const generateType = ViewModeGenerateTypeMap[kind];
|
||||
const { data: structureRunData } = useTraceRunData(generateType);
|
||||
const { status: structureStatus } = useGenerateStatus(structureRunData);
|
||||
|
||||
const { data: alteration, loading: alterationLoading } =
|
||||
useFetchArtifactAlteration(kind);
|
||||
const { runGenerate, loading: runLoading } = useDatasetGenerate();
|
||||
const [updateSheetOpen, setUpdateSheetOpen] = useState(false);
|
||||
|
||||
const newlyUploaded = alteration?.newly_uploaded ?? 0;
|
||||
const removed = alteration?.removed ?? 0;
|
||||
const hasChanges = newlyUploaded > 0 || removed > 0;
|
||||
|
||||
useEffect(() => {
|
||||
if (structureStatus === GenerateStatus.completed) {
|
||||
if (structureStatus === GenerateStatus.Completed) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: DatasetStructureKeys.kind(knowledgeBaseId, kind),
|
||||
});
|
||||
@@ -105,6 +119,14 @@ export function DatasetStructureView({ kind }: DatasetStructureViewProps) {
|
||||
}
|
||||
}, [deleteDatasetStructure, kind]);
|
||||
|
||||
const handleUpdateClick = useCallback(async () => {
|
||||
setUpdateSheetOpen(true);
|
||||
if (structureStatus === GenerateStatus.Running) {
|
||||
return;
|
||||
}
|
||||
await runGenerate({ type: generateType }).catch(() => {});
|
||||
}, [structureStatus, runGenerate, generateType]);
|
||||
|
||||
const canGenerate = (knowledgeBase?.chunk_count ?? 0) > 0;
|
||||
|
||||
if (loading && !data) {
|
||||
@@ -124,16 +146,32 @@ export function DatasetStructureView({ kind }: DatasetStructureViewProps) {
|
||||
return (
|
||||
<Card className="flex-1 min-h-0 overflow-hidden flex border-border-button rounded-xl flex-col">
|
||||
<div className="flex justify-between gap-4 px-4 pt-4">
|
||||
<ConfirmDeleteDialog
|
||||
title={t('knowledgeDetails.deleteStructureConfirm', {
|
||||
name: t(ViewModeLabelKeyMap[kind]),
|
||||
})}
|
||||
onOk={handleDeleteStructure}
|
||||
>
|
||||
<Button variant="outline" size="sm" disabled={deleting}>
|
||||
<Trash2 />
|
||||
</Button>
|
||||
</ConfirmDeleteDialog>
|
||||
<div className="flex items-center gap-2">
|
||||
<ConfirmDeleteDialog
|
||||
title={t('knowledgeDetails.deleteStructureConfirm', {
|
||||
name: t(ViewModeLabelKeyMap[kind]),
|
||||
})}
|
||||
onOk={handleDeleteStructure}
|
||||
>
|
||||
<Button variant="outline" size="sm" disabled={deleting}>
|
||||
<Trash2 />
|
||||
</Button>
|
||||
</ConfirmDeleteDialog>
|
||||
<CompilationUpdateButton
|
||||
traceData={structureRunData}
|
||||
generateType={generateType}
|
||||
hasChanges={hasChanges}
|
||||
newlyUploaded={newlyUploaded}
|
||||
removed={removed}
|
||||
loading={alterationLoading || runLoading}
|
||||
tooltip={t('knowledgeDetails.updateStructureTooltip', {
|
||||
newlyUploaded,
|
||||
removed,
|
||||
name: t(ViewModeLabelKeyMap[kind]),
|
||||
})}
|
||||
onClick={handleUpdateClick}
|
||||
/>
|
||||
</div>
|
||||
{kind === ViewMode.Graph && (
|
||||
<SelectWithSearch
|
||||
options={entityOptions}
|
||||
@@ -151,6 +189,14 @@ export function DatasetStructureView({ kind }: DatasetStructureViewProps) {
|
||||
template={template}
|
||||
highlightNodeId={selectedEntityName || null}
|
||||
/>
|
||||
<UpdateLogSheet
|
||||
open={updateSheetOpen}
|
||||
onOpenChange={setUpdateSheetOpen}
|
||||
data={structureRunData}
|
||||
title={t('knowledgeDetails.updateStructureSheetTitle', {
|
||||
name: t(ViewModeLabelKeyMap[kind]),
|
||||
})}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
ITraceInfo,
|
||||
useDatasetGenerate,
|
||||
} from '@/pages/dataset/dataset/generate-button/hook';
|
||||
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
|
||||
useGenerateStatus,
|
||||
} from '@/hooks/use-dataset-generate';
|
||||
|
||||
import {
|
||||
GenerableViewMode,
|
||||
|
||||
@@ -4,18 +4,17 @@ import {
|
||||
ResizablePanel,
|
||||
ResizablePanelGroup,
|
||||
} from '@/components/ui/resizable';
|
||||
import { GenerateStatus, GenerateType } from '@/constants/knowledge';
|
||||
import {
|
||||
useGenerateStatus,
|
||||
useTraceRunData,
|
||||
} from '@/hooks/use-dataset-generate';
|
||||
import {
|
||||
ArtifactKeys,
|
||||
ArtifactTopicKeys,
|
||||
useFetchArtifactTopicList,
|
||||
useFetchKnowledgeBaseConfiguration,
|
||||
} from '@/hooks/use-knowledge-request';
|
||||
import {
|
||||
GenerateStatus,
|
||||
GenerateType,
|
||||
} from '@/pages/dataset/dataset/generate-button/constants';
|
||||
import { useTraceRunData } from '@/pages/dataset/dataset/generate-button/hook';
|
||||
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useParams } from 'react-router';
|
||||
@@ -46,7 +45,7 @@ export function LlmWikiView() {
|
||||
const [updateSheetOpen, setUpdateSheetOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (artifactStatus === GenerateStatus.completed) {
|
||||
if (artifactStatus === GenerateStatus.Completed) {
|
||||
setUpdateSheetOpen(false);
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ArtifactKeys.listByDataset(id!),
|
||||
|
||||
@@ -5,14 +5,13 @@ import {
|
||||
ResizablePanel,
|
||||
ResizablePanelGroup,
|
||||
} from '@/components/ui/resizable';
|
||||
import { GenerateStatus, GenerateType } from '@/constants/knowledge';
|
||||
import {
|
||||
useGenerateStatus,
|
||||
useTraceRunData,
|
||||
} from '@/hooks/use-dataset-generate';
|
||||
import { DatasetSkillKeys } from '@/hooks/use-dataset-skill-request';
|
||||
import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request';
|
||||
import {
|
||||
GenerateStatus,
|
||||
GenerateType,
|
||||
} from '@/pages/dataset/dataset/generate-button/constants';
|
||||
import { useTraceRunData } from '@/pages/dataset/dataset/generate-button/hook';
|
||||
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useEffect } from 'react';
|
||||
import { useParams } from 'react-router';
|
||||
@@ -39,7 +38,7 @@ export function SkillsView() {
|
||||
const { status: skillStatus } = useGenerateStatus(skillRunData);
|
||||
|
||||
useEffect(() => {
|
||||
if (skillStatus === GenerateStatus.completed) {
|
||||
if (skillStatus === GenerateStatus.Completed) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: DatasetSkillKeys.tree(id!),
|
||||
});
|
||||
|
||||
88
web/src/pages/dataset/compilation/update-button.tsx
Normal file
88
web/src/pages/dataset/compilation/update-button.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import { WandSparkles } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from '@/components/ui/tooltip';
|
||||
import { GenerateStatus, GenerateType } from '@/constants/knowledge';
|
||||
import {
|
||||
ITraceInfo,
|
||||
useGenerateStatus,
|
||||
} from '@/hooks/use-dataset-generate';
|
||||
|
||||
import { UpdateRunProgress } from './update-run-progress';
|
||||
|
||||
type CompilationUpdateButtonProps = {
|
||||
traceData?: ITraceInfo;
|
||||
generateType: GenerateType;
|
||||
hasChanges: boolean;
|
||||
newlyUploaded: number;
|
||||
removed: number;
|
||||
loading: boolean;
|
||||
tooltip: string;
|
||||
onClick: () => void;
|
||||
};
|
||||
|
||||
export function CompilationUpdateButton({
|
||||
traceData,
|
||||
generateType,
|
||||
hasChanges,
|
||||
newlyUploaded,
|
||||
removed,
|
||||
loading,
|
||||
tooltip,
|
||||
onClick,
|
||||
}: CompilationUpdateButtonProps) {
|
||||
const { t } = useTranslation();
|
||||
const { status } = useGenerateStatus(traceData);
|
||||
const isRunning = status === GenerateStatus.Running;
|
||||
const isGenerating = isRunning || status === GenerateStatus.Failed;
|
||||
|
||||
// A failed trace persists (progress stays < 0) until the next run, so it
|
||||
// must not keep the button visible on its own — only real changes or a
|
||||
// live run should.
|
||||
if (!hasChanges && !isRunning) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant={'outline'} onClick={onClick} disabled={loading}>
|
||||
{isGenerating ? (
|
||||
<UpdateRunProgress data={traceData} generateType={generateType} />
|
||||
) : (
|
||||
<>
|
||||
{t('knowledgeDetails.update', { defaultValue: 'Update' })}
|
||||
{newlyUploaded > 0 && (
|
||||
<Badge variant="success" className="ml-1">
|
||||
{newlyUploaded}
|
||||
</Badge>
|
||||
)}
|
||||
{removed > 0 && (
|
||||
<Badge variant="destructive" className="ml-1">
|
||||
{removed}
|
||||
</Badge>
|
||||
)}
|
||||
<WandSparkles />
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{isGenerating
|
||||
? t('knowledgeDetails.viewUpdateLogs', {
|
||||
defaultValue: 'View update logs',
|
||||
})
|
||||
: tooltip}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import {
|
||||
Sheet,
|
||||
@@ -7,28 +6,28 @@ import {
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
} from '@/components/ui/sheet';
|
||||
import { GenerateStatus } from '@/pages/dataset/dataset/generate-button/constants';
|
||||
import { ITraceInfo } from '@/pages/dataset/dataset/generate-button/hook';
|
||||
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
|
||||
import { GenerateStatus } from '@/constants/knowledge';
|
||||
import { ITraceInfo, useGenerateStatus } from '@/hooks/use-dataset-generate';
|
||||
|
||||
import { ProgressLogPanel } from '../progress-log-panel';
|
||||
import { ProgressLogPanel } from './progress-log-panel';
|
||||
|
||||
type WikiUpdateSheetProps = {
|
||||
type UpdateLogSheetProps = {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
data?: ITraceInfo;
|
||||
title: string;
|
||||
};
|
||||
|
||||
export function WikiUpdateSheet({
|
||||
export function UpdateLogSheet({
|
||||
open,
|
||||
onOpenChange,
|
||||
data,
|
||||
}: WikiUpdateSheetProps) {
|
||||
const { t } = useTranslation();
|
||||
title,
|
||||
}: UpdateLogSheetProps) {
|
||||
const { status } = useGenerateStatus(data);
|
||||
|
||||
useEffect(() => {
|
||||
if (status === GenerateStatus.completed) {
|
||||
if (status === GenerateStatus.Completed) {
|
||||
onOpenChange(false);
|
||||
}
|
||||
}, [status, onOpenChange]);
|
||||
@@ -37,11 +36,7 @@ export function WikiUpdateSheet({
|
||||
<Sheet open={open} onOpenChange={onOpenChange} modal={false}>
|
||||
<SheetContent className="flex flex-col">
|
||||
<SheetHeader>
|
||||
<SheetTitle>
|
||||
{t('knowledgeDetails.updateSheetTitle', {
|
||||
defaultValue: 'Update Wiki',
|
||||
})}
|
||||
</SheetTitle>
|
||||
<SheetTitle>{title}</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className="flex-1 min-h-0 flex flex-col pt-4">
|
||||
<ProgressLogPanel
|
||||
@@ -2,20 +2,24 @@ import { CircleX } from 'lucide-react';
|
||||
import { useCallback, type MouseEvent } from 'react';
|
||||
|
||||
import { IconFontFill } from '@/components/icon-font';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { GenerateType } from '@/pages/dataset/dataset/generate-button/constants';
|
||||
import { GenerateType } from '@/constants/knowledge';
|
||||
import {
|
||||
ITraceInfo,
|
||||
useDatasetGenerate,
|
||||
} from '@/pages/dataset/dataset/generate-button/hook';
|
||||
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
|
||||
useGenerateStatus,
|
||||
} from '@/hooks/use-dataset-generate';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { toFixed } from '@/utils/common-util';
|
||||
|
||||
type WikiUpdateProgressProps = {
|
||||
type UpdateRunProgressProps = {
|
||||
data?: ITraceInfo;
|
||||
generateType: GenerateType;
|
||||
};
|
||||
|
||||
export function WikiUpdateProgress({ data }: WikiUpdateProgressProps) {
|
||||
export function UpdateRunProgress({
|
||||
data,
|
||||
generateType,
|
||||
}: UpdateRunProgressProps) {
|
||||
const { pauseGenerate } = useDatasetGenerate();
|
||||
const { status, percent } = useGenerateStatus(data);
|
||||
|
||||
@@ -23,12 +27,10 @@ export function WikiUpdateProgress({ data }: WikiUpdateProgressProps) {
|
||||
(e: MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
if (data?.id) {
|
||||
pauseGenerate({ task_id: data.id, type: GenerateType.Artifact }).catch(
|
||||
() => {},
|
||||
);
|
||||
pauseGenerate({ task_id: data.id, type: generateType }).catch(() => {});
|
||||
}
|
||||
},
|
||||
[pauseGenerate, data?.id],
|
||||
[pauseGenerate, data?.id, generateType],
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -9,8 +9,8 @@ type UseWikiUpdateOptions = {
|
||||
};
|
||||
|
||||
export function useWikiUpdate({ onUpdate }: UseWikiUpdateOptions = {}) {
|
||||
const { data, loading: queryLoading } = useFetchArtifactAlteration();
|
||||
const { runArtifactIndex, loading: mutationLoading } = useRunArtifactIndex();
|
||||
const { data, loading: queryLoading } = useFetchArtifactAlteration('wiki');
|
||||
const { runArtifactIndex, loading: mutationLoading } = useRunArtifactIndex('wiki');
|
||||
|
||||
const newlyUploaded = data?.newly_uploaded ?? 0;
|
||||
const removed = data?.removed ?? 0;
|
||||
|
||||
@@ -1,28 +1,23 @@
|
||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { GenerateStatus, GenerateType } from '@/constants/knowledge';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from '@/components/ui/tooltip';
|
||||
ITraceInfo,
|
||||
useGenerateStatus,
|
||||
} from '@/hooks/use-dataset-generate';
|
||||
import { IArtifact } from '@/interfaces/database/dataset';
|
||||
import { GenerateStatus } from '@/pages/dataset/dataset/generate-button/constants';
|
||||
import { ITraceInfo } from '@/pages/dataset/dataset/generate-button/hook';
|
||||
import { useGenerateStatus } from '@/pages/dataset/dataset/generate-button/use-generate-status';
|
||||
import { Trash2, WandSparkles } from 'lucide-react';
|
||||
import { Trash2 } from 'lucide-react';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { LeftPanelTab } from '../constants';
|
||||
import { CompilationUpdateButton } from '../update-button';
|
||||
import { UpdateLogSheet } from '../update-log-sheet';
|
||||
import { useWikiClear } from './hooks/use-wiki-clear';
|
||||
import { useWikiUpdate } from './hooks/use-wiki-update';
|
||||
import { WikiGraphPanel } from './wiki-graph-panel';
|
||||
import { WikiNavBar } from './wiki-nav-bar';
|
||||
import { WikiUpdateProgress } from './wiki-update-progress';
|
||||
import { WikiUpdateSheet } from './wiki-update-sheet';
|
||||
|
||||
type WikiLeftPanelProps = {
|
||||
tab: LeftPanelTab;
|
||||
@@ -62,12 +57,10 @@ export function WikiLeftPanel({
|
||||
} = useWikiUpdate();
|
||||
|
||||
const { status } = useGenerateStatus(traceData);
|
||||
const isGenerating =
|
||||
status === GenerateStatus.running || status === GenerateStatus.failed;
|
||||
|
||||
const handleUpdateClick = useCallback(async () => {
|
||||
onUpdateSheetOpenChange(true);
|
||||
if (status === GenerateStatus.running) {
|
||||
if (status === GenerateStatus.Running) {
|
||||
return;
|
||||
}
|
||||
await handleUpdate();
|
||||
@@ -76,50 +69,21 @@ export function WikiLeftPanel({
|
||||
return (
|
||||
<aside className="size-full flex flex-col p-5">
|
||||
<div className="flex items-center justify-between pb-5">
|
||||
{(hasChanges || isGenerating) && (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
onClick={handleUpdateClick}
|
||||
disabled={updateLoading}
|
||||
>
|
||||
{isGenerating ? (
|
||||
<WikiUpdateProgress data={traceData} />
|
||||
) : (
|
||||
<>
|
||||
{t('knowledgeDetails.update', { defaultValue: 'Update' })}
|
||||
{newlyUploaded > 0 && (
|
||||
<Badge variant="success" className="ml-1">
|
||||
{newlyUploaded}
|
||||
</Badge>
|
||||
)}
|
||||
{removed > 0 && (
|
||||
<Badge variant="destructive" className="ml-1">
|
||||
{removed}
|
||||
</Badge>
|
||||
)}
|
||||
<WandSparkles />
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{isGenerating
|
||||
? t('knowledgeDetails.viewUpdateLogs', {
|
||||
defaultValue: 'View update logs',
|
||||
})
|
||||
: t('knowledgeDetails.updateTooltip', {
|
||||
newlyUploaded,
|
||||
removed,
|
||||
defaultValue:
|
||||
'{{newlyUploaded}} new, {{removed}} removed documents found. Click to compile and merge into current Wiki.',
|
||||
})}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
)}
|
||||
<CompilationUpdateButton
|
||||
traceData={traceData}
|
||||
generateType={GenerateType.Artifact}
|
||||
hasChanges={hasChanges}
|
||||
newlyUploaded={newlyUploaded}
|
||||
removed={removed}
|
||||
loading={updateLoading}
|
||||
tooltip={t('knowledgeDetails.updateTooltip', {
|
||||
newlyUploaded,
|
||||
removed,
|
||||
defaultValue:
|
||||
'{{newlyUploaded}} new, {{removed}} removed documents found. Click to compile and merge into current Wiki.',
|
||||
})}
|
||||
onClick={handleUpdateClick}
|
||||
/>
|
||||
<ConfirmDeleteDialog
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
@@ -164,10 +128,13 @@ export function WikiLeftPanel({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<WikiUpdateSheet
|
||||
<UpdateLogSheet
|
||||
open={updateSheetOpen}
|
||||
onOpenChange={onUpdateSheetOpenChange}
|
||||
data={traceData}
|
||||
title={t('knowledgeDetails.updateSheetTitle', {
|
||||
defaultValue: 'Update Wiki',
|
||||
})}
|
||||
/>
|
||||
</aside>
|
||||
);
|
||||
|
||||
@@ -2,26 +2,3 @@ export enum LogTabs {
|
||||
FILE_LOGS = 'fileLogs',
|
||||
DATASET_LOGS = 'datasetLogs',
|
||||
}
|
||||
|
||||
export enum ProcessingType {
|
||||
knowledgeGraph = 'Graph',
|
||||
raptor = 'RAPTOR',
|
||||
artifact = 'Artifact',
|
||||
skill = 'Skill',
|
||||
mindmap = 'Mindmap',
|
||||
timeline = 'Timeline',
|
||||
sessionEssence = 'Session_Essence',
|
||||
sessionGraph = 'Session_Graph',
|
||||
}
|
||||
|
||||
export const ProcessingTypeMap = {
|
||||
[ProcessingType.knowledgeGraph]: 'Knowledge Graph',
|
||||
[ProcessingType.raptor]: 'RAPTOR',
|
||||
[ProcessingType.artifact]: 'Artifact',
|
||||
[ProcessingType.skill]: 'Skill',
|
||||
[ProcessingType.mindmap]: 'Mind Map',
|
||||
[ProcessingType.timeline]: 'Timeline',
|
||||
[ProcessingType.sessionEssence]: 'Session Essence',
|
||||
[ProcessingType.sessionGraph]: 'Session Graph',
|
||||
GraphRAG: 'Knowledge Graph',
|
||||
};
|
||||
|
||||
@@ -18,7 +18,11 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from '@/components/ui/tooltip';
|
||||
import { RunningStatusMap } from '@/constants/knowledge';
|
||||
import {
|
||||
ProcessingType,
|
||||
ProcessingTypeMap,
|
||||
RunningStatusMap,
|
||||
} from '@/constants/knowledge';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -45,7 +49,7 @@ import { FC, useMemo, useState } from 'react';
|
||||
import { useParams } from 'react-router';
|
||||
import { RunningStatus } from '../dataset/constant';
|
||||
import ProcessLogModal, { ILogInfo } from '../process-log-modal';
|
||||
import { LogTabs, ProcessingType, ProcessingTypeMap } from './dataset-common';
|
||||
import { LogTabs } from './dataset-common';
|
||||
import { DocumentLog, FileLogsTableProps, IFileLogItem } from './interface';
|
||||
|
||||
export const getFileLogsTableColumns = (
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { ProcessingType } from '../../dataset-overview/dataset-common';
|
||||
|
||||
export const GenerateStatus = {
|
||||
running: 'running',
|
||||
completed: 'completed',
|
||||
start: 'start',
|
||||
failed: 'failed',
|
||||
};
|
||||
|
||||
export enum GenerateType {
|
||||
KnowledgeGraph = 'KnowledgeGraph',
|
||||
Raptor = 'Raptor',
|
||||
Artifact = 'Artifact',
|
||||
ToSkills = 'ToSkills',
|
||||
MindMap = 'MindMap',
|
||||
Timeline = 'Timeline',
|
||||
SessionEssence = 'SessionEssence',
|
||||
SessionGraph = 'SessionGraph',
|
||||
}
|
||||
|
||||
export enum TraceType {
|
||||
Graph = 'graph',
|
||||
Raptor = 'raptor',
|
||||
Artifact = 'artifact',
|
||||
Skill = 'skill',
|
||||
MindMap = 'mindmap',
|
||||
Timeline = 'timeline',
|
||||
SessionEssence = 'session_essence',
|
||||
SessionGraph = 'session_graph',
|
||||
}
|
||||
|
||||
export const GenerateTypeMap = {
|
||||
[GenerateType.KnowledgeGraph]: ProcessingType.knowledgeGraph,
|
||||
[GenerateType.Raptor]: ProcessingType.raptor,
|
||||
[GenerateType.Artifact]: ProcessingType.artifact,
|
||||
[GenerateType.ToSkills]: ProcessingType.skill,
|
||||
[GenerateType.MindMap]: ProcessingType.mindmap,
|
||||
[GenerateType.Timeline]: ProcessingType.timeline,
|
||||
[GenerateType.SessionEssence]: ProcessingType.sessionEssence,
|
||||
[GenerateType.SessionGraph]: ProcessingType.sessionGraph,
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { GenerateStatus } from './constants';
|
||||
import { ITraceInfo } from './hook';
|
||||
|
||||
export function useGenerateStatus(data?: ITraceInfo) {
|
||||
const status = useMemo(() => {
|
||||
if (!data) {
|
||||
return GenerateStatus.start;
|
||||
}
|
||||
if (data.progress >= 1) {
|
||||
return GenerateStatus.completed;
|
||||
} else if (!data.progress && data.progress !== 0) {
|
||||
return GenerateStatus.start;
|
||||
} else if (data.progress < 0) {
|
||||
return GenerateStatus.failed;
|
||||
} else if (data.progress < 1) {
|
||||
return GenerateStatus.running;
|
||||
}
|
||||
return GenerateStatus.start;
|
||||
}, [data]);
|
||||
|
||||
const percent = useMemo(() => {
|
||||
if (status === GenerateStatus.failed) {
|
||||
return 100;
|
||||
} else if (status === GenerateStatus.running) {
|
||||
return data!.progress * 100;
|
||||
}
|
||||
return 0;
|
||||
}, [status, data]);
|
||||
|
||||
return { status, percent };
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ProcessingType } from '@/constants/knowledge';
|
||||
import { IRenameTag } from '@/interfaces/database/dataset';
|
||||
import {
|
||||
IFetchArtifactGraphRequestParams,
|
||||
@@ -7,7 +8,6 @@ import {
|
||||
IFetchKnowledgeListRequestParams,
|
||||
IUpdateArtifactPageRequestBody,
|
||||
} from '@/interfaces/request/knowledge';
|
||||
import { ProcessingType } from '@/pages/dataset/dataset-overview/dataset-common';
|
||||
import api from '@/utils/api';
|
||||
import nextRequest from '@/utils/next-request';
|
||||
import registerServer from '@/utils/register-server';
|
||||
@@ -419,8 +419,8 @@ export const getArtifactGraph = (
|
||||
params?: IFetchArtifactGraphRequestParams,
|
||||
) => request.get(api.getArtifactGraph(datasetId), { params });
|
||||
|
||||
export const getArtifactsAlteration = (datasetId: string) =>
|
||||
request.get(api.artifactsAlteration(datasetId));
|
||||
export const getArtifactsAlteration = (datasetId: string, kind: string) =>
|
||||
request.get(api.artifactsAlteration(datasetId), { params: { kind } });
|
||||
|
||||
export const getArtifactsStructure = (
|
||||
datasetId: string,
|
||||
|
||||
Reference in New Issue
Block a user