4.7 doc update (#1068)

* fix: plugin update

* feat: get current time plugin

* fix: ts

* perf: select app ux

* fix: ts

* perf: max w

* move code

* perf: inform tip

* fix: inform

* doc

* fix: tool handle

* perf: tmp file store

* doc

* fix: message file selector

* feat: doc

* perf: switch trigger

* doc

* fix: openapi import

* rount the number

* parse openapi schema

* fix empty line after variables (#64)

* doc image

* image size

* doc

* doc

* catch error

---------

Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
This commit is contained in:
Archer
2024-03-27 12:50:07 +08:00
committed by GitHub
parent c7e6448272
commit 6b7b03c245
160 changed files with 1393 additions and 558 deletions

View File

@@ -0,0 +1,15 @@
import SwaggerParser from '@apidevtools/swagger-parser';
export const loadOpenAPISchemaFromUrl = async (url: string) => {
return SwaggerParser.bundle(url);
};
export const checkOpenAPISchemaValid = async (str: string) => {
try {
const res = await SwaggerParser.validate(JSON.parse(str));
console.log(res);
return !!res;
} catch (error) {
return false;
}
};

View File

@@ -6,7 +6,7 @@ import { chatNodeSystemPromptTip } from './tip';
export const Input_Template_Switch: FlowNodeInputItemType = {
key: ModuleInputKeyEnum.switch,
type: FlowNodeInputTypeEnum.triggerAndFinish,
type: FlowNodeInputTypeEnum.hidden,
label: '',
description: 'core.module.input.description.Trigger',
valueType: ModuleIOValueTypeEnum.any,

View File

@@ -122,6 +122,7 @@ export const HttpModule468: FlowNodeTemplateType = {
outputType: FlowNodeOutputTypeEnum.source,
valueType: ModuleIOValueTypeEnum.string
}
}
},
Output_Template_Finish
]
};

View File

