From d6e90d4b5abeebaae77f97c7f2d7d27d1945ff8f Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Fri, 23 Feb 2024 17:49:16 +0800 Subject: [PATCH] sub plan page (#23) * fix chunk index; error page text * feat: dataset process Integral prediction * feat: stand plan field * feat: sub plan limit * perf: index * query extension * perf: share link push app name * perf: plan point unit * perf: get sub plan * perf: account page --- packages/global/common/error/code/team.ts | 62 -- .../module/template/system/queryExtension.ts | 64 ++ packages/global/support/user/constant.ts | 28 - packages/service/core/dataset/search/utils.ts | 85 --- packages/service/support/outLink/tools.ts | 53 -- .../service/support/user/team/teamSchema.ts | 71 --- projects/app/next.config.js | 127 ---- projects/app/public/docs/versionIntro.md | 46 -- projects/app/src/components/Layout/index.tsx | 2 + .../app/src/components/Markdown/index.tsx | 162 ----- .../wallet/StandardPlanContentList.tsx | 128 ---- .../src/global/support/wallet/constants.ts | 1 - projects/app/src/pages/_error.tsx | 48 -- .../pages/account/components/BillTable.tsx | 3 +- .../src/pages/account/components/InfoOld.tsx | 439 ++++++++++++++ .../src/pages/account/components/InforNew.tsx | 551 ------------------ projects/app/src/pages/api/core/app/create.ts | 135 ----- .../src/pages/api/core/chat/clearHistories.ts | 77 --- .../src/pages/api/core/chat/updateHistory.ts | 32 - .../app/src/pages/api/core/dataset/create.ts | 60 -- .../pages/api/core/dataset/data/pushData.ts | 63 -- .../user/team/limit/datasetSizeLimit.ts | 36 -- .../Import/commonProgress/DataProcess.tsx | 347 ----------- .../moduleDispatch/tools/queryExternsion.ts | 77 +++ .../support/permission/auth/teamChat.ts | 6 +- .../service/support/permission/teamLimit.ts | 102 ++++ projects/app/src/web/common/api/fetch.ts | 236 -------- projects/app/src/web/core/app/templates.ts | 392 ------------- .../app/src/web/support/wallet/sub/api.ts | 16 - 29 files changed, 688 insertions(+), 2761 deletions(-) delete mode 100644 packages/global/common/error/code/team.ts create mode 100644 packages/global/core/module/template/system/queryExtension.ts delete mode 100644 packages/service/core/dataset/search/utils.ts delete mode 100644 packages/service/support/outLink/tools.ts delete mode 100644 packages/service/support/user/team/teamSchema.ts delete mode 100644 projects/app/next.config.js delete mode 100644 projects/app/public/docs/versionIntro.md delete mode 100644 projects/app/src/components/Markdown/index.tsx delete mode 100644 projects/app/src/components/support/wallet/StandardPlanContentList.tsx delete mode 100644 projects/app/src/global/support/wallet/constants.ts delete mode 100644 projects/app/src/pages/_error.tsx create mode 100644 projects/app/src/pages/account/components/InfoOld.tsx delete mode 100644 projects/app/src/pages/account/components/InforNew.tsx delete mode 100644 projects/app/src/pages/api/core/app/create.ts delete mode 100644 projects/app/src/pages/api/core/chat/clearHistories.ts delete mode 100644 projects/app/src/pages/api/core/chat/updateHistory.ts delete mode 100644 projects/app/src/pages/api/core/dataset/create.ts delete mode 100644 projects/app/src/pages/api/core/dataset/data/pushData.ts delete mode 100644 projects/app/src/pages/api/support/user/team/limit/datasetSizeLimit.ts delete mode 100644 projects/app/src/pages/dataset/detail/components/Import/commonProgress/DataProcess.tsx create mode 100644 projects/app/src/service/moduleDispatch/tools/queryExternsion.ts create mode 100644 projects/app/src/service/support/permission/teamLimit.ts delete mode 100644 projects/app/src/web/common/api/fetch.ts delete mode 100644 projects/app/src/web/core/app/templates.ts delete mode 100644 projects/app/src/web/support/wallet/sub/api.ts diff --git a/packages/global/common/error/code/team.ts b/packages/global/common/error/code/team.ts deleted file mode 100644 index f404afe1a88a..000000000000 --- a/packages/global/common/error/code/team.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { ErrType } from '../errorCode'; -import { i18nT } from '../../../../web/i18n/utils'; -/* team: 500000 */ -export enum TeamErrEnum { - teamOverSize = 'teamOverSize', - unAuthTeam = 'unAuthTeam', - aiPointsNotEnough = 'aiPointsNotEnough', - datasetSizeNotEnough = 'datasetSizeNotEnough', - datasetAmountNotEnough = 'datasetAmountNotEnough', - appAmountNotEnough = 'appAmountNotEnough', - pluginAmountNotEnough = 'pluginAmountNotEnough', - websiteSyncNotEnough = 'websiteSyncNotEnough', - reRankNotEnough = 'reRankNotEnough' -} - -const teamErr = [ - { - statusText: TeamErrEnum.teamOverSize, - message: i18nT('common:code_error.team_error.over_size') - }, - { statusText: TeamErrEnum.unAuthTeam, message: i18nT('common:code_error.team_error.un_auth') }, - { - statusText: TeamErrEnum.aiPointsNotEnough, - message: i18nT('common:code_error.team_error.ai_points_not_enough') - }, // 需要定义或留空 - { - statusText: TeamErrEnum.datasetSizeNotEnough, - message: i18nT('common:code_error.team_error.dataset_size_not_enough') - }, - { - statusText: TeamErrEnum.datasetAmountNotEnough, - message: i18nT('common:code_error.team_error.dataset_amount_not_enough') - }, - { - statusText: TeamErrEnum.appAmountNotEnough, - message: i18nT('common:code_error.team_error.app_amount_not_enough') - }, - { - statusText: TeamErrEnum.pluginAmountNotEnough, - message: i18nT('common:code_error.team_error.plugin_amount_not_enough') - }, - { - statusText: TeamErrEnum.websiteSyncNotEnough, - message: i18nT('common:code_error.team_error.website_sync_not_enough') - }, - { - statusText: TeamErrEnum.reRankNotEnough, - message: i18nT('common:code_error.team_error.re_rank_not_enough') - } -]; - -export default teamErr.reduce((acc, cur, index) => { - return { - ...acc, - [cur.statusText]: { - code: 500000 + index, - statusText: cur.statusText, - message: cur.message, - data: null - } - }; -}, {} as ErrType<`${TeamErrEnum}`>); diff --git a/packages/global/core/module/template/system/queryExtension.ts b/packages/global/core/module/template/system/queryExtension.ts new file mode 100644 index 000000000000..dc598190fdda --- /dev/null +++ b/packages/global/core/module/template/system/queryExtension.ts @@ -0,0 +1,64 @@ +import { + FlowNodeInputTypeEnum, + FlowNodeOutputTypeEnum, + FlowNodeTypeEnum +} from '../../node/constant'; +import { FlowModuleTemplateType } from '../../type'; +import { + ModuleIOValueTypeEnum, + ModuleInputKeyEnum, + ModuleOutputKeyEnum, + ModuleTemplateTypeEnum +} from '../../constants'; +import { + Input_Template_History, + Input_Template_Switch, + Input_Template_UserChatInput +} from '../input'; +import { Output_Template_UserChatInput } from '../output'; + +export const AiQueryExtension: FlowModuleTemplateType = { + id: FlowNodeTypeEnum.chatNode, + templateType: ModuleTemplateTypeEnum.other, + flowType: FlowNodeTypeEnum.queryExtension, + avatar: '/imgs/module/cfr.svg', + name: 'core.module.template.Query extension', + intro: 'core.module.template.Query extension intro', + showStatus: true, + inputs: [ + Input_Template_Switch, + { + key: ModuleInputKeyEnum.aiModel, + type: FlowNodeInputTypeEnum.selectLLMModel, + label: 'core.module.input.label.aiModel', + required: true, + valueType: ModuleIOValueTypeEnum.string, + showTargetInApp: false, + showTargetInPlugin: false + }, + { + key: ModuleInputKeyEnum.aiSystemPrompt, + type: FlowNodeInputTypeEnum.textarea, + label: 'core.app.edit.Query extension background prompt', + max: 300, + valueType: ModuleIOValueTypeEnum.string, + description: 'core.app.edit.Query extension background tip', + placeholder: 'core.module.QueryExtension.placeholder', + showTargetInApp: true, + showTargetInPlugin: true + }, + Input_Template_History, + Input_Template_UserChatInput + ], + outputs: [ + Output_Template_UserChatInput, + { + key: ModuleOutputKeyEnum.text, + label: 'core.module.output.label.query extension result', + description: 'core.module.output.description.query extension result', + valueType: ModuleIOValueTypeEnum.string, + type: FlowNodeOutputTypeEnum.source, + targets: [] + } + ] +}; diff --git a/packages/global/support/user/constant.ts b/packages/global/support/user/constant.ts index 3b157e7de553..332090a6a246 100644 --- a/packages/global/support/user/constant.ts +++ b/packages/global/support/user/constant.ts @@ -1,4 +1,3 @@ -import { StandardSubLevelEnum } from "../wallet/sub/constants" export enum UserStatusEnum { active = 'active', forbidden = 'forbidden' @@ -17,30 +16,3 @@ export enum OAuthEnum { google = 'google', wechat = 'wechat' } - -export const standardInfoMap = { - [StandardSubLevelEnum.free]: { - maxTeamNum: '1', - maxAppNum: '1', - maxPreservation: 7, - other: ['10 万积分≈40 次对话 = 2 元'] - }, - [StandardSubLevelEnum.experience]: { - maxTeamNum: '5', - maxAppNum: '5', - maxPreservation: 30, - other: ['200 万积分 ≈ 800 次对话', '优先训练功能', '24 h/次 web 站点同步', '24 h/次 导出知识库 ', '重排优先级(选不同卡) '] - }, - [StandardSubLevelEnum.team]: { - maxTeamNum: '10', - maxAppNum: '10', - maxPreservation: 90, - other: ['1500 万积分 ≈ 6000 次对话', '中级优先训练功能', '个人 key(不扣积分)', '自定义版权 logo,title,分享链接去水印 ', '12 h/次 web 站点同步 ', '12 h/次 导出知识库 ', '高级重排优先级(选不同卡) '] - }, - [StandardSubLevelEnum.enterprise]: { - maxTeamNum: '50', - maxAppNum: '50', - maxPreservation: 360, - other: ['5000 万积分 ≈ 20000 次对话 ', '高级优先训练功能', '个人 key(不扣积分)', '自定义版权 logo,title,分享链接去水印 ', '6 h/次 web 站点同步', '6 h/次 导出知识库 ', '高级重排优先级(选不同卡) '] - }, -} \ No newline at end of file diff --git a/packages/service/core/dataset/search/utils.ts b/packages/service/core/dataset/search/utils.ts deleted file mode 100644 index e0c1abcab521..000000000000 --- a/packages/service/core/dataset/search/utils.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d'; -import { queryExtension } from '../../ai/functions/queryExtension'; -import { ChatItemType } from '@fastgpt/global/core/chat/type'; -import { hashStr } from '@fastgpt/global/common/string/tools'; -import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt'; - -export const datasetSearchQueryExtension = async ({ - query, - extensionModel, - extensionBg = '', - histories = [] -}: { - query: string; - extensionModel?: LLMModelItemType; - extensionBg?: string; - histories?: ChatItemType[]; -}) => { - const filterSamQuery = (queries: string[]) => { - const set = new Set(); - const filterSameQueries = queries.filter((item) => { - // 删除所有的标点符号与空格等,只对文本进行比较 - const str = hashStr(item.replace(/[^\p{L}\p{N}]/gu, '')); - if (set.has(str)) return false; - set.add(str); - return true; - }); - - return filterSameQueries; - }; - - let { queries, rewriteQuery, alreadyExtension } = (() => { - // concat query - let rewriteQuery = - histories.length > 0 - ? `${histories - .map((item) => { - return `${item.obj}: ${chatValue2RuntimePrompt(item.value).text}`; - }) - .join('\n')} -Human: ${query} -` - : query; - - /* if query already extension, direct parse */ - try { - const jsonParse = JSON.parse(query); - const queries: string[] = Array.isArray(jsonParse) ? filterSamQuery(jsonParse) : [query]; - const alreadyExtension = Array.isArray(jsonParse); - return { - queries, - rewriteQuery: alreadyExtension ? queries.join('\n') : rewriteQuery, - alreadyExtension: alreadyExtension - }; - } catch (error) { - return { - queries: [query], - rewriteQuery, - alreadyExtension: false - }; - } - })(); - - // ai extension - const aiExtensionResult = await (async () => { - if (!extensionModel || alreadyExtension) return; - const result = await queryExtension({ - chatBg: extensionBg, - query, - histories, - model: extensionModel.model - }); - if (result.extensionQueries?.length === 0) return; - return result; - })(); - if (aiExtensionResult) { - queries = filterSamQuery(queries.concat(aiExtensionResult.extensionQueries)); - rewriteQuery = queries.join('\n'); - } - - return { - concatQueries: queries, - rewriteQuery, - aiExtensionResult - }; -}; diff --git a/packages/service/support/outLink/tools.ts b/packages/service/support/outLink/tools.ts deleted file mode 100644 index ce337ff5339f..000000000000 --- a/packages/service/support/outLink/tools.ts +++ /dev/null @@ -1,53 +0,0 @@ -import axios from 'axios'; -import { MongoOutLink } from './schema'; -import { FastGPTProUrl } from '../../common/system/constants'; -import { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type'; - -export const addOutLinkUsage = async ({ - shareId, - totalPoints -}: { - shareId: string; - totalPoints: number; -}) => { - MongoOutLink.findOneAndUpdate( - { shareId }, - { - $inc: { usagePoints: totalPoints }, - lastTime: new Date() - } - ).catch((err) => { - console.log('update shareChat error', err); - }); -}; - -export const pushResult2Remote = async ({ - outLinkUid, - shareId, - appName, - flowResponses -}: { - outLinkUid?: string; // raw id, not parse - shareId?: string; - appName: string; - flowResponses?: ChatHistoryItemResType[]; -}) => { - if (!shareId || !outLinkUid || !FastGPTProUrl) return; - try { - const outLink = await MongoOutLink.findOne({ - shareId - }); - if (!outLink?.limit?.hookUrl) return; - - axios({ - method: 'post', - baseURL: outLink.limit.hookUrl, - url: '/shareAuth/finish', - data: { - token: outLinkUid, - appName, - responseData: flowResponses - } - }); - } catch (error) {} -}; diff --git a/packages/service/support/user/team/teamSchema.ts b/packages/service/support/user/team/teamSchema.ts deleted file mode 100644 index 590320b9be20..000000000000 --- a/packages/service/support/user/team/teamSchema.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { connectionMongo, getMongoModel } from '../../../common/mongo'; -const { Schema } = connectionMongo; -import { TeamSchema as TeamType } from '@fastgpt/global/support/user/team/type.d'; -import { userCollectionName } from '../../user/schema'; -import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant'; -import { TeamDefaultPermissionVal } from '@fastgpt/global/support/permission/user/constant'; - -const TeamSchema = new Schema({ - name: { - type: String, - required: true - }, - ownerId: { - type: Schema.Types.ObjectId, - ref: userCollectionName - }, - defaultPermission: { - type: Number, - default: TeamDefaultPermissionVal - }, - avatar: { - type: String, - default: '/icon/logo.svg' - }, - createTime: { - type: Date, - default: () => Date.now() - }, - balance: { - type: Number, - default: 0 - }, - teamDomain: { - type: String - }, - tagsUrl: { - type: String, - }, - limit: { - lastExportDatasetTime: { - type: Date - }, - lastWebsiteSyncTime: { - type: Date - } - }, - lafAccount: { - token: { - type: String - }, - appid: { - type: String - }, - pat: { - type: String - } - }, - notificationAccount: { - type: String, - required: false - } -}); - -try { - TeamSchema.index({ name: 1 }); - TeamSchema.index({ ownerId: 1 }); -} catch (error) { - console.log(error); -} - -export const MongoTeam = getMongoModel(TeamCollectionName, TeamSchema); diff --git a/projects/app/next.config.js b/projects/app/next.config.js deleted file mode 100644 index 1e455e044a26..000000000000 --- a/projects/app/next.config.js +++ /dev/null @@ -1,127 +0,0 @@ -const { i18n } = require('./next-i18next.config'); -const path = require('path'); -const fs = require('fs'); - -const isDev = process.env.NODE_ENV === 'development'; - -/** @type {import('next').NextConfig} */ -const nextConfig = { - i18n, - output: 'standalone', - reactStrictMode: isDev ? false : true, - compress: true, - webpack(config, { isServer, nextRuntime }) { - Object.assign(config.resolve.alias, { - '@mongodb-js/zstd': false, - '@aws-sdk/credential-providers': false, - snappy: false, - aws4: false, - 'mongodb-client-encryption': false, - kerberos: false, - 'supports-color': false, - 'bson-ext': false, - 'pg-native': false - }); - config.module = { - ...config.module, - rules: config.module.rules.concat([ - { - test: /\.svg$/i, - issuer: /\.[jt]sx?$/, - use: ['@svgr/webpack'] - }, - { - test: /\.node$/, - use: [{ loader: 'nextjs-node-loader' }] - } - ]), - exprContextCritical: false, - unknownContextCritical: false - }; - - if (!config.externals) { - config.externals = []; - } - - if (isServer) { - // config.externals.push('@zilliz/milvus2-sdk-node'); - - if (nextRuntime === 'nodejs') { - const oldEntry = config.entry; - config = { - ...config, - async entry(...args) { - const entries = await oldEntry(...args); - return { - ...entries, - ...getWorkerConfig(), - 'worker/systemPluginRun': path.resolve( - process.cwd(), - '../../packages/plugins/runtime/worker.ts' - ) - }; - } - }; - } - } else { - config.resolve = { - ...config.resolve, - fallback: { - ...config.resolve.fallback, - fs: false - } - }; - } - - config.experiments = { - asyncWebAssembly: true, - layers: true - }; - - return config; - }, - transpilePackages: ['@fastgpt/*', 'ahooks'], - experimental: { - // 优化 Server Components 的构建和运行,避免不必要的客户端打包。 - serverComponentsExternalPackages: ['mongoose', 'pg', '@node-rs/jieba', 'duck-duck-scrape'], - outputFileTracingRoot: path.join(__dirname, '../../') - } -}; - -module.exports = nextConfig; - -function getWorkerConfig() { - const result = fs.readdirSync(path.resolve(__dirname, '../../packages/service/worker')); - - // 获取所有的目录名 - const folderList = result.filter((item) => { - return fs - .statSync(path.resolve(__dirname, '../../packages/service/worker', item)) - .isDirectory(); - }); - - /* - { - 'worker/htmlStr2Md': path.resolve( - process.cwd(), - '../../packages/service/worker/htmlStr2Md/index.ts' - ), - 'worker/countGptMessagesTokens': path.resolve( - process.cwd(), - '../../packages/service/worker/countGptMessagesTokens/index.ts' - ), - 'worker/readFile': path.resolve( - process.cwd(), - '../../packages/service/worker/readFile/index.ts' - ) - } - */ - const workerConfig = folderList.reduce((acc, item) => { - acc[`worker/${item}`] = path.resolve( - process.cwd(), - `../../packages/service/worker/${item}/index.ts` - ); - return acc; - }, {}); - return workerConfig; -} diff --git a/projects/app/public/docs/versionIntro.md b/projects/app/public/docs/versionIntro.md deleted file mode 100644 index 970a11e8680f..000000000000 --- a/projects/app/public/docs/versionIntro.md +++ /dev/null @@ -1,46 +0,0 @@ -### FastGPT V4.8.9 - -#### 新功能说明 - -1. **文件上传** - -支持在简易模式和工作流中上传文档,目前版本,主要以上传文档总结为主,如果需要通过工作流编排实现类似于内容提取、文档对比之类的功能,需要配合代码运行去使用。 - -- 在系统配置中可以开启文件上传,对话框中即可上传文件。文件包括文档和图片;是否可上传图片,不再依赖视觉模型决定,而是通过系统配置决定。 -- 简易模式下,会通过工具调用,由模型决定是否读取文档,所以尽可能选择支持工具调用的模型。 -- 工作流模式下,可以通过文档解析节点,手动获取解析结果进行后续流程。 - -| | | -| --------------------------------------------------------- | --------------------------------------------------------- | -| ![](https://oss.laf.run/otnvvf-imgs/4.8.9/1280X1280.PNG) | ![](https://oss.laf.run/otnvvf-imgs/4.8.9/1280X12802.PNG) | -| ![](https://oss.laf.run/otnvvf-imgs/4.8.9/1280X12806.PNG) | ![](https://oss.laf.run/otnvvf-imgs/4.8.9/1280X12801.PNG) | - -2. **AI 对话模型,启用视觉模型** - -之前有反馈,工作流中所有模型都会强制使用视觉模式,浪费了资源,目前可以手动关闭。开启后会自动获取对话框上传的图片和“用户问题”中的图片链接。 - -![](https://oss.laf.run/otnvvf-imgs/4.8.9/1280X12803.PNG) - -3. **清空对话引导** - -![](https://oss.laf.run/otnvvf-imgs/4.8.9/1280X12804.PNG) - -#### 优化说明 - -1. 优化 - 对话框懒加载。 -2. 优化 - i18n 翻译。 -3. 优化 - 减少工具调用结果的存储,不再实际存储完整响应,避免超出存储限制。 -4. 优化 - QA 拆分支持自定义 chunk 大小,并优化 gpt4o-mini 拆分时,chunk 太大导致生成内容很少的问题。 - -#### 问题修复 - -1. 修复 - 删除应用后回到聊天选择最后一次对话的应用为删除的应用时提示无该应用问题。 -2. 修复 - 插件运行获取历史记录后无法更新到页面。 -3. 修复 - 插件默认值无法正常显示。 -4. 修复 - 工具调用温度和最大回复值未生效。 -5. 修复 - 知识库文件上传进度更新可能异常。 -6. 修复 - 知识库 rebuilding 时候,页面总是刷新到第一页。 -7. 修复 - 函数调用模式,assistant role 中,GPT 模型必须传入 content 参数。(不影响大部分模型,目前基本都改用用 ToolChoice 模式,FC 模式已弃用)。 -8. 修复 - docs: Repair and supplement document content xinference.md。 -9. 修复 - 知识库列表右下角类型的名称上下居中。 -10. 修复 - 知识库 list openapi 鉴权问题。 diff --git a/projects/app/src/components/Layout/index.tsx b/projects/app/src/components/Layout/index.tsx index 1fca86121bad..8117bf7a1373 100644 --- a/projects/app/src/components/Layout/index.tsx +++ b/projects/app/src/components/Layout/index.tsx @@ -97,6 +97,8 @@ const Layout = ({ children }: { children: JSX.Element }) => { )} )} + + {!!userInfo && } {feConfigs?.isPlus && ( <> diff --git a/projects/app/src/components/Markdown/index.tsx b/projects/app/src/components/Markdown/index.tsx deleted file mode 100644 index f308fc4e0316..000000000000 --- a/projects/app/src/components/Markdown/index.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import React, { useMemo } from 'react'; -import ReactMarkdown from 'react-markdown'; -import 'katex/dist/katex.min.css'; -import RemarkMath from 'remark-math'; // Math syntax -import RemarkBreaks from 'remark-breaks'; // Line break -import RehypeKatex from 'rehype-katex'; // Math render -import RemarkGfm from 'remark-gfm'; // Special markdown syntax -import RehypeExternalLinks from 'rehype-external-links'; - -import styles from './index.module.scss'; -import dynamic from 'next/dynamic'; - -import { Link, Button } from '@chakra-ui/react'; -import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; -import { useTranslation } from 'next-i18next'; -import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus'; -import MyIcon from '@fastgpt/web/components/common/Icon'; -import { MARKDOWN_QUOTE_SIGN } from '@fastgpt/global/core/chat/constants'; -import { CodeClassNameEnum } from './utils'; - -const CodeLight = dynamic(() => import('./CodeLight'), { ssr: false }); -const MermaidCodeBlock = dynamic(() => import('./img/MermaidCodeBlock'), { ssr: false }); -const MdImage = dynamic(() => import('./img/Image'), { ssr: false }); -const EChartsCodeBlock = dynamic(() => import('./img/EChartsCodeBlock'), { ssr: false }); - -const ChatGuide = dynamic(() => import('./chat/Guide'), { ssr: false }); -const QuestionGuide = dynamic(() => import('./chat/QuestionGuide'), { ssr: false }); - -const Markdown = ({ - source = '', - showAnimation = false -}: { - source?: string; - showAnimation?: boolean; -}) => { - const components = useMemo( - () => ({ - img: Image, - pre: RewritePre, - p: (pProps: any) =>

, - code: Code, - a: A - }), - [] - ); - - const formatSource = useMemo(() => { - const formatSource = source - .replace(/(http[s]?:\/\/[^\s,。]+)([。,])/g, '$1 $2') // Follow the link with a space - .replace(/\n*(\[QUOTE SIGN\]\(.*\))/g, '$1'); - - return formatSource; - }, [source]); - - return ( - - {formatSource} - - ); -}; - -export default React.memo(Markdown); - -/* Custom dom */ -const Code = React.memo(function Code(e: any) { - const { className, codeBlock, children } = e; - const match = /language-(\w+)/.exec(className || ''); - const codeType = match?.[1]; - - const strChildren = String(children); - - const Component = useMemo(() => { - if (codeType === CodeClassNameEnum.mermaid) { - return ; - } - if (codeType === CodeClassNameEnum.guide) { - return ; - } - if (codeType === CodeClassNameEnum.questionGuide) { - return ; - } - if (codeType === CodeClassNameEnum.echarts) { - return ; - } - - return ( - - {children} - - ); - }, [codeType, className, codeBlock, match, children, strChildren]); - - return Component; -}); -const Image = React.memo(function Image({ src }: { src?: string }) { - return ; -}); -const A = React.memo(function A({ children, ...props }: any) { - const { t } = useTranslation(); - - // empty href link - if (!props.href && typeof children?.[0] === 'string') { - const text = useMemo(() => String(children), [children]); - - return ( - - - - ); - } - - // quote link(未使用) - if (children?.length === 1 && typeof children?.[0] === 'string') { - const text = String(children); - if (text === MARKDOWN_QUOTE_SIGN && props.href) { - return ( - - getCollectionSourceAndOpen(props.href)} - /> - - ); - } - } - - return {children}; -}); - -function RewritePre({ children }: any) { - const modifiedChildren = React.Children.map(children, (child) => { - if (React.isValidElement(child)) { - // @ts-ignore - return React.cloneElement(child, { codeBlock: true }); - } - return child; - }); - - return <>{modifiedChildren}; -} diff --git a/projects/app/src/components/support/wallet/StandardPlanContentList.tsx b/projects/app/src/components/support/wallet/StandardPlanContentList.tsx deleted file mode 100644 index 314e7b5cb35e..000000000000 --- a/projects/app/src/components/support/wallet/StandardPlanContentList.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import { useSystemStore } from '@/web/common/system/useSystemStore'; -import { StandardSubLevelEnum, SubModeEnum } from '@fastgpt/global/support/wallet/sub/constants'; -import React, { useMemo } from 'react'; -import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants'; -import { Box, Flex, Grid } from '@chakra-ui/react'; -import MyIcon from '@fastgpt/web/components/common/Icon'; -import { useTranslation } from 'next-i18next'; -import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; -import { useRouter } from 'next/router'; -import { AI_POINT_USAGE_CARD_ROUTE } from '@/web/support/wallet/sub/constants'; -import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; - -const StandardPlanContentList = ({ - level, - mode -}: { - level: `${StandardSubLevelEnum}`; - mode: `${SubModeEnum}`; -}) => { - const { t } = useTranslation(); - const { subPlans } = useSystemStore(); - const router = useRouter(); - - const planContent = useMemo(() => { - const plan = subPlans?.standard?.[level]; - if (!plan) return; - return { - price: plan.price * (mode === SubModeEnum.month ? 1 : 10), - level: level as `${StandardSubLevelEnum}`, - ...standardSubLevelMap[level as `${StandardSubLevelEnum}`], - maxTeamMember: plan.maxTeamMember, - maxAppAmount: plan.maxAppAmount, - maxDatasetAmount: plan.maxDatasetAmount, - chatHistoryStoreDuration: plan.chatHistoryStoreDuration, - maxDatasetSize: plan.maxDatasetSize, - permissionCustomApiKey: plan.permissionCustomApiKey, - permissionCustomCopyright: plan.permissionCustomCopyright, - trainingWeight: plan.trainingWeight, - permissionReRank: plan.permissionReRank, - totalPoints: plan.totalPoints * (mode === SubModeEnum.month ? 1 : 12), - permissionWebsiteSync: plan.permissionWebsiteSync - }; - }, [subPlans?.standard, level, mode]); - - return planContent ? ( - - - - - {t('support.wallet.subscription.function.Max members', { - amount: planContent.maxTeamMember - })} - - - - - - {t('support.wallet.subscription.function.Max app', { - amount: planContent.maxAppAmount - })} - - - - - - {t('support.wallet.subscription.function.Max dataset', { - amount: planContent.maxDatasetAmount - })} - - - - - - {t('support.wallet.subscription.function.History store', { - amount: planContent.chatHistoryStoreDuration - })} - - - - - - {t('support.wallet.subscription.function.Max dataset size', { - amount: planContent.maxDatasetSize - })} - - - - - - - {t('support.wallet.subscription.function.Points', { - amount: planContent.totalPoints - })} - - { - router.push(AI_POINT_USAGE_CARD_ROUTE); - }} - > - - - - - - {t('support.wallet.subscription.Training weight', { - weight: planContent.trainingWeight - })} - - - {!!planContent.permissionReRank && ( - - - {t('chat:rearrangement')} - - )} - {!!planContent.permissionWebsiteSync && ( - - - {t('chat:web_site_sync')} - - )} - - ) : null; -}; - -export default StandardPlanContentList; diff --git a/projects/app/src/global/support/wallet/constants.ts b/projects/app/src/global/support/wallet/constants.ts deleted file mode 100644 index 761fd5124a63..000000000000 --- a/projects/app/src/global/support/wallet/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const AI_POINT_USAGE_CARD_ROUTE = '/price#point-card'; diff --git a/projects/app/src/pages/_error.tsx b/projects/app/src/pages/_error.tsx deleted file mode 100644 index bbaae955a39c..000000000000 --- a/projects/app/src/pages/_error.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { useEffect } from 'react'; -import { useRouter } from 'next/router'; -import { serviceSideProps } from '@/web/common/utils/i18n'; -import { useSystemStore } from '@/web/common/system/useSystemStore'; -import { Box } from '@chakra-ui/react'; -import { TrackEventName } from '@/web/common/system/constants'; - -function Error() { - const router = useRouter(); - const { lastRoute } = useSystemStore(); - - useEffect(() => { - setTimeout(() => { - window.umami?.track(TrackEventName.pageError, { - userAgent: navigator.userAgent, - platform: navigator.platform, - appName: navigator.appName, - lastRoute, - route: router.asPath - }); - }, 1000); - - setTimeout(() => { - router.back(); - }, 2000); - }, []); - - return ( - - {`出现未捕获的异常。 -1. 私有部署用户,90%由于配置文件不正确导致。 -2. 部分系统不兼容相关API。大部分是苹果的safari 浏览器导致,可以尝试更换 chrome。 -3. 请关闭浏览器翻译功能,部分翻译导致页面崩溃。 - -排除3后,打开控制台的 console 查看具体报错信息。 -如果提示 xxx undefined 的话,就是配置文件有错误。 -`} - - ); -} - -export async function getServerSideProps(context: any) { - return { - props: { ...(await serviceSideProps(context)) } - }; -} - -export default Error; diff --git a/projects/app/src/pages/account/components/BillTable.tsx b/projects/app/src/pages/account/components/BillTable.tsx index 27b228f22ad7..eb382a95261c 100644 --- a/projects/app/src/pages/account/components/BillTable.tsx +++ b/projects/app/src/pages/account/components/BillTable.tsx @@ -31,7 +31,6 @@ import MyBox from '@/components/common/MyBox'; import { useRequest } from '@/web/common/hooks/useRequest'; import MyModal from '@/components/MyModal'; import { standardSubLevelMap, subModeMap } from '@fastgpt/global/support/wallet/sub/constants'; -import { formatNumber2Million } from '@fastgpt/global/common/math/tools'; const BillTable = () => { const { t } = useTranslation(); @@ -233,7 +232,7 @@ function BillDetailModal({ bill, onClose }: { bill: BillSchemaType; onClose: () {bill.metadata?.extraPoints !== undefined && ( {t('support.wallet.subscription.Extra ai points')}: - {formatNumber2Million(bill.metadata.extraPoints)}百万 + {bill.metadata.extraPoints} )} diff --git a/projects/app/src/pages/account/components/InfoOld.tsx b/projects/app/src/pages/account/components/InfoOld.tsx new file mode 100644 index 000000000000..83e16173f82e --- /dev/null +++ b/projects/app/src/pages/account/components/InfoOld.tsx @@ -0,0 +1,439 @@ +import React, { useCallback, useMemo, useRef } from 'react'; +import { + Box, + Flex, + Button, + useDisclosure, + useTheme, + Divider, + Select, + Input, + Link, + Progress +} from '@chakra-ui/react'; +import { useForm } from 'react-hook-form'; +import { UserUpdateParams } from '@/types/user'; +import { useToast } from '@fastgpt/web/hooks/useToast'; +import { useUserStore } from '@/web/support/user/useUserStore'; +import type { UserType } from '@fastgpt/global/support/user/type.d'; +import { useQuery } from '@tanstack/react-query'; +import dynamic from 'next/dynamic'; +import { useSelectFile } from '@/web/common/file/hooks/useSelectFile'; +import { compressImgFileAndUpload } from '@/web/common/file/controller'; +import { useSystemStore } from '@/web/common/system/useSystemStore'; +import { useTranslation } from 'next-i18next'; +import { timezoneList } from '@fastgpt/global/common/time/timezone'; +import Avatar from '@/components/Avatar'; +import MyIcon from '@fastgpt/web/components/common/Icon'; +import MyTooltip from '@/components/MyTooltip'; +import { langMap, setLngStore } from '@/web/common/utils/i18n'; +import { useRouter } from 'next/router'; +import MySelect from '@/components/Select'; +import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools'; +import { putUpdateMemberName } from '@/web/support/user/team/api'; +import { getDocPath } from '@/web/common/system/doc'; +import { getTeamPlanStatus } from '@/web/support/wallet/sub/api'; +import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants'; + +const TeamMenu = dynamic(() => import('@/components/support/user/team/TeamMenu')); +const PayModal = dynamic(() => import('./PayModal')); +const UpdatePswModal = dynamic(() => import('./UpdatePswModal')); +const OpenAIAccountModal = dynamic(() => import('./OpenAIAccountModal')); + +const UserInfo = () => { + const theme = useTheme(); + const router = useRouter(); + const { feConfigs, systemVersion } = useSystemStore(); + const { t, i18n } = useTranslation(); + const { userInfo, updateUserInfo, initUserInfo } = useUserStore(); + const timezones = useRef(timezoneList()); + const { reset } = useForm({ + defaultValues: userInfo as UserType + }); + + const { toast } = useToast(); + const { + isOpen: isOpenPayModal, + onClose: onClosePayModal, + onOpen: onOpenPayModal + } = useDisclosure(); + const { + isOpen: isOpenUpdatePsw, + onClose: onCloseUpdatePsw, + onOpen: onOpenUpdatePsw + } = useDisclosure(); + const { isOpen: isOpenOpenai, onClose: onCloseOpenai, onOpen: onOpenOpenai } = useDisclosure(); + + const { File, onOpen: onOpenSelectFile } = useSelectFile({ + fileType: '.jpg,.png', + multiple: false + }); + + const onclickSave = useCallback( + async (data: UserType) => { + await updateUserInfo({ + avatar: data.avatar, + timezone: data.timezone, + openaiAccount: data.openaiAccount + }); + reset(data); + toast({ + title: '更新数据成功', + status: 'success' + }); + }, + [reset, toast, updateUserInfo] + ); + + const onSelectFile = useCallback( + async (e: File[]) => { + const file = e[0]; + if (!file || !userInfo) return; + try { + const src = await compressImgFileAndUpload({ + type: MongoImageTypeEnum.userAvatar, + file, + maxW: 300, + maxH: 300 + }); + + onclickSave({ + ...userInfo, + avatar: src + }); + } catch (err: any) { + toast({ + title: typeof err === 'string' ? err : t('common.error.Select avatar failed'), + status: 'warning' + }); + } + }, + [onclickSave, t, toast, userInfo] + ); + + useQuery(['init'], initUserInfo, { + onSuccess(res) { + reset(res); + } + }); + + const { + data: teamSubPlan = { + totalPoints: 0, + usedPoints: 0, + datasetMaxSize: 800, + usedDatasetSize: 0 + } + } = useQuery(['getTeamPlanStatus'], getTeamPlanStatus); + const datasetUsageMap = useMemo(() => { + const rate = teamSubPlan.usedDatasetSize / teamSubPlan.datasetMaxSize; + + const colorScheme = (() => { + if (rate < 0.5) return 'green'; + if (rate < 0.8) return 'yellow'; + return 'red'; + })(); + + return { + colorScheme, + value: rate * 100, + maxSize: teamSubPlan.datasetMaxSize || t('common.Unlimited'), + usedSize: teamSubPlan.usedDatasetSize + }; + }, [teamSubPlan.usedDatasetSize, teamSubPlan.datasetMaxSize, t]); + const aiPointsUsageMap = useMemo(() => { + const rate = teamSubPlan.usedPoints / teamSubPlan.totalPoints; + + const colorScheme = (() => { + if (rate < 0.5) return 'green'; + if (rate < 0.8) return 'yellow'; + return 'red'; + })(); + + return { + colorScheme, + value: rate * 100, + maxSize: teamSubPlan.totalPoints || t('common.Unlimited'), + usedSize: teamSubPlan.usedPoints + }; + }, [teamSubPlan.usedPoints, teamSubPlan.totalPoints, t]); + + return ( + + + + + + + + + + + {t('user.Replace')} + + + + {feConfigs.isPlus && ( + + {t('user.Member Name')}:  + { + const val = e.target.value; + if (val === userInfo?.team?.memberName) return; + try { + putUpdateMemberName(val); + } catch (error) {} + }} + /> + + )} + + {t('user.Account')}:  + {userInfo?.username} + + + {t('user.Team')}:  + + + + + + {t('user.Language')}:  + + ({ + label: lang.label, + value: key + }))} + onchange={(val: any) => { + const lang = val; + setLngStore(lang); + router.replace(router.basePath, router.asPath, { locale: lang }); + }} + /> + + + + {t('user.Timezone')}:  + + + + {t('user.Password')}:  + ***** + + + {feConfigs.isPlus && ( + <> + + + + {t('user.team.Balance')}:  + + + {formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)} 元 + + {feConfigs?.show_pay && userInfo?.team?.canWrite && ( + + )} + + + {feConfigs?.show_pay && ( + <> + + + + {t('support.user.team.Dataset usage')}: {datasetUsageMap.usedSize}/ + {datasetUsageMap.maxSize} + + {userInfo?.team?.canWrite && ( + + )} + + + + + + + + + AI积分: {Math.round(teamSubPlan.usedPoints)}/{teamSubPlan.totalPoints} + + + + + + + + )} + + )} + + {feConfigs?.docUrl && ( + + + + {t('system.Help Document')} + + + + V{systemVersion} + + + )} + {feConfigs?.chatbotUrl && ( + + + + {t('common.system.Help Chatbot')} + + + )} + {feConfigs?.show_openai_account && ( + <> + + + + + + + OpenAI/OneAPI 账号 + + + + + + )} + + + {isOpenPayModal && } + {isOpenUpdatePsw && } + {isOpenOpenai && userInfo && ( + + onclickSave({ + ...userInfo, + openaiAccount: data + }) + } + onClose={onCloseOpenai} + /> + )} + + + ); +}; + +export default React.memo(UserInfo); diff --git a/projects/app/src/pages/account/components/InforNew.tsx b/projects/app/src/pages/account/components/InforNew.tsx deleted file mode 100644 index 47b131b96833..000000000000 --- a/projects/app/src/pages/account/components/InforNew.tsx +++ /dev/null @@ -1,551 +0,0 @@ -import React, { useCallback, useMemo, useRef, useState } from 'react'; -import { - Box, - Flex, - Button, - useDisclosure, - useTheme, - Text, - Spacer, - Stack, - Divider, - Select, - Input, - Link, - Progress -} from '@chakra-ui/react'; -import { useForm } from 'react-hook-form'; -import { UserUpdateParams } from '@/types/user'; -import { useToast } from '@fastgpt/web/hooks/useToast'; -import { useUserStore } from '@/web/support/user/useUserStore'; -import type { UserType } from '@fastgpt/global/support/user/type.d'; -import { FeTeamSubType, TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type'; -import { standardInfoMap } from '@fastgpt/global/support/user/constant'; -import { useQuery } from '@tanstack/react-query'; -import dynamic from 'next/dynamic'; -import { useSelectFile } from '@/web/common/file/hooks/useSelectFile'; -import { compressImgFileAndUpload } from '@/web/common/file/controller'; -import { useSystemStore } from '@/web/common/system/useSystemStore'; -import { useTranslation } from 'next-i18next'; -import { timezoneList } from '@fastgpt/global/common/time/timezone'; -import Avatar from '@/components/Avatar'; -import MyIcon from '@fastgpt/web/components/common/Icon'; -import MyTooltip from '@/components/MyTooltip'; -import { langMap, setLngStore } from '@/web/common/utils/i18n'; -import { useRouter } from 'next/router'; -import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools'; -import { putUpdateMemberName } from '@/web/support/user/team/api'; -import { getDocPath } from '@/web/common/system/doc'; -import { getTeamDatasetValidSub } from '@/web/support/wallet/sub/api'; -import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants'; -const StandDetailModal = dynamic(() => import('./standardDetailModal')); -const TeamMenu = dynamic(() => import('@/components/support/user/team/TeamMenu')); -const PayModal = dynamic(() => import('./PayModal')); -const UpdatePswModal = dynamic(() => import('./UpdatePswModal')); -const OpenAIAccountModal = dynamic(() => import('./OpenAIAccountModal')); -const SubDatasetModal = dynamic(() => import('@/components/support/wallet/QRCodePayModal')); - -const UserInfo = () => { - const theme = useTheme(); - const router = useRouter(); - const { feConfigs, systemVersion } = useSystemStore(); - const { t, i18n } = useTranslation(); - const { userInfo, updateUserInfo, setUserInfo, initUserInfo } = useUserStore(); - const [standardInfo, setStandardInfo] = useState(); - const timezones = useRef(timezoneList()); - const { reset } = useForm({ - defaultValues: userInfo as UserType - }); - const IconList = { - baseInfor: { - icon: 'acount/cube', - label: t('user.Personal Information'), - id: null - } - }; - - const { toast } = useToast(); - const { - isOpen: isOpenPayModal, - onClose: onClosePayModal, - onOpen: onOpenPayModal - } = useDisclosure(); - const { - isOpen: isOpenUpdatePsw, - onClose: onCloseUpdatePsw, - onOpen: onOpenUpdatePsw - } = useDisclosure(); - const { - isOpen: isOpenStandardModal, - onClose: onCloseStandardModal, - onOpen: onOpenStandardModal - } = useDisclosure(); - const { isOpen: isOpenOpenai, onClose: onCloseOpenai, onOpen: onOpenOpenai } = useDisclosure(); - const { File, onOpen: onOpenSelectFile } = useSelectFile({ - fileType: '.jpg,.png', - multiple: false - }); - - const onclickSave = useCallback( - async (data: UserType) => { - await updateUserInfo({ - avatar: data.avatar, - timezone: data.timezone, - openaiAccount: data.openaiAccount - }); - reset(data); - toast({ - title: '更新数据成功', - status: 'success' - }); - }, - [reset, toast, updateUserInfo] - ); - - const onSelectFile = useCallback( - async (e: File[]) => { - const file = e[0]; - if (!file || !userInfo) return; - try { - const src = await compressImgFileAndUpload({ - type: MongoImageTypeEnum.userAvatar, - file, - maxW: 300, - maxH: 300 - }); - - onclickSave({ - ...userInfo, - avatar: src - }); - } catch (err: any) { - toast({ - title: typeof err === 'string' ? err : t('common.error.Select avatar failed'), - status: 'warning' - }); - } - }, - [onclickSave, t, toast, userInfo] - ); - - useQuery(['init'], initUserInfo, { - onSuccess(res) { - reset(res); - } - }); - - const { - data: teamSubPlan = { totalPoints: 0, usedPoints: 0, datasetMaxSize: 800, usedDatasetSize: 0 } - } = useQuery(['getTeamDatasetValidSub'], async () => { - const res = await getTeamDatasetValidSub(); - if (res) { - const { - standard = { currentSubLevel: 'free', expiredTime: new Date() }, - datasetMaxSize = 0, - standardMaxDatasetSize = 0, - standardMaxPoints = 0, - totalPoints = 0, - usedDatasetSize = 0, - usedPoints = 0 - } = res; - - setStandardInfo({ - standard: standard as TeamSubSchema, - datasetMaxSize: datasetMaxSize, - standardMaxDatasetSize: standardMaxDatasetSize, - standardMaxPoints: standardMaxPoints, - totalPoints: totalPoints, - usedDatasetSize: usedDatasetSize, - usedPoints: usedPoints - }); - return res; - } - }); - const datasetUsageMap = useMemo(() => { - const rate = teamSubPlan.usedDatasetSize / teamSubPlan.datasetMaxSize; - - const colorScheme = (() => { - if (rate < 0.5) return 'green'; - if (rate < 0.8) return 'yellow'; - return 'red'; - })(); - - return { - colorScheme, - value: rate * 100, - maxSize: teamSubPlan.datasetMaxSize || t('common.Unlimited'), - usedSize: teamSubPlan.usedDatasetSize - }; - }, [teamSubPlan.usedDatasetSize, teamSubPlan.datasetMaxSize, t]); - - return ( - - - - 个人信息 - - - - - - - - - - - - {t('user.Replace')} - - - - - - {feConfigs.isPlus && ( - - - {t('user.Member Name')}:  - - { - const val = e.target.value; - if (val === userInfo?.team?.memberName) return; - try { - putUpdateMemberName(val); - } catch (error) {} - }} - /> - - )} - - - {t('user.Account')}:  - - {userInfo?.username} - - - - {t('user.Password')}:  - - ***** - - - - - - - {t('user.Team')}:  - - - - - - {feConfigs.isPlus && ( - <> - - - - {t('user.team.Balance')}:  - - - {formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)}{' '} - 元 - - {feConfigs?.show_pay && userInfo?.team?.canWrite && ( - - )} - - - - )} - - - - - - 套餐与用量 - - - - - - - - 当前套餐 - - - {'免费套餐'} - - - {'过期时间: ' + standardInfo?.standard?.expiredTime} - - - - - - - {standardInfo?.standard?.currentSubLevel && - standardInfoMap[ - standardInfo.standard?.currentSubLevel as keyof typeof standardInfoMap - ].maxTeamNum + '个成员'} - - - - {standardInfo?.standard?.currentSubLevel && - standardInfoMap[ - standardInfo.standard?.currentSubLevel as keyof typeof standardInfoMap - ]?.maxAppNum + '个应用插件'} - - - - {standardInfo?.standardMaxPoints + '个知识库'} - - - - {standardInfo?.standard?.currentSubLevel && - standardInfoMap[ - standardInfo.standard?.currentSubLevel as keyof typeof standardInfoMap - ]?.maxPreservation + '天历史记录保持'} - - - - {standardInfo?.datasetMaxSize + '个向量存储'} - - {standardInfo?.standard?.currentSubLevel && - standardInfoMap[ - standardInfo.standard?.currentSubLevel as keyof typeof standardInfoMap - ]?.other.map((item: string, index: number) => { - return ( - - - {item} - - ); - })} - - - - - - - 知识库存储 - - {standardInfo?.usedDatasetSize + ' / ' + standardInfo?.standardMaxPoints + ' 组'} - - - - - 购买额外存储 - - - - - - - - - - - - AI 积分 - - {standardInfo?.usedDatasetSize + - ' / ' + - standardInfo?.standardMaxPoints + - ' 积分'} - - - - - 购买额外积分 - - - - - - - - - - - - - - 其它 - - - {feConfigs?.docUrl && ( - - - - {t('system.Help Document')} - - - - V{systemVersion} - - - )} - - - - {t('common.system.Help Chatbot')} - - - - {feConfigs?.show_openai_account && ( - - - - OpenAI/OneAPI 账号 - - - - )} - - - {isOpenPayModal && } - {isOpenUpdatePsw && } - {isOpenOpenai && userInfo && ( - - onclickSave({ - ...userInfo, - openaiAccount: data - }) - } - onClose={onCloseOpenai} - /> - )} - {isOpenStandardModal && } - - - ); -}; - -export default React.memo(UserInfo); diff --git a/projects/app/src/pages/api/core/app/create.ts b/projects/app/src/pages/api/core/app/create.ts deleted file mode 100644 index 623fcd18034e..000000000000 --- a/projects/app/src/pages/api/core/app/create.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { AppFolderTypeList, AppTypeEnum } from '@fastgpt/global/core/app/constants'; -import { MongoApp } from '@fastgpt/service/core/app/schema'; -import { authUserPer } from '@fastgpt/service/support/permission/user/auth'; -import { checkTeamAppLimit } from '@fastgpt/service/support/permission/teamLimit'; -import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun'; -import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema'; -import { NextAPI } from '@/service/middleware/entry'; -import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; -import type { AppSchema } from '@fastgpt/global/core/app/type'; -import { ApiRequestProps } from '@fastgpt/service/type/next'; -import type { ParentIdType } from '@fastgpt/global/common/parentFolder/type'; -import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils'; -import { defaultNodeVersion } from '@fastgpt/global/core/workflow/node/constant'; -import { ClientSession } from '@fastgpt/service/common/mongo'; -import { authApp } from '@fastgpt/service/support/permission/app/auth'; -import { CommonErrEnum } from '@fastgpt/global/common/error/code/common'; - -export type CreateAppBody = { - parentId?: ParentIdType; - name?: string; - avatar?: string; - type?: AppTypeEnum; - modules: AppSchema['modules']; - edges?: AppSchema['edges']; - chatConfig?: AppSchema['chatConfig']; -}; - -async function handler(req: ApiRequestProps) { - const { parentId, name, avatar, type, modules, edges, chatConfig } = req.body; - - if (!name || !type || !Array.isArray(modules)) { - return Promise.reject(CommonErrEnum.inheritPermissionError); - } - - // 凭证校验 - const { teamId, tmbId } = await authUserPer({ req, authToken: true, per: WritePermissionVal }); - if (parentId) { - // if it is not a root app - // check the parent folder permission - await authApp({ req, appId: parentId, per: WritePermissionVal, authToken: true }); - } - - // 上限校验 - await checkTeamAppLimit(teamId); - - // 创建app - const appId = await onCreateApp({ - parentId, - name, - avatar, - type, - modules, - edges, - chatConfig, - teamId, - tmbId - }); - - return appId; -} - -export default NextAPI(handler); - -export const onCreateApp = async ({ - parentId, - name, - intro, - avatar, - type, - modules, - edges, - chatConfig, - teamId, - tmbId, - pluginData, - session -}: { - parentId?: ParentIdType; - name?: string; - avatar?: string; - type?: AppTypeEnum; - modules?: AppSchema['modules']; - edges?: AppSchema['edges']; - chatConfig?: AppSchema['chatConfig']; - intro?: string; - teamId: string; - tmbId: string; - pluginData?: AppSchema['pluginData']; - session?: ClientSession; -}) => { - const create = async (session: ClientSession) => { - const [{ _id: appId }] = await MongoApp.create( - [ - { - ...parseParentIdInMongo(parentId), - avatar, - name, - intro, - teamId, - tmbId, - modules, - edges, - chatConfig, - type, - version: 'v2', - pluginData, - ...(type === AppTypeEnum.plugin && { 'pluginData.nodeVersion': defaultNodeVersion }) - } - ], - { session } - ); - - if (!AppFolderTypeList.includes(type!)) { - await MongoAppVersion.create( - [ - { - appId, - nodes: modules, - edges, - chatConfig - } - ], - { session } - ); - } - - return appId; - }; - - if (session) { - return create(session); - } else { - return await mongoSessionRun(create); - } -}; diff --git a/projects/app/src/pages/api/core/chat/clearHistories.ts b/projects/app/src/pages/api/core/chat/clearHistories.ts deleted file mode 100644 index acbc455f450d..000000000000 --- a/projects/app/src/pages/api/core/chat/clearHistories.ts +++ /dev/null @@ -1,77 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; -import { jsonRes } from '@fastgpt/service/common/response'; -import { authCert } from '@fastgpt/service/support/permission/auth/common'; -import { MongoChat } from '@fastgpt/service/core/chat/chatSchema'; -import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema'; -import { ClearHistoriesProps } from '@/global/core/chat/api'; -import { authOutLink } from '@/service/support/permission/auth/outLink'; -import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants'; -import { authTeamSpaceToken } from '@/service/support/permission/auth/team'; -import { NextAPI } from '@/service/middleware/entry'; -import { deleteChatFiles } from '@fastgpt/service/core/chat/controller'; -import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun'; - -/* clear chat history */ -async function handler(req: NextApiRequest, res: NextApiResponse) { - const { appId, shareId, outLinkUid, teamId, teamToken } = req.query as ClearHistoriesProps; - - let chatAppId = appId!; - - const match = await (async () => { - if (shareId && outLinkUid) { - const { appId, uid } = await authOutLink({ shareId, outLinkUid }); - - chatAppId = appId; - return { - shareId, - outLinkUid: uid - }; - } - if (teamId && teamToken) { - const { uid } = await authTeamSpaceToken({ teamId, teamToken }); - return { - teamId, - appId, - outLinkUid: uid - }; - } - if (appId) { - const { tmbId } = await authCert({ req, authToken: true }); - - return { - tmbId, - appId, - source: ChatSourceEnum.online - }; - } - - return Promise.reject('Param are error'); - })(); - - // find chatIds - const list = await MongoChat.find(match, 'chatId').lean(); - const idList = list.map((item) => item.chatId); - - await deleteChatFiles({ chatIdList: idList }); - - await mongoSessionRun(async (session) => { - await MongoChatItem.deleteMany( - { - appId: chatAppId, - chatId: { $in: idList } - }, - { session } - ); - await MongoChat.deleteMany( - { - appId: chatAppId, - chatId: { $in: idList } - }, - { session } - ); - }); - - jsonRes(res); -} - -export default NextAPI(handler); diff --git a/projects/app/src/pages/api/core/chat/updateHistory.ts b/projects/app/src/pages/api/core/chat/updateHistory.ts deleted file mode 100644 index a5e23fb0b025..000000000000 --- a/projects/app/src/pages/api/core/chat/updateHistory.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; -import { jsonRes } from '@fastgpt/service/common/response'; -import { UpdateHistoryProps } from '@/global/core/chat/api.d'; -import { MongoChat } from '@fastgpt/service/core/chat/chatSchema'; -import { authChatCrud } from '@/service/support/permission/auth/chat'; -import { NextAPI } from '@/service/middleware/entry'; -import { ApiRequestProps } from '@fastgpt/service/type/next'; -import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; - -/* update chat top, custom title */ -async function handler(req: ApiRequestProps, res: NextApiResponse) { - const { appId, chatId, title, customTitle, top } = req.body; - await authChatCrud({ - req, - authToken: true, - ...req.body, - per: WritePermissionVal - }); - - await MongoChat.findOneAndUpdate( - { appId, chatId }, - { - updateTime: new Date(), - ...(title !== undefined && { title }), - ...(customTitle !== undefined && { customTitle }), - ...(top !== undefined && { top }) - } - ); - jsonRes(res); -} - -export default NextAPI(handler); diff --git a/projects/app/src/pages/api/core/dataset/create.ts b/projects/app/src/pages/api/core/dataset/create.ts deleted file mode 100644 index de00134f57e9..000000000000 --- a/projects/app/src/pages/api/core/dataset/create.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { MongoDataset } from '@fastgpt/service/core/dataset/schema'; -import type { CreateDatasetParams } from '@/global/core/dataset/api.d'; -import { authUserPer } from '@fastgpt/service/support/permission/user/auth'; -import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants'; -import { getLLMModel, getVectorModel, getDatasetModel } from '@fastgpt/service/core/ai/model'; -import { checkTeamDatasetLimit } from '@fastgpt/service/support/permission/teamLimit'; -import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; -import { NextAPI } from '@/service/middleware/entry'; -import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset'; -import type { ApiRequestProps } from '@fastgpt/service/type/next'; -import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils'; - -export type DatasetCreateQuery = {}; -export type DatasetCreateBody = CreateDatasetParams; -export type DatasetCreateResponse = string; - -async function handler( - req: ApiRequestProps -): Promise { - const { - parentId, - name, - type = DatasetTypeEnum.dataset, - avatar, - vectorModel = global.vectorModels[0].model, - agentModel = getDatasetModel().model - } = req.body; - - // auth - const { teamId, tmbId } = await authUserPer({ - req, - authToken: true, - authApiKey: true, - per: WritePermissionVal - }); - - // check model valid - const vectorModelStore = getVectorModel(vectorModel); - const agentModelStore = getLLMModel(agentModel); - if (!vectorModelStore || !agentModelStore) { - return Promise.reject(DatasetErrEnum.invalidVectorModelOrQAModel); - } - - // check limit - await checkTeamDatasetLimit(teamId); - - const { _id } = await MongoDataset.create({ - ...parseParentIdInMongo(parentId), - name, - teamId, - tmbId, - vectorModel, - agentModel, - avatar, - type - }); - - return _id; -} -export default NextAPI(handler); diff --git a/projects/app/src/pages/api/core/dataset/data/pushData.ts b/projects/app/src/pages/api/core/dataset/data/pushData.ts deleted file mode 100644 index 12947c969f36..000000000000 --- a/projects/app/src/pages/api/core/dataset/data/pushData.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* push data to training queue */ -import type { NextApiRequest, NextApiResponse } from 'next'; -import { jsonRes } from '@fastgpt/service/common/response'; -import type { - PushDatasetDataProps, - PushDatasetDataResponse -} from '@fastgpt/global/core/dataset/api.d'; -import { authDatasetCollection } from '@fastgpt/service/support/permission/dataset/auth'; -import { checkDatasetLimit } from '@fastgpt/service/support/permission/teamLimit'; -import { predictDataLimitLength } from '@fastgpt/global/core/dataset/utils'; -import { pushDataListToTrainingQueue } from '@fastgpt/service/core/dataset/training/controller'; -import { NextAPI } from '@/service/middleware/entry'; -import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; - -async function handler(req: NextApiRequest, res: NextApiResponse) { - const body = req.body as PushDatasetDataProps; - const { collectionId, data } = body; - - if (!collectionId || !Array.isArray(data)) { - throw new Error('collectionId or data is empty'); - } - - if (data.length > 200) { - throw new Error('Data is too long, max 200'); - } - - // 凭证校验 - const { teamId, tmbId, collection } = await authDatasetCollection({ - req, - authToken: true, - authApiKey: true, - collectionId, - per: WritePermissionVal - }); - - // auth dataset limit - await checkDatasetLimit({ - teamId, - insertLen: predictDataLimitLength(collection.trainingType, data) - }); - - jsonRes(res, { - data: await pushDataListToTrainingQueue({ - ...body, - teamId, - tmbId, - datasetId: collection.datasetId._id, - agentModel: collection.datasetId.agentModel, - vectorModel: collection.datasetId.vectorModel - }) - }); -} - -export default NextAPI(handler); - -export const config = { - api: { - bodyParser: { - sizeLimit: '10mb' - }, - responseLimit: '12mb' - } -}; diff --git a/projects/app/src/pages/api/support/user/team/limit/datasetSizeLimit.ts b/projects/app/src/pages/api/support/user/team/limit/datasetSizeLimit.ts deleted file mode 100644 index 4075be2e9b51..000000000000 --- a/projects/app/src/pages/api/support/user/team/limit/datasetSizeLimit.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; -import { jsonRes } from '@fastgpt/service/common/response'; -import { connectToDatabase } from '@/service/mongo'; -import { authCert } from '@fastgpt/service/support/permission/auth/common'; -import { checkDatasetLimit } from '@fastgpt/service/support/permission/teamLimit'; - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - try { - await connectToDatabase(); - const { size } = req.query as { - size: string; - }; - - // 凭证校验 - const { teamId } = await authCert({ req, authToken: true }); - - if (!size) { - return jsonRes(res); - } - - const numberSize = Number(size); - - await checkDatasetLimit({ - teamId, - insertLen: numberSize - }); - - jsonRes(res); - } catch (err) { - res.status(500); - jsonRes(res, { - code: 500, - error: err - }); - } -} diff --git a/projects/app/src/pages/dataset/detail/components/Import/commonProgress/DataProcess.tsx b/projects/app/src/pages/dataset/detail/components/Import/commonProgress/DataProcess.tsx deleted file mode 100644 index 2b20647d0086..000000000000 --- a/projects/app/src/pages/dataset/detail/components/Import/commonProgress/DataProcess.tsx +++ /dev/null @@ -1,347 +0,0 @@ -import React, { useCallback, useMemo, useRef, useState } from 'react'; -import { - Box, - Flex, - NumberInput, - NumberInputField, - NumberInputStepper, - NumberIncrementStepper, - NumberDecrementStepper, - Input, - Button, - ModalBody, - ModalFooter, - Textarea, - useDisclosure -} from '@chakra-ui/react'; -import MyIcon from '@fastgpt/web/components/common/Icon'; -import { useTranslation } from 'next-i18next'; -import LeftRadio from '@fastgpt/web/components/common/Radio/LeftRadio'; -import { TrainingModeEnum, TrainingTypeMap } from '@fastgpt/global/core/dataset/constants'; -import { ImportProcessWayEnum } from '@/web/core/dataset/constants'; -import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; -import { useSystemStore } from '@/web/common/system/useSystemStore'; -import MyModal from '@fastgpt/web/components/common/MyModal'; -import { Prompt_AgentQA } from '@fastgpt/global/core/ai/prompt/agent'; -import Preview from '../components/Preview'; -import MyTag from '@fastgpt/web/components/common/Tag/index'; -import { useContextSelector } from 'use-context-selector'; -import { DatasetImportContext } from '../Context'; -import { useToast } from '@fastgpt/web/hooks/useToast'; -import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; - -function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean }) { - const { t } = useTranslation(); - const { feConfigs } = useSystemStore(); - - const { - goToNext, - processParamsForm, - chunkSizeField, - minChunkSize, - showChunkInput, - showPromptInput, - maxChunkSize, - priceTip, - chunkSize - } = useContextSelector(DatasetImportContext, (v) => v); - const { getValues, setValue, register, watch } = processParamsForm; - const { toast } = useToast(); - const mode = watch('mode'); - const way = watch('way'); - - const { - isOpen: isOpenCustomPrompt, - onOpen: onOpenCustomPrompt, - onClose: onCloseCustomPrompt - } = useDisclosure(); - - const trainingModeList = useMemo(() => { - const list = Object.entries(TrainingTypeMap); - return list; - }, []); - - const onSelectTrainWay = useCallback( - (e: TrainingModeEnum) => { - if (!feConfigs?.isPlus && !TrainingTypeMap[e]?.openSource) { - return toast({ - status: 'warning', - title: t('common:common.system.Commercial version function') - }); - } - setValue('mode', e); - }, - [feConfigs?.isPlus, setValue, t, toast] - ); - - return ( - - - - - {t('common:core.dataset.import.Data process params')} - - - - {t('common:core.dataset.import.Training mode')} - ({ - title: t(value.label as any), - value: key, - tooltip: t(value.tooltip as any) - }))} - px={3} - py={2} - value={mode} - onChange={onSelectTrainWay} - defaultBg="white" - activeBg="white" - display={'flex'} - flexWrap={'wrap'} - /> - - - {t('common:core.dataset.import.Process way')} - - {showChunkInput && chunkSizeField && ( - - - {t('common:core.dataset.import.Ideal chunk length')} - - - - - span': { - display: 'block' - } - }} - > - - { - setValue(chunkSizeField, +e); - }} - > - - - - - - - - - - )} - - - - {t('common:core.dataset.import.Custom split char')} - - - - - - - - - - {showPromptInput && ( - - {t('common:core.dataset.collection.QA Prompt')} - - {getValues('qaPrompt')} - - - - - - - )} - - ) - } - ]} - px={3} - py={3} - defaultBg="white" - activeBg="white" - value={way} - w={'100%'} - onChange={(e) => { - setValue('way', e); - }} - > - - - {feConfigs?.show_pay && ( - - - {priceTip} - - - )} - - - - - - - - - - {isOpenCustomPrompt && ( - { - setValue('qaPrompt', e); - }} - onClose={onCloseCustomPrompt} - /> - )} - - ); -} - -export default React.memo(DataProcess); - -const PromptTextarea = ({ - defaultValue, - onChange, - onClose -}: { - defaultValue: string; - onChange: (e: string) => void; - onClose: () => void; -}) => { - const ref = useRef(null); - const { t } = useTranslation(); - - return ( - - -