diff --git a/README.md b/README.md
index d9eaf8822..51e632300 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
English |
简体中文 |
- 日本語
+ 日语
FastGPT 是一个基于 LLM 大语言模型的知识库问答系统,提供开箱即用的数据处理、模型调用等能力。同时可以通过 Flow 可视化进行工作流编排,从而实现复杂的问答场景!
diff --git a/README_en.md b/README_en.md
index 33a95ee05..1cafbc423 100644
--- a/README_en.md
+++ b/README_en.md
@@ -7,7 +7,7 @@
English |
简体中文 |
- 日本語
+ 日语
FastGPT is a knowledge-based Q&A system built on the LLM, offers out-of-the-box data processing and model invocation capabilities, allows for workflow orchestration through Flow visualization!
diff --git a/README_ja.md b/README_ja.md
index 1a2684ab4..5946c227f 100644
--- a/README_ja.md
+++ b/README_ja.md
@@ -7,7 +7,7 @@
English |
简体中文 |
- 日本語
+ 日语
FastGPT は、LLM 上 に 構築 された 知識 ベースの Q&A システムで、すぐに 使 えるデータ 処理 とモデル 呼 び 出 し 機能 を 提供 し、Flow の 可視化 を 通 じてワークフローのオーケストレーションを 可能 にします!
diff --git a/docSite/content/docs/installation/upgrading/43.md b/docSite/content/docs/installation/upgrading/43.md
index 6aca74023..b8506ac88 100644
--- a/docSite/content/docs/installation/upgrading/43.md
+++ b/docSite/content/docs/installation/upgrading/43.md
@@ -1,5 +1,5 @@
---
-title: '升级到 V4.3'
+title: '升级到 V4.3(需要初始化)'
description: 'FastGPT 从旧版本升级到 V4.3 操作指南'
icon: 'upgrade'
draft: false
diff --git a/docSite/content/docs/installation/upgrading/44.md b/docSite/content/docs/installation/upgrading/44.md
index 27d138fe4..e9fd3ff0c 100644
--- a/docSite/content/docs/installation/upgrading/44.md
+++ b/docSite/content/docs/installation/upgrading/44.md
@@ -1,5 +1,5 @@
---
-title: '升级到 V4.4'
+title: '升级到 V4.4(需要初始化)'
description: 'FastGPT 从旧版本升级到 V4.4 操作指南'
icon: 'upgrade'
draft: false
diff --git a/docSite/content/docs/installation/upgrading/441.md b/docSite/content/docs/installation/upgrading/441.md
index 0721627f2..a133038c3 100644
--- a/docSite/content/docs/installation/upgrading/441.md
+++ b/docSite/content/docs/installation/upgrading/441.md
@@ -1,5 +1,5 @@
---
-title: '升级到 V4.4.1'
+title: '升级到 V4.4.1(需要初始化)'
description: 'FastGPT 从旧版本升级到 V4.4.1 操作指南'
icon: 'upgrade'
draft: false
diff --git a/docSite/content/docs/installation/upgrading/442.md b/docSite/content/docs/installation/upgrading/442.md
index 0c5832931..de0f66383 100644
--- a/docSite/content/docs/installation/upgrading/442.md
+++ b/docSite/content/docs/installation/upgrading/442.md
@@ -1,5 +1,5 @@
---
-title: '升级到 V4.4.2'
+title: '升级到 V4.4.2(需要初始化)'
description: 'FastGPT 从旧版本升级到 V4.4.2 操作指南'
icon: 'upgrade'
draft: false
diff --git a/docSite/content/docs/installation/upgrading/445.md b/docSite/content/docs/installation/upgrading/445.md
index 8dae7384c..c4162dd07 100644
--- a/docSite/content/docs/installation/upgrading/445.md
+++ b/docSite/content/docs/installation/upgrading/445.md
@@ -1,6 +1,6 @@
---
-title: 'V4.4.5'
-description: 'FastGPT V4.4.5 更新(需执行升级脚本)'
+title: 'V4.4.5(需要初始化)'
+description: 'FastGPT V4.4.5 更新'
icon: 'upgrade'
draft: false
toc: true
diff --git a/projects/app/public/locales/en/common.json b/projects/app/public/locales/en/common.json
index 4f9d7ccae..ee93bc5e8 100644
--- a/projects/app/public/locales/en/common.json
+++ b/projects/app/public/locales/en/common.json
@@ -201,7 +201,8 @@
"Drag Tip": "Click and move",
"Move Success": "Move Success",
"No Folder": "There's no subdirectory. Just put it here",
- "Root Path": "Root Folder"
+ "Root Path": "Root Folder",
+ "empty": "There is nothing to choose from in this directory"
},
"input": {
"Repeat Value": "Repeat Value"
@@ -237,6 +238,7 @@
"Record": "Speech",
"Restart": "Restart",
"Select File": "Select file",
+ "Select Image": "Select Image",
"Send Message": "Send Message",
"Speaking": "I'm listening...",
"Stop Speak": "Stop Speak",
@@ -286,6 +288,7 @@
"My Dataset": "My Dataset",
"Queue Desc": "This data refers to the current amount of training for the entire system. FastGPT uses queued training, and if you have too much data to train, you may need to wait for a while",
"Select Dataset": "Select Dataset",
+ "Select Dataset Tips": "Select only knowledge bases with the same index model",
"Select Folder": "Enter folder",
"System Data Queue": "Data Queue",
"Training Name": "Dataset Training",
diff --git a/projects/app/public/locales/zh/common.json b/projects/app/public/locales/zh/common.json
index 27007ef59..29f9e21a6 100644
--- a/projects/app/public/locales/zh/common.json
+++ b/projects/app/public/locales/zh/common.json
@@ -201,7 +201,8 @@
"Drag Tip": "点我可拖动",
"Move Success": "移动成功",
"No Folder": "没有子目录了,就放这里吧",
- "Root Path": "根目录"
+ "Root Path": "根目录",
+ "empty": "这个目录已经没东西可选了~"
},
"input": {
"Repeat Value": "有重复的值"
@@ -237,6 +238,7 @@
"Record": "语音输入",
"Restart": "重开对话",
"Select File": "选择文件",
+ "Select Image": "选择图片",
"Send Message": "发送",
"Speaking": "我在听,请说...",
"Stop Speak": "停止录音",
@@ -286,6 +288,7 @@
"My Dataset": "我的知识库",
"Queue Desc": "该数据是指整个系统当前待训练的数量。{{title}} 采用排队训练的方式,如果待训练的数据过多,可能需要等待一段时间",
"Select Dataset": "选择该知识库",
+ "Select Dataset Tips": "仅能选择同一个索引模型的知识库",
"Select Folder": "进入文件夹",
"System Data Queue": "排队长度",
"Training Name": "数据训练",
diff --git a/projects/app/src/components/ChatBox/MessageInput.tsx b/projects/app/src/components/ChatBox/MessageInput.tsx
index 5f33e6c7c..88568e75f 100644
--- a/projects/app/src/components/ChatBox/MessageInput.tsx
+++ b/projects/app/src/components/ChatBox/MessageInput.tsx
@@ -185,6 +185,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
boxShadow={isSpeaking ? `0 0 10px rgba(54,111,255,0.4)` : `0 0 10px rgba(0,0,0,0.2)`}
borderRadius={['none', 'md']}
bg={'white'}
+ overflow={'hidden'}
{...(isPc
? {
border: '1px solid',
@@ -289,8 +290,8 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
onOpenSelectFile();
}}
>
-
-
+
+
diff --git a/projects/app/src/components/ChatBox/QuoteModal.tsx b/projects/app/src/components/ChatBox/QuoteModal.tsx
index 7c4b3ce7e..07d82f1ee 100644
--- a/projects/app/src/components/ChatBox/QuoteModal.tsx
+++ b/projects/app/src/components/ChatBox/QuoteModal.tsx
@@ -69,12 +69,12 @@ const QuoteModal = ({
isCentered
minW={['90vw', '600px']}
title={
- <>
+
知识库引用({rawSearch.length}条)
注意: 修改知识库内容成功后,此处不会显示变更情况。点击编辑后,会显示知识库最新的内容。
- >
+
}
>
diff --git a/projects/app/src/components/ChatBox/SelectMarkCollection.tsx b/projects/app/src/components/ChatBox/SelectMarkCollection.tsx
index 6a11d22ee..529993d37 100644
--- a/projects/app/src/components/ChatBox/SelectMarkCollection.tsx
+++ b/projects/app/src/components/ChatBox/SelectMarkCollection.tsx
@@ -45,7 +45,6 @@ const SelectMarkCollection = ({
isOpen
paths={paths}
onClose={onClose}
- parentId={parentId}
setParentId={setParentId}
tips={t('chat.Select Mark Kb Desc')}
>
diff --git a/projects/app/src/components/Icon/icons/common/pause.svg b/projects/app/src/components/Icon/icons/common/pause.svg
deleted file mode 100644
index db3a12833..000000000
--- a/projects/app/src/components/Icon/icons/common/pause.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/projects/app/src/components/Icon/icons/light/app.svg b/projects/app/src/components/Icon/icons/light/app.svg
deleted file mode 100644
index 4f4f4d354..000000000
--- a/projects/app/src/components/Icon/icons/light/app.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/projects/app/src/components/Icon/index.tsx b/projects/app/src/components/Icon/index.tsx
index debe39f1f..d2363658e 100644
--- a/projects/app/src/components/Icon/index.tsx
+++ b/projects/app/src/components/Icon/index.tsx
@@ -3,10 +3,7 @@ import type { IconProps } from '@chakra-ui/react';
import { Icon } from '@chakra-ui/react';
const iconPaths = {
- appFill: () => import('./icons/fill/app.svg'),
- appLight: () => import('./icons/light/app.svg'),
copy: () => import('./icons/copy.svg'),
- chatSend: () => import('./icons/chatSend.svg'),
delete: () => import('./icons/delete.svg'),
stop: () => import('./icons/stop.svg'),
collectionLight: () => import('./icons/collectionLight.svg'),
@@ -89,7 +86,6 @@ const iconPaths = {
moveLight: () => import('./icons/light/move.svg'),
questionGuide: () => import('./icons/app/questionGuide.svg'),
loading: () => import('./icons/light/loading.svg'),
- pause: () => import('./icons/common/pause.svg'),
'core/app/aiLight': () => import('./icons/core/app/aiLight.svg'),
'core/app/aiFill': () => import('./icons/core/app/aiFill.svg'),
'common/text/t': () => import('./icons/common/text/t.svg'),
diff --git a/projects/app/src/components/MyModal/index.tsx b/projects/app/src/components/MyModal/index.tsx
index 72627d605..d24fe5c6c 100644
--- a/projects/app/src/components/MyModal/index.tsx
+++ b/projects/app/src/components/MyModal/index.tsx
@@ -39,7 +39,7 @@ const MyModal = ({
minW={['90vw', '400px']}
maxW={maxW}
position={'relative'}
- maxH={'90vh'}
+ maxH={['80vh', '85vh']}
{...props}
>
{!title && onClose && }
diff --git a/projects/app/src/components/common/ParentPaths/index.tsx b/projects/app/src/components/common/ParentPaths/index.tsx
index 72a4939a0..6adabdae0 100644
--- a/projects/app/src/components/common/ParentPaths/index.tsx
+++ b/projects/app/src/components/common/ParentPaths/index.tsx
@@ -26,9 +26,9 @@ const ParentPaths = (props: {
return paths.length === 0 && !!FirstPathDom ? (
<>{FirstPathDom}>
) : (
-
+
{concatPaths.map((item, i) => (
-
+
{i !== concatPaths.length - 1 && (
-
+
)}
))}
diff --git a/projects/app/src/components/core/dataset/SelectModal.tsx b/projects/app/src/components/core/dataset/SelectModal.tsx
index b6eb3075e..558cca8c7 100644
--- a/projects/app/src/components/core/dataset/SelectModal.tsx
+++ b/projects/app/src/components/core/dataset/SelectModal.tsx
@@ -6,6 +6,7 @@ import { useTranslation } from 'next-i18next';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { Box, Flex, ModalHeader } from '@chakra-ui/react';
import MyIcon from '@/components/Icon';
+import ParentPaths from '@/components/common/ParentPaths';
type PathItemType = {
parentId: string;
@@ -14,7 +15,6 @@ type PathItemType = {
const DatasetSelectContainer = ({
isOpen,
- parentId,
setParentId,
paths,
onClose,
@@ -22,7 +22,6 @@ const DatasetSelectContainer = ({
children
}: {
isOpen: boolean;
- parentId?: string;
setParentId: Dispatch;
paths: PathItemType[];
onClose: () => void;
@@ -35,45 +34,17 @@ const DatasetSelectContainer = ({
return (
-
- {!!parentId ? (
-
- {paths.map((item, i) => (
-
- {
- setParentId(item.parentId);
- }
- })}
- >
- {item.parentName}
-
- {i !== paths.length - 1 && (
-
- )}
-
- ))}
-
- ) : (
- {t('chat.Select Mark Kb')}
- )}
+
+ ({
+ parentId: path.parentId,
+ parentName: path.parentName
+ }))}
+ FirstPathDom={t('chat.Select Mark Kb')}
+ onClick={(e) => {
+ setParentId(e);
+ }}
+ />
{!!tips && (
{tips}
@@ -94,16 +65,7 @@ export function useDatasetSelect() {
Promise.all([getDatasets({ parentId }), getDatasetPaths(parentId)])
);
- const paths = useMemo(
- () => [
- {
- parentId: '',
- parentName: t('dataset.My Dataset')
- },
- ...(data?.[1] || [])
- ],
- [data, t]
- );
+ const paths = useMemo(() => [...(data?.[1] || [])], [data]);
return {
parentId,
diff --git a/projects/app/src/components/core/module/DatasetSelectModal.tsx b/projects/app/src/components/core/module/DatasetSelectModal.tsx
index bd2fe6fb3..afda0bca5 100644
--- a/projects/app/src/components/core/module/DatasetSelectModal.tsx
+++ b/projects/app/src/components/core/module/DatasetSelectModal.tsx
@@ -26,6 +26,8 @@ import { useTranslation } from 'next-i18next';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { feConfigs } from '@/web/common/system/staticData';
import DatasetSelectContainer, { useDatasetSelect } from '@/components/core/dataset/SelectModal';
+import { useLoading } from '@/web/common/hooks/useLoading';
+import EmptyTip from '@/components/EmptyTip';
export type KbParamsType = {
searchSimilarity: number;
@@ -54,7 +56,8 @@ export const DatasetSelectModal = ({
})
);
const { toast } = useToast();
- const { paths, parentId, setParentId, datasets } = useDatasetSelect();
+ const { paths, setParentId, datasets, isLoading } = useDatasetSelect();
+ const { Loading } = useLoading();
const filterKbList = useMemo(() => {
return {
@@ -71,9 +74,8 @@ export const DatasetSelectModal = ({
@@ -158,7 +160,7 @@ export const DatasetSelectModal = ({
if (vectorModel && vectorModel !== item.vectorModel.model) {
return toast({
status: 'warning',
- title: '仅能选择同一个索引模型的知识库'
+ title: t('dataset.Select Dataset Tips')
});
}
setSelectedKbList((state) => [
@@ -197,14 +199,7 @@ export const DatasetSelectModal = ({
})()
)}
- {filterKbList.unSelected.length === 0 && (
-
-
-
- 这个目录已经没东西可选了~
-
-
- )}
+ {filterKbList.unSelected.length === 0 && }
@@ -219,9 +214,11 @@ export const DatasetSelectModal = ({
onChange(filterKbList);
}}
>
- 完成
+ {t('common.Done')}
+
+
);
diff --git a/projects/app/src/pages/api/admin/initv46-fix.ts b/projects/app/src/pages/api/admin/initv46-fix.ts
index 0a639b9ab..1aeb05f2a 100644
--- a/projects/app/src/pages/api/admin/initv46-fix.ts
+++ b/projects/app/src/pages/api/admin/initv46-fix.ts
@@ -12,6 +12,8 @@ import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
import { Types, connectionMongo } from '@fastgpt/service/common/mongo';
import { TeamMemberCollectionName } from '@fastgpt/global/support/user/team/constant';
+import { getUserDefaultTeam } from '@fastgpt/service/support/user/team/controller';
+import { getGFSCollection } from '@fastgpt/service/common/file/gridfs/controller';
let success = 0;
/* pg 中的数据搬到 mongo dataset.datas 中,并做映射 */
@@ -22,9 +24,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
await connectToDatabase();
success = 0;
- jsonRes(res, {
- data: await init(limit)
- });
+ await init(limit);
+ await initCollectionFileTeam(limit);
+
+ jsonRes(res, {});
} catch (error) {
console.log(error);
@@ -103,3 +106,71 @@ async function init(limit: number): Promise {
}
}
}
+
+async function initCollectionFileTeam(limit: number) {
+ /* init user default Team */
+ const DatasetFile = getGFSCollection('dataset');
+ const matchWhere = {
+ $or: [{ 'metadata.teamId': { $exists: false } }, { 'metadata.teamId': null }]
+ };
+ const uniqueUsersWithNoTeamId = await DatasetFile.aggregate([
+ {
+ $match: matchWhere
+ },
+ {
+ $group: {
+ _id: '$metadata.userId', // 按 metadata.userId 分组以去重
+ userId: { $first: '$metadata.userId' } // 保留第一个出现的 userId
+ }
+ },
+ {
+ $project: {
+ _id: 0, // 不显示 _id 字段
+ userId: 1 // 只显示 userId 字段
+ }
+ }
+ ]).toArray();
+ const users = uniqueUsersWithNoTeamId;
+
+ console.log('un init total', users.length);
+ // limit 组一次
+ const userArr: any[][] = [];
+ for (let i = 0; i < users.length; i += limit) {
+ userArr.push(users.slice(i, i + limit));
+ }
+
+ let success = 0;
+ for await (const item of userArr) {
+ await Promise.all(item.map((item) => init(item.userId)));
+ success += limit;
+ console.log(success);
+ }
+
+ async function init(userId: string): Promise {
+ try {
+ const tmb = await getUserDefaultTeam({
+ userId
+ });
+
+ await DatasetFile.updateMany(
+ {
+ 'metadata.userId': String(userId),
+ ...matchWhere
+ },
+ {
+ $set: {
+ 'metadata.teamId': String(tmb.teamId),
+ 'metadata.tmbId': String(tmb.tmbId)
+ }
+ }
+ );
+ } catch (error) {
+ if (error === 'team not exist' || error === 'tmbId or userId is required') {
+ return;
+ }
+ console.log(error);
+ await delay(1000);
+ return init(userId);
+ }
+ }
+}
diff --git a/projects/app/src/pages/api/admin/initv46.ts b/projects/app/src/pages/api/admin/initv46.ts
index a8a55f9f1..85f0cda59 100644
--- a/projects/app/src/pages/api/admin/initv46.ts
+++ b/projects/app/src/pages/api/admin/initv46.ts
@@ -264,7 +264,7 @@ async function initCollectionFileTeam(limit: number) {
await DatasetFile.updateMany(
{
- userId,
+ 'metadata.userId': String(userId),
...matchWhere
},
{
diff --git a/projects/app/src/pages/app/detail/components/BasicEdit/index.tsx b/projects/app/src/pages/app/detail/components/BasicEdit/index.tsx
index f567eabe2..500e85ebf 100644
--- a/projects/app/src/pages/app/detail/components/BasicEdit/index.tsx
+++ b/projects/app/src/pages/app/detail/components/BasicEdit/index.tsx
@@ -60,33 +60,30 @@ import PermissionIconText from '@/components/support/permission/IconText';
import QGSwitch from '../QGSwitch';
import TTSSelect from '../TTSSelect';
import { checkChatSupportSelectFileByModules } from '@/web/core/chat/utils';
+import { useSticky } from '@/web/common/hooks/useSticky';
const VariableEditModal = dynamic(() => import('@/components/core/module/VariableEditModal'));
const InfoModal = dynamic(() => import('../InfoModal'));
const DatasetSelectModal = dynamic(() => import('@/components/core/module/DatasetSelectModal'));
const AIChatSettingsModal = dynamic(() => import('@/components/core/module/AIChatSettingsModal'));
-const Settings = ({ appId }: { appId: string }) => {
+function ConfigForm({
+ divRef,
+ isSticky
+}: {
+ divRef: React.RefObject;
+ isSticky: boolean;
+}) {
const theme = useTheme();
const router = useRouter();
- const { t } = useTranslation();
const { toast } = useToast();
+ const { t } = useTranslation();
const { appDetail, updateAppDetail } = useAppStore();
const { loadAllDatasets, allDatasets } = useDatasetStore();
const { isPc } = useSystemStore();
-
const [editVariable, setEditVariable] = useState();
- const [settingAppInfo, setSettingAppInfo] = useState();
-
const [refresh, setRefresh] = useState(false);
- const { openConfirm: openConfirmSave, ConfirmModal: ConfirmSaveModal } = useConfirm({
- content: t('app.Confirm Save App Tip'),
- bg: appDetail.type === AppTypeEnum.basic ? '' : 'red.600'
- });
- const { openConfirm: openConfirmDel, ConfirmModal: ConfirmDelModal } = useConfirm({
- content: t('app.Confirm Del App Tip')
- });
const { register, setValue, getValues, reset, handleSubmit, control } = useForm({
defaultValues: getDefaultAppForm()
});
@@ -111,16 +108,21 @@ const Settings = ({ appId }: { appId: string }) => {
onClose: onCloseAIChatSetting
} = useDisclosure();
const {
- isOpen: isOpenKbSelect,
+ isOpen: isOpenDatasetSelect,
onOpen: onOpenKbSelect,
onClose: onCloseKbSelect
} = useDisclosure();
const {
- isOpen: isOpenKbParams,
+ isOpen: isOpenDatasetParams,
onOpen: onOpenKbParams,
onClose: onCloseKbParams
} = useDisclosure();
+ const { openConfirm: openConfirmSave, ConfirmModal: ConfirmSaveModal } = useConfirm({
+ content: t('app.Confirm Save App Tip'),
+ bg: appDetail.type === AppTypeEnum.basic ? '' : 'red.600'
+ });
+
const chatModelSelectList = useMemo(() => {
return chatModelList.map((item) => ({
value: item.model,
@@ -133,32 +135,6 @@ const Settings = ({ appId }: { appId: string }) => {
[allDatasets, datasets]
);
- /* 点击删除 */
- const { mutate: handleDelModel, isLoading } = useRequest({
- mutationFn: async () => {
- if (!appDetail) return null;
- await delModelById(appDetail._id);
- return 'success';
- },
- onSuccess(res) {
- if (!res) return;
- toast({
- title: t('common.Delete Success'),
- status: 'success'
- });
- router.replace(`/app/list`);
- },
- errorToast: t('common.Delete Failed')
- });
-
- const appModule2Form = useCallback(() => {
- const formVal = appModules2Form(appDetail.modules);
- reset(formVal);
- setTimeout(() => {
- setRefresh((state) => !state);
- }, 100);
- }, [appDetail.modules, reset]);
-
const { mutate: onSubmitSave, isLoading: isSaving } = useRequest({
mutationFn: async (data: EditFormType) => {
const modules = appForm2Modules(data);
@@ -173,12 +149,20 @@ const Settings = ({ appId }: { appId: string }) => {
errorToast: t('common.Save Failed')
});
+ const appModule2Form = useCallback(() => {
+ const formVal = appModules2Form(appDetail.modules);
+ reset(formVal);
+ setTimeout(() => {
+ setRefresh((state) => !state);
+ }, 100);
+ }, [appDetail.modules, reset]);
+
+ useQuery(['loadAllDatasets'], loadAllDatasets);
+
useEffect(() => {
appModule2Form();
}, [appModule2Form]);
- useQuery(['loadAllDatasets'], loadAllDatasets);
-
const BoxStyles: BoxProps = {
bg: 'myWhite.200',
px: 4,
@@ -202,110 +186,23 @@ const Settings = ({ appId }: { appId: string }) => {
};
return (
-
-
-
-
-
-
- (AppId:{' '}
-
- {appId}
-
- )
-
-
- {/* basic info */}
-
+ {/* title */}
+
-
-
-
- {appDetail.name}
-
- {appDetail.isOwner && (
- }
- variant={'base'}
- borderRadius={'md'}
- aria-label={'delete'}
- _hover={{
- bg: 'myGray.100',
- color: 'red.600'
- }}
- isLoading={isLoading}
- onClick={openConfirmDel(handleDelModel)}
- />
- )}
-
-
- {appDetail.intro || '快来给应用一个介绍~'}
-
-
- }
- onClick={() => router.push(`/chat?appId=${appId}`)}
- >
- 对话
-
- }
- onClick={() => {
- router.replace({
- query: {
- appId,
- currentTab: 'outLink'
- }
- });
- }}
- >
- 外接
-
- {appDetail.isOwner && (
- }
- onClick={() => setSettingAppInfo(appDetail)}
- >
- 设置
-
- )}
-
-
-
-
应用配置
@@ -329,215 +226,217 @@ const Settings = ({ appId }: { appId: string }) => {
- {/* welcome */}
-
-
-
- 对话开场白
-
-
-
-
-
-
- {/* variable */}
-
-
-
-
- 变量
-
- setEditVariable(addVariable())}>
- + 新增
-
-
- {variables.length > 0 && (
-
-
-
-
-
- 变量名
- 变量 key
- 必填
-
-
-
-
- {variables.map((item, index) => (
-
- {item.label}
- {item.key}
- {item.required ? '✔' : ''}
-
- setEditVariable(item)}
- />
- removeVariable(index)}
- />
-
-
- ))}
-
-
-
-
- )}
-
-
- {/* ai */}
-
-
-
-
- {t('app.AI Settings')}
-
-
-
- {t('app.Open AI Advanced Settings')}
-
-
-
-
- {t('core.ai.Model')}
-
- {
- setValue('chatModel.model', val);
- const maxToken =
- chatModelList.find((item) => item.model === getValues('chatModel.model'))
- ?.maxResponse || 4000;
- const token = maxToken / 2;
- setValue('chatModel.maxToken', token);
- setRefresh(!refresh);
- }}
- />
-
-
-
-
- {t('core.ai.Prompt')}
-
-
+
+ {/* welcome */}
+
+
+
+ 对话开场白
+
+
-
+
-
-
+ {...register('guide.welcome.text')}
+ />
+
- {/* dataset */}
-
-
-
-
- {t('core.dataset.Choose Dataset')}
+ {/* variable */}
+
+
+
+
+ 变量
+
+ setEditVariable(addVariable())}>
+ + 新增
+
-
-
- {t('common.Choose')}
-
-
-
- {t('common.Params')}
-
-
-
- {t('core.dataset.Similarity')}: {getValues('dataset.searchSimilarity')},{' '}
- {t('core.dataset.Search Top K')}: {getValues('dataset.searchLimit')}
- {getValues('dataset.searchEmptyText') === ''
- ? ''
- : t('core.dataset.Set Empty Result Tip')}
-
-
- {selectDatasets.map((item) => (
-
-
- router.push({
- pathname: '/dataset/detail',
- query: {
- datasetId: item._id
- }
- })
- }
- >
-
-
- {item.name}
-
-
-
- ))}
-
-
+ {variables.length > 0 && (
+
+
+
+
+
+ 变量名
+ 变量 key
+ 必填
+
+
+
+
+ {variables.map((item, index) => (
+
+ {item.label}
+ {item.key}
+ {item.required ? '✔' : ''}
+
+ setEditVariable(item)}
+ />
+ removeVariable(index)}
+ />
+
+
+ ))}
+
+
+
+
+ )}
+
-
- {
- setValue('tts', e);
- setRefresh((state) => !state);
- }}
- />
-
+ {/* ai */}
+
+
+
+
+ {t('app.AI Settings')}
+
+
+
+ {t('app.Open AI Advanced Settings')}
+
+
-
- {
- const value = e.target.checked;
- setValue('questionGuide', value);
- setRefresh((state) => !state);
- }}
- />
+
+ {t('core.ai.Model')}
+
+ {
+ setValue('chatModel.model', val);
+ const maxToken =
+ chatModelList.find((item) => item.model === getValues('chatModel.model'))
+ ?.maxResponse || 4000;
+ const token = maxToken / 2;
+ setValue('chatModel.maxToken', token);
+ setRefresh(!refresh);
+ }}
+ />
+
+
+
+
+ {t('core.ai.Prompt')}
+
+
+
+
+
+
+
+
+ {/* dataset */}
+
+
+
+
+ {t('core.dataset.Choose Dataset')}
+
+
+
+ {t('common.Choose')}
+
+
+
+ {t('common.Params')}
+
+
+
+ {t('core.dataset.Similarity')}: {getValues('dataset.searchSimilarity')},{' '}
+ {t('core.dataset.Search Top K')}: {getValues('dataset.searchLimit')}
+ {getValues('dataset.searchEmptyText') === ''
+ ? ''
+ : t('core.dataset.Set Empty Result Tip')}
+
+
+ {selectDatasets.map((item) => (
+
+
+ router.push({
+ pathname: '/dataset/detail',
+ query: {
+ datasetId: item._id
+ }
+ })
+ }
+ >
+
+
+ {item.name}
+
+
+
+ ))}
+
+
+
+ {/* tts */}
+
+ {
+ setValue('tts', e);
+ setRefresh((state) => !state);
+ }}
+ />
+
+
+ {/* whisper */}
+
+ {
+ const value = e.target.checked;
+ setValue('questionGuide', value);
+ setRefresh((state) => !state);
+ }}
+ />
+
-
- {settingAppInfo && (
- setSettingAppInfo(undefined)} />
- )}
{editVariable && (
{
defaultData={getValues('chatModel')}
/>
)}
- {isOpenKbSelect && (
+ {isOpenDatasetSelect && (
({
datasetId: item._id,
vectorModel: item.vectorModel
@@ -584,8 +483,7 @@ const Settings = ({ appId }: { appId: string }) => {
onChange={replaceKbList}
/>
)}
-
- {isOpenKbParams && (
+ {isOpenDatasetParams && (
{
)}
);
-};
+}
-const ChatTest = ({ appId }: { appId: string }) => {
+function Settings({ appId }: { appId: string }) {
+ const theme = useTheme();
+ const router = useRouter();
+ const { t } = useTranslation();
+ const { toast } = useToast();
+ const { parentRef, divRef, isSticky } = useSticky();
+ const { appDetail } = useAppStore();
+ const [settingAppInfo, setSettingAppInfo] = useState();
+
+ const { openConfirm: openConfirmDel, ConfirmModal: ConfirmDelModal } = useConfirm({
+ content: t('app.Confirm Del App Tip')
+ });
+
+ /* 点击删除 */
+ const { mutate: handleDelModel, isLoading } = useRequest({
+ mutationFn: async () => {
+ if (!appDetail) return null;
+ await delModelById(appDetail._id);
+ return 'success';
+ },
+ onSuccess(res) {
+ if (!res) return;
+ toast({
+ title: t('common.Delete Success'),
+ status: 'success'
+ });
+ router.replace(`/app/list`);
+ },
+ errorToast: t('common.Delete Failed')
+ });
+
+ return (
+
+
+
+
+
+
+
+ (AppId:{' '}
+
+ {appId}
+
+ )
+
+
+ {/* basic info */}
+
+
+
+
+ {appDetail.name}
+
+ {appDetail.isOwner && (
+ }
+ variant={'base'}
+ borderRadius={'md'}
+ aria-label={'delete'}
+ _hover={{
+ bg: 'myGray.100',
+ color: 'red.600'
+ }}
+ isLoading={isLoading}
+ onClick={openConfirmDel(handleDelModel)}
+ />
+ )}
+
+
+ {appDetail.intro || '快来给应用一个介绍~'}
+
+
+ }
+ onClick={() => router.push(`/chat?appId=${appId}`)}
+ >
+ 对话
+
+ }
+ onClick={() => {
+ router.replace({
+ query: {
+ appId,
+ currentTab: 'outLink'
+ }
+ });
+ }}
+ >
+ 外接
+
+ {appDetail.isOwner && (
+ }
+ onClick={() => setSettingAppInfo(appDetail)}
+ >
+ 设置
+
+ )}
+
+
+
+ {/* config form */}
+
+
+
+ {settingAppInfo && (
+ setSettingAppInfo(undefined)} />
+ )}
+
+ );
+}
+
+function ChatTest({ appId }: { appId: string }) {
const { t } = useTranslation();
const { userInfo } = useUserStore();
const { appDetail } = useAppStore();
@@ -703,7 +748,7 @@ const ChatTest = ({ appId }: { appId: string }) => {
)}
);
-};
+}
const BasicEdit = ({ appId }: { appId: string }) => {
const { isPc } = useSystemStore();
diff --git a/projects/app/src/pages/app/detail/index.tsx b/projects/app/src/pages/app/detail/index.tsx
index 6a051d32e..5c5743bed 100644
--- a/projects/app/src/pages/app/detail/index.tsx
+++ b/projects/app/src/pages/app/detail/index.tsx
@@ -99,7 +99,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
display={['none', 'flex']}
flexDirection={'column'}
p={4}
- w={'200px'}
+ w={'180px'}
borderRight={theme.borders.base}
>
diff --git a/projects/app/src/pages/dataset/list/index.tsx b/projects/app/src/pages/dataset/list/index.tsx
index a8c27b16f..1182ba0b7 100644
--- a/projects/app/src/pages/dataset/list/index.tsx
+++ b/projects/app/src/pages/dataset/list/index.tsx
@@ -40,6 +40,7 @@ import { useUserStore } from '@/web/support/user/useUserStore';
import PermissionIconText from '@/components/support/permission/IconText';
import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant';
import { DatasetItemType } from '@fastgpt/global/core/dataset/type';
+import ParentPaths from '@/components/common/ParentPaths';
const CreateModal = dynamic(() => import('./component/CreateModal'), { ssr: false });
const MoveModal = dynamic(() => import('./component/MoveModal'), { ssr: false });
@@ -113,64 +114,34 @@ const Kb = () => {
return Promise.all([loadDatasets(parentId), getDatasetPaths(parentId)]);
});
- const paths = useMemo(
- () => [
- {
- parentId: '',
- parentName: t('dataset.My Dataset')
- },
- ...(data?.[1] || [])
- ],
- [data, t]
- );
+ const paths = data?.[1] || [];
return (
{/* url path */}
- {!!parentId ? (
-
- {paths.map((item, i) => (
-
- {
- router.push({
- query: {
- parentId: item.parentId
- }
- });
- }
- })}
- >
- {item.parentName}
-
- {i !== paths.length - 1 && (
-
- )}
-
- ))}
-
- ) : (
-
-
-
- 我的知识库
-
-
- )}
+ ({
+ parentId: path.parentId,
+ parentName: path.parentName
+ }))}
+ FirstPathDom={
+
+
+
+ {t('dataset.My Dataset')}
+
+
+ }
+ onClick={(e) => {
+ router.push({
+ query: {
+ parentId: e
+ }
+ });
+ }}
+ />
+ {/* create icon */}
{userInfo?.team?.canWrite && (
(null);
+ const divRef = useRef(null);
+ const [isSticky, setIsSticky] = useState(false);
+
+ useEffect(() => {
+ const cb = () => {
+ if (!divRef.current) return;
+ const rect = divRef.current.getBoundingClientRect();
+ const isSticky = rect.top <= threshold;
+ setIsSticky(isSticky);
+ };
+ parentRef.current?.addEventListener('scroll', cb);
+
+ return () => {
+ parentRef.current?.removeEventListener('scroll', cb);
+ };
+ }, [threshold]);
+
+ return {
+ parentRef,
+ divRef,
+ isSticky
+ };
+}