Optimize the project structure and introduce DDD design (#394)

This commit is contained in:
Archer 2023-10-12 17:46:37 +08:00 committed by GitHub
parent 76ac5238b6
commit ad7a17bf40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
193 changed files with 1169 additions and 1084 deletions

View File

@ -13,18 +13,20 @@ weight: 20
## 商业版 ## 商业版
商业版最终交付版本功能与 https://fastgpt.run 完全一致,品牌内容可自定义。 商业版最终交付版本功能与 https://fastgpt.run 完全一致,品牌内容可自定义,商业授权时长同`License`有效期
{{% alert icon="🤖" context="warning" %}} {{% alert icon="🤖" context="warning" %}}
商业版与开源版功能差异:(目前计划) 商业版比开源版额外增加的内容:(目前计划)
1. 自定义 title 和 logo 1. 自定义 title 和 logo
2. 用户注册,支付 (已有微信扫码支付,后续会补充支付方式) 2. 用户注册,支付 (已有微信扫码支付,后续会补充支付方式)
3. API 访问限制,可配置:额度、过期时间 3. API 访问限制,可配置:额度、过期时间
4. 团队空间 (计划) 4. 分享链接限制可配置额度、过期时间、QPM、身份验证Hook
5. 完善的 OpenAPI计划 5. 内容审核(目前对接了百度)
6. 高级编排额外插件(计划) 6. 团队空间 (计划)
7. 后台管理系统 7. 完善的 OpenAPI计划
8. 高级编排额外插件(计划)
9. 后台管理系统
a. 查询:用户、支付、应用、知识库 a. 查询:用户、支付、应用、知识库
b. 变更:用户 b. 变更:用户
c. 新增:用户 c. 新增:用户
@ -36,7 +38,7 @@ weight: 20
+ 使用 [Sealos 公有云](https://sealos.io)部署1万元/年/套 (无部署费用。赠送 8000 sealos 公有云额度,可用于 FastGPT 或其他云资源)。 + 使用 [Sealos 公有云](https://sealos.io)部署1万元/年/套 (无部署费用。赠送 8000 sealos 公有云额度,可用于 FastGPT 或其他云资源)。
+ 渠道商使用 Sealos 部署:返现 20% 成交额。 + 渠道商使用 Sealos 部署:返现 20% 成交额。
+ 私有服务器部署2万元/年/套(如需部署支持,按技术服务费计算) + 私有服务器部署2万元/年/套
+ 渠道商私有服务器部署1.3万元/年/套(渠道商合同单独约谈,累计 5 套以上可签) + 渠道商私有服务器部署1.3万元/年/套(渠道商合同单独约谈,累计 5 套以上可签)
#### 用户注册数量费用(按注册量算,不计量分享和 API #### 用户注册数量费用(按注册量算,不计量分享和 API
@ -81,7 +83,7 @@ weight: 20
完整版应用 = 开源版镜像 + 商业版镜像 完整版应用 = 开源版镜像 + 商业版镜像
我们会提供一个商业版镜像给你使用,该镜像需要一个 license 启动license 有效期为 1 年。此外,还会提供一个简单的后台管理系统(目前只设置了简单的查询功能) 我们会提供一个商业版镜像给你使用,该镜像需要一个 License 启动License 有效期为 1 年。此外,还会提供一个简单的后台管理系统(目前只设置了简单的查询功能)
2. 二次开发如何操作? 2. 二次开发如何操作?

View File

@ -94,7 +94,16 @@ docker build -t dockername/fastgpt --build-arg name=app .
如果遇到问题,比如合并冲突或不知道如何打开拉取请求,请查看 GitHub 的[拉取请求教程](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests),了解如何解决合并冲突和其他问题。一旦您的 PR 被合并,您将自豪地被列为[贡献者表](https://github.com/labring/FastGPT/graphs/contributors)中的一员。 如果遇到问题,比如合并冲突或不知道如何打开拉取请求,请查看 GitHub 的[拉取请求教程](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests),了解如何解决合并冲突和其他问题。一旦您的 PR 被合并,您将自豪地被列为[贡献者表](https://github.com/labring/FastGPT/graphs/contributors)中的一员。
## 加入社区
## QA
### 本地数据库无法连接
1. 如果你是连接远程的数据库,先检查对应的端口是否开放。
2. 如果是本地运行的数据库,可尝试`host`改成`localhost``127.0.0.1`
### 加入社区
遇到困难了吗?有任何问题吗? 加入微信群与开发者和用户保持沟通。 遇到困难了吗?有任何问题吗? 加入微信群与开发者和用户保持沟通。

View File

@ -9,6 +9,8 @@ weight: 720
## 准备条件 ## 准备条件
服务器要求2C2G 起
### 1. 准备好代理环境(国外服务器可忽略) ### 1. 准备好代理环境(国外服务器可忽略)
确保可以访问 OpenAI具体方案可以参考[代理方案](/docs/installation/proxy/)。或直接在 Sealos 上 [部署 OneAPI](/docs/installation/one-api),既解决代理问题也能实现多 Key 轮询、接入其他大模型。 确保可以访问 OpenAI具体方案可以参考[代理方案](/docs/installation/proxy/)。或直接在 Sealos 上 [部署 OneAPI](/docs/installation/one-api),既解决代理问题也能实现多 Key 轮询、接入其他大模型。
@ -70,9 +72,9 @@ brew install orbstack
依次执行下面命令,创建 FastGPT 文件并拉取`docker-compose.yml``config.json`,执行完后目录下会有 2 个文件。 依次执行下面命令,创建 FastGPT 文件并拉取`docker-compose.yml``config.json`,执行完后目录下会有 2 个文件。
非 Linux 环境可手动创建目录并下载这2个文件。 非 Linux 环境或无法访问外网环境可手动创建一个目录并下载下面2个链接的文件。
**注意: 配置文件中 Mongo 为 5.x部分服务器不支持需手动更改其镜像版本为 4.4.24** **注意: `docker-compose.yml` 配置文件中 Mongo 为 5.x部分服务器不支持需手动更改其镜像版本为 4.4.24**
```bash ```bash
mkdir fastgpt mkdir fastgpt
@ -118,7 +120,12 @@ docker-compose up -d
1. `docker logs fastgpt` 可以查看日志,在启动容器后,第一次请求网页,会进行配置文件读取,可以看看有没有读取成功以及有无错误日志。 1. `docker logs fastgpt` 可以查看日志,在启动容器后,第一次请求网页,会进行配置文件读取,可以看看有没有读取成功以及有无错误日志。
2. `docker exec -it fastgpt sh` 进入 FastGPT 容器,可以通过`ls data`查看目录下是否成功挂载`config.json`文件。可通过`cat data/config.json`查看配置文件。 2. `docker exec -it fastgpt sh` 进入 FastGPT 容器,可以通过`ls data`查看目录下是否成功挂载`config.json`文件。可通过`cat data/config.json`查看配置文件。
### 为什么无法连接 oneapi 和 本地模型镜像。 **可能不生效的原因**
1. 挂载目录不正确
2. 配置文件不正确,日志中会提示`invalid json`,配置文件需要是标准的 JSON 文件。
### 为什么无法连接`本地模型`镜像。
`docker-compose.yml`中使用了桥接的模式建立了`fastgpt`网络如想通过0.0.0.0或镜像名访问其它镜像,需将其它镜像也加入到网络中。 `docker-compose.yml`中使用了桥接的模式建立了`fastgpt`网络如想通过0.0.0.0或镜像名访问其它镜像,需将其它镜像也加入到网络中。

View File

@ -242,7 +242,7 @@
"openapi": { "openapi": {
"app key tips": "These keys have the identification of the current application and can be used by external access.", "app key tips": "These keys have the identification of the current application and can be used by external access.",
"key alias": "Alias of key, for display only", "key alias": "Alias of key, for display only",
"key tips": "You can use API keys to access certain interfaces" "key tips": "You can use the API Key to access certain interfaces (you can't access the application, you need to use the API key within the application to access the application)."
}, },
"outlink": { "outlink": {
"Copy Iframe": "Copy Iframe", "Copy Iframe": "Copy Iframe",

View File

@ -242,7 +242,7 @@
"openapi": { "openapi": {
"app key tips": "这些 key 已有当前应用标识,具体使用可参考文档", "app key tips": "这些 key 已有当前应用标识,具体使用可参考文档",
"key alias": "key 的别名,仅用于展示", "key alias": "key 的别名,仅用于展示",
"key tips": "你可以使用 API 秘钥访问一些特定的接口" "key tips": "你可以使用 API 秘钥访问一些特定的接口(无法访问应用访问应用需使用应用内的API Key)"
}, },
"outlink": { "outlink": {
"Copy Iframe": "嵌入网页", "Copy Iframe": "嵌入网页",

View File

@ -1,5 +0,0 @@
import { GET, POST, PUT, DELETE } from '@/api/request';
import { CreateTrainingBillType } from './index.d';
export const postCreateTrainingBill = (data: CreateTrainingBillType) =>
POST<string>(`/common/bill/createTrainingBill`, data);

View File

@ -1,5 +0,0 @@
import { GET, POST, PUT, DELETE } from '@/api/request';
import { CreateQuestionGuideProps } from './type';
export const postQuestionGuide = (data: CreateQuestionGuideProps, cancelToken: AbortController) =>
POST<string[]>('/core/ai/agent/createQuestionGuide', data, { cancelToken });

View File

@ -1,28 +0,0 @@
import { KbTypeEnum } from '@/constants/dataset';
import type { RequestPaging } from '@/types';
import { TrainingModeEnum } from '@/constants/plugin';
import { DatasetDataItemType } from '@/types/core/dataset/data';
export type PushDataProps = {
kbId: string;
data: DatasetDataItemType[];
mode: `${TrainingModeEnum}`;
prompt?: string;
billId?: string;
};
export type PushDataResponse = {
insertLen: number;
};
export type UpdateDataPrams = {
dataId: string;
kbId: string;
a?: string;
q?: string;
};
export type GetDatasetDataListProps = RequestPaging & {
kbId: string;
searchText: string;
fileId: string;
};

View File

@ -1,72 +0,0 @@
import { GET, POST, PUT, DELETE } from '@/api/request';
import type { DatasetDataItemType } from '@/types/core/dataset/data';
import type {
PushDataProps,
PushDataResponse,
UpdateDataPrams,
GetDatasetDataListProps
} from './data.d';
import { QuoteItemType } from '@/types/chat';
import { getToken } from '@/utils/user';
import download from 'downloadjs';
/* kb data */
export const getDatasetDataList = (data: GetDatasetDataListProps) =>
POST(`/core/dataset/data/getDataList`, data);
/**
* export and download data
*/
export const exportDatasetData = (data: { kbId: string }) =>
fetch(`/api/core/dataset/data/exportAll?kbId=${data.kbId}`, {
method: 'GET',
headers: {
token: getToken()
}
})
.then(async (res) => {
if (!res.ok) {
const data = await res.json();
throw new Error(data?.message || 'Export failed');
}
return res.blob();
})
.then((blob) => download(blob, 'dataset.csv', 'text/csv'));
/**
*
*/
export const getTrainingData = (data: { kbId: string; init: boolean }) =>
POST<{
qaListLen: number;
vectorListLen: number;
}>(`/core/dataset/data/getTrainingData`, data);
/* get length of system training queue */
export const getTrainingQueueLen = () => GET<number>(`/core/dataset/data/getQueueLen`);
export const getDatasetDataItemById = (dataId: string) =>
GET<QuoteItemType>(`/core/dataset/data/getDataById`, { dataId });
/**
* push data to training queue
*/
export const postChunks2Dataset = (data: PushDataProps) =>
POST<PushDataResponse>(`/core/dataset/data/pushData`, data);
/**
* insert one data to dataset (immediately insert)
*/
export const postData2Dataset = (data: { kbId: string; data: DatasetDataItemType }) =>
POST<string>(`/core/dataset/data/insertData`, data);
/**
*
*/
export const putDatasetDataById = (data: UpdateDataPrams) =>
PUT('/core/dataset/data/updateData', data);
/**
*
*/
export const delOneDatasetDataById = (dataId: string) =>
DELETE(`/core/dataset/data/delDataById?dataId=${dataId}`);

View File

@ -1,10 +0,0 @@
import { RequestPaging } from '../../../types/index';
export type GetFileListProps = RequestPaging & {
kbId: string;
searchText: string;
};
export type UpdateFileProps = { id: string; name?: string; datasetUsed?: boolean };
export type MarkFileUsedProps = { fileIds: string[] };

View File

@ -1,19 +0,0 @@
import { GET, POST, PUT, DELETE } from '@/api/request';
import type { DatasetFileItemType } from '@/types/core/dataset/file';
import type { GSFileInfoType } from '@/types/common/file';
import type { GetFileListProps, UpdateFileProps, MarkFileUsedProps } from './file.d';
export const getDatasetFiles = (data: GetFileListProps) =>
POST<DatasetFileItemType[]>(`/core/dataset/file/list`, data);
export const delDatasetFileById = (params: { fileId: string; kbId: string }) =>
DELETE(`/core/dataset/file/delById`, params);
export const getFileInfoById = (fileId: string) =>
GET<GSFileInfoType>(`/core/dataset/file/detail`, { fileId });
export const delDatasetEmptyFiles = (kbId: string) =>
DELETE(`/core/dataset/file/delEmptyFiles`, { kbId });
export const updateDatasetFile = (data: UpdateFileProps) => PUT(`/core/dataset/file/update`, data);
export const putMarkFilesUsed = (data: MarkFileUsedProps) =>
PUT(`/core/dataset/file/markUsed`, data);

View File

@ -1,34 +0,0 @@
import { KbTypeEnum } from '@/constants/dataset';
import type { RequestPaging } from '@/types';
import { TrainingModeEnum } from '@/constants/plugin';
import type { SearchTestItemType } from '@/types/core/dataset';
export type DatasetUpdateParams = {
id: string;
parentId?: string;
tags?: string;
name?: string;
avatar?: string;
};
export type CreateDatasetParams = {
parentId?: string;
name: string;
tags: string[];
avatar: string;
vectorModel?: string;
type: `${KbTypeEnum}`;
};
export type DatasetUpdateParams = {
id: string;
parentId?: string;
tags?: string;
name?: string;
avatar?: string;
};
export type SearchTestProps = {
kbId: string;
text: string;
};
export type SearchTestResponseType = SearchTestItemType['results'];

View File

@ -1,32 +0,0 @@
import { GET, POST, PUT, DELETE } from '@/api/request';
import type { DatasetItemType, DatasetsItemType, DatasetPathItemType } from '@/types/core/dataset';
import type {
DatasetUpdateParams,
CreateDatasetParams,
SearchTestProps,
SearchTestResponseType
} from './index.d';
import { KbTypeEnum } from '@/constants/dataset';
export const getDatasets = (data: { parentId?: string; type?: `${KbTypeEnum}` }) =>
GET<DatasetsItemType[]>(`/core/dataset/list`, data);
/**
* get type=dataset list
*/
export const getAllDataset = () => GET<DatasetsItemType[]>(`/core/dataset/allDataset`);
export const getDatasetPaths = (parentId?: string) =>
GET<DatasetPathItemType[]>('/core/dataset/paths', { parentId });
export const getDatasetById = (id: string) => GET<DatasetItemType>(`/core/dataset/detail?id=${id}`);
export const postCreateDataset = (data: CreateDatasetParams) =>
POST<string>(`/core/dataset/create`, data);
export const putDatasetById = (data: DatasetUpdateParams) => PUT(`/core/dataset/update`, data);
export const delDatasetById = (id: string) => DELETE(`/core/dataset/delete?id=${id}`);
export const postSearchText = (data: SearchTestProps) =>
POST<SearchTestResponseType>(`/core/dataset/searchTest`, data);

View File

@ -1,6 +0,0 @@
import { GET, POST, PUT, DELETE } from '../request';
import type { FetchResultItem } from '@/types/plugin';
export const fetchUrls = (urlList: string[]) =>
POST<FetchResultItem[]>(`/plugins/urlFetch`, { urlList });

View File

@ -1,18 +0,0 @@
import { GET, POST } from '../request';
import { AxiosProgressEvent } from 'axios';
export const uploadImg = (base64Img: string) => POST<string>('/system/uploadImage', { base64Img });
export const postUploadFiles = (
data: FormData,
onUploadProgress: (progressEvent: AxiosProgressEvent) => void
) =>
POST<string[]>('/support/file/upload', data, {
onUploadProgress,
headers: {
'Content-Type': 'multipart/form-data; charset=utf-8'
}
});
export const getFileViewUrl = (fileId: string) => GET<string>('/support/file/readUrl', { fileId });

View File

@ -1,4 +0,0 @@
import { GET, POST, PUT } from './request';
import type { InitDateResponse } from '@/pages/api/system/getInitData';
export const getInitData = () => GET<InitDateResponse>('/system/getInitData');

View File

@ -1,9 +1,9 @@
import React, { useRef } from 'react'; import React, { useRef } from 'react';
import { ModalBody, Textarea, ModalFooter, Button } from '@chakra-ui/react'; import { ModalBody, Textarea, ModalFooter, Button } from '@chakra-ui/react';
import MyModal from '../MyModal'; import MyModal from '../MyModal';
import { useRequest } from '@/hooks/useRequest'; import { useRequest } from '@/web/common/hooks/useRequest';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { userUpdateChatFeedback } from '@/api/chat'; import { userUpdateChatFeedback } from '@/web/core/api/chat';
const FeedbackModal = ({ const FeedbackModal = ({
chatItemId, chatItemId,

View File

@ -1,8 +1,8 @@
import React, { useCallback, useMemo, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { ModalBody, Box, useTheme, Flex, Progress } from '@chakra-ui/react'; import { ModalBody, Box, useTheme, Flex, Progress } from '@chakra-ui/react';
import { getDatasetDataItemById } from '@/api/core/dataset/data'; import { getDatasetDataItemById } from '@/web/core/api/dataset';
import { useLoading } from '@/hooks/useLoading'; import { useLoading } from '@/web/common/hooks/useLoading';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { getErrText } from '@/utils/tools'; import { getErrText } from '@/utils/tools';
import { QuoteItemType } from '@/types/chat'; import { QuoteItemType } from '@/types/chat';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';

View File

@ -1,9 +1,9 @@
import React from 'react'; import React from 'react';
import { ModalBody, ModalFooter, Button } from '@chakra-ui/react'; import { ModalBody, ModalFooter, Button } from '@chakra-ui/react';
import MyModal from '../MyModal'; import MyModal from '../MyModal';
import { useRequest } from '@/hooks/useRequest'; import { useRequest } from '@/web/common/hooks/useRequest';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { userUpdateChatFeedback } from '@/api/chat'; import { userUpdateChatFeedback } from '@/web/core/api/chat';
const ReadFeedbackModal = ({ const ReadFeedbackModal = ({
chatItemId, chatItemId,

View File

@ -2,7 +2,7 @@ import React, { useCallback, useMemo, useState } from 'react';
import { ChatHistoryItemResType, ChatItemType, QuoteItemType } from '@/types/chat'; import { ChatHistoryItemResType, ChatItemType, QuoteItemType } from '@/types/chat';
import { Flex, BoxProps, useDisclosure } from '@chakra-ui/react'; import { Flex, BoxProps, useDisclosure } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/web/common/store/global';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import Tag from '../Tag'; import Tag from '../Tag';
import MyTooltip from '../MyTooltip'; import MyTooltip from '../MyTooltip';

View File

@ -1,7 +1,7 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { ModalBody, useTheme, ModalFooter, Button, Box, Card, Flex, Grid } from '@chakra-ui/react'; import { ModalBody, useTheme, ModalFooter, Button, Box, Card, Flex, Grid } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import Avatar from '../Avatar'; import Avatar from '../Avatar';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import { KbTypeEnum } from '@/constants/dataset'; import { KbTypeEnum } from '@/constants/dataset';

View File

@ -15,10 +15,10 @@ import {
ChatSiteItemType, ChatSiteItemType,
ExportChatType ExportChatType
} from '@/types/chat'; } from '@/types/chat';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { useAudioPlay } from '@/utils/web/voice'; import { useAudioPlay } from '@/web/common/utils/voice';
import { getErrText } from '@/utils/tools'; import { getErrText } from '@/utils/tools';
import { useCopyData } from '@/hooks/useCopyData'; import { useCopyData } from '@/web/common/hooks/useCopyData';
import { import {
Box, Box,
Card, Card,
@ -30,22 +30,22 @@ import {
BoxProps, BoxProps,
FlexProps FlexProps
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { feConfigs } from '@/store/static'; import { feConfigs } from '@/web/common/store/static';
import { event } from '@/utils/plugin/eventbus'; import { eventBus } from '@/web/common/utils/eventbus';
import { adaptChat2GptMessages } from '@/utils/common/adapt/message'; import { adaptChat2GptMessages } from '@/utils/common/adapt/message';
import { useMarkdown } from '@/hooks/useMarkdown'; import { useMarkdown } from '@/web/common/hooks/useMarkdown';
import { AppModuleItemType } from '@/types/app'; import { AppModuleItemType } from '@/types/app';
import { VariableInputEnum } from '@/constants/app'; import { VariableInputEnum } from '@/constants/app';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import type { MessageItemType } from '@/types/core/chat/type'; import type { MessageItemType } from '@/types/core/chat/type';
import { fileDownload } from '@/utils/web/file'; import { fileDownload } from '@/web/common/utils/file';
import { htmlTemplate } from '@/constants/common'; import { htmlTemplate } from '@/constants/common';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/web/common/store/global';
import { TaskResponseKeyEnum } from '@/constants/chat'; import { TaskResponseKeyEnum } from '@/constants/chat';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
import { userUpdateChatFeedback, adminUpdateChatFeedback } from '@/api/chat'; import { userUpdateChatFeedback, adminUpdateChatFeedback } from '@/web/core/api/chat';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
@ -61,7 +61,7 @@ const InputDataModal = dynamic(() => import('@/pages/kb/detail/components/InputD
import styles from './index.module.scss'; import styles from './index.module.scss';
import Script from 'next/script'; import Script from 'next/script';
import { postQuestionGuide } from '@/api/core/ai/agent/api'; import { postQuestionGuide } from '@/web/core/api/ai';
import { splitGuideModule } from './utils'; import { splitGuideModule } from './utils';
import { DatasetSpecialIdEnum } from '@fastgpt/core/dataset/constant'; import { DatasetSpecialIdEnum } from '@fastgpt/core/dataset/constant';
@ -518,13 +518,13 @@ const ChatBox = (
} }
}; };
window.addEventListener('message', windowMessage); window.addEventListener('message', windowMessage);
event.on('guideClick', ({ text }: { text: string }) => { eventBus.on('guideClick', ({ text }: { text: string }) => {
if (!text) return; if (!text) return;
handleSubmit((data) => sendPrompt(data, text))(); handleSubmit((data) => sendPrompt(data, text))();
}); });
return () => { return () => {
event.off('guideClick'); eventBus.off('guideClick');
window.removeEventListener('message', windowMessage); window.removeEventListener('message', windowMessage);
}; };
}, [handleSubmit, sendPrompt]); }, [handleSubmit, sendPrompt]);

View File

@ -1,6 +1,6 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Menu, MenuButton, MenuItem, MenuList, MenuButtonProps } from '@chakra-ui/react'; import { Menu, MenuButton, MenuItem, MenuList, MenuButtonProps } from '@chakra-ui/react';
import { getLangStore, LangEnum, setLangStore, langMap } from '@/utils/web/i18n'; import { getLangStore, LangEnum, setLangStore, langMap } from '@/web/common/utils/i18n';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useToast } from '@chakra-ui/react'; import { useToast } from '@chakra-ui/react';
import { useUserStore } from '@/store/user'; import { useUserStore } from '@/web/support/store/user';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
const unAuthPage: { [key: string]: boolean } = { const unAuthPage: { [key: string]: boolean } = {

View File

@ -1,15 +1,15 @@
import React, { useEffect, useMemo } from 'react'; import React, { useEffect, useMemo } from 'react';
import { Box, useColorMode, Flex } from '@chakra-ui/react'; import { Box, useColorMode, Flex } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useLoading } from '@/hooks/useLoading'; import { useLoading } from '@/web/common/hooks/useLoading';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/web/common/store/global';
import { throttle } from 'lodash'; import { throttle } from 'lodash';
import Auth from './auth'; import Auth from './auth';
import Navbar from './navbar'; import Navbar from './navbar';
import NavbarPhone from './navbarPhone'; import NavbarPhone from './navbarPhone';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useUserStore } from '@/store/user'; import { useUserStore } from '@/web/support/store/user';
import { getUnreadCount } from '@/api/user'; import { getUnreadCount } from '@/web/support/api/user';
const pcUnShowLayoutRoute: Record<string, boolean> = { const pcUnShowLayoutRoute: Record<string, boolean> = {
'/': true, '/': true,

View File

@ -1,16 +1,16 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { Box, Flex, Link } from '@chakra-ui/react'; import { Box, Flex, Link } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useUserStore } from '@/store/user'; import { useUserStore } from '@/web/support/store/user';
import { useChatStore } from '@/store/chat'; import { useChatStore } from '@/web/core/store/chat';
import { HUMAN_ICON } from '@/constants/chat'; import { HUMAN_ICON } from '@/constants/chat';
import { feConfigs } from '@/store/static'; import { feConfigs } from '@/web/common/store/static';
import NextLink from 'next/link'; import NextLink from 'next/link';
import Badge from '../Badge'; import Badge from '../Badge';
import Avatar from '../Avatar'; import Avatar from '../Avatar';
import MyIcon from '../Icon'; import MyIcon from '../Icon';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/web/common/store/global';
import MyTooltip from '../MyTooltip'; import MyTooltip from '../MyTooltip';
export enum NavbarTypeEnum { export enum NavbarTypeEnum {

View File

@ -1,7 +1,7 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { Flex, Box } from '@chakra-ui/react'; import { Flex, Box } from '@chakra-ui/react';
import { useChatStore } from '@/store/chat'; import { useChatStore } from '@/web/core/store/chat';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Badge from '../Badge'; import Badge from '../Badge';
import MyIcon from '../Icon'; import MyIcon from '../Icon';

View File

@ -2,7 +2,7 @@ import React from 'react';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { Box, Flex, useColorModeValue } from '@chakra-ui/react'; import { Box, Flex, useColorModeValue } from '@chakra-ui/react';
import Icon from '@/components/Icon'; import Icon from '@/components/Icon';
import { useCopyData } from '@/hooks/useCopyData'; import { useCopyData } from '@/web/common/hooks/useCopyData';
const codeLight: { [key: string]: React.CSSProperties } = { const codeLight: { [key: string]: React.CSSProperties } = {
'code[class*=language-]': { 'code[class*=language-]': {

View File

@ -5,7 +5,7 @@ import RemarkGfm from 'remark-gfm';
import RemarkMath from 'remark-math'; import RemarkMath from 'remark-math';
import RehypeKatex from 'rehype-katex'; import RehypeKatex from 'rehype-katex';
import RemarkBreaks from 'remark-breaks'; import RemarkBreaks from 'remark-breaks';
import { event } from '@/utils/plugin/eventbus'; import { eventBus } from '@/web/common/utils/eventbus';
import 'katex/dist/katex.min.css'; import 'katex/dist/katex.min.css';
import styles from '../index.module.scss'; import styles from '../index.module.scss';
@ -27,7 +27,7 @@ function MyLink(e: any) {
textDecoration={'underline'} textDecoration={'underline'}
cursor={'pointer'} cursor={'pointer'}
onClick={() => { onClick={() => {
event.emit('guideClick', { text }); eventBus.emit('guideClick', { text });
}} }}
> >
{text} {text}

View File

@ -1,7 +1,7 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { Box, useTheme } from '@chakra-ui/react'; import { Box, useTheme } from '@chakra-ui/react';
import { getFileAndOpen } from '@/utils/web/file'; import { getFileAndOpen } from '@/web/common/utils/file';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { getErrText } from '@/utils/tools'; import { getErrText } from '@/utils/tools';
type QuoteItemType = { type QuoteItemType = {

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { Tooltip, TooltipProps } from '@chakra-ui/react'; import { Tooltip, TooltipProps } from '@chakra-ui/react';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/web/common/store/global';
interface Props extends TooltipProps { interface Props extends TooltipProps {
forceShow?: boolean; forceShow?: boolean;

View File

@ -1,9 +1,9 @@
import { getDatasets, getDatasetPaths } from '@/api/core/dataset'; import { getDatasets, getDatasetPaths } from '@/web/core/api/dataset';
import MyModal from '@/components/MyModal'; import MyModal from '@/components/MyModal';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import React, { Dispatch, useMemo, useState } from 'react'; import React, { Dispatch, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/web/common/store/global';
import { Box, Flex, ModalHeader } from '@chakra-ui/react'; import { Box, Flex, ModalHeader } from '@chakra-ui/react';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';

View File

@ -25,19 +25,19 @@ import {
createAOpenApiKey, createAOpenApiKey,
delOpenApiById, delOpenApiById,
putOpenApiKey putOpenApiKey
} from '@/api/support/openapi'; } from '@/web/support/api/openapi';
import type { EditApiKeyProps } from '@/api/support/openapi/index.d'; import type { EditApiKeyProps } from '@/global/support/api/openapiReq';
import { useQuery, useMutation } from '@tanstack/react-query'; import { useQuery, useMutation } from '@tanstack/react-query';
import { useLoading } from '@/hooks/useLoading'; import { useLoading } from '@/web/common/hooks/useLoading';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { AddIcon, QuestionOutlineIcon } from '@chakra-ui/icons'; import { AddIcon, QuestionOutlineIcon } from '@chakra-ui/icons';
import { useCopyData } from '@/hooks/useCopyData'; import { useCopyData } from '@/web/common/hooks/useCopyData';
import { feConfigs } from '@/store/static'; import { feConfigs } from '@/web/common/store/static';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import MyModal from '@/components/MyModal'; import MyModal from '@/components/MyModal';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { useRequest } from '@/hooks/useRequest'; import { useRequest } from '@/web/common/hooks/useRequest';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
type EditProps = EditApiKeyProps & { _id?: string }; type EditProps = EditApiKeyProps & { _id?: string };

View File

@ -7,6 +7,9 @@ export enum SystemInputEnum {
'userChatInput' = 'userChatInput', 'userChatInput' = 'userChatInput',
'questionGuide' = 'questionGuide' 'questionGuide' = 'questionGuide'
} }
export enum SystemOutputEnum {
finish = 'finish'
}
export enum VariableInputEnum { export enum VariableInputEnum {
input = 'input', input = 'input',

View File

@ -9,13 +9,14 @@ import {
} from './index'; } from './index';
import type { AppItemType } from '@/types/app'; import type { AppItemType } from '@/types/app';
import type { FlowModuleTemplateType } from '@/types/core/app/flow'; import type { FlowModuleTemplateType } from '@/types/core/app/flow';
import { chatModelList } from '@/store/static'; import { chatModelList } from '@/web/common/store/static';
import { import {
Input_Template_History, Input_Template_History,
Input_Template_TFSwitch, Input_Template_TFSwitch,
Input_Template_UserChatInput Input_Template_UserChatInput
} from './inputTemplate'; } from './inputTemplate';
import { ContextExtractEnum, HttpPropsEnum } from './flowField'; import { ContextExtractEnum, HttpPropsEnum } from './flowField';
import { Output_Template_Finish } from './outputTemplate';
export const ChatModelSystemTip = export const ChatModelSystemTip =
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可使用变量,例如 {{language}}'; '模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可使用变量,例如 {{language}}';
@ -130,12 +131,15 @@ export const ChatModule: FlowModuleTemplateType = {
intro: 'AI 大模型对话', intro: 'AI 大模型对话',
showStatus: true, showStatus: true,
inputs: [ inputs: [
Input_Template_TFSwitch,
{ {
key: 'model', key: 'model',
type: FlowInputItemTypeEnum.custom, type: FlowInputItemTypeEnum.selectChatModel,
label: '对话模型', label: '对话模型',
value: chatModelList[0]?.model, value: chatModelList[0]?.model,
list: chatModelList.map((item) => ({ label: item.name, value: item.model })) list: chatModelList.map((item) => ({ label: item.name, value: item.model })),
required: true,
valueCheck: (val) => !!val
}, },
{ {
key: 'temperature', key: 'temperature',
@ -152,7 +156,7 @@ export const ChatModule: FlowModuleTemplateType = {
}, },
{ {
key: 'maxToken', key: 'maxToken',
type: FlowInputItemTypeEnum.custom, type: FlowInputItemTypeEnum.maxToken,
label: '回复上限', label: '回复上限',
value: chatModelList[0] ? chatModelList[0].contextMaxToken / 2 : 2000, value: chatModelList[0] ? chatModelList[0].contextMaxToken / 2 : 2000,
min: 100, min: 100,
@ -190,10 +194,9 @@ export const ChatModule: FlowModuleTemplateType = {
valueType: FlowValueTypeEnum.string, valueType: FlowValueTypeEnum.string,
value: '' value: ''
}, },
Input_Template_TFSwitch,
{ {
key: 'quoteQA', key: 'quoteQA',
type: FlowInputItemTypeEnum.custom, type: FlowInputItemTypeEnum.quoteList,
label: '引用内容', label: '引用内容',
description: "对象数组格式,结构:\n [{q:'问题',a:'回答'}]", description: "对象数组格式,结构:\n [{q:'问题',a:'回答'}]",
valueType: FlowValueTypeEnum.kbQuote, valueType: FlowValueTypeEnum.kbQuote,
@ -219,14 +222,7 @@ export const ChatModule: FlowModuleTemplateType = {
type: FlowOutputItemTypeEnum.source, type: FlowOutputItemTypeEnum.source,
targets: [] targets: []
}, },
{ Output_Template_Finish
key: 'finish',
label: '回复结束',
description: 'AI 回复完成后触发',
valueType: FlowValueTypeEnum.boolean,
type: FlowOutputItemTypeEnum.source,
targets: []
}
] ]
}; };
@ -237,12 +233,15 @@ export const KBSearchModule: FlowModuleTemplateType = {
intro: '去知识库中搜索对应的答案。可作为 AI 对话引用参考。', intro: '去知识库中搜索对应的答案。可作为 AI 对话引用参考。',
showStatus: true, showStatus: true,
inputs: [ inputs: [
Input_Template_TFSwitch,
{ {
key: 'kbList', key: 'kbList',
type: FlowInputItemTypeEnum.custom, type: FlowInputItemTypeEnum.selectDataset,
label: '关联的知识库', label: '关联的知识库',
value: [], value: [],
list: [] list: [],
required: true,
valueCheck: (val) => !!val.length
}, },
{ {
key: 'similarity', key: 'similarity',
@ -271,7 +270,6 @@ export const KBSearchModule: FlowModuleTemplateType = {
{ label: '20', value: 20 } { label: '20', value: 20 }
] ]
}, },
Input_Template_TFSwitch,
Input_Template_UserChatInput Input_Template_UserChatInput
], ],
outputs: [ outputs: [
@ -297,7 +295,8 @@ export const KBSearchModule: FlowModuleTemplateType = {
type: FlowOutputItemTypeEnum.source, type: FlowOutputItemTypeEnum.source,
valueType: FlowValueTypeEnum.kbQuote, valueType: FlowValueTypeEnum.kbQuote,
targets: [] targets: []
} },
Output_Template_Finish
] ]
}; };
@ -312,23 +311,14 @@ export const AnswerModule: FlowModuleTemplateType = {
{ {
key: SpecialInputKeyEnum.answerText, key: SpecialInputKeyEnum.answerText,
type: FlowInputItemTypeEnum.textarea, type: FlowInputItemTypeEnum.textarea,
valueType: FlowValueTypeEnum.string, valueType: FlowValueTypeEnum.any,
value: '', value: '',
label: '回复的内容', label: '回复的内容',
description: description:
'可以使用 \\n 来实现连续换行。\n\n可以通过外部模块输入实现回复外部模块输入时会覆盖当前填写的内容' '可以使用 \\n 来实现连续换行。\n\n可以通过外部模块输入实现回复外部模块输入时会覆盖当前填写的内容。\n\n如传入非字符串类型数据将会自动转成字符串'
} }
], ],
outputs: [ outputs: [Output_Template_Finish]
{
key: 'finish',
label: '回复结束',
description: '回复完成后触发',
valueType: FlowValueTypeEnum.boolean,
type: FlowOutputItemTypeEnum.source,
targets: []
}
]
}; };
export const ClassifyQuestionModule: FlowModuleTemplateType = { export const ClassifyQuestionModule: FlowModuleTemplateType = {
flowType: FlowModuleTypeEnum.classifyQuestion, flowType: FlowModuleTypeEnum.classifyQuestion,
@ -461,6 +451,7 @@ export const HttpModule: FlowModuleTemplateType = {
description: '可以发出一个 HTTP POST 请求,实现更为复杂的操作(联网搜索、数据库查询等)', description: '可以发出一个 HTTP POST 请求,实现更为复杂的操作(联网搜索、数据库查询等)',
showStatus: true, showStatus: true,
inputs: [ inputs: [
Input_Template_TFSwitch,
{ {
key: HttpPropsEnum.url, key: HttpPropsEnum.url,
value: '', value: '',
@ -468,19 +459,11 @@ export const HttpModule: FlowModuleTemplateType = {
label: '请求地址', label: '请求地址',
description: '请求目标地址', description: '请求目标地址',
placeholder: 'https://api.fastgpt.run/getInventory', placeholder: 'https://api.fastgpt.run/getInventory',
required: true required: true,
}, valueCheck: (val) => !!val
Input_Template_TFSwitch
],
outputs: [
{
key: HttpPropsEnum.finish,
label: '请求结束',
valueType: FlowValueTypeEnum.boolean,
type: FlowOutputItemTypeEnum.source,
targets: []
} }
] ],
outputs: [Output_Template_Finish]
}; };
export const EmptyModule: FlowModuleTemplateType = { export const EmptyModule: FlowModuleTemplateType = {
flowType: FlowModuleTypeEnum.empty, flowType: FlowModuleTypeEnum.empty,
@ -527,13 +510,7 @@ export const AppModule: FlowModuleTemplateType = {
type: FlowOutputItemTypeEnum.source, type: FlowOutputItemTypeEnum.source,
targets: [] targets: []
}, },
{ Output_Template_Finish
key: 'finish',
label: '请求结束',
valueType: FlowValueTypeEnum.boolean,
type: FlowOutputItemTypeEnum.source,
targets: []
}
] ]
}; };

View File

@ -8,17 +8,21 @@ export enum FlowInputItemTypeEnum {
select = 'select', select = 'select',
slider = 'slider', slider = 'slider',
custom = 'custom', custom = 'custom',
target = 'target', target = 'target', // data input
none = 'none',
switch = 'switch', switch = 'switch',
hidden = 'hidden', selectApp = 'selectApp',
selectApp = 'selectApp' // chat special input
quoteList = 'quoteList',
maxToken = 'maxToken',
selectChatModel = 'selectChatModel',
// dataset special input
selectDataset = 'selectDataset',
hidden = 'hidden'
} }
export enum FlowOutputItemTypeEnum { export enum FlowOutputItemTypeEnum {
answer = 'answer', answer = 'answer',
source = 'source', source = 'source',
none = 'none',
hidden = 'hidden' hidden = 'hidden'
} }

View File

@ -0,0 +1,12 @@
import type { FlowOutputItemType } from '@/types/core/app/flow';
import { SystemOutputEnum } from '../app';
import { FlowOutputItemTypeEnum, FlowValueTypeEnum } from './index';
export const Output_Template_Finish: FlowOutputItemType = {
key: SystemOutputEnum.finish,
label: '模块调用结束',
description: '模块调用结束时触发',
valueType: FlowValueTypeEnum.boolean,
type: FlowOutputItemTypeEnum.source,
targets: []
};

View File

@ -0,0 +1,14 @@
import {
type QAModelItemType,
type ChatModelItemType,
type VectorModelItemType,
FunctionModelItemType
} from '@/types/model';
export type InitDateResponse = {
chatModels: ChatModelItemType[];
qaModel: QAModelItemType;
vectorModels: VectorModelItemType[];
feConfigs: FeConfigsType;
systemVersion: string;
};

View File

@ -1,6 +1,6 @@
import { ChatCompletionRequestMessage } from '@fastgpt/core/ai/type'; import { ChatCompletionRequestMessage } from '@fastgpt/core/ai/type';
export type CreateQuestionGuideProps = { export type CreateQuestionGuideParams = {
messages: ChatCompletionRequestMessage[]; messages: ChatCompletionRequestMessage[];
shareId?: string; shareId?: string;
}; };

View File

@ -2,7 +2,7 @@ import type { AppSchema } from '@/types/mongoSchema';
import type { ChatItemType } from '@/types/chat'; import type { ChatItemType } from '@/types/chat';
import { AppModuleItemType, VariableItemType } from '@/types/app'; import { AppModuleItemType, VariableItemType } from '@/types/app';
export interface InitChatResponse { export type InitChatResponse = {
chatId: string; chatId: string;
appId: string; appId: string;
app: { app: {
@ -16,9 +16,4 @@ export interface InitChatResponse {
title: string; title: string;
variables: Record<string, any>; variables: Record<string, any>;
history: ChatItemType[]; history: ChatItemType[];
} };
export interface InitShareChatResponse {
userAvatar: string;
app: InitChatResponse['app'];
}

View File

@ -0,0 +1,59 @@
import { KbTypeEnum } from '@/constants/dataset';
import type { RequestPaging } from '@/types';
import { TrainingModeEnum } from '@/constants/plugin';
import type { SearchTestItemType } from '@/types/core/dataset';
import { DatasetDataItemType } from '@/types/core/dataset/data';
/* ===== dataset ===== */
export type DatasetUpdateParams = {
id: string;
parentId?: string;
tags?: string;
name?: string;
avatar?: string;
};
export type CreateDatasetParams = {
parentId?: string;
name: string;
tags: string[];
avatar: string;
vectorModel?: string;
type: `${KbTypeEnum}`;
};
export type SearchTestProps = {
kbId: string;
text: string;
};
/* ======= file =========== */
export type GetFileListProps = RequestPaging & {
kbId: string;
searchText: string;
};
export type UpdateFileProps = { id: string; name?: string; datasetUsed?: boolean };
export type MarkFileUsedProps = { fileIds: string[] };
/* ==== data ===== */
export type PushDataProps = {
kbId: string;
data: DatasetDataItemType[];
mode: `${TrainingModeEnum}`;
prompt?: string;
billId?: string;
};
export type UpdateDatasetDataPrams = {
dataId: string;
kbId: string;
a?: string;
q?: string;
};
export type GetDatasetDataListProps = RequestPaging & {
kbId: string;
searchText: string;
fileId: string;
};

View File

@ -0,0 +1,15 @@
import { KbTypeEnum } from '@/constants/dataset';
import type { RequestPaging } from '@/types';
import { TrainingModeEnum } from '@/constants/plugin';
import type { SearchTestItemType } from '@/types/core/dataset';
import { DatasetDataItemType } from '@/types/core/dataset/data';
/* ===== dataset ===== */
export type SearchTestResponseType = SearchTestItemType['results'];
/* ======= file =========== */
/* ==== data ===== */
export type PushDataResponse = {
insertLen: number;
};

View File

@ -0,0 +1,6 @@
import type { InitChatResponse } from '@/global/core/api/chatRes.d';
export type InitShareChatResponse = {
userAvatar: string;
app: InitChatResponse['app'];
};

View File

@ -4,18 +4,18 @@ import Script from 'next/script';
import Head from 'next/head'; import Head from 'next/head';
import { ChakraProvider, ColorModeScript } from '@chakra-ui/react'; import { ChakraProvider, ColorModeScript } from '@chakra-ui/react';
import Layout from '@/components/Layout'; import Layout from '@/components/Layout';
import { theme } from '@/constants/theme'; import { theme } from '@/web/styles/theme';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import NProgress from 'nprogress'; //nprogress module import NProgress from 'nprogress'; //nprogress module
import Router from 'next/router'; import Router from 'next/router';
import { clientInitData, feConfigs } from '@/store/static'; import { clientInitData, feConfigs } from '@/web/common/store/static';
import { appWithTranslation, useTranslation } from 'next-i18next'; import { appWithTranslation, useTranslation } from 'next-i18next';
import { getLangStore, setLangStore } from '@/utils/web/i18n'; import { getLangStore, setLangStore } from '@/web/common/utils/i18n';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/web/common/store/global';
import 'nprogress/nprogress.css'; import 'nprogress/nprogress.css';
import '@/styles/reset.scss'; import '@/web/styles/reset.scss';
import { FeConfigsType } from '@/types'; import { FeConfigsType } from '@/types';
//Binding events. //Binding events.

View File

@ -1,7 +1,7 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { serviceSideProps } from '@/utils/web/i18n'; import { serviceSideProps } from '@/web/common/utils/i18n';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/web/common/store/global';
import { addLog } from '@/service/utils/tools'; import { addLog } from '@/service/utils/tools';
import { getErrText } from '@/utils/tools'; import { getErrText } from '@/utils/tools';

View File

@ -12,16 +12,16 @@ import {
Button Button
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { BillSourceMap } from '@/constants/user'; import { BillSourceMap } from '@/constants/user';
import { getUserBills } from '@/api/user'; import { getUserBills } from '@/web/common/api/bill';
import type { UserBillType } from '@/types/user'; import type { UserBillType } from '@/types/user';
import { usePagination } from '@/hooks/usePagination'; import { usePagination } from '@/web/common/hooks/usePagination';
import { useLoading } from '@/hooks/useLoading'; import { useLoading } from '@/web/common/hooks/useLoading';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import DateRangePicker, { type DateRangeType } from '@/components/DateRangePicker'; import DateRangePicker, { type DateRangeType } from '@/components/DateRangePicker';
import { addDays } from 'date-fns'; import { addDays } from 'date-fns';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/web/common/store/global';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
const BillDetail = dynamic(() => import('./BillDetail')); const BillDetail = dynamic(() => import('./BillDetail'));

View File

@ -14,21 +14,21 @@ import {
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { UserUpdateParams } from '@/types/user'; import { UserUpdateParams } from '@/types/user';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { useUserStore } from '@/store/user'; import { useUserStore } from '@/web/support/store/user';
import { UserType } from '@/types/user'; import { UserType } from '@/types/user';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { useSelectFile } from '@/hooks/useSelectFile'; import { useSelectFile } from '@/web/common/hooks/useSelectFile';
import { compressImg } from '@/utils/web/file'; import { compressImg } from '@/web/common/utils/file';
import { feConfigs, systemVersion } from '@/store/static'; import { feConfigs, systemVersion } from '@/web/common/store/static';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { timezoneList } from '@/utils/user'; import { timezoneList } from '@/utils/user';
import Loading from '@/components/Loading'; import Loading from '@/components/Loading';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import { getLangStore, LangEnum, langMap, setLangStore } from '@/utils/web/i18n'; import { getLangStore, LangEnum, langMap, setLangStore } from '@/web/common/utils/i18n';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import MyMenu from '@/components/MyMenu'; import MyMenu from '@/components/MyMenu';
import MySelect from '@/components/Select'; import MySelect from '@/components/Select';

View File

@ -1,11 +1,11 @@
import React from 'react'; import React from 'react';
import { Box, Flex, useTheme } from '@chakra-ui/react'; import { Box, Flex, useTheme } from '@chakra-ui/react';
import { getInforms, readInform } from '@/api/user'; import { getInforms, readInform } from '@/web/support/api/user';
import { usePagination } from '@/hooks/usePagination'; import { usePagination } from '@/web/common/hooks/usePagination';
import { useLoading } from '@/hooks/useLoading'; import { useLoading } from '@/web/common/hooks/useLoading';
import type { informSchema } from '@/types/mongoSchema'; import type { informSchema } from '@/types/mongoSchema';
import { formatTimeToChatTime } from '@/utils/tools'; import { formatTimeToChatTime } from '@/utils/tools';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/web/common/store/global';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
const BillTable = () => { const BillTable = () => {

View File

@ -3,7 +3,7 @@ import { ModalBody, Box, Flex, Input, ModalFooter, Button } from '@chakra-ui/rea
import MyModal from '@/components/MyModal'; import MyModal from '@/components/MyModal';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { useRequest } from '@/hooks/useRequest'; import { useRequest } from '@/web/common/hooks/useRequest';
import { UserType } from '@/types/user'; import { UserType } from '@/types/user';
const OpenAIAccountModal = ({ const OpenAIAccountModal = ({
@ -32,7 +32,8 @@ const OpenAIAccountModal = ({
<MyModal isOpen onClose={onClose} title={t('user.OpenAI Account Setting')}> <MyModal isOpen onClose={onClose} title={t('user.OpenAI Account Setting')}>
<ModalBody> <ModalBody>
<Box fontSize={'sm'} color={'myGray.500'}> <Box fontSize={'sm'} color={'myGray.500'}>
线使 OpenAI Chat OpenAI key OneAPI 线使 OpenAI
Chat Key 访
</Box> </Box>
<Flex alignItems={'center'} mt={5}> <Flex alignItems={'center'} mt={5}>
<Box flex={'0 0 65px'}>API Key:</Box> <Box flex={'0 0 65px'}>API Key:</Box>

View File

@ -1,7 +1,7 @@
import React, { useState, useCallback } from 'react'; import React, { useState, useCallback } from 'react';
import { ModalFooter, ModalBody, Button, Input, Box, Grid } from '@chakra-ui/react'; import { ModalFooter, ModalBody, Button, Input, Box, Grid } from '@chakra-ui/react';
import { getPayCode, checkPayResult } from '@/api/user'; import { getPayCode, checkPayResult } from '@/web/common/api/bill';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { getErrText } from '@/utils/tools'; import { getErrText } from '@/utils/tools';
@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next';
import { formatPrice } from '@fastgpt/common/bill/index'; import { formatPrice } from '@fastgpt/common/bill/index';
import Markdown from '@/components/Markdown'; import Markdown from '@/components/Markdown';
import MyModal from '@/components/MyModal'; import MyModal from '@/components/MyModal';
import { vectorModelList, chatModelList, qaModel } from '@/store/static'; import { vectorModelList, chatModelList, qaModel } from '@/web/common/store/static';
const PayModal = ({ onClose }: { onClose: () => void }) => { const PayModal = ({ onClose }: { onClose: () => void }) => {
const router = useRouter(); const router = useRouter();

View File

@ -11,13 +11,13 @@ import {
Flex, Flex,
Box Box
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { getPayOrders, checkPayResult } from '@/api/user'; import { getPayOrders, checkPayResult } from '@/web/common/api/bill';
import { PaySchema } from '@/types/mongoSchema'; import { PaySchema } from '@/types/mongoSchema';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { formatPrice } from '@fastgpt/common/bill/index'; import { formatPrice } from '@fastgpt/common/bill/index';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { useLoading } from '@/hooks/useLoading'; import { useLoading } from '@/web/common/hooks/useLoading';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
const PayRecordTable = () => { const PayRecordTable = () => {

View File

@ -16,15 +16,15 @@ import {
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { getPromotionInitData, getPromotionRecords } from '@/api/user'; import { getPromotionInitData, getPromotionRecords } from '@/web/support/api/user';
import { useUserStore } from '@/store/user'; import { useUserStore } from '@/web/support/store/user';
import { useLoading } from '@/hooks/useLoading'; import { useLoading } from '@/web/common/hooks/useLoading';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useCopyData } from '@/hooks/useCopyData'; import { useCopyData } from '@/web/common/hooks/useCopyData';
import { usePagination } from '@/hooks/usePagination'; import { usePagination } from '@/web/common/hooks/usePagination';
import { PromotionRecordType } from '@/api/response/user'; import type { PromotionRecordType } from '@/global/support/api/userRes.d';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import dayjs from 'dayjs'; import dayjs from 'dayjs';

View File

@ -3,8 +3,8 @@ import { ModalBody, Box, Flex, Input, ModalFooter, Button } from '@chakra-ui/rea
import MyModal from '@/components/MyModal'; import MyModal from '@/components/MyModal';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { useRequest } from '@/hooks/useRequest'; import { useRequest } from '@/web/common/hooks/useRequest';
import { updatePasswordByOld } from '@/api/user'; import { updatePasswordByOld } from '@/web/support/api/user';
type FormType = { type FormType = {
oldPsw: string; oldPsw: string;

View File

@ -1,17 +1,17 @@
import React, { useCallback, useRef } from 'react'; import React, { useCallback, useRef } from 'react';
import { Box, Flex, useTheme } from '@chakra-ui/react'; import { Box, Flex, useTheme } from '@chakra-ui/react';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/web/common/store/global';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { clearToken } from '@/utils/user'; import { clearToken } from '@/utils/user';
import { useUserStore } from '@/store/user'; import { useUserStore } from '@/web/support/store/user';
import { useConfirm } from '@/hooks/useConfirm'; import { useConfirm } from '@/web/common/hooks/useConfirm';
import PageContainer from '@/components/PageContainer'; import PageContainer from '@/components/PageContainer';
import SideTabs from '@/components/SideTabs'; import SideTabs from '@/components/SideTabs';
import Tabs from '@/components/Tabs'; import Tabs from '@/components/Tabs';
import UserInfo from './components/Info'; import UserInfo from './components/Info';
import { serviceSideProps } from '@/utils/web/i18n'; import { serviceSideProps } from '@/web/common/utils/i18n';
import { feConfigs } from '@/store/static'; import { feConfigs } from '@/web/common/store/static';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Script from 'next/script'; import Script from 'next/script';

View File

@ -6,7 +6,7 @@ import type { PagingData } from '@/types';
import { AppLogsListItemType } from '@/types/app'; import { AppLogsListItemType } from '@/types/app';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import { addDays } from 'date-fns'; import { addDays } from 'date-fns';
import { GetAppChatLogsParams } from '@/api/request/app'; import type { GetAppChatLogsParams } from '@/global/core/api/appReq.d';
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try { try {

View File

@ -1,7 +1,7 @@
import type { NextApiRequest, NextApiResponse } from 'next'; import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { connectToDatabase, ChatItem } from '@/service/mongo'; import { connectToDatabase, ChatItem } from '@/service/mongo';
import { AdminUpdateFeedbackParams } from '@/api/request/chat'; import type { AdminUpdateFeedbackParams } from '@/global/core/api/chatReq.d';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
/* 初始化我的聊天框,需要身份验证 */ /* 初始化我的聊天框,需要身份验证 */

View File

@ -1,7 +1,7 @@
import type { NextApiRequest, NextApiResponse } from 'next'; import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { Chat, ChatItem } from '@/service/mongo'; import { Chat, ChatItem } from '@/service/mongo';
import type { InitChatResponse } from '@/api/response/chat'; import type { InitChatResponse } from '@/global/core/api/chatRes.d';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import { ChatItemType } from '@/types/chat'; import { ChatItemType } from '@/types/chat';
import { authApp } from '@/service/utils/auth'; import { authApp } from '@/service/utils/auth';

View File

@ -3,7 +3,7 @@ import { jsonRes } from '@/service/response';
import { connectToDatabase, Bill } from '@/service/mongo'; import { connectToDatabase, Bill } from '@/service/mongo';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import { BillSourceEnum } from '@/constants/user'; import { BillSourceEnum } from '@/constants/user';
import { CreateTrainingBillType } from '@/api/common/bill/index.d'; import { CreateTrainingBillType } from '@/global/common/api/billReq.d';
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try { try {

View File

@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { connectToDatabase } from '@/service/mongo'; import { connectToDatabase } from '@/service/mongo';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import { CreateQuestionGuideProps } from '@/api/core/ai/agent/type'; import type { CreateQuestionGuideParams } from '@/global/core/api/aiReq.d';
import { pushQuestionGuideBill } from '@/service/common/bill/push'; import { pushQuestionGuideBill } from '@/service/common/bill/push';
import { defaultQGModel } from '@/pages/api/system/getInitData'; import { defaultQGModel } from '@/pages/api/system/getInitData';
import { createQuestionGuide } from '@fastgpt/core/ai/functions/createQuestionGuide'; import { createQuestionGuide } from '@fastgpt/core/ai/functions/createQuestionGuide';
@ -10,7 +10,7 @@ import { createQuestionGuide } from '@fastgpt/core/ai/functions/createQuestionGu
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) { export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try { try {
await connectToDatabase(); await connectToDatabase();
const { messages } = req.body as CreateQuestionGuideProps; const { messages } = req.body as CreateQuestionGuideParams;
const { user } = await authUser({ const { user } = await authUser({
req, req,
authOutLink: true, authOutLink: true,

View File

@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { connectToDatabase, KB } from '@/service/mongo'; import { connectToDatabase, KB } from '@/service/mongo';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import type { CreateDatasetParams } from '@/api/core/dataset/index.d'; import type { CreateDatasetParams } from '@/global/core/api/datasetReq.d';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) { export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try { try {

View File

@ -10,7 +10,8 @@ import { startQueue } from '@/service/utils/tools';
import { getVectorModel } from '@/service/utils/data'; import { getVectorModel } from '@/service/utils/data';
import { DatasetDataItemType } from '@/types/core/dataset/data'; import { DatasetDataItemType } from '@/types/core/dataset/data';
import { countPromptTokens } from '@/utils/common/tiktoken'; import { countPromptTokens } from '@/utils/common/tiktoken';
import type { PushDataProps, PushDataResponse } from '@/api/core/dataset/data.d'; import type { PushDataResponse } from '@/global/core/api/datasetRes.d';
import type { PushDataProps } from '@/global/core/api/datasetReq.d';
import { authFileIdValid } from '@/service/dataset/auth'; import { authFileIdValid } from '@/service/dataset/auth';
const modeMap = { const modeMap = {

View File

@ -6,11 +6,11 @@ import { withNextCors } from '@/service/utils/tools';
import { KB, connectToDatabase } from '@/service/mongo'; import { KB, connectToDatabase } from '@/service/mongo';
import { getVector } from '@/pages/api/openapi/plugin/vector'; import { getVector } from '@/pages/api/openapi/plugin/vector';
import { PgDatasetTableName } from '@/constants/plugin'; import { PgDatasetTableName } from '@/constants/plugin';
import type { UpdateDataPrams } from '@/api/core/dataset/data.d'; import type { UpdateDatasetDataPrams } from '@/global/core/api/datasetReq.d';
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) { export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try { try {
const { dataId, a = '', q = '', kbId } = req.body as UpdateDataPrams; const { dataId, a = '', q = '', kbId } = req.body as UpdateDatasetDataPrams;
if (!dataId) { if (!dataId) {
throw new Error('缺少参数'); throw new Error('缺少参数');

View File

@ -3,7 +3,7 @@ import { jsonRes } from '@/service/response';
import { connectToDatabase } from '@/service/mongo'; import { connectToDatabase } from '@/service/mongo';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import { GridFSStorage } from '@/service/lib/gridfs'; import { GridFSStorage } from '@/service/lib/gridfs';
import { MarkFileUsedProps } from '@/api/core/dataset/file.d'; import { MarkFileUsedProps } from '@/global/core/api/datasetReq.d';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) { export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {

View File

@ -3,7 +3,7 @@ import { jsonRes } from '@/service/response';
import { connectToDatabase } from '@/service/mongo'; import { connectToDatabase } from '@/service/mongo';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import { GridFSStorage } from '@/service/lib/gridfs'; import { GridFSStorage } from '@/service/lib/gridfs';
import { UpdateFileProps } from '@/api/core/dataset/file.d'; import { UpdateFileProps } from '@/global/core/api/datasetReq.d';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
import { PgClient } from '@/service/pg'; import { PgClient } from '@/service/pg';
import { PgDatasetTableName } from '@/constants/plugin'; import { PgDatasetTableName } from '@/constants/plugin';

View File

@ -6,7 +6,8 @@ import { withNextCors } from '@/service/utils/tools';
import { getVector } from '../../openapi/plugin/vector'; import { getVector } from '../../openapi/plugin/vector';
import { PgDatasetTableName } from '@/constants/plugin'; import { PgDatasetTableName } from '@/constants/plugin';
import { KB } from '@/service/mongo'; import { KB } from '@/service/mongo';
import type { SearchTestProps, SearchTestResponseType } from '@/api/core/dataset/index.d'; import type { SearchTestProps } from '@/global/core/api/datasetReq.d';
import type { SearchTestResponseType } from '@/global/core/api/datasetRes.d';
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) { export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try { try {

View File

@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { connectToDatabase, KB } from '@/service/mongo'; import { connectToDatabase, KB } from '@/service/mongo';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import type { DatasetUpdateParams } from '@/api/core/dataset/index.d'; import type { DatasetUpdateParams } from '@/global/core/api/datasetReq.d';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) { export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try { try {

View File

@ -5,7 +5,7 @@ import { JSDOM } from 'jsdom';
import { Readability } from '@mozilla/readability'; import { Readability } from '@mozilla/readability';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import type { FetchResultItem } from '@/types/plugin'; import type { FetchResultItem } from '@/global/common/api/pluginRes.d';
import { simpleText } from '@/utils/file'; import { simpleText } from '@/utils/file';
export type UrlFetchResponse = FetchResultItem[]; export type UrlFetchResponse = FetchResultItem[];

View File

@ -1,6 +1,6 @@
import type { NextApiRequest, NextApiResponse } from 'next'; import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { request } from '@/api/service/request'; import { request } from '@/service/common/api/request';
import type { Method } from 'axios'; import type { Method } from 'axios';
import { connectToDatabase } from '@/service/mongo'; import { connectToDatabase } from '@/service/mongo';

View File

@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { connectToDatabase, OpenApi } from '@/service/mongo'; import { connectToDatabase, OpenApi } from '@/service/mongo';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import type { GetApiKeyProps } from '@/api/support/openapi/index.d'; import type { GetApiKeyProps } from '@/global/support/api/openapiReq.d';
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try { try {

View File

@ -4,7 +4,7 @@ import { jsonRes } from '@/service/response';
import { connectToDatabase, OpenApi } from '@/service/mongo'; import { connectToDatabase, OpenApi } from '@/service/mongo';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
import type { EditApiKeyProps } from '@/api/support/openapi/index.d'; import type { EditApiKeyProps } from '@/global/support/api/openapiReq.d';
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try { try {

View File

@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { connectToDatabase, OpenApi } from '@/service/mongo'; import { connectToDatabase, OpenApi } from '@/service/mongo';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import type { EditApiKeyProps } from '@/api/support/openapi/index.d'; import type { EditApiKeyProps } from '@/global/support/api/openapiReq.d';
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try { try {

View File

@ -1,7 +1,7 @@
import type { NextApiRequest, NextApiResponse } from 'next'; import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { connectToDatabase, OutLink, User } from '@/service/mongo'; import { connectToDatabase, OutLink, User } from '@/service/mongo';
import type { InitShareChatResponse } from '@/api/response/chat'; import type { InitShareChatResponse } from '@/global/support/api/outLinkRes.d';
import { authApp } from '@/service/utils/auth'; import { authApp } from '@/service/utils/auth';
import { HUMAN_ICON } from '@/constants/chat'; import { HUMAN_ICON } from '@/constants/chat';
import { getChatModelNameList, getGuideModule } from '@/components/ChatBox/utils'; import { getChatModelNameList, getGuideModule } from '@/components/ChatBox/utils';

View File

@ -28,7 +28,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
}); });
jsonRes(res, { jsonRes(res, {
data: `/api/support/file/read?token=${token}` data: `/api/system/file/read?token=${token}`
}); });
} catch (error) { } catch (error) {
jsonRes(res, { jsonRes(res, {

View File

@ -2,20 +2,8 @@ import type { FeConfigsType, SystemEnvType } from '@/types';
import type { NextApiRequest, NextApiResponse } from 'next'; import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { import type { InitDateResponse } from '@/global/common/api/systemRes';
type QAModelItemType, import { type VectorModelItemType, FunctionModelItemType } from '@/types/model';
type ChatModelItemType,
type VectorModelItemType,
FunctionModelItemType
} from '@/types/model';
export type InitDateResponse = {
chatModels: ChatModelItemType[];
qaModel: QAModelItemType;
vectorModels: VectorModelItemType[];
feConfigs: FeConfigsType;
systemVersion: string;
};
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (!global.feConfigs) { if (!global.feConfigs) {

View File

@ -15,8 +15,8 @@ import {
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { defaultQuotePrompt, defaultQuoteTemplate } from '@/prompts/core/AIChat'; import { defaultQuotePrompt, defaultQuoteTemplate } from '@/global/core/prompt/AIChat';
import { feConfigs } from '@/store/static'; import { feConfigs } from '@/web/common/store/static';
const AIChatSettingsModal = ({ const AIChatSettingsModal = ({
onClose, onClose,

View File

@ -11,9 +11,9 @@ import React, {
import { Box, Flex, IconButton } from '@chakra-ui/react'; import { Box, Flex, IconButton } from '@chakra-ui/react';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import { FlowModuleTypeEnum } from '@/constants/flow'; import { FlowModuleTypeEnum } from '@/constants/flow';
import { streamFetch } from '@/api/fetch'; import { streamFetch } from '@/web/common/api/fetch';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import { useUserStore } from '@/store/user'; import { useUserStore } from '@/web/support/store/user';
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox'; import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
import { getGuideModule } from '@/components/ChatBox/utils'; import { getGuideModule } from '@/components/ChatBox/utils';

View File

@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { Textarea, Button, ModalBody, ModalFooter } from '@chakra-ui/react'; import { Textarea, Button, ModalBody, ModalFooter } from '@chakra-ui/react';
import MyModal from '@/components/MyModal'; import MyModal from '@/components/MyModal';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { useFlowStore } from './Provider'; import { useFlowStore } from './Provider';
const ImportSettings = ({ onClose }: { onClose: () => void }) => { const ImportSettings = ({ onClose }: { onClose: () => void }) => {

View File

@ -6,167 +6,23 @@ import Divider from '../modules/Divider';
import Container from '../modules/Container'; import Container from '../modules/Container';
import RenderInput from '../render/RenderInput'; import RenderInput from '../render/RenderInput';
import RenderOutput from '../render/RenderOutput'; import RenderOutput from '../render/RenderOutput';
import MySelect from '@/components/Select';
import { chatModelList } from '@/store/static';
import MySlider from '@/components/Slider';
import { Box, Button, useDisclosure } from '@chakra-ui/react';
import { formatPrice } from '@fastgpt/common/bill/index';
import MyIcon from '@/components/Icon';
import dynamic from 'next/dynamic';
import { AIChatProps } from '@/types/core/aiChat';
import { useFlowStore } from '../Provider';
const AIChatSettingsModal = dynamic(() => import('../../../AIChatSettingsModal')); import { useFlowStore } from '../Provider';
const NodeChat = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeChat = ({ data }: NodeProps<FlowModuleItemType>) => {
const { moduleId, inputs, outputs } = data; const { moduleId, inputs, outputs } = data;
const { onChangeNode } = useFlowStore(); const { onChangeNode } = useFlowStore();
const chatModulesData = useMemo(() => {
const obj: Record<string, any> = {};
inputs.forEach((item) => {
obj[item.key] = item.value;
});
return obj as AIChatProps;
}, [inputs]);
const {
isOpen: isOpenAIChatSetting,
onOpen: onOpenAIChatSetting,
onClose: onCloseAIChatSetting
} = useDisclosure();
return ( return (
<NodeCard minW={'400px'} {...data}> <NodeCard minW={'400px'} {...data}>
<Divider text="Input" /> <Divider text="Input" />
<Container> <Container>
<RenderInput <RenderInput moduleId={moduleId} flowInputList={inputs} />
moduleId={moduleId}
flowInputList={inputs}
CustomComponent={{
model: (inputItem) => {
const list = chatModelList.map((item) => {
const priceStr = `(${formatPrice(item.price, 1000)}元/1k Tokens)`;
return {
value: item.model,
label: `${item.name}${priceStr}`
};
});
return (
<MySelect
width={'100%'}
value={inputItem.value}
list={list}
onchange={(e) => {
onChangeNode({
moduleId,
type: 'inputs',
key: inputItem.key,
value: {
...inputItem,
value: e
}
});
// update max tokens
const model =
chatModelList.find((item) => item.model === e) || chatModelList[0];
if (!model) return;
onChangeNode({
moduleId,
type: 'inputs',
key: 'maxToken',
value: {
...inputs.find((input) => input.key === 'maxToken'),
markList: [
{ label: '100', value: 100 },
{ label: `${model.contextMaxToken}`, value: model.contextMaxToken }
],
max: model.contextMaxToken,
value: model.contextMaxToken / 2
}
});
}}
/>
);
},
maxToken: (inputItem) => {
const model = inputs.find((item) => item.key === 'model')?.value;
const modelData = chatModelList.find((item) => item.model === model);
const maxToken = modelData ? modelData.contextMaxToken : 4000;
const markList = [
{ label: '100', value: 100 },
{ label: `${maxToken}`, value: maxToken }
];
return (
<Box pt={5} pb={4} px={2}>
<MySlider
markList={markList}
width={'100%'}
min={inputItem.min || 100}
max={maxToken}
step={inputItem.step || 1}
value={inputItem.value}
onChange={(e) => {
onChangeNode({
moduleId,
type: 'inputs',
key: inputItem.key,
value: {
...inputItem,
value: e
}
});
}}
/>
</Box>
);
},
quoteQA: (inputItem) => {
return (
<Button
variant={'base'}
leftIcon={<MyIcon name={'settingLight'} w={'14px'} />}
onClick={onOpenAIChatSetting}
>
</Button>
);
}
}}
/>
</Container> </Container>
<Divider text="Output" /> <Divider text="Output" />
<Container> <Container>
<RenderOutput moduleId={moduleId} flowOutputList={outputs} /> <RenderOutput moduleId={moduleId} flowOutputList={outputs} />
</Container> </Container>
{isOpenAIChatSetting && (
<AIChatSettingsModal
onClose={onCloseAIChatSetting}
onSuccess={(e) => {
for (let key in e) {
const item = inputs.find((input) => input.key === key);
if (!item) continue;
onChangeNode({
moduleId,
type: 'inputs',
key,
value: {
...item,
// @ts-ignore
value: e[key]
}
});
}
onCloseAIChatSetting();
}}
defaultData={chatModulesData}
/>
)}
</NodeCard> </NodeCard>
); );
}; };

View File

@ -1,104 +1,20 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import { FlowModuleItemType } from '@/types/core/app/flow'; import { FlowModuleItemType } from '@/types/core/app/flow';
import { Flex, Box, Button, useTheme, useDisclosure, Grid } from '@chakra-ui/react';
import { useDatasetStore } from '@/store/dataset';
import { useQuery } from '@tanstack/react-query';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../modules/NodeCard';
import Divider from '../modules/Divider'; import Divider from '../modules/Divider';
import Container from '../modules/Container'; import Container from '../modules/Container';
import RenderInput from '../render/RenderInput'; import RenderInput from '../render/RenderInput';
import RenderOutput from '../render/RenderOutput'; import RenderOutput from '../render/RenderOutput';
import { DatasetSelectModal } from '../../../DatasetSelectModal';
import type { SelectedDatasetType } from '@/types/core/dataset';
import Avatar from '@/components/Avatar';
import { useFlowStore } from '../Provider';
const KBSelect = ({
activeKbs = [],
onChange
}: {
activeKbs: SelectedDatasetType;
onChange: (e: SelectedDatasetType) => void;
}) => {
const theme = useTheme();
const { allDatasets, loadAllDatasets } = useDatasetStore();
const {
isOpen: isOpenKbSelect,
onOpen: onOpenKbSelect,
onClose: onCloseKbSelect
} = useDisclosure();
const showKbList = useMemo(
() => allDatasets.filter((item) => activeKbs.find((kb) => kb.kbId === item._id)),
[allDatasets, activeKbs]
);
useQuery(['loadAllDatasets'], loadAllDatasets);
return (
<>
<Grid gridTemplateColumns={'1fr 1fr'} gridGap={4}>
<Button h={'36px'} onClick={onOpenKbSelect}>
</Button>
{showKbList.map((item) => (
<Flex
key={item._id}
alignItems={'center'}
h={'36px'}
border={theme.borders.base}
px={2}
borderRadius={'md'}
>
<Avatar src={item.avatar} w={'24px'}></Avatar>
<Box ml={3} fontWeight={'bold'} fontSize={['md', 'lg', 'xl']}>
{item.name}
</Box>
</Flex>
))}
</Grid>
<DatasetSelectModal
isOpen={isOpenKbSelect}
activeKbs={activeKbs}
onChange={onChange}
onClose={onCloseKbSelect}
/>
</>
);
};
const NodeKbSearch = ({ data }: NodeProps<FlowModuleItemType>) => { const NodeKbSearch = ({ data }: NodeProps<FlowModuleItemType>) => {
const { moduleId, inputs, outputs } = data; const { moduleId, inputs, outputs } = data;
const { onChangeNode } = useFlowStore();
return ( return (
<NodeCard minW={'400px'} {...data}> <NodeCard minW={'400px'} {...data}>
<Divider text="Input" /> <Divider text="Input" />
<Container> <Container>
<RenderInput <RenderInput moduleId={moduleId} flowInputList={inputs} />
moduleId={moduleId}
flowInputList={inputs}
CustomComponent={{
kbList: ({ key, value, ...props }) => (
<KBSelect
activeKbs={value}
onChange={(e) => {
onChangeNode({
moduleId,
key,
type: 'inputs',
value: {
...props,
key,
value: e
}
});
}}
/>
)
}}
/>
</Container> </Container>
<Divider text="Output" /> <Divider text="Output" />
<Container> <Container>

View File

@ -1,24 +1,18 @@
import React from 'react'; import React from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import { Box } from '@chakra-ui/react';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../modules/NodeCard';
import { FlowModuleItemType } from '@/types/core/app/flow'; import { FlowModuleItemType } from '@/types/core/app/flow';
import Container from '../modules/Container'; import Container from '../modules/Container';
import { SystemInputEnum } from '@/constants/app';
import { FlowValueTypeEnum } from '@/constants/flow'; import RenderOutput from '../render/RenderOutput';
import SourceHandle from '../render/SourceHandle';
const QuestionInputNode = ({ data }: NodeProps<FlowModuleItemType>) => { const QuestionInputNode = ({ data }: NodeProps<FlowModuleItemType>) => {
const { moduleId, inputs, outputs } = data;
return ( return (
<NodeCard minW={'240px'} {...data}> <NodeCard minW={'240px'} {...data}>
<Container borderTop={'2px solid'} borderTopColor={'myGray.200'} textAlign={'end'}> <Container borderTop={'2px solid'} borderTopColor={'myGray.200'} textAlign={'end'}>
<Box position={'relative'}> <RenderOutput moduleId={moduleId} flowOutputList={outputs} />
<SourceHandle
handleKey={SystemInputEnum.userChatInput}
valueType={FlowValueTypeEnum.string}
/>
</Box>
</Container> </Container>
</NodeCard> </NodeCard>
); );

View File

@ -26,7 +26,7 @@ import React, {
} from 'react'; } from 'react';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
import { appModule2FlowEdge, appModule2FlowNode } from '@/utils/adapt'; import { appModule2FlowEdge, appModule2FlowNode } from '@/utils/adapt';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { FlowModuleTypeEnum, FlowValueTypeEnum } from '@/constants/flow'; import { FlowModuleTypeEnum, FlowValueTypeEnum } from '@/constants/flow';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { AppModuleItemType } from '@/types/app'; import { AppModuleItemType } from '@/types/app';

View File

@ -3,7 +3,7 @@ import { Box, Flex } from '@chakra-ui/react';
import { ModuleTemplates } from '@/constants/flow/ModuleTemplate'; import { ModuleTemplates } from '@/constants/flow/ModuleTemplate';
import { FlowModuleItemType, FlowModuleTemplateType } from '@/types/core/app/flow'; import { FlowModuleItemType, FlowModuleTemplateType } from '@/types/core/app/flow';
import type { Node } from 'reactflow'; import type { Node } from 'reactflow';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/web/common/store/global';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import { FlowModuleTypeEnum } from '@/constants/flow'; import { FlowModuleTypeEnum } from '@/constants/flow';
import { useFlowStore } from './Provider'; import { useFlowStore } from './Provider';

View File

@ -6,8 +6,8 @@ import type { FlowModuleItemType } from '@/types/core/app/flow';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useEditTitle } from '@/hooks/useEditTitle'; import { useEditTitle } from '@/web/common/hooks/useEditTitle';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { useFlowStore } from '../Provider'; import { useFlowStore } from '../Provider';
type Props = FlowModuleItemType & { type Props = FlowModuleItemType & {

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React, { useMemo, useState } from 'react';
import type { FlowInputItemType, SelectAppItemType } from '@/types/core/app/flow'; import type { FlowInputItemType, SelectAppItemType } from '@/types/core/app/flow';
import { import {
Box, Box,
@ -12,20 +12,31 @@ import {
Flex, Flex,
useDisclosure, useDisclosure,
Button, Button,
useTheme useTheme,
Grid
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { FlowInputItemTypeEnum } from '@/constants/flow'; import { FlowInputItemTypeEnum } from '@/constants/flow';
import { QuestionOutlineIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon } from '@chakra-ui/icons';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { useFlowStore } from '../Provider';
import Avatar from '@/components/Avatar';
import MySelect from '@/components/Select'; import MySelect from '@/components/Select';
import MySlider from '@/components/Slider'; import MySlider from '@/components/Slider';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import TargetHandle from './TargetHandle'; import TargetHandle from './TargetHandle';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import { useTranslation } from 'react-i18next';
import { AIChatProps } from '@/types/core/aiChat';
import { chatModelList } from '@/web/common/store/static';
import { formatPrice } from '@fastgpt/common/bill';
import { useDatasetStore } from '@/web/core/store/dataset';
import { SelectedDatasetType } from '@/types/core/dataset';
import { useQuery } from '@tanstack/react-query';
const SetInputFieldModal = dynamic(() => import('../modules/SetInputFieldModal')); const SetInputFieldModal = dynamic(() => import('../modules/SetInputFieldModal'));
const SelectAppModal = dynamic(() => import('../../../SelectAppModal')); const SelectAppModal = dynamic(() => import('../../../SelectAppModal'));
import { useFlowStore } from '../Provider'; const AIChatSettingsModal = dynamic(() => import('../../../AIChatSettingsModal'));
import Avatar from '@/components/Avatar'; const DatasetSelectModal = dynamic(() => import('../../../DatasetSelectModal'));
export const Label = ({ export const Label = ({
moduleId, moduleId,
@ -145,123 +156,51 @@ const RenderInput = ({
moduleId: string; moduleId: string;
CustomComponent?: Record<string, (e: FlowInputItemType) => React.ReactNode>; CustomComponent?: Record<string, (e: FlowInputItemType) => React.ReactNode>;
}) => { }) => {
const { onChangeNode } = useFlowStore(); const sortInputs = useMemo(
() => flowInputList.sort((a, b) => (a.key === FlowInputItemTypeEnum.switch ? -1 : 1)),
[flowInputList]
);
return ( return (
<> <>
{flowInputList.map( {sortInputs.map(
(item) => (item) =>
item.type !== FlowInputItemTypeEnum.hidden && ( item.type !== FlowInputItemTypeEnum.hidden && (
<Box key={item.key} _notLast={{ mb: 7 }} position={'relative'}> <Box key={item.key} _notLast={{ mb: 7 }} position={'relative'}>
{!!item.label && <Label moduleId={moduleId} inputKey={item.key} {...item} />} {!!item.label && <Label moduleId={moduleId} inputKey={item.key} {...item} />}
<Box mt={2} className={'nodrag'}> <Box mt={2} className={'nodrag'}>
{item.type === FlowInputItemTypeEnum.numberInput && ( {item.type === FlowInputItemTypeEnum.numberInput && (
<NumberInput <NumberInputRender item={item} moduleId={moduleId} />
defaultValue={item.value}
min={item.min}
max={item.max}
onChange={(e) => {
onChangeNode({
moduleId,
type: 'inputs',
key: item.key,
value: {
...item,
value: Number(e)
}
});
}}
>
<NumberInputField />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
)} )}
{item.type === FlowInputItemTypeEnum.input && ( {item.type === FlowInputItemTypeEnum.input && (
<Input <TextInputRender item={item} moduleId={moduleId} />
placeholder={item.placeholder}
defaultValue={item.value}
onChange={(e) => {
onChangeNode({
moduleId,
type: 'inputs',
key: item.key,
value: {
...item,
value: e.target.value
}
});
}}
/>
)} )}
{item.type === FlowInputItemTypeEnum.textarea && ( {item.type === FlowInputItemTypeEnum.textarea && (
<Textarea <TextareaRender item={item} moduleId={moduleId} />
rows={5}
placeholder={item.placeholder}
resize={'both'}
defaultValue={item.value}
onChange={(e) => {
onChangeNode({
moduleId,
type: 'inputs',
key: item.key,
value: {
...item,
value: e.target.value
}
});
}}
/>
)} )}
{item.type === FlowInputItemTypeEnum.select && ( {item.type === FlowInputItemTypeEnum.select && (
<MySelect <SelectRender item={item} moduleId={moduleId} />
width={'100%'}
value={item.value}
list={item.list || []}
onchange={(e) => {
onChangeNode({
moduleId,
type: 'inputs',
key: item.key,
value: {
...item,
value: e
}
});
}}
/>
)} )}
{item.type === FlowInputItemTypeEnum.slider && ( {item.type === FlowInputItemTypeEnum.slider && (
<Box pt={5} pb={4} px={2}> <SliderRender item={item} moduleId={moduleId} />
<MySlider )}
markList={item.markList} {item.type === FlowInputItemTypeEnum.selectApp && (
width={'100%'} <SelectAppRender item={item} moduleId={moduleId} />
min={item.min || 0} )}
max={item.max} {item.type === FlowInputItemTypeEnum.quoteList && (
step={item.step || 1} <QuoteListRender inputs={sortInputs} item={item} moduleId={moduleId} />
value={item.value} )}
onChange={(e) => { {item.type === FlowInputItemTypeEnum.maxToken && (
onChangeNode({ <MaxTokenRender inputs={sortInputs} item={item} moduleId={moduleId} />
moduleId, )}
type: 'inputs', {item.type === FlowInputItemTypeEnum.selectChatModel && (
key: item.key, <SelectChatModelRender inputs={sortInputs} item={item} moduleId={moduleId} />
value: { )}
...item, {item.type === FlowInputItemTypeEnum.selectDataset && (
value: e <SelectDatasetRender item={item} moduleId={moduleId} />
}
});
}}
/>
</Box>
)} )}
{item.type === FlowInputItemTypeEnum.custom && CustomComponent[item.key] && ( {item.type === FlowInputItemTypeEnum.custom && CustomComponent[item.key] && (
<>{CustomComponent[item.key]({ ...item })}</> <>{CustomComponent[item.key]({ ...item })}</>
)} )}
{item.type === FlowInputItemTypeEnum.selectApp && (
<RenderSelectApp app={item} moduleId={moduleId} />
)}
</Box> </Box>
</Box> </Box>
) )
@ -272,7 +211,346 @@ const RenderInput = ({
export default React.memo(RenderInput); export default React.memo(RenderInput);
function RenderSelectApp({ app, moduleId }: { app: FlowInputItemType; moduleId: string }) { type RenderProps = {
inputs?: FlowInputItemType[];
item: FlowInputItemType;
moduleId: string;
};
var NumberInputRender = React.memo(function NumberInputRender({ item, moduleId }: RenderProps) {
const { onChangeNode } = useFlowStore();
return (
<NumberInput
defaultValue={item.value}
min={item.min}
max={item.max}
onChange={(e) => {
onChangeNode({
moduleId,
type: 'inputs',
key: item.key,
value: {
...item,
value: Number(e)
}
});
}}
>
<NumberInputField />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
);
});
var TextInputRender = React.memo(function TextInputRender({ item, moduleId }: RenderProps) {
const { onChangeNode } = useFlowStore();
return (
<Input
placeholder={item.placeholder}
defaultValue={item.value}
onChange={(e) => {
onChangeNode({
moduleId,
type: 'inputs',
key: item.key,
value: {
...item,
value: e.target.value
}
});
}}
/>
);
});
var TextareaRender = React.memo(function TextareaRender({ item, moduleId }: RenderProps) {
const { onChangeNode } = useFlowStore();
return (
<Textarea
rows={5}
placeholder={item.placeholder}
resize={'both'}
defaultValue={item.value}
onChange={(e) => {
onChangeNode({
moduleId,
type: 'inputs',
key: item.key,
value: {
...item,
value: e.target.value
}
});
}}
/>
);
});
var SelectRender = React.memo(function SelectRender({ item, moduleId }: RenderProps) {
const { onChangeNode } = useFlowStore();
return (
<MySelect
width={'100%'}
value={item.value}
list={item.list || []}
onchange={(e) => {
onChangeNode({
moduleId,
type: 'inputs',
key: item.key,
value: {
...item,
value: e
}
});
}}
/>
);
});
var SliderRender = React.memo(function SliderRender({ item, moduleId }: RenderProps) {
const { onChangeNode } = useFlowStore();
return (
<Box pt={5} pb={4} px={2}>
<MySlider
markList={item.markList}
width={'100%'}
min={item.min || 0}
max={item.max}
step={item.step || 1}
value={item.value}
onChange={(e) => {
onChangeNode({
moduleId,
type: 'inputs',
key: item.key,
value: {
...item,
value: e
}
});
}}
/>
</Box>
);
});
var QuoteListRender = React.memo(function QuoteListRender({ inputs = [], moduleId }: RenderProps) {
const { onChangeNode } = useFlowStore();
const { t } = useTranslation();
const chatModulesData = useMemo(() => {
const obj: Record<string, any> = {};
inputs.forEach((item) => {
obj[item.key] = item.value;
});
return obj as AIChatProps;
}, [inputs]);
const {
isOpen: isOpenAIChatSetting,
onOpen: onOpenAIChatSetting,
onClose: onCloseAIChatSetting
} = useDisclosure();
return (
<>
<Button
variant={'base'}
leftIcon={<MyIcon name={'settingLight'} w={'14px'} />}
onClick={onOpenAIChatSetting}
>
{t('app.Quote Prompt Settings')}
</Button>
{isOpenAIChatSetting && (
<AIChatSettingsModal
onClose={onCloseAIChatSetting}
onSuccess={(e) => {
for (let key in e) {
const item = inputs.find((input) => input.key === key);
if (!item) continue;
onChangeNode({
moduleId,
type: 'inputs',
key,
value: {
...item,
//@ts-ignore
value: e[key]
}
});
}
onCloseAIChatSetting();
}}
defaultData={chatModulesData}
/>
)}
</>
);
});
var MaxTokenRender = React.memo(function MaxTokenRender({
inputs = [],
item,
moduleId
}: RenderProps) {
const { onChangeNode } = useFlowStore();
const model = inputs.find((item) => item.key === 'model')?.value;
const modelData = chatModelList.find((item) => item.model === model);
const maxToken = modelData ? modelData.contextMaxToken : 4000;
const markList = [
{ label: '100', value: 100 },
{ label: `${maxToken}`, value: maxToken }
];
return (
<Box pt={5} pb={4} px={2}>
<MySlider
markList={markList}
width={'100%'}
min={item.min || 100}
max={maxToken}
step={item.step || 1}
value={item.value}
onChange={(e) => {
onChangeNode({
moduleId,
type: 'inputs',
key: item.key,
value: {
...item,
value: e
}
});
}}
/>
</Box>
);
});
var SelectChatModelRender = React.memo(function SelectChatModelRender({
inputs = [],
item,
moduleId
}: RenderProps) {
const { onChangeNode } = useFlowStore();
const list = chatModelList.map((item) => {
const priceStr = `(${formatPrice(item.price, 1000)}元/1k Tokens)`;
return {
value: item.model,
label: `${item.name}${priceStr}`
};
});
return (
<MySelect
width={'100%'}
value={item.value}
list={list}
onchange={(e) => {
onChangeNode({
moduleId,
type: 'inputs',
key: item.key,
value: {
...item,
value: e
}
});
// update max tokens
const model = chatModelList.find((item) => item.model === e) || chatModelList[0];
if (!model) return;
onChangeNode({
moduleId,
type: 'inputs',
key: 'maxToken',
value: {
...inputs.find((input) => input.key === 'maxToken'),
markList: [
{ label: '100', value: 100 },
{ label: `${model.contextMaxToken}`, value: model.contextMaxToken }
],
max: model.contextMaxToken,
value: model.contextMaxToken / 2
}
});
}}
/>
);
});
var SelectDatasetRender = React.memo(function SelectDatasetRender({ item, moduleId }: RenderProps) {
const { onChangeNode } = useFlowStore();
const theme = useTheme();
const { allDatasets, loadAllDatasets } = useDatasetStore();
const {
isOpen: isOpenKbSelect,
onOpen: onOpenKbSelect,
onClose: onCloseKbSelect
} = useDisclosure();
const showKbList = useMemo(() => {
const value = item.value as SelectedDatasetType;
return allDatasets.filter((dataset) => value.find((kb) => kb.kbId === dataset._id));
}, [allDatasets, item.value]);
useQuery(['loadAllDatasets'], loadAllDatasets);
return (
<>
<Grid gridTemplateColumns={'1fr 1fr'} gridGap={4}>
<Button h={'36px'} onClick={onOpenKbSelect}>
</Button>
{showKbList.map((item) => (
<Flex
key={item._id}
alignItems={'center'}
h={'36px'}
border={theme.borders.base}
px={2}
borderRadius={'md'}
>
<Avatar src={item.avatar} w={'24px'}></Avatar>
<Box ml={3} fontWeight={'bold'} fontSize={['md', 'lg', 'xl']}>
{item.name}
</Box>
</Flex>
))}
</Grid>
<DatasetSelectModal
isOpen={isOpenKbSelect}
activeKbs={item.value}
onChange={(e) => {
onChangeNode({
moduleId,
key: item.key,
type: 'inputs',
value: {
...item,
value: e
}
});
}}
onClose={onCloseKbSelect}
/>
</>
);
});
var SelectAppRender = React.memo(function SelectAppRender({ item, moduleId }: RenderProps) {
const { onChangeNode, appId } = useFlowStore(); const { onChangeNode, appId } = useFlowStore();
const theme = useTheme(); const theme = useTheme();
@ -282,7 +560,7 @@ function RenderSelectApp({ app, moduleId }: { app: FlowInputItemType; moduleId:
onClose: onCloseSelectApp onClose: onCloseSelectApp
} = useDisclosure(); } = useDisclosure();
const value = app.value as SelectAppItemType | undefined; const value = item.value as SelectAppItemType | undefined;
return ( return (
<> <>
@ -303,7 +581,7 @@ function RenderSelectApp({ app, moduleId }: { app: FlowInputItemType; moduleId:
{isOpenSelectApp && ( {isOpenSelectApp && (
<SelectAppModal <SelectAppModal
defaultApps={app.value?.id ? [app.value.id] : []} defaultApps={item.value?.id ? [item.value.id] : []}
filterApps={[appId]} filterApps={[appId]}
onClose={onCloseSelectApp} onClose={onCloseSelectApp}
onSuccess={(e) => { onSuccess={(e) => {
@ -312,7 +590,7 @@ function RenderSelectApp({ app, moduleId }: { app: FlowInputItemType; moduleId:
type: 'inputs', type: 'inputs',
key: 'app', key: 'app',
value: { value: {
...app, ...item,
value: e[0] value: e[0]
} }
}); });
@ -321,4 +599,4 @@ function RenderSelectApp({ app, moduleId }: { app: FlowInputItemType; moduleId:
)} )}
</> </>
); );
} });

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React, { useMemo, useState } from 'react';
import type { FlowOutputItemType } from '@/types/core/app/flow'; import type { FlowOutputItemType } from '@/types/core/app/flow';
import { Box, Flex } from '@chakra-ui/react'; import { Box, Flex } from '@chakra-ui/react';
import { FlowOutputItemTypeEnum } from '@/constants/flow'; import { FlowOutputItemTypeEnum } from '@/constants/flow';
@ -9,6 +9,7 @@ import MyIcon from '@/components/Icon';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
const SetOutputFieldModal = dynamic(() => import('../modules/SetOutputFieldModal')); const SetOutputFieldModal = dynamic(() => import('../modules/SetOutputFieldModal'));
import { useFlowStore } from '../Provider'; import { useFlowStore } from '../Provider';
import { SystemOutputEnum } from '@/constants/app';
const Label = ({ const Label = ({
moduleId, moduleId,
@ -127,13 +128,17 @@ const RenderOutput = ({
moduleId: string; moduleId: string;
flowOutputList: FlowOutputItemType[]; flowOutputList: FlowOutputItemType[];
}) => { }) => {
const sortOutput = useMemo(
() => flowOutputList.sort((a, b) => (a.key === SystemOutputEnum.finish ? -1 : 1)),
[flowOutputList]
);
return ( return (
<> <>
{flowOutputList.map( {sortOutput.map(
(item) => (item) =>
item.type !== FlowOutputItemTypeEnum.hidden && ( item.type !== FlowOutputItemTypeEnum.hidden && (
<Box key={item.key} _notLast={{ mb: 7 }} position={'relative'}> <Box key={item.key} _notLast={{ mb: 7 }} position={'relative'}>
<Label moduleId={moduleId} outputKey={item.key} outputs={flowOutputList} {...item} /> <Label moduleId={moduleId} outputKey={item.key} outputs={sortOutput} {...item} />
<Box mt={FlowOutputItemTypeEnum.answer ? 0 : 2} className={'nodrag'}> <Box mt={FlowOutputItemTypeEnum.answer ? 0 : 2} className={'nodrag'}>
{item.type === FlowOutputItemTypeEnum.source && ( {item.type === FlowOutputItemTypeEnum.source && (
<SourceHandle handleKey={item.key} valueType={item.valueType} /> <SourceHandle handleKey={item.key} valueType={item.valueType} />

View File

@ -10,11 +10,11 @@ import {
} from '@/constants/flow'; } from '@/constants/flow';
import { FlowOutputTargetItemType } from '@/types/core/app/flow'; import { FlowOutputTargetItemType } from '@/types/core/app/flow';
import { AppModuleItemType } from '@/types/app'; import { AppModuleItemType } from '@/types/app';
import { useRequest } from '@/hooks/useRequest'; import { useRequest } from '@/web/common/hooks/useRequest';
import type { AppSchema } from '@/types/mongoSchema'; import type { AppSchema } from '@/types/mongoSchema';
import { useUserStore } from '@/store/user'; import { useUserStore } from '@/web/support/store/user';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useCopyData } from '@/hooks/useCopyData'; import { useCopyData } from '@/web/common/hooks/useCopyData';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import styles from './index.module.scss'; import styles from './index.module.scss';
import { AppTypeEnum } from '@/constants/app'; import { AppTypeEnum } from '@/constants/app';
@ -125,6 +125,9 @@ function FlowHeader({ app, onCloseSettings }: Props & {}) {
if (item.inputs.find((input) => input.required && !input.connected)) { if (item.inputs.find((input) => input.required && !input.connected)) {
return Promise.reject(`${item.name}】存在未连接的必填输入`); return Promise.reject(`${item.name}】存在未连接的必填输入`);
} }
if (item.inputs.find((input) => input.valueCheck && !input.valueCheck(input.value))) {
return Promise.reject(`${item.name}】存在为填写的必填项`);
}
} }
return updateAppDetail(app._id, { return updateAppDetail(app._id, {

View File

@ -19,18 +19,18 @@ import {
Text, Text,
Switch Switch
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useUserStore } from '@/store/user'; import { useUserStore } from '@/web/support/store/user';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { QuestionOutlineIcon, SmallAddIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon, SmallAddIcon } from '@chakra-ui/icons';
import { useForm, useFieldArray } from 'react-hook-form'; import { useForm, useFieldArray } from 'react-hook-form';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/web/common/store/global';
import { import {
appModules2Form, appModules2Form,
getDefaultAppForm, getDefaultAppForm,
appForm2Modules, appForm2Modules,
type EditFormType type EditFormType
} from '@/utils/app'; } from '@/utils/app';
import { chatModelList } from '@/store/static'; import { chatModelList } from '@/web/common/store/static';
import { formatPrice } from '@fastgpt/common/bill/index'; import { formatPrice } from '@fastgpt/common/bill/index';
import { import {
ChatModelSystemTip, ChatModelSystemTip,
@ -39,14 +39,14 @@ import {
questionGuideTip questionGuideTip
} from '@/constants/flow/ModuleTemplate'; } from '@/constants/flow/ModuleTemplate';
import { AppModuleItemType, VariableItemType } from '@/types/app'; import { AppModuleItemType, VariableItemType } from '@/types/app';
import { useRequest } from '@/hooks/useRequest'; import { useRequest } from '@/web/common/hooks/useRequest';
import { useConfirm } from '@/hooks/useConfirm'; import { useConfirm } from '@/web/common/hooks/useConfirm';
import { FlowModuleTypeEnum } from '@/constants/flow'; import { FlowModuleTypeEnum } from '@/constants/flow';
import { streamFetch } from '@/api/fetch'; import { streamFetch } from '@/web/common/api/fetch';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/web/common/hooks/useToast';
import { AppSchema } from '@/types/mongoSchema'; import { AppSchema } from '@/types/mongoSchema';
import { delModelById } from '@/api/app'; import { delModelById } from '@/web/core/api/app';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { getGuideModule } from '@/components/ChatBox/utils'; import { getGuideModule } from '@/components/ChatBox/utils';
@ -61,7 +61,7 @@ import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/
import { addVariable } from '../VariableEditModal'; import { addVariable } from '../VariableEditModal';
import { KbParamsModal } from '../DatasetSelectModal'; import { KbParamsModal } from '../DatasetSelectModal';
import { AppTypeEnum } from '@/constants/app'; import { AppTypeEnum } from '@/constants/app';
import { useDatasetStore } from '@/store/dataset'; import { useDatasetStore } from '@/web/core/store/dataset';
const VariableEditModal = dynamic(() => import('../VariableEditModal')); const VariableEditModal = dynamic(() => import('../VariableEditModal'));
const InfoModal = dynamic(() => import('../InfoModal')); const InfoModal = dynamic(() => import('../InfoModal'));

Some files were not shown because too many files have changed in this diff Show More