feat(agent): support selecting models from api with calculated prices

main
sp mac bookpro 2605 2026-05-25 23:03:19 +08:00
parent 109d9cc779
commit 7cf68160a8
2 changed files with 39 additions and 4 deletions

View File

@ -111,6 +111,17 @@ export interface ChatHistoryResp {
branches: Record<string, BranchInfo>; branches: Record<string, BranchInfo>;
} }
export interface AiModel {
model_name: string;
icon: string;
model_ratio: number;
completion_ratio: number;
}
export const ModelAPI = {
list: () => api.get<{ data: AiModel[] }>('/models').then((r) => r.data.data),
};
export const AgentAPI = { export const AgentAPI = {
list: () => api.get<Agent[]>('/agents').then((r) => r.data), list: () => api.get<Agent[]>('/agents').then((r) => r.data),
detail: (id: string) => api.get<Agent>(`/agents/${id}`).then((r) => r.data), detail: (id: string) => api.get<Agent>(`/agents/${id}`).then((r) => r.data),

View File

@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react';
import { Button, Form, Input, InputNumber, Modal, Upload, App as AntApp, List, Popconfirm, Tag, Switch, Select, Collapse } from 'antd'; import { Button, Form, Input, InputNumber, Modal, Upload, App as AntApp, List, Popconfirm, Tag, Switch, Select, Collapse } from 'antd';
import type { UploadFile } from 'antd/es/upload/interface'; import type { UploadFile } from 'antd/es/upload/interface';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { Agent, AgentAPI, ImageAPI, KnowledgeStatus, SkillType, Team, TeamAPI } from '../api'; import { Agent, AgentAPI, ImageAPI, KnowledgeStatus, SkillType, Team, TeamAPI, AiModel, ModelAPI } from '../api';
import SkillEditor from '../components/SkillEditor'; import SkillEditor from '../components/SkillEditor';
import McpPanel from '../components/McpPanel'; import McpPanel from '../components/McpPanel';
import ChatPreview from '../components/ChatPreview'; import ChatPreview from '../components/ChatPreview';
@ -37,6 +37,7 @@ export default function AgentEditor() {
const [agent, setAgent] = useState<Agent | null>(null); const [agent, setAgent] = useState<Agent | null>(null);
const [saving, setSaving] = useState(false); const [saving, setSaving] = useState(false);
const [teams, setTeams] = useState<Team[]>([]); const [teams, setTeams] = useState<Team[]>([]);
const [models, setModels] = useState<AiModel[]>([]);
const [autoSaveStatus, setAutoSaveStatus] = useState<'saved' | 'saving' | 'error'>('saved'); const [autoSaveStatus, setAutoSaveStatus] = useState<'saved' | 'saving' | 'error'>('saved');
const [initModalOpen, setInitModalOpen] = useState(isNew); const [initModalOpen, setInitModalOpen] = useState(isNew);
const [selectedAvatar, setSelectedAvatar] = useState(DEFAULT_AVATAR); const [selectedAvatar, setSelectedAvatar] = useState(DEFAULT_AVATAR);
@ -74,6 +75,9 @@ export default function AgentEditor() {
TeamAPI.list() TeamAPI.list()
.then(setTeams) .then(setTeams)
.catch(() => setTeams([])); .catch(() => setTeams([]));
ModelAPI.list()
.then(setModels)
.catch(() => setModels([]));
if (isNew) { if (isNew) {
setInitModalOpen(true); setInitModalOpen(true);
setSelectedAvatar(DEFAULT_AVATAR); setSelectedAvatar(DEFAULT_AVATAR);
@ -475,9 +479,29 @@ export default function AgentEditor() {
label="模型" label="模型"
className="mb-0" className="mb-0"
> >
<Input <Select
placeholder="默认模型" placeholder="选择模型"
style={{ borderRadius: 12, height: 42 }} style={{ height: 42 }}
dropdownStyle={{ borderRadius: 12 }}
options={models.map((m) => {
const inputPrice = 2 * m.model_ratio;
const outputPrice = inputPrice * m.completion_ratio;
return {
value: m.model_name,
label: (
<div className="flex items-center justify-between w-full py-1">
<div className="flex items-center gap-2">
<img src={m.icon} alt={m.model_name} className="w-5 h-5 object-contain rounded" />
<span className="font-medium text-gray-800">{m.model_name}</span>
</div>
<div className="flex flex-col items-end justify-center text-[10px] text-gray-400">
<span>: ${inputPrice.toFixed(2)}/M</span>
<span>: ${outputPrice.toFixed(2)}/M</span>
</div>
</div>
),
};
})}
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item