Переглянути джерело

fix: some RAG retrieval bugs (#1577)

Co-authored-by: Joel <iamjoel007@gmail.com>
zxhlyh 1 рік тому
батько
коміт
6768fd4d87

+ 5 - 1
web/app/components/app/chat/citation/popup.tsx

@@ -100,7 +100,11 @@ const Popup: FC<PopupProps> = ({
                             data={source.index_node_hash.substring(0, 7)}
                             icon={<BezierCurve03 className='mr-1 w-3 h-3' />}
                           />
-                          <ProgressTooltip data={Number(source.score.toFixed(2))} />
+                          {
+                            source.score && (
+                              <ProgressTooltip data={Number(source.score.toFixed(2))} />
+                            )
+                          }
                         </div>
                       )
                     }

+ 3 - 1
web/app/components/app/configuration/dataset-config/settings-modal/index.tsx

@@ -59,6 +59,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
   const {
     rerankDefaultModel,
     isRerankDefaultModelVaild,
+    rerankModelList,
   } = useProviderContext()
 
   const handleValueChange = (type: string, value: string) => {
@@ -78,6 +79,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
       !isReRankModelSelected({
         rerankDefaultModel,
         isRerankDefaultModelVaild,
+        rerankModelList,
         retrievalConfig,
         indexMethod,
       })
@@ -270,7 +272,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
       )}
 
       <div
-        className='absolute z-10 bottom-0 w-full flex justify-end py-4 px-6 border-t bg-white '
+        className='absolute z-[5] bottom-0 w-full flex justify-end py-4 px-6 border-t bg-white '
         style={{
           borderColor: 'rgba(0, 0, 0, 0.05)',
         }}

+ 15 - 4
web/app/components/datasets/common/check-rerank-model.ts

