feat: 模型数据管理

This commit is contained in:
archer 2023-03-29 00:22:48 +08:00
parent 713332522f
commit f32c557bdd
No known key found for this signature in database
GPG Key ID: 166CA6BF2383B2BB
14 changed files with 366 additions and 95 deletions

View File

@ -41,6 +41,7 @@
"react-hook-form": "^7.43.1", "react-hook-form": "^7.43.1",
"react-markdown": "^8.0.5", "react-markdown": "^8.0.5",
"react-syntax-highlighter": "^15.5.0", "react-syntax-highlighter": "^15.5.0",
"redis": "^4.6.5",
"rehype-katex": "^6.0.2", "rehype-katex": "^6.0.2",
"remark-gfm": "^3.0.1", "remark-gfm": "^3.0.1",
"remark-math": "^5.1.1", "remark-math": "^5.1.1",

95
pnpm-lock.yaml generated
View File

@ -47,6 +47,7 @@ specifiers:
react-hook-form: ^7.43.1 react-hook-form: ^7.43.1
react-markdown: ^8.0.5 react-markdown: ^8.0.5
react-syntax-highlighter: ^15.5.0 react-syntax-highlighter: ^15.5.0
redis: ^4.6.5
rehype-katex: ^6.0.2 rehype-katex: ^6.0.2
remark-gfm: ^3.0.1 remark-gfm: ^3.0.1
remark-math: ^5.1.1 remark-math: ^5.1.1
@ -87,6 +88,7 @@ dependencies:
react-hook-form: registry.npmmirror.com/react-hook-form/7.43.1_react@18.2.0 react-hook-form: registry.npmmirror.com/react-hook-form/7.43.1_react@18.2.0
react-markdown: registry.npmmirror.com/react-markdown/8.0.5_pmekkgnqduwlme35zpnqhenc34 react-markdown: registry.npmmirror.com/react-markdown/8.0.5_pmekkgnqduwlme35zpnqhenc34
react-syntax-highlighter: registry.npmmirror.com/react-syntax-highlighter/15.5.0_react@18.2.0 react-syntax-highlighter: registry.npmmirror.com/react-syntax-highlighter/15.5.0_react@18.2.0
redis: registry.npmmirror.com/redis/4.6.5
rehype-katex: registry.npmmirror.com/rehype-katex/6.0.2 rehype-katex: registry.npmmirror.com/rehype-katex/6.0.2
remark-gfm: registry.npmmirror.com/remark-gfm/3.0.1 remark-gfm: registry.npmmirror.com/remark-gfm/3.0.1
remark-math: registry.npmmirror.com/remark-math/5.1.1 remark-math: registry.npmmirror.com/remark-math/5.1.1
@ -4504,6 +4506,72 @@ packages:
version: 2.11.6 version: 2.11.6
dev: false dev: false
registry.npmmirror.com/@redis/bloom/1.2.0_@redis+client@1.5.6:
resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@redis/bloom/-/bloom-1.2.0.tgz}
id: registry.npmmirror.com/@redis/bloom/1.2.0
name: '@redis/bloom'
version: 1.2.0
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': registry.npmmirror.com/@redis/client/1.5.6
dev: false
registry.npmmirror.com/@redis/client/1.5.6:
resolution: {integrity: sha512-dFD1S6je+A47Lj22jN/upVU2fj4huR7S9APd7/ziUXsIXDL+11GPYti4Suv5y8FuXaN+0ZG4JF+y1houEJ7ToA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@redis/client/-/client-1.5.6.tgz}
name: '@redis/client'
version: 1.5.6
engines: {node: '>=14'}
dependencies:
cluster-key-slot: registry.npmmirror.com/cluster-key-slot/1.1.2
generic-pool: registry.npmmirror.com/generic-pool/3.9.0
yallist: registry.npmmirror.com/yallist/4.0.0
dev: false
registry.npmmirror.com/@redis/graph/1.1.0_@redis+client@1.5.6:
resolution: {integrity: sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@redis/graph/-/graph-1.1.0.tgz}
id: registry.npmmirror.com/@redis/graph/1.1.0
name: '@redis/graph'
version: 1.1.0
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': registry.npmmirror.com/@redis/client/1.5.6
dev: false
registry.npmmirror.com/@redis/json/1.0.4_@redis+client@1.5.6:
resolution: {integrity: sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@redis/json/-/json-1.0.4.tgz}
id: registry.npmmirror.com/@redis/json/1.0.4
name: '@redis/json'
version: 1.0.4
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': registry.npmmirror.com/@redis/client/1.5.6
dev: false
registry.npmmirror.com/@redis/search/1.1.2_@redis+client@1.5.6:
resolution: {integrity: sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@redis/search/-/search-1.1.2.tgz}
id: registry.npmmirror.com/@redis/search/1.1.2
name: '@redis/search'
version: 1.1.2
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': registry.npmmirror.com/@redis/client/1.5.6
dev: false
registry.npmmirror.com/@redis/time-series/1.0.4_@redis+client@1.5.6:
resolution: {integrity: sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@redis/time-series/-/time-series-1.0.4.tgz}
id: registry.npmmirror.com/@redis/time-series/1.0.4
name: '@redis/time-series'
version: 1.0.4
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': registry.npmmirror.com/@redis/client/1.5.6
dev: false
registry.npmmirror.com/@rushstack/eslint-patch/1.2.0: registry.npmmirror.com/@rushstack/eslint-patch/1.2.0:
resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz} resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz}
name: '@rushstack/eslint-patch' name: '@rushstack/eslint-patch'
@ -5562,6 +5630,13 @@ packages:
version: 0.0.1 version: 0.0.1
dev: false dev: false
registry.npmmirror.com/cluster-key-slot/1.1.2:
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz}
name: cluster-key-slot
version: 1.1.2
engines: {node: '>=0.10.0'}
dev: false
registry.npmmirror.com/color-convert/1.9.3: registry.npmmirror.com/color-convert/1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz} resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz}
name: color-convert name: color-convert
@ -6799,6 +6874,13 @@ packages:
version: 1.2.3 version: 1.2.3
dev: true dev: true
registry.npmmirror.com/generic-pool/3.9.0:
resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/generic-pool/-/generic-pool-3.9.0.tgz}
name: generic-pool
version: 3.9.0
engines: {node: '>= 4'}
dev: false
registry.npmmirror.com/gensync/1.0.0-beta.2: registry.npmmirror.com/gensync/1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz} resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz}
name: gensync name: gensync
@ -9367,6 +9449,19 @@ packages:
picomatch: registry.npmmirror.com/picomatch/2.3.1 picomatch: registry.npmmirror.com/picomatch/2.3.1
dev: false dev: false
registry.npmmirror.com/redis/4.6.5:
resolution: {integrity: sha512-O0OWA36gDQbswOdUuAhRL6mTZpHFN525HlgZgDaVNgCJIAZR3ya06NTESb0R+TUZ+BFaDpz6NnnVvoMx9meUFg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/redis/-/redis-4.6.5.tgz}
name: redis
version: 4.6.5
dependencies:
'@redis/bloom': registry.npmmirror.com/@redis/bloom/1.2.0_@redis+client@1.5.6
'@redis/client': registry.npmmirror.com/@redis/client/1.5.6
'@redis/graph': registry.npmmirror.com/@redis/graph/1.1.0_@redis+client@1.5.6
'@redis/json': registry.npmmirror.com/@redis/json/1.0.4_@redis+client@1.5.6
'@redis/search': registry.npmmirror.com/@redis/search/1.1.2_@redis+client@1.5.6
'@redis/time-series': registry.npmmirror.com/@redis/time-series/1.0.4_@redis+client@1.5.6
dev: false
registry.npmmirror.com/refractor/3.6.0: registry.npmmirror.com/refractor/3.6.0:
resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/refractor/-/refractor-3.6.0.tgz} resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/refractor/-/refractor-3.6.0.tgz}
name: refractor name: refractor

