fix(web): model bugfix
This commit is contained in:
@@ -546,7 +546,10 @@ export const en = {
|
|||||||
tags: 'Tags',
|
tags: 'Tags',
|
||||||
createCustomModel: 'Add Custom Model',
|
createCustomModel: 'Add Custom Model',
|
||||||
edit: 'Edit',
|
edit: 'Edit',
|
||||||
selectOneTip: 'Model API KEY not configured, please configure in Model Plaza first',
|
selectOneTip: 'Model API KEY not configured, please configure it in the model list first',
|
||||||
|
load_balance_strategy: 'Concurrency Strategy',
|
||||||
|
round_robin: 'Sequential Execution - Call each model in order',
|
||||||
|
none: 'None',
|
||||||
|
|
||||||
api_key: 'API KEY',
|
api_key: 'API KEY',
|
||||||
api_base: 'API Base URL',
|
api_base: 'API Base URL',
|
||||||
|
|||||||
@@ -1112,7 +1112,10 @@ export const zh = {
|
|||||||
tags: '标签',
|
tags: '标签',
|
||||||
createCustomModel: '添加自定义模型',
|
createCustomModel: '添加自定义模型',
|
||||||
edit: '编辑',
|
edit: '编辑',
|
||||||
selectOneTip: '模型未配置API KEY,请先在模型广场配置',
|
selectOneTip: '模型未配置API KEY,请先在模型列表配置',
|
||||||
|
load_balance_strategy: '并发策略',
|
||||||
|
round_robin: '顺序执行 - 按顺序依次调用每个模型',
|
||||||
|
none: '无',
|
||||||
|
|
||||||
api_key: 'API KEY',
|
api_key: 'API KEY',
|
||||||
api_base: 'API Base URL',
|
api_base: 'API Base URL',
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ const CustomModelModal = forwardRef<CustomModelModalRef, CustomModelModalProps>(
|
|||||||
<CustomSelect
|
<CustomSelect
|
||||||
url={modelTypeUrl}
|
url={modelTypeUrl}
|
||||||
hasAll={false}
|
hasAll={false}
|
||||||
|
disabled={isEdit}
|
||||||
format={(items) => items.map((item) => ({ label: t(`modelNew.${item}`), value: String(item) }))}
|
format={(items) => items.map((item) => ({ label: t(`modelNew.${item}`), value: String(item) }))}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@@ -141,6 +142,7 @@ const CustomModelModal = forwardRef<CustomModelModalRef, CustomModelModalProps>(
|
|||||||
<CustomSelect
|
<CustomSelect
|
||||||
url={modelProviderUrl}
|
url={modelProviderUrl}
|
||||||
hasAll={false}
|
hasAll={false}
|
||||||
|
disabled={isEdit}
|
||||||
format={(items) => items.map((item) => ({ label: t(`modelNew.${item}`), value: String(item) }))}
|
format={(items) => items.map((item) => ({ label: t(`modelNew.${item}`), value: String(item) }))}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { forwardRef, useImperativeHandle, useState } from 'react';
|
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||||
import { Form, Input, App } from 'antd';
|
import { Form, Input, App, Select } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import type { ModelListItem, CompositeModelForm, GroupModelModalRef, GroupModelModalProps, ModelApiKey } from '../types';
|
import type { ModelListItem, CompositeModelForm, GroupModelModalRef, GroupModelModalProps, ModelApiKey } from '../types';
|
||||||
@@ -106,6 +106,7 @@ const GroupModelModal = forwardRef<GroupModelModalRef, GroupModelModalProps>(({
|
|||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
|
initialValues={{ balance_strategy: 'none' }}
|
||||||
>
|
>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="logo"
|
name="logo"
|
||||||
@@ -147,6 +148,19 @@ const GroupModelModal = forwardRef<GroupModelModalRef, GroupModelModalProps>(({
|
|||||||
<Input.TextArea placeholder={t('common.pleaseEnter')} />
|
<Input.TextArea placeholder={t('common.pleaseEnter')} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="load_balance_strategy"
|
||||||
|
label={t('modelNew.load_balance_strategy')}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
options={['round_robin', 'none'].map(key => ({
|
||||||
|
label: t(`modelNew.${key}`),
|
||||||
|
value: key
|
||||||
|
}))}
|
||||||
|
placeholder={t('common.pleaseSelect')}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item name="api_key_ids">
|
<Form.Item name="api_key_ids">
|
||||||
<ModelImplement type={type} />
|
<ModelImplement type={type} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ const KeyConfigModal = forwardRef<KeyConfigModalRef, KeyConfigModalProps>(({
|
|||||||
updateProviderApiKeys({
|
updateProviderApiKeys({
|
||||||
...values,
|
...values,
|
||||||
provider: model.provider
|
provider: model.provider
|
||||||
}).then(() => {
|
}).then((res) => {
|
||||||
if (refresh) {
|
if (refresh) {
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
handleClose()
|
handleClose()
|
||||||
message.success(t('common.updateSuccess'))
|
message.success(res as string)
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { forwardRef, useImperativeHandle, useState } from 'react';
|
import { forwardRef, useImperativeHandle, useState, useMemo, useEffect } from 'react';
|
||||||
import { Form, Cascader, App } from 'antd';
|
import { Form, Cascader, App, type CascaderProps } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import type { SubModelModalForm, SubModelModalRef, SubModelModalProps, ModelList } from './types';
|
import type { SubModelModalForm, SubModelModalRef, SubModelModalProps, ModelList } from './types';
|
||||||
@@ -18,7 +18,8 @@ interface Option {
|
|||||||
}
|
}
|
||||||
const SubModelModal = forwardRef<SubModelModalRef, SubModelModalProps>(({
|
const SubModelModal = forwardRef<SubModelModalRef, SubModelModalProps>(({
|
||||||
refresh,
|
refresh,
|
||||||
type
|
type,
|
||||||
|
groupedByProvider
|
||||||
}, ref) => {
|
}, ref) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { message } = App.useApp()
|
const { message } = App.useApp()
|
||||||
@@ -26,28 +27,27 @@ const SubModelModal = forwardRef<SubModelModalRef, SubModelModalProps>(({
|
|||||||
const [form] = Form.useForm<SubModelModalForm>();
|
const [form] = Form.useForm<SubModelModalForm>();
|
||||||
const [selecteds, setSelecteds] = useState<any[]>([])
|
const [selecteds, setSelecteds] = useState<any[]>([])
|
||||||
const [modelList, setModelList] = useState<Option[]>([])
|
const [modelList, setModelList] = useState<Option[]>([])
|
||||||
|
const provider = Form.useWatch(['provider'], form)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (provider && groupedByProvider) {
|
||||||
|
const lastModels = groupedByProvider[provider] || []
|
||||||
|
const list = lastModels.map(vo => [{ name: vo.model_name, id: vo.model_config_ids[0], value: vo.model_config_ids[0], provider }, { value: vo.id }])
|
||||||
|
setSelecteds(list)
|
||||||
|
form.setFieldValue('api_key_ids', lastModels.map(vo => [vo.model_config_ids[0], vo.id]))
|
||||||
|
}
|
||||||
|
}, [groupedByProvider, provider])
|
||||||
|
|
||||||
// 封装取消方法,添加关闭弹窗逻辑
|
// 封装取消方法,添加关闭弹窗逻辑
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
setSelecteds([])
|
setSelecteds([])
|
||||||
|
setModelList([])
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOpen = (list?: ModelList[], provider?: string) => {
|
const handleOpen = () => {
|
||||||
if (list?.length && provider) {
|
form.resetFields()
|
||||||
const initialValue: SubModelModalForm = {
|
|
||||||
provider,
|
|
||||||
api_key_ids: list.map(vo => {
|
|
||||||
return [vo.model_config_ids[0], vo.id]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
form.setFieldsValue(initialValue);
|
|
||||||
handleChangeProvider(provider, initialValue.api_key_ids)
|
|
||||||
} else {
|
|
||||||
form.resetFields()
|
|
||||||
}
|
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
};
|
};
|
||||||
// 封装保存方法,添加提交逻辑
|
// 封装保存方法,添加提交逻辑
|
||||||
@@ -67,7 +67,6 @@ const SubModelModal = forwardRef<SubModelModalRef, SubModelModalProps>(({
|
|||||||
const handleChange = (value: (string | number)[][], selectedOptions: Option[][]) => {
|
const handleChange = (value: (string | number)[][], selectedOptions: Option[][]) => {
|
||||||
const filterList = selectedOptions.filter(vo => vo.length === 1).map(item => item[0])
|
const filterList = selectedOptions.filter(vo => vo.length === 1).map(item => item[0])
|
||||||
const lastFilterLit = value.filter(vo => vo.length !== 1)
|
const lastFilterLit = value.filter(vo => vo.length !== 1)
|
||||||
console.log('onchange', value, lastFilterLit, selectedOptions, filterList)
|
|
||||||
if (filterList.length) {
|
if (filterList.length) {
|
||||||
message.warning(`【${filterList.map(vo => vo.label)}】${t('modelNew.selectOneTip')}`)
|
message.warning(`【${filterList.map(vo => vo.label)}】${t('modelNew.selectOneTip')}`)
|
||||||
form.setFieldValue('api_key_ids', lastFilterLit)
|
form.setFieldValue('api_key_ids', lastFilterLit)
|
||||||
@@ -77,35 +76,51 @@ const SubModelModal = forwardRef<SubModelModalRef, SubModelModalProps>(({
|
|||||||
|
|
||||||
const handleChangeProvider = (provider: string, api_key_ids?: any[]) => {
|
const handleChangeProvider = (provider: string, api_key_ids?: any[]) => {
|
||||||
form.setFieldValue('api_key_ids', undefined)
|
form.setFieldValue('api_key_ids', undefined)
|
||||||
getModelNewList({
|
if (provider) {
|
||||||
provider: provider,
|
getModelNewList({
|
||||||
is_composite: false,
|
provider: provider,
|
||||||
is_active: true,
|
is_composite: false,
|
||||||
type
|
is_active: true,
|
||||||
})
|
type
|
||||||
.then(res => {
|
|
||||||
const response = res as ProviderModelItem[]
|
|
||||||
const list = response[0]?.models || []
|
|
||||||
setModelList(list.map(vo => {
|
|
||||||
const children = vo.api_keys.map(item => ({
|
|
||||||
label: item.api_key,
|
|
||||||
value: item.id,
|
|
||||||
}))
|
|
||||||
return {
|
|
||||||
...vo,
|
|
||||||
label: vo.name,
|
|
||||||
value: vo.id,
|
|
||||||
children: children
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
if (api_key_ids?.length) {
|
|
||||||
form.setFieldsValue({
|
|
||||||
api_key_ids: api_key_ids
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.then(res => {
|
||||||
|
const response = res as ProviderModelItem[]
|
||||||
|
const list = response[0]?.models || []
|
||||||
|
setModelList(list.map(vo => {
|
||||||
|
const children = vo.api_keys.map(item => ({
|
||||||
|
label: item.api_key,
|
||||||
|
value: item.id,
|
||||||
|
}))
|
||||||
|
return {
|
||||||
|
...vo,
|
||||||
|
label: vo.name,
|
||||||
|
value: vo.id,
|
||||||
|
children: children
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
if (api_key_ids?.length) {
|
||||||
|
form.setFieldsValue({
|
||||||
|
api_key_ids: api_key_ids
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setModelList([])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
const displayRender: CascaderProps<Option>['displayRender'] = (labels, selectedOptions = []) =>
|
||||||
|
labels.map((label, i) => {
|
||||||
|
const option = selectedOptions[i];
|
||||||
|
if (i === labels.length - 1) {
|
||||||
|
return (
|
||||||
|
<span key={option?.value || i}>
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <span key={option?.value || i}>{label} / </span>;
|
||||||
|
});
|
||||||
|
|
||||||
// 暴露给父组件的方法
|
// 暴露给父组件的方法
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
@@ -154,6 +169,7 @@ const SubModelModal = forwardRef<SubModelModalRef, SubModelModalProps>(({
|
|||||||
className="rb:w-full!"
|
className="rb:w-full!"
|
||||||
showCheckedStrategy={SHOW_CHILD}
|
showCheckedStrategy={SHOW_CHILD}
|
||||||
changeOnSelect
|
changeOnSelect
|
||||||
|
displayRender={displayRender}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ const ModelImplement: FC<ModelImplementProps> = ({ type, value, onChange }) => {
|
|||||||
}
|
}
|
||||||
subModelModalRef.current?.handleOpen()
|
subModelModalRef.current?.handleOpen()
|
||||||
}
|
}
|
||||||
const handleEdit = (list: ModelList[], provider: string ) => {
|
|
||||||
subModelModalRef.current?.handleOpen(list, provider)
|
|
||||||
}
|
|
||||||
const handleDelete = (provider: string) => {
|
const handleDelete = (provider: string) => {
|
||||||
modal.confirm({
|
modal.confirm({
|
||||||
title: t('common.confirmDeleteDesc', { name: provider }),
|
title: t('common.confirmDeleteDesc', { name: provider }),
|
||||||
@@ -78,16 +75,11 @@ const ModelImplement: FC<ModelImplementProps> = ({ type, value, onChange }) => {
|
|||||||
<div key={provider} className="rb:mb-4 last:rb:mb-0">
|
<div key={provider} className="rb:mb-4 last:rb:mb-0">
|
||||||
<Flex justify="space-between" align="center" className="rb:mb-2 last:rb:mb-0">
|
<Flex justify="space-between" align="center" className="rb:mb-2 last:rb:mb-0">
|
||||||
<div className="rb:font-medium">{[...new Set(items?.map((vo) => vo.model_name))].join(', ')}</div>
|
<div className="rb:font-medium">{[...new Set(items?.map((vo) => vo.model_name))].join(', ')}</div>
|
||||||
<Space>
|
|
||||||
<div
|
<div
|
||||||
className="rb:w-6 rb:h-6 rb:cursor-pointer rb:bg-[url('@/assets/images/editBorder.svg')] rb:hover:bg-[url('@/assets/images/editBg.svg')]"
|
className="rb:w-6 rb:h-6 rb:cursor-pointer rb:bg-[url('@/assets/images/deleteBorder.svg')] rb:hover:bg-[url('@/assets/images/deleteBg.svg')]"
|
||||||
onClick={() => handleEdit(items, provider)}
|
onClick={() => handleDelete(provider)}
|
||||||
></div>
|
></div>
|
||||||
<div
|
|
||||||
className="rb:w-6 rb:h-6 rb:cursor-pointer rb:bg-[url('@/assets/images/deleteBorder.svg')] rb:hover:bg-[url('@/assets/images/deleteBg.svg')]"
|
|
||||||
onClick={() => handleDelete(provider)}
|
|
||||||
></div>
|
|
||||||
</Space>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
<Tag className="rb:mb-2">{t(`modelNew.${provider}`)}</Tag>
|
<Tag className="rb:mb-2">{t(`modelNew.${provider}`)}</Tag>
|
||||||
</div>
|
</div>
|
||||||
@@ -98,6 +90,7 @@ const ModelImplement: FC<ModelImplementProps> = ({ type, value, onChange }) => {
|
|||||||
ref={subModelModalRef}
|
ref={subModelModalRef}
|
||||||
refresh={handleRefresh}
|
refresh={handleRefresh}
|
||||||
type={type}
|
type={type}
|
||||||
|
groupedByProvider={groupedByProvider}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ export interface SubModelModalForm {
|
|||||||
api_key_ids: string[][];
|
api_key_ids: string[][];
|
||||||
}
|
}
|
||||||
export interface SubModelModalRef {
|
export interface SubModelModalRef {
|
||||||
handleOpen: (list?: ModelList[], provider?: string) => void;
|
handleOpen: () => void;
|
||||||
}
|
}
|
||||||
export interface SubModelModalProps {
|
export interface SubModelModalProps {
|
||||||
type?: string;
|
type?: string;
|
||||||
refresh?: (vo: ModelList[]) => void;
|
refresh?: (vo: ModelList[]) => void;
|
||||||
|
groupedByProvider?: Record<string, ModelList[]>
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useImperativeHandle, forwardRef, useRef } from 'react';
|
import { useState, useImperativeHandle, forwardRef, useRef, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Button, Switch, Row, Col, Space, Tooltip } from 'antd'
|
import { Button, Switch, Row, Col, Space, Tooltip } from 'antd'
|
||||||
|
|
||||||
@@ -8,8 +8,9 @@ import RbCard from '@/components/RbCard/Card'
|
|||||||
import Tag from '@/components/Tag';
|
import Tag from '@/components/Tag';
|
||||||
import PageEmpty from '@/components/Empty/PageEmpty';
|
import PageEmpty from '@/components/Empty/PageEmpty';
|
||||||
import MultiKeyConfigModal from './MultiKeyConfigModal'
|
import MultiKeyConfigModal from './MultiKeyConfigModal'
|
||||||
import { getModelNewList, updateModelStatus } from '@/api/models'
|
import { getModelNewList, updateModelStatus, modelTypeUrl } from '@/api/models'
|
||||||
import { getLogoUrl } from '../utils'
|
import { getLogoUrl } from '../utils'
|
||||||
|
import CustomSelect from '@/components/CustomSelect'
|
||||||
|
|
||||||
interface ModelListDetailProps {
|
interface ModelListDetailProps {
|
||||||
refresh?: () => void;
|
refresh?: () => void;
|
||||||
@@ -22,8 +23,10 @@ const ModelListDetail = forwardRef<ModelListDetailRef, ModelListDetailProps>(({
|
|||||||
const [list, setList] = useState<ModelListItem[]>([])
|
const [list, setList] = useState<ModelListItem[]>([])
|
||||||
const multiKeyConfigModalRef = useRef<MultiKeyConfigModalRef>(null)
|
const multiKeyConfigModalRef = useRef<MultiKeyConfigModalRef>(null)
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [type, setType] = useState<string | undefined | null>(null)
|
||||||
|
|
||||||
const handleOpen = (vo: ProviderModelItem) => {
|
const handleOpen = (vo: ProviderModelItem) => {
|
||||||
|
setType(null)
|
||||||
setOpen(true)
|
setOpen(true)
|
||||||
getData(vo)
|
getData(vo)
|
||||||
}
|
}
|
||||||
@@ -53,27 +56,50 @@ const ModelListDetail = forwardRef<ModelListDetailRef, ModelListDetailProps>(({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
|
setType(null)
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
refresh?.()
|
refresh?.()
|
||||||
}
|
}
|
||||||
const handleRefresh = () => {
|
const handleRefresh = () => {
|
||||||
getData(data)
|
getData(data)
|
||||||
}
|
}
|
||||||
|
const handleTypeChange = (value: string) => {
|
||||||
|
setType(value)
|
||||||
|
}
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
handleOpen,
|
handleOpen,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const filterList = useMemo(() => {
|
||||||
|
if (!type) return list
|
||||||
|
return list.filter(vo => vo.type === type)
|
||||||
|
}, [type, list])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RbDrawer
|
<RbDrawer
|
||||||
title={<>{t(`modelNew.${data.provider}`)} {t('modelNew.modelList')} ({list.length}{t('modelNew.item')})</>}
|
title={<>{t(`modelNew.${data.provider}`)} {t('modelNew.modelList')} ({list.length}{t('modelNew.item')})</>}
|
||||||
open={open}
|
open={open}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
>
|
>
|
||||||
{list.length === 0
|
<Row gutter={16}>
|
||||||
|
<Col span={12}>
|
||||||
|
<CustomSelect
|
||||||
|
value={type}
|
||||||
|
url={modelTypeUrl}
|
||||||
|
hasAll={false}
|
||||||
|
format={(items) => items.map((item) => ({ label: t(`modelNew.${item}`), value: String(item) }))}
|
||||||
|
onChange={handleTypeChange}
|
||||||
|
className="rb:w-full"
|
||||||
|
allowClear={true}
|
||||||
|
placeholder={t('modelNew.type')}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{filterList.length === 0
|
||||||
? <PageEmpty />
|
? <PageEmpty />
|
||||||
: <div className="rb:grid rb:grid-cols-2 rb:gap-4">
|
: <div className="rb:grid rb:grid-cols-2 rb:gap-4 rb:mt-3">
|
||||||
{list.map(item => (
|
{filterList.map(item => (
|
||||||
<RbCard
|
<RbCard
|
||||||
key={item.id}
|
key={item.id}
|
||||||
title={item.name}
|
title={item.name}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { useState, useRef, type FC } from 'react';
|
import { useState, useRef, type FC } from 'react';
|
||||||
import { Button, Flex, Space, type SegmentedProps } from 'antd'
|
import { Button, Flex, Space, type SegmentedProps, Form } from 'antd'
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import GroupModelModal from './components/GroupModelModal'
|
import GroupModelModal from './components/GroupModelModal'
|
||||||
import type { ModelListItem, GroupModelModalRef, CustomModelModalRef, ModelPlazaItem, BaseRef } from './types'
|
import type { ModelListItem, GroupModelModalRef, CustomModelModalRef, ModelPlazaItem, BaseRef, Query } from './types'
|
||||||
import SearchInput from '@/components/SearchInput'
|
import SearchInput from '@/components/SearchInput'
|
||||||
import PageTabs from '@/components/PageTabs'
|
import PageTabs from '@/components/PageTabs'
|
||||||
import GroupModel from './Group'
|
import GroupModel from './Group'
|
||||||
@@ -17,11 +17,12 @@ const tabKeys = ['group', 'list', 'square']
|
|||||||
const ModelManagement: FC = () => {
|
const ModelManagement: FC = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [activeTab, setActiveTab] = useState('group');
|
const [activeTab, setActiveTab] = useState('group');
|
||||||
const [query, setQuery] = useState({})
|
|
||||||
const configModalRef = useRef<GroupModelModalRef>(null)
|
const configModalRef = useRef<GroupModelModalRef>(null)
|
||||||
const customModelModalRef = useRef<CustomModelModalRef>(null)
|
const customModelModalRef = useRef<CustomModelModalRef>(null)
|
||||||
const groupRef = useRef<BaseRef>(null)
|
const groupRef = useRef<BaseRef>(null)
|
||||||
const squareRef = useRef<BaseRef>(null)
|
const squareRef = useRef<BaseRef>(null)
|
||||||
|
const [form] = Form.useForm<Query>()
|
||||||
|
const query = Form.useWatch([], form)
|
||||||
|
|
||||||
const formatTabItems = () => {
|
const formatTabItems = () => {
|
||||||
return tabKeys.map(value => ({
|
return tabKeys.map(value => ({
|
||||||
@@ -31,7 +32,7 @@ const ModelManagement: FC = () => {
|
|||||||
}
|
}
|
||||||
const handleChangeTab = (value: SegmentedProps['value']) => {
|
const handleChangeTab = (value: SegmentedProps['value']) => {
|
||||||
setActiveTab(value as string);
|
setActiveTab(value as string);
|
||||||
setQuery({})
|
form.resetFields()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleEdit = (vo?: ModelListItem | ModelPlazaItem) => {
|
const handleEdit = (vo?: ModelListItem | ModelPlazaItem) => {
|
||||||
@@ -54,15 +55,6 @@ const ModelManagement: FC = () => {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleSearch = (value?: string) => {
|
|
||||||
setQuery({ search: value })
|
|
||||||
}
|
|
||||||
const handleTypeChange = (value: string) => {
|
|
||||||
setQuery(pre => ({ ...pre, type: value }))
|
|
||||||
}
|
|
||||||
const handleProviderChange = (value: string) => {
|
|
||||||
setQuery(pre => ({ ...pre, provider: value }))
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -73,35 +65,44 @@ const ModelManagement: FC = () => {
|
|||||||
onChange={handleChangeTab}
|
onChange={handleChangeTab}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Space size={12}>
|
<Form form={form}>
|
||||||
{activeTab === 'list' ? <>
|
<Space size={12}>
|
||||||
<CustomSelect
|
{activeTab === 'list' &&
|
||||||
url={modelTypeUrl}
|
<Form.Item name="type" noStyle>
|
||||||
hasAll={false}
|
<CustomSelect
|
||||||
format={(items) => items.map((item) => ({ label: t(`modelNew.${item}`), value: String(item) }))}
|
url={modelTypeUrl}
|
||||||
onChange={handleTypeChange}
|
hasAll={false}
|
||||||
className="rb:w-30"
|
format={(items) => items.map((item) => ({ label: t(`modelNew.${item}`), value: String(item) }))}
|
||||||
allowClear={true}
|
className="rb:w-30"
|
||||||
placeholder={t('modelNew.type')}
|
allowClear={true}
|
||||||
/>
|
placeholder={t('modelNew.type')}
|
||||||
<CustomSelect
|
/>
|
||||||
url={modelProviderUrl}
|
</Form.Item>
|
||||||
hasAll={false}
|
}
|
||||||
format={(items) => items.map((item) => ({ label: t(`modelNew.${item}`), value: String(item) }))}
|
{(activeTab === 'list' || activeTab === 'square') &&
|
||||||
onChange={handleProviderChange}
|
<Form.Item name="provider" noStyle>
|
||||||
className="rb:w-30"
|
<CustomSelect
|
||||||
allowClear={true}
|
url={modelProviderUrl}
|
||||||
placeholder={t('modelNew.provider')}
|
hasAll={false}
|
||||||
/>
|
format={(items) => items.map((item) => ({ label: t(`modelNew.${item}`), value: String(item) }))}
|
||||||
</>
|
className="rb:w-30"
|
||||||
: <SearchInput
|
allowClear={true}
|
||||||
placeholder={t(`modelNew.${activeTab}SearchPlaceholder`)}
|
placeholder={t('modelNew.provider')}
|
||||||
onSearch={handleSearch}
|
/>
|
||||||
className="rb:w-70!"
|
</Form.Item>
|
||||||
/>}
|
}
|
||||||
{activeTab === 'group' && <Button type="primary" onClick={() => handleEdit()}>+ {t('modelNew.createGroupModel')}</Button>}
|
{activeTab !== 'list' &&
|
||||||
{activeTab === 'square' && <Button type="primary" onClick={() => handleEdit()}>+ {t('modelNew.createCustomModel')}</Button>}
|
<Form.Item name="search" noStyle>
|
||||||
</Space>
|
<SearchInput
|
||||||
|
placeholder={t(`modelNew.${activeTab}SearchPlaceholder`)}
|
||||||
|
className="rb:w-70!"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
}
|
||||||
|
{activeTab === 'group' && <Button type="primary" onClick={() => handleEdit()}>+ {t('modelNew.createGroupModel')}</Button>}
|
||||||
|
{activeTab === 'square' && <Button type="primary" onClick={() => handleEdit()}>+ {t('modelNew.createCustomModel')}</Button>}
|
||||||
|
</Space>
|
||||||
|
</Form>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<div className="rb:w-full rb:h-[calc(100%-48px)] rb:my-4">
|
<div className="rb:w-full rb:h-[calc(100%-48px)] rb:my-4">
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export const nodeLibrary: NodeLibrary[] = [
|
|||||||
model_id: {
|
model_id: {
|
||||||
type: 'customSelect',
|
type: 'customSelect',
|
||||||
url: getModelListUrl,
|
url: getModelListUrl,
|
||||||
params: { type: 'llm,chat', is_active: true }, // llm/chat
|
params: { type: 'llm,chat', pagesize: 100, is_active: true }, // llm/chat
|
||||||
valueKey: 'id',
|
valueKey: 'id',
|
||||||
labelKey: 'name',
|
labelKey: 'name',
|
||||||
},
|
},
|
||||||
@@ -166,7 +166,7 @@ export const nodeLibrary: NodeLibrary[] = [
|
|||||||
model_id: {
|
model_id: {
|
||||||
type: 'customSelect',
|
type: 'customSelect',
|
||||||
url: getModelListUrl,
|
url: getModelListUrl,
|
||||||
params: { type: 'llm,chat', is_active: true }, // llm/chat
|
params: { type: 'llm,chat', pagesize: 100, is_active: true }, // llm/chat
|
||||||
valueKey: 'id',
|
valueKey: 'id',
|
||||||
labelKey: 'name',
|
labelKey: 'name',
|
||||||
},
|
},
|
||||||
@@ -259,7 +259,7 @@ export const nodeLibrary: NodeLibrary[] = [
|
|||||||
model_id: {
|
model_id: {
|
||||||
type: 'customSelect',
|
type: 'customSelect',
|
||||||
url: getModelListUrl,
|
url: getModelListUrl,
|
||||||
params: { type: 'llm,chat', is_active: true }, // llm/chat
|
params: { type: 'llm,chat', pagesize: 100, is_active: true }, // llm/chat
|
||||||
valueKey: 'id',
|
valueKey: 'id',
|
||||||
labelKey: 'name',
|
labelKey: 'name',
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user