admin-projects/src/pages/AiGateway.tsx
WangDL badf4258b1
Some checks failed
Deploy Admin Frontend / build-and-deploy (push) Has been cancelled
feat: M0-08 AI Gateway admin web page
2026-05-23 09:39:53 +08:00

58 lines
3.0 KiB
TypeScript

import { useQuery, useQueryClient } from '@tanstack/react-query'
import { Card, Row, Col, Statistic, Table, Tag, Button, Typography } from 'antd'
import { ReloadOutlined, CloudOutlined } from '@ant-design/icons'
import { api } from '@/services/http-client'
const { Title, Text } = Typography
export default function AiGatewayPage() {
const qc = useQueryClient()
const { data } = useQuery({ queryKey: ['ai-gateway', 'status'], queryFn: (): Promise<any> => api.get('/admin-api/ai-gateway/status'), staleTime: 30_000 })
const tierCols = [
{ title: '级别', dataIndex: 'name', width: 80 },
{ title: '主模型', dataIndex: 'provider', width: 120 },
{ title: '模型', dataIndex: 'model', width: 180 },
{ title: '备用', dataIndex: 'fallback', width: 180, render: (v: string) => v || '-' },
]
const tiers = data?.tiers ? [
{ name: 'cheap', ...data.tiers.cheap, fallback: data.tiers.cheap.fallback?.model || '-' },
{ name: 'primary', ...data.tiers.primary, fallback: data.tiers.primary.fallback?.model || data.tiers.primary.fallback || '-' },
{ name: 'strong', ...data.tiers.strong, fallback: data.tiers.strong.fallback?.model || '-' },
] : []
return (
<div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}>
<Title level={5} style={{ margin: 0 }}><CloudOutlined /> AI Gateway</Title>
<Button icon={<ReloadOutlined />} onClick={() => qc.invalidateQueries({ queryKey: ['ai-gateway'] })}></Button>
</div>
<Row gutter={[16, 16]} style={{ marginBottom: 16 }}>
<Col span={6}><Card size="small"><Statistic title="Provider" value={data?.providers?.length || 0} suffix="个" /></Card></Col>
<Col span={6}><Card size="small"><Statistic title="Prompt 模板" value={data?.prompts?.length || 0} suffix="个" /></Card></Col>
<Col span={6}><Card size="small"><Statistic title="路由级别" value={3} suffix="层" /></Card></Col>
<Col span={6}><Card size="small"><Statistic title="重试次数" value={data?.retry?.primary || 3} suffix="次" /></Card></Col>
</Row>
<Row gutter={[16, 16]}>
<Col span={12}>
<Card size="small" title="Provider 列表">
<Table dataSource={(data?.providers || []).map((p: string) => ({ name: p }))} columns={[{ title: '名称', dataIndex: 'name', render: (v: string) => <Tag color={v==='deepseek'?'blue':v==='minimax'?'purple':'green'}>{v}</Tag> }]} rowKey="name" pagination={false} size="small" />
</Card>
</Col>
<Col span={12}>
<Card size="small" title="模型路由">
<Table dataSource={tiers} columns={tierCols} rowKey="name" pagination={false} size="small" />
</Card>
</Col>
</Row>
<Card size="small" title="Prompt 模板" style={{ marginTop: 16 }}>
<Table dataSource={(data?.prompts || []).map((p: string) => ({ name: p }))} columns={[{ title: '名称', dataIndex: 'name', render: (v: string) => <Text code>{v}</Text> }]} rowKey="name" pagination={false} size="small" />
</Card>
</div>
)
}