Co-authored-by: Joel <iamjoel007@gmail.com>tags/0.3.31
| @@ -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> | |||
| ) | |||
| } | |||
| @@ -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)', | |||
| }} | |||
| @@ -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 { | |||
| @@ -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) && ( | |||
| @@ -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({ | |||
| @@ -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> | |||
| ) | |||
| @@ -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, | |||
| }) | |||
| @@ -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: { | |||
| @@ -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'> | |||
| { | |||
| @@ -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> | |||
| ) | |||
| } | |||
| @@ -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> | |||
| ) | |||
| } | |||
| @@ -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> | |||
| @@ -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.', | |||
| @@ -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', | |||
| @@ -223,6 +223,7 @@ const translation = { | |||
| }, | |||
| }, | |||
| modelProvider: { | |||
| notConfigured: '系统模型尚未完全配置,部分功能可能无法使用。', | |||
| systemModelSettings: '系统模型设置', | |||
| systemModelSettingsLink: '为什么需要设置系统模型?', | |||
| selectModel: '选择您的模型', | |||
| @@ -252,6 +253,7 @@ const translation = { | |||
| tip: '该模型已被删除。请添模型或选择其他模型。', | |||
| emptyTip: '无可用模型', | |||
| emptySetting: '请前往设置进行配置', | |||
| rerankTip: '请设置 Rerank 模型', | |||
| }, | |||
| card: { | |||
| quota: '额度', | |||