View File

@ -2,6 +2,9 @@ import { GET, POST, DELETE, PUT } from './request';
import type { ModelSchema } from '@/types/mongoSchema'; import type { ModelSchema } from '@/types/mongoSchema';
import { ModelUpdateParams } from '@/types/model'; import { ModelUpdateParams } from '@/types/model';
import { TrainingItemType } from '../types/training'; import { TrainingItemType } from '../types/training';
import { PagingData } from '@/types';
import { RequestPaging } from '../types/index';
import { Obj2Query } from '@/utils/tools';
export const getMyModels = () => GET<ModelSchema[]>('/model/list'); export const getMyModels = () => GET<ModelSchema[]>('/model/list');
@ -16,13 +19,30 @@ export const putModelById = (id: string, data: ModelUpdateParams) =>
PUT(`/model/update?modelId=${id}`, data); PUT(`/model/update?modelId=${id}`, data);
export const postTrainModel = (id: string, form: FormData) => export const postTrainModel = (id: string, form: FormData) =>
POST(`/model/train?modelId=${id}`, form, { POST(`/model/train/train?modelId=${id}`, form, {
headers: { headers: {
'content-type': 'multipart/form-data' 'content-type': 'multipart/form-data'
} }
}); });
export const putModelTrainingStatus = (id: string) => PUT(`/model/putTrainStatus?modelId=${id}`); export const putModelTrainingStatus = (id: string) =>
PUT(`/model/train/putTrainStatus?modelId=${id}`);
export const getModelTrainings = (id: string) => export const getModelTrainings = (id: string) =>
GET<TrainingItemType[]>(`/model/getTrainings?modelId=${id}`); GET<TrainingItemType[]>(`/model/train/getTrainings?modelId=${id}`);
/* 模型 data */
type GetModelDataListProps = RequestPaging & {
modelId: string;
};
export const getModelDataList = (props: GetModelDataListProps) =>
GET(`/model/data/getModelData?${Obj2Query(props)}`);
export const postModelData = (data: { modelId: string; data: { q: string; a: string }[] }) =>
POST(`/model/data/pushModelData`, data);
export const putModelDataById = (data: { modelId: string; answer: string }) =>
PUT('/model/data/putModelData', data);
export const DelOneModelData = (modelId: string) =>
DELETE(`/model/data/delModelDataById?modelId=${modelId}`);

