import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; import { json2Yaml, yaml2Json } from '@/pages/backends/config'; import { CollapsePanel, IconFont, ScrollSpyTabs, useFinishFailed, useScrollActiveChange, useWrapperContext } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react'; import FormContext from '../config/form-context'; import { FormData, MaasProviderItem as ListItem } from '../config/types'; import useProviderRequiredFields from '../hooks/use-provider-required-fields'; import AdvanceConfig from './advance-config'; import Basic from './basic'; import SupportedModels from './supported-models'; interface ProviderFormProps { ref?: any; action: PageActionType; currentData?: ListItem; // Used when action is EDIT onFinish: (values: FormData) => Promise; onFinishFailed?: (errorInfo: any) => void; } const TABKeysMap = { BASIC: 'basic', SUPPORTEDMODELS: 'supportedModels', ADVANCED: 'advanced' }; const requiredFields = { [TABKeysMap.BASIC]: { sort: 1, fields: ['name', 'config', 'api_key'] }, [TABKeysMap.SUPPORTEDMODELS]: { sort: 2, fields: ['models'] } }; const ProviderForm: React.FC = forwardRef((props, ref) => { const { action, currentData, onFinish, onFinishFailed } = props; const intl = useIntl(); const providerRequiredFieldsMap = useProviderRequiredFields(); const [form] = Form.useForm(); const { getScrollElementScrollableHeight } = useWrapperContext(); const configType = Form.useWatch(['config', 'type'], form); const scrollTabsRef = useRef(null); const advanceRef = useRef(null); const { activeKey, collapseKeys, handleActiveChange, handleOnCollapseChange, updateActiveKey } = useScrollActiveChange({ initalActiveKeys: [TABKeysMap.BASIC], initialCollapseKeys: [TABKeysMap.SUPPORTEDMODELS] }); const segmentOptions = [ { value: TABKeysMap.BASIC, label: intl.formatMessage({ id: 'common.title.basicInfo' }), icon: , field: 'name' }, { value: TABKeysMap.SUPPORTEDMODELS, label: intl.formatMessage({ id: 'providers.table.models' }), icon: , field: 'supportedModels' }, { value: TABKeysMap.ADVANCED, label: intl.formatMessage({ id: 'resources.form.advanced' }), icon: , field: 'advanceConfig' } ]; const providerFields = useMemo(() => { const currentProviderFields = providerRequiredFieldsMap[configType] || []; return currentProviderFields; }, [providerRequiredFieldsMap, configType]); const formatAPIKeys = (values: FormData) => { const apiTokens = values.api_tokens?.filter?.( (item) => item && item.trim() !== '' ); const apiTokenList = _.concat([], values.api_key, apiTokens || []); if (action === PageAction.CREATE) { return apiTokenList.map((item: string) => ({ input: item })); } const existingTokens = new Set( (currentData?.api_tokens || []).map((item: { hash: string }) => item.hash) ); return apiTokenList.map((item: string) => existingTokens.has(item) ? { hash: item } : { input: item } ); }; const getCustomConfig = () => { const customConfig = yaml2Json(advanceRef.current?.getYamlValue() || ''); const config = form.getFieldValue('config') || {}; return { ...config, ...customConfig }; }; const handleOnFinish = (values: FormData) => { const data = { ..._.omit(values, ['api_key']), api_tokens: formatAPIKeys(values), config: { ...values.config, ...yaml2Json(advanceRef.current?.getYamlValue() || '') }, models: _.uniqBy(values.models, 'name'), clone_from_id: action === PageAction.COPY ? currentData?.id : undefined }; onFinish(data); }; const onTargetChange = (key: string) => { scrollTabsRef.current?.handleTargetChange(key); }; const { handleOnFinishFailed } = useFinishFailed({ requiredFields, onTargetChange, updateActiveKey }); const handleFinishFailed = (errorInfo: any) => { handleOnFinishFailed(errorInfo); onFinishFailed?.(errorInfo); }; useImperativeHandle(ref, () => ({ submit: () => { form.submit(); }, resetFields: () => { form.resetFields(); } })); useEffect(() => { if ( (action === PageAction.EDIT || action === PageAction.COPY) && currentData ) { const apiTokensList = _.get(currentData, 'api_tokens', []).map( (item: any) => item.hash || '' ); const currentProvider = _.get( providerRequiredFieldsMap, [currentData.config.type], [] ); const currentRequiredFields = currentProvider.map( (item: { name: string }) => item.name ); const customConfigYaml = json2Yaml( _.omit(currentData.config, ['type', ...currentRequiredFields]) || {} ); form.setFieldsValue({ ...currentData, models: (currentData.models || []).map((item) => ({ ...item, category: item.category || null })), api_key: apiTokensList?.[0] || '', api_tokens: apiTokensList?.slice(1) || [], proxy_enabled: !!currentData.proxy_url, custom_config: customConfigYaml }); advanceRef.current?.setYamlValue?.(customConfigYaml); } }, [form, currentData, action]); return (
}, { key: TABKeysMap.ADVANCED, label: intl.formatMessage({ id: 'resources.form.advanced' }), forceRender: true, children: ( ) } ]} >
); }); export default ProviderForm;