import React, { useState, useMemo } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { useForm, Controller } from 'react-hook-form'; import { Box, Container, Typography, Paper, TextField, Button, Slider, FormControl, InputLabel, Select, MenuItem, FormControlLabel, Switch, Grid, Pagination, Checkbox, ListItemText, OutlinedInput, ListSubheader, Chip, } from '@mui/material'; import { useKnowledgeDetail } from '@/hooks/knowledge-hooks'; import { useRerankModelOptions } from '@/hooks/llm-hooks'; import knowledgeService from '@/services/knowledge_service'; import type { ITestRetrievalRequestBody } from '@/interfaces/request/knowledge'; import type { INextTestingResult } from '@/interfaces/database/knowledge'; import KnowledgeBreadcrumbs from './components/KnowledgeBreadcrumbs'; import TestChunkResult from './components/TestChunkResult'; import { useSnackbar } from '@/components/Provider/SnackbarProvider'; import { useTranslation } from 'react-i18next'; import { toLower } from 'lodash'; import { t } from 'i18next'; // 语言选项常量 const Languages = [ 'English', 'Chinese', 'Spanish', 'French', 'German', 'Japanese', 'Korean', 'Vietnamese', ]; const options = Languages.map((x) => ({ label: t('language.' + toLower(x)), value: x, })); // 表单数据接口 interface TestFormData { question: string; similarity_threshold: number; vector_similarity_weight: number; rerank_id?: string; top_k?: number; use_kg?: boolean; cross_languages?: string[]; doc_ids?: string[]; } function KnowledgeBaseTesting() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const { t } = useTranslation(); // 状态管理 const [testResult, setTestResult] = useState(null); const [testing, setTesting] = useState(false); const [page, setPage] = useState(1); const [pageSize] = useState(10); const [selectedDocIds, setSelectedDocIds] = useState([]); const { showMessage } = useSnackbar(); // 获取知识库详情 const { knowledge: knowledgeDetail, loading: detailLoading } = useKnowledgeDetail(id || ''); // 获取重排序模型选项 const { options: rerankOptions, loading: rerankLoading } = useRerankModelOptions(); // 表单配置 const { control, handleSubmit, watch, register, setValue, getValues, formState: { errors } } = useForm({ defaultValues: { question: '', similarity_threshold: 0.2, vector_similarity_weight: 0.3, rerank_id: '', top_k: 1024, use_kg: false, cross_languages: [], doc_ids: [], }, }); // 处理测试提交 const handleTestSubmit = async (data: TestFormData) => { if (!id) return; setTesting(true); try { const requestBody: ITestRetrievalRequestBody = { question: data.question, similarity_threshold: data.similarity_threshold, vector_similarity_weight: data.vector_similarity_weight, kb_id: id, page: page, size: pageSize, }; // 只有当字段有值时才添加到请求体中 if (data.rerank_id) { requestBody.rerank_id = data.rerank_id; } if (data.top_k) { requestBody.top_k = data.top_k; } if (data.use_kg !== undefined) { requestBody.use_kg = data.use_kg; } // 如果有选择的文档,添加到请求中 if (data.doc_ids && data.doc_ids.length > 0) { requestBody.doc_ids = data.doc_ids; } else { if (selectedDocIds.length > 0) { requestBody.doc_ids = selectedDocIds; } } if (data.cross_languages && data.cross_languages.length > 0) { requestBody.cross_languages = data.cross_languages; } const response = await knowledgeService.retrievalTest(requestBody); if (response.data.code === 0) { setTestResult(response.data.data); setPage(1); // 重置到第一页 showMessage.success('检索测试完成'); } else { throw new Error(response.data.message || '检索测试失败'); } } catch (error: any) { showMessage.error(error.message || '检索测试失败'); } finally { setTesting(false); } }; // 处理分页变化 const handlePageChange = async (event: React.ChangeEvent, value: number) => { if (!id) return; setPage(value); setTesting(true); try { const formData = getValues(); const requestBody: ITestRetrievalRequestBody = { question: formData.question, similarity_threshold: formData.similarity_threshold, vector_similarity_weight: formData.vector_similarity_weight, kb_id: id, page: value, size: pageSize, highlight: true, }; // 只有当字段有值时才添加到请求体中 if (formData.rerank_id) { requestBody.rerank_id = formData.rerank_id; } if (formData.top_k) { requestBody.top_k = formData.top_k; } if (formData.use_kg !== undefined) { requestBody.use_kg = formData.use_kg; } if (selectedDocIds.length > 0) { requestBody.doc_ids = selectedDocIds; } if (formData.cross_languages && formData.cross_languages.length > 0) { requestBody.cross_languages = formData.cross_languages; } const response = await knowledgeService.retrievalTest(requestBody); if (response.data.code === 0) { setTestResult(response.data.data); } else { throw new Error(response.data.message || '分页请求失败'); } } catch (error: any) { showMessage.error(error.message || '分页请求失败'); } finally { setTesting(false); } }; // 处理文档过滤 const handleDocumentFilter = (docIds: string[]) => { setSelectedDocIds(docIds); setValue('doc_ids', docIds); handleTestSubmit(getValues()); }; // 返回详情页 const handleBackToDetail = () => { navigate(`/knowledge/${id}`); }; if (detailLoading) { return ( 加载中... ); } return ( {/* 面包屑导航 */} 知识库测试 {knowledgeDetail?.name} {/* 测试表单 */} 测试配置 相似度阈值: {watch('similarity_threshold')} setValue('similarity_threshold', value as number)} min={0} max={1} step={0.1} marks valueLabelDisplay="auto" /> 向量相似度权重: {watch('vector_similarity_weight')} setValue('vector_similarity_weight', value as number)} min={0} max={1} step={0.1} marks valueLabelDisplay="auto" /> 重排序模型 (可选) ( )} /> {/* Top-K 字段 - 只有选择了rerank_id时才显示 */} {watch('rerank_id') && ( )} 跨语言搜索 ( )} /> } label="使用知识图谱" /> {testResult && ( )} {/* 分页组件 */} {testResult && testResult.total > 10 && ( )} ); }; export default KnowledgeBaseTesting;