| import { DataSourceType } from '@/models/datasets' | import { DataSourceType } from '@/models/datasets' | ||||
| import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' | import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' | ||||
| import { useStore } from '@/app/components/app/store' | import { useStore } from '@/app/components/app/store' | ||||
| import { getLocaleOnClient } from '@/i18n' | |||||
| import { useAppContext } from '@/context/app-context' | import { useAppContext } from '@/context/app-context' | ||||
| import Tooltip from '@/app/components/base/tooltip' | import Tooltip from '@/app/components/base/tooltip' | ||||
| import LinkedAppsPanel from '@/app/components/base/linked-apps-panel' | import LinkedAppsPanel from '@/app/components/base/linked-apps-panel' | ||||
| import { PipelineFill, PipelineLine } from '@/app/components/base/icons/src/public/pipeline' | import { PipelineFill, PipelineLine } from '@/app/components/base/icons/src/public/pipeline' | ||||
| import { Divider } from '@/app/components/base/icons/src/public/knowledge' | import { Divider } from '@/app/components/base/icons/src/public/knowledge' | ||||
| import { LanguagesSupported } from '@/i18n/language' | |||||
| import { useGetDocLanguage } from '@/context/i18n' | |||||
| export type IAppDetailLayoutProps = { | export type IAppDetailLayoutProps = { | ||||
| children: React.ReactNode | children: React.ReactNode | ||||
| documentCount, | documentCount, | ||||
| expand, | expand, | ||||
| }: IExtraInfoProps) => { | }: IExtraInfoProps) => { | ||||
| const locale = getLocaleOnClient() | |||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const docLanguage = useGetDocLanguage() | |||||
| const hasRelatedApps = relatedApps?.data && relatedApps?.data?.length > 0 | const hasRelatedApps = relatedApps?.data && relatedApps?.data?.length > 0 | ||||
| const relatedAppsTotal = relatedApps?.data?.length || 0 | const relatedAppsTotal = relatedApps?.data?.length || 0 | ||||
| <div className='my-2 text-xs text-text-tertiary'>{t('common.datasetMenus.emptyTip')}</div> | <div className='my-2 text-xs text-text-tertiary'>{t('common.datasetMenus.emptyTip')}</div> | ||||
| <a | <a | ||||
| className='mt-2 inline-flex cursor-pointer items-center text-xs text-text-accent' | className='mt-2 inline-flex cursor-pointer items-center text-xs text-text-accent' | ||||
| href={ | |||||
| locale === LanguagesSupported[1] | |||||
| ? 'https://docs.dify.ai/v/zh-hans/guides/knowledge-base/integrate-knowledge-within-application' | |||||
| : 'https://docs.dify.ai/guides/knowledge-base/integrate-knowledge-within-application' | |||||
| } | |||||
| href={`https://docs.dify.ai/${docLanguage}/guides/knowledge-base/integrate-knowledge-within-application`} | |||||
| target='_blank' rel='noopener noreferrer' | target='_blank' rel='noopener noreferrer' | ||||
| > | > | ||||
| <RiBookOpenLine className='mr-1 text-text-accent' /> | <RiBookOpenLine className='mr-1 text-text-accent' /> |
| message: t(status === DSLImportStatus.COMPLETED ? 'app.newApp.appCreated' : 'app.newApp.caution'), | message: t(status === DSLImportStatus.COMPLETED ? 'app.newApp.appCreated' : 'app.newApp.caution'), | ||||
| children: status === DSLImportStatus.COMPLETED_WITH_WARNINGS && t('app.newApp.appCreateDSLWarning'), | children: status === DSLImportStatus.COMPLETED_WITH_WARNINGS && t('app.newApp.appCreateDSLWarning'), | ||||
| }) | }) | ||||
| localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') | |||||
| if (app_id) | if (app_id) | ||||
| await handleCheckPluginDependencies(app_id) | await handleCheckPluginDependencies(app_id) | ||||
| getRedirection(isCurrentWorkspaceEditor, { id: app_id!, mode: app_mode }, push) | getRedirection(isCurrentWorkspaceEditor, { id: app_id!, mode: app_mode }, push) |
| import React, { useCallback, useEffect, useRef, useState } from 'react' | |||||
| import AppIcon from '@/app/components/base/app-icon' | import AppIcon from '@/app/components/base/app-icon' | ||||
| import type { AppIconSelection } from '@/app/components/base/app-icon-picker' | import type { AppIconSelection } from '@/app/components/base/app-icon-picker' | ||||
| import AppIconPicker from '@/app/components/base/app-icon-picker' | import AppIconPicker from '@/app/components/base/app-icon-picker' | ||||
| import Textarea from '@/app/components/base/textarea' | import Textarea from '@/app/components/base/textarea' | ||||
| import type { AppIconType } from '@/types/app' | import type { AppIconType } from '@/types/app' | ||||
| import { RiCloseLine } from '@remixicon/react' | import { RiCloseLine } from '@remixicon/react' | ||||
| import React, { useCallback, useRef, useState } from 'react' | |||||
| import PermissionSelector from '../../settings/permission-selector' | import PermissionSelector from '../../settings/permission-selector' | ||||
| import type { CreateDatasetReq } from '@/models/datasets' | |||||
| import { DatasetPermission } from '@/models/datasets' | import { DatasetPermission } from '@/models/datasets' | ||||
| import { useMembers } from '@/service/use-common' | import { useMembers } from '@/service/use-common' | ||||
| import Button from '@/app/components/base/button' | import Button from '@/app/components/base/button' | ||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import Toast from '@/app/components/base/toast' | import Toast from '@/app/components/base/toast' | ||||
| import { useCreateDataset } from '@/service/knowledge/use-create-dataset' | |||||
| import type { Member } from '@/models/common' | |||||
| type CreateFromScratchProps = { | type CreateFromScratchProps = { | ||||
| onClose: () => void | |||||
| onCreate: () => void | |||||
| onClose?: () => void | |||||
| onCreate?: () => void | |||||
| } | } | ||||
| const DEFAULT_APP_ICON: AppIconSelection = { | const DEFAULT_APP_ICON: AppIconSelection = { | ||||
| const [showAppIconPicker, setShowAppIconPicker] = useState(false) | const [showAppIconPicker, setShowAppIconPicker] = useState(false) | ||||
| const [selectedMemberIDs, setSelectedMemberIDs] = useState<string[]>([]) | const [selectedMemberIDs, setSelectedMemberIDs] = useState<string[]>([]) | ||||
| const previousAppIcon = useRef<AppIconSelection>(DEFAULT_APP_ICON) | const previousAppIcon = useRef<AppIconSelection>(DEFAULT_APP_ICON) | ||||
| const [memberList, setMemberList] = useState<Member[]>([]) | |||||
| const { data: memberList } = useMembers() | |||||
| const { data: members } = useMembers() | |||||
| useEffect(() => { | |||||
| if (members?.accounts) | |||||
| setMemberList(members.accounts) | |||||
| }, [members]) | |||||
| const handleAppNameChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => { | const handleAppNameChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => { | ||||
| const value = event.target.value | const value = event.target.value | ||||
| setPermission(value!) | setPermission(value!) | ||||
| }, []) | }, []) | ||||
| const { mutateAsync: createEmptyDataset } = useCreateDataset() | |||||
| const handleCreate = useCallback(() => { | const handleCreate = useCallback(() => { | ||||
| if (!name) { | if (!name) { | ||||
| Toast.notify({ | Toast.notify({ | ||||
| }) | }) | ||||
| return | return | ||||
| } | } | ||||
| onCreate() | |||||
| onClose() | |||||
| }, [name, onCreate, onClose]) | |||||
| const request: CreateDatasetReq = { | |||||
| name, | |||||
| description, | |||||
| icon_info: { | |||||
| icon_type: appIcon.type, | |||||
| icon: appIcon.type === 'image' ? appIcon.fileId : appIcon.icon, | |||||
| icon_background: appIcon.type === 'image' ? undefined : appIcon.background, | |||||
| icon_url: appIcon.type === 'image' ? appIcon.url : undefined, | |||||
| }, | |||||
| permission, | |||||
| } | |||||
| // Handle permission | |||||
| if (request.permission === DatasetPermission.partialMembers) { | |||||
| const selectedMemberList = selectedMemberIDs.map((id) => { | |||||
| return { | |||||
| user_id: id, | |||||
| role: memberList.find(member => member.id === id)?.role, | |||||
| } | |||||
| }) | |||||
| request.partial_member_list = selectedMemberList | |||||
| } | |||||
| createEmptyDataset(request) | |||||
| onCreate?.() | |||||
| onClose?.() | |||||
| }, [name, permission, appIcon, description, createEmptyDataset, memberList, selectedMemberIDs, onCreate, onClose]) | |||||
| return ( | return ( | ||||
| <div className='relative flex flex-col'> | <div className='relative flex flex-col'> | ||||
| {/* Header */} | {/* Header */} | ||||
| <div className='pb-3 pl-6 pr-14 pt-6'> | <div className='pb-3 pl-6 pr-14 pt-6'> | ||||
| <span className='title-2xl-semi-bold text-text-primary'> | <span className='title-2xl-semi-bold text-text-primary'> | ||||
| Create Knowledge | |||||
| {t('datasetPipeline.creation.createKnowledge')} | |||||
| </span> | </span> | ||||
| </div> | </div> | ||||
| <button | <button | ||||
| <div className='flex flex-col gap-y-5 px-6 py-3'> | <div className='flex flex-col gap-y-5 px-6 py-3'> | ||||
| <div className='flex items-end gap-x-3 self-stretch'> | <div className='flex items-end gap-x-3 self-stretch'> | ||||
| <div className='flex grow flex-col gap-y-1 pb-1'> | <div className='flex grow flex-col gap-y-1 pb-1'> | ||||
| <label className='system-sm-medium flex h-6 items-center text-text-secondary'>Knowledge name & icon</label> | |||||
| <label className='system-sm-medium flex h-6 items-center text-text-secondary'> | |||||
| {t('datasetPipeline.creation.knowledgeNameAndIcon')} | |||||
| </label> | |||||
| <Input | <Input | ||||
| onChange={handleAppNameChange} | onChange={handleAppNameChange} | ||||
| value={name} | value={name} | ||||
| placeholder='Please enter the name of the Knowledge Base' | |||||
| placeholder={t('datasetPipeline.creation.knowledgeNameAndIconPlaceholder')} | |||||
| /> | /> | ||||
| </div> | </div> | ||||
| <AppIcon | <AppIcon | ||||
| /> | /> | ||||
| </div> | </div> | ||||
| <div className='flex flex-col gap-y-1'> | <div className='flex flex-col gap-y-1'> | ||||
| <label className='system-sm-medium flex h-6 items-center text-text-secondary'>Knowledge description</label> | |||||
| <label className='system-sm-medium flex h-6 items-center text-text-secondary'> | |||||
| {t('datasetPipeline.creation.knowledgeDescription')} | |||||
| </label> | |||||
| <Textarea | <Textarea | ||||
| onChange={handleDescriptionChange} | onChange={handleDescriptionChange} | ||||
| value={description} | value={description} | ||||
| placeholder='Describe what is in this Knowledge Base. A detailed description allows AI to access the content of the dataset more accurately. If empty, Dify will use the default hit strategy. (Optional)' | |||||
| placeholder={t('datasetPipeline.creation.knowledgeDescriptionPlaceholder')} | |||||
| /> | /> | ||||
| </div> | </div> | ||||
| <div className='flex flex-col gap-y-1'> | <div className='flex flex-col gap-y-1'> | ||||
| <label className='system-sm-medium flex h-6 items-center text-text-secondary'>Permissions</label> | |||||
| <PermissionSelector | |||||
| permission={permission} | |||||
| value={selectedMemberIDs} | |||||
| onChange={handlePermissionChange} | |||||
| onMemberSelect={setSelectedMemberIDs} | |||||
| memberList={memberList?.accounts || []} | |||||
| /> | |||||
| <label className='system-sm-medium flex h-6 items-center text-text-secondary'> | |||||
| {t('datasetPipeline.creation.knowledgePermissions')} | |||||
| </label> | |||||
| <PermissionSelector | |||||
| permission={permission} | |||||
| value={selectedMemberIDs} | |||||
| onChange={handlePermissionChange} | |||||
| onMemberSelect={setSelectedMemberIDs} | |||||
| memberList={memberList} | |||||
| /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {/* Actions */} | {/* Actions */} |
| import { useRouter, useSearchParams } from 'next/navigation' | import { useRouter, useSearchParams } from 'next/navigation' | ||||
| import CreateFromDSLModal, { CreateFromDSLModalTab } from './create-from-dsl-modal' | import CreateFromDSLModal, { CreateFromDSLModalTab } from './create-from-dsl-modal' | ||||
| import { useProviderContextSelector } from '@/context/provider-context' | import { useProviderContextSelector } from '@/context/provider-context' | ||||
| import { useTranslation } from 'react-i18next' | |||||
| const CreateOptions = () => { | const CreateOptions = () => { | ||||
| const { t } = useTranslation() | |||||
| const [showCreateModal, setShowCreateModal] = useState(false) | const [showCreateModal, setShowCreateModal] = useState(false) | ||||
| const [showImportModal, setShowImportModal] = useState(false) | const [showImportModal, setShowImportModal] = useState(false) | ||||
| <div className='flex items-center gap-x-3 px-16 py-2'> | <div className='flex items-center gap-x-3 px-16 py-2'> | ||||
| <Item | <Item | ||||
| Icon={RiAddCircleFill} | Icon={RiAddCircleFill} | ||||
| title='Create from scratch' | |||||
| description='Blank knowledge pipeline' | |||||
| title={t('datasetPipeline.creation.createFromScratch.title')} | |||||
| description={t('datasetPipeline.creation.createFromScratch.description')} | |||||
| onClick={openCreateFromScratch} | onClick={openCreateFromScratch} | ||||
| /> | /> | ||||
| <Item | <Item | ||||
| Icon={RiFileUploadLine} | Icon={RiFileUploadLine} | ||||
| title='Import' | |||||
| description='Import from a DSL file' | |||||
| title={t('datasetPipeline.creation.ImportDSL.title')} | |||||
| description={t('datasetPipeline.creation.ImportDSL.description')} | |||||
| onClick={openImportFromDSL} | onClick={openImportFromDSL} | ||||
| /> | /> | ||||
| <Modal | <Modal |
| import React from 'react' | import React from 'react' | ||||
| import { RiArrowLeftLine } from '@remixicon/react' | import { RiArrowLeftLine } from '@remixicon/react' | ||||
| import Button from '../../base/button' | import Button from '../../base/button' | ||||
| import { useTranslation } from 'react-i18next' | |||||
| const Header = () => { | const Header = () => { | ||||
| const { t } = useTranslation() | |||||
| return ( | return ( | ||||
| <div className='system-md-semibold relative flex px-16 pb-2 pt-5 text-text-primary'> | <div className='system-md-semibold relative flex px-16 pb-2 pt-5 text-text-primary'> | ||||
| <span>Create knowledge pipeline</span> | |||||
| <span>{t('datasetPipeline.creation.title')}</span> | |||||
| <a | <a | ||||
| className='absolute bottom-0 left-5' | className='absolute bottom-0 left-5' | ||||
| href='/datasets' | href='/datasets' |
| import { ChunkingMode } from '@/models/datasets' | |||||
| import { usePipelineTemplateList } from '@/service/use-pipeline' | |||||
| import TemplateCard from './template-card' | import TemplateCard from './template-card' | ||||
| export type Pipeline = { | |||||
| id: string | |||||
| name: string | |||||
| icon_type: 'emoji' | 'image' | |||||
| icon?: string | |||||
| icon_background?: string | |||||
| file_id?: string | |||||
| url?: string | |||||
| description: string | |||||
| doc_form: ChunkingMode | |||||
| } | |||||
| import { ChunkingMode } from '@/models/datasets' | |||||
| import type { PipelineTemple } from '@/models/pipeline' | |||||
| const BuiltInPipelineList = () => { | const BuiltInPipelineList = () => { | ||||
| const mockData: Pipeline[] = [{ | |||||
| // TODO: remove mock data | |||||
| const mockData: PipelineTemple[] = [{ | |||||
| id: '1', | id: '1', | ||||
| name: 'Pipeline 1', | name: 'Pipeline 1', | ||||
| description: 'This is a description of Pipeline 1. When use the general chunking mode, the chunks retrieved and recalled are the same. When use the general chunking mode, the chunks retrieved and recalled are the same.', | description: 'This is a description of Pipeline 1. When use the general chunking mode, the chunks retrieved and recalled are the same. When use the general chunking mode, the chunks retrieved and recalled are the same.', | ||||
| icon_type: 'emoji', | |||||
| icon: '🤖', | |||||
| icon_background: '#F0FDF9', | |||||
| icon_info: { | |||||
| icon: '🤖', | |||||
| icon_background: '#F0FDF9', | |||||
| icon_type: 'emoji', | |||||
| }, | |||||
| doc_form: ChunkingMode.text, | doc_form: ChunkingMode.text, | ||||
| position: 0, | |||||
| }, { | }, { | ||||
| id: '2', | id: '2', | ||||
| name: 'Pipeline 2', | name: 'Pipeline 2', | ||||
| description: 'This is a description of Pipeline 2. When use the general chunking mode, the chunks retrieved and recalled are the same.', | description: 'This is a description of Pipeline 2. When use the general chunking mode, the chunks retrieved and recalled are the same.', | ||||
| icon_type: 'emoji', | |||||
| icon: '🏖️', | |||||
| icon_background: '#FFF4ED', | |||||
| icon_info: { | |||||
| icon: '🏖️', | |||||
| icon_background: '#FFF4ED', | |||||
| icon_type: 'emoji', | |||||
| }, | |||||
| doc_form: ChunkingMode.parentChild, | doc_form: ChunkingMode.parentChild, | ||||
| position: 1, | |||||
| }, { | }, { | ||||
| id: '3', | id: '3', | ||||
| name: 'Pipeline 3', | name: 'Pipeline 3', | ||||
| description: 'This is a description of Pipeline 3', | description: 'This is a description of Pipeline 3', | ||||
| icon_type: 'emoji', | |||||
| icon: '🚀', | |||||
| icon_background: '#FEFBE8', | |||||
| icon_info: { | |||||
| icon: '🚀', | |||||
| icon_background: '#FEFBE8', | |||||
| icon_type: 'emoji', | |||||
| }, | |||||
| doc_form: ChunkingMode.qa, | doc_form: ChunkingMode.qa, | ||||
| position: 2, | |||||
| }, { | }, { | ||||
| id: '4', | id: '4', | ||||
| name: 'Pipeline 4', | name: 'Pipeline 4', | ||||
| description: 'This is a description of Pipeline 4', | description: 'This is a description of Pipeline 4', | ||||
| icon_type: 'emoji', | |||||
| icon: '🍯', | |||||
| icon_background: '#F5F3FF', | |||||
| icon_info: { | |||||
| icon: '🍯', | |||||
| icon_background: '#F5F3FF', | |||||
| icon_type: 'emoji', | |||||
| }, | |||||
| doc_form: ChunkingMode.graph, | doc_form: ChunkingMode.graph, | ||||
| position: 3, | |||||
| }] | }] | ||||
| const { data: pipelineList, isLoading } = usePipelineTemplateList({ type: 'built-in' }) | |||||
| const list = pipelineList?.pipelines || mockData | |||||
| if (isLoading || !list) | |||||
| return null | |||||
| return ( | return ( | ||||
| <div className='grid grow grid-cols-1 gap-3 overflow-y-auto px-16 pt-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4'> | <div className='grid grow grid-cols-1 gap-3 overflow-y-auto px-16 pt-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4'> | ||||
| {mockData.map((pipeline, index) => ( | |||||
| {list.map((pipeline, index) => ( | |||||
| <TemplateCard | <TemplateCard | ||||
| key={index} | key={index} | ||||
| pipeline={pipeline} | pipeline={pipeline} |
| import { ChunkingMode } from '@/models/datasets' | import { ChunkingMode } from '@/models/datasets' | ||||
| import type { Pipeline } from './built-in-pipeline-list' | |||||
| import TemplateCard from './template-card' | import TemplateCard from './template-card' | ||||
| import { usePipelineTemplateList } from '@/service/use-pipeline' | |||||
| import type { PipelineTemple } from '@/models/pipeline' | |||||
| const CustomizedList = () => { | const CustomizedList = () => { | ||||
| const mockData: Pipeline[] = [{ | |||||
| const mockData: PipelineTemple[] = [{ | |||||
| id: '1', | id: '1', | ||||
| name: 'Pipeline 1', | name: 'Pipeline 1', | ||||
| description: 'This is a description of Pipeline 1. When use the general chunking mode, the chunks retrieved and recalled are the same. When use the general chunking mode, the chunks retrieved and recalled are the same.', | description: 'This is a description of Pipeline 1. When use the general chunking mode, the chunks retrieved and recalled are the same. When use the general chunking mode, the chunks retrieved and recalled are the same.', | ||||
| icon_type: 'emoji', | |||||
| icon: '🤖', | |||||
| icon_background: '#F0FDF9', | |||||
| icon_info: { | |||||
| icon: '🤖', | |||||
| icon_background: '#F0FDF9', | |||||
| icon_type: 'emoji', | |||||
| }, | |||||
| doc_form: ChunkingMode.text, | doc_form: ChunkingMode.text, | ||||
| position: 0, | |||||
| }, { | }, { | ||||
| id: '2', | id: '2', | ||||
| name: 'Pipeline 2', | name: 'Pipeline 2', | ||||
| description: 'This is a description of Pipeline 2. When use the general chunking mode, the chunks retrieved and recalled are the same.', | description: 'This is a description of Pipeline 2. When use the general chunking mode, the chunks retrieved and recalled are the same.', | ||||
| icon_type: 'emoji', | |||||
| icon: '🏖️', | |||||
| icon_background: '#FFF4ED', | |||||
| icon_info: { | |||||
| icon: '🏖️', | |||||
| icon_background: '#FFF4ED', | |||||
| icon_type: 'emoji', | |||||
| }, | |||||
| doc_form: ChunkingMode.parentChild, | doc_form: ChunkingMode.parentChild, | ||||
| position: 1, | |||||
| }, { | }, { | ||||
| id: '3', | id: '3', | ||||
| name: 'Pipeline 3', | name: 'Pipeline 3', | ||||
| description: 'This is a description of Pipeline 3', | description: 'This is a description of Pipeline 3', | ||||
| icon_type: 'emoji', | |||||
| icon: '🚀', | |||||
| icon_background: '#FEFBE8', | |||||
| icon_info: { | |||||
| icon: '🚀', | |||||
| icon_background: '#FEFBE8', | |||||
| icon_type: 'emoji', | |||||
| }, | |||||
| doc_form: ChunkingMode.qa, | doc_form: ChunkingMode.qa, | ||||
| position: 2, | |||||
| }, { | }, { | ||||
| id: '4', | id: '4', | ||||
| name: 'Pipeline 4', | name: 'Pipeline 4', | ||||
| description: 'This is a description of Pipeline 4', | description: 'This is a description of Pipeline 4', | ||||
| icon_type: 'emoji', | |||||
| icon: '🍯', | |||||
| icon_background: '#F5F3FF', | |||||
| icon_info: { | |||||
| icon: '🍯', | |||||
| icon_background: '#F5F3FF', | |||||
| icon_type: 'emoji', | |||||
| }, | |||||
| doc_form: ChunkingMode.graph, | doc_form: ChunkingMode.graph, | ||||
| position: 3, | |||||
| }] | }] | ||||
| const { data: pipelineList, isLoading } = usePipelineTemplateList({ type: 'customized' }) | |||||
| const list = pipelineList?.pipelines || mockData | |||||
| if (isLoading || !list) | |||||
| return null | |||||
| return ( | return ( | ||||
| <div className='grid grow grid-cols-1 gap-3 overflow-y-auto px-16 pt-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4'> | <div className='grid grow grid-cols-1 gap-3 overflow-y-auto px-16 pt-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4'> | ||||
| {mockData.map((pipeline, index) => ( | |||||
| {list.map((pipeline, index) => ( | |||||
| <TemplateCard | <TemplateCard | ||||
| key={index} | key={index} | ||||
| pipeline={pipeline} | pipeline={pipeline} |
| import { useCallback, useState } from 'react' | |||||
| import { useCallback, useMemo, useState } from 'react' | |||||
| import Tab from './tab' | import Tab from './tab' | ||||
| import BuiltInPipelineList from './built-in-pipeline-list' | import BuiltInPipelineList from './built-in-pipeline-list' | ||||
| import CustomizedList from './customized-list' | import CustomizedList from './customized-list' | ||||
| const OPTIONS = [ | |||||
| { value: 'built-in', label: 'Built-in Pipeline' }, | |||||
| { value: 'customized', label: 'Customized' }, | |||||
| ] | |||||
| import { useTranslation } from 'react-i18next' | |||||
| const List = () => { | const List = () => { | ||||
| const { t } = useTranslation() | |||||
| const [activeTab, setActiveTab] = useState('built-in') | const [activeTab, setActiveTab] = useState('built-in') | ||||
| const options = useMemo(() => { | |||||
| return [ | |||||
| { value: 'built-in', label: t('datasetPipeline.tabs.builtInPipeline') }, | |||||
| { value: 'customized', label: t('datasetPipeline.tabs.customized') }, | |||||
| ] | |||||
| }, [t]) | |||||
| const handleTabChange = useCallback((tab: string) => { | const handleTabChange = useCallback((tab: string) => { | ||||
| setActiveTab(tab) | setActiveTab(tab) | ||||
| }, []) | }, []) | ||||
| <Tab | <Tab | ||||
| activeTab={activeTab} | activeTab={activeTab} | ||||
| handleTabChange={handleTabChange} | handleTabChange={handleTabChange} | ||||
| options={OPTIONS} | |||||
| options={options} | |||||
| /> | /> | ||||
| { | { | ||||
| activeTab === 'built-in' && <BuiltInPipelineList /> | activeTab === 'built-in' && <BuiltInPipelineList /> |
| import Button from '@/app/components/base/button' | import Button from '@/app/components/base/button' | ||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import Toast from '@/app/components/base/toast' | import Toast from '@/app/components/base/toast' | ||||
| import type { Pipeline } from '../built-in-pipeline-list' | |||||
| import type { PipelineTemple } from '@/models/pipeline' | |||||
| type EditPipelineInfoProps = { | type EditPipelineInfoProps = { | ||||
| onClose: () => void | onClose: () => void | ||||
| onSave: () => void | onSave: () => void | ||||
| pipeline: Pipeline | |||||
| pipeline: PipelineTemple | |||||
| } | } | ||||
| const EditPipelineInfo = ({ | const EditPipelineInfo = ({ | ||||
| }: EditPipelineInfoProps) => { | }: EditPipelineInfoProps) => { | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const [name, setName] = useState(pipeline.name) | const [name, setName] = useState(pipeline.name) | ||||
| const iconInfo = pipeline.icon_info | |||||
| const [appIcon, setAppIcon] = useState<AppIconSelection>( | const [appIcon, setAppIcon] = useState<AppIconSelection>( | ||||
| pipeline.icon_type === 'image' | |||||
| ? { type: 'image' as const, url: pipeline.url || '', fileId: pipeline.file_id || '' } | |||||
| : { type: 'emoji' as const, icon: pipeline.icon || '', background: pipeline.icon_background || '' }, | |||||
| iconInfo.icon_type === 'image' | |||||
| ? { type: 'image' as const, url: iconInfo.icon_url || '', fileId: iconInfo.icon || '' } | |||||
| : { type: 'emoji' as const, icon: iconInfo.icon || '', background: iconInfo.icon_background || '' }, | |||||
| ) | ) | ||||
| const [description, setDescription] = useState(pipeline.description) | const [description, setDescription] = useState(pipeline.description) | ||||
| const [showAppIconPicker, setShowAppIconPicker] = useState(false) | const [showAppIconPicker, setShowAppIconPicker] = useState(false) | ||||
| const previousAppIcon = useRef<AppIconSelection>( | const previousAppIcon = useRef<AppIconSelection>( | ||||
| pipeline.icon_type === 'image' | |||||
| ? { type: 'image' as const, url: pipeline.url || '', fileId: pipeline.file_id || '' } | |||||
| : { type: 'emoji' as const, icon: pipeline.icon || '', background: pipeline.icon_background || '' }, | |||||
| iconInfo.icon_type === 'image' | |||||
| ? { type: 'image' as const, url: iconInfo.icon_url || '', fileId: iconInfo.icon || '' } | |||||
| : { type: 'emoji' as const, icon: iconInfo.icon || '', background: iconInfo.icon_background || '' }, | |||||
| ) | ) | ||||
| const handleAppNameChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => { | const handleAppNameChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => { |
| import React, { useCallback, useState } from 'react' | import React, { useCallback, useState } from 'react' | ||||
| import type { Pipeline } from '../built-in-pipeline-list' | |||||
| import AppIcon from '@/app/components/base/app-icon' | import AppIcon from '@/app/components/base/app-icon' | ||||
| import { DOC_FORM_ICON, DOC_FORM_TEXT } from '../../../list/dataset-card' | |||||
| import { General } from '@/app/components/base/icons/src/public/knowledge' | import { General } from '@/app/components/base/icons/src/public/knowledge' | ||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import Button from '@/app/components/base/button' | import Button from '@/app/components/base/button' | ||||
| import Operations from './operations' | import Operations from './operations' | ||||
| import Modal from '@/app/components/base/modal' | import Modal from '@/app/components/base/modal' | ||||
| import EditPipelineInfo from './edit-pipeline-info' | import EditPipelineInfo from './edit-pipeline-info' | ||||
| import type { PipelineTemple } from '@/models/pipeline' | |||||
| import { DOC_FORM_ICON, DOC_FORM_TEXT } from '@/models/datasets' | |||||
| type TemplateCardProps = { | type TemplateCardProps = { | ||||
| pipeline: Pipeline | |||||
| pipeline: PipelineTemple | |||||
| showMoreOperations?: boolean | showMoreOperations?: boolean | ||||
| } | } | ||||
| }, []) | }, []) | ||||
| const Icon = DOC_FORM_ICON[pipeline.doc_form] || General | const Icon = DOC_FORM_ICON[pipeline.doc_form] || General | ||||
| const iconInfo = pipeline.icon_info | |||||
| return ( | return ( | ||||
| <div className='group relative flex h-[132px] cursor-pointer flex-col rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg pb-3 shadow-xs shadow-shadow-shadow-3'> | <div className='group relative flex h-[132px] cursor-pointer flex-col rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg pb-3 shadow-xs shadow-shadow-shadow-3'> | ||||
| <div className='relative shrink-0'> | <div className='relative shrink-0'> | ||||
| <AppIcon | <AppIcon | ||||
| size='large' | size='large' | ||||
| iconType={pipeline.icon_type} | |||||
| icon={pipeline.icon_type === 'image' ? pipeline.file_id : pipeline.icon} | |||||
| background={pipeline.icon_type === 'image' ? undefined : pipeline.icon_background} | |||||
| imageUrl={pipeline.icon_type === 'image' ? pipeline.url : undefined} | |||||
| iconType={iconInfo.icon_type} | |||||
| icon={iconInfo.icon} | |||||
| background={iconInfo.icon_type === 'image' ? undefined : iconInfo.icon_background} | |||||
| imageUrl={iconInfo.icon_type === 'image' ? iconInfo.icon_url : undefined} | |||||
| /> | /> | ||||
| <div className='absolute -bottom-1 -right-1 z-10'> | <div className='absolute -bottom-1 -right-1 z-10'> | ||||
| <Icon className='size-4' /> | <Icon className='size-4' /> |
| import { useRouter } from 'next/navigation' | import { useRouter } from 'next/navigation' | ||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import type { DataSet } from '@/models/datasets' | import type { DataSet } from '@/models/datasets' | ||||
| import { ChunkingMode } from '@/models/datasets' | |||||
| import { useAppContext } from '@/context/app-context' | |||||
| import { ExternalKnowledgeBase, General, Graph, ParentChild, Qa } from '@/app/components/base/icons/src/public/knowledge' | |||||
| import { useSelector as useAppContextWithSelector } from '@/context/app-context' | |||||
| import { General } from '@/app/components/base/icons/src/public/knowledge' | |||||
| import { useKnowledge } from '@/hooks/use-knowledge' | import { useKnowledge } from '@/hooks/use-knowledge' | ||||
| import { useCallback, useEffect, useMemo, useRef, useState } from 'react' | import { useCallback, useEffect, useMemo, useRef, useState } from 'react' | ||||
| import type { Tag } from '@/app/components/base/tag-management/constant' | import type { Tag } from '@/app/components/base/tag-management/constant' | ||||
| import Operations from './operations' | import Operations from './operations' | ||||
| import AppIcon from '@/app/components/base/app-icon' | import AppIcon from '@/app/components/base/app-icon' | ||||
| import CornerLabel from '@/app/components/base/corner-label' | import CornerLabel from '@/app/components/base/corner-label' | ||||
| import { DOC_FORM_ICON, DOC_FORM_TEXT } from '@/models/datasets' | |||||
| const EXTERNAL_PROVIDER = 'external' | const EXTERNAL_PROVIDER = 'external' | ||||
| export const DOC_FORM_ICON: Record<ChunkingMode | 'external', React.ComponentType<{ className: string }>> = { | |||||
| [ChunkingMode.text]: General, | |||||
| [ChunkingMode.qa]: Qa, | |||||
| [ChunkingMode.parentChild]: ParentChild, | |||||
| [ChunkingMode.graph]: Graph, | |||||
| external: ExternalKnowledgeBase, | |||||
| } | |||||
| export const DOC_FORM_TEXT: Record<ChunkingMode, string> = { | |||||
| [ChunkingMode.text]: 'general', | |||||
| [ChunkingMode.qa]: 'qa', | |||||
| [ChunkingMode.parentChild]: 'parentChild', | |||||
| [ChunkingMode.graph]: 'graph', | |||||
| } | |||||
| export type DatasetCardProps = { | |||||
| type DatasetCardProps = { | |||||
| dataset: DataSet | dataset: DataSet | ||||
| onSuccess?: () => void | onSuccess?: () => void | ||||
| } | } | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const { push } = useRouter() | const { push } = useRouter() | ||||
| const { isCurrentWorkspaceDatasetOperator } = useAppContext() | |||||
| const isCurrentWorkspaceDatasetOperator = useAppContextWithSelector(state => state.isCurrentWorkspaceDatasetOperator) | |||||
| const [tags, setTags] = useState<Tag[]>(dataset.tags) | const [tags, setTags] = useState<Tag[]>(dataset.tags) | ||||
| const tagSelectorRef = useRef<HTMLDivElement>(null) | const tagSelectorRef = useRef<HTMLDivElement>(null) | ||||
| const isHoveringTagSelector = useHover(tagSelectorRef) | const isHoveringTagSelector = useHover(tagSelectorRef) |
| const translation = {} | |||||
| export default translation |
| const translation = { | |||||
| creation: { | |||||
| title: 'Create knowledge pipeline', | |||||
| createFromScratch: { | |||||
| title: 'Create from scratch', | |||||
| description: 'Blank knowledge pipeline', | |||||
| }, | |||||
| ImportDSL: { | |||||
| title: 'Import', | |||||
| description: 'Import from a DSL file', | |||||
| }, | |||||
| createKnowledge: 'Create Knowledge', | |||||
| knowledgeNameAndIcon: 'Knowledge name & icon', | |||||
| knowledgeNameAndIconPlaceholder: 'Please enter the name of the Knowledge Base', | |||||
| knowledgeDescription: 'Knowledge description', | |||||
| knowledgeDescriptionPlaceholder: 'Describe what is in this Knowledge Base. A detailed description allows AI to access the content of the dataset more accurately. If empty, Dify will use the default hit strategy. (Optional)', | |||||
| knowledgePermissions: 'Permissions', | |||||
| }, | |||||
| tabs: { | |||||
| builtInPipeline: 'Built-in pipeline', | |||||
| customized: 'Customized', | |||||
| }, | |||||
| } | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| datasetHitTesting: require(`./${lang}/dataset-hit-testing`).default, | datasetHitTesting: require(`./${lang}/dataset-hit-testing`).default, | ||||
| datasetSettings: require(`./${lang}/dataset-settings`).default, | datasetSettings: require(`./${lang}/dataset-settings`).default, | ||||
| datasetCreation: require(`./${lang}/dataset-creation`).default, | datasetCreation: require(`./${lang}/dataset-creation`).default, | ||||
| datasetPipeline: require(`./${lang}/dataset-pipeline`).default, | |||||
| explore: require(`./${lang}/explore`).default, | explore: require(`./${lang}/explore`).default, | ||||
| billing: require(`./${lang}/billing`).default, | billing: require(`./${lang}/billing`).default, | ||||
| custom: require(`./${lang}/custom`).default, | custom: require(`./${lang}/custom`).default, |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| const translation = { | |||||
| creation: { | |||||
| title: '创建知识库流水线', | |||||
| createFromScratch: { | |||||
| title: '从零开始创建', | |||||
| description: '空白知识库流水线', | |||||
| }, | |||||
| ImportDSL: { | |||||
| title: '导入', | |||||
| description: '从 DSL 文件导入', | |||||
| }, | |||||
| createKnowledge: '创建知识库', | |||||
| knowledgeNameAndIcon: '知识库名称和图标', | |||||
| knowledgeNameAndIconPlaceholder: '请输入知识库名称', | |||||
| knowledgeDescription: '知识库描述', | |||||
| knowledgeDescriptionPlaceholder: '描述知识库中的内容。详细的描述可以让 AI 更准确地访问数据集的内容。如果为空,Dify 将使用默认的命中策略。(可选)', | |||||
| knowledgePermissions: '权限', | |||||
| }, | |||||
| tabs: { | |||||
| builtInPipeline: '内置流水线', | |||||
| customized: '自定义', | |||||
| }, | |||||
| } | |||||
| export default translation |
| const translation = {} | |||||
| export default translation |
| import type { IndexingType } from '@/app/components/datasets/create/step-two' | import type { IndexingType } from '@/app/components/datasets/create/step-two' | ||||
| import type { MetadataFilteringVariableType } from '@/app/components/workflow/nodes/knowledge-retrieval/types' | import type { MetadataFilteringVariableType } from '@/app/components/workflow/nodes/knowledge-retrieval/types' | ||||
| import type { MetadataItemWithValue } from '@/app/components/datasets/metadata/types' | import type { MetadataItemWithValue } from '@/app/components/datasets/metadata/types' | ||||
| import { ExternalKnowledgeBase, General, Graph, ParentChild, Qa } from '@/app/components/base/icons/src/public/knowledge' | |||||
| export enum DataSourceType { | export enum DataSourceType { | ||||
| FILE = 'upload_file', | FILE = 'upload_file', | ||||
| name: string | name: string | ||||
| } | } | ||||
| export type IconInfo = { | |||||
| icon: string | |||||
| icon_background?: string | |||||
| icon_type: AppIconType | |||||
| icon_url?: string | |||||
| } | |||||
| export type DataSet = { | export type DataSet = { | ||||
| id: string | id: string | ||||
| name: string | name: string | ||||
| indexing_status: DocumentIndexingStatus | indexing_status: DocumentIndexingStatus | ||||
| icon_info: { | |||||
| icon: string | |||||
| icon_background?: string | |||||
| icon_type: AppIconType | |||||
| icon_url?: string | |||||
| } | |||||
| icon_info: IconInfo | |||||
| description: string | description: string | ||||
| permission: DatasetPermission | permission: DatasetPermission | ||||
| data_source_type: DataSourceType | data_source_type: DataSourceType | ||||
| export type DocumentReq = { | export type DocumentReq = { | ||||
| original_document_id?: string | original_document_id?: string | ||||
| indexing_technique?: string | |||||
| indexing_technique?: IndexingType | |||||
| doc_form: ChunkingMode | doc_form: ChunkingMode | ||||
| doc_language: string | doc_language: string | ||||
| process_rule: ProcessRule | process_rule: ProcessRule | ||||
| job_id: string | job_id: string | ||||
| job_status: string | job_status: string | ||||
| } | } | ||||
| export const DOC_FORM_ICON: Record<ChunkingMode | 'external', React.ComponentType<{ className: string }>> = { | |||||
| [ChunkingMode.text]: General, | |||||
| [ChunkingMode.qa]: Qa, | |||||
| [ChunkingMode.parentChild]: ParentChild, | |||||
| [ChunkingMode.graph]: Graph, | |||||
| external: ExternalKnowledgeBase, | |||||
| } | |||||
| export const DOC_FORM_TEXT: Record<ChunkingMode, string> = { | |||||
| [ChunkingMode.text]: 'general', | |||||
| [ChunkingMode.qa]: 'qa', | |||||
| [ChunkingMode.parentChild]: 'parentChild', | |||||
| [ChunkingMode.graph]: 'graph', | |||||
| } | |||||
| export type CreateDatasetReq = { | |||||
| name: string | |||||
| description: string | |||||
| icon_info: IconInfo | |||||
| doc_form?: ChunkingMode | |||||
| permission: DatasetPermission | |||||
| partial_member_list?: { | |||||
| user_id: string | |||||
| role?: 'owner' | 'admin' | 'editor' | 'normal' | 'dataset_operator' | |||||
| }[] | |||||
| indexing_technique?: IndexingType | |||||
| retrieval_mode?: RetrievalConfig | |||||
| embedding_model?: string | |||||
| embedding_model_provider?: string | |||||
| } | |||||
| export type CreateDatasetResponse = { | |||||
| id: string | |||||
| name: string | |||||
| description: string | |||||
| permission: DatasetPermission | |||||
| data_source_type: DataSourceType | |||||
| indexing_technique: IndexingType | |||||
| created_by: string | |||||
| created_at: number | |||||
| updated_by: string | |||||
| updated_at: number | |||||
| } |
| import type { ChunkingMode, IconInfo } from './datasets' | |||||
| export type PipelineTemplateListParams = { | |||||
| type: 'built-in' | 'customized' | |||||
| } | |||||
| export type PipelineTemple = { | |||||
| id: string | |||||
| name: string | |||||
| icon_info: IconInfo | |||||
| description: string | |||||
| position: number | |||||
| doc_form: ChunkingMode | |||||
| } | |||||
| export type PipelineTemplateListResponse = { | |||||
| pipelines: PipelineTemple[] | |||||
| } | |||||
| export type PipelineTemplateByIdResponse = { | |||||
| name: string | |||||
| icon_info: IconInfo | |||||
| description: string | |||||
| export_data: string | |||||
| } | |||||
| export type UpdatePipelineInfoPayload = { | |||||
| pipelineId: string | |||||
| name: string | |||||
| icon_info: IconInfo | |||||
| description: string | |||||
| } | |||||
| export type ExportPipelineDSLResponse = { | |||||
| data: string | |||||
| } |
| import { useMutation } from '@tanstack/react-query' | import { useMutation } from '@tanstack/react-query' | ||||
| import { createDocument, createFirstDocument, fetchDefaultProcessRule, fetchFileIndexingEstimate } from '../datasets' | import { createDocument, createFirstDocument, fetchDefaultProcessRule, fetchFileIndexingEstimate } from '../datasets' | ||||
| import type { IndexingType } from '@/app/components/datasets/create/step-two' | import type { IndexingType } from '@/app/components/datasets/create/step-two' | ||||
| import type { ChunkingMode, CrawlOptions, CrawlResultItem, CreateDocumentReq, CustomFile, DataSourceType, FileIndexingEstimateResponse, IndexingEstimateParams, NotionInfo, ProcessRule, ProcessRuleResponse, createDocumentResponse } from '@/models/datasets' | |||||
| import type { | |||||
| ChunkingMode, | |||||
| CrawlOptions, | |||||
| CrawlResultItem, | |||||
| CreateDatasetReq, | |||||
| CreateDatasetResponse, | |||||
| CreateDocumentReq, | |||||
| CustomFile, | |||||
| DataSourceType, | |||||
| FileIndexingEstimateResponse, | |||||
| IndexingEstimateParams, | |||||
| NotionInfo, | |||||
| ProcessRule, | |||||
| ProcessRuleResponse, | |||||
| createDocumentResponse, | |||||
| } from '@/models/datasets' | |||||
| import type { DataSourceProvider, NotionPage } from '@/models/common' | import type { DataSourceProvider, NotionPage } from '@/models/common' | ||||
| import { post } from '../base' | |||||
| export const getNotionInfo = ( | export const getNotionInfo = ( | ||||
| notionPages: NotionPage[], | notionPages: NotionPage[], | ||||
| ...mutationOptions, | ...mutationOptions, | ||||
| }) | }) | ||||
| } | } | ||||
| export const useCreateDataset = ( | |||||
| mutationOptions: MutationOptions<CreateDatasetResponse, Error, CreateDatasetReq> = {}, | |||||
| ) => { | |||||
| return useMutation({ | |||||
| mutationFn: (req: CreateDatasetReq) => { | |||||
| return post<CreateDatasetResponse>('/datasets', { body: req }) | |||||
| }, | |||||
| ...mutationOptions, | |||||
| }) | |||||
| } |
| import { useMutation, useQuery } from '@tanstack/react-query' | |||||
| import { del, get, patch } from './base' | |||||
| import type { | |||||
| ExportPipelineDSLResponse, | |||||
| PipelineTemplateByIdResponse, | |||||
| PipelineTemplateListParams, | |||||
| PipelineTemplateListResponse, | |||||
| UpdatePipelineInfoPayload, | |||||
| } from '@/models/pipeline' | |||||
| const NAME_SPACE = 'pipeline' | |||||
| export const usePipelineTemplateList = (params: PipelineTemplateListParams) => { | |||||
| return useQuery<PipelineTemplateListResponse>({ | |||||
| queryKey: [NAME_SPACE, 'template', 'list'], | |||||
| queryFn: () => { | |||||
| return get<PipelineTemplateListResponse>('/rag/pipeline/template', { params }) | |||||
| }, | |||||
| }) | |||||
| } | |||||
| export const usePipelineTemplateById = (templateId: string) => { | |||||
| return useQuery<PipelineTemplateByIdResponse>({ | |||||
| queryKey: [NAME_SPACE, 'template', templateId], | |||||
| queryFn: () => { | |||||
| return get<PipelineTemplateByIdResponse>(`/rag/pipeline/template/${templateId}`) | |||||
| }, | |||||
| }) | |||||
| } | |||||
| export const useUpdatePipelineInfo = ({ | |||||
| onSuccess, | |||||
| onError, | |||||
| }: { | |||||
| onSuccess?: () => void | |||||
| onError?: (error: any) => void | |||||
| }) => { | |||||
| return useMutation({ | |||||
| mutationKey: [NAME_SPACE, 'template', 'update'], | |||||
| mutationFn: (payload: UpdatePipelineInfoPayload) => { | |||||
| const { pipelineId, ...rest } = payload | |||||
| return patch(`/rag/pipeline/${pipelineId}`, { | |||||
| body: rest, | |||||
| }) | |||||
| }, | |||||
| onSuccess, | |||||
| onError, | |||||
| }) | |||||
| } | |||||
| export const useDeletePipeline = ({ | |||||
| onSuccess, | |||||
| onError, | |||||
| }: { | |||||
| onSuccess?: () => void | |||||
| onError?: (error: any) => void | |||||
| }) => { | |||||
| return useMutation({ | |||||
| mutationKey: [NAME_SPACE, 'template', 'delete'], | |||||
| mutationFn: (pipelineId: string) => { | |||||
| return del(`/rag/pipeline/${pipelineId}`) | |||||
| }, | |||||
| onSuccess, | |||||
| onError, | |||||
| }) | |||||
| } | |||||
| export const useExportPipelineDSL = (pipelineId: string) => { | |||||
| return useQuery<ExportPipelineDSLResponse>({ | |||||
| queryKey: [NAME_SPACE, 'template', 'export', pipelineId], | |||||
| queryFn: () => { | |||||
| return get<ExportPipelineDSLResponse>(`/rag/pipeline/${pipelineId}`) | |||||
| }, | |||||
| }) | |||||
| } |