@@ -5,18 +5,29 @@ export const isReRankModelSelected = ({
   rerankDefaultModel,
   isRerankDefaultModelVaild,
   retrievalConfig,
+  rerankModelList,
   indexMethod,
 }: {
   rerankDefaultModel?: BackendModel
   isRerankDefaultModelVaild: boolean
   retrievalConfig: RetrievalConfig
+  rerankModelList: BackendModel[]
   indexMethod?: string
 }) => {
-  const rerankModel = (retrievalConfig.reranking_model?.reranking_model_name ? retrievalConfig.reranking_model : undefined) || (isRerankDefaultModelVaild ? rerankDefaultModel : undefined)
+  const rerankModelSelected = (() => {
+    if (retrievalConfig.reranking_model?.reranking_model_name)
+      return !!rerankModelList.find(({ model_name }) => model_name === retrievalConfig.reranking_model?.reranking_model_name)
+
+    if (isRerankDefaultModelVaild)
+      return !!rerankDefaultModel
+
+    return false
+  })()
+
   if (
     indexMethod === 'high_quality'
-    && (retrievalConfig.reranking_enable || retrievalConfig.search_method === RETRIEVE_METHOD.fullText)
-    && !rerankModel
+    && (retrievalConfig.reranking_enable || retrievalConfig.search_method === RETRIEVE_METHOD.hybrid)
+    && !rerankModelSelected
   )
     return false
 
@@ -35,7 +46,7 @@ export const ensureRerankModelSelected = ({
   const rerankModel = retrievalConfig.reranking_model?.reranking_model_name ? retrievalConfig.reranking_model : undefined
   if (
     indexMethod === 'high_quality'
-    && (retrievalConfig.reranking_enable || retrievalConfig.search_method === RETRIEVE_METHOD.fullText)
+    && (retrievalConfig.reranking_enable || retrievalConfig.search_method === RETRIEVE_METHOD.hybrid)
     && !rerankModel
   ) {
     return {

+ 14 - 2
web/app/components/datasets/common/retrieval-method-config/index.tsx

@@ -16,11 +16,23 @@ type Props = {
 }
 
 const RetrievalMethodConfig: FC<Props> = ({
-  value,
+  value: passValue,
   onChange,
 }) => {
   const { t } = useTranslation()
-  const { supportRetrievalMethods } = useProviderContext()
+  const { supportRetrievalMethods, rerankDefaultModel } = useProviderContext()
+  const value = (() => {
+    if (!passValue.reranking_model.reranking_model_name) {
+      return {
+        ...passValue,
+        reranking_model: {
+          reranking_provider_name: rerankDefaultModel?.model_provider.provider_name || '',
+          reranking_model_name: rerankDefaultModel?.model_name || '',
+        },
+      }
+    }
+    return passValue
+  })()
   return (
     <div className='space-y-2'>
       {supportRetrievalMethods.includes(RETRIEVE_METHOD.semantic) && (

+ 5 - 0
web/app/components/datasets/create/step-two/index.tsx

@@ -263,6 +263,7 @@ const StepTwo = ({
   const {
     rerankDefaultModel,
     isRerankDefaultModelVaild,
+    rerankModelList,
   } = useProviderContext()
   const getCreationParams = () => {
     let params
@@ -282,6 +283,7 @@ const StepTwo = ({
         !isReRankModelSelected({
           rerankDefaultModel,
           isRerankDefaultModelVaild,
+          rerankModelList,
           // eslint-disable-next-line @typescript-eslint/no-use-before-define
           retrievalConfig,
           indexMethod: indexMethod as string,
@@ -359,6 +361,9 @@ const StepTwo = ({
     try {
       let res
       const params = getCreationParams()
+      if (!params)
+        return false
+
       setIsCreating(true)
       if (!datasetId) {
         res = await createFirstDocument({

+ 30 - 1
web/app/components/datasets/hit-testing/modify-retrieval-modal.tsx

@@ -3,11 +3,14 @@ import type { FC } from 'react'
 import React, { useRef, useState } from 'react'
 import { useClickAway } from 'ahooks'
 import { useTranslation } from 'react-i18next'
+import Toast from '../../base/toast'
 import { XClose } from '@/app/components/base/icons/src/vender/line/general'
 import type { RetrievalConfig } from '@/types/app'
 import RetrievalMethodConfig from '@/app/components/datasets/common/retrieval-method-config'
 import EconomicalRetrievalMethodConfig from '@/app/components/datasets/common/economical-retrieval-method-config'
 import Button from '@/app/components/base/button'
+import { useProviderContext } from '@/context/provider-context'
+import { ensureRerankModelSelected, isReRankModelSelected } from '@/app/components/datasets/common/check-rerank-model'
 
 type Props = {
   indexMethod: string
@@ -33,6 +36,32 @@ const ModifyRetrievalModal: FC<Props> = ({
       onHide()
   }, ref)
 
+  const {
+    rerankDefaultModel,
+    isRerankDefaultModelVaild,
+    rerankModelList,
+  } = useProviderContext()
+
+  const handleSave = () => {
+    if (
+      !isReRankModelSelected({
+        rerankDefaultModel,
+        isRerankDefaultModelVaild,
+        rerankModelList,
+        retrievalConfig,
+        indexMethod,
+      })
+    ) {
+      Toast.notify({ type: 'error', message: t('appDebug.datasetConfig.rerankModelRequired') })
+      return
+    }
+    onSave(ensureRerankModelSelected({
+      rerankDefaultModel: rerankDefaultModel!,
+      retrievalConfig,
+      indexMethod,
+    }))
+  }
+
   if (!isShow)
     return null
 
@@ -87,7 +116,7 @@ const ModifyRetrievalModal: FC<Props> = ({
         }}
       >
         <Button className='mr-2 flex-shrink-0' onClick={onHide}>{t('common.operation.cancel')}</Button>
-        <Button type='primary' className='flex-shrink-0' onClick={() => onSave(retrievalConfig)} >{t('common.operation.save')}</Button>
+        <Button type='primary' className='flex-shrink-0' onClick={handleSave} >{t('common.operation.save')}</Button>
       </div>
     </div>
   )

+ 2 - 0
web/app/components/datasets/settings/form/index.tsx

@@ -59,6 +59,7 @@ const Form = () => {
   const {
     rerankDefaultModel,
     isRerankDefaultModelVaild,
+    rerankModelList,
   } = useProviderContext()
 
   const handleSave = async () => {
@@ -72,6 +73,7 @@ const Form = () => {
       !isReRankModelSelected({
         rerankDefaultModel,
         isRerankDefaultModelVaild,
+        rerankModelList,
         retrievalConfig,
         indexMethod,
       })

+ 6 - 2
web/app/components/header/account-setting/model-page/configs/cohere.tsx

@@ -16,12 +16,16 @@ const config: ProviderConfig = {
       'en': <CohereText className='w-[120px] h-6' />,
       'zh-Hans': <CohereText className='w-[120px] h-6' />,
     },
+    hit: {
+      'en': 'Rerank Model Supported',
+      'zh-Hans': '支持 Rerank 模型',
+    },
   },
   modal: {
     key: ProviderEnum.cohere,
     title: {
-      'en': 'cohere',
-      'zh-Hans': 'cohere',
+      'en': 'Rerank Model',
+      'zh-Hans': 'Rerank 模型',
     },
     icon: <Cohere className='w-6 h-6' />,
     link: {

+ 19 - 3
web/app/components/header/account-setting/model-page/index.tsx

@@ -26,6 +26,7 @@ import { ModelType } from '@/app/components/header/account-setting/model-page/de
 import { useEventEmitterContextContext } from '@/context/event-emitter'
 import { useProviderContext } from '@/context/provider-context'
 import I18n from '@/context/i18n'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
 
 const MODEL_CARD_LIST = [
   config.openai,
@@ -42,6 +43,10 @@ const ModelPage = () => {
   const { locale } = useContext(I18n)
   const {
     updateModelList,
+    textGenerationDefaultModel,
+    embeddingsDefaultModel,
+    speech2textDefaultModel,
+    rerankDefaultModel,
   } = useProviderContext()
   const { data: providers, mutate: mutateProviders } = useSWR('/workspaces/current/model-providers', fetchModelProviders)
   const [showModal, setShowModal] = useState(false)
@@ -196,11 +201,22 @@ const ModelPage = () => {
     }
   }
 
+  const defaultModelNotConfigured = !textGenerationDefaultModel && !embeddingsDefaultModel && !speech2textDefaultModel && !rerankDefaultModel
+
   return (
     <div className='relative pt-1 -mt-2'>
-      <div className='flex items-center justify-between mb-2 h-8'>
-        <div className='text-sm font-medium text-gray-800'>{t('common.modelProvider.models')}</div>
-        <SystemModel />
+      <div className={`flex items-center justify-between mb-2 h-8 ${defaultModelNotConfigured && 'px-3 bg-[#FFFAEB] rounded-lg border border-[#FEF0C7]'}`}>
+        {
+          defaultModelNotConfigured
+            ? (
+              <div className='flex items-center text-xs font-medium text-gray-700'>
+                <AlertTriangle className='mr-1 w-3 h-3 text-[#F79009]' />
+                {t('common.modelProvider.notConfigured')}
+              </div>
+            )
+            : <div className='text-sm font-medium text-gray-800'>{t('common.modelProvider.models')}</div>
+        }
+        <SystemModel onUpdate={() => mutateProviders()} />
       </div>
       <div className='grid grid-cols-2 gap-4 mb-6'>
         {

+ 70 - 65
web/app/components/header/account-setting/model-page/model-modal/index.tsx

@@ -2,7 +2,6 @@ import { useCallback, useState } from 'react'
 import type { FC } from 'react'
 import { useTranslation } from 'react-i18next'
 import { useContext } from 'use-context-selector'
-import { Portal } from '@headlessui/react'
 import type { FormValue, ProviderConfigModal } from '../declarations'
 import { ConfigurableProviders } from '../utils'
 import Form from './Form'
@@ -12,6 +11,10 @@ import { Lock01 } from '@/app/components/base/icons/src/vender/solid/security'
 import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/general'
 import { AlertCircle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
 import { useEventEmitterContextContext } from '@/context/event-emitter'
+import {
+  PortalToFollowElem,
+  PortalToFollowElemContent,
+} from '@/app/components/base/portal-to-follow-elem'
 
 type ModelModalProps = {
   isShow: boolean
@@ -90,75 +93,77 @@ const ModelModal: FC<ModelModalProps> = ({
     return null
 
   return (
-    <Portal>
-      <div className='fixed inset-0 flex items-center justify-center bg-black/[.25]'>
-        <div className='w-[640px] max-h-[calc(100vh-120px)] bg-white shadow-xl rounded-2xl overflow-y-auto'>
-          <div className='px-8 pt-8'>
-            <div className='flex justify-between items-center mb-2'>
-              <div className='text-xl font-semibold text-gray-900'>{renderTitlePrefix()}</div>
-              {modelModal?.icon}
-            </div>
-            <Form
-              modelModal={modelModal}
-              fields={modelModal?.fields || []}
-              initValue={modelModal?.defaultValue}
-              onChange={newValue => setValue(newValue)}
-              onValidatedError={handleValidatedError}
-              mode={mode}
-              cleared={cleared}
-              onClearedChange={setCleared}
-              onValidating={handleValidating}
-            />
-            <div className='flex justify-between items-center py-6'>
-              <a
-                href={modelModal?.link.href}
-                target='_blank'
-                className='inline-flex items-center text-xs text-primary-600'
-              >
-                {modelModal?.link.label[locale]}
-                <LinkExternal02 className='ml-1 w-3 h-3' />
-              </a>
-              <div>
-                <Button className='mr-2 !h-9 !text-sm font-medium text-gray-700' onClick={onCancel}>{t('common.operation.cancel')}</Button>
-                <Button
-                  className='!h-9 !text-sm font-medium'
-                  type='primary'
-                  onClick={handleSave}
-                  disabled={loading || (mode === 'edit' && !cleared) || validating}
+    <PortalToFollowElem open>
+      <PortalToFollowElemContent className='w-full h-full z-[60]'>
+        <div className='fixed inset-0 flex items-center justify-center bg-black/[.25]'>
+          <div className='w-[640px] max-h-[calc(100vh-120px)] bg-white shadow-xl rounded-2xl overflow-y-auto'>
+            <div className='px-8 pt-8'>
+              <div className='flex justify-between items-center mb-2'>
+                <div className='text-xl font-semibold text-gray-900'>{renderTitlePrefix()}</div>
+                {modelModal?.icon}
+              </div>
+              <Form
+                modelModal={modelModal}
+                fields={modelModal?.fields || []}
+                initValue={modelModal?.defaultValue}
+                onChange={newValue => setValue(newValue)}
+                onValidatedError={handleValidatedError}
+                mode={mode}
+                cleared={cleared}
+                onClearedChange={setCleared}
+                onValidating={handleValidating}
+              />
+              <div className='flex justify-between items-center py-6'>
+                <a
+                  href={modelModal?.link.href}
+                  target='_blank'
+                  className='inline-flex items-center text-xs text-primary-600'
                 >
-                  {t('common.operation.save')}
-                </Button>
+                  {modelModal?.link.label[locale]}
+                  <LinkExternal02 className='ml-1 w-3 h-3' />
+                </a>
+                <div>
+                  <Button className='mr-2 !h-9 !text-sm font-medium text-gray-700' onClick={onCancel}>{t('common.operation.cancel')}</Button>
+                  <Button
+                    className='!h-9 !text-sm font-medium'
+                    type='primary'
+                    onClick={handleSave}
+                    disabled={loading || (mode === 'edit' && !cleared) || validating}
+                  >
+                    {t('common.operation.save')}
+                  </Button>
+                </div>
               </div>
             </div>
-          </div>
-          <div className='border-t-[0.5px] border-t-[rgba(0,0,0,0.05)]'>
-            {
-              errorMessage
-                ? (
-                  <div className='flex px-[10px] py-3 bg-[#FEF3F2] text-xs text-[#D92D20]'>
-                    <AlertCircle className='mt-[1px] mr-2 w-[14px] h-[14px]' />
-                    {errorMessage}
-                  </div>
-                )
-                : (
-                  <div className='flex justify-center items-center py-3 bg-gray-50 text-xs text-gray-500'>
-                    <Lock01 className='mr-1 w-3 h-3 text-gray-500' />
-                    {t('common.modelProvider.encrypted.front')}
-                    <a
-                      className='text-primary-600 mx-1'
-                      target={'_blank'}
-                      href='https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
-                    >
-                      PKCS1_OAEP
-                    </a>
-                    {t('common.modelProvider.encrypted.back')}
-                  </div>
-                )
-            }
+            <div className='border-t-[0.5px] border-t-[rgba(0,0,0,0.05)]'>
+              {
+                errorMessage
+                  ? (
+                    <div className='flex px-[10px] py-3 bg-[#FEF3F2] text-xs text-[#D92D20]'>
+                      <AlertCircle className='mt-[1px] mr-2 w-[14px] h-[14px]' />
+                      {errorMessage}
+                    </div>
+                  )
+                  : (
+                    <div className='flex justify-center items-center py-3 bg-gray-50 text-xs text-gray-500'>
+                      <Lock01 className='mr-1 w-3 h-3 text-gray-500' />
+                      {t('common.modelProvider.encrypted.front')}
+                      <a
+                        className='text-primary-600 mx-1'
+                        target={'_blank'}
+                        href='https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
+                      >
+                        PKCS1_OAEP
+                      </a>
+                      {t('common.modelProvider.encrypted.back')}
+                    </div>
+                  )
+              }
+            </div>
           </div>
         </div>
-      </div>
-    </Portal>
+      </PortalToFollowElemContent>
+    </PortalToFollowElem>
   )
 }
 

+ 83 - 24
web/app/components/header/account-setting/model-page/model-selector/index.tsx

@@ -1,14 +1,17 @@
 import type { FC } from 'react'
-import { Fragment, useState } from 'react'
+import React, { Fragment, useEffect, useState } from 'react'
+import useSWR from 'swr'
 import { Popover, Transition } from '@headlessui/react'
 import { useTranslation } from 'react-i18next'
 import _ from 'lodash-es'
 import cn from 'classnames'
+import ModelModal from '../model-modal'
+import cohereConfig from '../configs/cohere'
 import s from './style.module.css'
-import type { BackendModel, ProviderEnum } from '@/app/components/header/account-setting/model-page/declarations'
+import type { BackendModel, FormValue, ProviderEnum } from '@/app/components/header/account-setting/model-page/declarations'
 import { ModelType } from '@/app/components/header/account-setting/model-page/declarations'
 import { ChevronDown } from '@/app/components/base/icons/src/vender/line/arrows'
-import { Check, SearchLg } from '@/app/components/base/icons/src/vender/line/general'
+import { Check, LinkExternal01, SearchLg } from '@/app/components/base/icons/src/vender/line/general'
 import { XCircle } from '@/app/components/base/icons/src/vender/solid/general'
 import { AlertCircle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
 import Tooltip from '@/app/components/base/tooltip'
@@ -20,6 +23,9 @@ import ModelModeTypeLabel from '@/app/components/app/configuration/config-model/
 import type { ModelModeType } from '@/types/app'
 import { CubeOutline } from '@/app/components/base/icons/src/vender/line/shapes'
 import { useModalContext } from '@/context/modal-context'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import { fetchDefaultModal, setModelProvider } from '@/service/common'
+import { useToastContext } from '@/app/components/base/toast'
 
 type Props = {
   value: {
@@ -35,6 +41,7 @@ type Props = {
   readonly?: boolean
   triggerIconSmall?: boolean
   whenEmptyGoToSetting?: boolean
+  onUpdate?: () => void
 }
 
 type ModelOption = {
@@ -59,6 +66,7 @@ const ModelSelector: FC<Props> = ({
   readonly,
   triggerIconSmall,
   whenEmptyGoToSetting,
+  onUpdate,
 }) => {
   const { t } = useTranslation()
   const { setShowAccountSettingModal } = useModalContext()
@@ -68,6 +76,7 @@ const ModelSelector: FC<Props> = ({
     speech2textModelList,
     rerankModelList,
     agentThoughtModelList,
+    updateModelList,
   } = useProviderContext()
   const [search, setSearch] = useState('')
   const modelList = supportAgentThought
@@ -98,7 +107,7 @@ const ModelSelector: FC<Props> = ({
     })
     : modelList
 
-  const hasRemoved = value && !modelList.find(({ model_name, model_provider }) => model_name === value.modelName && model_provider.provider_name === value.providerName)
+  const hasRemoved = (value && value.modelName && value.providerName) && !modelList.find(({ model_name, model_provider }) => model_name === value.modelName && model_provider.provider_name === value.providerName)
 
   const modelOptions: ModelOption[] = (() => {
     const providers = _.uniq(filteredModelList.map(item => item.model_provider.provider_name))
@@ -121,6 +130,45 @@ const ModelSelector: FC<Props> = ({
     })
     return res
   })()
+  const { eventEmitter } = useEventEmitterContextContext()
+  const [showRerankModal, setShowRerankModal] = useState(false)
+  const [shouldFetchRerankDefaultModel, setShouldFetchRerankDefaultModel] = useState(false)
+  const { notify } = useToastContext()
+  const { data: rerankDefaultModel } = useSWR(shouldFetchRerankDefaultModel ? '/workspaces/current/default-model?model_type=reranking' : null, fetchDefaultModal)
+  const handleOpenRerankModal = (e: React.MouseEvent<HTMLDivElement>) => {
+    e.stopPropagation()
+    setShowRerankModal(true)
+  }
+  const handleRerankModalSave = async (originValue?: FormValue) => {
+    if (originValue) {
+      try {
+        eventEmitter?.emit('provider-save')
+        const res = await setModelProvider({
+          url: `/workspaces/current/model-providers/${cohereConfig.modal.key}`,
+          body: {
+            config: originValue,
+          },
+        })
+        if (res.result === 'success') {
+          notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+          updateModelList(ModelType.reranking)
+          setShowRerankModal(false)
+          setShouldFetchRerankDefaultModel(true)
+          if (onUpdate)
+            onUpdate()
+        }
+        eventEmitter?.emit('')
+      }
+      catch (e) {
+        eventEmitter?.emit('')
+      }
+    }
+  }
+
+  useEffect(() => {
+    if (rerankDefaultModel && whenEmptyGoToSetting)
+      onChange(rerankDefaultModel)
+  }, [rerankDefaultModel])
 
   return (
     <div className=''>
@@ -130,7 +178,7 @@ const ModelSelector: FC<Props> = ({
             ({ open }) => (
               <>
                 {
-                  value
+                  (value && value.modelName && value.providerName)
                     ? (
                       <>
                         <ModelIcon
@@ -146,9 +194,19 @@ const ModelSelector: FC<Props> = ({
                         </div>
                       </>
                     )
-                    : (
-                      <div className='grow text-left text-sm text-gray-800 opacity-60'>{t('common.modelProvider.selectModel')}</div>
-                    )
+                    : whenEmptyGoToSetting
+                      ? (
+                        <div className='grow flex items-center h-9 justify-between' onClick={handleOpenRerankModal}>
+                          <div className='flex items-center text-[13px] font-medium text-primary-500'>
+                            <CubeOutline className='mr-1.5 w-4 h-4' />
+                            {t('common.modelProvider.selector.rerankTip')}
+                          </div>
+                          <LinkExternal01 className='w-3 h-3 text-gray-500' />
+                        </div>
+                      )
+                      : (
+                        <div className='grow text-left text-sm text-gray-800 opacity-60'>{t('common.modelProvider.selectModel')}</div>
+                      )
                 }
                 {
                   hasRemoved && (
@@ -162,7 +220,16 @@ const ModelSelector: FC<Props> = ({
                     </Tooltip>
                   )
                 }
-                {!readonly && <ChevronDown className={`w-4 h-4 text-gray-700 ${open ? 'opacity-100' : 'opacity-60'}`} />}
+                {
+                  !readonly && !whenEmptyGoToSetting && (
+                    <ChevronDown className={`w-4 h-4 text-gray-700 ${open ? 'opacity-100' : 'opacity-60'}`} />
+                  )
+                }
+                {
+                  whenEmptyGoToSetting && (value && value.modelName && value.providerName) && (
+                    <ChevronDown className={`w-4 h-4 text-gray-700 ${open ? 'opacity-100' : 'opacity-60'}`} />
+                  )
+                }
               </>
             )
           }
@@ -246,21 +313,6 @@ const ModelSelector: FC<Props> = ({
                   return null
                 })
               }
-              {
-                whenEmptyGoToSetting && modelList.length === 0 && (
-                  <div className='pt-6'>
-                    <div className='flex items-center justify-center mx-auto mb-2 w-12 h-12 rounded-[10px] border border-[#EAECF5]'>
-                      <CubeOutline className='w-6 h-6 text-gray-500' />
-                    </div>
-                    <div className='mb-1 text-center text-[13px] font-medium text-gray-500'>
-                      {t('common.modelProvider.selector.emptyTip')}
-                    </div>
-                    <div className='mb-6 text-center text-xs text-primary-500'>
-                      <span onClick={() => setShowAccountSettingModal({ payload: 'provider' })}>{t('common.modelProvider.selector.emptySetting')}</span>
-                    </div>
-                  </div>
-                )
-              }
               {modelList.length !== 0 && (search && filteredModelList.length === 0) && (
                 <div className='px-3 pt-1.5 h-[30px] text-center text-xs text-gray-500'>{t('common.modelProvider.noModelFound', { model: search })}</div>
               )}
@@ -281,6 +333,13 @@ const ModelSelector: FC<Props> = ({
           </Transition>
         )}
       </Popover>
+      <ModelModal
+        isShow={showRerankModal}
+        modelModal={cohereConfig.modal}
+        onCancel={() => setShowRerankModal(false)}
+        onSave={handleRerankModalSave}
+        mode={'add'}
+      />
     </div>
   )
 }

+ 10 - 2
web/app/components/header/account-setting/model-page/system-model/index.tsx

@@ -1,3 +1,4 @@
+import type { FC } from 'react'
 import { useState } from 'react'
 import { useTranslation } from 'react-i18next'
 import ModelSelector from '../model-selector'
@@ -17,7 +18,12 @@ import { ModelType } from '@/app/components/header/account-setting/model-page/de
 import { useToastContext } from '@/app/components/base/toast'
 import Button from '@/app/components/base/button'
 
-const SystemModel = () => {
+type SystemModelProps = {
+  onUpdate: () => void
+}
+const SystemModel: FC<SystemModelProps> = ({
+  onUpdate,
+}) => {
   const { t } = useTranslation()
   const {
     textGenerationDefaultModel,
@@ -91,7 +97,7 @@ const SystemModel = () => {
     >
       <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
         <div className={`
-          flex items-center px-2 h-6 text-xs text-gray-700 cursor-pointer rounded-md border-[0.5px] border-gray-200 shadow-xs
+          flex items-center px-2 h-6 text-xs text-gray-700 cursor-pointer bg-white rounded-md border-[0.5px] border-gray-200 shadow-xs
           hover:bg-gray-100 hover:shadow-none
           ${open && 'bg-gray-100 shadow-none'}
         `}>
@@ -158,6 +164,8 @@ const SystemModel = () => {
                 value={selectedModel[ModelType.reranking]}
                 modelType={ModelType.reranking}
                 onChange={v => handleChangeDefaultModel(ModelType.reranking, v)}
+                whenEmptyGoToSetting
+                onUpdate={onUpdate}
               />
             </div>
           </div>

+ 1 - 1
web/i18n/lang/app-debug.en.ts

@@ -305,7 +305,7 @@ const translation = {
   },
   result: 'Output Text',
   datasetConfig: {
-    settingTitle: 'Retrieve Settings',
+    settingTitle: 'Retrieval settings',
     retrieveOneWay: {
       title: 'N-to-1 retrieval',
       description: 'Based on user intent and dataset descriptions, the Agent autonomously selects the best dataset for querying. Best for applications with distinct, limited datasets.',

+ 2 - 0
web/i18n/lang/common.en.ts

@@ -223,6 +223,7 @@ const translation = {
     },
   },
   modelProvider: {
+    notConfigured: 'The system model has not yet been fully configured, and some functions may be unavailable.',
     systemModelSettings: 'System Model Settings',
     systemModelSettingsLink: 'Why is it necessary to set up a system model?',
     selectModel: 'Select your model',
@@ -252,6 +253,7 @@ const translation = {
       tip: 'This model has been removed. Please add a model or select another model.',
       emptyTip: 'No available models',
       emptySetting: 'Please go to settings to configure',
+      rerankTip: 'Please set up the Rerank model',
     },
     card: {
       quota: 'QUOTA',

+ 2 - 0
web/i18n/lang/common.zh.ts

@@ -223,6 +223,7 @@ const translation = {
     },
   },
   modelProvider: {
+    notConfigured: '系统模型尚未完全配置,部分功能可能无法使用。',
     systemModelSettings: '系统模型设置',
     systemModelSettingsLink: '为什么需要设置系统模型?',
     selectModel: '选择您的模型',
@@ -252,6 +253,7 @@ const translation = {
       tip: '该模型已被删除。请添模型或选择其他模型。',
       emptyTip: '无可用模型',
       emptySetting: '请前往设置进行配置',
+      rerankTip: '请设置 Rerank 模型',
     },
     card: {
       quota: '额度',