Skip to content

Commit

Permalink
Merge branch 'c121914yu:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
molimao authored Jun 19, 2023
2 parents 0b16b79 + a02a528 commit fd75c09
Show file tree
Hide file tree
Showing 61 changed files with 1,287 additions and 1,222 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Fast GPT

Fast GPT 允许你使用自己的 openai API KEY 来快速的调用 openai 接口,目前集成了 Gpt35, Gpt4 和 embedding. 可构建自己的知识库。
Fast GPT 允许你使用自己的 openai API KEY 来快速的调用 openai 接口,目前集成了 Gpt35, Gpt4 和 embedding. 可构建自己的知识库。并且 OpenAPI Chat 接口兼容 OpenAI 接口,意味着你只需修改 BaseUrl 和 Authorization 即可在已有项目基础上接入 FastGpt!

## 🛸 在线体验

Expand Down
1 change: 1 addition & 0 deletions client/.env.template
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# 运行端口,如果不是 3000 口运行,需要改成其他的。注意:不是改了这个变量就会变成其他端口,而是因为改成其他端口,才用这个变量。
DB_MAX_LINK=15 # database max link
PORT=3000
# 代理
# AXIOS_PROXY_HOST=127.0.0.1
Expand Down
7 changes: 4 additions & 3 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,24 @@
"jsonwebtoken": "^9.0.0",
"lodash": "^4.17.21",
"mammoth": "^1.5.1",
"mermaid": "^8.13.5",
"mermaid": "^10.2.3",
"mongoose": "^6.10.0",
"nanoid": "^4.0.1",
"next": "13.1.6",
"nextjs-cors": "^2.1.2",
"nodemailer": "^6.9.1",
"nprogress": "^0.2.0",
"openai": "^3.2.1",
"openai": "^3.3.0",
"papaparse": "^5.4.1",
"pg": "^8.10.0",
"react": "18.2.0",
"react-day-picker": "^8.7.1",
"react-dom": "18.2.0",
"react-hook-form": "^7.43.1",
"react-markdown": "^8.0.5",
"react-markdown": "^8.0.7",
"react-syntax-highlighter": "^15.5.0",
"rehype-katex": "^6.0.2",
"remark-breaks": "^3.0.3",
"remark-gfm": "^3.0.1",
"remark-math": "^5.1.1",
"request-ip": "^3.3.0",
Expand Down
523 changes: 174 additions & 349 deletions client/pnpm-lock.yaml

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions client/public/docs/versionIntro.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
### Fast GPT V3.8.4
### Fast GPT V3.8.8

