83 lines
3.4 KiB
TypeScript
83 lines
3.4 KiB
TypeScript
|
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
|||
|
|
import { Card, Row, Col, Statistic, Button, Typography, Descriptions, App } from 'antd'
|
|||
|
|
import { ReloadOutlined, DatabaseOutlined, NodeIndexOutlined } from '@ant-design/icons'
|
|||
|
|
import { api } from '@/services/http-client'
|
|||
|
|
|
|||
|
|
const { Title } = Typography
|
|||
|
|
|
|||
|
|
export default function VectorAdminPage() {
|
|||
|
|
const qc = useQueryClient()
|
|||
|
|
const { message } = App.useApp()
|
|||
|
|
|
|||
|
|
const { data: coll, isLoading: collLoading } = useQuery({
|
|||
|
|
queryKey: ['vector', 'collection'],
|
|||
|
|
queryFn: (): Promise<any> => api.get('/admin-api/vector/collection'),
|
|||
|
|
staleTime: 30_000,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
const { data: count } = useQuery({
|
|||
|
|
queryKey: ['vector', 'count'],
|
|||
|
|
queryFn: (): Promise<any> => api.get('/admin-api/vector/count'),
|
|||
|
|
staleTime: 30_000,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
const handleReindex = async () => {
|
|||
|
|
try {
|
|||
|
|
await api.post('/admin-api/vector/reindex')
|
|||
|
|
message.success('索引重建已提交')
|
|||
|
|
qc.invalidateQueries({ queryKey: ['vector'] })
|
|||
|
|
} catch {
|
|||
|
|
message.error('操作失败')
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div>
|
|||
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}>
|
|||
|
|
<Title level={5} style={{ margin: 0 }}><DatabaseOutlined /> 向量检索</Title>
|
|||
|
|
<Button icon={<ReloadOutlined />} onClick={() => qc.invalidateQueries({ queryKey: ['vector'] })}>刷新</Button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<Row gutter={[16, 16]} style={{ marginBottom: 16 }}>
|
|||
|
|
<Col span={6}>
|
|||
|
|
<Card size="small"><Statistic title="向量总数" value={count?.count ?? 0} loading={collLoading} suffix="条" /></Card>
|
|||
|
|
</Col>
|
|||
|
|
<Col span={6}>
|
|||
|
|
<Card size="small"><Statistic title="向量维度" value={coll?.vectorSize || 1024} /></Card>
|
|||
|
|
</Col>
|
|||
|
|
<Col span={6}>
|
|||
|
|
<Card size="small"><Statistic title="距离度量" value={coll?.distance || 'Cosine'} /></Card>
|
|||
|
|
</Col>
|
|||
|
|
<Col span={6}>
|
|||
|
|
<Card size="small"><Statistic title="状态" value={coll?.status || '-'} valueStyle={{ color: coll?.status === 'green' ? '#52c41a' : '#faad14' }} /></Card>
|
|||
|
|
</Col>
|
|||
|
|
</Row>
|
|||
|
|
|
|||
|
|
<Row gutter={[16, 16]}>
|
|||
|
|
<Col span={16}>
|
|||
|
|
<Card size="small" title="Collection 信息">
|
|||
|
|
<Descriptions column={2} size="small" bordered>
|
|||
|
|
<Descriptions.Item label="名称">{coll?.name || 'zhixi_chunks'}</Descriptions.Item>
|
|||
|
|
<Descriptions.Item label="向量维度">{coll?.vectorSize || 1024}</Descriptions.Item>
|
|||
|
|
<Descriptions.Item label="距离度量">{coll?.distance || 'Cosine'}</Descriptions.Item>
|
|||
|
|
<Descriptions.Item label="向量总数">{count?.count ?? 0}</Descriptions.Item>
|
|||
|
|
<Descriptions.Item label="索引算法">HNSW (m=16, ef_construct=100)</Descriptions.Item>
|
|||
|
|
<Descriptions.Item label="Payload 索引">userId (keyword), knowledgeBaseId (keyword), deleted (bool)</Descriptions.Item>
|
|||
|
|
</Descriptions>
|
|||
|
|
</Card>
|
|||
|
|
</Col>
|
|||
|
|
<Col span={8}>
|
|||
|
|
<Card size="small" title="索引操作">
|
|||
|
|
<Button icon={<NodeIndexOutlined />} block onClick={handleReindex} style={{ marginBottom: 8 }}>
|
|||
|
|
触发索引重建
|
|||
|
|
</Button>
|
|||
|
|
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
|||
|
|
索引重建会通过任务队列异步执行,不影响线上检索。建议在低峰期操作。
|
|||
|
|
</Typography.Text>
|
|||
|
|
</Card>
|
|||
|
|
</Col>
|
|||
|
|
</Row>
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|