From f32c557bdd10f76b90dcb8329f4294b8105462f8 Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Wed, 29 Mar 2023 00:22:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=A8=A1=E5=9E=8B=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 95 +++++++++++++++++++ src/api/model.ts | 26 ++++- src/constants/model.ts | 9 +- src/hooks/usePaging.ts | 4 +- ...elMoedlDataById.ts => delModelDataById.ts} | 0 src/pages/api/model/data/getModelData.ts | 11 ++- src/pages/model/components/ModelDataCard.tsx | 86 +++++++++++++++++ src/pages/model/components/ModelEditForm.tsx | 53 ++++++++++- src/pages/model/detail.tsx | 95 +++---------------- src/service/mongo.ts | 2 + src/service/redis.ts | 74 +++++++++++++++ src/types/index.d.ts | 2 + src/types/mongoSchema.d.ts | 3 +- 14 files changed, 366 insertions(+), 95 deletions(-) rename src/pages/api/model/data/{delMoedlDataById.ts => delModelDataById.ts} (100%) create mode 100644 src/pages/model/components/ModelDataCard.tsx create mode 100644 src/service/redis.ts diff --git a/package.json b/package.json index b7d61f55b..a041f7726 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "react-hook-form": "^7.43.1", "react-markdown": "^8.0.5", "react-syntax-highlighter": "^15.5.0", + "redis": "^4.6.5", "rehype-katex": "^6.0.2", "remark-gfm": "^3.0.1", "remark-math": "^5.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a9109580f..affab94bf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,6 +47,7 @@ specifiers: react-hook-form: ^7.43.1 react-markdown: ^8.0.5 react-syntax-highlighter: ^15.5.0 + redis: ^4.6.5 rehype-katex: ^6.0.2 remark-gfm: ^3.0.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-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 + redis: registry.npmmirror.com/redis/4.6.5 rehype-katex: registry.npmmirror.com/rehype-katex/6.0.2 remark-gfm: registry.npmmirror.com/remark-gfm/3.0.1 remark-math: registry.npmmirror.com/remark-math/5.1.1 @@ -4504,6 +4506,72 @@ packages: version: 2.11.6 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: 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' @@ -5562,6 +5630,13 @@ packages: version: 0.0.1 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: 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 @@ -6799,6 +6874,13 @@ packages: version: 1.2.3 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: 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 @@ -9367,6 +9449,19 @@ packages: picomatch: registry.npmmirror.com/picomatch/2.3.1 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: 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 diff --git a/src/api/model.ts b/src/api/model.ts index 8381667fe..b62d14922 100644 --- a/src/api/model.ts +++ b/src/api/model.ts @@ -2,6 +2,9 @@ import { GET, POST, DELETE, PUT } from './request'; import type { ModelSchema } from '@/types/mongoSchema'; import { ModelUpdateParams } from '@/types/model'; import { TrainingItemType } from '../types/training'; +import { PagingData } from '@/types'; +import { RequestPaging } from '../types/index'; +import { Obj2Query } from '@/utils/tools'; export const getMyModels = () => GET('/model/list'); @@ -16,13 +19,30 @@ export const putModelById = (id: string, data: ModelUpdateParams) => PUT(`/model/update?modelId=${id}`, data); export const postTrainModel = (id: string, form: FormData) => - POST(`/model/train?modelId=${id}`, form, { + POST(`/model/train/train?modelId=${id}`, form, { headers: { '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) => - GET(`/model/getTrainings?modelId=${id}`); + GET(`/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}`); diff --git a/src/constants/model.ts b/src/constants/model.ts index ef1a4800d..2c37ee8b7 100644 --- a/src/constants/model.ts +++ b/src/constants/model.ts @@ -1,5 +1,4 @@ -import type { ServiceName } from '@/types/mongoSchema'; -import { ModelSchema } from '../types/mongoSchema'; +import type { ServiceName, ModelDataType, ModelSchema } from '@/types/mongoSchema'; export enum ChatModelNameEnum { GPT35 = 'gpt-3.5-turbo', @@ -76,6 +75,12 @@ export const formatModelStatus = { } }; +export const ModelDataStatusMap: Record = { + 0: '训练完成', + 1: '等待训练', + 2: '训练中' +}; + export const defaultModel: ModelSchema = { _id: '', userId: '', diff --git a/src/hooks/usePaging.ts b/src/hooks/usePaging.ts index 2f8b88c85..1733e4fa2 100644 --- a/src/hooks/usePaging.ts +++ b/src/hooks/usePaging.ts @@ -8,7 +8,7 @@ export const usePaging = ({ pageSize = 10, params = {} }: { - api: (data: any) => Promise>; + api: (data: any) => any; pageSize?: number; params?: Record; }) => { @@ -30,7 +30,7 @@ export const usePaging = ({ setRequesting(true); try { - const res = await api({ + const res: PagingData = await api({ pageNum: num, pageSize, ...params diff --git a/src/pages/api/model/data/delMoedlDataById.ts b/src/pages/api/model/data/delModelDataById.ts similarity index 100% rename from src/pages/api/model/data/delMoedlDataById.ts rename to src/pages/api/model/data/delModelDataById.ts diff --git a/src/pages/api/model/data/getModelData.ts b/src/pages/api/model/data/getModelData.ts index 3c41ec458..ec30dd9ed 100644 --- a/src/pages/api/model/data/getModelData.ts +++ b/src/pages/api/model/data/getModelData.ts @@ -14,6 +14,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< pageNum: string; pageSize: string; }; + const { authorization } = req.headers; pageNum = +pageNum; @@ -41,7 +42,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< .limit(pageSize); jsonRes(res, { - data + data: { + pageNum, + pageSize, + data, + total: await ModelData.countDocuments({ + modelId, + userId + }) + } }); } catch (err) { jsonRes(res, { diff --git a/src/pages/model/components/ModelDataCard.tsx b/src/pages/model/components/ModelDataCard.tsx new file mode 100644 index 000000000..7ce60c8e4 --- /dev/null +++ b/src/pages/model/components/ModelDataCard.tsx @@ -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({ + api: getModelDataList, + pageSize: 10, + params: { + modelId: model._id + } + }); + + return ( + <> + + + 模型数据: {total}组 + + + + + + + + + + + + + + + + {dataList.map((item) => ( + + + + + + + ))} + +
QuestionTextStatus
{item.q}{item.a}{ModelDataStatusMap[item.status]} + } aria-label={'delete'} /> +
+
+
+ + ); +}; + +export default ModelDataCard; diff --git a/src/pages/model/components/ModelEditForm.tsx b/src/pages/model/components/ModelEditForm.tsx index c74b82918..fe78c3914 100644 --- a/src/pages/model/components/ModelEditForm.tsx +++ b/src/pages/model/components/ModelEditForm.tsx @@ -11,13 +11,26 @@ import { SliderFilledTrack, SliderThumb, SliderMark, - Tooltip + Tooltip, + Button } from '@chakra-ui/react'; import { QuestionOutlineIcon } from '@chakra-ui/icons'; import type { ModelSchema } from '@/types/mongoSchema'; 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 }) => { +const ModelEditForm = ({ + formHooks, + handleDelModel +}: { + formHooks: UseFormReturn; + handleDelModel: () => void; +}) => { + const { openConfirm, ConfirmChild } = useConfirm({ + content: '确认删除该模型?' + }); const { register, setValue, getValues } = formHooks; const [refresh, setRefresh] = useState(false); @@ -29,7 +42,7 @@ const ModelEditForm = ({ formHooks }: { formHooks: UseFormReturn }) - + 名称: }) > - + + + 底层模型: + + {getValues('service.modelName')} + + + + 价格: + + + {formatPrice( + modelList.find((item) => item.model === getValues('service.modelName'))?.price || 0, + 1000 + )} + 元/1K tokens(包括上下文和回答) + + + + 删除: + + + {/* 介绍: