| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018 | 
							- 'use client'
 - import type { FC } from 'react'
 - import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
 - import useSWR from 'swr'
 - import { useTranslation } from 'react-i18next'
 - import { useContext } from 'use-context-selector'
 - import { usePathname } from 'next/navigation'
 - import produce from 'immer'
 - import { useBoolean, useGetState } from 'ahooks'
 - import { clone, isEqual } from 'lodash-es'
 - import { CodeBracketIcon } from '@heroicons/react/20/solid'
 - import { useShallow } from 'zustand/react/shallow'
 - import AgentSettingButton from '@/app/components/app/configuration/config/agent-setting-button'
 - import useAdvancedPromptConfig from '@/app/components/app/configuration/hooks/use-advanced-prompt-config'
 - import EditHistoryModal from '@/app/components/app/configuration/config-prompt/conversation-history/edit-modal'
 - import {
 -   useDebugWithSingleOrMultipleModel,
 -   useFormattingChangedDispatcher,
 - } from '@/app/components/app/configuration/debug/hooks'
 - import type { ModelAndParameter } from '@/app/components/app/configuration/debug/types'
 - import Button from '@/app/components/base/button'
 - import Loading from '@/app/components/base/loading'
 - import AppPublisher from '@/app/components/app/app-publisher/features-wrapper'
 - import type {
 -   AnnotationReplyConfig,
 -   DatasetConfigs,
 -   Inputs,
 -   ModelConfig,
 -   ModerationConfig,
 -   MoreLikeThisConfig,
 -   PromptConfig,
 -   PromptVariable,
 -   TextToSpeechConfig,
 - } from '@/models/debug'
 - import type { ExternalDataTool } from '@/models/common'
 - import type { DataSet } from '@/models/datasets'
 - import type { ModelConfig as BackendModelConfig, VisionSettings } from '@/types/app'
 - import ConfigContext from '@/context/debug-configuration'
 - import Config from '@/app/components/app/configuration/config'
 - import Debug from '@/app/components/app/configuration/debug'
 - import Confirm from '@/app/components/base/confirm'
 - import { ModelFeatureEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
 - import { ToastContext } from '@/app/components/base/toast'
 - import { fetchAppDetail, updateAppModelConfig } from '@/service/apps'
 - import { promptVariablesToUserInputsForm, userInputsFormToPromptVariables } from '@/utils/model-config'
 - import { fetchDatasets } from '@/service/datasets'
 - import { useProviderContext } from '@/context/provider-context'
 - import { AgentStrategy, AppType, ModelModeType, RETRIEVE_TYPE, Resolution, TransferMethod } from '@/types/app'
 - import { PromptMode } from '@/models/debug'
 - import { ANNOTATION_DEFAULT, DATASET_DEFAULT, DEFAULT_AGENT_SETTING, DEFAULT_CHAT_PROMPT_CONFIG, DEFAULT_COMPLETION_PROMPT_CONFIG } from '@/config'
 - import SelectDataSet from '@/app/components/app/configuration/dataset-config/select-dataset'
 - import { useModalContext } from '@/context/modal-context'
 - import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
 - import Drawer from '@/app/components/base/drawer'
 - import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
 - import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations'
 - import {
 -   useModelListAndDefaultModelAndCurrentProviderAndModel,
 -   useTextGenerationCurrentProviderAndModelAndModelList,
 - } from '@/app/components/header/account-setting/model-provider-page/hooks'
 - import { fetchCollectionList } from '@/service/tools'
 - import { type Collection } from '@/app/components/tools/types'
 - import { useStore as useAppStore } from '@/app/components/app/store'
 - import {
 -   getMultipleRetrievalConfig,
 -   getSelectedDatasetsMode,
 - } from '@/app/components/workflow/nodes/knowledge-retrieval/utils'
 - import { FeaturesProvider } from '@/app/components/base/features'
 - import type { Features as FeaturesData, FileUpload } from '@/app/components/base/features/types'
 - import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
 - import { SupportUploadFileTypes } from '@/app/components/workflow/types'
 - import NewFeaturePanel from '@/app/components/base/features/new-feature-panel'
 - import { fetchFileUploadConfig } from '@/service/common'
 - 
 - type PublishConfig = {
 -   modelConfig: ModelConfig
 -   completionParams: FormValue
 - }
 - 
 - const Configuration: FC = () => {
 -   const { t } = useTranslation()
 -   const { notify } = useContext(ToastContext)
 -   const { appDetail, showAppConfigureFeaturesModal, setAppSiderbarExpand, setShowAppConfigureFeaturesModal } = useAppStore(useShallow(state => ({
 -     appDetail: state.appDetail,
 -     setAppSiderbarExpand: state.setAppSiderbarExpand,
 -     showAppConfigureFeaturesModal: state.showAppConfigureFeaturesModal,
 -     setShowAppConfigureFeaturesModal: state.setShowAppConfigureFeaturesModal,
 -   })))
 -   const { data: fileUploadConfigResponse } = useSWR({ url: '/files/upload' }, fetchFileUploadConfig)
 - 
 -   const latestPublishedAt = useMemo(() => appDetail?.model_config.updated_at, [appDetail])
 -   const [formattingChanged, setFormattingChanged] = useState(false)
 -   const { setShowAccountSettingModal } = useModalContext()
 -   const [hasFetchedDetail, setHasFetchedDetail] = useState(false)
 -   const isLoading = !hasFetchedDetail
 -   const pathname = usePathname()
 -   const matched = pathname.match(/\/app\/([^/]+)/)
 -   const appId = (matched?.length && matched[1]) ? matched[1] : ''
 -   const [mode, setMode] = useState('')
 -   const [publishedConfig, setPublishedConfig] = useState<PublishConfig | null>(null)
 - 
 -   const [conversationId, setConversationId] = useState<string | null>('')
 - 
 -   const media = useBreakpoints()
 -   const isMobile = media === MediaType.mobile
 -   const [isShowDebugPanel, { setTrue: showDebugPanel, setFalse: hideDebugPanel }] = useBoolean(false)
 - 
 -   const [introduction, setIntroduction] = useState<string>('')
 -   const [suggestedQuestions, setSuggestedQuestions] = useState<string[]>([])
 -   const [controlClearChatMessage, setControlClearChatMessage] = useState(0)
 -   const [prevPromptConfig, setPrevPromptConfig] = useState<PromptConfig>({
 -     prompt_template: '',
 -     prompt_variables: [],
 -   })
 -   const [moreLikeThisConfig, setMoreLikeThisConfig] = useState<MoreLikeThisConfig>({
 -     enabled: false,
 -   })
 -   const [suggestedQuestionsAfterAnswerConfig, setSuggestedQuestionsAfterAnswerConfig] = useState<MoreLikeThisConfig>({
 -     enabled: false,
 -   })
 -   const [speechToTextConfig, setSpeechToTextConfig] = useState<MoreLikeThisConfig>({
 -     enabled: false,
 -   })
 -   const [textToSpeechConfig, setTextToSpeechConfig] = useState<TextToSpeechConfig>({
 -     enabled: false,
 -     voice: '',
 -     language: '',
 -   })
 -   const [citationConfig, setCitationConfig] = useState<MoreLikeThisConfig>({
 -     enabled: false,
 -   })
 -   const [annotationConfig, doSetAnnotationConfig] = useState<AnnotationReplyConfig>({
 -     id: '',
 -     enabled: false,
 -     score_threshold: ANNOTATION_DEFAULT.score_threshold,
 -     embedding_model: {
 -       embedding_provider_name: '',
 -       embedding_model_name: '',
 -     },
 -   })
 -   const formattingChangedDispatcher = useFormattingChangedDispatcher()
 -   const setAnnotationConfig = (config: AnnotationReplyConfig, notSetFormatChanged?: boolean) => {
 -     doSetAnnotationConfig(config)
 -     if (!notSetFormatChanged)
 -       formattingChangedDispatcher()
 -   }
 - 
 -   const [moderationConfig, setModerationConfig] = useState<ModerationConfig>({
 -     enabled: false,
 -   })
 -   const [externalDataToolsConfig, setExternalDataToolsConfig] = useState<ExternalDataTool[]>([])
 -   const [inputs, setInputs] = useState<Inputs>({})
 -   const [query, setQuery] = useState('')
 -   const [completionParams, doSetCompletionParams] = useState<FormValue>({})
 -   const [_, setTempStop, getTempStop] = useGetState<string[]>([])
 -   const setCompletionParams = (value: FormValue) => {
 -     const params = { ...value }
 - 
 -     // eslint-disable-next-line @typescript-eslint/no-use-before-define
 -     if ((!params.stop || params.stop.length === 0) && (modeModeTypeRef.current === ModelModeType.completion)) {
 -       params.stop = getTempStop()
 -       setTempStop([])
 -     }
 -     doSetCompletionParams(params)
 -   }
 - 
 -   const [modelConfig, doSetModelConfig] = useState<ModelConfig>({
 -     provider: 'openai',
 -     model_id: 'gpt-3.5-turbo',
 -     mode: ModelModeType.unset,
 -     configs: {
 -       prompt_template: '',
 -       prompt_variables: [] as PromptVariable[],
 -     },
 -     more_like_this: null,
 -     opening_statement: '',
 -     suggested_questions: [],
 -     sensitive_word_avoidance: null,
 -     speech_to_text: null,
 -     text_to_speech: null,
 -     file_upload: null,
 -     suggested_questions_after_answer: null,
 -     retriever_resource: null,
 -     annotation_reply: null,
 -     dataSets: [],
 -     agentConfig: DEFAULT_AGENT_SETTING,
 -   })
 - 
 -   const isAgent = mode === 'agent-chat'
 - 
 -   const isOpenAI = modelConfig.provider === 'openai'
 - 
 -   const [collectionList, setCollectionList] = useState<Collection[]>([])
 -   useEffect(() => {
 - 
 -   }, [])
 -   const [datasetConfigs, setDatasetConfigs] = useState<DatasetConfigs>({
 -     retrieval_model: RETRIEVE_TYPE.multiWay,
 -     reranking_model: {
 -       reranking_provider_name: '',
 -       reranking_model_name: '',
 -     },
 -     top_k: DATASET_DEFAULT.top_k,
 -     score_threshold_enabled: false,
 -     score_threshold: DATASET_DEFAULT.score_threshold,
 -     datasets: {
 -       datasets: [],
 -     },
 -   })
 - 
 -   const setModelConfig = (newModelConfig: ModelConfig) => {
 -     doSetModelConfig(newModelConfig)
 -   }
 - 
 -   const modelModeType = modelConfig.mode
 -   const modeModeTypeRef = useRef(modelModeType)
 -   useEffect(() => {
 -     modeModeTypeRef.current = modelModeType
 -   }, [modelModeType])
 - 
 -   const [dataSets, setDataSets] = useState<DataSet[]>([])
 -   const contextVar = modelConfig.configs.prompt_variables.find((item: any) => item.is_context_var)?.key
 -   const hasSetContextVar = !!contextVar
 -   const [isShowSelectDataSet, { setTrue: showSelectDataSet, setFalse: hideSelectDataSet }] = useBoolean(false)
 -   const selectedIds = dataSets.map(item => item.id)
 -   const [rerankSettingModalOpen, setRerankSettingModalOpen] = useState(false)
 -   const {
 -     currentModel: currentRerankModel,
 -   } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)
 -   const handleSelect = (data: DataSet[]) => {
 -     if (isEqual(data.map(item => item.id), dataSets.map(item => item.id))) {
 -       hideSelectDataSet()
 -       return
 -     }
 - 
 -     formattingChangedDispatcher()
 -     let newDatasets = data
 -     if (data.find(item => !item.name)) { // has not loaded selected dataset
 -       const newSelected = produce(data, (draft: any) => {
 -         data.forEach((item, index) => {
 -           if (!item.name) { // not fetched database
 -             const newItem = dataSets.find(i => i.id === item.id)
 -             if (newItem)
 -               draft[index] = newItem
 -           }
 -         })
 -       })
 -       setDataSets(newSelected)
 -       newDatasets = newSelected
 -     }
 -     else {
 -       setDataSets(data)
 -     }
 -     hideSelectDataSet()
 -     const {
 -       allExternal,
 -       allInternal,
 -       mixtureInternalAndExternal,
 -       mixtureHighQualityAndEconomic,
 -       inconsistentEmbeddingModel,
 -     } = getSelectedDatasetsMode(newDatasets)
 - 
 -     if (
 -       (allInternal && (mixtureHighQualityAndEconomic || inconsistentEmbeddingModel))
 -       || mixtureInternalAndExternal
 -       || allExternal
 -     )
 -       setRerankSettingModalOpen(true)
 - 
 -     const { datasets, retrieval_model, score_threshold_enabled, ...restConfigs } = datasetConfigs
 - 
 -     const retrievalConfig = getMultipleRetrievalConfig({
 -       top_k: restConfigs.top_k,
 -       score_threshold: restConfigs.score_threshold,
 -       reranking_model: restConfigs.reranking_model && {
 -         provider: restConfigs.reranking_model.reranking_provider_name,
 -         model: restConfigs.reranking_model.reranking_model_name,
 -       },
 -       reranking_mode: restConfigs.reranking_mode,
 -       weights: restConfigs.weights,
 -       reranking_enable: restConfigs.reranking_enable,
 -     }, newDatasets, dataSets, !!currentRerankModel)
 - 
 -     setDatasetConfigs({
 -       ...retrievalConfig,
 -       reranking_model: restConfigs.reranking_model && {
 -         reranking_provider_name: restConfigs.reranking_model.reranking_provider_name,
 -         reranking_model_name: restConfigs.reranking_model.reranking_model_name,
 -       },
 -       retrieval_model,
 -       score_threshold_enabled,
 -       datasets,
 -     })
 -   }
 - 
 -   const [isShowHistoryModal, { setTrue: showHistoryModal, setFalse: hideHistoryModal }] = useBoolean(false)
 - 
 -   const syncToPublishedConfig = (_publishedConfig: PublishConfig) => {
 -     const modelConfig = _publishedConfig.modelConfig
 -     setModelConfig(_publishedConfig.modelConfig)
 -     setCompletionParams(_publishedConfig.completionParams)
 -     setDataSets(modelConfig.dataSets || [])
 -     // reset feature
 -     setIntroduction(modelConfig.opening_statement!)
 -     setMoreLikeThisConfig(modelConfig.more_like_this || {
 -       enabled: false,
 -     })
 -     setSuggestedQuestionsAfterAnswerConfig(modelConfig.suggested_questions_after_answer || {
 -       enabled: false,
 -     })
 -     setSpeechToTextConfig(modelConfig.speech_to_text || {
 -       enabled: false,
 -     })
 -     setTextToSpeechConfig(modelConfig.text_to_speech || {
 -       enabled: false,
 -       voice: '',
 -       language: '',
 -     })
 -     setCitationConfig(modelConfig.retriever_resource || {
 -       enabled: false,
 -     })
 -   }
 - 
 -   const { isAPIKeySet } = useProviderContext()
 -   const {
 -     currentModel: currModel,
 -     textGenerationModelList,
 -   } = useTextGenerationCurrentProviderAndModelAndModelList(
 -     {
 -       provider: modelConfig.provider,
 -       model: modelConfig.model_id,
 -     },
 -   )
 - 
 -   const isFunctionCall = (() => {
 -     const features = currModel?.features
 -     if (!features)
 -       return false
 -     return features.includes(ModelFeatureEnum.toolCall) || features.includes(ModelFeatureEnum.multiToolCall)
 -   })()
 - 
 -   // Fill old app data missing model mode.
 -   useEffect(() => {
 -     if (hasFetchedDetail && !modelModeType) {
 -       const mode = currModel?.model_properties.mode as (ModelModeType | undefined)
 -       if (mode) {
 -         const newModelConfig = produce(modelConfig, (draft: ModelConfig) => {
 -           draft.mode = mode
 -         })
 -         setModelConfig(newModelConfig)
 -       }
 -     }
 -   }, [textGenerationModelList, hasFetchedDetail, modelModeType, currModel, modelConfig])
 - 
 -   const [promptMode, doSetPromptMode] = useState(PromptMode.simple)
 -   const isAdvancedMode = promptMode === PromptMode.advanced
 -   const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true)
 -   const setPromptMode = async (mode: PromptMode) => {
 -     if (mode === PromptMode.advanced) {
 -       // eslint-disable-next-line @typescript-eslint/no-use-before-define
 -       await migrateToDefaultPrompt()
 -       setCanReturnToSimpleMode(true)
 -     }
 - 
 -     doSetPromptMode(mode)
 -   }
 -   const [visionConfig, doSetVisionConfig] = useState({
 -     enabled: false,
 -     number_limits: 2,
 -     detail: Resolution.low,
 -     transfer_methods: [TransferMethod.local_file],
 -   })
 - 
 -   const handleSetVisionConfig = (config: VisionSettings, notNoticeFormattingChanged?: boolean) => {
 -     doSetVisionConfig({
 -       enabled: config.enabled || false,
 -       number_limits: config.number_limits || 2,
 -       detail: config.detail || Resolution.low,
 -       transfer_methods: config.transfer_methods || [TransferMethod.local_file],
 -     })
 -     if (!notNoticeFormattingChanged)
 -       formattingChangedDispatcher()
 -   }
 - 
 -   const {
 -     chatPromptConfig,
 -     setChatPromptConfig,
 -     completionPromptConfig,
 -     setCompletionPromptConfig,
 -     currentAdvancedPrompt,
 -     setCurrentAdvancedPrompt,
 -     hasSetBlockStatus,
 -     setConversationHistoriesRole,
 -     migrateToDefaultPrompt,
 -   } = useAdvancedPromptConfig({
 -     appMode: mode,
 -     modelName: modelConfig.model_id,
 -     promptMode,
 -     modelModeType,
 -     prePrompt: modelConfig.configs.prompt_template,
 -     hasSetDataSet: dataSets.length > 0,
 -     onUserChangedPrompt: () => {
 -       setCanReturnToSimpleMode(false)
 -     },
 -     completionParams,
 -     setCompletionParams,
 -     setStop: setTempStop,
 -   })
 -   const setModel = async ({
 -     modelId,
 -     provider,
 -     mode: modeMode,
 -     features,
 -   }: { modelId: string; provider: string; mode: string; features: string[] }) => {
 -     if (isAdvancedMode) {
 -       const appMode = mode
 - 
 -       if (modeMode === ModelModeType.completion) {
 -         if (appMode !== AppType.completion) {
 -           if (!completionPromptConfig.prompt?.text || !completionPromptConfig.conversation_histories_role.assistant_prefix || !completionPromptConfig.conversation_histories_role.user_prefix)
 -             await migrateToDefaultPrompt(true, ModelModeType.completion)
 -         }
 -         else {
 -           if (!completionPromptConfig.prompt?.text)
 -             await migrateToDefaultPrompt(true, ModelModeType.completion)
 -         }
 -       }
 -       if (modeMode === ModelModeType.chat) {
 -         if (chatPromptConfig.prompt.length === 0)
 -           await migrateToDefaultPrompt(true, ModelModeType.chat)
 -       }
 -     }
 -     const newModelConfig = produce(modelConfig, (draft: ModelConfig) => {
 -       draft.provider = provider
 -       draft.model_id = modelId
 -       draft.mode = modeMode as ModelModeType
 -     })
 - 
 -     setModelConfig(newModelConfig)
 -     const supportVision = features && features.includes(ModelFeatureEnum.vision)
 - 
 -     handleSetVisionConfig({
 -       ...visionConfig,
 -       enabled: supportVision,
 -     }, true)
 -     setCompletionParams({})
 -   }
 - 
 -   const isShowVisionConfig = !!currModel?.features?.includes(ModelFeatureEnum.vision)
 - 
 -   // *** web app features ***
 -   const featuresData: FeaturesData = useMemo(() => {
 -     return {
 -       moreLikeThis: modelConfig.more_like_this || { enabled: false },
 -       opening: {
 -         enabled: !!modelConfig.opening_statement,
 -         opening_statement: modelConfig.opening_statement || '',
 -         suggested_questions: modelConfig.suggested_questions || [],
 -       },
 -       moderation: modelConfig.sensitive_word_avoidance || { enabled: false },
 -       speech2text: modelConfig.speech_to_text || { enabled: false },
 -       text2speech: modelConfig.text_to_speech || { enabled: false },
 -       file: {
 -         image: {
 -           detail: modelConfig.file_upload?.image?.detail || Resolution.high,
 -           enabled: !!modelConfig.file_upload?.image?.enabled,
 -           number_limits: modelConfig.file_upload?.image?.number_limits || 3,
 -           transfer_methods: modelConfig.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'],
 -         },
 -         enabled: !!(modelConfig.file_upload?.enabled || modelConfig.file_upload?.image?.enabled),
 -         allowed_file_types: modelConfig.file_upload?.allowed_file_types || [SupportUploadFileTypes.image, SupportUploadFileTypes.video],
 -         allowed_file_extensions: modelConfig.file_upload?.allowed_file_extensions || [...FILE_EXTS[SupportUploadFileTypes.image], ...FILE_EXTS[SupportUploadFileTypes.video]].map(ext => `.${ext}`),
 -         allowed_file_upload_methods: modelConfig.file_upload?.allowed_file_upload_methods || modelConfig.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'],
 -         number_limits: modelConfig.file_upload?.number_limits || modelConfig.file_upload?.image?.number_limits || 3,
 -         fileUploadConfig: fileUploadConfigResponse,
 -       } as FileUpload,
 -       suggested: modelConfig.suggested_questions_after_answer || { enabled: false },
 -       citation: modelConfig.retriever_resource || { enabled: false },
 -       annotationReply: modelConfig.annotation_reply || { enabled: false },
 -     }
 -   }, [fileUploadConfigResponse, modelConfig])
 -   const handleFeaturesChange = useCallback((flag: any) => {
 -     setShowAppConfigureFeaturesModal(true)
 -     if (flag)
 -       formattingChangedDispatcher()
 -   }, [formattingChangedDispatcher, setShowAppConfigureFeaturesModal])
 -   const handleAddPromptVariable = useCallback((variable: PromptVariable[]) => {
 -     const newModelConfig = produce(modelConfig, (draft: ModelConfig) => {
 -       draft.configs.prompt_variables = variable
 -     })
 -     setModelConfig(newModelConfig)
 -   }, [modelConfig])
 - 
 -   useEffect(() => {
 -     (async () => {
 -       const collectionList = await fetchCollectionList()
 -       setCollectionList(collectionList)
 -       fetchAppDetail({ url: '/apps', id: appId }).then(async (res: any) => {
 -         setMode(res.mode)
 -         const modelConfig = res.model_config
 -         const promptMode = modelConfig.prompt_type === PromptMode.advanced ? PromptMode.advanced : PromptMode.simple
 -         doSetPromptMode(promptMode)
 -         if (promptMode === PromptMode.advanced) {
 -           if (modelConfig.chat_prompt_config && modelConfig.chat_prompt_config.prompt.length > 0)
 -             setChatPromptConfig(modelConfig.chat_prompt_config)
 -           else
 -             setChatPromptConfig(clone(DEFAULT_CHAT_PROMPT_CONFIG) as any)
 -           setCompletionPromptConfig(modelConfig.completion_prompt_config || clone(DEFAULT_COMPLETION_PROMPT_CONFIG) as any)
 -           setCanReturnToSimpleMode(false)
 -         }
 - 
 -         const model = res.model_config.model
 - 
 -         let datasets: any = null
 -         // old dataset struct
 -         if (modelConfig.agent_mode?.tools?.find(({ dataset }: any) => dataset?.enabled))
 -           datasets = modelConfig.agent_mode?.tools.filter(({ dataset }: any) => dataset?.enabled)
 -         // new dataset struct
 -         else if (modelConfig.dataset_configs.datasets?.datasets?.length > 0)
 -           datasets = modelConfig.dataset_configs?.datasets?.datasets
 - 
 -         if (dataSets && datasets?.length && datasets?.length > 0) {
 -           const { data: dataSetsWithDetail } = await fetchDatasets({ url: '/datasets', params: { page: 1, ids: datasets.map(({ dataset }: any) => dataset.id) } })
 -           datasets = dataSetsWithDetail
 -           setDataSets(datasets)
 -         }
 - 
 -         setIntroduction(modelConfig.opening_statement)
 -         setSuggestedQuestions(modelConfig.suggested_questions || [])
 -         if (modelConfig.more_like_this)
 -           setMoreLikeThisConfig(modelConfig.more_like_this)
 - 
 -         if (modelConfig.suggested_questions_after_answer)
 -           setSuggestedQuestionsAfterAnswerConfig(modelConfig.suggested_questions_after_answer)
 - 
 -         if (modelConfig.speech_to_text)
 -           setSpeechToTextConfig(modelConfig.speech_to_text)
 - 
 -         if (modelConfig.text_to_speech)
 -           setTextToSpeechConfig(modelConfig.text_to_speech)
 - 
 -         if (modelConfig.retriever_resource)
 -           setCitationConfig(modelConfig.retriever_resource)
 - 
 -         if (modelConfig.annotation_reply)
 -           setAnnotationConfig(modelConfig.annotation_reply, true)
 - 
 -         if (modelConfig.sensitive_word_avoidance)
 -           setModerationConfig(modelConfig.sensitive_word_avoidance)
 - 
 -         if (modelConfig.external_data_tools)
 -           setExternalDataToolsConfig(modelConfig.external_data_tools)
 - 
 -         const config = {
 -           modelConfig: {
 -             provider: model.provider,
 -             model_id: model.name,
 -             mode: model.mode,
 -             configs: {
 -               prompt_template: modelConfig.pre_prompt || '',
 -               prompt_variables: userInputsFormToPromptVariables(
 -                 [
 -                   ...modelConfig.user_input_form,
 -                   ...(
 -                     modelConfig.external_data_tools?.length
 -                       ? modelConfig.external_data_tools.map((item: any) => {
 -                         return {
 -                           external_data_tool: {
 -                             variable: item.variable as string,
 -                             label: item.label as string,
 -                             enabled: item.enabled,
 -                             type: item.type as string,
 -                             config: item.config,
 -                             required: true,
 -                             icon: item.icon,
 -                             icon_background: item.icon_background,
 -                           },
 -                         }
 -                       })
 -                       : []
 -                   ),
 -                 ],
 -                 modelConfig.dataset_query_variable,
 -               ),
 -             },
 -             more_like_this: modelConfig.more_like_this,
 -             opening_statement: modelConfig.opening_statement,
 -             suggested_questions: modelConfig.suggested_questions,
 -             sensitive_word_avoidance: modelConfig.sensitive_word_avoidance,
 -             speech_to_text: modelConfig.speech_to_text,
 -             text_to_speech: modelConfig.text_to_speech,
 -             file_upload: modelConfig.file_upload,
 -             suggested_questions_after_answer: modelConfig.suggested_questions_after_answer,
 -             retriever_resource: modelConfig.retriever_resource,
 -             annotation_reply: modelConfig.annotation_reply,
 -             external_data_tools: modelConfig.external_data_tools,
 -             dataSets: datasets || [],
 -             // eslint-disable-next-line multiline-ternary
 -             agentConfig: res.mode === 'agent-chat' ? {
 -               max_iteration: DEFAULT_AGENT_SETTING.max_iteration,
 -               ...modelConfig.agent_mode,
 -               // remove dataset
 -               enabled: true, // modelConfig.agent_mode?.enabled is not correct. old app: the value of app with dataset's is always true
 -               tools: modelConfig.agent_mode?.tools.filter((tool: any) => {
 -                 return !tool.dataset
 -               }).map((tool: any) => {
 -                 return {
 -                   ...tool,
 -                   isDeleted: res.deleted_tools?.includes(tool.tool_name),
 -                   notAuthor: collectionList.find(c => tool.provider_id === c.id)?.is_team_authorization === false,
 -                 }
 -               }),
 -             } : DEFAULT_AGENT_SETTING,
 -           },
 -           completionParams: model.completion_params,
 -         }
 - 
 -         if (modelConfig.file_upload)
 -           handleSetVisionConfig(modelConfig.file_upload.image, true)
 - 
 -         syncToPublishedConfig(config)
 -         setPublishedConfig(config)
 -         const retrievalConfig = getMultipleRetrievalConfig(modelConfig.dataset_configs, datasets, datasets, !!currentRerankModel)
 -         setDatasetConfigs({
 -           retrieval_model: RETRIEVE_TYPE.multiWay,
 -           ...modelConfig.dataset_configs,
 -           ...retrievalConfig,
 -         })
 -         setHasFetchedDetail(true)
 -       })
 -     })()
 -     // eslint-disable-next-line react-hooks/exhaustive-deps
 -   }, [appId])
 - 
 -   const promptEmpty = (() => {
 -     if (mode !== AppType.completion)
 -       return false
 - 
 -     if (isAdvancedMode) {
 -       if (modelModeType === ModelModeType.chat)
 -         return chatPromptConfig.prompt.every(({ text }: any) => !text)
 - 
 -       else
 -         return !completionPromptConfig.prompt?.text
 -     }
 - 
 -     else { return !modelConfig.configs.prompt_template }
 -   })()
 -   const cannotPublish = (() => {
 -     if (mode !== AppType.completion) {
 -       if (!isAdvancedMode)
 -         return false
 - 
 -       if (modelModeType === ModelModeType.completion) {
 -         if (!hasSetBlockStatus.history || !hasSetBlockStatus.query)
 -           return true
 - 
 -         return false
 -       }
 - 
 -       return false
 -     }
 -     else { return promptEmpty }
 -   })()
 -   const contextVarEmpty = mode === AppType.completion && dataSets.length > 0 && !hasSetContextVar
 -   const onPublish = async (modelAndParameter?: ModelAndParameter, features?: FeaturesData) => {
 -     const modelId = modelAndParameter?.model || modelConfig.model_id
 -     const promptTemplate = modelConfig.configs.prompt_template
 -     const promptVariables = modelConfig.configs.prompt_variables
 - 
 -     if (promptEmpty) {
 -       notify({ type: 'error', message: t('appDebug.otherError.promptNoBeEmpty') })
 -       return
 -     }
 -     if (isAdvancedMode && mode !== AppType.completion) {
 -       if (modelModeType === ModelModeType.completion) {
 -         if (!hasSetBlockStatus.history) {
 -           notify({ type: 'error', message: t('appDebug.otherError.historyNoBeEmpty') })
 -           return
 -         }
 -         if (!hasSetBlockStatus.query) {
 -           notify({ type: 'error', message: t('appDebug.otherError.queryNoBeEmpty') })
 -           return
 -         }
 -       }
 -     }
 -     if (contextVarEmpty) {
 -       notify({ type: 'error', message: t('appDebug.feature.dataSet.queryVariable.contextVarNotEmpty') })
 -       return
 -     }
 -     const postDatasets = dataSets.map(({ id }) => ({
 -       dataset: {
 -         enabled: true,
 -         id,
 -       },
 -     }))
 - 
 -     const fileUpload = { ...features?.file }
 -     delete fileUpload?.fileUploadConfig
 - 
 -     // new model config data struct
 -     const data: BackendModelConfig = {
 -       // Simple Mode prompt
 -       pre_prompt: !isAdvancedMode ? promptTemplate : '',
 -       prompt_type: promptMode,
 -       chat_prompt_config: {},
 -       completion_prompt_config: {},
 -       user_input_form: promptVariablesToUserInputsForm(promptVariables),
 -       dataset_query_variable: contextVar || '',
 -       //  features
 -       more_like_this: features?.moreLikeThis as any,
 -       opening_statement: features?.opening?.enabled ? (features.opening?.opening_statement || '') : '',
 -       suggested_questions: features?.opening?.enabled ? (features.opening?.suggested_questions || []) : [],
 -       sensitive_word_avoidance: features?.moderation as any,
 -       speech_to_text: features?.speech2text as any,
 -       text_to_speech: features?.text2speech as any,
 -       file_upload: fileUpload as any,
 -       suggested_questions_after_answer: features?.suggested as any,
 -       retriever_resource: features?.citation as any,
 -       agent_mode: {
 -         ...modelConfig.agentConfig,
 -         strategy: isFunctionCall ? AgentStrategy.functionCall : AgentStrategy.react,
 -       },
 -       model: {
 -         provider: modelAndParameter?.provider || modelConfig.provider,
 -         name: modelId,
 -         mode: modelConfig.mode,
 -         completion_params: modelAndParameter?.parameters || completionParams as any,
 -       },
 -       dataset_configs: {
 -         ...datasetConfigs,
 -         datasets: {
 -           datasets: [...postDatasets],
 -         } as any,
 -       },
 -     }
 - 
 -     if (isAdvancedMode) {
 -       data.chat_prompt_config = chatPromptConfig
 -       data.completion_prompt_config = completionPromptConfig
 -     }
 - 
 -     await updateAppModelConfig({ url: `/apps/${appId}/model-config`, body: data })
 -     const newModelConfig = produce(modelConfig, (draft: any) => {
 -       draft.opening_statement = introduction
 -       draft.more_like_this = moreLikeThisConfig
 -       draft.suggested_questions_after_answer = suggestedQuestionsAfterAnswerConfig
 -       draft.speech_to_text = speechToTextConfig
 -       draft.text_to_speech = textToSpeechConfig
 -       draft.retriever_resource = citationConfig
 -       draft.dataSets = dataSets
 -     })
 -     setPublishedConfig({
 -       modelConfig: newModelConfig,
 -       completionParams,
 -     })
 -     notify({ type: 'success', message: t('common.api.success') })
 - 
 -     setCanReturnToSimpleMode(false)
 -     return true
 -   }
 - 
 -   const [showUseGPT4Confirm, setShowUseGPT4Confirm] = useState(false)
 - 
 -   const {
 -     debugWithMultipleModel,
 -     multipleModelConfigs,
 -     handleMultipleModelConfigsChange,
 -   } = useDebugWithSingleOrMultipleModel(appId)
 - 
 -   const handleDebugWithMultipleModelChange = () => {
 -     handleMultipleModelConfigsChange(
 -       true,
 -       [
 -         { id: `${Date.now()}`, model: modelConfig.model_id, provider: modelConfig.provider, parameters: completionParams },
 -         { id: `${Date.now()}-no-repeat`, model: '', provider: '', parameters: {} },
 -       ],
 -     )
 -     setAppSiderbarExpand('collapse')
 -   }
 - 
 -   if (isLoading) {
 -     return <div className='flex items-center justify-center h-full'>
 -       <Loading type='area' />
 -     </div>
 -   }
 - 
 -   return (
 -     <ConfigContext.Provider value={{
 -       appId,
 -       isAPIKeySet,
 -       isTrailFinished: false,
 -       mode,
 -       modelModeType,
 -       promptMode,
 -       isAdvancedMode,
 -       isAgent,
 -       isOpenAI,
 -       isFunctionCall,
 -       collectionList,
 -       setPromptMode,
 -       canReturnToSimpleMode,
 -       setCanReturnToSimpleMode,
 -       chatPromptConfig,
 -       completionPromptConfig,
 -       currentAdvancedPrompt,
 -       setCurrentAdvancedPrompt,
 -       conversationHistoriesRole: completionPromptConfig.conversation_histories_role,
 -       showHistoryModal,
 -       setConversationHistoriesRole,
 -       hasSetBlockStatus,
 -       conversationId,
 -       introduction,
 -       setIntroduction,
 -       suggestedQuestions,
 -       setSuggestedQuestions,
 -       setConversationId,
 -       controlClearChatMessage,
 -       setControlClearChatMessage,
 -       prevPromptConfig,
 -       setPrevPromptConfig,
 -       moreLikeThisConfig,
 -       setMoreLikeThisConfig,
 -       suggestedQuestionsAfterAnswerConfig,
 -       setSuggestedQuestionsAfterAnswerConfig,
 -       speechToTextConfig,
 -       setSpeechToTextConfig,
 -       textToSpeechConfig,
 -       setTextToSpeechConfig,
 -       citationConfig,
 -       setCitationConfig,
 -       annotationConfig,
 -       setAnnotationConfig,
 -       moderationConfig,
 -       setModerationConfig,
 -       externalDataToolsConfig,
 -       setExternalDataToolsConfig,
 -       formattingChanged,
 -       setFormattingChanged,
 -       inputs,
 -       setInputs,
 -       query,
 -       setQuery,
 -       completionParams,
 -       setCompletionParams,
 -       modelConfig,
 -       setModelConfig,
 -       showSelectDataSet,
 -       dataSets,
 -       setDataSets,
 -       datasetConfigs,
 -       setDatasetConfigs,
 -       hasSetContextVar,
 -       isShowVisionConfig,
 -       visionConfig,
 -       setVisionConfig: handleSetVisionConfig,
 -       rerankSettingModalOpen,
 -       setRerankSettingModalOpen,
 -     }}
 -     >
 -       <FeaturesProvider features={featuresData}>
 -         <>
 -           <div className="flex flex-col h-full">
 -             <div className='relative flex grow h-[200px] pt-14'>
 -               {/* Header */}
 -               <div className='absolute top-0 left-0 w-full bg-white h-14'>
 -                 <div className='flex items-center justify-between px-6 h-14'>
 -                   <div className='flex items-center'>
 -                     <div className='text-base font-semibold leading-6 text-gray-900'>{t('appDebug.orchestrate')}</div>
 -                     <div className='flex items-center h-[14px] space-x-1 text-xs'>
 -                       {isAdvancedMode && (
 -                         <div className='ml-1 flex items-center h-5 px-1.5 border border-gray-100 rounded-md text-[11px] font-medium text-gray-500 uppercase'>{t('appDebug.promptMode.advanced')}</div>
 -                       )}
 -                     </div>
 -                   </div>
 -                   <div className='flex items-center'>
 -                     {/* Agent Setting */}
 -                     {isAgent && (
 -                       <AgentSettingButton
 -                         isChatModel={modelConfig.mode === ModelModeType.chat}
 -                         agentConfig={modelConfig.agentConfig}
 - 
 -                         isFunctionCall={isFunctionCall}
 -                         onAgentSettingChange={(config) => {
 -                           const nextConfig = produce(modelConfig, (draft: ModelConfig) => {
 -                             draft.agentConfig = config
 -                           })
 -                           setModelConfig(nextConfig)
 -                         }}
 -                       />
 -                     )}
 -                     {/* Model and Parameters */}
 -                     {!debugWithMultipleModel && (
 -                       <>
 -                         <ModelParameterModal
 -                           isAdvancedMode={isAdvancedMode}
 -                           mode={mode}
 -                           provider={modelConfig.provider}
 -                           completionParams={completionParams}
 -                           modelId={modelConfig.model_id}
 -                           setModel={setModel as any}
 -                           onCompletionParamsChange={(newParams: FormValue) => {
 -                             setCompletionParams(newParams)
 -                           }}
 -                           debugWithMultipleModel={debugWithMultipleModel}
 -                           onDebugWithMultipleModelChange={handleDebugWithMultipleModelChange}
 -                         />
 -                         <div className='mx-2 w-[1px] h-[14px] bg-gray-200'></div>
 -                       </>
 -                     )}
 -                     {isMobile && (
 -                       <Button className='!h-8 !text-[13px] font-medium' onClick={showDebugPanel}>
 -                         <span className='mr-1'>{t('appDebug.operation.debugConfig')}</span>
 -                         <CodeBracketIcon className="w-4 h-4 text-gray-500" />
 -                       </Button>
 -                     )}
 -                     <AppPublisher {...{
 -                       publishDisabled: cannotPublish,
 -                       publishedAt: (latestPublishedAt || 0) * 1000,
 -                       debugWithMultipleModel,
 -                       multipleModelConfigs,
 -                       onPublish,
 -                       publishedConfig: publishedConfig!,
 -                       resetAppConfig: () => syncToPublishedConfig(publishedConfig!),
 -                     }} />
 -                   </div>
 -                 </div>
 -               </div>
 -               <div className={`w-full sm:w-1/2 shrink-0 flex flex-col h-full ${debugWithMultipleModel && 'max-w-[560px]'}`}>
 -                 <Config />
 -               </div>
 -               {!isMobile && <div className="relative flex flex-col w-1/2 h-full overflow-y-auto grow " style={{ borderColor: 'rgba(0, 0, 0, 0.02)' }}>
 -                 <div className='grow flex flex-col border-t-[0.5px] border-l-[0.5px] rounded-tl-2xl border-components-panel-border bg-chatbot-bg '>
 -                   <Debug
 -                     isAPIKeySet={isAPIKeySet}
 -                     onSetting={() => setShowAccountSettingModal({ payload: 'provider' })}
 -                     inputs={inputs}
 -                     modelParameterParams={{
 -                       setModel: setModel as any,
 -                       onCompletionParamsChange: setCompletionParams,
 -                     }}
 -                     debugWithMultipleModel={debugWithMultipleModel}
 -                     multipleModelConfigs={multipleModelConfigs}
 -                     onMultipleModelConfigsChange={handleMultipleModelConfigsChange}
 -                   />
 -                 </div>
 -               </div>}
 -             </div>
 -           </div>
 -           {showUseGPT4Confirm && (
 -             <Confirm
 -               title={t('appDebug.trailUseGPT4Info.title')}
 -               content={t('appDebug.trailUseGPT4Info.description')}
 -               isShow={showUseGPT4Confirm}
 -               onConfirm={() => {
 -                 setShowAccountSettingModal({ payload: 'provider' })
 -                 setShowUseGPT4Confirm(false)
 -               }}
 -               onCancel={() => setShowUseGPT4Confirm(false)}
 -             />
 -           )}
 - 
 -           {isShowSelectDataSet && (
 -             <SelectDataSet
 -               isShow={isShowSelectDataSet}
 -               onClose={hideSelectDataSet}
 -               selectedIds={selectedIds}
 -               onSelect={handleSelect}
 -             />
 -           )}
 - 
 -           {isShowHistoryModal && (
 -             <EditHistoryModal
 -               isShow={isShowHistoryModal}
 -               saveLoading={false}
 -               onClose={hideHistoryModal}
 -               data={completionPromptConfig.conversation_histories_role}
 -               onSave={(data) => {
 -                 setConversationHistoriesRole(data)
 -                 hideHistoryModal()
 -               }}
 -             />
 -           )}
 -           {isMobile && (
 -             <Drawer showClose isOpen={isShowDebugPanel} onClose={hideDebugPanel} mask footer={null} panelClassname='!bg-gray-50'>
 -               <Debug
 -                 isAPIKeySet={isAPIKeySet}
 -                 onSetting={() => setShowAccountSettingModal({ payload: 'provider' })}
 -                 inputs={inputs}
 -                 modelParameterParams={{
 -                   setModel: setModel as any,
 -                   onCompletionParamsChange: setCompletionParams,
 -                 }}
 -                 debugWithMultipleModel={debugWithMultipleModel}
 -                 multipleModelConfigs={multipleModelConfigs}
 -                 onMultipleModelConfigsChange={handleMultipleModelConfigsChange}
 -               />
 -             </Drawer>
 -           )}
 -           {showAppConfigureFeaturesModal && (
 -             <NewFeaturePanel
 -               show
 -               inWorkflow={false}
 -               showFileUpload={false}
 -               isChatMode={mode !== 'completion'}
 -               disabled={false}
 -               onChange={handleFeaturesChange}
 -               onClose={() => setShowAppConfigureFeaturesModal(false)}
 -               promptVariables={modelConfig.configs.prompt_variables}
 -               onAutoAddPromptVariable={handleAddPromptVariable}
 -             />
 -           )}
 -         </>
 -       </FeaturesProvider>
 -     </ConfigContext.Provider>
 -   )
 - }
 - export default React.memo(Configuration)
 
 
  |