mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Import dsl from agent list page #9869 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -24,9 +24,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|||||||
import { useDebounce } from 'ahooks';
|
import { useDebounce } from 'ahooks';
|
||||||
import { get, set } from 'lodash';
|
import { get, set } from 'lodash';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useParams, useSearchParams } from 'umi';
|
import { useParams, useSearchParams } from 'umi';
|
||||||
import { v4 as uuid } from 'uuid';
|
|
||||||
import {
|
import {
|
||||||
useGetPaginationWithRouter,
|
useGetPaginationWithRouter,
|
||||||
useHandleSearchChange,
|
useHandleSearchChange,
|
||||||
@ -80,7 +78,7 @@ export const EmptyDsl = {
|
|||||||
component_name: 'Begin',
|
component_name: 'Begin',
|
||||||
params: {},
|
params: {},
|
||||||
},
|
},
|
||||||
downstream: ['Answer:China'], // other edge target is downstream, edge source is current node id
|
downstream: [], // other edge target is downstream, edge source is current node id
|
||||||
upstream: [], // edge source is upstream, edge target is current node id
|
upstream: [], // edge source is upstream, edge target is current node id
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -96,21 +94,11 @@ export const EmptyDsl = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useFetchAgentTemplates = () => {
|
export const useFetchAgentTemplates = () => {
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const { data } = useQuery<IFlowTemplate[]>({
|
const { data } = useQuery<IFlowTemplate[]>({
|
||||||
queryKey: [AgentApiAction.FetchAgentTemplates],
|
queryKey: [AgentApiAction.FetchAgentTemplates],
|
||||||
initialData: [],
|
initialData: [],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await agentService.listTemplates();
|
const { data } = await agentService.listTemplates();
|
||||||
if (Array.isArray(data?.data)) {
|
|
||||||
data.data.unshift({
|
|
||||||
id: uuid(),
|
|
||||||
title: t('flow.blank'),
|
|
||||||
description: t('flow.createFromNothing'),
|
|
||||||
dsl: EmptyDsl,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return data.data;
|
return data.data;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -41,8 +41,8 @@ export interface DSL {
|
|||||||
path?: string[];
|
path?: string[];
|
||||||
answer?: any[];
|
answer?: any[];
|
||||||
graph?: IGraph;
|
graph?: IGraph;
|
||||||
messages: Message[];
|
messages?: Message[];
|
||||||
reference: IReference[];
|
reference?: IReference[];
|
||||||
globals: Record<string, any>;
|
globals: Record<string, any>;
|
||||||
retrieval: IReference[];
|
retrieval: IReference[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,71 +1,17 @@
|
|||||||
import { useToast } from '@/components/hooks/use-toast';
|
|
||||||
import { FileMimeType, Platform } from '@/constants/common';
|
|
||||||
import { useSetModalState } from '@/hooks/common-hooks';
|
|
||||||
import { useFetchAgent } from '@/hooks/use-agent-request';
|
import { useFetchAgent } from '@/hooks/use-agent-request';
|
||||||
import { IGraph } from '@/interfaces/database/flow';
|
|
||||||
import { downloadJsonFile } from '@/utils/file-util';
|
import { downloadJsonFile } from '@/utils/file-util';
|
||||||
import { message } from 'antd';
|
|
||||||
import isEmpty from 'lodash/isEmpty';
|
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useBuildDslData } from './use-build-dsl';
|
import { useBuildDslData } from './use-build-dsl';
|
||||||
import { useSetGraphInfo } from './use-set-graph';
|
|
||||||
|
|
||||||
export const useHandleExportOrImportJsonFile = () => {
|
export const useHandleExportJsonFile = () => {
|
||||||
const { buildDslData } = useBuildDslData();
|
const { buildDslData } = useBuildDslData();
|
||||||
const {
|
|
||||||
visible: fileUploadVisible,
|
|
||||||
hideModal: hideFileUploadModal,
|
|
||||||
showModal: showFileUploadModal,
|
|
||||||
} = useSetModalState();
|
|
||||||
const setGraphInfo = useSetGraphInfo();
|
|
||||||
const { data } = useFetchAgent();
|
const { data } = useFetchAgent();
|
||||||
const { t } = useTranslation();
|
|
||||||
const { toast } = useToast();
|
|
||||||
|
|
||||||
const onFileUploadOk = useCallback(
|
|
||||||
async ({
|
|
||||||
fileList,
|
|
||||||
platform,
|
|
||||||
}: {
|
|
||||||
fileList: File[];
|
|
||||||
platform: Platform;
|
|
||||||
}) => {
|
|
||||||
console.log('🚀 ~ useHandleExportOrImportJsonFile ~ platform:', platform);
|
|
||||||
if (fileList.length > 0) {
|
|
||||||
const file = fileList[0];
|
|
||||||
if (file.type !== FileMimeType.Json) {
|
|
||||||
toast({ title: t('flow.jsonUploadTypeErrorMessage') });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const graphStr = await file.text();
|
|
||||||
const errorMessage = t('flow.jsonUploadContentErrorMessage');
|
|
||||||
try {
|
|
||||||
const graph = JSON.parse(graphStr);
|
|
||||||
if (graphStr && !isEmpty(graph) && Array.isArray(graph?.nodes)) {
|
|
||||||
setGraphInfo(graph ?? ({} as IGraph));
|
|
||||||
hideFileUploadModal();
|
|
||||||
} else {
|
|
||||||
message.error(errorMessage);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
message.error(errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[hideFileUploadModal, setGraphInfo, t, toast],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleExportJson = useCallback(() => {
|
const handleExportJson = useCallback(() => {
|
||||||
downloadJsonFile(buildDslData().graph, `${data.title}.json`);
|
downloadJsonFile(buildDslData().graph, `${data.title}.json`);
|
||||||
}, [buildDslData, data.title]);
|
}, [buildDslData, data.title]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fileUploadVisible,
|
|
||||||
handleExportJson,
|
handleExportJson,
|
||||||
handleImportJson: showFileUploadModal,
|
|
||||||
hideFileUploadModal,
|
|
||||||
onFileUploadOk,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -24,7 +24,6 @@ import { ReactFlowProvider } from '@xyflow/react';
|
|||||||
import {
|
import {
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
CirclePlay,
|
CirclePlay,
|
||||||
Download,
|
|
||||||
History,
|
History,
|
||||||
LaptopMinimalCheck,
|
LaptopMinimalCheck,
|
||||||
Logs,
|
Logs,
|
||||||
@ -37,7 +36,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { useParams } from 'umi';
|
import { useParams } from 'umi';
|
||||||
import AgentCanvas from './canvas';
|
import AgentCanvas from './canvas';
|
||||||
import { DropdownProvider } from './canvas/context';
|
import { DropdownProvider } from './canvas/context';
|
||||||
import { useHandleExportOrImportJsonFile } from './hooks/use-export-json';
|
import { useHandleExportJsonFile } from './hooks/use-export-json';
|
||||||
import { useFetchDataOnMount } from './hooks/use-fetch-data';
|
import { useFetchDataOnMount } from './hooks/use-fetch-data';
|
||||||
import { useGetBeginNodeDataInputs } from './hooks/use-get-begin-query';
|
import { useGetBeginNodeDataInputs } from './hooks/use-get-begin-query';
|
||||||
import {
|
import {
|
||||||
@ -46,7 +45,6 @@ import {
|
|||||||
useWatchAgentChange,
|
useWatchAgentChange,
|
||||||
} from './hooks/use-save-graph';
|
} from './hooks/use-save-graph';
|
||||||
import { SettingDialog } from './setting-dialog';
|
import { SettingDialog } from './setting-dialog';
|
||||||
import { UploadAgentDialog } from './upload-agent-dialog';
|
|
||||||
import { useAgentHistoryManager } from './use-agent-history-manager';
|
import { useAgentHistoryManager } from './use-agent-history-manager';
|
||||||
import { VersionDialog } from './version-dialog';
|
import { VersionDialog } from './version-dialog';
|
||||||
|
|
||||||
@ -71,13 +69,8 @@ export default function Agent() {
|
|||||||
} = useSetModalState();
|
} = useSetModalState();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
useAgentHistoryManager();
|
useAgentHistoryManager();
|
||||||
const {
|
|
||||||
handleExportJson,
|
const { handleExportJson } = useHandleExportJsonFile();
|
||||||
handleImportJson,
|
|
||||||
fileUploadVisible,
|
|
||||||
onFileUploadOk,
|
|
||||||
hideFileUploadModal,
|
|
||||||
} = useHandleExportOrImportJsonFile();
|
|
||||||
const { saveGraph, loading } = useSaveGraph();
|
const { saveGraph, loading } = useSaveGraph();
|
||||||
const { flowDetail: agentDetail } = useFetchDataOnMount();
|
const { flowDetail: agentDetail } = useFetchDataOnMount();
|
||||||
const inputs = useGetBeginNodeDataInputs();
|
const inputs = useGetBeginNodeDataInputs();
|
||||||
@ -158,11 +151,6 @@ export default function Agent() {
|
|||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent>
|
<DropdownMenuContent>
|
||||||
<AgentDropdownMenuItem onClick={handleImportJson}>
|
|
||||||
<Download />
|
|
||||||
{t('flow.import')}
|
|
||||||
</AgentDropdownMenuItem>
|
|
||||||
<DropdownMenuSeparator />
|
|
||||||
<AgentDropdownMenuItem onClick={handleExportJson}>
|
<AgentDropdownMenuItem onClick={handleExportJson}>
|
||||||
<Upload />
|
<Upload />
|
||||||
{t('flow.export')}
|
{t('flow.export')}
|
||||||
@ -193,12 +181,6 @@ export default function Agent() {
|
|||||||
></AgentCanvas>
|
></AgentCanvas>
|
||||||
</DropdownProvider>
|
</DropdownProvider>
|
||||||
</ReactFlowProvider>
|
</ReactFlowProvider>
|
||||||
{fileUploadVisible && (
|
|
||||||
<UploadAgentDialog
|
|
||||||
hideModal={hideFileUploadModal}
|
|
||||||
onOk={onFileUploadOk}
|
|
||||||
></UploadAgentDialog>
|
|
||||||
)}
|
|
||||||
{embedVisible && (
|
{embedVisible && (
|
||||||
<EmbedDialog
|
<EmbedDialog
|
||||||
visible={embedVisible}
|
visible={embedVisible}
|
||||||
|
|||||||
@ -112,10 +112,9 @@ export default function AgentTemplates() {
|
|||||||
|
|
||||||
<main className="flex-1 bg-text-title-invert/50 h-dvh">
|
<main className="flex-1 bg-text-title-invert/50 h-dvh">
|
||||||
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 max-h-[94vh] overflow-auto px-8 pt-8">
|
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 max-h-[94vh] overflow-auto px-8 pt-8">
|
||||||
{tempListFilter?.map((x, index) => {
|
{tempListFilter?.map((x) => {
|
||||||
return (
|
return (
|
||||||
<TemplateCard
|
<TemplateCard
|
||||||
isCreate={index === 0}
|
|
||||||
key={x.id}
|
key={x.id}
|
||||||
data={x}
|
data={x}
|
||||||
showModal={showModal}
|
showModal={showModal}
|
||||||
|
|||||||
4
web/src/pages/agents/constant.ts
Normal file
4
web/src/pages/agents/constant.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export enum FlowType {
|
||||||
|
Agent = 'agent',
|
||||||
|
Flow = 'flow',
|
||||||
|
}
|
||||||
@ -6,31 +6,20 @@ import { z } from 'zod';
|
|||||||
|
|
||||||
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
import {
|
import { Form } from '@/components/ui/form';
|
||||||
Form,
|
|
||||||
FormControl,
|
|
||||||
FormField,
|
|
||||||
FormItem,
|
|
||||||
FormLabel,
|
|
||||||
FormMessage,
|
|
||||||
} from '@/components/ui/form';
|
|
||||||
import { Input } from '@/components/ui/input';
|
|
||||||
import { IModalProps } from '@/interfaces/common';
|
import { IModalProps } from '@/interfaces/common';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { TagRenameId } from '@/pages/add-knowledge/constant';
|
import { TagRenameId } from '@/pages/add-knowledge/constant';
|
||||||
import { BrainCircuit, Check, Route } from 'lucide-react';
|
import { BrainCircuit, Check, Route } from 'lucide-react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { FlowType } from './constant';
|
||||||
|
import { NameFormField, NameFormSchema } from './name-form-field';
|
||||||
|
|
||||||
export type CreateAgentFormProps = IModalProps<any> & {
|
export type CreateAgentFormProps = IModalProps<any> & {
|
||||||
shouldChooseAgent?: boolean;
|
shouldChooseAgent?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FlowType {
|
|
||||||
Agent = 'agent',
|
|
||||||
Flow = 'flow',
|
|
||||||
}
|
|
||||||
|
|
||||||
type FlowTypeCardProps = {
|
type FlowTypeCardProps = {
|
||||||
value?: FlowType;
|
value?: FlowType;
|
||||||
onChange?: (value: FlowType) => void;
|
onChange?: (value: FlowType) => void;
|
||||||
@ -51,7 +40,7 @@ function FlowTypeCards({ value, onChange }: FlowTypeCardProps) {
|
|||||||
<Card
|
<Card
|
||||||
key={val}
|
key={val}
|
||||||
className={cn('flex-1 rounded-lg border bg-transparent', {
|
className={cn('flex-1 rounded-lg border bg-transparent', {
|
||||||
'border-bg-base': isActive,
|
'border-text-primary': isActive,
|
||||||
'border-border-default': !isActive,
|
'border-border-default': !isActive,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
@ -81,30 +70,28 @@ function FlowTypeCards({ value, onChange }: FlowTypeCardProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const FormSchema = z.object({
|
||||||
|
...NameFormSchema,
|
||||||
|
tag: z.string().trim().optional(),
|
||||||
|
description: z.string().trim().optional(),
|
||||||
|
type: z.nativeEnum(FlowType).optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type FormSchemaType = z.infer<typeof FormSchema>;
|
||||||
|
|
||||||
export function CreateAgentForm({
|
export function CreateAgentForm({
|
||||||
hideModal,
|
hideModal,
|
||||||
onOk,
|
onOk,
|
||||||
shouldChooseAgent = false,
|
shouldChooseAgent = false,
|
||||||
}: CreateAgentFormProps) {
|
}: CreateAgentFormProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const FormSchema = z.object({
|
|
||||||
name: z
|
|
||||||
.string()
|
|
||||||
.min(1, {
|
|
||||||
message: t('common.namePlaceholder'),
|
|
||||||
})
|
|
||||||
.trim(),
|
|
||||||
tag: z.string().trim().optional(),
|
|
||||||
description: z.string().trim().optional(),
|
|
||||||
type: z.nativeEnum(FlowType).optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof FormSchema>>({
|
const form = useForm<FormSchemaType>({
|
||||||
resolver: zodResolver(FormSchema),
|
resolver: zodResolver(FormSchema),
|
||||||
defaultValues: { name: '', type: FlowType.Agent },
|
defaultValues: { name: '', type: FlowType.Agent },
|
||||||
});
|
});
|
||||||
|
|
||||||
async function onSubmit(data: z.infer<typeof FormSchema>) {
|
async function onSubmit(data: FormSchemaType) {
|
||||||
const ret = await onOk?.(data);
|
const ret = await onOk?.(data);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
hideModal?.();
|
hideModal?.();
|
||||||
@ -123,23 +110,7 @@ export function CreateAgentForm({
|
|||||||
<FlowTypeCards></FlowTypeCards>
|
<FlowTypeCards></FlowTypeCards>
|
||||||
</RAGFlowFormItem>
|
</RAGFlowFormItem>
|
||||||
)}
|
)}
|
||||||
<FormField
|
<NameFormField></NameFormField>
|
||||||
control={form.control}
|
|
||||||
name="name"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel required>{t('common.name')}</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input
|
|
||||||
placeholder={t('common.namePlaceholder')}
|
|
||||||
{...field}
|
|
||||||
autoComplete="off"
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|||||||
42
web/src/pages/agents/hooks/use-create-agent.ts
Normal file
42
web/src/pages/agents/hooks/use-create-agent.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { useSetModalState } from '@/hooks/common-hooks';
|
||||||
|
import { EmptyDsl, useSetAgent } from '@/hooks/use-agent-request';
|
||||||
|
import { DSL } from '@/interfaces/database/agent';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { FlowType } from '../constant';
|
||||||
|
import { FormSchemaType } from '../create-agent-form';
|
||||||
|
|
||||||
|
export function useCreateAgentOrPipeline() {
|
||||||
|
const { loading, setAgent } = useSetAgent();
|
||||||
|
const {
|
||||||
|
visible: creatingVisible,
|
||||||
|
hideModal: hideCreatingModal,
|
||||||
|
showModal: showCreatingModal,
|
||||||
|
} = useSetModalState();
|
||||||
|
|
||||||
|
const createAgent = useCallback(
|
||||||
|
async (name: string) => {
|
||||||
|
return setAgent({ title: name, dsl: EmptyDsl as DSL });
|
||||||
|
},
|
||||||
|
[setAgent],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleCreateAgentOrPipeline = useCallback(
|
||||||
|
async (data: FormSchemaType) => {
|
||||||
|
if (data.type === FlowType.Agent) {
|
||||||
|
const ret = await createAgent(data.name);
|
||||||
|
if (ret.code === 0) {
|
||||||
|
hideCreatingModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[createAgent, hideCreatingModal],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading,
|
||||||
|
creatingVisible,
|
||||||
|
hideCreatingModal,
|
||||||
|
showCreatingModal,
|
||||||
|
handleCreateAgentOrPipeline,
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -8,7 +8,6 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '@/components/ui/dropdown-menu';
|
} from '@/components/ui/dropdown-menu';
|
||||||
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
|
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
|
||||||
import { useSetModalState } from '@/hooks/common-hooks';
|
|
||||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
import { useFetchAgentListByPage } from '@/hooks/use-agent-request';
|
import { useFetchAgentListByPage } from '@/hooks/use-agent-request';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
@ -17,6 +16,9 @@ import { Clipboard, ClipboardPlus, FileInput, Plus } from 'lucide-react';
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { AgentCard } from './agent-card';
|
import { AgentCard } from './agent-card';
|
||||||
import { CreateAgentDialog } from './create-agent-dialog';
|
import { CreateAgentDialog } from './create-agent-dialog';
|
||||||
|
import { useCreateAgentOrPipeline } from './hooks/use-create-agent';
|
||||||
|
import { UploadAgentDialog } from './upload-agent-dialog';
|
||||||
|
import { useHandleImportJsonFile } from './use-import-json';
|
||||||
import { useRenameAgent } from './use-rename-agent';
|
import { useRenameAgent } from './use-rename-agent';
|
||||||
|
|
||||||
export default function Agents() {
|
export default function Agents() {
|
||||||
@ -34,10 +36,19 @@ export default function Agents() {
|
|||||||
} = useRenameAgent();
|
} = useRenameAgent();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
visible: creatingVisible,
|
creatingVisible,
|
||||||
hideModal: hideCreatingModal,
|
hideCreatingModal,
|
||||||
showModal: showCreatingModal,
|
showCreatingModal,
|
||||||
} = useSetModalState();
|
loading,
|
||||||
|
handleCreateAgentOrPipeline,
|
||||||
|
} = useCreateAgentOrPipeline();
|
||||||
|
|
||||||
|
const {
|
||||||
|
handleImportJson,
|
||||||
|
fileUploadVisible,
|
||||||
|
onFileUploadOk,
|
||||||
|
hideFileUploadModal,
|
||||||
|
} = useHandleImportJsonFile();
|
||||||
|
|
||||||
const handlePageChange = useCallback(
|
const handlePageChange = useCallback(
|
||||||
(page: number, pageSize?: number) => {
|
(page: number, pageSize?: number) => {
|
||||||
@ -77,7 +88,10 @@ export default function Agents() {
|
|||||||
<ClipboardPlus />
|
<ClipboardPlus />
|
||||||
Create from Template
|
Create from Template
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem justifyBetween={false}>
|
<DropdownMenuItem
|
||||||
|
justifyBetween={false}
|
||||||
|
onClick={handleImportJson}
|
||||||
|
>
|
||||||
<FileInput />
|
<FileInput />
|
||||||
Import json file
|
Import json file
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
@ -115,13 +129,19 @@ export default function Agents() {
|
|||||||
)}
|
)}
|
||||||
{creatingVisible && (
|
{creatingVisible && (
|
||||||
<CreateAgentDialog
|
<CreateAgentDialog
|
||||||
loading={false}
|
loading={loading}
|
||||||
visible={creatingVisible}
|
visible={creatingVisible}
|
||||||
hideModal={hideCreatingModal}
|
hideModal={hideCreatingModal}
|
||||||
shouldChooseAgent
|
shouldChooseAgent
|
||||||
onOk={() => {}}
|
onOk={handleCreateAgentOrPipeline}
|
||||||
></CreateAgentDialog>
|
></CreateAgentDialog>
|
||||||
)}
|
)}
|
||||||
|
{fileUploadVisible && (
|
||||||
|
<UploadAgentDialog
|
||||||
|
hideModal={hideFileUploadModal}
|
||||||
|
onOk={onFileUploadOk}
|
||||||
|
></UploadAgentDialog>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
28
web/src/pages/agents/name-form-field.tsx
Normal file
28
web/src/pages/agents/name-form-field.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import i18n from '@/locales/config';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export const NameFormSchema = {
|
||||||
|
name: z
|
||||||
|
.string()
|
||||||
|
.min(1, {
|
||||||
|
message: i18n.t('common.namePlaceholder'),
|
||||||
|
})
|
||||||
|
.trim(),
|
||||||
|
};
|
||||||
|
|
||||||
|
export function NameFormField() {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<RAGFlowFormItem
|
||||||
|
name="name"
|
||||||
|
required
|
||||||
|
label={t('common.name')}
|
||||||
|
tooltip={t('flow.sqlStatementTip')}
|
||||||
|
>
|
||||||
|
<Input placeholder={t('common.namePlaceholder')} autoComplete="off" />
|
||||||
|
</RAGFlowFormItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -3,7 +3,6 @@ import { Button } from '@/components/ui/button';
|
|||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
import { IFlowTemplate } from '@/interfaces/database/flow';
|
import { IFlowTemplate } from '@/interfaces/database/flow';
|
||||||
import i18n from '@/locales/config';
|
import i18n from '@/locales/config';
|
||||||
import { Plus } from 'lucide-react';
|
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
interface IProps {
|
interface IProps {
|
||||||
@ -12,7 +11,7 @@ interface IProps {
|
|||||||
showModal(record: IFlowTemplate): void;
|
showModal(record: IFlowTemplate): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TemplateCard({ data, showModal, isCreate = false }: IProps) {
|
export function TemplateCard({ data, showModal }: IProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
@ -26,28 +25,13 @@ export function TemplateCard({ data, showModal, isCreate = false }: IProps) {
|
|||||||
return (
|
return (
|
||||||
<Card className="border-colors-outline-neutral-standard group relative min-h-40">
|
<Card className="border-colors-outline-neutral-standard group relative min-h-40">
|
||||||
<CardContent className="p-4 ">
|
<CardContent className="p-4 ">
|
||||||
{isCreate && (
|
|
||||||
<div
|
|
||||||
className="flex flex-col justify-center items-center gap-4 mb-4 absolute top-0 right-0 left-0 bottom-0 cursor-pointer "
|
|
||||||
onClick={handleClick}
|
|
||||||
>
|
|
||||||
<Plus size={50} fontWeight={700} />
|
|
||||||
<div>{t('flow.createAgent')}</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{!isCreate && (
|
|
||||||
<>
|
|
||||||
<div className="flex justify-start items-center gap-4 mb-4">
|
<div className="flex justify-start items-center gap-4 mb-4">
|
||||||
<RAGFlowAvatar
|
<RAGFlowAvatar
|
||||||
className="w-7 h-7"
|
className="w-7 h-7"
|
||||||
avatar={
|
avatar={data.avatar ? data.avatar : 'https://github.com/shadcn.png'}
|
||||||
data.avatar ? data.avatar : 'https://github.com/shadcn.png'
|
|
||||||
}
|
|
||||||
name={data?.title[language] || 'CN'}
|
name={data?.title[language] || 'CN'}
|
||||||
></RAGFlowAvatar>
|
></RAGFlowAvatar>
|
||||||
<div className="text-[18px] font-bold ">
|
<div className="text-[18px] font-bold ">{data?.title[language]}</div>
|
||||||
{data?.title[language]}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<p className="break-words">{data?.description[language]}</p>
|
<p className="break-words">{data?.description[language]}</p>
|
||||||
<div className="group-hover:bg-gradient-to-t from-black/70 from-10% via-black/0 via-50% to-black/0 w-full h-full group-hover:block absolute top-0 left-0 hidden rounded-xl">
|
<div className="group-hover:bg-gradient-to-t from-black/70 from-10% via-black/0 via-50% to-black/0 w-full h-full group-hover:block absolute top-0 left-0 hidden rounded-xl">
|
||||||
@ -59,8 +43,6 @@ export function TemplateCard({ data, showModal, isCreate = false }: IProps) {
|
|||||||
{t('flow.useTemplate')}
|
{t('flow.useTemplate')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { ButtonLoading } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@ -5,7 +6,6 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from '@/components/ui/dialog';
|
} from '@/components/ui/dialog';
|
||||||
import { LoadingButton } from '@/components/ui/loading-button';
|
|
||||||
import { IModalProps } from '@/interfaces/common';
|
import { IModalProps } from '@/interfaces/common';
|
||||||
import { TagRenameId } from '@/pages/add-knowledge/constant';
|
import { TagRenameId } from '@/pages/add-knowledge/constant';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -26,9 +26,9 @@ export function UploadAgentDialog({
|
|||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<UploadAgentForm hideModal={hideModal} onOk={onOk}></UploadAgentForm>
|
<UploadAgentForm hideModal={hideModal} onOk={onOk}></UploadAgentForm>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<LoadingButton type="submit" form={TagRenameId} loading={loading}>
|
<ButtonLoading type="submit" form={TagRenameId} loading={loading}>
|
||||||
{t('common.save')}
|
{t('common.save')}
|
||||||
</LoadingButton>
|
</ButtonLoading>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@ -13,32 +13,24 @@ import {
|
|||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage,
|
||||||
} from '@/components/ui/form';
|
} from '@/components/ui/form';
|
||||||
import { FileMimeType, Platform } from '@/constants/common';
|
import { FileMimeType } from '@/constants/common';
|
||||||
import { IModalProps } from '@/interfaces/common';
|
import { IModalProps } from '@/interfaces/common';
|
||||||
import { TagRenameId } from '@/pages/add-knowledge/constant';
|
import { TagRenameId } from '@/pages/add-knowledge/constant';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { NameFormField, NameFormSchema } from '../name-form-field';
|
||||||
|
|
||||||
// const options = Object.values(Platform).map((x) => ({ label: x, value: x }));
|
export const FormSchema = z.object({
|
||||||
|
|
||||||
export function UploadAgentForm({ hideModal, onOk }: IModalProps<any>) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const FormSchema = z.object({
|
|
||||||
platform: z
|
|
||||||
.string()
|
|
||||||
.min(1, {
|
|
||||||
message: t('common.namePlaceholder'),
|
|
||||||
})
|
|
||||||
.trim(),
|
|
||||||
fileList: z.array(z.instanceof(File)),
|
fileList: z.array(z.instanceof(File)),
|
||||||
});
|
...NameFormSchema,
|
||||||
|
});
|
||||||
|
|
||||||
|
export type FormSchemaType = z.infer<typeof FormSchema>;
|
||||||
|
export function UploadAgentForm({ hideModal, onOk }: IModalProps<any>) {
|
||||||
const form = useForm<z.infer<typeof FormSchema>>({
|
const form = useForm<z.infer<typeof FormSchema>>({
|
||||||
resolver: zodResolver(FormSchema),
|
resolver: zodResolver(FormSchema),
|
||||||
defaultValues: { platform: Platform.RAGFlow },
|
defaultValues: { name: '' },
|
||||||
});
|
});
|
||||||
|
|
||||||
async function onSubmit(data: z.infer<typeof FormSchema>) {
|
async function onSubmit(data: FormSchemaType) {
|
||||||
console.log('🚀 ~ onSubmit ~ data:', data);
|
|
||||||
const ret = await onOk?.(data);
|
const ret = await onOk?.(data);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
hideModal?.();
|
hideModal?.();
|
||||||
@ -52,12 +44,13 @@ export function UploadAgentForm({ hideModal, onOk }: IModalProps<any>) {
|
|||||||
className="space-y-6"
|
className="space-y-6"
|
||||||
id={TagRenameId}
|
id={TagRenameId}
|
||||||
>
|
>
|
||||||
|
<NameFormField></NameFormField>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="fileList"
|
name="fileList"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('common.name')}</FormLabel>
|
<FormLabel required>DSL</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<FileUploader
|
<FileUploader
|
||||||
value={field.value}
|
value={field.value}
|
||||||
@ -70,19 +63,6 @@ export function UploadAgentForm({ hideModal, onOk }: IModalProps<any>) {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{/* <FormField
|
|
||||||
control={form.control}
|
|
||||||
name="platform"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>{t('common.name')}</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<RAGFlowSelect {...field} options={options} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/> */}
|
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
56
web/src/pages/agents/use-import-json.ts
Normal file
56
web/src/pages/agents/use-import-json.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { useToast } from '@/components/hooks/use-toast';
|
||||||
|
import { FileMimeType } from '@/constants/common';
|
||||||
|
import { useSetModalState } from '@/hooks/common-hooks';
|
||||||
|
import { EmptyDsl, useSetAgent } from '@/hooks/use-agent-request';
|
||||||
|
import { message } from 'antd';
|
||||||
|
import isEmpty from 'lodash/isEmpty';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { FormSchemaType } from './upload-agent-dialog/upload-agent-form';
|
||||||
|
|
||||||
|
export const useHandleImportJsonFile = () => {
|
||||||
|
const {
|
||||||
|
visible: fileUploadVisible,
|
||||||
|
hideModal: hideFileUploadModal,
|
||||||
|
showModal: showFileUploadModal,
|
||||||
|
} = useSetModalState();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { toast } = useToast();
|
||||||
|
const { loading, setAgent } = useSetAgent();
|
||||||
|
|
||||||
|
const onFileUploadOk = useCallback(
|
||||||
|
async ({ fileList, name }: FormSchemaType) => {
|
||||||
|
if (fileList.length > 0) {
|
||||||
|
const file = fileList[0];
|
||||||
|
if (file.type !== FileMimeType.Json) {
|
||||||
|
toast({ title: t('flow.jsonUploadTypeErrorMessage') });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const graphStr = await file.text();
|
||||||
|
const errorMessage = t('flow.jsonUploadContentErrorMessage');
|
||||||
|
try {
|
||||||
|
const graph = JSON.parse(graphStr);
|
||||||
|
if (graphStr && !isEmpty(graph) && Array.isArray(graph?.nodes)) {
|
||||||
|
const dsl = { ...EmptyDsl, graph };
|
||||||
|
setAgent({ title: name, dsl });
|
||||||
|
hideFileUploadModal();
|
||||||
|
} else {
|
||||||
|
message.error(errorMessage);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
message.error(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[hideFileUploadModal, setAgent, t, toast],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
fileUploadVisible,
|
||||||
|
handleImportJson: showFileUploadModal,
|
||||||
|
hideFileUploadModal,
|
||||||
|
onFileUploadOk,
|
||||||
|
loading,
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user