| <div className='flex items-center justify-between'> | <div className='flex items-center justify-between'> | ||||
| <div className='system-md-semibold flex cursor-pointer items-center gap-1 text-text-primary' onClick={() => setCollapse(!collapse)}> | <div className='system-md-semibold flex cursor-pointer items-center gap-1 text-text-primary' onClick={() => setCollapse(!collapse)}> | ||||
| <RiArrowDownSLine className={cn('h-4 w-4', collapse && '-rotate-90')} /> | <RiArrowDownSLine className={cn('h-4 w-4', collapse && '-rotate-90')} /> | ||||
| {t('common.modelProvider.installProvider')} | |||||
| {t('common.modelProvider.installDataSourceProvider')} | |||||
| </div> | </div> | ||||
| <div className='mb-2 flex items-center pt-2'> | <div className='mb-2 flex items-center pt-2'> | ||||
| <span className='system-sm-regular pr-1 text-text-tertiary'>{t('common.modelProvider.discoverMore')}</span> | <span className='system-sm-regular pr-1 text-text-tertiary'>{t('common.modelProvider.discoverMore')}</span> |
| readonly && 'cursor-not-allowed', | readonly && 'cursor-not-allowed', | ||||
| wrapperClassName && (typeof wrapperClassName === 'function' ? wrapperClassName(isActive) : wrapperClassName), | wrapperClassName && (typeof wrapperClassName === 'function' ? wrapperClassName(isActive) : wrapperClassName), | ||||
| )} | )} | ||||
| onClick={() => !readonly && enableSelect && id && onClick?.(id)} | |||||
| onClick={(e) => { | |||||
| e.stopPropagation() | |||||
| !readonly && enableSelect && id && onClick?.(id) | |||||
| }} | |||||
| > | > | ||||
| <div className={cn( | <div className={cn( | ||||
| 'relative flex rounded-t-xl p-2', | 'relative flex rounded-t-xl p-2', |
| import type { KnowledgeBaseNodeType } from './types' | import type { KnowledgeBaseNodeType } from './types' | ||||
| import { genNodeMetaData } from '@/app/components/workflow/utils' | import { genNodeMetaData } from '@/app/components/workflow/utils' | ||||
| import { BlockEnum } from '@/app/components/workflow/types' | import { BlockEnum } from '@/app/components/workflow/types' | ||||
| import { IndexingType } from '@/app/components/datasets/create/step-two' | |||||
| const metaData = genNodeMetaData({ | const metaData = genNodeMetaData({ | ||||
| sort: 3.1, | sort: 3.1, | ||||
| chunk_structure, | chunk_structure, | ||||
| indexing_technique, | indexing_technique, | ||||
| retrieval_model, | retrieval_model, | ||||
| embedding_model, | |||||
| embedding_model_provider, | |||||
| index_chunk_variable_selector, | |||||
| } = payload | } = payload | ||||
| const { | |||||
| search_method, | |||||
| reranking_enable, | |||||
| reranking_model, | |||||
| } = retrieval_model || {} | |||||
| if (!chunk_structure) { | if (!chunk_structure) { | ||||
| return { | return { | ||||
| isValid: false, | isValid: false, | ||||
| } | } | ||||
| } | } | ||||
| if (index_chunk_variable_selector.length === 0) { | |||||
| return { | |||||
| isValid: false, | |||||
| errorMessage: t('workflow.nodes.knowledgeBase.chunksVariableIsRequired'), | |||||
| } | |||||
| } | |||||
| if (!indexing_technique) { | if (!indexing_technique) { | ||||
| return { | return { | ||||
| isValid: false, | isValid: false, | ||||
| } | } | ||||
| } | } | ||||
| if (!retrieval_model || !retrieval_model.search_method) { | |||||
| if (indexing_technique === IndexingType.QUALIFIED && (!embedding_model || !embedding_model_provider)) { | |||||
| return { | |||||
| isValid: false, | |||||
| errorMessage: t('workflow.nodes.knowledgeBase.embeddingModelIsRequired'), | |||||
| } | |||||
| } | |||||
| if (!retrieval_model || !search_method) { | |||||
| return { | return { | ||||
| isValid: false, | isValid: false, | ||||
| errorMessage: t('workflow.nodes.knowledgeBase.retrievalSettingIsRequired'), | errorMessage: t('workflow.nodes.knowledgeBase.retrievalSettingIsRequired'), | ||||
| } | } | ||||
| } | } | ||||
| if (reranking_enable && (!reranking_model || !reranking_model.reranking_provider_name || !reranking_model.reranking_model_name)) { | |||||
| return { | |||||
| isValid: false, | |||||
| errorMessage: t('workflow.nodes.knowledgeBase.rerankingModelIsRequired'), | |||||
| } | |||||
| } | |||||
| return { | return { | ||||
| isValid: true, | isValid: true, | ||||
| errorMessage: '', | errorMessage: '', |
| ChunkStructureEnum, | ChunkStructureEnum, | ||||
| IndexMethodEnum, | IndexMethodEnum, | ||||
| RetrievalSearchMethodEnum, | RetrievalSearchMethodEnum, | ||||
| WeightedScoreEnum, | |||||
| } from '../types' | } from '../types' | ||||
| import type { | import type { | ||||
| HybridSearchModeEnum, | |||||
| KnowledgeBaseNodeType, | KnowledgeBaseNodeType, | ||||
| RerankingModel, | RerankingModel, | ||||
| } from '../types' | } from '../types' | ||||
| import { | |||||
| HybridSearchModeEnum, | |||||
| } from '../types' | |||||
| import { isHighQualitySearchMethod } from '../utils' | import { isHighQualitySearchMethod } from '../utils' | ||||
| import { DEFAULT_WEIGHTED_SCORE, RerankingModeEnum } from '@/models/datasets' | |||||
| export const useConfig = (id: string) => { | export const useConfig = (id: string) => { | ||||
| const store = useStoreApi() | const store = useStoreApi() | ||||
| }) | }) | ||||
| }, [id, handleNodeDataUpdateWithSyncDraft]) | }, [id, handleNodeDataUpdateWithSyncDraft]) | ||||
| const getDefaultWeights = useCallback(({ | |||||
| embeddingModel, | |||||
| embeddingModelProvider, | |||||
| }: { | |||||
| embeddingModel: string | |||||
| embeddingModelProvider: string | |||||
| }) => { | |||||
| return { | |||||
| vector_setting: { | |||||
| vector_weight: DEFAULT_WEIGHTED_SCORE.other.semantic, | |||||
| embedding_provider_name: embeddingModelProvider || '', | |||||
| embedding_model_name: embeddingModel, | |||||
| }, | |||||
| keyword_setting: { | |||||
| keyword_weight: DEFAULT_WEIGHTED_SCORE.other.keyword, | |||||
| }, | |||||
| } | |||||
| }, []) | |||||
| const handleChunkStructureChange = useCallback((chunkStructure: ChunkStructureEnum) => { | const handleChunkStructureChange = useCallback((chunkStructure: ChunkStructureEnum) => { | ||||
| const nodeData = getNodeData() | const nodeData = getNodeData() | ||||
| const { | const { | ||||
| embeddingModelProvider: string | embeddingModelProvider: string | ||||
| }) => { | }) => { | ||||
| const nodeData = getNodeData() | const nodeData = getNodeData() | ||||
| handleNodeDataUpdate({ | |||||
| const defaultWeights = getDefaultWeights({ | |||||
| embeddingModel, | |||||
| embeddingModelProvider, | |||||
| }) | |||||
| const changeData = { | |||||
| embedding_model: embeddingModel, | embedding_model: embeddingModel, | ||||
| embedding_model_provider: embeddingModelProvider, | embedding_model_provider: embeddingModelProvider, | ||||
| retrieval_model: { | retrieval_model: { | ||||
| ...nodeData?.data.retrieval_model, | ...nodeData?.data.retrieval_model, | ||||
| vector_setting: { | |||||
| ...nodeData?.data.retrieval_model.vector_setting, | |||||
| embedding_provider_name: embeddingModelProvider, | |||||
| embedding_model_name: embeddingModel, | |||||
| }, | |||||
| }, | }, | ||||
| }) | |||||
| }, [getNodeData, handleNodeDataUpdate]) | |||||
| } | |||||
| if (changeData.retrieval_model.weights) { | |||||
| changeData.retrieval_model = { | |||||
| ...changeData.retrieval_model, | |||||
| weights: { | |||||
| ...changeData.retrieval_model.weights, | |||||
| vector_setting: { | |||||
| ...changeData.retrieval_model.weights.vector_setting, | |||||
| embedding_provider_name: embeddingModelProvider, | |||||
| embedding_model_name: embeddingModel, | |||||
| }, | |||||
| }, | |||||
| } | |||||
| } | |||||
| else { | |||||
| changeData.retrieval_model = { | |||||
| ...changeData.retrieval_model, | |||||
| weights: defaultWeights, | |||||
| } | |||||
| } | |||||
| handleNodeDataUpdate(changeData) | |||||
| }, [getNodeData, getDefaultWeights, handleNodeDataUpdate]) | |||||
| const handleRetrievalSearchMethodChange = useCallback((searchMethod: RetrievalSearchMethodEnum) => { | const handleRetrievalSearchMethodChange = useCallback((searchMethod: RetrievalSearchMethodEnum) => { | ||||
| const nodeData = getNodeData() | const nodeData = getNodeData() | ||||
| handleNodeDataUpdate({ | |||||
| const changeData = { | |||||
| retrieval_model: { | retrieval_model: { | ||||
| ...nodeData?.data.retrieval_model, | ...nodeData?.data.retrieval_model, | ||||
| search_method: searchMethod, | search_method: searchMethod, | ||||
| reranking_mode: nodeData?.data.retrieval_model.reranking_mode || RerankingModeEnum.RerankingModel, | |||||
| }, | }, | ||||
| }) | |||||
| } | |||||
| if (searchMethod === RetrievalSearchMethodEnum.hybrid) { | |||||
| changeData.retrieval_model = { | |||||
| ...changeData.retrieval_model, | |||||
| reranking_enable: changeData.retrieval_model.reranking_mode === RerankingModeEnum.RerankingModel, | |||||
| } | |||||
| } | |||||
| handleNodeDataUpdate(changeData) | |||||
| }, [getNodeData, handleNodeDataUpdate]) | }, [getNodeData, handleNodeDataUpdate]) | ||||
| const handleHybridSearchModeChange = useCallback((hybridSearchMode: HybridSearchModeEnum) => { | const handleHybridSearchModeChange = useCallback((hybridSearchMode: HybridSearchModeEnum) => { | ||||
| const nodeData = getNodeData() | const nodeData = getNodeData() | ||||
| const defaultWeights = getDefaultWeights({ | |||||
| embeddingModel: nodeData?.data.embedding_model || '', | |||||
| embeddingModelProvider: nodeData?.data.embedding_model_provider || '', | |||||
| }) | |||||
| handleNodeDataUpdate({ | handleNodeDataUpdate({ | ||||
| retrieval_model: { | retrieval_model: { | ||||
| ...nodeData?.data.retrieval_model, | ...nodeData?.data.retrieval_model, | ||||
| reranking_mode: hybridSearchMode, | reranking_mode: hybridSearchMode, | ||||
| reranking_enable: hybridSearchMode === HybridSearchModeEnum.RerankingModel, | |||||
| weights: nodeData?.data.retrieval_model.weights || defaultWeights, | |||||
| }, | }, | ||||
| }) | }) | ||||
| }, [getNodeData, handleNodeDataUpdate]) | |||||
| }, [getNodeData, getDefaultWeights, handleNodeDataUpdate]) | |||||
| const handleRerankingModelEnabledChange = useCallback((rerankingModelEnabled: boolean) => { | const handleRerankingModelEnabledChange = useCallback((rerankingModelEnabled: boolean) => { | ||||
| const nodeData = getNodeData() | const nodeData = getNodeData() | ||||
| retrieval_model: { | retrieval_model: { | ||||
| ...nodeData?.data.retrieval_model, | ...nodeData?.data.retrieval_model, | ||||
| weights: { | weights: { | ||||
| weight_type: 'weighted_score', | |||||
| weight_type: WeightedScoreEnum.Customized, | |||||
| vector_setting: { | vector_setting: { | ||||
| ...nodeData?.data.retrieval_model.weights?.vector_setting, | |||||
| vector_weight: weightedScore.value[0], | vector_weight: weightedScore.value[0], | ||||
| embedding_provider_name: '', | |||||
| embedding_model_name: '', | |||||
| }, | }, | ||||
| keyword_setting: { | keyword_setting: { | ||||
| keyword_weight: weightedScore.value[1], | keyword_weight: weightedScore.value[1], |
| toBeConfigured: 'To be configured', | toBeConfigured: 'To be configured', | ||||
| configureTip: 'Set up api-key or add model to use', | configureTip: 'Set up api-key or add model to use', | ||||
| installProvider: 'Install model providers', | installProvider: 'Install model providers', | ||||
| installDataSourceProvider: 'Install data source providers', | |||||
| discoverMore: 'Discover more in ', | discoverMore: 'Discover more in ', | ||||
| emptyProviderTitle: 'Model provider not set up', | emptyProviderTitle: 'Model provider not set up', | ||||
| emptyProviderTip: 'Please install a model provider first.', | emptyProviderTip: 'Please install a model provider first.', |
| aboutRetrieval: 'about retrieval method.', | aboutRetrieval: 'about retrieval method.', | ||||
| chunkIsRequired: 'Chunk structure is required', | chunkIsRequired: 'Chunk structure is required', | ||||
| indexMethodIsRequired: 'Index method is required', | indexMethodIsRequired: 'Index method is required', | ||||
| chunksVariableIsRequired: 'Chunks variable is required', | |||||
| embeddingModelIsRequired: 'Embedding model is required', | |||||
| retrievalSettingIsRequired: 'Retrieval setting is required', | retrievalSettingIsRequired: 'Retrieval setting is required', | ||||
| rerankingModelIsRequired: 'Reranking model is required', | |||||
| }, | }, | ||||
| }, | }, | ||||
| tracing: { | tracing: { |
| emptyProviderTitle: 'モデルプロバイダーが設定されていません', | emptyProviderTitle: 'モデルプロバイダーが設定されていません', | ||||
| discoverMore: 'もっと発見する', | discoverMore: 'もっと発見する', | ||||
| installProvider: 'モデルプロバイダーをインストールする', | installProvider: 'モデルプロバイダーをインストールする', | ||||
| installDataSourceProvider: 'データソースプロバイダーをインストールする', | |||||
| configureTip: 'API キーを設定するか、使用するモデルを追加してください', | configureTip: 'API キーを設定するか、使用するモデルを追加してください', | ||||
| toBeConfigured: '設定中', | toBeConfigured: '設定中', | ||||
| emptyProviderTip: '最初にモデルプロバイダーをインストールしてください。', | emptyProviderTip: '最初にモデルプロバイダーをインストールしてください。', |
| toBeConfigured: '待配置', | toBeConfigured: '待配置', | ||||
| configureTip: '请配置 API 密钥,添加模型。', | configureTip: '请配置 API 密钥,添加模型。', | ||||
| installProvider: '安装模型供应商', | installProvider: '安装模型供应商', | ||||
| installDataSourceProvider: '安装数据源供应商', | |||||
| discoverMore: '发现更多就在', | discoverMore: '发现更多就在', | ||||
| emptyProviderTitle: '尚未安装模型供应商', | emptyProviderTitle: '尚未安装模型供应商', | ||||
| emptyProviderTip: '请安装模型供应商。', | emptyProviderTip: '请安装模型供应商。', |
| aboutRetrieval: '关于知识检索。', | aboutRetrieval: '关于知识检索。', | ||||
| chunkIsRequired: '分段结构是必需的', | chunkIsRequired: '分段结构是必需的', | ||||
| indexMethodIsRequired: '索引方法是必需的', | indexMethodIsRequired: '索引方法是必需的', | ||||
| chunksVariableIsRequired: 'Chunks 变量是必需的', | |||||
| embeddingModelIsRequired: 'Embedding 模型是必需的', | |||||
| retrievalSettingIsRequired: '检索设置是必需的', | retrievalSettingIsRequired: '检索设置是必需的', | ||||
| rerankingModelIsRequired: 'Reranking 模型是必需的', | |||||
| }, | }, | ||||
| }, | }, | ||||
| tracing: { | tracing: { |