feat: M0-08 AI Gateway admin web page
Some checks failed
Deploy Admin Frontend / build-and-deploy (push) Has been cancelled
Some checks failed
Deploy Admin Frontend / build-and-deploy (push) Has been cancelled
This commit is contained in:
parent
b90ac755c4
commit
badf4258b1
@ -107,6 +107,10 @@ function App() {
|
||||
path="config"
|
||||
element={<PermissionGuard requiredRole="SUPER_ADMIN"><Suspense fallback={<PageLoading />}><ConfigPage /></Suspense></PermissionGuard>}
|
||||
/>
|
||||
<Route
|
||||
path="ai-gateway"
|
||||
element={<PermissionGuard requiredRole="SUPER_ADMIN"><Suspense fallback={<PageLoading />}><AiGatewayPage /></Suspense></PermissionGuard>}
|
||||
/>
|
||||
<Route
|
||||
path="metrics"
|
||||
element={<PermissionGuard requiredRole="SUPER_ADMIN"><Suspense fallback={<PageLoading />}><MetricsPage /></Suspense></PermissionGuard>}
|
||||
|
||||
@ -31,6 +31,7 @@ export const adminMenuItems: AdminMenuItem[] = [
|
||||
{ path: '/git', name: '代码仓库', icon: <CodeOutlined /> },
|
||||
{ path: '/ops', name: '系统运维', icon: <CloudServerOutlined />, requiredRole: 'SUPER_ADMIN', children: [
|
||||
{ path: '/metrics', name: '接口监控' },
|
||||
{ path: '/ai-gateway', name: 'AI Gateway' },
|
||||
{ path: '/servers', name: '服务器' },
|
||||
{ path: '/events', name: '事件队列' },
|
||||
{ path: '/config', name: '配置管理' },
|
||||
|
||||
@ -26,6 +26,7 @@ const breadcrumbMap: Record<string, string> = {
|
||||
'/servers': '服务器运维',
|
||||
'/config': '配置管理',
|
||||
'/metrics': '接口监控',
|
||||
'/ai-gateway': 'AI Gateway',
|
||||
'/safety': '内容安全',
|
||||
'/events': '事件队列',
|
||||
'/audit': '审计日志',
|
||||
|
||||
57
src/pages/AiGateway.tsx
Normal file
57
src/pages/AiGateway.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
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>
|
||||
)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user