|
@@ -3,22 +3,34 @@ import type { FC } from 'react'
|
|
|
import React, { useEffect, useState } from 'react'
|
|
|
import cn from 'classnames'
|
|
|
import { useTranslation } from 'react-i18next'
|
|
|
-import { useBoolean, useClickAway } from 'ahooks'
|
|
|
-import { ChevronDownIcon, Cog8ToothIcon, InformationCircleIcon } from '@heroicons/react/24/outline'
|
|
|
+import { useBoolean, useClickAway, useGetState } from 'ahooks'
|
|
|
+import { Cog8ToothIcon, InformationCircleIcon } from '@heroicons/react/24/outline'
|
|
|
+import produce from 'immer'
|
|
|
import ParamItem from './param-item'
|
|
|
import ModelIcon from './model-icon'
|
|
|
+import ModelName from './model-name'
|
|
|
import Radio from '@/app/components/base/radio'
|
|
|
import Panel from '@/app/components/base/panel'
|
|
|
import type { CompletionParams } from '@/models/debug'
|
|
|
-import { AppType, ProviderType } from '@/types/app'
|
|
|
-import { MODEL_LIST, TONE_LIST } from '@/config'
|
|
|
+import { TONE_LIST } from '@/config'
|
|
|
import Toast from '@/app/components/base/toast'
|
|
|
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
|
|
|
import { formatNumber } from '@/utils/format'
|
|
|
-export type IConifgModelProps = {
|
|
|
+import { Brush01 } from '@/app/components/base/icons/src/vender/solid/editor'
|
|
|
+import { Scales02 } from '@/app/components/base/icons/src/vender/solid/FinanceAndECommerce'
|
|
|
+import { Target04 } from '@/app/components/base/icons/src/vender/solid/general'
|
|
|
+import { Sliders02 } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices'
|
|
|
+import { fetchModelParams } from '@/service/debug'
|
|
|
+import Loading from '@/app/components/base/loading'
|
|
|
+import ModelSelector from '@/app/components/header/account-setting/model-page/model-selector'
|
|
|
+import { ModelType, ProviderEnum } from '@/app/components/header/account-setting/model-page/declarations'
|
|
|
+import { useProviderContext } from '@/context/provider-context'
|
|
|
+
|
|
|
+export type IConfigModelProps = {
|
|
|
mode: string
|
|
|
modelId: string
|
|
|
- setModelId: (id: string, provider: ProviderType) => void
|
|
|
+ provider: ProviderEnum
|
|
|
+ setModelId: (id: string, provider: ProviderEnum) => void
|
|
|
completionParams: CompletionParams
|
|
|
onCompletionParamsChange: (newParams: CompletionParams) => void
|
|
|
disabled: boolean
|
|
@@ -26,21 +38,10 @@ export type IConifgModelProps = {
|
|
|
onShowUseGPT4Confirm: () => void
|
|
|
}
|
|
|
|
|
|
-const options = MODEL_LIST
|
|
|
-
|
|
|
-const getMaxToken = (modelId: string) => {
|
|
|
- if (['claude-instant-1', 'claude-2'].includes(modelId))
|
|
|
- return 30 * 1000
|
|
|
-
|
|
|
- if (['gpt-4', 'gpt-3.5-turbo-16k'].includes(modelId))
|
|
|
- return 8000
|
|
|
-
|
|
|
- return 4000
|
|
|
-}
|
|
|
-
|
|
|
-const ConifgModel: FC<IConifgModelProps> = ({
|
|
|
- mode,
|
|
|
+const ConfigModel: FC<IConfigModelProps> = ({
|
|
|
+ // mode,
|
|
|
modelId,
|
|
|
+ provider,
|
|
|
setModelId,
|
|
|
completionParams,
|
|
|
onCompletionParamsChange,
|
|
@@ -49,89 +50,140 @@ const ConifgModel: FC<IConifgModelProps> = ({
|
|
|
onShowUseGPT4Confirm,
|
|
|
}) => {
|
|
|
const { t } = useTranslation()
|
|
|
- const isChatApp = mode === AppType.chat
|
|
|
- const availableModels = options.filter(item => item.type === mode)
|
|
|
+ const { textGenerationModelList } = useProviderContext()
|
|
|
const [isShowConfig, { setFalse: hideConfig, toggle: toogleShowConfig }] = useBoolean(false)
|
|
|
const [maxTokenSettingTipVisible, setMaxTokenSettingTipVisible] = useState(false)
|
|
|
const configContentRef = React.useRef(null)
|
|
|
- const currModel = options.find(item => item.id === modelId)
|
|
|
+ const currModel = textGenerationModelList.find(item => item.model_name === modelId)
|
|
|
+ // Cache loaded model param
|
|
|
+ const [allParams, setAllParams, getAllParams] = useGetState<Record<string, Record<string, any>>>({})
|
|
|
+ const currParams = allParams[provider]?.[modelId]
|
|
|
+ const hasEnableParams = currParams && Object.keys(currParams).some(key => currParams[key].enabled)
|
|
|
+ const allSupportParams = ['temperature', 'top_p', 'presence_penalty', 'frequency_penalty', 'max_tokens']
|
|
|
+ const currSupportParams = currParams ? allSupportParams.filter(key => currParams[key].enabled) : allSupportParams
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ (async () => {
|
|
|
+ if (!allParams[provider]?.[modelId]) {
|
|
|
+ const res = await fetchModelParams(provider, modelId)
|
|
|
+ const newAllParams = produce(allParams, (draft) => {
|
|
|
+ if (!draft[provider])
|
|
|
+ draft[provider] = {}
|
|
|
+
|
|
|
+ draft[provider][modelId] = res
|
|
|
+ })
|
|
|
+ setAllParams(newAllParams)
|
|
|
+ }
|
|
|
+ })()
|
|
|
+ }, [provider, modelId])
|
|
|
+
|
|
|
useClickAway(() => {
|
|
|
hideConfig()
|
|
|
}, configContentRef)
|
|
|
|
|
|
- const params = [
|
|
|
- {
|
|
|
- id: 1,
|
|
|
- name: t('common.model.params.temperature'),
|
|
|
- key: 'temperature',
|
|
|
- tip: t('common.model.params.temperatureTip'),
|
|
|
- max: 2,
|
|
|
- },
|
|
|
- {
|
|
|
- id: 2,
|
|
|
- name: t('common.model.params.topP'),
|
|
|
- key: 'top_p',
|
|
|
- tip: t('common.model.params.topPTip'),
|
|
|
- max: 1,
|
|
|
- },
|
|
|
- {
|
|
|
- id: 3,
|
|
|
- name: t('common.model.params.presencePenalty'),
|
|
|
- key: 'presence_penalty',
|
|
|
- tip: t('common.model.params.presencePenaltyTip'),
|
|
|
- min: -2,
|
|
|
- max: 2,
|
|
|
- },
|
|
|
- {
|
|
|
- id: 4,
|
|
|
- name: t('common.model.params.frequencyPenalty'),
|
|
|
- key: 'frequency_penalty',
|
|
|
- tip: t('common.model.params.frequencyPenaltyTip'),
|
|
|
- min: -2,
|
|
|
- max: 2,
|
|
|
- },
|
|
|
- {
|
|
|
- id: 5,
|
|
|
- name: t('common.model.params.maxToken'),
|
|
|
- key: 'max_tokens',
|
|
|
- tip: t('common.model.params.maxTokenTip'),
|
|
|
- step: 100,
|
|
|
- max: getMaxToken(modelId),
|
|
|
- },
|
|
|
- ]
|
|
|
-
|
|
|
- const selectModelDisabled = false // chat gpt-3.5-turbo, gpt-4; text generation text-davinci-003, gpt-3.5-turbo
|
|
|
-
|
|
|
const selectedModel = { name: modelId } // options.find(option => option.id === modelId)
|
|
|
- const [isShowOption, { setFalse: hideOption, toggle: toogleOption }] = useBoolean(false)
|
|
|
- const triggerRef = React.useRef(null)
|
|
|
- useClickAway(() => {
|
|
|
- hideOption()
|
|
|
- }, triggerRef)
|
|
|
|
|
|
- const handleSelectModel = (id: string, provider = ProviderType.openai) => {
|
|
|
- return () => {
|
|
|
+ const ensureModelParamLoaded = (provider: ProviderEnum, modelId: string) => {
|
|
|
+ return new Promise<void>((resolve) => {
|
|
|
+ if (getAllParams()[provider]?.[modelId]) {
|
|
|
+ resolve()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const runId = setInterval(() => {
|
|
|
+ if (getAllParams()[provider]?.[modelId]) {
|
|
|
+ resolve()
|
|
|
+ clearInterval(runId)
|
|
|
+ }
|
|
|
+ }, 500)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ const transformValue = (value: number, fromRange: [number, number], toRange: [number, number]): number => {
|
|
|
+ const [fromStart = 0, fromEnd] = fromRange
|
|
|
+ const [toStart = 0, toEnd] = toRange
|
|
|
+
|
|
|
+ // The following three if is to avoid precision loss
|
|
|
+ if (fromStart === toStart && fromEnd === toEnd)
|
|
|
+ return value
|
|
|
+
|
|
|
+ if (value <= fromStart)
|
|
|
+ return toStart
|
|
|
+
|
|
|
+ if (value >= fromEnd)
|
|
|
+ return toEnd
|
|
|
+
|
|
|
+ const fromLength = fromEnd - fromStart
|
|
|
+ const toLength = toEnd - toStart
|
|
|
+
|
|
|
+ let adjustedValue = (value - fromStart) * (toLength / fromLength) + toStart
|
|
|
+ adjustedValue = parseFloat(adjustedValue.toFixed(2))
|
|
|
+ return adjustedValue
|
|
|
+ }
|
|
|
+
|
|
|
+ const handleSelectModel = (id: string, nextProvider = ProviderEnum.openai) => {
|
|
|
+ return async () => {
|
|
|
if (id === 'gpt-4' && !canUseGPT4) {
|
|
|
hideConfig()
|
|
|
- hideOption()
|
|
|
onShowUseGPT4Confirm()
|
|
|
return
|
|
|
}
|
|
|
- const nextSelectModelMaxToken = getMaxToken(id)
|
|
|
- if (completionParams.max_tokens > nextSelectModelMaxToken) {
|
|
|
- Toast.notify({
|
|
|
- type: 'warning',
|
|
|
- message: t('common.model.params.setToCurrentModelMaxTokenTip', { maxToken: formatNumber(nextSelectModelMaxToken) }),
|
|
|
- })
|
|
|
- onCompletionParamsChange({
|
|
|
- ...completionParams,
|
|
|
- max_tokens: nextSelectModelMaxToken,
|
|
|
+ const prevParamsRule = getAllParams()[provider]?.[modelId]
|
|
|
+
|
|
|
+ setModelId(id, nextProvider)
|
|
|
+
|
|
|
+ await ensureModelParamLoaded(nextProvider, id)
|
|
|
+
|
|
|
+ const nextParamsRule = getAllParams()[nextProvider]?.[id]
|
|
|
+ // debugger
|
|
|
+ const nextSelectModelMaxToken = nextParamsRule.max_tokens.max
|
|
|
+ const newConCompletionParams = produce(completionParams, (draft: any) => {
|
|
|
+ if (nextParamsRule.max_tokens.enabled) {
|
|
|
+ if (completionParams.max_tokens > nextSelectModelMaxToken) {
|
|
|
+ Toast.notify({
|
|
|
+ type: 'warning',
|
|
|
+ message: t('common.model.params.setToCurrentModelMaxTokenTip', { maxToken: formatNumber(nextSelectModelMaxToken) }),
|
|
|
+ })
|
|
|
+ draft.max_tokens = parseFloat((nextSelectModelMaxToken * 0.8).toFixed(2))
|
|
|
+ }
|
|
|
+ // prev don't have max token
|
|
|
+ if (!completionParams.max_tokens)
|
|
|
+ draft.max_tokens = nextParamsRule.max_tokens.default
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ delete draft.max_tokens
|
|
|
+ }
|
|
|
+
|
|
|
+ allSupportParams.forEach((key) => {
|
|
|
+ if (key === 'max_tokens')
|
|
|
+ return
|
|
|
+
|
|
|
+ if (!nextParamsRule[key].enabled) {
|
|
|
+ delete draft[key]
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (draft[key] === undefined) {
|
|
|
+ draft[key] = nextParamsRule[key].default || 0
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!prevParamsRule[key].enabled) {
|
|
|
+ draft[key] = nextParamsRule[key].default || 0
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ draft[key] = transformValue(
|
|
|
+ draft[key],
|
|
|
+ [prevParamsRule[key].min, prevParamsRule[key].max],
|
|
|
+ [nextParamsRule[key].min, nextParamsRule[key].max],
|
|
|
+ )
|
|
|
})
|
|
|
- }
|
|
|
- setModelId(id, provider)
|
|
|
+ })
|
|
|
+ onCompletionParamsChange(newConCompletionParams)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // only openai support this
|
|
|
function matchToneId(completionParams: CompletionParams): number {
|
|
|
const remvoedCustomeTone = TONE_LIST.slice(0, -1)
|
|
|
const CUSTOM_TONE_ID = 4
|
|
@@ -146,6 +198,11 @@ const ConifgModel: FC<IConifgModelProps> = ({
|
|
|
|
|
|
// tone is a preset of completionParams.
|
|
|
const [toneId, setToneId] = React.useState(matchToneId(completionParams)) // default is Balanced
|
|
|
+ const toneTabBgClassName = ({
|
|
|
+ 1: 'bg-[#F5F8FF]',
|
|
|
+ 2: 'bg-[#F4F3FF]',
|
|
|
+ 3: 'bg-[#F6FEFC]',
|
|
|
+ })[toneId] || ''
|
|
|
// set completionParams by toneId
|
|
|
const handleToneChange = (id: number) => {
|
|
|
if (id === 4)
|
|
@@ -164,40 +221,59 @@ const ConifgModel: FC<IConifgModelProps> = ({
|
|
|
setToneId(matchToneId(completionParams))
|
|
|
}, [completionParams])
|
|
|
|
|
|
- const handleParamChange = (id: number, value: number) => {
|
|
|
- const key = params.find(item => item.id === id)?.key
|
|
|
+ const handleParamChange = (key: string, value: number) => {
|
|
|
+ const currParamsRule = getAllParams()[provider]?.[modelId]
|
|
|
+ let notOutRangeValue = parseFloat(value.toFixed(2))
|
|
|
+ notOutRangeValue = Math.max(currParamsRule[key].min, notOutRangeValue)
|
|
|
+ notOutRangeValue = Math.min(currParamsRule[key].max, notOutRangeValue)
|
|
|
|
|
|
- if (key) {
|
|
|
- onCompletionParamsChange({
|
|
|
- ...completionParams,
|
|
|
- [key]: value,
|
|
|
- })
|
|
|
- }
|
|
|
+ onCompletionParamsChange({
|
|
|
+ ...completionParams,
|
|
|
+ [key]: notOutRangeValue,
|
|
|
+ })
|
|
|
}
|
|
|
const ableStyle = 'bg-indigo-25 border-[#2A87F5] cursor-pointer'
|
|
|
const diabledStyle = 'bg-[#FFFCF5] border-[#F79009]'
|
|
|
|
|
|
+ const getToneIcon = (toneId: number) => {
|
|
|
+ const className = 'w-[14px] h-[14px]'
|
|
|
+ const res = ({
|
|
|
+ 1: <Brush01 className={className}/>,
|
|
|
+ 2: <Scales02 className={className} />,
|
|
|
+ 3: <Target04 className={className} />,
|
|
|
+ 4: <Sliders02 className={className} />,
|
|
|
+ })[toneId]
|
|
|
+ return res
|
|
|
+ }
|
|
|
useEffect(() => {
|
|
|
- const max = params[4].max
|
|
|
- if (currModel?.provider !== ProviderType.anthropic && completionParams.max_tokens > max * 2 / 3)
|
|
|
+ if (!currParams)
|
|
|
+ return
|
|
|
+
|
|
|
+ const max = currParams.max_tokens.max
|
|
|
+ const isSupportMaxToken = currParams.max_tokens.enabled
|
|
|
+ if (isSupportMaxToken && currModel?.model_provider.provider_name !== ProviderEnum.anthropic && completionParams.max_tokens > max * 2 / 3)
|
|
|
setMaxTokenSettingTipVisible(true)
|
|
|
else
|
|
|
setMaxTokenSettingTipVisible(false)
|
|
|
- }, [params, completionParams.max_tokens, setMaxTokenSettingTipVisible])
|
|
|
-
|
|
|
+ }, [currParams, completionParams.max_tokens, setMaxTokenSettingTipVisible])
|
|
|
return (
|
|
|
<div className='relative' ref={configContentRef}>
|
|
|
<div
|
|
|
className={cn('flex items-center border h-8 px-2.5 space-x-2 rounded-lg', disabled ? diabledStyle : ableStyle)}
|
|
|
onClick={() => !disabled && toogleShowConfig()}
|
|
|
>
|
|
|
- <ModelIcon modelId={currModel?.id as string} />
|
|
|
- <div className='text-[13px] text-gray-900 font-medium'>{selectedModel.name}</div>
|
|
|
+ <ModelIcon
|
|
|
+ modelId={modelId}
|
|
|
+ providerName={provider}
|
|
|
+ />
|
|
|
+ <div className='text-[13px] text-gray-900 font-medium'>
|
|
|
+ <ModelName modelId={selectedModel.name} />
|
|
|
+ </div>
|
|
|
{disabled ? <InformationCircleIcon className='w-3.5 h-3.5 text-[#F79009]' /> : <Cog8ToothIcon className='w-3.5 h-3.5 text-gray-500' />}
|
|
|
</div>
|
|
|
{isShowConfig && (
|
|
|
<Panel
|
|
|
- className='absolute z-20 top-8 right-0 !w-[496px] bg-white'
|
|
|
+ className='absolute z-20 top-8 right-0 !w-[496px] bg-white !overflow-visible shadow-md'
|
|
|
keepUnFold
|
|
|
headerIcon={
|
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
@@ -215,49 +291,88 @@ const ConifgModel: FC<IConifgModelProps> = ({
|
|
|
<div className='py-3 pl-10 pr-6 text-sm'>
|
|
|
<div className="flex items-center justify-between my-5 h-9">
|
|
|
<div>{t('appDebug.modelConfig.model')}</div>
|
|
|
- {/* model selector */}
|
|
|
- <div className="relative" style={{ zIndex: 30 }}>
|
|
|
- <div ref={triggerRef} onClick={() => !selectModelDisabled && toogleOption()} className={cn(selectModelDisabled ? 'cursor-not-allowed' : 'cursor-pointer', 'flex items-center h-9 px-3 space-x-2 rounded-lg bg-gray-50 ')}>
|
|
|
- <ModelIcon modelId={currModel?.id as string} />
|
|
|
- <div className="text-sm gray-900">{selectedModel?.name}</div>
|
|
|
- {!selectModelDisabled && <ChevronDownIcon className={cn(isShowOption && 'rotate-180', 'w-[14px] h-[14px] text-gray-500')} />}
|
|
|
- </div>
|
|
|
- {isShowOption && (
|
|
|
- <div className={cn(isChatApp ? 'min-w-[159px]' : 'w-[179px]', 'absolute right-0 bg-gray-50 rounded-lg shadow')}>
|
|
|
- {availableModels.map(item => (
|
|
|
- <div key={item.id} onClick={handleSelectModel(item.id, item.provider)} className="flex items-center h-9 px-3 rounded-lg cursor-pointer hover:bg-gray-100">
|
|
|
- <ModelIcon className='shrink-0 mr-2' modelId={item?.id} />
|
|
|
- <div className="text-sm gray-900 whitespace-nowrap">{item.name}</div>
|
|
|
+ <ModelSelector
|
|
|
+ popClassName='right-0'
|
|
|
+ triggerIconSmall
|
|
|
+ value={{
|
|
|
+ modelName: modelId,
|
|
|
+ providerName: provider,
|
|
|
+ }}
|
|
|
+ modelType={ModelType.textGeneration}
|
|
|
+ onChange={(model) => {
|
|
|
+ handleSelectModel(model.model_name, model.model_provider.provider_name as ProviderEnum)()
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ {hasEnableParams && (
|
|
|
+ <div className="border-b border-gray-100"></div>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {/* Tone type */}
|
|
|
+ {[ProviderEnum.openai, ProviderEnum.azure_openai].includes(provider) && (
|
|
|
+ <div className="mt-5 mb-4">
|
|
|
+ <div className="mb-3 text-sm text-gray-900">{t('appDebug.modelConfig.setTone')}</div>
|
|
|
+ <Radio.Group className={cn('!rounded-lg', toneTabBgClassName)} value={toneId} onChange={handleToneChange}>
|
|
|
+ <>
|
|
|
+ {TONE_LIST.slice(0, 3).map(tone => (
|
|
|
+ <div className='grow flex items-center' key={tone.id}>
|
|
|
+ <Radio
|
|
|
+ value={tone.id}
|
|
|
+ className={cn(tone.id === toneId && 'rounded-md border border-gray-200 shadow-md', '!mr-0 grow !px-2 !justify-center text-[13px] font-medium')}
|
|
|
+ labelClassName={cn(tone.id === toneId
|
|
|
+ ? ({
|
|
|
+ 1: 'text-[#6938EF]',
|
|
|
+ 2: 'text-[#444CE7]',
|
|
|
+ 3: 'text-[#107569]',
|
|
|
+ })[toneId]
|
|
|
+ : 'text-[#667085]', 'flex items-center space-x-2')}
|
|
|
+ >
|
|
|
+ <>
|
|
|
+ {getToneIcon(tone.id)}
|
|
|
+ <div>{t(`common.model.tone.${tone.name}`) as string}</div>
|
|
|
+ <div className=""></div>
|
|
|
+ </>
|
|
|
+ </Radio>
|
|
|
+ {tone.id !== toneId && tone.id + 1 !== toneId && (<div className='h-5 border-r border-gray-200'></div>)}
|
|
|
</div>
|
|
|
))}
|
|
|
- </div>
|
|
|
- )}
|
|
|
+ </>
|
|
|
+ <Radio
|
|
|
+ value={TONE_LIST[3].id}
|
|
|
+ className={cn(toneId === 4 && 'rounded-md border border-gray-200 shadow-md', '!mr-0 grow !px-2 !justify-center text-[13px] font-medium')}
|
|
|
+ labelClassName={cn('flex items-center space-x-2 ', toneId === 4 ? 'text-[#155EEF]' : 'text-[#667085]')}
|
|
|
+ >
|
|
|
+ <>
|
|
|
+ {getToneIcon(TONE_LIST[3].id)}
|
|
|
+ <div>{t(`common.model.tone.${TONE_LIST[3].name}`) as string}</div>
|
|
|
+ </>
|
|
|
+ </Radio>
|
|
|
+ </Radio.Group>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <div className="border-b border-gray-100"></div>
|
|
|
-
|
|
|
- {/* Response type */}
|
|
|
- <div className="mt-5 mb-4">
|
|
|
- <div className="mb-4 text-sm text-gray-900">{t('appDebug.modelConfig.setTone')}</div>
|
|
|
- <Radio.Group value={toneId} onChange={handleToneChange}>
|
|
|
- <>
|
|
|
- {TONE_LIST.slice(0, 3).map(tone => (
|
|
|
- <Radio key={tone.id} value={tone.id} className="grow !px-0 !justify-center">{t(`common.model.tone.${tone.name}`) as string}</Radio>
|
|
|
- ))}
|
|
|
- </>
|
|
|
- <div className="ml-[2px] mr-[3px] h-5 border-r border-gray-200"></div>
|
|
|
- <Radio value={TONE_LIST[3].id}>{t(`common.model.tone.${TONE_LIST[3].name}`) as string}</Radio>
|
|
|
- </Radio.Group>
|
|
|
- </div>
|
|
|
+ )}
|
|
|
|
|
|
{/* Params */}
|
|
|
- <div className="mt-4 space-y-4">
|
|
|
- {params.map(({ key, ...param }) => (<ParamItem key={key} {...param} value={(completionParams as any)[key] as any} onChange={handleParamChange} />))}
|
|
|
+ <div className={cn(hasEnableParams && 'mt-4', 'space-y-4', !allParams[provider]?.[modelId] && 'flex items-center min-h-[200px]')}>
|
|
|
+ {allParams[provider]?.[modelId]
|
|
|
+ ? (
|
|
|
+ currSupportParams.map(key => (<ParamItem
|
|
|
+ key={key}
|
|
|
+ id={key}
|
|
|
+ name={t(`common.model.params.${key}`)}
|
|
|
+ tip={t(`common.model.params.${key}Tip`)}
|
|
|
+ {...currParams[key] as any}
|
|
|
+ value={(completionParams as any)[key] as any}
|
|
|
+ onChange={handleParamChange}
|
|
|
+ />))
|
|
|
+ )
|
|
|
+ : (
|
|
|
+ <Loading type='area'/>
|
|
|
+ )}
|
|
|
</div>
|
|
|
</div>
|
|
|
{
|
|
|
maxTokenSettingTipVisible && (
|
|
|
- <div className='flex py-2 pr-4 pl-5 bg-[#FFFAEB] border-t border-[#FEF0C7]'>
|
|
|
+ <div className='flex py-2 pr-4 pl-5 rounded-bl-xl rounded-br-xl bg-[#FFFAEB] border-t border-[#FEF0C7]'>
|
|
|
<AlertTriangle className='shrink-0 mr-2 mt-[3px] w-3 h-3 text-[#F79009]' />
|
|
|
<div className='mr-2 text-xs font-medium text-gray-700'>{t('common.model.params.maxTokenSettingTip')}</div>
|
|
|
</div>
|
|
@@ -270,4 +385,4 @@ const ConifgModel: FC<IConifgModelProps> = ({
|
|
|
)
|
|
|
}
|
|
|
|
|
|
-export default React.memo(ConifgModel)
|
|
|
+export default React.memo(ConfigModel)
|