From f6552d0d4f9f0037bac75bd913f8d42fe0a5551a Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Tue, 26 Sep 2023 14:31:37 +0800 Subject: [PATCH] v4.4.5-2 (#355) --- .../docs/installation/upgrading/445.md | 23 ++ .../core/aiApi/config.ts | 2 +- packages/core/aiApi/constant.ts | 1 + packages/core/aiApi/type.d.ts | 1 + packages/core/init.ts | 13 ++ packages/core/package.json | 9 +- packages/core/types/index.d.ts | 5 + packages/core/user/type.d.ts | 19 ++ pnpm-lock.yaml | 28 +-- projects/app/package.json | 11 +- projects/app/public/locales/en/common.json | 2 + projects/app/public/locales/zh/common.json | 4 +- projects/app/src/components/ChatBox/utils.ts | 12 +- projects/app/src/components/Loading/index.tsx | 12 +- .../src/components/support/apikey/Table.tsx | 4 +- .../app/src/constants/flow/ModuleTemplate.ts | 26 ++- projects/app/src/pages/api/admin/initChat.ts | 58 ----- .../app/src/pages/api/admin/initChatItem.ts | 98 -------- .../app/src/pages/api/admin/initOutlink.ts | 27 --- projects/app/src/pages/api/admin/initv445.ts | 104 +++++++++ projects/app/src/pages/api/chat/init.ts | 4 +- .../pages/api/core/dataset/file/markUsed.ts | 2 +- .../src/pages/api/openapi/plugin/vector.ts | 2 +- .../pages/api/openapi/v1/chat/completions.ts | 6 +- .../app/src/pages/api/support/outLink/init.ts | 4 +- .../app/src/pages/api/user/account/update.ts | 4 +- .../components/AdEdit/components/ChatTest.tsx | 4 +- .../AdEdit/components/Nodes/NodeUserGuide.tsx | 221 ++++++++++++++---- .../AdEdit/components/TemplateList.tsx | 2 +- .../app/detail/components/BasicEdit/index.tsx | 34 +-- projects/app/src/pages/index.tsx | 37 ++- .../kb/detail/components/Import/Chunk.tsx | 2 +- .../components/Import/CreateFileModal.tsx | 2 +- .../pages/kb/detail/components/Import/QA.tsx | 2 +- projects/app/src/service/events/generateQA.ts | 4 +- projects/app/src/service/models/app.ts | 3 + .../moduleDispatch/agent/classifyQuestion.ts | 23 +- .../service/moduleDispatch/agent/extract.ts | 2 +- .../src/service/moduleDispatch/chat/oneapi.ts | 4 +- projects/app/src/service/mongo.ts | 12 +- projects/app/src/service/pg.ts | 1 + projects/app/src/types/index.d.ts | 2 - projects/app/src/utils/adapt.ts | 2 +- projects/app/src/utils/app.ts | 89 +++---- .../app/src/utils/common/adapt/message.ts | 2 +- .../app/src/utils/common/tiktoken/index.ts | 2 +- projects/app/src/utils/file.ts | 2 +- projects/app/tsconfig.json | 2 +- 48 files changed, 536 insertions(+), 399 deletions(-) create mode 100644 docSite/content/docs/installation/upgrading/445.md rename projects/app/src/service/lib/openai.ts => packages/core/aiApi/config.ts (94%) create mode 100644 packages/core/aiApi/constant.ts create mode 100644 packages/core/aiApi/type.d.ts create mode 100644 packages/core/init.ts create mode 100644 packages/core/types/index.d.ts create mode 100644 packages/core/user/type.d.ts delete mode 100644 projects/app/src/pages/api/admin/initChat.ts delete mode 100644 projects/app/src/pages/api/admin/initChatItem.ts delete mode 100644 projects/app/src/pages/api/admin/initOutlink.ts create mode 100644 projects/app/src/pages/api/admin/initv445.ts diff --git a/docSite/content/docs/installation/upgrading/445.md b/docSite/content/docs/installation/upgrading/445.md new file mode 100644 index 000000000..68253b764 --- /dev/null +++ b/docSite/content/docs/installation/upgrading/445.md @@ -0,0 +1,23 @@ +--- +title: '升级到 V4.4.5' +description: 'FastGPT 从旧版本升级到 V4.4.5 操作指南' +icon: 'upgrade' +draft: false +toc: true +weight: 992 +--- + +## 执行初始化 API + +发起 1 个 HTTP 请求(记得携带 `headers.rootkey`,这个值是环境变量里的) + +1. https://xxxxx/api/admin/initv445 + +```bash +curl --location --request POST 'https://{{host}}/api/admin/initv445' \ +--header 'rootkey: {{rootkey}}' \ +--header 'Content-Type: application/json' +``` + +初始化了 variable 模块,将其合并到用户引导模块中。 + diff --git a/projects/app/src/service/lib/openai.ts b/packages/core/aiApi/config.ts similarity index 94% rename from projects/app/src/service/lib/openai.ts rename to packages/core/aiApi/config.ts index 98371c541..cc9c94e2f 100644 --- a/projects/app/src/service/lib/openai.ts +++ b/packages/core/aiApi/config.ts @@ -1,4 +1,4 @@ -import { UserModelSchema } from '@/types/mongoSchema'; +import { UserModelSchema } from '../user/type'; import { Configuration, OpenAIApi } from 'openai'; export const openaiBaseUrl = process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1'; diff --git a/packages/core/aiApi/constant.ts b/packages/core/aiApi/constant.ts new file mode 100644 index 000000000..2c6b9bee5 --- /dev/null +++ b/packages/core/aiApi/constant.ts @@ -0,0 +1 @@ +export { ChatCompletionRequestMessageRoleEnum } from 'openai'; diff --git a/packages/core/aiApi/type.d.ts b/packages/core/aiApi/type.d.ts new file mode 100644 index 000000000..7fa86c127 --- /dev/null +++ b/packages/core/aiApi/type.d.ts @@ -0,0 +1 @@ +export type { CreateChatCompletionRequest, ChatCompletionRequestMessage } from 'openai'; diff --git a/packages/core/init.ts b/packages/core/init.ts new file mode 100644 index 000000000..a50966fe5 --- /dev/null +++ b/packages/core/init.ts @@ -0,0 +1,13 @@ +import tunnel from 'tunnel'; + +export function initHttpAgent() { + // proxy obj + if (process.env.AXIOS_PROXY_HOST && process.env.AXIOS_PROXY_PORT) { + global.httpsAgent = tunnel.httpsOverHttp({ + proxy: { + host: process.env.AXIOS_PROXY_HOST, + port: +process.env.AXIOS_PROXY_PORT + } + }); + } +} diff --git a/packages/core/package.json b/packages/core/package.json index 9af0d8e11..46673ad04 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,4 +1,11 @@ { "name": "@fastgpt/core", - "version": "1.0.0" + "version": "1.0.0", + "dependencies": { + "openai": "^3.3.0", + "tunnel": "^0.0.6" + }, + "devDependencies": { + "@types/tunnel": "^0.0.4" + } } diff --git a/packages/core/types/index.d.ts b/packages/core/types/index.d.ts new file mode 100644 index 000000000..acceaede9 --- /dev/null +++ b/packages/core/types/index.d.ts @@ -0,0 +1,5 @@ +import type { Agent } from 'http'; + +declare global { + var httpsAgent: Agent; +} diff --git a/packages/core/user/type.d.ts b/packages/core/user/type.d.ts new file mode 100644 index 000000000..eb058cfc1 --- /dev/null +++ b/packages/core/user/type.d.ts @@ -0,0 +1,19 @@ +export type UserModelSchema = { + _id: string; + username: string; + password: string; + avatar: string; + balance: number; + promotionRate: number; + inviterId?: string; + openaiKey: string; + createTime: number; + timezone: string; + openaiAccount?: { + key: string; + baseUrl: string; + }; + limit: { + exportKbTime?: Date; + }; +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e9a81b6a8..a477870b8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,7 +29,18 @@ importers: packages/common: {} - packages/core: {} + packages/core: + dependencies: + openai: + specifier: ^3.3.0 + version: registry.npmmirror.com/openai@3.3.0 + tunnel: + specifier: ^0.0.6 + version: registry.npmmirror.com/tunnel@0.0.6 + devDependencies: + '@types/tunnel': + specifier: ^0.0.4 + version: registry.npmmirror.com/@types/tunnel@0.0.4 packages/support: {} @@ -152,9 +163,6 @@ importers: nprogress: specifier: ^0.2.0 version: registry.npmmirror.com/nprogress@0.2.0 - openai: - specifier: ^3.3.0 - version: registry.npmmirror.com/openai@3.3.0 papaparse: specifier: ^5.4.1 version: registry.npmmirror.com/papaparse@5.4.1 @@ -209,9 +217,6 @@ importers: timezones-list: specifier: ^3.0.2 version: registry.npmmirror.com/timezones-list@3.0.2 - tunnel: - specifier: ^0.0.6 - version: registry.npmmirror.com/tunnel@0.0.6 winston: specifier: ^3.10.0 version: registry.npmmirror.com/winston@3.10.0 @@ -270,9 +275,6 @@ importers: '@types/request-ip': specifier: ^0.0.37 version: registry.npmmirror.com/@types/request-ip@0.0.37 - '@types/tunnel': - specifier: ^0.0.3 - version: registry.npmmirror.com/@types/tunnel@0.0.3 eslint: specifier: 8.34.0 version: registry.npmmirror.com/eslint@8.34.0 @@ -5611,10 +5613,10 @@ packages: version: 1.3.3 dev: false - registry.npmmirror.com/@types/tunnel@0.0.3: - resolution: {integrity: sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/tunnel/-/tunnel-0.0.3.tgz} + registry.npmmirror.com/@types/tunnel@0.0.4: + resolution: {integrity: sha512-bQgDBL5XiqrrPUaZd9bZ2esOXcU4GTmgg0n6LHDqoMJezO3VFRZsW8qN6Gp64/LAmjtzNU3iAHBfV3Z2ht5DSg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/tunnel/-/tunnel-0.0.4.tgz} name: '@types/tunnel' - version: 0.0.3 + version: 0.0.4 dependencies: '@types/node': registry.npmmirror.com/@types/node@18.14.0 dev: true diff --git a/projects/app/package.json b/projects/app/package.json index b8601e514..af6c0ddf3 100644 --- a/projects/app/package.json +++ b/projects/app/package.json @@ -14,6 +14,9 @@ "@chakra-ui/system": "^2.5.8", "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", + "@fastgpt/common": "workspace:*", + "@fastgpt/core": "workspace:*", + "@fastgpt/support": "workspace:*", "@mozilla/readability": "^0.4.4", "@tanstack/react-query": "^4.24.10", "@types/nprogress": "^0.2.0", @@ -45,7 +48,6 @@ "next-i18next": "^14.0.3", "nextjs-cors": "^2.1.2", "nprogress": "^0.2.0", - "openai": "^3.3.0", "papaparse": "^5.4.1", "pg": "^8.10.0", "pg-query-stream": "^4.5.3", @@ -64,13 +66,9 @@ "request-ip": "^3.3.0", "sass": "^1.58.3", "timezones-list": "^3.0.2", - "tunnel": "^0.0.6", "winston": "^3.10.0", "winston-mongodb": "^5.1.1", - "zustand": "^4.3.5", - "@fastgpt/support": "workspace:*", - "@fastgpt/common": "workspace:*", - "@fastgpt/core": "workspace:*" + "zustand": "^4.3.5" }, "devDependencies": { "@svgr/webpack": "^6.5.1", @@ -89,7 +87,6 @@ "@types/react-dom": "18.0.11", "@types/react-syntax-highlighter": "^15.5.6", "@types/request-ip": "^0.0.37", - "@types/tunnel": "^0.0.3", "eslint": "8.34.0", "eslint-config-next": "13.1.6", "typescript": "4.9.5" diff --git a/projects/app/public/locales/en/common.json b/projects/app/public/locales/en/common.json index f84bfc438..acc68aafe 100644 --- a/projects/app/public/locales/en/common.json +++ b/projects/app/public/locales/en/common.json @@ -237,8 +237,10 @@ "outlink": { "Copy Iframe": "Copy Iframe", "Copy Link": "Copy", + "Create API Key": "Create Key", "Create Link": "Create Link", "Delete Link": "Delete", + "Edit API Key": "Edit Key", "Edit Ifrme Link": "Edit Iframe Link", "Edit Link": "Edit", "Edit Share Window": "Edit Share Window", diff --git a/projects/app/public/locales/zh/common.json b/projects/app/public/locales/zh/common.json index ff1baee95..7ecb67eff 100644 --- a/projects/app/public/locales/zh/common.json +++ b/projects/app/public/locales/zh/common.json @@ -230,15 +230,17 @@ "Tools": "工具" }, "openapi": { - "app key tips": "这些 Key 已有当前应用标识,可以直接外部接入使用。", + "app key tips": "这些 key 已有当前应用标识,具体使用可参考文档", "key alias": "key 的别名,仅用于展示", "key tips": "你可以使用 API 秘钥访问一些特定的接口" }, "outlink": { "Copy Iframe": "复制嵌入", "Copy Link": "复制", + "Create API Key": "创建新 Key", "Create Link": "创建链接", "Delete Link": "删除链接", + "Edit API Key": "编辑 Key 信息", "Edit Ifrme Link": "更新嵌入链接", "Edit Link": "编辑", "Edit Share Window": "更新分享窗口", diff --git a/projects/app/src/components/ChatBox/utils.ts b/projects/app/src/components/ChatBox/utils.ts index 35694edfe..4feb6f23a 100644 --- a/projects/app/src/components/ChatBox/utils.ts +++ b/projects/app/src/components/ChatBox/utils.ts @@ -3,16 +3,14 @@ import { FlowModuleTypeEnum } from '@/constants/flow'; import { getChatModel } from '@/service/utils/data'; import { AppModuleItemType, VariableItemType } from '@/types/app'; -export const getSpecialModule = (modules: AppModuleItemType[]) => { +export const getGuideModules = (modules: AppModuleItemType[]) => { + const guideModules = modules.find((item) => item.flowType === FlowModuleTypeEnum.userGuide); + const welcomeText: string = - modules - .find((item) => item.flowType === FlowModuleTypeEnum.userGuide) - ?.inputs?.find((item) => item.key === SystemInputEnum.welcomeText)?.value || ''; + guideModules?.inputs?.find((item) => item.key === SystemInputEnum.welcomeText)?.value || ''; const variableModules: VariableItemType[] = - modules - .find((item) => item.flowType === FlowModuleTypeEnum.variable) - ?.inputs.find((item) => item.key === SystemInputEnum.variables)?.value || []; + guideModules?.inputs.find((item) => item.key === SystemInputEnum.variables)?.value || []; return { welcomeText, diff --git a/projects/app/src/components/Loading/index.tsx b/projects/app/src/components/Loading/index.tsx index 919ca7592..ac3676340 100644 --- a/projects/app/src/components/Loading/index.tsx +++ b/projects/app/src/components/Loading/index.tsx @@ -1,12 +1,20 @@ import React from 'react'; import { Spinner, Flex, Box } from '@chakra-ui/react'; -const Loading = ({ fixed = true, text = '' }: { fixed?: boolean; text?: string }) => { +const Loading = ({ + fixed = true, + text = '', + bg = 'rgba(255,255,255,0.5)' +}: { + fixed?: boolean; + text?: string; + bg?: string; +}) => { return ( { onClick={() => copyData(baseUrl, '已复制 API 地址')} > - API地址 + API根地址 {baseUrl} @@ -292,7 +292,7 @@ function EditKeyModal({ }); return ( - + {t('Name')}: diff --git a/projects/app/src/constants/flow/ModuleTemplate.ts b/projects/app/src/constants/flow/ModuleTemplate.ts index f62f3434c..f45278b70 100644 --- a/projects/app/src/constants/flow/ModuleTemplate.ts +++ b/projects/app/src/constants/flow/ModuleTemplate.ts @@ -24,12 +24,14 @@ export const ChatModelLimitTip = export const userGuideTip = '可以添加特殊的对话前后引导模块,更好的让用户进行对话'; export const welcomeTextTip = '每次对话开始前,发送一个初始内容。支持标准 Markdown 语法,可使用的额外标记:\n[快捷按键]: 用户点击后可以直接发送该问题'; +export const variableTip = + '可以在对话开始前,要求用户填写一些内容作为本轮对话的特定变量。该模块位于开场引导之后。\n变量可以通过 {{变量key}} 的形式注入到其他模块 string 类型的输入中,例如:提示词、限定词等'; export const VariableModule: FlowModuleTemplateType = { flowType: FlowModuleTypeEnum.variable, logo: '/imgs/module/variable.png', name: '全局变量', - intro: '可以在对话开始前,要求用户填写一些内容作为本轮对话的变量。该模块位于开场引导之后。', + intro: variableTip, description: '全局变量可以通过 {{变量key}} 的形式注入到其他模块 string 类型的输入中,例如:提示词、限定词等', inputs: [ @@ -52,6 +54,12 @@ export const UserGuideModule: FlowModuleTemplateType = { key: SystemInputEnum.welcomeText, type: FlowInputItemTypeEnum.input, label: '开场白' + }, + { + key: SystemInputEnum.variables, + type: FlowInputItemTypeEnum.systemInput, + label: '对话框变量', + value: [] } ], outputs: [] @@ -476,7 +484,7 @@ export const ModuleTemplates = [ }, { label: '引导模块', - list: [UserGuideModule, VariableModule] + list: [UserGuideModule] }, { label: '内容生成', @@ -491,7 +499,19 @@ export const ModuleTemplates = [ list: [ClassifyQuestionModule, ContextExtractModule, HttpModule] } ]; -export const ModuleTemplatesFlat = ModuleTemplates.map((templates) => templates.list)?.flat(); +export const ModuleTemplatesFlat = [ + VariableModule, + UserGuideModule, + UserInputModule, + HistoryModule, + ChatModule, + KBSearchModule, + AnswerModule, + ClassifyQuestionModule, + ContextExtractModule, + HttpModule, + EmptyModule +]; // template export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = [ diff --git a/projects/app/src/pages/api/admin/initChat.ts b/projects/app/src/pages/api/admin/initChat.ts deleted file mode 100644 index 6b2be11c5..000000000 --- a/projects/app/src/pages/api/admin/initChat.ts +++ /dev/null @@ -1,58 +0,0 @@ -// Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import type { NextApiRequest, NextApiResponse } from 'next'; -import { jsonRes } from '@/service/response'; -import { authUser } from '@/service/utils/auth'; -import { connectToDatabase, Chat } from '@/service/mongo'; - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - try { - await authUser({ req, authRoot: true }); - await connectToDatabase(); - - const { limit = 1000 } = req.body as { limit: number }; - let skip = 0; - const total = await Chat.countDocuments({ - chatId: { $exists: false } - }); - let promise = Promise.resolve(); - console.log(total); - - for (let i = 0; i < total; i += limit) { - const skipVal = skip; - skip += limit; - promise = promise - .then(() => init(limit, skipVal)) - .then(() => { - console.log(skipVal); - }); - } - - await promise; - - jsonRes(res, {}); - } catch (error) { - jsonRes(res, { - code: 500, - error - }); - } -} - -async function init(limit: number, skip: number) { - // 遍历 app - const chats = await Chat.find( - { - chatId: { $exists: false } - }, - '_id' - ).limit(limit); - - await Promise.all( - chats.map((chat) => - Chat.findByIdAndUpdate(chat._id, { - chatId: String(chat._id), - source: 'online' - }) - ) - ); -} diff --git a/projects/app/src/pages/api/admin/initChatItem.ts b/projects/app/src/pages/api/admin/initChatItem.ts deleted file mode 100644 index a52694a61..000000000 --- a/projects/app/src/pages/api/admin/initChatItem.ts +++ /dev/null @@ -1,98 +0,0 @@ -// Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import type { NextApiRequest, NextApiResponse } from 'next'; -import { jsonRes } from '@/service/response'; -import { authUser } from '@/service/utils/auth'; -import { connectToDatabase, Chat, ChatItem } from '@/service/mongo'; -import { customAlphabet } from 'nanoid'; -const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24); - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - try { - await authUser({ req, authRoot: true }); - await connectToDatabase(); - - const { limit = 100 } = req.body as { limit: number }; - let skip = 0; - - const total = await Chat.countDocuments({ - content: { $exists: true, $not: { $size: 0 } }, - isInit: { $ne: true } - }); - const totalChat = await Chat.aggregate([ - { - $project: { - contentLength: { $size: '$content' } - } - }, - { - $group: { - _id: null, - totalLength: { $sum: '$contentLength' } - } - } - ]); - - console.log('chatLen:', total, totalChat); - - let promise = Promise.resolve(); - - for (let i = 0; i < total; i += limit) { - const skipVal = skip; - skip += limit; - promise = promise - .then(() => init(limit)) - .then(() => { - console.log(skipVal); - }); - } - - await promise; - - jsonRes(res, {}); - } catch (error) { - jsonRes(res, { - code: 500, - error - }); - } -} - -async function init(limit: number) { - // 遍历 app - const chats = await Chat.find( - { - content: { $exists: true, $not: { $size: 0 } }, - isInit: { $ne: true } - }, - '_id userId appId chatId content' - ) - .sort({ updateTime: -1 }) - .limit(limit); - - await Promise.all( - chats.map(async (chat) => { - const inserts = chat.content - .map((item) => ({ - dataId: nanoid(), - chatId: chat.chatId, - userId: chat.userId, - appId: chat.appId, - obj: item.obj, - value: item.value, - responseData: item.responseData - })) - .filter((item) => item.chatId && item.userId && item.appId && item.obj && item.value); - - try { - await Promise.all(inserts.map((item) => ChatItem.create(item))); - await Chat.findByIdAndUpdate(chat._id, { - isInit: true - }); - } catch (error) { - console.log(error); - - await ChatItem.deleteMany({ chatId: chat.chatId }); - } - }) - ); -} diff --git a/projects/app/src/pages/api/admin/initOutlink.ts b/projects/app/src/pages/api/admin/initOutlink.ts deleted file mode 100644 index 6d94e17dd..000000000 --- a/projects/app/src/pages/api/admin/initOutlink.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import type { NextApiRequest, NextApiResponse } from 'next'; -import { jsonRes } from '@/service/response'; -import { authUser } from '@/service/utils/auth'; -import { connectToDatabase, OutLink } from '@/service/mongo'; -import { OutLinkTypeEnum } from '@/constants/chat'; - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - try { - await authUser({ req, authRoot: true }); - await connectToDatabase(); - - await OutLink.updateMany( - {}, - { - $set: { type: OutLinkTypeEnum.share } - } - ); - - jsonRes(res, {}); - } catch (error) { - jsonRes(res, { - code: 500, - error - }); - } -} diff --git a/projects/app/src/pages/api/admin/initv445.ts b/projects/app/src/pages/api/admin/initv445.ts new file mode 100644 index 000000000..322a7a470 --- /dev/null +++ b/projects/app/src/pages/api/admin/initv445.ts @@ -0,0 +1,104 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/service/response'; +import { authUser } from '@/service/utils/auth'; +import { connectToDatabase, App } from '@/service/mongo'; +import { FlowInputItemTypeEnum, FlowModuleTypeEnum } from '@/constants/flow'; +import { SystemInputEnum } from '@/constants/app'; + +const limit = 300; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + await connectToDatabase(); + await authUser({ req, authRoot: true }); + + const totalApps = await App.countDocuments(); + + // init app + await App.updateMany({}, { $set: { inited: false } }); + + for (let i = 0; i < totalApps; i += limit) { + await initVariable(); + console.log(i + limit); + } + + jsonRes(res, { + data: { + total: totalApps + } + }); + } catch (error) { + jsonRes(res, { + code: 500, + error + }); + } +} + +async function initVariable(): Promise { + try { + const apps = await App.find({ inited: false }).limit(limit); + await Promise.all( + apps.map(async (app) => { + const jsonAPP = app.toObject(); + // @ts-ignore + app.inited = true; + const modules = jsonAPP.modules; + + // 找到 variable + const variable = modules.find((item) => item.flowType === FlowModuleTypeEnum.variable); + if (!variable) return await app.save(); + + // 找到 guide 模块 + const userGuideModule = modules.find( + (item) => item.flowType === FlowModuleTypeEnum.userGuide + ); + if (userGuideModule) { + userGuideModule.inputs = [ + userGuideModule.inputs[0], + { + key: SystemInputEnum.variables, + type: FlowInputItemTypeEnum.systemInput, + label: '对话框变量', + value: variable.inputs[0]?.value + } + ]; + } else { + modules.unshift({ + moduleId: 'userGuide', + flowType: FlowModuleTypeEnum.userGuide, + name: '用户引导', + position: { + x: 447.98520778293346, + y: 721.4016845336229 + }, + inputs: [ + { + key: SystemInputEnum.welcomeText, + type: FlowInputItemTypeEnum.input, + label: '开场白' + }, + { + key: SystemInputEnum.variables, + type: FlowInputItemTypeEnum.systemInput, + label: '对话框变量', + value: variable.inputs[0]?.value + } + ], + outputs: [] + }); + } + + jsonAPP.modules = jsonAPP.modules.filter( + (item) => item.flowType !== FlowModuleTypeEnum.variable + ); + + app.modules = JSON.parse(JSON.stringify(jsonAPP.modules)); + + await app.save(); + }) + ); + } catch (error) { + return initVariable(); + } +} diff --git a/projects/app/src/pages/api/chat/init.ts b/projects/app/src/pages/api/chat/init.ts index 523ca2b18..82107adc9 100644 --- a/projects/app/src/pages/api/chat/init.ts +++ b/projects/app/src/pages/api/chat/init.ts @@ -6,7 +6,7 @@ import { authUser } from '@/service/utils/auth'; import { ChatItemType } from '@/types/chat'; import { authApp } from '@/service/utils/auth'; import type { ChatSchema } from '@/types/mongoSchema'; -import { getSpecialModule, getChatModelNameList } from '@/components/ChatBox/utils'; +import { getGuideModules, getChatModelNameList } from '@/components/ChatBox/utils'; import { TaskResponseKeyEnum } from '@/constants/chat'; /* 初始化我的聊天框,需要身份验证 */ @@ -81,7 +81,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) chatId, appId, app: { - ...getSpecialModule(app.modules), + ...getGuideModules(app.modules), chatModels: getChatModelNameList(app.modules), name: app.name, avatar: app.avatar, diff --git a/projects/app/src/pages/api/core/dataset/file/markUsed.ts b/projects/app/src/pages/api/core/dataset/file/markUsed.ts index bd4eba028..f3800d616 100644 --- a/projects/app/src/pages/api/core/dataset/file/markUsed.ts +++ b/projects/app/src/pages/api/core/dataset/file/markUsed.ts @@ -18,7 +18,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< await collection.updateMany( { - _id: { $in: fileIds.map((id) => new Types.ObjectId(id)) }, + _id: { $in: fileIds.filter((id) => !!id).map((id) => new Types.ObjectId(id)) }, ['metadata.userId']: userId }, { diff --git a/projects/app/src/pages/api/openapi/plugin/vector.ts b/projects/app/src/pages/api/openapi/plugin/vector.ts index ee903dbbf..e0d06ee24 100644 --- a/projects/app/src/pages/api/openapi/plugin/vector.ts +++ b/projects/app/src/pages/api/openapi/plugin/vector.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { authBalanceByUid, authUser } from '@/service/utils/auth'; import { withNextCors } from '@/service/utils/tools'; -import { getAIChatApi, axiosConfig } from '@/service/lib/openai'; +import { getAIChatApi, axiosConfig } from '@fastgpt/core/aiApi/config'; import { pushGenerateVectorBill } from '@/service/common/bill/push'; type Props = { diff --git a/projects/app/src/pages/api/openapi/v1/chat/completions.ts b/projects/app/src/pages/api/openapi/v1/chat/completions.ts index 6fe3fdd8c..205f935d0 100644 --- a/projects/app/src/pages/api/openapi/v1/chat/completions.ts +++ b/projects/app/src/pages/api/openapi/v1/chat/completions.ts @@ -14,12 +14,14 @@ import { dispatchContentExtract, dispatchHttpRequest } from '@/service/moduleDispatch'; -import type { CreateChatCompletionRequest } from 'openai'; +import type { + CreateChatCompletionRequest, + ChatCompletionRequestMessage +} from '@fastgpt/core/aiApi/type'; import { gptMessage2ChatType, textAdaptGptResponse } from '@/utils/adapt'; import { getChatHistory } from './getHistory'; import { saveChat } from '@/service/utils/chat/saveChat'; import { sseResponse } from '@/service/utils/tools'; -import { type ChatCompletionRequestMessage } from 'openai'; import { TaskResponseKeyEnum } from '@/constants/chat'; import { FlowModuleTypeEnum, initModuleType } from '@/constants/flow'; import { AppModuleItemType, RunningModuleItemType } from '@/types/app'; diff --git a/projects/app/src/pages/api/support/outLink/init.ts b/projects/app/src/pages/api/support/outLink/init.ts index 482d926f1..b98d6797e 100644 --- a/projects/app/src/pages/api/support/outLink/init.ts +++ b/projects/app/src/pages/api/support/outLink/init.ts @@ -4,7 +4,7 @@ import { connectToDatabase, OutLink, User } from '@/service/mongo'; import type { InitShareChatResponse } from '@/api/response/chat'; import { authApp } from '@/service/utils/auth'; import { HUMAN_ICON } from '@/constants/chat'; -import { getChatModelNameList, getSpecialModule } from '@/components/ChatBox/utils'; +import { getChatModelNameList, getGuideModules } from '@/components/ChatBox/utils'; import { authShareChatInit } from '@/service/support/outLink/auth'; /* init share chat window */ @@ -46,7 +46,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) data: { userAvatar: user?.avatar || HUMAN_ICON, app: { - ...getSpecialModule(app.modules), + ...getGuideModules(app.modules), chatModels: getChatModelNameList(app.modules), name: app.name, avatar: app.avatar, diff --git a/projects/app/src/pages/api/user/account/update.ts b/projects/app/src/pages/api/user/account/update.ts index aa9fd76d6..5718ee814 100644 --- a/projects/app/src/pages/api/user/account/update.ts +++ b/projects/app/src/pages/api/user/account/update.ts @@ -5,7 +5,7 @@ import { User } from '@/service/models/user'; import { connectToDatabase } from '@/service/mongo'; import { authUser } from '@/service/utils/auth'; import { UserUpdateParams } from '@/types/user'; -import { axiosConfig, getAIChatApi, openaiBaseUrl } from '@/service/lib/openai'; +import { axiosConfig, getAIChatApi, openaiBaseUrl } from '@fastgpt/core/aiApi/config'; /* update user info */ export default async function handler(req: NextApiRequest, res: NextApiResponse) { @@ -34,7 +34,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< ...axiosConfig(openaiAccount) } ); - if (!response?.data?.choices?.[0]?.message?.content) { + if (response?.data?.choices?.[0]?.message?.content === undefined) { throw new Error(JSON.stringify(response?.data)); } } diff --git a/projects/app/src/pages/app/detail/components/AdEdit/components/ChatTest.tsx b/projects/app/src/pages/app/detail/components/AdEdit/components/ChatTest.tsx index c43691b96..f3f43abc1 100644 --- a/projects/app/src/pages/app/detail/components/AdEdit/components/ChatTest.tsx +++ b/projects/app/src/pages/app/detail/components/AdEdit/components/ChatTest.tsx @@ -15,7 +15,7 @@ import { streamFetch } from '@/api/fetch'; import MyTooltip from '@/components/MyTooltip'; import { useUserStore } from '@/store/user'; import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox'; -import { getSpecialModule } from '@/components/ChatBox/utils'; +import { getGuideModules } from '@/components/ChatBox/utils'; export type ChatTestComponentRef = { resetChatTest: () => void; @@ -114,7 +114,7 @@ const ChatTest = ( appAvatar={app.avatar} userAvatar={userInfo?.avatar} showMarkIcon - {...getSpecialModule(modules)} + {...getGuideModules(modules)} onStartChat={startChat} onDelMessage={() => {}} /> diff --git a/projects/app/src/pages/app/detail/components/AdEdit/components/Nodes/NodeUserGuide.tsx b/projects/app/src/pages/app/detail/components/AdEdit/components/Nodes/NodeUserGuide.tsx index efc367ecb..b95e05ba4 100644 --- a/projects/app/src/pages/app/detail/components/AdEdit/components/Nodes/NodeUserGuide.tsx +++ b/projects/app/src/pages/app/detail/components/AdEdit/components/Nodes/NodeUserGuide.tsx @@ -1,17 +1,49 @@ -import React, { useMemo } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { NodeProps } from 'reactflow'; -import { Box, Flex, Textarea } from '@chakra-ui/react'; +import { + Box, + Flex, + Textarea, + Button, + Table, + Thead, + Tbody, + Tr, + Th, + Td, + TableContainer +} from '@chakra-ui/react'; import { QuestionOutlineIcon } from '@chakra-ui/icons'; -import NodeCard from '../modules/NodeCard'; import { FlowModuleItemType } from '@/types/flow'; -import Container from '../modules/Container'; import { SystemInputEnum } from '@/constants/app'; +import { welcomeTextTip, variableTip } from '@/constants/flow/ModuleTemplate'; + +import VariableEditModal, { addVariable } from '../../../VariableEditModal'; import MyIcon from '@/components/Icon'; import MyTooltip from '@/components/MyTooltip'; -import { welcomeTextTip } from '@/constants/flow/ModuleTemplate'; +import Container from '../modules/Container'; +import NodeCard from '../modules/NodeCard'; +import { VariableItemType } from '@/types/app'; const NodeUserGuide = ({ data }: NodeProps) => { + return ( + <> + + + + + + + + + + ); +}; +export default React.memo(NodeUserGuide); + +export function WelcomeText({ data }: { data: FlowModuleItemType }) { const { inputs, moduleId, onChangeNode } = data; + const welcomeText = useMemo( () => inputs.find((item) => item.key === SystemInputEnum.welcomeText), [inputs] @@ -19,41 +51,148 @@ const NodeUserGuide = ({ data }: NodeProps) => { return ( <> - - - <> - - - 开场白 - - - - - {welcomeText && ( -