From 38d49ea05fc52aa55a2682ecc067f35eae4eb310 Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Fri, 10 Mar 2023 19:44:06 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=E9=94=99=E8=AF=AF=E6=8F=90?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/api/chat/chatGpt.ts | 6 +++--- src/pages/login/components/ForgetPasswordForm.tsx | 12 +++++------- src/pages/login/components/LoginForm.tsx | 12 +++++------- src/pages/login/components/RegisterForm.tsx | 13 +++++-------- src/pages/login/index.tsx | 8 ++++++-- src/pages/model/detail.tsx | 8 ++++++-- src/pages/model/list.tsx | 10 ++++++++-- src/service/mongo.ts | 7 ++----- src/types/index.d.ts | 8 ++++---- tsconfig.json | 1 + 10 files changed, 45 insertions(+), 40 deletions(-) diff --git a/src/pages/api/chat/chatGpt.ts b/src/pages/api/chat/chatGpt.ts index 775fd3dba..176941553 100644 --- a/src/pages/api/chat/chatGpt.ts +++ b/src/pages/api/chat/chatGpt.ts @@ -50,13 +50,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const formatPrompts: ChatCompletionRequestMessage[] = filterPrompts.map( (item: ChatItemType) => ({ role: map[item.obj], - content: item.value.replace(/\n/g, ' ') + content: item.value }) ); // 第一句话,强调代码类型 formatPrompts.unshift({ role: ChatCompletionRequestMessageRoleEnum.System, - content: '如果你想返回代码,请务必声明代码的类型!' + content: '如果你想返回代码,请务必声明代码的类型!并且在代码块前加一个换行符。' }); // 获取 chatAPI const chatAPI = getOpenAIApi(userApiKey); @@ -100,7 +100,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } try { const json = JSON.parse(data); - const content: string = json.choices[0].delta.content || ''; + const content: string = json.choices[0].delta.content || '\n'; // console.log('content:', content) res.write(`event: responseData\ndata: ${content.replace(/\n/g, '
')}\n\n`); AIResponse += content; diff --git a/src/pages/login/components/ForgetPasswordForm.tsx b/src/pages/login/components/ForgetPasswordForm.tsx index 3ec8655b8..31d2fd32a 100644 --- a/src/pages/login/components/ForgetPasswordForm.tsx +++ b/src/pages/login/components/ForgetPasswordForm.tsx @@ -61,13 +61,11 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { title: `密码已找回`, status: 'success' }); - } catch (error) { - typeof error === 'string' && - toast({ - title: error, - status: 'error', - position: 'top' - }); + } catch (error: any) { + toast({ + title: error.message || '修改密码异常', + status: 'error' + }); } setRequesting(false); }, diff --git a/src/pages/login/components/LoginForm.tsx b/src/pages/login/components/LoginForm.tsx index 05092ccd9..8a6d2f499 100644 --- a/src/pages/login/components/LoginForm.tsx +++ b/src/pages/login/components/LoginForm.tsx @@ -42,13 +42,11 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => { title: '登录成功', status: 'success' }); - } catch (error) { - typeof error === 'string' && - toast({ - title: error, - status: 'error', - position: 'top' - }); + } catch (error: any) { + toast({ + title: error.message || '登录异常', + status: 'error' + }); } setRequesting(false); }, diff --git a/src/pages/login/components/RegisterForm.tsx b/src/pages/login/components/RegisterForm.tsx index ced23724d..aec2cdc61 100644 --- a/src/pages/login/components/RegisterForm.tsx +++ b/src/pages/login/components/RegisterForm.tsx @@ -61,14 +61,11 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { title: `注册成功`, status: 'success' }); - } catch (error) { - typeof error === 'string' && - toast({ - title: error, - status: 'error', - duration: 4000, - isClosable: true - }); + } catch (error: any) { + toast({ + title: error.message || '注册异常', + status: 'error' + }); } setRequesting(false); }, diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index 39ae9c5e3..e6fb8ea7d 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -1,4 +1,4 @@ -import React, { useState, useCallback, useMemo } from 'react'; +import React, { useState, useCallback, useEffect } from 'react'; import styles from './index.module.scss'; import { Box, Flex, Image } from '@chakra-ui/react'; import { PageTypeEnum } from '@/constants/user'; @@ -21,7 +21,7 @@ const Login = () => { const loginSuccess = useCallback( (res: ResLogin) => { setUserInfo(res.user, res.token); - router.push('/'); + router.push('/model/list'); }, [router, setUserInfo] ); @@ -38,6 +38,10 @@ const Login = () => { return ; } + useEffect(() => { + router.prefetch('/model/list'); + }, [router]); + return ( { try { await putModelTrainingStatus(model._id); loadModel(); - } catch (error) { + } catch (error: any) { console.error(error); + toast({ + title: error.message || '更新失败', + status: 'error' + }); } setLoading(false); - }, [setLoading, loadModel, model]); + }, [model, setLoading, loadModel, toast]); return ( <> diff --git a/src/pages/model/list.tsx b/src/pages/model/list.tsx index c6057b81a..b2f801e1f 100644 --- a/src/pages/model/list.tsx +++ b/src/pages/model/list.tsx @@ -10,10 +10,12 @@ import { useScreen } from '@/hooks/useScreen'; import { useQuery } from '@tanstack/react-query'; import { useLoading } from '@/hooks/useLoading'; import dynamic from 'next/dynamic'; +import { useToast } from '@/hooks/useToast'; const CreateModel = dynamic(() => import('./components/CreateModel')); const ModelList = () => { + const { toast } = useToast(); const { isPc } = useScreen(); const router = useRouter(); const [models, setModels] = useState([]); @@ -43,12 +45,16 @@ const ModelList = () => { router.push(`/chat?chatId=${chatId}`, undefined, { shallow: true }); - } catch (err) { + } catch (err: any) { console.error(err); + toast({ + title: err.message || '出现一些异常', + status: 'error' + }); } setIsLoading(false); }, - [router, setIsLoading] + [router, setIsLoading, toast] ); return ( diff --git a/src/service/mongo.ts b/src/service/mongo.ts index 80a8b3016..6e4b81e5a 100644 --- a/src/service/mongo.ts +++ b/src/service/mongo.ts @@ -1,18 +1,16 @@ -import mongoose from 'mongoose'; +import mongoose, { Mongoose } from 'mongoose'; /** * 连接 MongoDB 数据库 */ export async function connectToDatabase(): Promise { - // @ts-ignore if (global.mongodb) { return; } - // @ts-ignore + global.mongodb = 'connecting'; console.log('connect mongo'); try { - // @ts-ignore global.mongodb = await mongoose.connect(process.env.MONGODB_URI as string, { dbName: 'doc_gpt', maxPoolSize: 10, @@ -20,7 +18,6 @@ export async function connectToDatabase(): Promise { }); } catch (error) { console.error('mongo connect error'); - // @ts-ignore global.mongodb = null; } } diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 2a2aedcda..a0eb4fa85 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -1,9 +1,9 @@ import type { Mongoose } from 'mongoose'; declare global { - interface Global { - mongodb: Mongoose; + namespace NodeJS { + interface Global { + mongodb: Mongoose | string; + } } } - -export type a = string; diff --git a/tsconfig.json b/tsconfig.json index c193e0a06..10d295142 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,7 @@ "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, + "noImplicitAny": true, "skipLibCheck": true, "strict": true, "forceConsistentCasingInFileNames": true, From 7fb76cde0b2b73ee26ed86b6dabcc5863ec27d81 Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Fri, 10 Mar 2023 20:18:31 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E7=B1=BB=E5=9E=8B=E5=A3=B0?= =?UTF-8?q?=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 ++-- src/components/Markdown/index.tsx | 5 +++-- src/service/mongo.ts | 2 +- src/types/index.d.ts | 7 ++----- tsconfig.json | 6 +++--- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 2983bcaf5..c81c369d7 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,6 @@ "sass": "^1.58.3", "sharp": "^0.31.3", "tunnel": "^0.0.6", - "typescript": "4.9.5", "uuid": "^9.0.0", "zustand": "^4.3.5" }, @@ -63,7 +62,8 @@ "eslint-config-next": "13.1.6", "husky": "^8.0.3", "lint-staged": "^13.1.2", - "prettier": "^2.8.4" + "prettier": "^2.8.4", + "typescript": "4.9.5" }, "lint-staged": { "./src/**/*.{ts,tsx,scss}": "npm run format" diff --git a/src/components/Markdown/index.tsx b/src/components/Markdown/index.tsx index 299ec0a6e..676281fac 100644 --- a/src/components/Markdown/index.tsx +++ b/src/components/Markdown/index.tsx @@ -25,7 +25,8 @@ const Markdown = ({ source, isChatting }: { source: string; isChatting: boolean pre: 'div', code({ node, inline, className, children, ...props }) { const match = /language-(\w+)/.exec(className || ''); - const code = String(children).replace(/\n$/, ''); + const code = String(children); + return !inline || match ? ( ) : ( - {children} + {code} ); } diff --git a/src/service/mongo.ts b/src/service/mongo.ts index 6e4b81e5a..0255684a0 100644 --- a/src/service/mongo.ts +++ b/src/service/mongo.ts @@ -1,4 +1,4 @@ -import mongoose, { Mongoose } from 'mongoose'; +import mongoose from 'mongoose'; /** * 连接 MongoDB 数据库 diff --git a/src/types/index.d.ts b/src/types/index.d.ts index a0eb4fa85..003a22551 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -1,9 +1,6 @@ import type { Mongoose } from 'mongoose'; declare global { - namespace NodeJS { - interface Global { - mongodb: Mongoose | string; - } - } + var mongodb: Mongoose | string | null; } +export {}; diff --git a/tsconfig.json b/tsconfig.json index 10d295142..fa4b956b4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,6 @@ "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, - "noImplicitAny": true, "skipLibCheck": true, "strict": true, "forceConsistentCasingInFileNames": true, @@ -18,8 +17,9 @@ "baseUrl": ".", "paths": { "@/*": ["./src/*"] - } + }, + "declaration": true }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.d.ts"], + "include": ["next-env.d.ts", "src/**/*"], "exclude": ["node_modules"] } From ed9e72ec9a55ddf8abe57bbf4a320bfa003fba01 Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Fri, 10 Mar 2023 22:12:13 +0800 Subject: [PATCH 3/5] perf: logs --- src/api/request.ts | 4 +- src/components/Layout/auth.tsx | 2 +- src/pages/api/chat/chatGpt.ts | 50 +++++++++----------- src/pages/api/user/tokenLogin.ts | 2 +- src/pages/chat/index.tsx | 4 +- src/pages/model/components/ModelEditForm.tsx | 2 +- src/pages/model/components/Training.tsx | 2 +- src/pages/model/detail.tsx | 10 ++-- src/pages/model/list.tsx | 2 +- src/service/errorCode.ts | 5 +- src/service/mongo.ts | 8 ++-- src/service/response.ts | 4 +- src/service/utils/sendEmail.ts | 4 +- src/utils/tools.ts | 2 +- 14 files changed, 50 insertions(+), 51 deletions(-) diff --git a/src/api/request.ts b/src/api/request.ts index a5df11ee5..0d3987dd5 100644 --- a/src/api/request.ts +++ b/src/api/request.ts @@ -34,7 +34,7 @@ function responseSuccess(response: AxiosResponse) { */ function checkRes(data: ResponseDataType) { if (data === undefined) { - console.error(data, 'data is empty'); + console.log('error->', data, 'data is empty'); return Promise.reject('服务器异常'); } else if (data.code < 200 || data.code >= 400) { return Promise.reject(data.message); @@ -46,7 +46,7 @@ function checkRes(data: ResponseDataType) { * 响应错误 */ function responseError(err: any) { - console.error('请求错误', err); + console.log('error->', '请求错误', err); if (!err) { return Promise.reject({ message: '未知错误' }); diff --git a/src/components/Layout/auth.tsx b/src/components/Layout/auth.tsx index 5f495b987..682f99a66 100644 --- a/src/components/Layout/auth.tsx +++ b/src/components/Layout/auth.tsx @@ -39,7 +39,7 @@ const Auth = ({ children }: { children: JSX.Element }) => { } }, onError(error) { - console.error(error); + console.log('error->', error); router.push('/login'); toast(); }, diff --git a/src/pages/api/chat/chatGpt.ts b/src/pages/api/chat/chatGpt.ts index 176941553..14dc43a31 100644 --- a/src/pages/api/chat/chatGpt.ts +++ b/src/pages/api/chat/chatGpt.ts @@ -6,6 +6,7 @@ import { getOpenAIApi, authChat } from '@/service/utils/chat'; import { openaiProxy } from '@/service/utils/tools'; import { ChatCompletionRequestMessage, ChatCompletionRequestMessageRoleEnum } from 'openai'; import { ChatItemType } from '@/types/chat'; +import { openaiError } from '@/service/errorCode'; /* 发送提示词 */ export default async function handler(req: NextApiRequest, res: NextApiResponse) { @@ -74,7 +75,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) httpsAgent: openaiProxy?.httpsAgent } ); - console.log('response success'); + console.log( + formatPrompts.reduce((sum, item) => sum + item.content.length, 0), + 'response success' + ); let AIResponse = ''; @@ -95,54 +99,44 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) updateTime: Date.now() }); res.write('event: done\ndata: \n\n'); - res.end(); return; } try { const json = JSON.parse(data); - const content: string = json.choices[0].delta.content || '\n'; + const content: string = json?.choices?.[0].delta.content || '\n'; // console.log('content:', content) res.write(`event: responseData\ndata: ${content.replace(/\n/g, '
')}\n\n`); AIResponse += content; - } catch (e) { - res.end(); + } catch (error) { + error; } } }; - const parser = createParser(onParse); - for await (const chunk of chatResponse.data as any) { - parser.feed(decoder.decode(chunk)); + try { + for await (const chunk of chatResponse.data as any) { + const parser = createParser(onParse); + parser.feed(decoder.decode(chunk)); + } + } catch (error) { + console.log(error, '===='); + throw new Error('错误了'); } } catch (err: any) { - let errorText = err; + // console.log('error->', err?.response, '==='); + let errorText = 'OpenAI 服务器访问超时'; if (err.code === 'ECONNRESET') { errorText = '服务器代理出错'; - } else { - switch (err?.response?.data?.error?.code) { - case 'invalid_api_key': - errorText = 'API-KEY不合法'; - break; - case 'context_length_exceeded': - errorText = '内容超长了,请重置对话'; - break; - case 'rate_limit_reached': - errorText = '同时访问用户过多,请稍后再试'; - break; - case null: - errorText = 'OpenAI 服务器访问超时'; - break; - default: - errorText = '服务器异常'; - } + } else if (err?.response?.statusText && openaiError[err.response.statusText]) { + errorText = openaiError[err.response.statusText]; } - console.error(errorText); + console.log('error->', errorText); res.write(`event: serviceError\ndata: ${errorText}\n\n`); - res.end(); // 删除最一条数据库记录, 也就是预发送的那一条 await ChatWindow.findByIdAndUpdate(windowId, { $pop: { content: 1 }, updateTime: Date.now() }); + res.end(); } } diff --git a/src/pages/api/user/tokenLogin.ts b/src/pages/api/user/tokenLogin.ts index 2c959eafd..a1ce44e86 100644 --- a/src/pages/api/user/tokenLogin.ts +++ b/src/pages/api/user/tokenLogin.ts @@ -10,7 +10,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const { authorization } = req.headers; if (!authorization) { - throw new Error('缺少参数'); + throw new Error('缺少登录凭证'); } const userId = await authToken(authorization); diff --git a/src/pages/chat/index.tsx b/src/pages/chat/index.tsx index c9cc2941d..9c5dc6d37 100644 --- a/src/pages/chat/index.tsx +++ b/src/pages/chat/index.tsx @@ -165,13 +165,13 @@ const Chat = () => { event.addEventListener('serviceError', ({ data: err }) => { clearTimeout(timer); event.close(); - console.error(err, '==='); + console.log('error->', err, '==='); reject(typeof err === 'string' ? err : '对话出现不知名错误~'); }); event.onerror = (err) => { clearTimeout(timer); event.close(); - console.error(err); + console.log('error->', err); reject(typeof err === 'string' ? err : '对话出现不知名错误~'); }; }); diff --git a/src/pages/model/components/ModelEditForm.tsx b/src/pages/model/components/ModelEditForm.tsx index 5c432f75e..65138bbc2 100644 --- a/src/pages/model/components/ModelEditForm.tsx +++ b/src/pages/model/components/ModelEditForm.tsx @@ -34,7 +34,7 @@ const ModelEditForm = ({ model }: { model?: ModelType }) => { status: 'success' }); } catch (err) { - console.error(err); + console.log('error->', err); toast({ title: err as string, status: 'success' diff --git a/src/pages/model/components/Training.tsx b/src/pages/model/components/Training.tsx index 4a4bb1d18..dc4b5cf81 100644 --- a/src/pages/model/components/Training.tsx +++ b/src/pages/model/components/Training.tsx @@ -29,7 +29,7 @@ const Training = ({ model }: { model: ModelType }) => { const res = await getModelTrainings(id); setRecords(res); } catch (error) { - console.error(error); + console.log('error->', error); } }, []); diff --git a/src/pages/model/detail.tsx b/src/pages/model/detail.tsx index aed0f95e4..0116ed741 100644 --- a/src/pages/model/detail.tsx +++ b/src/pages/model/detail.tsx @@ -42,7 +42,7 @@ const ModelDetail = () => { res.security.expiredTime /= 60 * 60 * 1000; setModel(res); } catch (err) { - console.error(err); + console.log('error->', err); } setLoading(false); }, [modelId, setLoading]); @@ -63,7 +63,7 @@ const ModelDetail = () => { }); router.replace('/model/list'); } catch (err) { - console.error(err); + console.log('error->', err); } setLoading(false); }, [setLoading, model, router, toast]); @@ -77,7 +77,7 @@ const ModelDetail = () => { router.push(`/chat?chatId=${chatId}`); } catch (err) { - console.error(err); + console.log('error->', err); } setLoading(false); }, [setLoading, model, router]); @@ -105,7 +105,7 @@ const ModelDetail = () => { title: typeof err === 'string' ? err : '文件格式错误', status: 'error' }); - console.error(err); + console.log('error->', err); } setLoading(false); }, @@ -121,7 +121,7 @@ const ModelDetail = () => { await putModelTrainingStatus(model._id); loadModel(); } catch (error: any) { - console.error(error); + console.log('error->', error); toast({ title: error.message || '更新失败', status: 'error' diff --git a/src/pages/model/list.tsx b/src/pages/model/list.tsx index b2f801e1f..70272009a 100644 --- a/src/pages/model/list.tsx +++ b/src/pages/model/list.tsx @@ -46,7 +46,7 @@ const ModelList = () => { shallow: true }); } catch (err: any) { - console.error(err); + console.log('error->', err); toast({ title: err.message || '出现一些异常', status: 'error' diff --git a/src/service/errorCode.ts b/src/service/errorCode.ts index 0f59b90d8..690f37e3d 100644 --- a/src/service/errorCode.ts +++ b/src/service/errorCode.ts @@ -1,3 +1,6 @@ export const openaiError: Record = { - context_length_exceeded: '内容超出长度' + context_length_exceeded: '内容超长了,请重置对话', + Unauthorized: 'API-KEY 不合法', + rate_limit_reached: '同时访问用户过多,请稍后再试', + 'Bad Request': '内容太多了~' }; diff --git a/src/service/mongo.ts b/src/service/mongo.ts index 0255684a0..08d6e4599 100644 --- a/src/service/mongo.ts +++ b/src/service/mongo.ts @@ -12,12 +12,14 @@ export async function connectToDatabase(): Promise { console.log('connect mongo'); try { global.mongodb = await mongoose.connect(process.env.MONGODB_URI as string, { + bufferCommands: true, dbName: 'doc_gpt', - maxPoolSize: 10, - minPoolSize: 1 + maxPoolSize: 5, + minPoolSize: 1, + maxConnecting: 5 }); } catch (error) { - console.error('mongo connect error'); + console.log('error->', 'mongo connect error'); global.mongodb = null; } } diff --git a/src/service/response.ts b/src/service/response.ts index d733e2f14..58201b365 100644 --- a/src/service/response.ts +++ b/src/service/response.ts @@ -27,8 +27,8 @@ export const jsonRes = ( msg = openaiError[error?.response?.data?.message]; } - console.error(error); - console.error(msg); + console.log('error->', error); + console.log('error->', msg); } res.json({ diff --git a/src/service/utils/sendEmail.ts b/src/service/utils/sendEmail.ts index afca5e053..a54797cb5 100644 --- a/src/service/utils/sendEmail.ts +++ b/src/service/utils/sendEmail.ts @@ -34,7 +34,7 @@ export const sendCode = (email: string, code: string, type: `${EmailTypeEnum}`) }; mailTransport.sendMail(options, function (err, msg) { if (err) { - console.error(err); + console.log('error->', err); reject('邮箱异常'); } else { resolve(''); @@ -53,7 +53,7 @@ export const sendTrainSucceed = (email: string, modelName: string) => { }; mailTransport.sendMail(options, function (err, msg) { if (err) { - console.error(err); + console.log('error->', err); reject('邮箱异常'); } else { resolve(''); diff --git a/src/utils/tools.ts b/src/utils/tools.ts index 787651bb7..5b6ce5445 100644 --- a/src/utils/tools.ts +++ b/src/utils/tools.ts @@ -21,7 +21,7 @@ export const useCopyData = () => { duration: 1000 }); } catch (error) { - console.error(error); + console.log('error->', error); toast({ title: '复制失败', status: 'error' From 9f96593136bfd9769645aada4ae307238638a464 Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Sat, 11 Mar 2023 13:19:00 +0800 Subject: [PATCH 4/5] README.md --- README.md | 2 +- tsconfig.json | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a8c7fe6b5..d37bd0814 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ docker run -d --network=host --name doc-gpt \ -e MY_MAIL=your email\ -e MAILE_CODE=your email code \ -e TOKEN_KEY=任意一个内容 \ - -e MONGODB_URI="mongodb://aha:ROOT_root123@127.0.0.0:27017/?authSource=admin&readPreference=primary&appname=MongoDB%20Compass&ssl=false" \ + -e MONGODB_URI="mongodb://user:password@127.0.0.0:27017/?authSource=admin&readPreference=primary&appname=MongoDB%20Compass&ssl=false" \ imageName:tag docker logs doc-gpt diff --git a/tsconfig.json b/tsconfig.json index fa4b956b4..c193e0a06 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,9 +17,8 @@ "baseUrl": ".", "paths": { "@/*": ["./src/*"] - }, - "declaration": true + } }, - "include": ["next-env.d.ts", "src/**/*"], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.d.ts"], "exclude": ["node_modules"] } From fd8135f50ce859ceb46a96b534521df02f7e752e Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Sat, 11 Mar 2023 16:56:27 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat:=20md=E6=95=B0=E5=AD=A6=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E5=BC=8F;perf:=20=E5=AD=97=E4=BD=93=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?;fix:=20=E5=8F=91=E9=80=81=E9=AA=8C=E8=AF=81=E7=A0=81=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E6=8F=90=E9=86=92=E3=80=82=E8=81=8A=E5=A4=A9=E4=BA=8C?= =?UTF-8?q?=E6=AC=A1=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Markdown/codeLight.ts | 4 - src/components/Markdown/index.module.scss | 10 +-- src/components/Markdown/index.tsx | 8 +- src/constants/theme.ts | 20 ++--- src/hooks/useSendCode.ts | 19 ++-- src/pages/api/user/sendEmail.ts | 1 - src/pages/chat/index.tsx | 90 ++++++++++--------- src/pages/model/components/ModelPhoneList.tsx | 8 +- src/pages/model/components/ModelTable.tsx | 6 +- src/pages/model/detail.tsx | 3 +- src/service/mongo.ts | 1 + src/styles/reset.scss | 3 + 12 files changed, 91 insertions(+), 82 deletions(-) diff --git a/src/components/Markdown/codeLight.ts b/src/components/Markdown/codeLight.ts index d6f17fd10..460e35305 100644 --- a/src/components/Markdown/codeLight.ts +++ b/src/components/Markdown/codeLight.ts @@ -2,9 +2,7 @@ import React from 'react'; export const codeLight: { [key: string]: React.CSSProperties } = { 'code[class*=language-]': { color: '#d4d4d4', - fontSize: '13px', textShadow: 'none', - fontFamily: 'Menlo,Monaco,Consolas,"Andale Mono","Ubuntu Mono","Courier New",monospace', direction: 'ltr', textAlign: 'left', whiteSpace: 'pre', @@ -21,9 +19,7 @@ export const codeLight: { [key: string]: React.CSSProperties } = { }, 'pre[class*=language-]': { color: '#d4d4d4', - fontSize: '13px', textShadow: 'none', - fontFamily: 'Menlo,Monaco,Consolas,"Andale Mono","Ubuntu Mono","Courier New",monospace', direction: 'ltr', textAlign: 'left', whiteSpace: 'pre', diff --git a/src/components/Markdown/index.module.scss b/src/components/Markdown/index.module.scss index 8b89f1f5c..825544096 100644 --- a/src/components/Markdown/index.module.scss +++ b/src/components/Markdown/index.module.scss @@ -341,7 +341,7 @@ background-color: #f0f0f0; border: 1px solid #cccccc; border-radius: 3px 3px 3px 3px; - font-size: 13px; + font-size: max(0.9em, 14px); line-height: 19px; overflow: auto; padding: 6px 10px; @@ -352,11 +352,12 @@ border: medium none; } .markdown { - font-size: 14px; - line-height: 1.6; - letter-spacing: 0.5px; text-align: justify; word-break: break-all; + overflow-y: hidden; + tab-size: 4; + word-spacing: normal; + pre { display: block; width: 100%; @@ -372,7 +373,6 @@ background-color: #222 !important; color: #fff; width: 100%; - font-family: 'Söhne,ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,Helvetica Neue,Arial,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji'; } a { diff --git a/src/components/Markdown/index.tsx b/src/components/Markdown/index.tsx index 676281fac..654bc0245 100644 --- a/src/components/Markdown/index.tsx +++ b/src/components/Markdown/index.tsx @@ -1,8 +1,6 @@ import React, { memo, useMemo } from 'react'; import ReactMarkdown from 'react-markdown'; -import styles from './index.module.scss'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; -import { codeLight } from './codeLight'; import { Box, Flex } from '@chakra-ui/react'; import { useCopyData } from '@/utils/tools'; import Icon from '@/components/Icon'; @@ -10,8 +8,12 @@ import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; import rehypeKatex from 'rehype-katex'; +import 'katex/dist/katex.min.css'; +import styles from './index.module.scss'; +import { codeLight } from './codeLight'; + const Markdown = ({ source, isChatting }: { source: string; isChatting: boolean }) => { - const formatSource = useMemo(() => source.replace(/\n/g, ' \n'), [source]); + const formatSource = useMemo(() => source, [source]); const { copyData } = useCopyData(); return ( diff --git a/src/constants/theme.ts b/src/constants/theme.ts index 72661ab04..5c60060bc 100644 --- a/src/constants/theme.ts +++ b/src/constants/theme.ts @@ -20,24 +20,27 @@ const Button = defineStyleConfig({ baseStyle: {}, sizes: { sm: { - fontSize: 'sm', + fontSize: 'xs', px: 3, py: 0, fontWeight: 'normal', - height: '26px' + height: '26px', + lineHeight: '26px' }, md: { - fontSize: 'md', + fontSize: 'sm', px: 6, py: 0, height: '34px', + lineHeight: '34px', fontWeight: 'normal' }, lg: { - fontSize: 'lg', + fontSize: 'md', px: 8, py: 0, height: '42px', + lineHeight: '42px', fontWeight: 'normal' } }, @@ -58,17 +61,12 @@ export const theme = extendTheme({ global: { 'html, body': { color: 'blackAlpha.800', - fontSize: '14px', - fontFamily: - 'Söhne,ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,Helvetica Neue,Arial,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji', height: '100%', - overflowY: 'auto' + maxHeight: '100vh', + overflowY: 'hidden' } } }, - fonts: { - body: 'system-ui, sans-serif' - }, fontSizes: { xs: '0.8rem', sm: '0.9rem', diff --git a/src/hooks/useSendCode.ts b/src/hooks/useSendCode.ts index 8e683b5b7..71939a364 100644 --- a/src/hooks/useSendCode.ts +++ b/src/hooks/useSendCode.ts @@ -1,14 +1,11 @@ import { useState, useMemo, useCallback } from 'react'; import { sendCodeToEmail } from '@/api/user'; import { EmailTypeEnum } from '@/constants/common'; -import { useToast } from '@chakra-ui/react'; let timer: any; +import { useToast } from './useToast'; export const useSendCode = () => { - const toast = useToast({ - position: 'top', - duration: 2000 - }); + const { toast } = useToast(); const [codeSending, setCodeSending] = useState(false); const [codeCountDown, setCodeCountDown] = useState(0); const sendCodeText = useMemo(() => { @@ -43,13 +40,11 @@ export const useSendCode = () => { status: 'success', position: 'top' }); - } catch (error) { - typeof error === 'string' && - toast({ - title: error, - status: 'error', - position: 'top' - }); + } catch (error: any) { + toast({ + title: error.message || '发送验证码异常', + status: 'error' + }); } setCodeSending(false); }, diff --git a/src/pages/api/user/sendEmail.ts b/src/pages/api/user/sendEmail.ts index 6ff5ee2cb..4a2b727b7 100644 --- a/src/pages/api/user/sendEmail.ts +++ b/src/pages/api/user/sendEmail.ts @@ -20,7 +20,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) if (type === EmailTypeEnum.register) { const maxCount = process.env.MAX_USER ? +process.env.MAX_USER : Infinity; const userCount = await User.count(); - if (userCount >= maxCount) { throw new Error('当前注册用户已满,请等待名额~'); } diff --git a/src/pages/chat/index.tsx b/src/pages/chat/index.tsx index 9c5dc6d37..159e16e1c 100644 --- a/src/pages/chat/index.tsx +++ b/src/pages/chat/index.tsx @@ -22,11 +22,10 @@ const Markdown = dynamic(() => import('@/components/Markdown')); const textareaMinH = '22px'; -const Chat = () => { +const Chat = ({ chatId, windowId }: { chatId: string; windowId?: string }) => { const { toast } = useToast(); const router = useRouter(); const { isPc, media } = useScreen(); - const { chatId, windowId } = router.query as { chatId: string; windowId?: string }; const ChatBox = useRef(null); const TextareaDom = useRef(null); @@ -40,7 +39,6 @@ const Chat = () => { // 滚动到底部 const scrollToBottom = useCallback(() => { - // 滚动到底部 setTimeout(() => { ChatBox.current && ChatBox.current.scrollTo({ @@ -52,16 +50,14 @@ const Chat = () => { // 初始化聊天框 useQuery( - [chatId, windowId], + ['initData'], () => { - if (!chatId) return null; setLoading(true); return getInitChatSiteInfo(chatId, windowId); }, { - cacheTime: 5 * 60 * 1000, onSuccess(res) { - if (!res) return; + // 可能没有 windowId,给它设置一下 router.replace(`/chat?chatId=${chatId}&windowId=${res.windowId}`); setChatSiteData(res.chatSite); @@ -72,7 +68,6 @@ const Chat = () => { })) ); scrollToBottom(); - setLoading(false); }, onError(e: any) { toast({ @@ -81,11 +76,30 @@ const Chat = () => { isClosable: true, duration: 5000 }); + }, + onSettled() { setLoading(false); } } ); + // 重置输入内容 + const resetInputVal = useCallback((val: string) => { + setInputVal(val); + setTimeout(() => { + /* 回到最小高度 */ + if (TextareaDom.current) { + TextareaDom.current.style.height = + val === '' ? textareaMinH : `${TextareaDom.current.scrollHeight}px`; + } + }, 100); + }, []); + + // 重载对话 + const resetChat = useCallback(() => { + window.open(`/chat?chatId=${chatId}`, '_self'); + }, [chatId]); + // gpt3 方法 const gpt3ChatPrompt = useCallback( async (newChatList: ChatSiteItemType[]) => { @@ -210,16 +224,8 @@ const Chat = () => { // 插入内容 setChatList(newChatList); - setInputVal(''); - // 滚动到底部 - setTimeout(() => { - scrollToBottom(); - - /* 回到最小高度 */ - if (TextareaDom.current) { - TextareaDom.current.style.height = textareaMinH; - } - }, 100); + resetInputVal(''); + scrollToBottom(); const fnMap: { [key: string]: any } = { [OpenAiModelEnum.GPT35]: chatGPTPrompt, @@ -239,13 +245,13 @@ const Chat = () => { } } catch (err) { toast({ - title: typeof err === 'string' ? err : '聊天已过期', + title: typeof err === 'string' ? err : '聊天出错了~', status: 'warning', duration: 5000, isClosable: true }); - setInputVal(storeInput); + resetInputVal(storeInput); setChatList(newChatList.slice(0, newChatList.length - 2)); } @@ -256,6 +262,7 @@ const Chat = () => { gpt3ChatPrompt, inputVal, isChatting, + resetInputVal, scrollToBottom, toast ]); @@ -267,16 +274,10 @@ const Chat = () => { await delLastMessage(windowId); const val = chatList[chatList.length - 1].value; - setInputVal(val); + resetInputVal(val); setChatList(chatList.slice(0, -1)); - - setTimeout(() => { - if (TextareaDom.current) { - TextareaDom.current.style.height = val.split('\n').length * 22 + 'px'; - } - }, 100); - }, [chatList, windowId]); + }, [chatList, resetInputVal, windowId]); return ( @@ -290,13 +291,9 @@ const Chat = () => { zIndex={1} > {chatSiteData?.name} - {/* 重置按键 */} - router.replace(`/chat?chatId=${chatId}`)}> - - {/* 滚动到底部按键 */} {ChatBox.current && ChatBox.current.scrollHeight > 2 * ChatBox.current.clientHeight && ( - + { > )} + {/* 重置按键 */} + {/* 聊天内容 */} @@ -312,7 +313,7 @@ const Chat = () => { @@ -321,11 +322,11 @@ const Chat = () => { /icon/logo.png - + {item.obj === 'AI' ? ( { 对话出现了异常 - @@ -428,3 +425,12 @@ const Chat = () => { }; export default Chat; + +export async function getServerSideProps(context: any) { + const chatId = context.query?.chatId || ''; + const windowId = context.query?.windowId || ''; + + return { + props: { chatId, windowId } + }; +} diff --git a/src/pages/model/components/ModelPhoneList.tsx b/src/pages/model/components/ModelPhoneList.tsx index 8d0913e89..a3e280876 100644 --- a/src/pages/model/components/ModelPhoneList.tsx +++ b/src/pages/model/components/ModelPhoneList.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { Box, Button, Flex, Heading, Tag } from '@chakra-ui/react'; +import React, { useEffect } from 'react'; +import { Box, Button, Flex, Tag } from '@chakra-ui/react'; import type { ModelType } from '@/types/model'; import { formatModelStatus } from '@/constants/model'; import dayjs from 'dayjs'; @@ -14,6 +14,10 @@ const ModelPhoneList = ({ }) => { const router = useRouter(); + useEffect(() => { + router.prefetch('/chat'); + }, [router]); + return ( {models.map((model) => ( diff --git a/src/pages/model/components/ModelTable.tsx b/src/pages/model/components/ModelTable.tsx index c87d0192d..963de509d 100644 --- a/src/pages/model/components/ModelTable.tsx +++ b/src/pages/model/components/ModelTable.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { useEffect } from 'react'; import { Button, Table, @@ -84,6 +84,10 @@ const ModelTable = ({ } ]; + useEffect(() => { + router.prefetch('/chat'); + }, [router]); + return ( diff --git a/src/pages/model/detail.tsx b/src/pages/model/detail.tsx index 0116ed741..34d891199 100644 --- a/src/pages/model/detail.tsx +++ b/src/pages/model/detail.tsx @@ -49,7 +49,8 @@ const ModelDetail = () => { useEffect(() => { loadModel(); - }, [loadModel, modelId]); + router.prefetch('/chat'); + }, [loadModel, modelId, router]); /* 点击删除 */ const handleDelModel = useCallback(async () => { diff --git a/src/service/mongo.ts b/src/service/mongo.ts index 08d6e4599..9219e953e 100644 --- a/src/service/mongo.ts +++ b/src/service/mongo.ts @@ -11,6 +11,7 @@ export async function connectToDatabase(): Promise { global.mongodb = 'connecting'; console.log('connect mongo'); try { + mongoose.set('strictQuery', true); global.mongodb = await mongoose.connect(process.env.MONGODB_URI as string, { bufferCommands: true, dbName: 'doc_gpt', diff --git a/src/styles/reset.scss b/src/styles/reset.scss index c6b60dc7e..feb2a8810 100644 --- a/src/styles/reset.scss +++ b/src/styles/reset.scss @@ -50,6 +50,9 @@ svg { } @media (max-width: 900px) { + html { + font-size: 14px; + } ::-webkit-scrollbar, ::-webkit-scrollbar { width: 2px;