1. 新增 - mermaid 导图兼容,可以在应用市场 'mermaid 导图' 进行体验。
2. 优化 - 部分 UI 和账号页。
2. 优化 - 知识库搜索速度
1. 新增 - V2 版 OpenAPI,可以在任意第三方套壳 ChatGpt 项目中直接使用 FastGpt 的应用,注意!是直接,不需要改任何代码。具体参考[API 文档中《在第三方应用中使用 FastGpt》](https://kjqvjse66l.feishu.cn/docx/DmLedTWtUoNGX8xui9ocdUEjnNh)
2. 新增 - 应用配置最大回复长度。
3. 新增 - 更多的知识库配置项:相似度、最大搜索数量、自定义空搜索结果回复。
4. 新增 - 知识库搜索测试,方便调试。
5. 优化 - 知识库提示词位置,拥有更强的引导。
6. 优化 - 应用编辑页面。
8 changes: 8 additions & 0 deletions client/public/js/baidutongji.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
var _hmt = _hmt || [];

(function () {
const hm = document.createElement('script');
hm.src = 'https://hm.baidu.com/hm.js?a5357e9dab086658bac0b6faf148882e';
const s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(hm, s);
})();
105 changes: 71 additions & 34 deletions client/src/api/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,67 +1,104 @@
import { GUIDE_PROMPT_HEADER, NEW_CHATID_HEADER, QUOTE_LEN_HEADER } from '@/constants/chat';
import { Props, ChatResponseType } from '@/pages/api/openapi/v1/chat/completions';
import { sseResponseEventEnum } from '@/constants/chat';
import { getErrText } from '@/utils/tools';

interface StreamFetchProps {
url: string;
data: any;
data: Props;
onMessage: (text: string) => void;
abortSignal: AbortController;
}
export const streamFetch = ({ url, data, onMessage, abortSignal }: StreamFetchProps) =>
new Promise<{
responseText: string;
newChatId: string;
systemPrompt: string;
quoteLen: number;
}>(async (resolve, reject) => {
export const streamFetch = ({ data, onMessage, abortSignal }: StreamFetchProps) =>
new Promise<ChatResponseType & { responseText: string }>(async (resolve, reject) => {
try {
const res = await fetch(url, {
const response = await window.fetch('/api/openapi/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
signal: abortSignal.signal
signal: abortSignal.signal,
body: JSON.stringify({
...data,
stream: true
})
});
const reader = res.body?.getReader();
if (!reader) return;

const decoder = new TextDecoder();
if (!response?.body) {
throw new Error('Request Error');
}

const newChatId = decodeURIComponent(res.headers.get(NEW_CHATID_HEADER) || '');
const systemPrompt = decodeURIComponent(res.headers.get(GUIDE_PROMPT_HEADER) || '').trim();
const quoteLen = res.headers.get(QUOTE_LEN_HEADER)
? Number(res.headers.get(QUOTE_LEN_HEADER))
: 0;
const reader = response.body?.getReader();
const decoder = new TextDecoder('utf-8');

// response data
let responseText = '';
let newChatId = '';
let quoteLen = 0;

const read = async () => {
try {
const { done, value } = await reader?.read();
const { done, value } = await reader.read();
if (done) {
if (res.status === 200) {
resolve({ responseText, newChatId, quoteLen, systemPrompt });
if (response.status === 200) {
return resolve({
responseText,
newChatId,
quoteLen
});
} else {
const parseError = JSON.parse(responseText);
reject(parseError?.message || '请求异常');
return reject('响应过程出现异常~');
}

return;
}
const text = decoder.decode(value);
responseText += text;
onMessage(text);
const chunk = decoder.decode(value);
const chunkLines = chunk.split('\n\n').filter((item) => item);
const chunkResponse = chunkLines.map((item) => {
const splitEvent = item.split('\n');
if (splitEvent.length === 2) {
return {
event: splitEvent[0].replace('event: ', ''),
data: splitEvent[1].replace('data: ', '')
};
}
return {
event: '',
data: splitEvent[0].replace('data: ', '')
};
});

chunkResponse.forEach((item) => {
// parse json data
const data = (() => {
try {
return JSON.parse(item.data);
} catch (error) {
return item.data;
}
})();

if (item.event === sseResponseEventEnum.answer && data !== '[DONE]') {
const answer: string = data?.choices?.[0].delta.content || '';
onMessage(answer);
responseText += answer;
} else if (item.event === sseResponseEventEnum.chatResponse) {
const chatResponse = data as ChatResponseType;
newChatId = chatResponse.newChatId;
quoteLen = chatResponse.quoteLen || 0;
}
});
read();
} catch (err: any) {
if (err?.message === 'The user aborted a request.') {
return resolve({ responseText, newChatId, quoteLen, systemPrompt });
return resolve({
responseText,
newChatId,
quoteLen
});
}
reject(typeof err === 'string' ? err : err?.message || '请求异常');
reject(getErrText(err, '请求异常'));
}
};
read();
} catch (err: any) {
console.log(err, '====');
reject(typeof err === 'string' ? err : err?.message || '请求异常');
reject(getErrText(err, '请求异常'));
}
});
1 change: 1 addition & 0 deletions client/src/api/response/chat.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { ChatItemType } from '@/types/chat';
export interface InitChatResponse {
chatId: string;
modelId: string;
systemPrompt?: string;
model: {
name: string;
avatar: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,7 @@ const CodeLight = ({
children,
className,
inline,
match,
...props
match
}: {
children: React.ReactNode & React.ReactNode[];
className?: string;
Expand All @@ -315,18 +314,14 @@ const CodeLight = ({
<Box ml={1}>复制</Box>
</Flex>
</Flex>
<SyntaxHighlighter style={codeLight as any} language={match?.[1]} PreTag="pre" {...props}>
<SyntaxHighlighter style={codeLight as any} language={match?.[1]} PreTag="pre">
{String(children)}
</SyntaxHighlighter>
</Box>
);
}

return (
<code className={className} {...props}>
{children}
</code>
);
return <code className={className}>{children}</code>;
};

export default React.memo(CodeLight);
2 changes: 1 addition & 1 deletion client/src/components/Markdown/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import { Image, Skeleton } from '@chakra-ui/react';

const MdImage = ({ src }: { src: string }) => {
const MdImage = ({ src }: { src?: string }) => {
const [isLoading, setIsLoading] = useState(true);
const [succeed, setSucceed] = useState(false);
return (
Expand Down
17 changes: 17 additions & 0 deletions client/src/components/Markdown/Link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { Box } from '@chakra-ui/react';

const regex = /((http|https|ftp):\/\/[^\s\u4e00-\u9fa5\u3000-\u303f\uff00-\uffef]+)/gi;

const Link = ({ href }: { href?: string }) => {
const decText = decodeURIComponent(href || '');
const replaceText = decText.replace(regex, (match, p1) => {
const isInternal = /^\/#/i.test(p1);
const target = isInternal ? '_self' : '_blank';
return `<a href="${p1}" target=${target}>${p1}</a>`;
});

return <Box as={'span'} dangerouslySetInnerHTML={{ __html: replaceText }} />;
};

export default React.memo(Link);
Loading

0 comments on commit fd75c09

Please sign in to comment.