✨ feat: add model name matching rules with priority-based lookup
Add flexible model name matching system to support different matching patterns: Backend changes: - Add `name_rule` field to Model struct with 4 matching types: * 0: Exact match (default) * 1: Prefix match * 2: Contains match * 3: Suffix match - Implement `FindModelByNameWithRule` function with priority order: exact > prefix > suffix > contains - Add database migration for new `name_rule` column Frontend changes: - Add "Match Type" column in models table with colored tags - Add name rule selector in create/edit modal with validation - Auto-set exact match and disable selection for preconfigured models - Add explanatory text showing priority order - Support i18n for all new UI elements This enables users to define model patterns once and reuse configurations across similar models, reducing repetitive setup while maintaining exact match priority for specific overrides. Closes: #[issue-number]
This commit is contained in:
@@ -184,6 +184,23 @@ const renderOperations = (text, record, setEditingModel, setShowEdit, manageMode
|
||||
);
|
||||
};
|
||||
|
||||
// 名称匹配类型渲染
|
||||
const renderNameRule = (rule, t) => {
|
||||
const map = {
|
||||
0: { color: 'green', label: t('精确') },
|
||||
1: { color: 'blue', label: t('前缀') },
|
||||
2: { color: 'orange', label: t('包含') },
|
||||
3: { color: 'purple', label: t('后缀') },
|
||||
};
|
||||
const cfg = map[rule];
|
||||
if (!cfg) return '-';
|
||||
return (
|
||||
<Tag color={cfg.color} size="small" shape='circle'>
|
||||
{cfg.label}
|
||||
</Tag>
|
||||
);
|
||||
};
|
||||
|
||||
export const getModelsColumns = ({
|
||||
t,
|
||||
manageModel,
|
||||
@@ -202,6 +219,11 @@ export const getModelsColumns = ({
|
||||
</Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('匹配类型'),
|
||||
dataIndex: 'name_rule',
|
||||
render: (val) => renderNameRule(val, t),
|
||||
},
|
||||
{
|
||||
title: t('描述'),
|
||||
dataIndex: 'description',
|
||||
|
||||
@@ -40,6 +40,13 @@ import { API, showError, showSuccess } from '../../../../helpers';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useIsMobile } from '../../../../hooks/common/useIsMobile';
|
||||
|
||||
const nameRuleOptions = [
|
||||
{ label: '精确名称匹配', value: 0 },
|
||||
{ label: '前缀名称匹配', value: 1 },
|
||||
{ label: '包含名称匹配', value: 2 },
|
||||
{ label: '后缀名称匹配', value: 3 },
|
||||
];
|
||||
|
||||
const endpointOptions = [
|
||||
{ label: 'OpenAI', value: 'openai' },
|
||||
{ label: 'Anthropic', value: 'anthropic' },
|
||||
@@ -111,6 +118,7 @@ const EditModelModal = (props) => {
|
||||
vendor: '',
|
||||
vendor_icon: '',
|
||||
endpoints: [],
|
||||
name_rule: props.editingModel?.model_name ? 0 : undefined, // 通过未配置模型过来的固定为精确匹配
|
||||
status: true,
|
||||
});
|
||||
|
||||
@@ -301,6 +309,20 @@ const EditModelModal = (props) => {
|
||||
showClear
|
||||
/>
|
||||
</Col>
|
||||
|
||||
<Col span={24}>
|
||||
<Form.Select
|
||||
field='name_rule'
|
||||
label={t('名称匹配类型')}
|
||||
placeholder={t('请选择名称匹配类型')}
|
||||
optionList={nameRuleOptions.map(o => ({ label: t(o.label), value: o.value }))}
|
||||
rules={[{ required: true, message: t('请选择名称匹配类型') }]}
|
||||
disabled={!!props.editingModel?.model_name} // 通过未配置模型过来的禁用选择
|
||||
style={{ width: '100%' }}
|
||||
extraText={t('根据模型名称和匹配规则查找模型元数据,优先级:精确 > 前缀 > 后缀 > 包含')}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
<Col span={24}>
|
||||
<Form.TextArea
|
||||
field='description'
|
||||
|
||||
Reference in New Issue
Block a user