View File

@ -1,5 +1,4 @@
import type { ServiceName } from '@/types/mongoSchema'; import type { ServiceName, ModelDataType, ModelSchema } from '@/types/mongoSchema';
import { ModelSchema } from '../types/mongoSchema';
export enum ChatModelNameEnum { export enum ChatModelNameEnum {
GPT35 = 'gpt-3.5-turbo', GPT35 = 'gpt-3.5-turbo',
@ -76,6 +75,12 @@ export const formatModelStatus = {
} }
}; };
export const ModelDataStatusMap: Record<ModelDataType, string> = {
0: '训练完成',
1: '等待训练',
2: '训练中'
};
export const defaultModel: ModelSchema = { export const defaultModel: ModelSchema = {
_id: '', _id: '',
userId: '', userId: '',

View File

@ -8,7 +8,7 @@ export const usePaging = <T = any>({
pageSize = 10, pageSize = 10,
params = {} params = {}
}: { }: {
api: (data: any) => Promise<PagingData<T>>; api: (data: any) => any;
pageSize?: number; pageSize?: number;
params?: Record<string, any>; params?: Record<string, any>;
}) => { }) => {
@ -30,7 +30,7 @@ export const usePaging = <T = any>({
setRequesting(true); setRequesting(true);
try { try {
const res = await api({ const res: PagingData<T> = await api({
pageNum: num, pageNum: num,
pageSize, pageSize,
...params ...params

View File

@ -14,6 +14,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
pageNum: string; pageNum: string;
pageSize: string; pageSize: string;
}; };
const { authorization } = req.headers; const { authorization } = req.headers;
pageNum = +pageNum; pageNum = +pageNum;
@ -41,7 +42,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
.limit(pageSize); .limit(pageSize);
jsonRes(res, { jsonRes(res, {
data data: {
pageNum,
pageSize,
data,
total: await ModelData.countDocuments({
modelId,
userId
})
}
}); });
} catch (err) { } catch (err) {
jsonRes(res, { jsonRes(res, {

View File

@ -0,0 +1,86 @@
import React, { useEffect, useCallback, useState } from 'react';
import {
Box,
TableContainer,
Table,
Thead,
Tbody,
Tr,
Th,
Td,
IconButton,
Flex,
Button
} from '@chakra-ui/react';
import type { ModelSchema } from '@/types/mongoSchema';
import { ModelDataSchema } from '@/types/mongoSchema';
import { ModelDataStatusMap } from '@/constants/model';
import { usePaging } from '@/hooks/usePaging';
import ScrollData from '@/components/ScrollData';
import { getModelDataList } from '@/api/model';
import { DeleteIcon } from '@chakra-ui/icons';
const ModelDataCard = ({ model }: { model: ModelSchema }) => {
const {
nextPage,
isLoadAll,
requesting,
data: dataList,
total
} = usePaging<ModelDataSchema>({
api: getModelDataList,
pageSize: 10,
params: {
modelId: model._id
}
});
return (
<>
<Flex>
<Box fontWeight={'bold'} fontSize={'lg'} flex={1}>
: {total}
</Box>
<Button size={'sm'}></Button>
</Flex>
<ScrollData
flex={'1 0 0'}
h={0}
px={6}
mt={3}
isLoadAll={isLoadAll}
requesting={requesting}
nextPage={nextPage}
fontSize={'xs'}
whiteSpace={'pre-wrap'}
>
<TableContainer mt={4}>
<Table variant={'simple'}>
<Thead>
<Tr>
<Th>Question</Th>
<Th>Text</Th>
<Th>Status</Th>
<Th></Th>
</Tr>
</Thead>
<Tbody>
{dataList.map((item) => (
<Tr key={item._id}>
<Td>{item.q}</Td>
<Td>{item.a}</Td>
<Td>{ModelDataStatusMap[item.status]}</Td>
<Td>
<IconButton icon={<DeleteIcon />} aria-label={'delete'} />
</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
</ScrollData>
</>
);
};
export default ModelDataCard;

View File

@ -11,13 +11,26 @@ import {
SliderFilledTrack, SliderFilledTrack,
SliderThumb, SliderThumb,
SliderMark, SliderMark,
Tooltip Tooltip,
Button
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { QuestionOutlineIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon } from '@chakra-ui/icons';
import type { ModelSchema } from '@/types/mongoSchema'; import type { ModelSchema } from '@/types/mongoSchema';
import { UseFormReturn } from 'react-hook-form'; import { UseFormReturn } from 'react-hook-form';
import { modelList } from '@/constants/model';
import { formatPrice } from '@/utils/user';
import { useConfirm } from '@/hooks/useConfirm';
const ModelEditForm = ({ formHooks }: { formHooks: UseFormReturn<ModelSchema> }) => { const ModelEditForm = ({
formHooks,
handleDelModel
}: {
formHooks: UseFormReturn<ModelSchema>;
handleDelModel: () => void;
}) => {
const { openConfirm, ConfirmChild } = useConfirm({
content: '确认删除该模型?'
});
const { register, setValue, getValues } = formHooks; const { register, setValue, getValues } = formHooks;
const [refresh, setRefresh] = useState(false); const [refresh, setRefresh] = useState(false);
@ -29,7 +42,7 @@ const ModelEditForm = ({ formHooks }: { formHooks: UseFormReturn<ModelSchema> })
</Flex> </Flex>
<FormControl mt={4}> <FormControl mt={4}>
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<Box flex={'0 0 50px'} w={0}> <Box flex={'0 0 80px'} w={0}>
: :
</Box> </Box>
<Input <Input
@ -39,7 +52,36 @@ const ModelEditForm = ({ formHooks }: { formHooks: UseFormReturn<ModelSchema> })
></Input> ></Input>
</Flex> </Flex>
</FormControl> </FormControl>
<FormControl mt={4}> <Flex alignItems={'center'} mt={4}>
<Box flex={'0 0 80px'} w={0}>
:
</Box>
<Box>{getValues('service.modelName')}</Box>
</Flex>
<Flex alignItems={'center'} mt={4}>
<Box flex={'0 0 80px'} w={0}>
:
</Box>
<Box>
{formatPrice(
modelList.find((item) => item.model === getValues('service.modelName'))?.price || 0,
1000
)}
/1K tokens()
</Box>
</Flex>
<Flex mt={5} alignItems={'center'}>
<Box flex={'0 0 80px'}>:</Box>
<Button
colorScheme={'gray'}
variant={'outline'}
size={'sm'}
onClick={openConfirm(handleDelModel)}
>
</Button>
</Flex>
{/* <FormControl mt={4}>
<Box mb={1}>:</Box> <Box mb={1}>:</Box>
<Textarea <Textarea
rows={5} rows={5}
@ -47,7 +89,7 @@ const ModelEditForm = ({ formHooks }: { formHooks: UseFormReturn<ModelSchema> })
{...register('intro')} {...register('intro')}
placeholder={'模型的介绍,仅做展示,不影响模型的效果'} placeholder={'模型的介绍,仅做展示,不影响模型的效果'}
/> />
</FormControl> </FormControl> */}
</Card> </Card>
<Card p={4}> <Card p={4}>
<Box fontWeight={'bold'}></Box> <Box fontWeight={'bold'}></Box>
@ -202,6 +244,7 @@ const ModelEditForm = ({ formHooks }: { formHooks: UseFormReturn<ModelSchema> })
</Flex> </Flex>
</FormControl> </FormControl>
</Card> */} </Card> */}
<ConfirmChild />
</> </>
); );
}; };

View File

@ -11,36 +11,34 @@ import { getChatSiteId } from '@/api/chat';
import type { ModelSchema } from '@/types/mongoSchema'; import type { ModelSchema } from '@/types/mongoSchema';
import { Card, Box, Flex, Button, Tag, Grid } from '@chakra-ui/react'; import { Card, Box, Flex, Button, Tag, Grid } from '@chakra-ui/react';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import { useConfirm } from '@/hooks/useConfirm';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { formatModelStatus, ModelStatusEnum, modelList, defaultModel } from '@/constants/model'; import { formatModelStatus, ModelStatusEnum, modelList, defaultModel } from '@/constants/model';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/store/global';
import { useScreen } from '@/hooks/useScreen'; import { useScreen } from '@/hooks/useScreen';
import ModelEditForm from './components/ModelEditForm'; import ModelEditForm from './components/ModelEditForm';
import Icon from '@/components/Iconfont'; // import Icon from '@/components/Iconfont';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import dynamic from 'next/dynamic'; // import dynamic from 'next/dynamic';
import ModelDataCard from './components/ModelDataCard';
const Training = dynamic(() => import('./components/Training')); // const Training = dynamic(() => import('./components/Training'));
const ModelDetail = ({ modelId }: { modelId: string }) => { const ModelDetail = ({ modelId }: { modelId: string }) => {
const { toast } = useToast(); const { toast } = useToast();
const router = useRouter(); const router = useRouter();
const { isPc, media } = useScreen(); const { isPc, media } = useScreen();
const { setLoading } = useGlobalStore(); const { setLoading } = useGlobalStore();
const { openConfirm, ConfirmChild } = useConfirm({
content: '确认删除该模型?'
});
const SelectFileDom = useRef<HTMLInputElement>(null); const SelectFileDom = useRef<HTMLInputElement>(null);
const [model, setModel] = useState<ModelSchema>(defaultModel); const [model, setModel] = useState<ModelSchema>(defaultModel);
const formHooks = useForm<ModelSchema>({ const formHooks = useForm<ModelSchema>({
defaultValues: model defaultValues: model
}); });
const canTrain = useMemo(() => { // const canTrain = useMemo(() => {
const openai = modelList.find((item) => item.model === model?.service.modelName); // const openai = modelList.find((item) => item.model === model?.service.modelName);
return openai && openai.trainName; // return openai && openai.trainName;
}, [model]); // }, [model]);
/* 加载模型数据 */ /* 加载模型数据 */
const loadModel = useCallback(async () => { const loadModel = useCallback(async () => {
@ -250,79 +248,15 @@ const ModelDetail = ({ modelId }: { modelId: string }) => {
)} )}
</Card> </Card>
<Grid mt={5} gridTemplateColumns={media('1fr 1fr', '1fr')} gridGap={5}> <Grid mt={5} gridTemplateColumns={media('1fr 1fr', '1fr')} gridGap={5}>
<ModelEditForm formHooks={formHooks} /> <ModelEditForm formHooks={formHooks} handleDelModel={handleDelModel} />
{canTrain && ( {/* {canTrain && (
<Card p={4}> <Card p={4}>
<Training model={model} /> <Training model={model} />
</Card> </Card>
)} )} */}
<Card p={4} height={'400px'} gridColumnStart={1} gridColumnEnd={3}>
<Card p={4}> {model._id && <ModelDataCard model={model} />}
<Box fontWeight={'bold'} fontSize={'lg'}>
</Box>
<Flex mt={5} alignItems={'center'}>
<Box flex={'0 0 80px'}>:</Box>
<Button
size={'sm'}
onClick={() => {
SelectFileDom.current?.click();
}}
title={!canTrain ? '模型不支持微调' : ''}
isDisabled={!canTrain}
>
</Button>
<Flex
as={'a'}
href="/TrainingTemplate.jsonl"
download
ml={5}
cursor={'pointer'}
alignItems={'center'}
color={'blue.500'}
>
<Icon name={'icon-yunxiazai'} color={'#3182ce'} />
</Flex>
</Flex>
{/* 提示 */}
<Box mt={3} py={3} color={'blackAlpha.600'}>
<Box as={'li'} lineHeight={1.9}>
使openai key
</Box>
<Box as={'li'} lineHeight={1.9}>
使
<Box
as={'span'}
fontWeight={'bold'}
textDecoration={'underline'}
color={'blackAlpha.800'}
mx={2}
cursor={'pointer'}
onClick={() => router.push('/data/list')}
>
</Box>
</Box>
<Box as={'li'} lineHeight={1.9}>
prompt completion
</Box>
<Box as={'li'} lineHeight={1.9}>
prompt {'</s>'}
</Box>
<Box as={'li'} lineHeight={1.9}>
completion {'</s>'}
</Box>
</Box>
<Flex mt={5} alignItems={'center'}>
<Box flex={'0 0 80px'}>:</Box>
<Button colorScheme={'red'} size={'sm'} onClick={openConfirm(handleDelModel)}>
</Button>
</Flex>
</Card> </Card>
</Grid> </Grid>
@ -330,7 +264,6 @@ const ModelDetail = ({ modelId }: { modelId: string }) => {
<Box position={'absolute'} w={0} h={0} overflow={'hidden'}> <Box position={'absolute'} w={0} h={0} overflow={'hidden'}>
<input ref={SelectFileDom} type="file" accept=".jsonl" onChange={startTraining} /> <input ref={SelectFileDom} type="file" accept=".jsonl" onChange={startTraining} />
</Box> </Box>
<ConfirmChild />
</> </>
); );
}; };

View File

@ -1,6 +1,7 @@
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import { generateQA } from './events/generateQA'; import { generateQA } from './events/generateQA';
import { generateAbstract } from './events/generateAbstract'; import { generateAbstract } from './events/generateAbstract';
import { connectRedis } from './redis';
/** /**
* MongoDB * MongoDB
@ -28,6 +29,7 @@ export async function connectToDatabase(): Promise<void> {
generateQA(); generateQA();
generateAbstract(); generateAbstract();
// connectRedis();
} }
export * from './models/authCode'; export * from './models/authCode';

74
src/service/redis.ts Normal file
View File

@ -0,0 +1,74 @@
import { createClient, SchemaFieldTypes } from 'redis';
export const connectRedis = async () => {
// 断开了,重连
if (global.redisClient && !global.redisClient.isOpen) {
await global.redisClient.disconnect();
} else if (global.redisClient) {
// 没断开,不再连接
return;
}
try {
global.redisClient = createClient({
url: 'redis://:121914yu@120.76.193.200:8100'
});
global.redisClient.on('error', (err) => {
console.log('Redis Client Error', err);
global.redisClient = null;
});
global.redisClient.on('end', () => {
global.redisClient = null;
});
global.redisClient.on('ready', () => {
console.log('redis connected');
});
await global.redisClient.connect();
// 0 - 测试库1 - 正式
await global.redisClient.select(0);
// 创建索引
await global.redisClient.ft.create(
'vec:question',
{
'$.vector': SchemaFieldTypes.VECTOR,
'$.modelId': {
type: SchemaFieldTypes.TEXT,
AS: 'modelId'
},
'$.userId': {
type: SchemaFieldTypes.TEXT,
AS: 'userId'
},
'$.status': {
type: SchemaFieldTypes.NUMERIC,
AS: 'status'
}
},
{
ON: 'JSON',
PREFIX: 'fastgpt:modeldata'
}
);
// await global.redisClient.json.set('fastgpt:modeldata:1', '$', {
// vector: [],
// modelId: 'daf',
// userId: 'adfd',
// q: 'fasf',
// a: 'afasf',
// status: 0,
// createTime: new Date()
// });
// const value = await global.redisClient.get('fastgpt:modeldata:1');
// console.log(value);
} catch (error) {
console.log(error, '==');
global.redisClient = null;
return Promise.reject('redis 连接失败');
}
};

View File

@ -1,7 +1,9 @@
import type { Mongoose } from 'mongoose'; import type { Mongoose } from 'mongoose';
import type { RedisClientType } from 'redis';
declare global { declare global {
var mongodb: Mongoose | string | null; var mongodb: Mongoose | string | null;
var redisClient: RedisClientType | null;
var generatingQA: boolean; var generatingQA: boolean;
var generatingAbstract: boolean; var generatingAbstract: boolean;
var QRCode: any; var QRCode: any;

View File

@ -51,11 +51,12 @@ export interface ModelPopulate extends ModelSchema {
userId: UserModelSchema; userId: UserModelSchema;
} }
export type ModelDataType = 0 | 1 | 2;
export interface ModelDataSchema { export interface ModelDataSchema {
_id: string; _id: string;
q: string; q: string;
a: string; a: string;
status: 0 | 1 | 2; status: ModelDataType;
createTime: Date; createTime: Date;
} }