import React, { useCallback, useState, useRef, useMemo, useEffect } from 'react'; import { useRouter } from 'next/router'; import { getModelById, delModelById, postTrainModel, putModelTrainingStatus, putModelById } from '@/api/model'; import { getChatSiteId } from '@/api/chat'; import type { ModelSchema } from '@/types/mongoSchema'; import { Card, Box, Flex, Button, Tag, Grid } from '@chakra-ui/react'; import { useToast } from '@/hooks/useToast'; import { useForm } from 'react-hook-form'; import { formatModelStatus, ModelStatusEnum, modelList, defaultModel } from '@/constants/model'; import { useGlobalStore } from '@/store/global'; import { useScreen } from '@/hooks/useScreen'; import ModelEditForm from './components/ModelEditForm'; // import Icon from '@/components/Iconfont'; import { useQuery } from '@tanstack/react-query'; // import dynamic from 'next/dynamic'; import ModelDataCard from './components/ModelDataCard'; // const Training = dynamic(() => import('./components/Training')); const ModelDetail = ({ modelId }: { modelId: string }) => { const { toast } = useToast(); const router = useRouter(); const { isPc, media } = useScreen(); const { setLoading } = useGlobalStore(); const SelectFileDom = useRef(null); const [model, setModel] = useState(defaultModel); const formHooks = useForm({ defaultValues: model }); // const canTrain = useMemo(() => { // const openai = modelList.find((item) => item.model === model?.service.modelName); // return openai && openai.trainName; // }, [model]); /* 加载模型数据 */ const loadModel = useCallback(async () => { setLoading(true); try { const res = await getModelById(modelId); console.log(res); res.security.expiredTime /= 60 * 60 * 1000; setModel(res); formHooks.reset(res); } catch (err) { console.log('error->', err); } setLoading(false); return null; }, [formHooks, modelId, setLoading]); useQuery([modelId], loadModel); /* 点击删除 */ const handleDelModel = useCallback(async () => { if (!model) return; setLoading(true); try { await delModelById(model._id); toast({ title: '删除成功', status: 'success' }); router.replace('/model/list'); } catch (err) { console.log('error->', err); } setLoading(false); }, [setLoading, model, router, toast]); /* 点前往聊天预览页 */ const handlePreviewChat = useCallback(async () => { setLoading(true); try { const chatId = await getChatSiteId(model._id); router.push(`/chat?chatId=${chatId}`); } catch (err) { console.log('error->', err); } setLoading(false); }, [setLoading, model, router]); /* 上传数据集,触发微调 */ const startTraining = useCallback( async (e: React.ChangeEvent) => { if (!modelId || !e.target.files || e.target.files?.length === 0) return; setLoading(true); try { const file = e.target.files[0]; const formData = new FormData(); formData.append('file', file); await postTrainModel(modelId, formData); toast({ title: '开始训练...', status: 'success' }); // 重新获取模型 loadModel(); } catch (err: any) { toast({ title: err?.message || '上传文件失败', status: 'error' }); console.log('error->', err); } setLoading(false); }, [setLoading, loadModel, modelId, toast] ); /* 点击更新模型状态 */ const handleClickUpdateStatus = useCallback(async () => { if (!model || model.status !== ModelStatusEnum.training) return; setLoading(true); try { const res = await putModelTrainingStatus(model._id); typeof res === 'string' && toast({ title: res, status: 'info' }); loadModel(); } catch (error: any) { console.log('error->', error); toast({ title: error.message || '更新失败', status: 'error' }); } setLoading(false); }, [model, setLoading, loadModel, toast]); // 提交保存模型修改 const saveSubmitSuccess = useCallback( async (data: ModelSchema) => { setLoading(true); try { await putModelById(data._id, { name: data.name, systemPrompt: data.systemPrompt, intro: data.intro, temperature: data.temperature, service: data.service, security: data.security }); toast({ title: '更新成功', status: 'success' }); } catch (err) { console.log('error->', err); toast({ title: err as string, status: 'success' }); } setLoading(false); }, [setLoading, toast] ); // 提交保存表单失败 const saveSubmitError = useCallback(() => { // deep search message const deepSearch = (obj: any): string => { if (!obj) return '提交表单错误'; if (!!obj.message) { return obj.message; } return deepSearch(Object.values(obj)[0]); }; toast({ title: deepSearch(formHooks.formState.errors), status: 'error', duration: 4000, isClosable: true }); }, [formHooks.formState.errors, toast]); useEffect(() => { router.prefetch('/chat'); window.onbeforeunload = (e) => { e.preventDefault(); e.returnValue = '内容已修改,确认离开页面吗?'; }; return () => { window.onbeforeunload = null; }; }, [router]); return ( <> {/* 头部 */} {isPc ? ( {model.name} {formatModelStatus[model.status].text} ) : ( <> {model?.name} {formatModelStatus[model.status].text} )} {/* {canTrain && ( )} */} {model._id && } {/* 文件选择 */} ); }; export default ModelDetail; export async function getServerSideProps(context: any) { const modelId = context.query?.modelId || ''; return { props: { modelId } }; }