fix: change agent model to single
parent
b0de11aff6
commit
cabea3f83a
|
|
@ -1,19 +1,21 @@
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Button, Checkbox, Dropdown } from 'antd';
|
import { Button, Radio, Dropdown } from 'antd';
|
||||||
import { DownOutlined } from '@ant-design/icons';
|
import { DownOutlined } from '@ant-design/icons';
|
||||||
import { AiModel } from '../../../api';
|
import { AiModel } from '../../../api';
|
||||||
import { DEFAULT_RH_40X40_GRAY } from '../../../constants';
|
import { DEFAULT_RH_40X40_GRAY } from '../../../constants';
|
||||||
|
|
||||||
interface ModelCheckboxDropdownProps {
|
interface ModelSelectDropdownProps {
|
||||||
value?: string[];
|
value?: string;
|
||||||
onChange?: (value: string[]) => void;
|
onChange?: (value: string) => void;
|
||||||
models: AiModel[];
|
models: AiModel[];
|
||||||
isMobile?: boolean;
|
isMobile?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ModelCheckboxDropdown({ value = [], onChange, models, isMobile = false }: ModelCheckboxDropdownProps) {
|
export default function ModelSelectDropdown({ value, onChange, models, isMobile = false }: ModelSelectDropdownProps) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const summary = value.length ? `${value.length} 个已选` : '选择模型';
|
|
||||||
|
const selectedModel = models.find(m => m.id === value);
|
||||||
|
const summary = selectedModel ? selectedModel.model_name : '选择模型';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
|
@ -22,43 +24,44 @@ export default function ModelCheckboxDropdown({ value = [], onChange, models, is
|
||||||
onOpenChange={setOpen}
|
onOpenChange={setOpen}
|
||||||
popupRender={() => (
|
popupRender={() => (
|
||||||
<div className={`agent-model-dropdown-panel${isMobile ? ' is-h5-panel' : ''}`} onClick={(e) => e.stopPropagation()}>
|
<div className={`agent-model-dropdown-panel${isMobile ? ' is-h5-panel' : ''}`} onClick={(e) => e.stopPropagation()}>
|
||||||
<Checkbox.Group
|
<Radio.Group
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(checked) => onChange?.(checked.map((item) => String(item)))}
|
onChange={(e) => {
|
||||||
className="agent-model-checkbox-group"
|
onChange?.(e.target.value);
|
||||||
|
setOpen(false); // 单选选中后自动关闭
|
||||||
|
}}
|
||||||
|
className="agent-model-radio-group"
|
||||||
>
|
>
|
||||||
{models.map((m) => {
|
{models.map((m) => {
|
||||||
const inputPrice = 2 * m.model_ratio;
|
const inputPrice = 2 * m.model_ratio;
|
||||||
const outputPrice = inputPrice * m.completion_ratio;
|
const outputPrice = inputPrice * m.completion_ratio;
|
||||||
return (
|
return (
|
||||||
<Checkbox key={m.id} value={m.id} className="agent-model-checkbox-item">
|
<Radio key={m.id} value={m.id} className="agent-model-radio-item">
|
||||||
<div className="agent-model-checkbox-content">
|
<div className="agent-model-radio-content">
|
||||||
<div className="agent-model-checkbox-meta">
|
<div className="agent-model-radio-meta">
|
||||||
<img
|
<img
|
||||||
src={m.icon || DEFAULT_RH_40X40_GRAY}
|
src={m.icon || DEFAULT_RH_40X40_GRAY}
|
||||||
alt={m.model_name}
|
alt={m.model_name}
|
||||||
className="agent-model-checkbox-icon"
|
className="agent-model-radio-icon"
|
||||||
/>
|
/>
|
||||||
<span className="agent-model-checkbox-name">{m.model_name}</span>
|
<span className="agent-model-radio-name">{m.model_name}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="agent-model-checkbox-price">
|
<div className="agent-model-radio-price">
|
||||||
<span>输入: ${inputPrice.toFixed(2)}/M</span>
|
<span>输入: ${inputPrice.toFixed(2)}/M</span>
|
||||||
<span>输出: ${outputPrice.toFixed(2)}/M</span>
|
<span>输出: ${outputPrice.toFixed(2)}/M</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Checkbox>
|
</Radio>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Checkbox.Group>
|
</Radio.Group>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Button type="text" block className="agent-model-dropdown-trigger">
|
<Button type="text" block className="agent-model-dropdown-trigger">
|
||||||
<span className="agent-model-dropdown-summary">{summary}</span>
|
<span className="agent-model-dropdown-summary">模型选择</span>
|
||||||
<span className="agent-model-dropdown-values">
|
<span className="agent-model-dropdown-values">
|
||||||
{value.length
|
{summary}
|
||||||
? value.map(id => models.find(m => m.id === id)?.model_name || id).join(', ')
|
|
||||||
: '未选择'}
|
|
||||||
</span>
|
</span>
|
||||||
<DownOutlined className="agent-model-dropdown-arrow" />
|
<DownOutlined className="agent-model-dropdown-arrow" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Form, InputNumber } from 'antd';
|
import { Form, InputNumber } from 'antd';
|
||||||
import { SettingOutlined } from '@ant-design/icons';
|
import { SettingOutlined } from '@ant-design/icons';
|
||||||
import { parseModelSelections } from '../../constants';
|
import { parseModelSelections } from '../../constants';
|
||||||
import ModelCheckboxDropdown from '../ModelCheckboxDropdown';
|
import ModelSelectDropdown from '../ModelSelectDropdown';
|
||||||
|
|
||||||
interface ModelSettingsCardProps {
|
interface ModelSettingsCardProps {
|
||||||
models: any[];
|
models: any[];
|
||||||
|
|
@ -22,17 +22,18 @@ export default function ModelSettingsCard({ models, isMobile = false }: ModelSet
|
||||||
required
|
required
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
validator: async (_rule, value) => {
|
required: true,
|
||||||
const selected = parseModelSelections(value);
|
message: '请选择一个模型',
|
||||||
if (selected.length > 0) return;
|
|
||||||
throw new Error('请选择至少一个模型');
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
className="mb-0"
|
className="mb-0"
|
||||||
getValueProps={(value) => ({ value: parseModelSelections(value) })}
|
getValueProps={(value) => {
|
||||||
|
// 如果后端返回的是数组或 JSON 字符串,取第一个作为单选值
|
||||||
|
const selected = parseModelSelections(value);
|
||||||
|
return { value: selected[0] || '' };
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<ModelCheckboxDropdown models={models} isMobile={isMobile} />
|
<ModelSelectDropdown models={models} isMobile={isMobile} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="temperature" label="Temperature" className="mb-0" hidden>
|
<Form.Item name="temperature" label="Temperature" className="mb-0" hidden>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
|
|
|
||||||
|
|
@ -946,14 +946,16 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-model-checkbox-group {
|
.agent-model-checkbox-group,
|
||||||
|
.agent-model-radio-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-model-checkbox-item {
|
.agent-model-checkbox-item,
|
||||||
|
.agent-model-radio-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
margin-inline-start: 0;
|
margin-inline-start: 0;
|
||||||
|
|
@ -963,15 +965,52 @@ body {
|
||||||
background: var(--color-surface);
|
background: var(--color-surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-model-checkbox-item .ant-checkbox {
|
.agent-model-checkbox-item .ant-checkbox,
|
||||||
|
.agent-model-radio-item .ant-radio {
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-model-checkbox-item .ant-checkbox + span {
|
.agent-model-checkbox-item .ant-checkbox + span,
|
||||||
|
.agent-model-radio-item .ant-radio + span {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-inline-start: 10px;
|
padding-inline-start: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.agent-model-radio-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-model-radio-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
min-width: 0;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-model-radio-name {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-model-radio-price {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: 8px;
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--color-text-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
.agent-model-checkbox-content {
|
.agent-model-checkbox-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -988,7 +1027,7 @@ body {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-model-checkbox-icon {
|
.agent-model-radio-icon {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue