feat: 模型介绍和温度调整。完善聊天页提示

This commit is contained in:
Archer
2023-03-18 12:32:55 +08:00
parent 1c364eca35
commit 00b90f071d
32 changed files with 628 additions and 327 deletions

View File

@@ -1,21 +1,29 @@
import React, { useCallback, useState, useEffect, useRef, useMemo } from 'react';
import React, { useCallback, useState, useRef, useMemo, useEffect } from 'react';
import { useRouter } from 'next/router';
import { getModelById, delModelById, postTrainModel, putModelTrainingStatus } from '@/api/model';
import {
getModelById,
delModelById,
postTrainModel,
putModelTrainingStatus,
putModelById
} from '@/api/model';
import { getChatSiteId } from '@/api/chat';
import type { ModelType } from '@/types/model';
import type { ModelSchema } from '@/types/mongoSchema';
import { Card, Box, Flex, Button, Tag, Grid } from '@chakra-ui/react';
import { useToast } from '@/hooks/useToast';
import { useConfirm } from '@/hooks/useConfirm';
import { formatModelStatus, ModelStatusEnum, OpenAiList } from '@/constants/model';
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';
const Training = dynamic(() => import('./components/Training'));
const ModelDetail = () => {
const ModelDetail = ({ modelId }: { modelId: string }) => {
const { toast } = useToast();
const router = useRouter();
const { isPc, media } = useScreen();
@@ -24,33 +32,35 @@ const ModelDetail = () => {
content: '确认删除该模型?'
});
const SelectFileDom = useRef<HTMLInputElement>(null);
const { modelId } = router.query as { modelId: string };
const [model, setModel] = useState<ModelType>();
const [model, setModel] = useState<ModelSchema>(defaultModel);
const formHooks = useForm<ModelSchema>({
defaultValues: model
});
const canTrain = useMemo(() => {
const openai = OpenAiList.find((item) => item.model === model?.service.modelName);
return openai && openai.canTraining === true;
const openai = ModelList[model.service.company].find(
(item) => item.model === model?.service.modelName
);
return openai && openai.trainName;
}, [model]);
/* 加载模型数据 */
const loadModel = useCallback(async () => {
if (!modelId) return;
setLoading(true);
try {
const res = await getModelById(modelId as string);
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);
}, [modelId, setLoading]);
return null;
}, [formHooks, modelId, setLoading]);
useEffect(() => {
loadModel();
router.prefetch('/chat');
}, [loadModel, modelId, router]);
useQuery([modelId], loadModel);
/* 点击删除 */
const handleDelModel = useCallback(async () => {
@@ -71,7 +81,6 @@ const ModelDetail = () => {
/* 点前往聊天预览页 */
const handlePreviewChat = useCallback(async () => {
if (!model) return;
setLoading(true);
try {
const chatId = await getChatSiteId(model._id);
@@ -131,6 +140,65 @@ const ModelDetail = () => {
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;
};
}, []);
return (
<>
{/* 头部 */}
@@ -138,50 +206,48 @@ const ModelDetail = () => {
{isPc ? (
<Flex alignItems={'center'}>
<Box fontSize={'xl'} fontWeight={'bold'}>
{model?.name || '模型'}
{model.name}
</Box>
{!!model && (
<Tag
ml={2}
variant="solid"
colorScheme={formatModelStatus[model.status].colorTheme}
cursor={model.status === ModelStatusEnum.training ? 'pointer' : 'default'}
onClick={handleClickUpdateStatus}
>
{formatModelStatus[model.status].text}
</Tag>
)}
<Tag
ml={2}
variant="solid"
colorScheme={formatModelStatus[model.status].colorTheme}
cursor={model.status === ModelStatusEnum.training ? 'pointer' : 'default'}
onClick={handleClickUpdateStatus}
>
{formatModelStatus[model.status].text}
</Tag>
<Box flex={1} />
<Button variant={'outline'} onClick={handlePreviewChat}>
</Button>
<Button ml={4} onClick={formHooks.handleSubmit(saveSubmitSuccess, saveSubmitError)}>
</Button>
</Flex>
) : (
<>
<Flex alignItems={'center'}>
<Box as={'h3'} fontSize={'xl'} fontWeight={'bold'} flex={1}>
{model?.name || '模型'}
{model?.name}
</Box>
{!!model && (
<Tag ml={2} colorScheme={formatModelStatus[model.status].colorTheme}>
{formatModelStatus[model.status].text}
</Tag>
)}
<Tag ml={2} colorScheme={formatModelStatus[model.status].colorTheme}>
{formatModelStatus[model.status].text}
</Tag>
</Flex>
<Box mt={4} textAlign={'right'}>
<Button variant={'outline'} onClick={handlePreviewChat}>
</Button>
<Button ml={4} onClick={formHooks.handleSubmit(saveSubmitSuccess, saveSubmitError)}>
</Button>
</Box>
</>
)}
</Card>
{/* 基本信息编辑 */}
<Box mt={5}>
<ModelEditForm model={model} />
</Box>
{/* 其他配置 */}
<Grid mt={5} gridTemplateColumns={media('1fr 1fr', '1fr')} gridGap={5}>
<ModelEditForm formHooks={formHooks} />
<Card p={4}>{!!model && <Training model={model} />}</Card>
<Card p={4}>
<Box fontWeight={'bold'} fontSize={'lg'}>
@@ -241,6 +307,8 @@ const ModelDetail = () => {
</Flex>
</Card>
</Grid>
{/* 文件选择 */}
<Box position={'absolute'} w={0} h={0} overflow={'hidden'}>
<input ref={SelectFileDom} type="file" accept=".jsonl" onChange={startTraining} />
</Box>
@@ -250,3 +318,11 @@ const ModelDetail = () => {
};
export default ModelDetail;
export async function getServerSideProps(context: any) {
const modelId = context.query?.modelId || '';
return {
props: { modelId }
};
}