model selector in endpoint modal

This commit is contained in:
JzoNg 2024-11-12 16:40:43 +08:00
parent 75a037bc2a
commit b188800f16
3 changed files with 98 additions and 28 deletions

View File

@ -1,6 +1,6 @@
export type FormValue = Record<string, any>
export interface TypeWithI18N<T = string> {
export type TypeWithI18N<T = string> = {
en_US: T
zh_Hans: T
[key: string]: T
@ -15,9 +15,12 @@ export enum FormTypeEnum {
boolean = 'boolean',
files = 'files',
file = 'file',
modelSelector = 'model-selector',
toolSelector = 'tool-selector',
appSelector = 'app-selector',
}
export interface FormOption {
export type FormOption = {
label: TypeWithI18N
value: string
show_on: FormShowOnObject[]
@ -89,12 +92,12 @@ export enum CustomConfigurationStatusEnum {
noConfigure = 'no-configure',
}
export interface FormShowOnObject {
export type FormShowOnObject = {
variable: string
value: string
}
export interface CredentialFormSchemaBase {
export type CredentialFormSchemaBase = {
variable: string
label: TypeWithI18N
type: FormTypeEnum
@ -112,7 +115,7 @@ export type CredentialFormSchemaRadio = CredentialFormSchemaBase & { options: Fo
export type CredentialFormSchemaSecretInput = CredentialFormSchemaBase & { placeholder?: TypeWithI18N }
export type CredentialFormSchema = CredentialFormSchemaTextInput | CredentialFormSchemaSelect | CredentialFormSchemaRadio | CredentialFormSchemaSecretInput
export interface ModelItem {
export type ModelItem = {
model: string
label: TypeWithI18N
model_type: ModelTypeEnum
@ -141,7 +144,7 @@ export enum QuotaUnitEnum {
credits = 'credits',
}
export interface QuotaConfiguration {
export type QuotaConfiguration = {
quota_type: CurrentSystemQuotaTypeEnum
quota_unit: QuotaUnitEnum
quota_limit: number
@ -150,7 +153,7 @@ export interface QuotaConfiguration {
is_valid: boolean
}
export interface ModelProvider {
export type ModelProvider = {
provider: string
label: TypeWithI18N
description?: TypeWithI18N
@ -184,7 +187,7 @@ export interface ModelProvider {
}
}
export interface Model {
export type Model = {
provider: string
icon_large: TypeWithI18N
icon_small: TypeWithI18N
@ -193,7 +196,7 @@ export interface Model {
status: ModelStatusEnum
}
export interface DefaultModelResponse {
export type DefaultModelResponse = {
model: string
model_type: ModelTypeEnum
provider: {
@ -203,17 +206,17 @@ export interface DefaultModelResponse {
}
}
export interface DefaultModel {
export type DefaultModel = {
provider: string
model: string
}
export interface CustomConfigurationModelFixedFields {
export type CustomConfigurationModelFixedFields = {
__model_name: string
__model_type: ModelTypeEnum
}
export interface ModelParameterRule {
export type ModelParameterRule = {
default?: number | string | boolean | string[]
help?: TypeWithI18N
label: TypeWithI18N
@ -228,7 +231,7 @@ export interface ModelParameterRule {
tagPlaceholder?: TypeWithI18N
}
export interface ModelLoadBalancingConfigEntry {
export type ModelLoadBalancingConfigEntry = {
/** model balancing config entry id */
id?: string
/** is config entry enabled */
@ -243,7 +246,7 @@ export interface ModelLoadBalancingConfigEntry {
ttl?: number
}
export interface ModelLoadBalancingConfig {
export type ModelLoadBalancingConfig = {
enabled: boolean
configs: ModelLoadBalancingConfigEntry[]
}

View File

@ -1,4 +1,4 @@
import { useState } from 'react'
import { useCallback, useState } from 'react'
import type { FC } from 'react'
import { ValidatingTip } from '../../key-validator/ValidateStatus'
import type {
@ -17,6 +17,8 @@ import cn from '@/utils/classnames'
import { SimpleSelect } from '@/app/components/base/select'
import Tooltip from '@/app/components/base/tooltip'
import Radio from '@/app/components/base/radio'
import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
type FormProps = {
className?: string
itemClassName?: string
@ -67,6 +69,24 @@ const Form: FC<FormProps> = ({
onChange({ ...value, [key]: val, ...shouldClearVariable })
}
const handleModelChanged = useCallback((key: string, model: { provider: string; modelId: string; mode?: string }) => {
const newValue = {
...value[key],
provider: model.provider,
name: model.modelId,
mode: model.mode,
}
onChange({ ...value, [key]: newValue })
}, [onChange, value])
const handleCompletionParamsChange = useCallback((key: string, newParams: Record<string, any>) => {
const newValue = {
...value[key],
completion_params: newParams,
}
onChange({ ...value, [key]: newValue })
}, [onChange, value])
const renderField = (formSchema: CredentialFormSchema) => {
const tooltip = formSchema.tooltip
const tooltipContent = (tooltip && (
@ -94,7 +114,7 @@ const Form: FC<FormProps> = ({
const disabled = readonly || (isEditMode && (variable === '__model_type' || variable === '__model_name'))
return (
<div key={variable} className={cn(itemClassName, 'py-3')}>
<div className={cn(fieldLabelClassName, 'flex items-center py-2 text-sm text-gray-900')}>
<div className={cn(fieldLabelClassName, 'flex items-center py-2 system-sm-regular text-text-secondary')}>
{label[language] || label.en_US}
{
required && (
@ -135,7 +155,7 @@ const Form: FC<FormProps> = ({
return (
<div key={variable} className={cn(itemClassName, 'py-3')}>
<div className={cn(fieldLabelClassName, 'flex items-center py-2 text-sm text-gray-900')}>
<div className={cn(fieldLabelClassName, 'flex items-center py-2 system-sm-regular text-text-secondary')}>
{label[language] || label.en_US}
{
required && (
@ -165,7 +185,7 @@ const Form: FC<FormProps> = ({
flex justify-center items-center mr-2 w-4 h-4 border border-gray-300 rounded-full
${value[variable] === option.value && 'border-[5px] border-primary-600'}
`} />
<div className='text-sm text-gray-900'>{option.label[language] || option.label.en_US}</div>
<div className='system-sm-regular text-text-secondary'>{option.label[language] || option.label.en_US}</div>
</div>
))
}
@ -176,7 +196,7 @@ const Form: FC<FormProps> = ({
)
}
if (formSchema.type === 'select') {
if (formSchema.type === FormTypeEnum.select) {
const {
options,
variable,
@ -191,7 +211,7 @@ const Form: FC<FormProps> = ({
return (
<div key={variable} className={cn(itemClassName, 'py-3')}>
<div className={cn(fieldLabelClassName, 'flex items-center py-2 text-sm text-gray-900')}>
<div className={cn(fieldLabelClassName, 'flex items-center py-2 system-sm-regular text-text-secondary')}>
{label[language] || label.en_US}
{
@ -202,6 +222,7 @@ const Form: FC<FormProps> = ({
{tooltipContent}
</div>
<SimpleSelect
wrapperClassName='h-8'
className={cn(inputClassName)}
disabled={readonly}
defaultValue={(isShowDefaultValue && ((value[variable] as string) === '' || value[variable] === undefined || value[variable] === null)) ? formSchema.default : value[variable]}
@ -220,7 +241,7 @@ const Form: FC<FormProps> = ({
)
}
if (formSchema.type === 'boolean') {
if (formSchema.type === FormTypeEnum.boolean) {
const {
variable,
label,
@ -233,9 +254,9 @@ const Form: FC<FormProps> = ({
return (
<div key={variable} className={cn(itemClassName, 'py-3')}>
<div className='flex items-center justify-between py-2 text-sm text-gray-900'>
<div className='flex items-center justify-between py-2 system-sm-regular text-text-secondary'>
<div className='flex items-center space-x-2'>
<span className={cn(fieldLabelClassName, 'flex items-center py-2 text-sm text-gray-900')}>{label[language] || label.en_US}</span>
<span className={cn(fieldLabelClassName, 'flex items-center py-2 system-sm-regular text-text-secondary')}>{label[language] || label.en_US}</span>
{
required && (
<span className='ml-1 text-red-500'>*</span>
@ -256,6 +277,52 @@ const Form: FC<FormProps> = ({
</div>
)
}
if (formSchema.type === FormTypeEnum.modelSelector) {
const {
variable,
label,
required,
} = formSchema as (CredentialFormSchemaTextInput | CredentialFormSchemaSecretInput)
return (
<div key={variable} className={cn(itemClassName, 'py-3')}>
<div className={cn(fieldLabelClassName, 'flex items-center py-2 system-sm-regular text-text-secondary')}>
{label[language] || label.en_US}
{
required && (
<span className='ml-1 text-red-500'>*</span>
)
}
{tooltipContent}
</div>
<ModelParameterModal
popupClassName='!w-[387px]'
isAdvancedMode
isInWorkflow
provider={value[variable]?.provider}
modelId={value[variable]?.name}
mode={value[variable]?.mode}
completionParams={value[variable]?.completion_params}
setModel={model => handleModelChanged(variable, model)}
onCompletionParamsChange={params => handleCompletionParamsChange(variable, params)}
hideDebugWithMultipleModel
debugWithMultipleModel={false}
readonly={readonly}
/>
{fieldMoreInfo?.(formSchema)}
{validating && changeKey === variable && <ValidatingTip />}
</div>
)
}
if (formSchema.type === FormTypeEnum.toolSelector) {
// TODO
}
if (formSchema.type === FormTypeEnum.appSelector) {
// TODO
}
}
return (

View File

@ -26,14 +26,14 @@ const Input: FC<InputProps> = ({
max,
}) => {
const toLimit = (v: string) => {
const minNum = parseFloat(`${min}`)
const maxNum = parseFloat(`${max}`)
if (!isNaN(minNum) && parseFloat(v) < minNum) {
const minNum = Number.parseFloat(`${min}`)
const maxNum = Number.parseFloat(`${max}`)
if (!isNaN(minNum) && Number.parseFloat(v) < minNum) {
onChange(`${min}`)
return
}
if (!isNaN(maxNum) && parseFloat(v) > maxNum)
if (!isNaN(maxNum) && Number.parseFloat(v) > maxNum)
onChange(`${max}`)
}
return (
@ -41,7 +41,7 @@ const Input: FC<InputProps> = ({
<input
tabIndex={0}
className={`
block px-3 w-full h-9 bg-gray-100 text-sm rounded-lg border border-transparent
block px-3 w-full h-8 bg-gray-100 text-sm rounded-lg border border-transparent
appearance-none outline-none caret-primary-600
hover:border-[rgba(0,0,0,0.08)] hover:bg-gray-50
focus:bg-white focus:border-gray-300 focus:shadow-xs