feat(admin): support provider model presets

This commit is contained in:
2026-05-24 22:28:07 +08:00
parent 6f730be0cd
commit 6d99e26e2a
3 changed files with 922 additions and 40 deletions
@@ -7,11 +7,15 @@ import {
authTypes,
applyProviderDefaults,
baseModelTypes,
baseModelTypeText,
baseModelTypeTextForProvider,
createEmptyPlatformForm,
modelMatchesProvider,
modelsForProvider,
platformModelPayloads,
platformPayload,
providerModelNameForProvider,
providerModelPresetFor,
providerModelPresets,
providerLabel,
selectedModelsForForm,
stableModelAlias,
@@ -48,7 +52,11 @@ export function PlatformManagementPanel(props: {
const platformMap = useMemo(() => new Map(props.platforms.map((item) => [item.id, item])), [props.platforms]);
const [form, setForm] = useState<PlatformWizardForm>(() => createEmptyPlatformForm(defaultProvider, providerDefaults(providerMap.get(defaultProvider))));
const providerOptions = useMemo(
() => Array.from(new Set([...props.providers.map((item) => item.providerKey), ...props.baseModels.map((item) => item.providerKey)])).filter(Boolean),
() => Array.from(new Set([
...props.providers.map((item) => item.providerKey),
...props.baseModels.map((item) => item.providerKey),
...props.baseModels.flatMap((item) => providerModelPresets(item).map((preset) => preset.providerKey)),
])).filter(Boolean),
[props.baseModels, props.providers],
);
const availableModels = useMemo(() => props.baseModels.filter((item) => item.status !== 'hidden'), [props.baseModels]);
@@ -763,13 +771,20 @@ function ModelSelection(props: {
<div className="platformModelChoices">
{selectedModels.map((model) => {
const modelLabel = stableModelAlias(model) || model.providerModelName;
const providerModelName = props.form.modelNameMappings[model.id] ?? model.providerModelName;
const defaultProviderModelName = providerModelNameForProvider(model, props.currentProvider);
const providerModelName = props.form.modelNameMappings[model.id] ?? defaultProviderModelName;
const providerPreset = providerModelPresetFor(model, props.currentProvider);
return (
<div className="platformModelChoice" key={model.id}>
<div className="platformModelChoiceMain">
<span>
<strong>{modelLabel}</strong>
<small>{props.providerMap.get(model.providerKey)?.displayName ?? model.providerKey} · {model.providerModelName} · {baseModelTypeText(model)}</small>
<small>
{props.providerMap.get(model.providerKey)?.displayName ?? model.providerKey}
{providerPreset ? ` · ${props.providerName} 真实名 ${defaultProviderModelName}` : ` · ${model.providerModelName}`}
{' · '}
{baseModelTypeTextForProvider(model, props.currentProvider)}
</small>
</span>
</div>
<div className="platformModelChoiceFields">
@@ -777,7 +792,7 @@ function ModelSelection(props: {
<Input
aria-label={`${modelLabel} 调用模型名`}
placeholder={model.providerModelName}
placeholder={defaultProviderModelName}
value={providerModelName}
onChange={(event) => updateModelNameMapping(model.id, event.target.value)}
/>
@@ -826,19 +841,30 @@ function ModelPickerDialog(props: {
const [query, setQuery] = useState('');
const [providerFilter, setProviderFilter] = useState(props.currentProvider || 'all');
const [draftIds, setDraftIds] = useState<string[]>(props.selectedModelIds);
const providerOptions = useMemo(() => Array.from(new Set(props.models.map((model) => model.providerKey))).filter(Boolean), [props.models]);
const providerOptions = useMemo(() => Array.from(new Set([
...props.models.map((model) => model.providerKey),
...props.models.flatMap((model) => providerModelPresets(model).map((preset) => preset.providerKey)),
])).filter(Boolean), [props.models]);
const draftIdSet = new Set(draftIds);
const keyword = query.trim().toLowerCase();
const filteredModels = props.models.filter((model) => {
if (providerFilter !== 'all' && model.providerKey !== providerFilter) return false;
if (providerFilter !== 'all' && !modelMatchesProvider(model, providerFilter)) return false;
const providerForText = providerFilter === 'all' ? props.currentProvider : providerFilter;
if (!keyword) return true;
return [
stableModelAlias(model),
model.providerModelName,
providerModelNameForProvider(model, providerForText),
model.canonicalModelKey,
baseModelTypeText(model),
baseModelTypeTextForProvider(model, providerForText),
model.providerKey,
props.providerMap.get(model.providerKey)?.displayName,
...providerModelPresets(model).flatMap((preset) => [
preset.providerKey,
preset.providerModelName,
preset.displayName,
preset.sourceProviderName,
]),
JSON.stringify(model.capabilities ?? {}),
].filter(Boolean).join(' ').toLowerCase().includes(keyword);
});
@@ -919,16 +945,26 @@ function ModelPickerDialog(props: {
</Button>
</div>
<div className="modelPickerList">
{filteredModels.length ? filteredModels.map((model) => (
<label className="modelPickerItem" key={model.id}>
<input type="checkbox" checked={draftIdSet.has(model.id)} onChange={() => toggleModel(model.id)} />
<span>
<strong>{stableModelAlias(model) || model.providerModelName}</strong>
<small>{props.providerMap.get(model.providerKey)?.displayName ?? model.providerKey} · {model.providerModelName} · {baseModelTypeText(model)}</small>
</span>
<Badge variant="outline">{baseModelTypeText(model)}</Badge>
</label>
)) : <div className="platformModelEmpty"></div>}
{filteredModels.length ? filteredModels.map((model) => {
const providerForText = providerFilter === 'all' ? props.currentProvider : providerFilter;
const preset = providerModelPresetFor(model, providerForText);
const providerModelName = providerModelNameForProvider(model, providerForText);
return (
<label className="modelPickerItem" key={model.id}>
<input type="checkbox" checked={draftIdSet.has(model.id)} onChange={() => toggleModel(model.id)} />
<span>
<strong>{stableModelAlias(model) || model.providerModelName}</strong>
<small>
{props.providerMap.get(model.providerKey)?.displayName ?? model.providerKey}
{preset ? ` · ${providerForText} 真实名 ${providerModelName}` : ` · ${model.providerModelName}`}
{' · '}
{baseModelTypeTextForProvider(model, providerForText)}
</small>
</span>
<Badge variant="outline">{baseModelTypeTextForProvider(model, providerForText)}</Badge>
</label>
);
}) : <div className="platformModelEmpty"></div>}
</div>
<footer className="modelPickerActions">
<Button type="button" variant="outline" onClick={props.onClose}></Button>