mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-18 10:03:55 +00:00
Merge branch 'main' into beian
This commit is contained in:
@@ -43,7 +43,7 @@ docker run -d --network=host --name doc-gpt \
|
|||||||
-e MY_MAIL=your email\
|
-e MY_MAIL=your email\
|
||||||
-e MAILE_CODE=your email code \
|
-e MAILE_CODE=your email code \
|
||||||
-e TOKEN_KEY=任意一个内容 \
|
-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
|
imageName:tag
|
||||||
docker logs doc-gpt
|
docker logs doc-gpt
|
||||||
|
|
||||||
|
@@ -45,7 +45,6 @@
|
|||||||
"sass": "^1.58.3",
|
"sass": "^1.58.3",
|
||||||
"sharp": "^0.31.3",
|
"sharp": "^0.31.3",
|
||||||
"tunnel": "^0.0.6",
|
"tunnel": "^0.0.6",
|
||||||
"typescript": "4.9.5",
|
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"zustand": "^4.3.5"
|
"zustand": "^4.3.5"
|
||||||
},
|
},
|
||||||
@@ -63,7 +62,8 @@
|
|||||||
"eslint-config-next": "13.1.6",
|
"eslint-config-next": "13.1.6",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"lint-staged": "^13.1.2",
|
"lint-staged": "^13.1.2",
|
||||||
"prettier": "^2.8.4"
|
"prettier": "^2.8.4",
|
||||||
|
"typescript": "4.9.5"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"./src/**/*.{ts,tsx,scss}": "npm run format"
|
"./src/**/*.{ts,tsx,scss}": "npm run format"
|
||||||
|
@@ -34,7 +34,7 @@ function responseSuccess(response: AxiosResponse<ResponseDataType>) {
|
|||||||
*/
|
*/
|
||||||
function checkRes(data: ResponseDataType) {
|
function checkRes(data: ResponseDataType) {
|
||||||
if (data === undefined) {
|
if (data === undefined) {
|
||||||
console.error(data, 'data is empty');
|
console.log('error->', data, 'data is empty');
|
||||||
return Promise.reject('服务器异常');
|
return Promise.reject('服务器异常');
|
||||||
} else if (data.code < 200 || data.code >= 400) {
|
} else if (data.code < 200 || data.code >= 400) {
|
||||||
return Promise.reject(data.message);
|
return Promise.reject(data.message);
|
||||||
@@ -46,7 +46,7 @@ function checkRes(data: ResponseDataType) {
|
|||||||
* 响应错误
|
* 响应错误
|
||||||
*/
|
*/
|
||||||
function responseError(err: any) {
|
function responseError(err: any) {
|
||||||
console.error('请求错误', err);
|
console.log('error->', '请求错误', err);
|
||||||
|
|
||||||
if (!err) {
|
if (!err) {
|
||||||
return Promise.reject({ message: '未知错误' });
|
return Promise.reject({ message: '未知错误' });
|
||||||
|
@@ -39,7 +39,7 @@ const Auth = ({ children }: { children: JSX.Element }) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError(error) {
|
onError(error) {
|
||||||
console.error(error);
|
console.log('error->', error);
|
||||||
router.push('/login');
|
router.push('/login');
|
||||||
toast();
|
toast();
|
||||||
},
|
},
|
||||||
|
@@ -2,9 +2,7 @@ import React from 'react';
|
|||||||
export const codeLight: { [key: string]: React.CSSProperties } = {
|
export const codeLight: { [key: string]: React.CSSProperties } = {
|
||||||
'code[class*=language-]': {
|
'code[class*=language-]': {
|
||||||
color: '#d4d4d4',
|
color: '#d4d4d4',
|
||||||
fontSize: '13px',
|
|
||||||
textShadow: 'none',
|
textShadow: 'none',
|
||||||
fontFamily: 'Menlo,Monaco,Consolas,"Andale Mono","Ubuntu Mono","Courier New",monospace',
|
|
||||||
direction: 'ltr',
|
direction: 'ltr',
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
whiteSpace: 'pre',
|
whiteSpace: 'pre',
|
||||||
@@ -21,9 +19,7 @@ export const codeLight: { [key: string]: React.CSSProperties } = {
|
|||||||
},
|
},
|
||||||
'pre[class*=language-]': {
|
'pre[class*=language-]': {
|
||||||
color: '#d4d4d4',
|
color: '#d4d4d4',
|
||||||
fontSize: '13px',
|
|
||||||
textShadow: 'none',
|
textShadow: 'none',
|
||||||
fontFamily: 'Menlo,Monaco,Consolas,"Andale Mono","Ubuntu Mono","Courier New",monospace',
|
|
||||||
direction: 'ltr',
|
direction: 'ltr',
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
whiteSpace: 'pre',
|
whiteSpace: 'pre',
|
||||||
|
@@ -341,7 +341,7 @@
|
|||||||
background-color: #f0f0f0;
|
background-color: #f0f0f0;
|
||||||
border: 1px solid #cccccc;
|
border: 1px solid #cccccc;
|
||||||
border-radius: 3px 3px 3px 3px;
|
border-radius: 3px 3px 3px 3px;
|
||||||
font-size: 13px;
|
font-size: max(0.9em, 14px);
|
||||||
line-height: 19px;
|
line-height: 19px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
@@ -352,11 +352,12 @@
|
|||||||
border: medium none;
|
border: medium none;
|
||||||
}
|
}
|
||||||
.markdown {
|
.markdown {
|
||||||
font-size: 14px;
|
|
||||||
line-height: 1.6;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
text-align: justify;
|
text-align: justify;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
|
overflow-y: hidden;
|
||||||
|
tab-size: 4;
|
||||||
|
word-spacing: normal;
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -372,7 +373,6 @@
|
|||||||
background-color: #222 !important;
|
background-color: #222 !important;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
width: 100%;
|
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 {
|
a {
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
import React, { memo, useMemo } from 'react';
|
import React, { memo, useMemo } from 'react';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import styles from './index.module.scss';
|
|
||||||
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
||||||
import { codeLight } from './codeLight';
|
|
||||||
import { Box, Flex } from '@chakra-ui/react';
|
import { Box, Flex } from '@chakra-ui/react';
|
||||||
import { useCopyData } from '@/utils/tools';
|
import { useCopyData } from '@/utils/tools';
|
||||||
import Icon from '@/components/Icon';
|
import Icon from '@/components/Icon';
|
||||||
@@ -10,8 +8,12 @@ import remarkGfm from 'remark-gfm';
|
|||||||
import remarkMath from 'remark-math';
|
import remarkMath from 'remark-math';
|
||||||
import rehypeKatex from 'rehype-katex';
|
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 Markdown = ({ source, isChatting }: { source: string; isChatting: boolean }) => {
|
||||||
const formatSource = useMemo(() => source.replace(/\n/g, ' \n'), [source]);
|
const formatSource = useMemo(() => source, [source]);
|
||||||
const { copyData } = useCopyData();
|
const { copyData } = useCopyData();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -25,7 +27,8 @@ const Markdown = ({ source, isChatting }: { source: string; isChatting: boolean
|
|||||||
pre: 'div',
|
pre: 'div',
|
||||||
code({ node, inline, className, children, ...props }) {
|
code({ node, inline, className, children, ...props }) {
|
||||||
const match = /language-(\w+)/.exec(className || '');
|
const match = /language-(\w+)/.exec(className || '');
|
||||||
const code = String(children).replace(/\n$/, '');
|
const code = String(children);
|
||||||
|
|
||||||
return !inline || match ? (
|
return !inline || match ? (
|
||||||
<Box my={3} borderRadius={'md'} overflow={'hidden'} backgroundColor={'#222'}>
|
<Box my={3} borderRadius={'md'} overflow={'hidden'} backgroundColor={'#222'}>
|
||||||
<Flex
|
<Flex
|
||||||
@@ -53,7 +56,7 @@ const Markdown = ({ source, isChatting }: { source: string; isChatting: boolean
|
|||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<code className={className} {...props}>
|
<code className={className} {...props}>
|
||||||
{children}
|
{code}
|
||||||
</code>
|
</code>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -20,24 +20,27 @@ const Button = defineStyleConfig({
|
|||||||
baseStyle: {},
|
baseStyle: {},
|
||||||
sizes: {
|
sizes: {
|
||||||
sm: {
|
sm: {
|
||||||
fontSize: 'sm',
|
fontSize: 'xs',
|
||||||
px: 3,
|
px: 3,
|
||||||
py: 0,
|
py: 0,
|
||||||
fontWeight: 'normal',
|
fontWeight: 'normal',
|
||||||
height: '26px'
|
height: '26px',
|
||||||
|
lineHeight: '26px'
|
||||||
},
|
},
|
||||||
md: {
|
md: {
|
||||||
fontSize: 'md',
|
fontSize: 'sm',
|
||||||
px: 6,
|
px: 6,
|
||||||
py: 0,
|
py: 0,
|
||||||
height: '34px',
|
height: '34px',
|
||||||
|
lineHeight: '34px',
|
||||||
fontWeight: 'normal'
|
fontWeight: 'normal'
|
||||||
},
|
},
|
||||||
lg: {
|
lg: {
|
||||||
fontSize: 'lg',
|
fontSize: 'md',
|
||||||
px: 8,
|
px: 8,
|
||||||
py: 0,
|
py: 0,
|
||||||
height: '42px',
|
height: '42px',
|
||||||
|
lineHeight: '42px',
|
||||||
fontWeight: 'normal'
|
fontWeight: 'normal'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -58,17 +61,12 @@ export const theme = extendTheme({
|
|||||||
global: {
|
global: {
|
||||||
'html, body': {
|
'html, body': {
|
||||||
color: 'blackAlpha.800',
|
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%',
|
height: '100%',
|
||||||
overflowY: 'auto'
|
maxHeight: '100vh',
|
||||||
|
overflowY: 'hidden'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fonts: {
|
|
||||||
body: 'system-ui, sans-serif'
|
|
||||||
},
|
|
||||||
fontSizes: {
|
fontSizes: {
|
||||||
xs: '0.8rem',
|
xs: '0.8rem',
|
||||||
sm: '0.9rem',
|
sm: '0.9rem',
|
||||||
|
@@ -1,14 +1,11 @@
|
|||||||
import { useState, useMemo, useCallback } from 'react';
|
import { useState, useMemo, useCallback } from 'react';
|
||||||
import { sendCodeToEmail } from '@/api/user';
|
import { sendCodeToEmail } from '@/api/user';
|
||||||
import { EmailTypeEnum } from '@/constants/common';
|
import { EmailTypeEnum } from '@/constants/common';
|
||||||
import { useToast } from '@chakra-ui/react';
|
|
||||||
let timer: any;
|
let timer: any;
|
||||||
|
import { useToast } from './useToast';
|
||||||
|
|
||||||
export const useSendCode = () => {
|
export const useSendCode = () => {
|
||||||
const toast = useToast({
|
const { toast } = useToast();
|
||||||
position: 'top',
|
|
||||||
duration: 2000
|
|
||||||
});
|
|
||||||
const [codeSending, setCodeSending] = useState(false);
|
const [codeSending, setCodeSending] = useState(false);
|
||||||
const [codeCountDown, setCodeCountDown] = useState(0);
|
const [codeCountDown, setCodeCountDown] = useState(0);
|
||||||
const sendCodeText = useMemo(() => {
|
const sendCodeText = useMemo(() => {
|
||||||
@@ -43,13 +40,11 @@ export const useSendCode = () => {
|
|||||||
status: 'success',
|
status: 'success',
|
||||||
position: 'top'
|
position: 'top'
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
typeof error === 'string' &&
|
toast({
|
||||||
toast({
|
title: error.message || '发送验证码异常',
|
||||||
title: error,
|
status: 'error'
|
||||||
status: 'error',
|
});
|
||||||
position: 'top'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
setCodeSending(false);
|
setCodeSending(false);
|
||||||
},
|
},
|
||||||
|
@@ -6,6 +6,7 @@ import { getOpenAIApi, authChat } from '@/service/utils/chat';
|
|||||||
import { openaiProxy } from '@/service/utils/tools';
|
import { openaiProxy } from '@/service/utils/tools';
|
||||||
import { ChatCompletionRequestMessage, ChatCompletionRequestMessageRoleEnum } from 'openai';
|
import { ChatCompletionRequestMessage, ChatCompletionRequestMessageRoleEnum } from 'openai';
|
||||||
import { ChatItemType } from '@/types/chat';
|
import { ChatItemType } from '@/types/chat';
|
||||||
|
import { openaiError } from '@/service/errorCode';
|
||||||
|
|
||||||
/* 发送提示词 */
|
/* 发送提示词 */
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
@@ -50,13 +51,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
const formatPrompts: ChatCompletionRequestMessage[] = filterPrompts.map(
|
const formatPrompts: ChatCompletionRequestMessage[] = filterPrompts.map(
|
||||||
(item: ChatItemType) => ({
|
(item: ChatItemType) => ({
|
||||||
role: map[item.obj],
|
role: map[item.obj],
|
||||||
content: item.value.replace(/\n/g, ' ')
|
content: item.value
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
// 第一句话,强调代码类型
|
// 第一句话,强调代码类型
|
||||||
formatPrompts.unshift({
|
formatPrompts.unshift({
|
||||||
role: ChatCompletionRequestMessageRoleEnum.System,
|
role: ChatCompletionRequestMessageRoleEnum.System,
|
||||||
content: '如果你想返回代码,请务必声明代码的类型!'
|
content: '如果你想返回代码,请务必声明代码的类型!并且在代码块前加一个换行符。'
|
||||||
});
|
});
|
||||||
// 获取 chatAPI
|
// 获取 chatAPI
|
||||||
const chatAPI = getOpenAIApi(userApiKey);
|
const chatAPI = getOpenAIApi(userApiKey);
|
||||||
@@ -74,7 +75,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
httpsAgent: openaiProxy?.httpsAgent
|
httpsAgent: openaiProxy?.httpsAgent
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
console.log('response success');
|
console.log(
|
||||||
|
formatPrompts.reduce((sum, item) => sum + item.content.length, 0),
|
||||||
|
'response success'
|
||||||
|
);
|
||||||
|
|
||||||
let AIResponse = '';
|
let AIResponse = '';
|
||||||
|
|
||||||
@@ -95,54 +99,44 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
updateTime: Date.now()
|
updateTime: Date.now()
|
||||||
});
|
});
|
||||||
res.write('event: done\ndata: \n\n');
|
res.write('event: done\ndata: \n\n');
|
||||||
res.end();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const json = JSON.parse(data);
|
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)
|
// console.log('content:', content)
|
||||||
res.write(`event: responseData\ndata: ${content.replace(/\n/g, '<br/>')}\n\n`);
|
res.write(`event: responseData\ndata: ${content.replace(/\n/g, '<br/>')}\n\n`);
|
||||||
AIResponse += content;
|
AIResponse += content;
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
res.end();
|
error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const parser = createParser(onParse);
|
try {
|
||||||
for await (const chunk of chatResponse.data as any) {
|
for await (const chunk of chatResponse.data as any) {
|
||||||
parser.feed(decoder.decode(chunk));
|
const parser = createParser(onParse);
|
||||||
|
parser.feed(decoder.decode(chunk));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error, '====');
|
||||||
|
throw new Error('错误了');
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
let errorText = err;
|
// console.log('error->', err?.response, '===');
|
||||||
|
let errorText = 'OpenAI 服务器访问超时';
|
||||||
if (err.code === 'ECONNRESET') {
|
if (err.code === 'ECONNRESET') {
|
||||||
errorText = '服务器代理出错';
|
errorText = '服务器代理出错';
|
||||||
} else {
|
} else if (err?.response?.statusText && openaiError[err.response.statusText]) {
|
||||||
switch (err?.response?.data?.error?.code) {
|
errorText = openaiError[err.response.statusText];
|
||||||
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 = '服务器异常';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
console.error(errorText);
|
console.log('error->', errorText);
|
||||||
res.write(`event: serviceError\ndata: ${errorText}\n\n`);
|
res.write(`event: serviceError\ndata: ${errorText}\n\n`);
|
||||||
res.end();
|
|
||||||
// 删除最一条数据库记录, 也就是预发送的那一条
|
// 删除最一条数据库记录, 也就是预发送的那一条
|
||||||
await ChatWindow.findByIdAndUpdate(windowId, {
|
await ChatWindow.findByIdAndUpdate(windowId, {
|
||||||
$pop: { content: 1 },
|
$pop: { content: 1 },
|
||||||
updateTime: Date.now()
|
updateTime: Date.now()
|
||||||
});
|
});
|
||||||
|
res.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
if (type === EmailTypeEnum.register) {
|
if (type === EmailTypeEnum.register) {
|
||||||
const maxCount = process.env.MAX_USER ? +process.env.MAX_USER : Infinity;
|
const maxCount = process.env.MAX_USER ? +process.env.MAX_USER : Infinity;
|
||||||
const userCount = await User.count();
|
const userCount = await User.count();
|
||||||
|
|
||||||
if (userCount >= maxCount) {
|
if (userCount >= maxCount) {
|
||||||
throw new Error('当前注册用户已满,请等待名额~');
|
throw new Error('当前注册用户已满,请等待名额~');
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
const { authorization } = req.headers;
|
const { authorization } = req.headers;
|
||||||
|
|
||||||
if (!authorization) {
|
if (!authorization) {
|
||||||
throw new Error('缺少参数');
|
throw new Error('缺少登录凭证');
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = await authToken(authorization);
|
const userId = await authToken(authorization);
|
||||||
|
@@ -22,11 +22,10 @@ const Markdown = dynamic(() => import('@/components/Markdown'));
|
|||||||
|
|
||||||
const textareaMinH = '22px';
|
const textareaMinH = '22px';
|
||||||
|
|
||||||
const Chat = () => {
|
const Chat = ({ chatId, windowId }: { chatId: string; windowId?: string }) => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { isPc, media } = useScreen();
|
const { isPc, media } = useScreen();
|
||||||
const { chatId, windowId } = router.query as { chatId: string; windowId?: string };
|
|
||||||
const ChatBox = useRef<HTMLDivElement>(null);
|
const ChatBox = useRef<HTMLDivElement>(null);
|
||||||
const TextareaDom = useRef<HTMLTextAreaElement>(null);
|
const TextareaDom = useRef<HTMLTextAreaElement>(null);
|
||||||
|
|
||||||
@@ -40,7 +39,6 @@ const Chat = () => {
|
|||||||
|
|
||||||
// 滚动到底部
|
// 滚动到底部
|
||||||
const scrollToBottom = useCallback(() => {
|
const scrollToBottom = useCallback(() => {
|
||||||
// 滚动到底部
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
ChatBox.current &&
|
ChatBox.current &&
|
||||||
ChatBox.current.scrollTo({
|
ChatBox.current.scrollTo({
|
||||||
@@ -52,16 +50,14 @@ const Chat = () => {
|
|||||||
|
|
||||||
// 初始化聊天框
|
// 初始化聊天框
|
||||||
useQuery(
|
useQuery(
|
||||||
[chatId, windowId],
|
['initData'],
|
||||||
() => {
|
() => {
|
||||||
if (!chatId) return null;
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
return getInitChatSiteInfo(chatId, windowId);
|
return getInitChatSiteInfo(chatId, windowId);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cacheTime: 5 * 60 * 1000,
|
|
||||||
onSuccess(res) {
|
onSuccess(res) {
|
||||||
if (!res) return;
|
// 可能没有 windowId,给它设置一下
|
||||||
router.replace(`/chat?chatId=${chatId}&windowId=${res.windowId}`);
|
router.replace(`/chat?chatId=${chatId}&windowId=${res.windowId}`);
|
||||||
|
|
||||||
setChatSiteData(res.chatSite);
|
setChatSiteData(res.chatSite);
|
||||||
@@ -72,7 +68,6 @@ const Chat = () => {
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
setLoading(false);
|
|
||||||
},
|
},
|
||||||
onError(e: any) {
|
onError(e: any) {
|
||||||
toast({
|
toast({
|
||||||
@@ -81,11 +76,30 @@ const Chat = () => {
|
|||||||
isClosable: true,
|
isClosable: true,
|
||||||
duration: 5000
|
duration: 5000
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
onSettled() {
|
||||||
setLoading(false);
|
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 方法
|
// gpt3 方法
|
||||||
const gpt3ChatPrompt = useCallback(
|
const gpt3ChatPrompt = useCallback(
|
||||||
async (newChatList: ChatSiteItemType[]) => {
|
async (newChatList: ChatSiteItemType[]) => {
|
||||||
@@ -165,13 +179,13 @@ const Chat = () => {
|
|||||||
event.addEventListener('serviceError', ({ data: err }) => {
|
event.addEventListener('serviceError', ({ data: err }) => {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
event.close();
|
event.close();
|
||||||
console.error(err, '===');
|
console.log('error->', err, '===');
|
||||||
reject(typeof err === 'string' ? err : '对话出现不知名错误~');
|
reject(typeof err === 'string' ? err : '对话出现不知名错误~');
|
||||||
});
|
});
|
||||||
event.onerror = (err) => {
|
event.onerror = (err) => {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
event.close();
|
event.close();
|
||||||
console.error(err);
|
console.log('error->', err);
|
||||||
reject(typeof err === 'string' ? err : '对话出现不知名错误~');
|
reject(typeof err === 'string' ? err : '对话出现不知名错误~');
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -210,16 +224,8 @@ const Chat = () => {
|
|||||||
|
|
||||||
// 插入内容
|
// 插入内容
|
||||||
setChatList(newChatList);
|
setChatList(newChatList);
|
||||||
setInputVal('');
|
resetInputVal('');
|
||||||
// 滚动到底部
|
scrollToBottom();
|
||||||
setTimeout(() => {
|
|
||||||
scrollToBottom();
|
|
||||||
|
|
||||||
/* 回到最小高度 */
|
|
||||||
if (TextareaDom.current) {
|
|
||||||
TextareaDom.current.style.height = textareaMinH;
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
const fnMap: { [key: string]: any } = {
|
const fnMap: { [key: string]: any } = {
|
||||||
[OpenAiModelEnum.GPT35]: chatGPTPrompt,
|
[OpenAiModelEnum.GPT35]: chatGPTPrompt,
|
||||||
@@ -239,13 +245,13 @@ const Chat = () => {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toast({
|
toast({
|
||||||
title: typeof err === 'string' ? err : '聊天已过期',
|
title: typeof err === 'string' ? err : '聊天出错了~',
|
||||||
status: 'warning',
|
status: 'warning',
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
isClosable: true
|
isClosable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
setInputVal(storeInput);
|
resetInputVal(storeInput);
|
||||||
|
|
||||||
setChatList(newChatList.slice(0, newChatList.length - 2));
|
setChatList(newChatList.slice(0, newChatList.length - 2));
|
||||||
}
|
}
|
||||||
@@ -256,6 +262,7 @@ const Chat = () => {
|
|||||||
gpt3ChatPrompt,
|
gpt3ChatPrompt,
|
||||||
inputVal,
|
inputVal,
|
||||||
isChatting,
|
isChatting,
|
||||||
|
resetInputVal,
|
||||||
scrollToBottom,
|
scrollToBottom,
|
||||||
toast
|
toast
|
||||||
]);
|
]);
|
||||||
@@ -267,16 +274,10 @@ const Chat = () => {
|
|||||||
await delLastMessage(windowId);
|
await delLastMessage(windowId);
|
||||||
const val = chatList[chatList.length - 1].value;
|
const val = chatList[chatList.length - 1].value;
|
||||||
|
|
||||||
setInputVal(val);
|
resetInputVal(val);
|
||||||
|
|
||||||
setChatList(chatList.slice(0, -1));
|
setChatList(chatList.slice(0, -1));
|
||||||
|
}, [chatList, resetInputVal, windowId]);
|
||||||
setTimeout(() => {
|
|
||||||
if (TextareaDom.current) {
|
|
||||||
TextareaDom.current.style.height = val.split('\n').length * 22 + 'px';
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
}, [chatList, windowId]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex height={'100%'} flexDirection={'column'}>
|
<Flex height={'100%'} flexDirection={'column'}>
|
||||||
@@ -290,13 +291,9 @@ const Chat = () => {
|
|||||||
zIndex={1}
|
zIndex={1}
|
||||||
>
|
>
|
||||||
<Box flex={1}>{chatSiteData?.name}</Box>
|
<Box flex={1}>{chatSiteData?.name}</Box>
|
||||||
{/* 重置按键 */}
|
|
||||||
<Box cursor={'pointer'} onClick={() => router.replace(`/chat?chatId=${chatId}`)}>
|
|
||||||
<Icon name={'icon-zhongzhi'} width={20} height={20} color={'#718096'}></Icon>
|
|
||||||
</Box>
|
|
||||||
{/* 滚动到底部按键 */}
|
{/* 滚动到底部按键 */}
|
||||||
{ChatBox.current && ChatBox.current.scrollHeight > 2 * ChatBox.current.clientHeight && (
|
{ChatBox.current && ChatBox.current.scrollHeight > 2 * ChatBox.current.clientHeight && (
|
||||||
<Box ml={10} cursor={'pointer'} onClick={scrollToBottom}>
|
<Box mr={10} cursor={'pointer'} onClick={scrollToBottom}>
|
||||||
<Icon
|
<Icon
|
||||||
name={'icon-xiangxiazhankai-xianxingyuankuang'}
|
name={'icon-xiangxiazhankai-xianxingyuankuang'}
|
||||||
width={25}
|
width={25}
|
||||||
@@ -305,6 +302,10 @@ const Chat = () => {
|
|||||||
></Icon>
|
></Icon>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
{/* 重置按键 */}
|
||||||
|
<Button size={'sm'} colorScheme={'gray'} onClick={resetChat}>
|
||||||
|
新对话
|
||||||
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
{/* 聊天内容 */}
|
{/* 聊天内容 */}
|
||||||
<Box ref={ChatBox} flex={'1 0 0'} h={0} w={'100%'} px={0} pb={10} overflowY={'auto'}>
|
<Box ref={ChatBox} flex={'1 0 0'} h={0} w={'100%'} px={0} pb={10} overflowY={'auto'}>
|
||||||
@@ -312,7 +313,7 @@ const Chat = () => {
|
|||||||
<Box
|
<Box
|
||||||
key={index}
|
key={index}
|
||||||
py={media(9, 6)}
|
py={media(9, 6)}
|
||||||
px={media(4, 3)}
|
px={media(4, 2)}
|
||||||
backgroundColor={index % 2 === 0 ? 'rgba(247,247,248,1)' : '#fff'}
|
backgroundColor={index % 2 === 0 ? 'rgba(247,247,248,1)' : '#fff'}
|
||||||
borderBottom={'1px solid rgba(0,0,0,0.1)'}
|
borderBottom={'1px solid rgba(0,0,0,0.1)'}
|
||||||
>
|
>
|
||||||
@@ -321,11 +322,11 @@ const Chat = () => {
|
|||||||
<Image
|
<Image
|
||||||
src={item.obj === 'Human' ? '/icon/human.png' : '/icon/logo.png'}
|
src={item.obj === 'Human' ? '/icon/human.png' : '/icon/logo.png'}
|
||||||
alt="/icon/logo.png"
|
alt="/icon/logo.png"
|
||||||
width={30}
|
width={media(30, 20)}
|
||||||
height={30}
|
height={media(30, 20)}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box flex={'1 0 0'} w={0} overflowX={'hidden'}>
|
<Box flex={'1 0 0'} w={0} overflow={'hidden'}>
|
||||||
{item.obj === 'AI' ? (
|
{item.obj === 'AI' ? (
|
||||||
<Markdown
|
<Markdown
|
||||||
source={item.value}
|
source={item.value}
|
||||||
@@ -360,11 +361,7 @@ const Chat = () => {
|
|||||||
<Box textAlign={'center'}>
|
<Box textAlign={'center'}>
|
||||||
<Box color={'red'}>对话出现了异常</Box>
|
<Box color={'red'}>对话出现了异常</Box>
|
||||||
<Flex py={5} justifyContent={'center'}>
|
<Flex py={5} justifyContent={'center'}>
|
||||||
<Button
|
<Button mr={20} onClick={resetChat} colorScheme={'green'}>
|
||||||
mr={20}
|
|
||||||
onClick={() => router.replace(`/chat?chatId=${chatId}`)}
|
|
||||||
colorScheme={'green'}
|
|
||||||
>
|
|
||||||
重开对话
|
重开对话
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={reEdit}>重新编辑最后一句</Button>
|
<Button onClick={reEdit}>重新编辑最后一句</Button>
|
||||||
@@ -438,3 +435,12 @@ const Chat = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default Chat;
|
export default Chat;
|
||||||
|
|
||||||
|
export async function getServerSideProps(context: any) {
|
||||||
|
const chatId = context.query?.chatId || '';
|
||||||
|
const windowId = context.query?.windowId || '';
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: { chatId, windowId }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@@ -61,13 +61,11 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
|||||||
title: `密码已找回`,
|
title: `密码已找回`,
|
||||||
status: 'success'
|
status: 'success'
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
typeof error === 'string' &&
|
toast({
|
||||||
toast({
|
title: error.message || '修改密码异常',
|
||||||
title: error,
|
status: 'error'
|
||||||
status: 'error',
|
});
|
||||||
position: 'top'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
setRequesting(false);
|
setRequesting(false);
|
||||||
},
|
},
|
||||||
|
@@ -42,13 +42,11 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
|
|||||||
title: '登录成功',
|
title: '登录成功',
|
||||||
status: 'success'
|
status: 'success'
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
typeof error === 'string' &&
|
toast({
|
||||||
toast({
|
title: error.message || '登录异常',
|
||||||
title: error,
|
status: 'error'
|
||||||
status: 'error',
|
});
|
||||||
position: 'top'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
setRequesting(false);
|
setRequesting(false);
|
||||||
},
|
},
|
||||||
|
@@ -61,14 +61,11 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
|||||||
title: `注册成功`,
|
title: `注册成功`,
|
||||||
status: 'success'
|
status: 'success'
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
typeof error === 'string' &&
|
toast({
|
||||||
toast({
|
title: error.message || '注册异常',
|
||||||
title: error,
|
status: 'error'
|
||||||
status: 'error',
|
});
|
||||||
duration: 4000,
|
|
||||||
isClosable: true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
setRequesting(false);
|
setRequesting(false);
|
||||||
},
|
},
|
||||||
|
@@ -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 styles from './index.module.scss';
|
||||||
import { Box, Flex, Image } from '@chakra-ui/react';
|
import { Box, Flex, Image } from '@chakra-ui/react';
|
||||||
import { PageTypeEnum } from '@/constants/user';
|
import { PageTypeEnum } from '@/constants/user';
|
||||||
@@ -21,7 +21,7 @@ const Login = () => {
|
|||||||
const loginSuccess = useCallback(
|
const loginSuccess = useCallback(
|
||||||
(res: ResLogin) => {
|
(res: ResLogin) => {
|
||||||
setUserInfo(res.user, res.token);
|
setUserInfo(res.user, res.token);
|
||||||
router.push('/');
|
router.push('/model/list');
|
||||||
},
|
},
|
||||||
[router, setUserInfo]
|
[router, setUserInfo]
|
||||||
);
|
);
|
||||||
@@ -38,6 +38,10 @@ const Login = () => {
|
|||||||
return <Component setPageType={setPageType} loginSuccess={loginSuccess} />;
|
return <Component setPageType={setPageType} loginSuccess={loginSuccess} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
router.prefetch('/model/list');
|
||||||
|
}, [router]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box className={styles.loginPage} h={'100%'} p={isPc ? '10vh 10vw' : 0}>
|
<Box className={styles.loginPage} h={'100%'} p={isPc ? '10vh 10vw' : 0}>
|
||||||
<Flex
|
<Flex
|
||||||
|
@@ -34,7 +34,7 @@ const ModelEditForm = ({ model }: { model?: ModelType }) => {
|
|||||||
status: 'success'
|
status: 'success'
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.log('error->', err);
|
||||||
toast({
|
toast({
|
||||||
title: err as string,
|
title: err as string,
|
||||||
status: 'success'
|
status: 'success'
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { Box, Button, Flex, Heading, Tag } from '@chakra-ui/react';
|
import { Box, Button, Flex, Tag } from '@chakra-ui/react';
|
||||||
import type { ModelType } from '@/types/model';
|
import type { ModelType } from '@/types/model';
|
||||||
import { formatModelStatus } from '@/constants/model';
|
import { formatModelStatus } from '@/constants/model';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
@@ -14,6 +14,10 @@ const ModelPhoneList = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
router.prefetch('/chat');
|
||||||
|
}, [router]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box borderRadius={'md'} overflow={'hidden'} mb={5}>
|
<Box borderRadius={'md'} overflow={'hidden'} mb={5}>
|
||||||
{models.map((model) => (
|
{models.map((model) => (
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import { useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Table,
|
Table,
|
||||||
@@ -84,6 +84,10 @@ const ModelTable = ({
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
router.prefetch('/chat');
|
||||||
|
}, [router]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card py={3}>
|
<Card py={3}>
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
|
@@ -29,7 +29,7 @@ const Training = ({ model }: { model: ModelType }) => {
|
|||||||
const res = await getModelTrainings(id);
|
const res = await getModelTrainings(id);
|
||||||
setRecords(res);
|
setRecords(res);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.log('error->', error);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@@ -42,14 +42,15 @@ const ModelDetail = () => {
|
|||||||
res.security.expiredTime /= 60 * 60 * 1000;
|
res.security.expiredTime /= 60 * 60 * 1000;
|
||||||
setModel(res);
|
setModel(res);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.log('error->', err);
|
||||||
}
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}, [modelId, setLoading]);
|
}, [modelId, setLoading]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadModel();
|
loadModel();
|
||||||
}, [loadModel, modelId]);
|
router.prefetch('/chat');
|
||||||
|
}, [loadModel, modelId, router]);
|
||||||
|
|
||||||
/* 点击删除 */
|
/* 点击删除 */
|
||||||
const handleDelModel = useCallback(async () => {
|
const handleDelModel = useCallback(async () => {
|
||||||
@@ -63,7 +64,7 @@ const ModelDetail = () => {
|
|||||||
});
|
});
|
||||||
router.replace('/model/list');
|
router.replace('/model/list');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.log('error->', err);
|
||||||
}
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}, [setLoading, model, router, toast]);
|
}, [setLoading, model, router, toast]);
|
||||||
@@ -77,7 +78,7 @@ const ModelDetail = () => {
|
|||||||
|
|
||||||
router.push(`/chat?chatId=${chatId}`);
|
router.push(`/chat?chatId=${chatId}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.log('error->', err);
|
||||||
}
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}, [setLoading, model, router]);
|
}, [setLoading, model, router]);
|
||||||
@@ -105,7 +106,7 @@ const ModelDetail = () => {
|
|||||||
title: typeof err === 'string' ? err : '文件格式错误',
|
title: typeof err === 'string' ? err : '文件格式错误',
|
||||||
status: 'error'
|
status: 'error'
|
||||||
});
|
});
|
||||||
console.error(err);
|
console.log('error->', err);
|
||||||
}
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
},
|
},
|
||||||
@@ -120,11 +121,15 @@ const ModelDetail = () => {
|
|||||||
try {
|
try {
|
||||||
await putModelTrainingStatus(model._id);
|
await putModelTrainingStatus(model._id);
|
||||||
loadModel();
|
loadModel();
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error(error);
|
console.log('error->', error);
|
||||||
|
toast({
|
||||||
|
title: error.message || '更新失败',
|
||||||
|
status: 'error'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}, [setLoading, loadModel, model]);
|
}, [model, setLoading, loadModel, toast]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@@ -10,10 +10,12 @@ import { useScreen } from '@/hooks/useScreen';
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useLoading } from '@/hooks/useLoading';
|
import { useLoading } from '@/hooks/useLoading';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
|
import { useToast } from '@/hooks/useToast';
|
||||||
|
|
||||||
const CreateModel = dynamic(() => import('./components/CreateModel'));
|
const CreateModel = dynamic(() => import('./components/CreateModel'));
|
||||||
|
|
||||||
const ModelList = () => {
|
const ModelList = () => {
|
||||||
|
const { toast } = useToast();
|
||||||
const { isPc } = useScreen();
|
const { isPc } = useScreen();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [models, setModels] = useState<ModelType[]>([]);
|
const [models, setModels] = useState<ModelType[]>([]);
|
||||||
@@ -43,12 +45,16 @@ const ModelList = () => {
|
|||||||
router.push(`/chat?chatId=${chatId}`, undefined, {
|
router.push(`/chat?chatId=${chatId}`, undefined, {
|
||||||
shallow: true
|
shallow: true
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
console.error(err);
|
console.log('error->', err);
|
||||||
|
toast({
|
||||||
|
title: err.message || '出现一些异常',
|
||||||
|
status: 'error'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
},
|
},
|
||||||
[router, setIsLoading]
|
[router, setIsLoading, toast]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@@ -1,3 +1,6 @@
|
|||||||
export const openaiError: Record<string, string> = {
|
export const openaiError: Record<string, string> = {
|
||||||
context_length_exceeded: '内容超出长度'
|
context_length_exceeded: '内容超长了,请重置对话',
|
||||||
|
Unauthorized: 'API-KEY 不合法',
|
||||||
|
rate_limit_reached: '同时访问用户过多,请稍后再试',
|
||||||
|
'Bad Request': '内容太多了~'
|
||||||
};
|
};
|
||||||
|
@@ -4,23 +4,23 @@ import mongoose from 'mongoose';
|
|||||||
* 连接 MongoDB 数据库
|
* 连接 MongoDB 数据库
|
||||||
*/
|
*/
|
||||||
export async function connectToDatabase(): Promise<void> {
|
export async function connectToDatabase(): Promise<void> {
|
||||||
// @ts-ignore
|
|
||||||
if (global.mongodb) {
|
if (global.mongodb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
|
||||||
global.mongodb = 'connecting';
|
global.mongodb = 'connecting';
|
||||||
console.log('connect mongo');
|
console.log('connect mongo');
|
||||||
try {
|
try {
|
||||||
// @ts-ignore
|
mongoose.set('strictQuery', true);
|
||||||
global.mongodb = await mongoose.connect(process.env.MONGODB_URI as string, {
|
global.mongodb = await mongoose.connect(process.env.MONGODB_URI as string, {
|
||||||
|
bufferCommands: true,
|
||||||
dbName: 'doc_gpt',
|
dbName: 'doc_gpt',
|
||||||
maxPoolSize: 10,
|
maxPoolSize: 5,
|
||||||
minPoolSize: 1
|
minPoolSize: 1,
|
||||||
|
maxConnecting: 5
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('mongo connect error');
|
console.log('error->', 'mongo connect error');
|
||||||
// @ts-ignore
|
|
||||||
global.mongodb = null;
|
global.mongodb = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,8 +27,8 @@ export const jsonRes = (
|
|||||||
msg = openaiError[error?.response?.data?.message];
|
msg = openaiError[error?.response?.data?.message];
|
||||||
}
|
}
|
||||||
|
|
||||||
console.error(error);
|
console.log('error->', error);
|
||||||
console.error(msg);
|
console.log('error->', msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
|
@@ -34,7 +34,7 @@ export const sendCode = (email: string, code: string, type: `${EmailTypeEnum}`)
|
|||||||
};
|
};
|
||||||
mailTransport.sendMail(options, function (err, msg) {
|
mailTransport.sendMail(options, function (err, msg) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.log('error->', err);
|
||||||
reject('邮箱异常');
|
reject('邮箱异常');
|
||||||
} else {
|
} else {
|
||||||
resolve('');
|
resolve('');
|
||||||
@@ -53,7 +53,7 @@ export const sendTrainSucceed = (email: string, modelName: string) => {
|
|||||||
};
|
};
|
||||||
mailTransport.sendMail(options, function (err, msg) {
|
mailTransport.sendMail(options, function (err, msg) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.log('error->', err);
|
||||||
reject('邮箱异常');
|
reject('邮箱异常');
|
||||||
} else {
|
} else {
|
||||||
resolve('');
|
resolve('');
|
||||||
|
@@ -50,6 +50,9 @@ svg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
|
html {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
::-webkit-scrollbar,
|
::-webkit-scrollbar,
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 2px;
|
width: 2px;
|
||||||
|
7
src/types/index.d.ts
vendored
7
src/types/index.d.ts
vendored
@@ -1,9 +1,6 @@
|
|||||||
import type { Mongoose } from 'mongoose';
|
import type { Mongoose } from 'mongoose';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Global {
|
var mongodb: Mongoose | string | null;
|
||||||
mongodb: Mongoose;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
export {};
|
||||||
export type a = string;
|
|
||||||
|
@@ -21,7 +21,7 @@ export const useCopyData = () => {
|
|||||||
duration: 1000
|
duration: 1000
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.log('error->', error);
|
||||||
toast({
|
toast({
|
||||||
title: '复制失败',
|
title: '复制失败',
|
||||||
status: 'error'
|
status: 'error'
|
||||||
|
Reference in New Issue
Block a user