@@ -13,19 +13,21 @@ import { HttpParamAndHeaderItemType } from '../../module/api';
import { CreateOnePluginParams } from '../controller';
import { ModuleItemType } from '../../module/type';
import { HttpImgUrl } from '../../../common/file/image/constants';
import SwaggerParser from '@apidevtools/swagger-parser';
export const str2OpenApiSchema = (yamlStr = ''): OpenApiJsonSchema => {
export const str2OpenApiSchema = async (yamlStr = ''): Promise<OpenApiJsonSchema> => {
try {
const data: OpenAPIV3.Document = (() => {
const data = (() => {
try {
return JSON.parse(yamlStr);
} catch (jsonError) {
return yaml.load(yamlStr, { schema: yaml.FAILSAFE_SCHEMA });
}
})();
const jsonSchema = (await SwaggerParser.parse(data)) as OpenAPIV3.Document;
const serverPath = data.servers?.[0].url || '';
const pathData = Object.keys(data.paths)
const serverPath = jsonSchema.servers?.[0].url || '';
const pathData = Object.keys(jsonSchema.paths)
.map((path) => {
const methodData: any = data.paths[path];
return Object.keys(methodData)
@@ -55,7 +57,7 @@ export const str2OpenApiSchema = (yamlStr = ''): OpenApiJsonSchema => {
}
};
export const httpApiSchema2Plugins = ({
export const httpApiSchema2Plugins = async ({
parentId,
apiSchemaStr = '',
customHeader = ''
@@ -63,8 +65,9 @@ export const httpApiSchema2Plugins = ({
parentId: string;
apiSchemaStr?: string;
customHeader?: string;
}): CreateOnePluginParams[] => {
const jsonSchema = str2OpenApiSchema(apiSchemaStr);
}): Promise<CreateOnePluginParams[]> => {
const jsonSchema = await str2OpenApiSchema(apiSchemaStr);
const baseUrl = jsonSchema.serverPath;
return jsonSchema.pathData.map((item) => {
@@ -222,7 +225,7 @@ export const httpApiSchema2Plugins = ({
}
}
if (item.request) {
const properties = item.request?.content?.['application/json']?.schema?.properties;
const properties = item.request?.content?.['application/json']?.schema?.properties || {};
const keys = Object.keys(properties);
if (keys.length > 0) {
httpNodeBody = JSON.stringify(

View File

@@ -12,7 +12,8 @@
"js-yaml": "^4.1.0",
"timezones-list": "^3.0.2",
"next": "13.5.2",
"jschardet": "3.1.1"
"jschardet": "3.1.1",
"@apidevtools/swagger-parser": "^10.1.0"
},
"devDependencies": {
"@types/js-yaml": "^4.0.9",

View File

@@ -8,6 +8,10 @@ export type SendInformProps = {
export type SendInform2UserProps = SendInformProps & {
tmbId: string;
};
export type SendInform2User = SendInformProps & {
type: `${InformTypeEnum}`;
tmbId: string;
};
export type UserInformSchema = {
_id: string;

View File

@@ -3,6 +3,7 @@ import multer from 'multer';
import path from 'path';
import { BucketNameEnum, bucketNameMap } from '@fastgpt/global/common/file/constants';
import { getNanoid } from '@fastgpt/global/common/string/tools';
import { tmpFileDirPath } from './constants';
type FileType = {
fieldname: string;
@@ -23,9 +24,9 @@ export const getUploadModel = ({ maxSize = 500 }: { maxSize?: number }) => {
},
preservePath: true,
storage: multer.diskStorage({
// destination: (_req, _file, cb) => {
// cb(null, tmpFileDirPath);
// },
destination: (_req, _file, cb) => {
cb(null, tmpFileDirPath);
},
filename: async (req, file, cb) => {
const { ext } = path.parse(decodeURIComponent(file.originalname));
cb(null, `${getNanoid()}${ext}`);

View File

@@ -27,3 +27,18 @@ export const guessBase64ImageType = (str: string) => {
const firstChar = str.charAt(0);
return imageTypeMap[firstChar] || defaultType;
};
export const clearDirFiles = (dirPath: string) => {
if (!fs.existsSync(dirPath)) {
return;
}
fs.readdirSync(dirPath).forEach((file) => {
const curPath = `${dirPath}/${file}`;
if (fs.lstatSync(curPath).isDirectory()) {
clearDirFiles(curPath);
} else {
fs.unlinkSync(curPath);
}
});
};

View File

@@ -19,20 +19,28 @@ const defaultPrompt = `作为一个向量检索助手,你的任务是结合历
历史记录:
"""
Q: 对话背景。
A: 当前对话是关于 FatGPT 的介绍和使用等。
A: 当前对话是关于 Nginx 的介绍和使用等。
"""
原问题: 怎么下载
检索词: ["FastGPT 如何下载?","下载 FastGPT 需要什么条件?","有哪些渠道可以下载 FastGPT"]
检索词: ["Nginx 如何下载?","下载 Nginx 需要什么条件?","有哪些渠道可以下载 Nginx"]
----------------
历史记录:
"""
Q: 对话背景。
A: 当前对话是关于 FatGPT 的介绍和使用等。
A: 当前对话是关于 Nginx 的介绍和使用等。
Q: 报错 "no connection"
A: 报错"no connection"可能是因为……
"""
原问题: 怎么解决
检索词: ["FastGPT 报错"no connection"如何解决?", "造成 'no connection' 报错的原因。", "FastGPT提示'no connection',要怎么办?"]
检索词: ["Nginx报错"no connection"如何解决?","造成'no connection'报错的原因。","Nginx提示'no connection',要怎么办?"]
----------------
历史记录:
"""
Q: 护产假多少天?
A: 护产假的天数根据员工所在的城市而定。请提供您所在的城市,以便我回答您的问题。
"""
原问题: 沈阳
检索词: ["沈阳的护产假多少天?"]
----------------
历史记录:
"""
@@ -42,14 +50,6 @@ A: FastGPT 的作者是 labring。
原问题: Tell me about him
检索词: ["Introduce labring, the author of FastGPT." ," Background information on author labring." "," Why does labring do FastGPT?"]
----------------
历史记录:
"""
Q: 对话背景。
A: 当前对话是关于 FatGPT 的介绍和使用等。
"""
原问题: 高级编排怎么用
检索词: ["FastGPT的高级编排是什么","FastGPT高级编排的使用教程。","FastGPT高级编排有什么用"]
----------------
历史记录:
"""
Q: 对话背景。

View File

@@ -13,13 +13,13 @@ export const Prompt_Tool_Call = `<Instruction>
USER: 你好呀
ANSWER: 0: 你好,有什么可以帮助你的么?
USER: 今天杭州的天气如何
ANSWER: 1: {"toolId":"w2121",arguments:{"city": "杭州"}}
ANSWER: 1: {"toolId":"testToolId",arguments:{"city": "杭州"}}
TOOL_RESPONSE: """
晴天......
"""
ANSWER: 0: 今天杭州是晴天。
USER: 今天杭州的天气适合去哪里玩?
ANSWER: 1: {"toolId":"as21da",arguments:{"query": "杭州 天气 去哪里玩"}}
ANSWER: 1: {"toolId":"testToolId2",arguments:{"query": "杭州 天气 去哪里玩"}}
TOOL_RESPONSE: """
晴天. 西湖、灵隐寺、千岛湖……
"""

View File

@@ -131,7 +131,7 @@ export const runToolWithPromptCall = async (
})();
const parseAnswerResult = parseAnswer(answer);
// console.log(answer, '==11==');
// console.log(parseAnswer, '==11==');
// No tools
if (typeof parseAnswerResult === 'string') {
// No tool is invoked, indicating that the process is over
@@ -270,7 +270,9 @@ export const runToolWithPromptCall = async (
// get the next user prompt
lastMessage.content += `${answer}
TOOL_RESPONSE: ${toolsRunResponse.toolResponsePrompt}
TOOL_RESPONSE: """
${toolsRunResponse.toolResponsePrompt}
"""
ANSWER: `;
/* check stop signal */

View File

@@ -73,7 +73,7 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
temperature = 0,
maxToken = 4000,
history = 6,
quoteQA = [],
quoteQA,
userChatInput,
isResponseAnswerText = true,
systemPrompt = '',
@@ -114,6 +114,7 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
const { filterMessages } = getChatMessages({
model: modelConstantsData,
histories: chatHistories,
quoteQA,
quoteText,
quotePrompt,
userChatInput,
@@ -269,13 +270,13 @@ function filterQuote({
: '';
return {
filterQuoteQA: filterQuoteQA,
quoteText
};
}
function getChatMessages({
quotePrompt,
quoteText,
quoteQA,
histories = [],
systemPrompt,
userChatInput,
@@ -284,18 +285,20 @@ function getChatMessages({
}: {
quotePrompt?: string;
quoteText: string;
quoteQA: ChatProps['params']['quoteQA'];
histories: ChatItemType[];
systemPrompt: string;
userChatInput: string;
inputFiles: UserChatItemValueItemType['file'][];
model: LLMModelItemType;
}) {
const replaceInputValue = quoteText
? replaceVariable(quotePrompt || Prompt_QuotePromptList[0].value, {
quote: quoteText,
question: userChatInput
})
: userChatInput;
const replaceInputValue =
quoteQA !== undefined
? replaceVariable(quotePrompt || Prompt_QuotePromptList[0].value, {
quote: quoteText,
question: userChatInput
})
: userChatInput;
const messages: ChatItemType[] = [
...getSystemPrompt(systemPrompt),

View File

@@ -34,10 +34,9 @@ export default function Editor({
showOpenModal?: boolean;
onOpenModal?: () => void;
variables: EditorVariablePickerType[];
onChange?: (editorState: EditorState) => void;
onChange?: (editorState: EditorState, editor: LexicalEditor) => void;
onBlur?: (editor: LexicalEditor) => void;
value?: string;
currentValue?: string;
placeholder?: string;
}) {
const [key, setKey] = useState(getNanoid(6));
@@ -112,9 +111,9 @@ export default function Editor({
<HistoryPlugin />
<FocusPlugin focus={focus} setFocus={setFocus} />
<OnChangePlugin
onChange={(e) => {
onChange={(editorState, editor) => {
startSts(() => {
onChange?.(e);
onChange?.(editorState, editor);
});
}}
/>

View File

@@ -1,5 +1,5 @@
import { Button, ModalBody, ModalFooter, useDisclosure } from '@chakra-ui/react';
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import { editorStateToText } from './utils';
import Editor from './Editor';
import MyModal from '../../MyModal';
@@ -30,14 +30,15 @@ const PromptEditor = ({
title?: string;
}) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const [, startSts] = useTransition();
const { t } = useTranslation();
const onChangeInput = useCallback((editorState: EditorState) => {
const text = editorState.read(() => $getRoot().getTextContent());
const formatValue = text.replaceAll('\n\n', '\n').replaceAll('}}{{', '}} {{');
const onChangeInput = useCallback((editorState: EditorState, editor: LexicalEditor) => {
const stringifiedEditorState = JSON.stringify(editorState.toJSON());
const parsedEditorState = editor.parseEditorState(stringifiedEditorState);
const editorStateTextString = parsedEditorState.read(() => $getRoot().getTextContent());
const formatValue = editorStateTextString.replaceAll('\n\n', '\n').replaceAll('}}{{', '}} {{');
onChange?.(formatValue);
}, []);
const onBlurInput = useCallback((editor: LexicalEditor) => {