| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 | import {  useCallback,  useEffect,  useRef,  useState,} from 'react'import produce from 'immer'import { isEqual } from 'lodash-es'import { v4 as uuid4 } from 'uuid'import type { ValueSelector, Var } from '../../types'import { BlockEnum, VarType } from '../../types'import {  useIsChatMode,  useNodesReadOnly,  useWorkflow,} from '../../hooks'import type {  HandleAddCondition,  HandleRemoveCondition,  HandleToggleConditionLogicalOperator,  HandleUpdateCondition,  KnowledgeRetrievalNodeType,  MetadataFilteringModeEnum,  MultipleRetrievalConfig,} from './types'import {  ComparisonOperator,  LogicalOperator,  MetadataFilteringVariableType,} from './types'import {  getMultipleRetrievalConfig,  getSelectedDatasetsMode,} from './utils'import { RETRIEVE_TYPE } from '@/types/app'import { DATASET_DEFAULT } from '@/config'import type { DataSet } from '@/models/datasets'import { fetchDatasets } from '@/service/datasets'import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'import useOneStepRun from '@/app/components/workflow/nodes/_base/hooks/use-one-step-run'import { useCurrentProviderAndModel, useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'import useAvailableVarList from '@/app/components/workflow/nodes/_base/hooks/use-available-var-list'import { useDatasetsDetailStore } from '../../datasets-detail-store/store'const useConfig = (id: string, payload: KnowledgeRetrievalNodeType) => {  const { nodesReadOnly: readOnly } = useNodesReadOnly()  const isChatMode = useIsChatMode()  const { getBeforeNodesInSameBranch } = useWorkflow()  const startNode = getBeforeNodesInSameBranch(id).find(node => node.data.type === BlockEnum.Start)  const startNodeId = startNode?.id  const { inputs, setInputs: doSetInputs } = useNodeCrud<KnowledgeRetrievalNodeType>(id, payload)  const updateDatasetsDetail = useDatasetsDetailStore(s => s.updateDatasetsDetail)  const inputRef = useRef(inputs)  const setInputs = useCallback((s: KnowledgeRetrievalNodeType) => {    const newInputs = produce(s, (draft) => {      if (s.retrieval_mode === RETRIEVE_TYPE.multiWay)        delete draft.single_retrieval_config      else        delete draft.multiple_retrieval_config    })    // not work in pass to draft...    doSetInputs(newInputs)    inputRef.current = newInputs  }, [doSetInputs])  const handleQueryVarChange = useCallback((newVar: ValueSelector | string) => {    const newInputs = produce(inputs, (draft) => {      draft.query_variable_selector = newVar as ValueSelector    })    setInputs(newInputs)  }, [inputs, setInputs])  const {    currentProvider,    currentModel,  } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.textGeneration)  const {    modelList: rerankModelList,    defaultModel: rerankDefaultModel,  } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)  const {    currentModel: currentRerankModel,    currentProvider: currentRerankProvider,  } = useCurrentProviderAndModel(    rerankModelList,    rerankDefaultModel      ? {        ...rerankDefaultModel,        provider: rerankDefaultModel.provider.provider,      }      : undefined,  )  const handleModelChanged = useCallback((model: { provider: string; modelId: string; mode?: string }) => {    const newInputs = produce(inputRef.current, (draft) => {      if (!draft.single_retrieval_config) {        draft.single_retrieval_config = {          model: {            provider: '',            name: '',            mode: '',            completion_params: {},          },        }      }      const draftModel = draft.single_retrieval_config?.model      draftModel.provider = model.provider      draftModel.name = model.modelId      draftModel.mode = model.mode!    })    setInputs(newInputs)  }, [setInputs])  const handleCompletionParamsChange = useCallback((newParams: Record<string, any>) => {    // inputRef.current.single_retrieval_config?.model is old  when change the provider...    if (isEqual(newParams, inputRef.current.single_retrieval_config?.model.completion_params))      return    const newInputs = produce(inputRef.current, (draft) => {      if (!draft.single_retrieval_config) {        draft.single_retrieval_config = {          model: {            provider: '',            name: '',            mode: '',            completion_params: {},          },        }      }      draft.single_retrieval_config.model.completion_params = newParams    })    setInputs(newInputs)  }, [setInputs])  // set defaults models  useEffect(() => {    const inputs = inputRef.current    if (inputs.retrieval_mode === RETRIEVE_TYPE.multiWay && inputs.multiple_retrieval_config?.reranking_model?.provider && currentRerankModel && rerankDefaultModel)      return    if (inputs.retrieval_mode === RETRIEVE_TYPE.oneWay && inputs.single_retrieval_config?.model?.provider)      return    const newInput = produce(inputs, (draft) => {      if (currentProvider?.provider && currentModel?.model) {        const hasSetModel = draft.single_retrieval_config?.model?.provider        if (!hasSetModel) {          draft.single_retrieval_config = {            model: {              provider: currentProvider?.provider,              name: currentModel?.model,              mode: currentModel?.model_properties?.mode as string,              completion_params: {},            },          }        }      }      const multipleRetrievalConfig = draft.multiple_retrieval_config      draft.multiple_retrieval_config = {        top_k: multipleRetrievalConfig?.top_k || DATASET_DEFAULT.top_k,        score_threshold: multipleRetrievalConfig?.score_threshold,        reranking_model: multipleRetrievalConfig?.reranking_model,        reranking_mode: multipleRetrievalConfig?.reranking_mode,        weights: multipleRetrievalConfig?.weights,        reranking_enable: multipleRetrievalConfig?.reranking_enable !== undefined          ? multipleRetrievalConfig.reranking_enable          : Boolean(currentRerankModel && rerankDefaultModel),      }    })    setInputs(newInput)  // eslint-disable-next-line react-hooks/exhaustive-deps  }, [currentProvider?.provider, currentModel, currentRerankModel, rerankDefaultModel])  const [selectedDatasets, setSelectedDatasets] = useState<DataSet[]>([])  const [rerankModelOpen, setRerankModelOpen] = useState(false)  const handleRetrievalModeChange = useCallback((newMode: RETRIEVE_TYPE) => {    const newInputs = produce(inputs, (draft) => {      draft.retrieval_mode = newMode      if (newMode === RETRIEVE_TYPE.multiWay) {        const multipleRetrievalConfig = draft.multiple_retrieval_config        draft.multiple_retrieval_config = getMultipleRetrievalConfig(multipleRetrievalConfig!, selectedDatasets, selectedDatasets, {          provider: currentRerankProvider?.provider,          model: currentRerankModel?.model,        })      }      else {        const hasSetModel = draft.single_retrieval_config?.model?.provider        if (!hasSetModel) {          draft.single_retrieval_config = {            model: {              provider: currentProvider?.provider || '',              name: currentModel?.model || '',              mode: currentModel?.model_properties?.mode as string,              completion_params: {},            },          }        }      }    })    setInputs(newInputs)  }, [currentModel?.model, currentModel?.model_properties?.mode, currentProvider?.provider, inputs, setInputs, selectedDatasets, currentRerankModel, currentRerankProvider])  const handleMultipleRetrievalConfigChange = useCallback((newConfig: MultipleRetrievalConfig) => {    const newInputs = produce(inputs, (draft) => {      draft.multiple_retrieval_config = getMultipleRetrievalConfig(newConfig!, selectedDatasets, selectedDatasets, {        provider: currentRerankProvider?.provider,        model: currentRerankModel?.model,      })    })    setInputs(newInputs)  }, [inputs, setInputs, selectedDatasets, currentRerankModel, currentRerankProvider])  const [selectedDatasetsLoaded, setSelectedDatasetsLoaded] = useState(false)  // datasets  useEffect(() => {    (async () => {      const inputs = inputRef.current      const datasetIds = inputs.dataset_ids      if (datasetIds?.length > 0) {        const { data: dataSetsWithDetail } = await fetchDatasets({ url: '/datasets', params: { page: 1, ids: datasetIds } as any })        setSelectedDatasets(dataSetsWithDetail)      }      const newInputs = produce(inputs, (draft) => {        draft.dataset_ids = datasetIds      })      setInputs(newInputs)      setSelectedDatasetsLoaded(true)    })()  // eslint-disable-next-line react-hooks/exhaustive-deps  }, [])  useEffect(() => {    const inputs = inputRef.current    let query_variable_selector: ValueSelector = inputs.query_variable_selector    if (isChatMode && inputs.query_variable_selector.length === 0 && startNodeId)      query_variable_selector = [startNodeId, 'sys.query']    setInputs(produce(inputs, (draft) => {      draft.query_variable_selector = query_variable_selector    }))  // eslint-disable-next-line react-hooks/exhaustive-deps  }, [])  const handleOnDatasetsChange = useCallback((newDatasets: DataSet[]) => {    const {      mixtureHighQualityAndEconomic,      mixtureInternalAndExternal,      inconsistentEmbeddingModel,      allInternal,      allExternal,    } = getSelectedDatasetsMode(newDatasets)    const newInputs = produce(inputs, (draft) => {      draft.dataset_ids = newDatasets.map(d => d.id)      if (payload.retrieval_mode === RETRIEVE_TYPE.multiWay && newDatasets.length > 0) {        const multipleRetrievalConfig = draft.multiple_retrieval_config        draft.multiple_retrieval_config = getMultipleRetrievalConfig(multipleRetrievalConfig!, newDatasets, selectedDatasets, {          provider: currentRerankProvider?.provider,          model: currentRerankModel?.model,        })      }    })    updateDatasetsDetail(newDatasets)    setInputs(newInputs)    setSelectedDatasets(newDatasets)    if (      (allInternal && (mixtureHighQualityAndEconomic || inconsistentEmbeddingModel))      || mixtureInternalAndExternal      || allExternal    )      setRerankModelOpen(true)  }, [inputs, setInputs, payload.retrieval_mode, selectedDatasets, currentRerankModel, currentRerankProvider, updateDatasetsDetail])  const filterVar = useCallback((varPayload: Var) => {    return varPayload.type === VarType.string  }, [])  // single run  const {    isShowSingleRun,    hideSingleRun,    runningStatus,    handleRun,    handleStop,    runInputData,    setRunInputData,    runResult,  } = useOneStepRun<KnowledgeRetrievalNodeType>({    id,    data: inputs,    defaultRunInputData: {      query: '',    },  })  const query = runInputData.query  const setQuery = useCallback((newQuery: string) => {    setRunInputData({      ...runInputData,      query: newQuery,    })  }, [runInputData, setRunInputData])  const handleMetadataFilterModeChange = useCallback((newMode: MetadataFilteringModeEnum) => {    setInputs(produce(inputRef.current, (draft) => {      draft.metadata_filtering_mode = newMode    }))  }, [setInputs])  const handleAddCondition = useCallback<HandleAddCondition>(({ name, type }) => {    let operator: ComparisonOperator = ComparisonOperator.is    if (type === MetadataFilteringVariableType.number)      operator = ComparisonOperator.equal    const newCondition = {      id: uuid4(),      name,      comparison_operator: operator,    }    const newInputs = produce(inputRef.current, (draft) => {      if (draft.metadata_filtering_conditions) {        draft.metadata_filtering_conditions.conditions.push(newCondition)      }      else {        draft.metadata_filtering_conditions = {          logical_operator: LogicalOperator.and,          conditions: [newCondition],        }      }    })    setInputs(newInputs)  }, [setInputs])  const handleRemoveCondition = useCallback<HandleRemoveCondition>((id) => {    const conditions = inputRef.current.metadata_filtering_conditions?.conditions || []    const index = conditions.findIndex(c => c.id === id)    const newInputs = produce(inputRef.current, (draft) => {      if (index > -1)        draft.metadata_filtering_conditions?.conditions.splice(index, 1)    })    setInputs(newInputs)  }, [setInputs])  const handleUpdateCondition = useCallback<HandleUpdateCondition>((id, newCondition) => {    const conditions = inputRef.current.metadata_filtering_conditions?.conditions || []    const index = conditions.findIndex(c => c.id === id)    const newInputs = produce(inputRef.current, (draft) => {      if (index > -1)        draft.metadata_filtering_conditions!.conditions[index] = newCondition    })    setInputs(newInputs)  }, [setInputs])  const handleToggleConditionLogicalOperator = useCallback<HandleToggleConditionLogicalOperator>(() => {    const oldLogicalOperator = inputRef.current.metadata_filtering_conditions?.logical_operator    const newLogicalOperator = oldLogicalOperator === LogicalOperator.and ? LogicalOperator.or : LogicalOperator.and    const newInputs = produce(inputRef.current, (draft) => {      draft.metadata_filtering_conditions!.logical_operator = newLogicalOperator    })    setInputs(newInputs)  }, [setInputs])  const handleMetadataModelChange = useCallback((model: { provider: string; modelId: string; mode?: string }) => {    const newInputs = produce(inputRef.current, (draft) => {      draft.metadata_model_config = {        provider: model.provider,        name: model.modelId,        mode: model.mode || 'chat',        completion_params: draft.metadata_model_config?.completion_params || { temperature: 0.7 },      }    })    setInputs(newInputs)  }, [setInputs])  const handleMetadataCompletionParamsChange = useCallback((newParams: Record<string, any>) => {    const newInputs = produce(inputRef.current, (draft) => {      draft.metadata_model_config = {        ...draft.metadata_model_config!,        completion_params: newParams,      }    })    setInputs(newInputs)  }, [setInputs])  const filterStringVar = useCallback((varPayload: Var) => {    return [VarType.string].includes(varPayload.type)  }, [])  const {    availableVars: availableStringVars,    availableNodesWithParent: availableStringNodesWithParent,  } = useAvailableVarList(id, {    onlyLeafNodeVar: false,    filterVar: filterStringVar,  })  const filterNumberVar = useCallback((varPayload: Var) => {    return [VarType.number].includes(varPayload.type)  }, [])  const {    availableVars: availableNumberVars,    availableNodesWithParent: availableNumberNodesWithParent,  } = useAvailableVarList(id, {    onlyLeafNodeVar: false,    filterVar: filterNumberVar,  })  return {    readOnly,    inputs,    handleQueryVarChange,    filterVar,    handleRetrievalModeChange,    handleMultipleRetrievalConfigChange,    handleModelChanged,    handleCompletionParamsChange,    selectedDatasets: selectedDatasets.filter(d => d.name),    selectedDatasetsLoaded,    handleOnDatasetsChange,    isShowSingleRun,    hideSingleRun,    runningStatus,    handleRun,    handleStop,    query,    setQuery,    runResult,    rerankModelOpen,    setRerankModelOpen,    handleMetadataFilterModeChange,    handleUpdateCondition,    handleAddCondition,    handleRemoveCondition,    handleToggleConditionLogicalOperator,    handleMetadataModelChange,    handleMetadataCompletionParamsChange,    availableStringVars,    availableStringNodesWithParent,    availableNumberVars,    availableNumberNodesWithParent,  }}export default useConfig
 |