mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 21:13:50 +00:00
v4.6-3 (#471)
This commit is contained in:
@@ -8,5 +8,8 @@ module.exports = {
|
||||
defaultLocale: 'zh',
|
||||
locales: ['en', 'zh', 'zh-Hans', 'zh-CN'],
|
||||
localeDetection: false
|
||||
}
|
||||
},
|
||||
localePath:
|
||||
typeof window === 'undefined' ? require('path').resolve('./public/locales') : '/locales',
|
||||
reloadOnPrerender: process.env.NODE_ENV === 'development'
|
||||
};
|
||||
|
@@ -33,8 +33,6 @@
|
||||
"hyperdown": "^2.4.29",
|
||||
"i18next": "^22.5.1",
|
||||
"immer": "^9.0.19",
|
||||
"js-cookie": "^3.0.5",
|
||||
"js-tiktoken": "^1.0.7",
|
||||
"jschardet": "^3.0.0",
|
||||
"jsdom": "^22.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
@@ -47,7 +45,6 @@
|
||||
"next-i18next": "^13.3.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"papaparse": "^5.4.1",
|
||||
"pg-query-stream": "^4.5.3",
|
||||
"react": "18.2.0",
|
||||
"react-day-picker": "^8.7.1",
|
||||
"react-dom": "18.2.0",
|
||||
|
@@ -1,9 +1,12 @@
|
||||
### Fast GPT V4.6
|
||||
|
||||
1. 新增 - 团队空间试用版。
|
||||
2. 新增 - OpenAI语音播报。
|
||||
3. [知识库结构详解](https://doc.fastgpt.in/docs/use-cases/datasetengine/)
|
||||
4. [知识库提示词详解](https://doc.fastgpt.in/docs/use-cases/ai_settings/#引用模板--引用提示词)
|
||||
5. [使用文档](https://doc.fastgpt.in/docs/intro/)
|
||||
6. [点击查看高级编排介绍文档](https://doc.fastgpt.in/docs/workflow)
|
||||
7. [点击查看商业版](https://doc.fastgpt.in/docs/commercial/)
|
||||
1. 新增 - 团队空间
|
||||
2. 新增 - 多路向量(多个向量映射一组数据)
|
||||
3. 新增 - tts语音
|
||||
4. 线上环境新增 - ReRank向量召回,提高召回精度
|
||||
5. 优化 - 知识库导出,可直接触发流下载,无需等待转圈圈
|
||||
6. [知识库结构详解](https://doc.fastgpt.in/docs/use-cases/datasetengine/)
|
||||
7. [知识库提示词详解](https://doc.fastgpt.in/docs/use-cases/ai_settings/#引用模板--引用提示词)
|
||||
8. [使用文档](https://doc.fastgpt.in/docs/intro/)
|
||||
9. [点击查看高级编排介绍文档](https://doc.fastgpt.in/docs/workflow)
|
||||
10. [点击查看商业版](https://doc.fastgpt.in/docs/commercial/)
|
||||
|
@@ -292,17 +292,32 @@
|
||||
"Select One Collection To Store": "Select the collection to store"
|
||||
},
|
||||
"data": {
|
||||
"Add Index": "Add Index",
|
||||
"Can not delete tip": "No modification permission",
|
||||
"Can not edit": "No edit permission",
|
||||
"Custom Index Number": "Custom index{{number}}",
|
||||
"Default Index": "Default Index",
|
||||
"Delete Success Tip": "",
|
||||
"Delete Tip": "Confirm to delete the data?",
|
||||
"File import": "File Import",
|
||||
"Index Edit": "Data Index",
|
||||
"Index Placeholder": "Enter the index text content",
|
||||
"Input Data": "Import Data",
|
||||
"Input Success Tip": "Succeeded in importing data",
|
||||
"Update Data": "Update Data",
|
||||
"Update Success Tip": "Update data successfully"
|
||||
"Update Success Tip": "Update data successfully",
|
||||
"edit": {
|
||||
"Content": "Content",
|
||||
"Course": "Document",
|
||||
"Delete": "Delete",
|
||||
"Index": "Index({{amount}})"
|
||||
}
|
||||
},
|
||||
"deleteDatasetTips": "Are you sure to delete the knowledge base? Data cannot be recovered after deletion, please confirm!",
|
||||
"deleteFolderTips": "Are you sure to delete this folder and all the knowledge bases it contains? Data cannot be recovered after deletion, please confirm!"
|
||||
"deleteFolderTips": "Are you sure to delete this folder and all the knowledge bases it contains? Data cannot be recovered after deletion, please confirm!",
|
||||
"test": {
|
||||
"noResult": "Search results are empty"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"team": {
|
||||
@@ -461,9 +476,11 @@
|
||||
"Bill Detail": "Bill Detail",
|
||||
"Change": "Change",
|
||||
"Copy invite url": "Copy invitation link",
|
||||
"Edit name": "Click to modify nickname",
|
||||
"Invite Url": "Invite Url",
|
||||
"Invite url tip": "Friends who register through this link will be permanently bound to you, and you will get a certain balance reward when they recharge. In addition, when friends register with their mobile phone number, you will get 5 yuan reward immediately.",
|
||||
"Language": "Language",
|
||||
"Member Name": "Name",
|
||||
"Notice": "Notice",
|
||||
"Old password is error": "Old password is error",
|
||||
"OpenAI Account Setting": "OpenAI Account Setting",
|
||||
@@ -513,12 +530,15 @@
|
||||
"Leave Team Failed": "Leave Team Failed",
|
||||
"Manage": "Team Manage",
|
||||
"Member": "Member",
|
||||
"Member Name": "Member",
|
||||
"Over Max Member Tip": "Team max {{max}} people",
|
||||
"Personal Team": "Personal",
|
||||
"Processing invitations": "Processing invitations",
|
||||
"Processing invitations Tips": "You have {{amount}} of team invitations that need to be processed",
|
||||
"Reinvite": "Reinvite",
|
||||
"Remove Member Confirm Tip": "Confirm to move {{username}} off the team",
|
||||
"Remove Member Confirm Tip": "Are you sure you want to move {{username}} off the team? All its resources are transferred to the team creator's account.",
|
||||
"Remove Member Failed": "Removing a team member failed",
|
||||
"Remove Member Success": "Removing a team member succeeded",
|
||||
"Remove Member Tip": "Move out team",
|
||||
"Role": "Role",
|
||||
"Select Team": "Select Team",
|
||||
|
@@ -292,17 +292,32 @@
|
||||
"Select One Collection To Store": "选择一个文件进行存储"
|
||||
},
|
||||
"data": {
|
||||
"Add Index": "新增自定义索引",
|
||||
"Can not delete tip": "无修改权限",
|
||||
"Can not edit": "无编辑权限",
|
||||
"Custom Index Number": "自定义索引{{number}}",
|
||||
"Default Index": "默认索引",
|
||||
"Delete Success Tip": "删除成功",
|
||||
"Delete Tip": "确认删除该条数据?",
|
||||
"File import": "文件导入",
|
||||
"Index Edit": "数据索引",
|
||||
"Index Placeholder": "输入索引文本内容",
|
||||
"Input Data": "导入新数据",
|
||||
"Input Success Tip": "导入数据成功",
|
||||
"Update Data": "更新数据",
|
||||
"Update Success Tip": "更新数据成功"
|
||||
"Update Success Tip": "更新数据成功",
|
||||
"edit": {
|
||||
"Content": "数据内容",
|
||||
"Course": "说明文档",
|
||||
"Delete": "删除数据",
|
||||
"Index": "数据索引({{amount}})"
|
||||
}
|
||||
},
|
||||
"deleteDatasetTips": "确认删除该知识库?删除后数据无法恢复,请确认!",
|
||||
"deleteFolderTips": "确认删除该文件夹及其包含的所有知识库?删除后数据无法恢复,请确认!"
|
||||
"deleteFolderTips": "确认删除该文件夹及其包含的所有知识库?删除后数据无法恢复,请确认!",
|
||||
"test": {
|
||||
"noResult": "搜索结果为空"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"team": {
|
||||
@@ -461,9 +476,11 @@
|
||||
"Bill Detail": "账单详情",
|
||||
"Change": "变更",
|
||||
"Copy invite url": "复制邀请链接",
|
||||
"Edit name": "点击修改昵称",
|
||||
"Invite Url": "邀请链接",
|
||||
"Invite url tip": "通过该链接注册的好友将永久与你绑定,其充值时你会获得一定余额奖励。\n此外,好友使用手机号注册时,你将立即获得 5 元奖励。\n奖励会发送到您的默认团队中。",
|
||||
"Language": "语言",
|
||||
"Member Name": "昵称",
|
||||
"Notice": "通知",
|
||||
"Old password is error": "旧密码错误",
|
||||
"OpenAI Account Setting": "OpenAI 账号配置",
|
||||
@@ -513,12 +530,15 @@
|
||||
"Leave Team Failed": "离开团队异常",
|
||||
"Manage": "团队管理",
|
||||
"Member": "成员",
|
||||
"Member Name": "成员名",
|
||||
"Over Max Member Tip": "团队最多{{max}}人",
|
||||
"Personal Team": "个人团队",
|
||||
"Processing invitations": "处理邀请",
|
||||
"Processing invitations Tips": "你有{{amount}}个需要处理的团队邀请",
|
||||
"Reinvite": "重新邀请",
|
||||
"Remove Member Confirm Tip": "确认将 {{username}} 移出团队?",
|
||||
"Remove Member Confirm Tip": "确认将 {{username}} 移出团队?其所有资源将转让到团队创建者的账户内。",
|
||||
"Remove Member Failed": "移除团队成员异常",
|
||||
"Remove Member Success": "移除团队成员成功",
|
||||
"Remove Member Tip": "移出团队",
|
||||
"Role": "身份",
|
||||
"Select Team": "团队选择",
|
||||
|
@@ -10,13 +10,12 @@ import InputDataModal, {
|
||||
type InputDataType
|
||||
} from '@/pages/dataset/detail/components/InputDataModal';
|
||||
import MyModal from '../MyModal';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useRouter } from 'next/router';
|
||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import MyTooltip from '../MyTooltip';
|
||||
import NextLink from 'next/link';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
|
||||
const QuoteModal = ({
|
||||
rawSearch = [],
|
||||
@@ -29,10 +28,9 @@ const QuoteModal = ({
|
||||
const { isPc } = useSystemStore();
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { userInfo } = useUserStore();
|
||||
const { toast } = useToast();
|
||||
const { setIsLoading, Loading } = useLoading();
|
||||
const [editInputData, setEditInputData] = useState<InputDataType & { datasetId: string }>();
|
||||
const [editInputData, setEditInputData] = useState<InputDataType & { collectionId: string }>();
|
||||
|
||||
const isShare = useMemo(() => router.pathname === '/chat/share', [router.pathname]);
|
||||
|
||||
@@ -99,7 +97,7 @@ const QuoteModal = ({
|
||||
color={'black'}
|
||||
sourceName={item.sourceName}
|
||||
sourceId={item.sourceId}
|
||||
addr={!isShare}
|
||||
canView={!isShare}
|
||||
/>
|
||||
<Box flex={1} />
|
||||
{!isShare && (
|
||||
@@ -131,7 +129,7 @@ const QuoteModal = ({
|
||||
<MyTooltip label={t('core.dataset.Quote Length')}>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name="common/text/t" w={'14px'} mr={1} color={'myGray.500'} />
|
||||
{item.q.length + item.a.length}
|
||||
{item.q.length + (item.a?.length || 0)}
|
||||
</Flex>
|
||||
</MyTooltip>
|
||||
{!isShare && item.score && (
|
||||
@@ -183,7 +181,6 @@ const QuoteModal = ({
|
||||
</MyModal>
|
||||
{editInputData && editInputData.id && (
|
||||
<InputDataModal
|
||||
canWrite={userInfo?.team?.canWrite || false}
|
||||
onClose={() => setEditInputData(undefined)}
|
||||
onSuccess={() => {
|
||||
console.log('更新引用成功');
|
||||
@@ -191,8 +188,8 @@ const QuoteModal = ({
|
||||
onDelete={() => {
|
||||
console.log('删除引用成功');
|
||||
}}
|
||||
datasetId={editInputData.datasetId}
|
||||
defaultValues={editInputData}
|
||||
defaultValue={editInputData}
|
||||
collectionId={editInputData.collectionId}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
@@ -2,7 +2,7 @@ import React, { useMemo, useState } from 'react';
|
||||
import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/api.d';
|
||||
import type { ChatItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { Flex, BoxProps, useDisclosure, Image, useTheme } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { ModalBody, useTheme, ModalFooter, Button, Box, Card, Flex, Grid } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Avatar from '../Avatar';
|
||||
@@ -8,6 +8,7 @@ import DatasetSelectModal, { useDatasetSelect } from '@/components/core/dataset/
|
||||
import dynamic from 'next/dynamic';
|
||||
import { AdminFbkType } from '@fastgpt/global/core/chat/type.d';
|
||||
import SelectCollections from '@/web/core/dataset/components/SelectCollections';
|
||||
import { getDefaultIndex } from '@fastgpt/global/core/dataset/utils';
|
||||
|
||||
const InputDataModal = dynamic(() => import('@/pages/dataset/detail/components/InputDataModal'));
|
||||
|
||||
@@ -163,15 +164,13 @@ const SelectMarkCollection = ({
|
||||
{adminMarkData.datasetId && adminMarkData.collectionId && (
|
||||
<InputDataModal
|
||||
onClose={onClose}
|
||||
datasetId={adminMarkData.datasetId}
|
||||
defaultValues={{
|
||||
collectionId={adminMarkData.collectionId}
|
||||
defaultValue={{
|
||||
id: adminMarkData.dataId,
|
||||
collectionId: adminMarkData.collectionId,
|
||||
sourceName: '手动标注',
|
||||
q: adminMarkData.q,
|
||||
a: adminMarkData.a
|
||||
a: adminMarkData.a,
|
||||
indexes: [getDefaultIndex({ dataId: `${Date.now()}` })]
|
||||
}}
|
||||
canWrite
|
||||
onSuccess={(data) => {
|
||||
if (!data.q || !adminMarkData.datasetId || !adminMarkData.collectionId || !data.id) {
|
||||
return onClose();
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { Box, useTheme, Flex, Image } from '@chakra-ui/react';
|
||||
import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/api.d';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { ModuleTemplatesFlat } from '@/constants/flow/ModuleTemplate';
|
||||
import Tabs from '../Tabs';
|
||||
|
||||
|
@@ -30,7 +30,7 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { feConfigs } from '@/web/common/system/staticData';
|
||||
import { eventBus } from '@/web/common/utils/eventbus';
|
||||
import { adaptChat2GptMessages } from '@/utils/common/adapt/message';
|
||||
import { adaptChat2GptMessages } from '@fastgpt/global/core/chat/adapt';
|
||||
import { useMarkdown } from '@/web/common/hooks/useMarkdown';
|
||||
import { ModuleItemType } from '@fastgpt/global/core/module/type.d';
|
||||
import { VariableInputEnum } from '@/constants/app';
|
||||
@@ -41,7 +41,7 @@ import { htmlTemplate } from '@/constants/common';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { TaskResponseKeyEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { adminUpdateChatFeedback, userUpdateChatFeedback } from '@/web/core/chat/api';
|
||||
import type { AdminMarkType } from './SelectMarkCollection';
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Button, ModalFooter, ModalBody } from '@chakra-ui/react';
|
||||
import MyModal from '../MyModal';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Markdown from '../Markdown';
|
||||
|
||||
const md = `
|
||||
|
@@ -1,48 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Menu, MenuButton, MenuItem, MenuList, MenuButtonProps } from '@chakra-ui/react';
|
||||
import { getLangStore, LangEnum, setLangStore, langMap } from '@/web/common/utils/i18n';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
const Language = (props: MenuButtonProps) => {
|
||||
const router = useRouter();
|
||||
const { i18n } = useTranslation();
|
||||
|
||||
const [language, setLanguage] = useState<`${LangEnum}`>(getLangStore());
|
||||
|
||||
return (
|
||||
<Menu autoSelect={false}>
|
||||
<MenuButton
|
||||
{...props}
|
||||
sx={{
|
||||
'& span': {
|
||||
flex: 0
|
||||
}
|
||||
}}
|
||||
>
|
||||
<MyIcon name={langMap[language].icon as any} w={['18px', '22px']} />
|
||||
</MenuButton>
|
||||
<MenuList w="max-content" minW="120px">
|
||||
{Object.entries(langMap).map(([key, lang]) => (
|
||||
<MenuItem
|
||||
key={key}
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
onClick={() => {
|
||||
const lang = key as `${LangEnum}`;
|
||||
setLangStore(lang);
|
||||
setLanguage(lang);
|
||||
i18n?.changeLanguage?.(lang);
|
||||
router.reload();
|
||||
}}
|
||||
>
|
||||
{lang.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</MenuList>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Language);
|
@@ -2,7 +2,7 @@ import React, { useMemo } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { Flex, Box } from '@chakra-ui/react';
|
||||
import { useChatStore } from '@/web/core/chat/storeChat';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Badge from '../Badge';
|
||||
import MyIcon from '../Icon';
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Box, Grid } from '@chakra-ui/react';
|
||||
import type { GridProps } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
// @ts-ignore
|
||||
interface Props extends GridProps {
|
||||
|
@@ -2,7 +2,7 @@ import MyIcon from '@/components/Icon';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const ParentPaths = (props: {
|
||||
paths?: ParentTreePathItemType[];
|
||||
|
@@ -10,7 +10,7 @@ import {
|
||||
useTheme
|
||||
} from '@chakra-ui/react';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
type Props = BoxProps & { defaultValues: string[]; onUpdate: (e: string[]) => void };
|
||||
|
||||
|
@@ -2,7 +2,7 @@ import { getDatasets, getDatasetPaths } from '@/web/core/dataset/api';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import React, { Dispatch, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
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';
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { EditFormType } from '@/web/core/app/basicSettings';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import {
|
||||
|
@@ -14,14 +14,14 @@ import {
|
||||
import Avatar from '@/components/Avatar';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import type { SelectedDatasetType } from '@/types/core/dataset';
|
||||
import type { SelectedDatasetType } from '@fastgpt/global/core/module/api.d';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import MySlider from '@/components/Slider';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
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';
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Textarea, Button, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { useFlowProviderStore } from './FlowProvider';
|
||||
|
||||
|
@@ -4,7 +4,7 @@ import MyModal from '@/components/MyModal';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { SelectAppItemType } from '@fastgpt/global/core/module/type';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useLoading } from '@/web/common/hooks/useLoading';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
|
@@ -10,7 +10,7 @@ import Avatar from '@/components/Avatar';
|
||||
import { useFlowProviderStore } from './FlowProvider';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { appModule2FlowNode } from '@/utils/adapt';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useRouter } from 'next/router';
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
|
||||
import MyIcon from '@/components/Icon';
|
||||
|
@@ -13,7 +13,7 @@ import { useForm } from 'react-hook-form';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import { FlowNodeValTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MySelect from '@/components/Select';
|
||||
|
||||
const typeSelectList = [
|
||||
|
@@ -5,7 +5,7 @@ import Avatar from '@/components/Avatar';
|
||||
import type { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useEditTitle } from '@/web/common/hooks/useEditTitle';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { useFlowProviderStore, onChangeNode } from '../../FlowProvider';
|
||||
|
@@ -15,7 +15,7 @@ import {
|
||||
FlowNodeValTypeEnum,
|
||||
FlowNodeSpecialInputKeyEnum
|
||||
} from '@fastgpt/global/core/module/node/constant';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import SourceHandle from '../render/SourceHandle';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { onChangeNode } from '../../FlowProvider';
|
||||
|
@@ -26,12 +26,12 @@ import MySlider from '@/components/Slider';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import TargetHandle from './TargetHandle';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { AIChatProps } from '@/types/core/aiChat';
|
||||
import { chatModelList } from '@/web/common/system/staticData';
|
||||
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import { SelectedDatasetType } from '@/types/core/dataset';
|
||||
import type { SelectedDatasetType } from '@fastgpt/global/core/module/api.d';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||
import type { EditFieldModeType, EditFieldType } from '../modules/FieldEditModal';
|
||||
|
@@ -33,7 +33,7 @@ import dayjs from 'dayjs';
|
||||
import { AddIcon, QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||
import { feConfigs } from '@/web/common/system/staticData';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { PermissionTypeEnum, PermissionTypeMap } from '@fastgpt/global/support/permission/constant';
|
||||
import { Box, Flex, FlexProps } from '@chakra-ui/react';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const PermissionIconText = ({
|
||||
permission,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import MyRadio from '@/components/Radio';
|
||||
import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const PermissionRadio = ({
|
||||
value,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
|
||||
import { compressImgAndUpload } from '@/web/common/file/controller';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { ModalCloseButton, ModalBody, Box, ModalFooter, Button } from '@chakra-ui/react';
|
||||
import TagTextarea from '@/components/common/Textarea/TagTextarea';
|
||||
import MySelect from '@/components/Select';
|
||||
@@ -57,8 +57,8 @@ const InviteModal = ({
|
||||
undefined,
|
||||
t('user.team.Invite Member Success Tip', {
|
||||
success: res.invite.length,
|
||||
inValid: res.inValid.join(', '),
|
||||
inTeam: res.inTeam.join(', ')
|
||||
inValid: res.inValid.map((item) => item.username).join(', '),
|
||||
inTeam: res.inTeam.map((item) => item.username).join(', ')
|
||||
})
|
||||
)();
|
||||
},
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import {
|
||||
getTeamList,
|
||||
@@ -100,7 +100,9 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
|
||||
mutationFn: delRemoveMember,
|
||||
onSuccess() {
|
||||
refetchMembers();
|
||||
}
|
||||
},
|
||||
successToast: t('user.team.Remove Member Success'),
|
||||
errorToast: t('user.team.Remove Member Failed')
|
||||
});
|
||||
const { mutate: onLeaveTeam, isLoading: isLoadingLeaveTeam } = useRequest({
|
||||
mutationFn: async (teamId?: string) => {
|
||||
@@ -306,7 +308,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
|
||||
<Td display={'flex'} alignItems={'center'}>
|
||||
<Avatar src={item.avatar} w={['18px', '22px']} />
|
||||
<Box flex={'1 0 0'} w={0} ml={1} className={'textEllipsis'}>
|
||||
{item.memberUsername}
|
||||
{item.memberName}
|
||||
</Box>
|
||||
</Td>
|
||||
<Td>{t(TeamMemberRoleMap[item.role]?.label || '')}</Td>
|
||||
@@ -383,7 +385,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
|
||||
}),
|
||||
undefined,
|
||||
t('user.team.Remove Member Confirm Tip', {
|
||||
username: item.memberUsername
|
||||
username: item.memberName
|
||||
})
|
||||
)()
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Box, Button, Flex, Image, useDisclosure, useTheme } from '@chakra-ui/react';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { feConfigs } from '@/web/common/system/staticData';
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import {
|
||||
Button,
|
||||
|
@@ -1,4 +1,7 @@
|
||||
import type { DatasetItemType } from '@/types/core/dataset';
|
||||
import type {
|
||||
DatasetCollectionItemType,
|
||||
DatasetItemType
|
||||
} from '@fastgpt/global/core/dataset/type.d';
|
||||
|
||||
export const defaultDatasetDetail: DatasetItemType = {
|
||||
_id: '',
|
||||
@@ -10,7 +13,7 @@ export const defaultDatasetDetail: DatasetItemType = {
|
||||
type: 'dataset',
|
||||
avatar: '/icon/logo.svg',
|
||||
name: '',
|
||||
tags: '',
|
||||
tags: [],
|
||||
permission: 'private',
|
||||
isOwner: false,
|
||||
canWrite: false,
|
||||
@@ -22,3 +25,32 @@ export const defaultDatasetDetail: DatasetItemType = {
|
||||
maxToken: 3000
|
||||
}
|
||||
};
|
||||
|
||||
export const defaultCollectionDetail: DatasetCollectionItemType = {
|
||||
_id: '',
|
||||
userId: '',
|
||||
teamId: '',
|
||||
tmbId: '',
|
||||
datasetId: {
|
||||
_id: '',
|
||||
parentId: '',
|
||||
userId: '',
|
||||
teamId: '',
|
||||
tmbId: '',
|
||||
updateTime: new Date(),
|
||||
type: 'dataset',
|
||||
avatar: '/icon/logo.svg',
|
||||
name: '',
|
||||
tags: [],
|
||||
permission: 'private',
|
||||
vectorModel: 'text-embedding-ada-002'
|
||||
},
|
||||
parentId: '',
|
||||
name: '',
|
||||
type: 'file',
|
||||
updateTime: new Date(),
|
||||
metadata: {},
|
||||
canWrite: false,
|
||||
sourceName: '',
|
||||
sourceId: ''
|
||||
};
|
||||
|
@@ -1,108 +0,0 @@
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { countPromptTokens } from '@/global/common/tiktoken';
|
||||
|
||||
/*
|
||||
replace {{variable}} to value
|
||||
*/
|
||||
export function replaceVariable(text: string, obj: Record<string, string | number>) {
|
||||
for (const key in obj) {
|
||||
const val = obj[key];
|
||||
if (!['string', 'number'].includes(typeof val)) continue;
|
||||
|
||||
text = text.replace(new RegExp(`{{(${key})}}`, 'g'), String(val));
|
||||
}
|
||||
return text || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* text split into chunks
|
||||
* maxLen - one chunk len. max: 3500
|
||||
* overlapLen - The size of the before and after Text
|
||||
* maxLen > overlapLen
|
||||
*/
|
||||
export const splitText2Chunks = ({ text = '', maxLen }: { text: string; maxLen: number }) => {
|
||||
const overlapLen = Math.floor(maxLen * 0.15); // Overlap length
|
||||
const tempMarker = 'SPLIT_HERE_SPLIT_HERE';
|
||||
|
||||
const stepReg: Record<number, RegExp> = {
|
||||
0: /(\n\n)/g,
|
||||
1: /([\n])/g,
|
||||
2: /[。]|(?!<[^a-zA-Z])\.\s/g,
|
||||
3: /([!?]|!\s|\?\s)/g,
|
||||
4: /([;]|;\s)/g,
|
||||
5: /([,]|,\s)/g
|
||||
};
|
||||
|
||||
const splitTextRecursively = ({ text = '', step }: { text: string; step: number }) => {
|
||||
if (text.length <= maxLen) {
|
||||
return [text];
|
||||
}
|
||||
const reg = stepReg[step];
|
||||
|
||||
if (!reg) {
|
||||
// use slice-maxLen to split text
|
||||
const chunks: string[] = [];
|
||||
let chunk = '';
|
||||
for (let i = 0; i < text.length; i += maxLen - overlapLen) {
|
||||
chunk = text.slice(i, i + maxLen);
|
||||
chunks.push(chunk);
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
// split text by delimiters
|
||||
const splitTexts = text
|
||||
.replace(reg, `$1${tempMarker}`)
|
||||
.split(`${tempMarker}`)
|
||||
.filter((part) => part);
|
||||
|
||||
let chunks: string[] = [];
|
||||
let preChunk = '';
|
||||
let chunk = '';
|
||||
for (let i = 0; i < splitTexts.length; i++) {
|
||||
let text = splitTexts[i];
|
||||
// chunk over size
|
||||
if (text.length > maxLen) {
|
||||
const innerChunks = splitTextRecursively({ text, step: step + 1 });
|
||||
if (innerChunks.length === 0) continue;
|
||||
// If the last chunk is too small, it is merged into the next chunk
|
||||
if (innerChunks[innerChunks.length - 1].length <= maxLen * 0.5) {
|
||||
text = innerChunks.pop() || '';
|
||||
chunks = chunks.concat(innerChunks);
|
||||
} else {
|
||||
chunks = chunks.concat(innerChunks);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
chunk += text;
|
||||
// size over lapLen, push it to next chunk
|
||||
if (chunk.length > maxLen - overlapLen) {
|
||||
preChunk += text;
|
||||
}
|
||||
if (chunk.length >= maxLen) {
|
||||
chunks.push(chunk);
|
||||
chunk = preChunk;
|
||||
preChunk = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (chunk && !chunks[chunks.length - 1].endsWith(chunk)) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
return chunks;
|
||||
};
|
||||
|
||||
try {
|
||||
const chunks = splitTextRecursively({ text, step: 0 });
|
||||
|
||||
const tokens = chunks.reduce((sum, chunk) => sum + countPromptTokens(chunk, 'system'), 0);
|
||||
|
||||
return {
|
||||
chunks,
|
||||
tokens
|
||||
};
|
||||
} catch (err) {
|
||||
throw new Error(getErrText(err));
|
||||
}
|
||||
};
|
File diff suppressed because one or more lines are too long
@@ -1,95 +0,0 @@
|
||||
/* Only the token of gpt-3.5-turbo is used */
|
||||
import type { ChatItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { Tiktoken } from 'js-tiktoken/lite';
|
||||
import { adaptChat2GptMessages } from '@/utils/common/adapt/message';
|
||||
import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/global/core/ai/constant';
|
||||
import encodingJson from './cl100k_base.json';
|
||||
|
||||
/* init tikToken obj */
|
||||
export function getTikTokenEnc() {
|
||||
if (typeof window !== 'undefined' && window.TikToken) {
|
||||
return window.TikToken;
|
||||
}
|
||||
if (typeof global !== 'undefined' && global.TikToken) {
|
||||
return global.TikToken;
|
||||
}
|
||||
|
||||
const enc = new Tiktoken(encodingJson);
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window.TikToken = enc;
|
||||
}
|
||||
if (typeof global !== 'undefined') {
|
||||
global.TikToken = enc;
|
||||
}
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
||||
/* count one prompt tokens */
|
||||
export function countPromptTokens(
|
||||
prompt = '',
|
||||
role: '' | `${ChatCompletionRequestMessageRoleEnum}` = ''
|
||||
) {
|
||||
const enc = getTikTokenEnc();
|
||||
const text = `${role}\n${prompt}`;
|
||||
try {
|
||||
const encodeText = enc.encode(text);
|
||||
return encodeText.length + 3; // 补充 role 估算值
|
||||
} catch (error) {
|
||||
return text.length;
|
||||
}
|
||||
}
|
||||
|
||||
/* count messages tokens */
|
||||
export function countMessagesTokens({ messages }: { messages: ChatItemType[] }) {
|
||||
const adaptMessages = adaptChat2GptMessages({ messages, reserveId: true });
|
||||
|
||||
let totalTokens = 0;
|
||||
for (let i = 0; i < adaptMessages.length; i++) {
|
||||
const item = adaptMessages[i];
|
||||
const tokens = countPromptTokens(item.content, item.role);
|
||||
totalTokens += tokens;
|
||||
}
|
||||
|
||||
return totalTokens;
|
||||
}
|
||||
|
||||
export function sliceTextByTokens({ text, length }: { text: string; length: number }) {
|
||||
const enc = getTikTokenEnc();
|
||||
|
||||
try {
|
||||
const encodeText = enc.encode(text);
|
||||
return enc.decode(encodeText.slice(0, length));
|
||||
} catch (error) {
|
||||
return text.slice(0, length);
|
||||
}
|
||||
}
|
||||
|
||||
/* slice messages from top to bottom by maxTokens */
|
||||
export function sliceMessagesTB({
|
||||
messages,
|
||||
maxTokens
|
||||
}: {
|
||||
messages: ChatItemType[];
|
||||
maxTokens: number;
|
||||
}) {
|
||||
const adaptMessages = adaptChat2GptMessages({ messages, reserveId: true });
|
||||
let reduceTokens = maxTokens;
|
||||
let result: ChatItemType[] = [];
|
||||
|
||||
for (let i = 0; i < adaptMessages.length; i++) {
|
||||
const item = adaptMessages[i];
|
||||
|
||||
const tokens = countPromptTokens(item.content, item.role);
|
||||
reduceTokens -= tokens;
|
||||
|
||||
if (reduceTokens > 0) {
|
||||
result.push(messages[i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result.length === 0 && messages[0] ? [messages[0]] : result;
|
||||
}
|
26
projects/app/src/global/core/api/datasetReq.d.ts
vendored
26
projects/app/src/global/core/api/datasetReq.d.ts
vendored
@@ -2,7 +2,7 @@ import { DatasetCollectionTypeEnum, DatasetTypeEnum } from '@fastgpt/global/core
|
||||
import type { RequestPaging } from '@/types';
|
||||
import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
import type { SearchTestItemType } from '@/types/core/dataset';
|
||||
import { DatasetChunkItemType, UploadChunkItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import { UploadChunkItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import { DatasetCollectionSchemaType } from '@fastgpt/global/core/dataset/type';
|
||||
import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||
|
||||
@@ -10,19 +10,11 @@ import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant'
|
||||
export type DatasetUpdateParams = {
|
||||
id: string;
|
||||
parentId?: string;
|
||||
tags?: string;
|
||||
tags?: string[];
|
||||
name?: string;
|
||||
avatar?: string;
|
||||
permission?: `${PermissionTypeEnum}`;
|
||||
};
|
||||
export type CreateDatasetParams = {
|
||||
parentId?: string;
|
||||
name: string;
|
||||
tags: string;
|
||||
avatar: string;
|
||||
vectorModel?: string;
|
||||
type: `${DatasetTypeEnum}`;
|
||||
};
|
||||
|
||||
export type SearchTestProps = {
|
||||
datasetId: string;
|
||||
@@ -54,20 +46,6 @@ export type UpdateDatasetCollectionParams = {
|
||||
};
|
||||
|
||||
/* ==== data ===== */
|
||||
export type SetOneDatasetDataProps = {
|
||||
id?: string;
|
||||
collectionId: string;
|
||||
q?: string; // embedding content
|
||||
a?: string; // bonus content
|
||||
};
|
||||
export type PushDataProps = {
|
||||
collectionId: string;
|
||||
data: DatasetChunkItemType[];
|
||||
mode: `${TrainingModeEnum}`;
|
||||
prompt?: string;
|
||||
billId?: string;
|
||||
};
|
||||
|
||||
export type GetDatasetDataListProps = RequestPaging & {
|
||||
searchText?: string;
|
||||
collectionId: string;
|
||||
|
35
projects/app/src/global/core/dataset/api.d.ts
vendored
Normal file
35
projects/app/src/global/core/dataset/api.d.ts
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
import { PushDatasetDataChunkProps } from '@fastgpt/global/core/dataset/api';
|
||||
import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
import { DatasetDataIndexItemType } from '@fastgpt/global/core/dataset/type';
|
||||
|
||||
/* ================= dataset ===================== */
|
||||
export type CreateDatasetParams = {
|
||||
parentId?: string;
|
||||
name: string;
|
||||
tags: string;
|
||||
avatar: string;
|
||||
vectorModel?: string;
|
||||
type: `${DatasetTypeEnum}`;
|
||||
};
|
||||
|
||||
/* ================= collection ===================== */
|
||||
|
||||
/* ================= data ===================== */
|
||||
export type InsertOneDatasetDataProps = PushDatasetDataChunkProps & {
|
||||
collectionId: string;
|
||||
};
|
||||
export type PushDatasetDataProps = {
|
||||
collectionId: string;
|
||||
data: PushDatasetDataChunkProps[];
|
||||
mode: `${TrainingModeEnum}`;
|
||||
prompt?: string;
|
||||
billId?: string;
|
||||
};
|
||||
export type UpdateDatasetDataProps = {
|
||||
id: string;
|
||||
q?: string; // embedding content
|
||||
a?: string; // bonus content
|
||||
indexes: (Omit<DatasetDataIndexItemType, 'dataId'> & {
|
||||
dataId?: string; // pg data id
|
||||
})[];
|
||||
};
|
@@ -1,5 +1,8 @@
|
||||
import { ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type';
|
||||
import { DatasetCollectionSchemaType } from '@fastgpt/global/core/dataset/type.d';
|
||||
import {
|
||||
DatasetCollectionSchemaType,
|
||||
DatasetDataSchemaType
|
||||
} from '@fastgpt/global/core/dataset/type.d';
|
||||
|
||||
/* ================= dataset ===================== */
|
||||
|
||||
@@ -11,7 +14,7 @@ export type DatasetCollectionsListItemType = {
|
||||
name: string;
|
||||
type: DatasetCollectionSchemaType['type'];
|
||||
updateTime: Date;
|
||||
dataAmount?: number;
|
||||
dataAmount: number;
|
||||
trainingAmount: number;
|
||||
metadata: DatasetCollectionSchemaType['metadata'];
|
||||
canWrite: boolean;
|
||||
@@ -19,7 +22,10 @@ export type DatasetCollectionsListItemType = {
|
||||
|
||||
/* ================= data ===================== */
|
||||
export type DatasetDataListItemType = {
|
||||
id: string;
|
||||
_id: string;
|
||||
datasetId: string;
|
||||
collectionId: string;
|
||||
q: string; // embedding content
|
||||
a: string; // bonus content
|
||||
indexes: DatasetDataSchemaType['indexes'];
|
||||
};
|
@@ -10,10 +10,10 @@ import NProgress from 'nprogress'; //nprogress module
|
||||
import Router from 'next/router';
|
||||
import { clientInitData, feConfigs } from '@/web/common/system/staticData';
|
||||
import { appWithTranslation, useTranslation } from 'next-i18next';
|
||||
import { getLangStore, setLangStore } from '@/web/common/utils/i18n';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import type { FeConfigsType } from '@fastgpt/global/common/system/types/index.d';
|
||||
import { change2DefaultLng, setLngStore } from '@/web/common/utils/i18n';
|
||||
|
||||
import 'nprogress/nprogress.css';
|
||||
import '@/web/styles/reset.scss';
|
||||
@@ -57,6 +57,7 @@ function App({ Component, pageProps }: AppProps) {
|
||||
);
|
||||
setScripts(scripts || []);
|
||||
})();
|
||||
|
||||
// add window error track
|
||||
window.onerror = function (msg, url) {
|
||||
window.umami?.track('windowError', {
|
||||
@@ -76,23 +77,22 @@ function App({ Component, pageProps }: AppProps) {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
hiId && localStorage.setItem('inviterId', hiId);
|
||||
}, [hiId]);
|
||||
// get default language
|
||||
const targetLng = change2DefaultLng(i18n.language);
|
||||
if (targetLng) {
|
||||
setLngStore(targetLng);
|
||||
router.replace(router.asPath, undefined, { locale: targetLng });
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const lang = getLangStore() || 'zh';
|
||||
i18n?.changeLanguage?.(lang);
|
||||
setLangStore(lang);
|
||||
|
||||
return () => {
|
||||
setLastRoute(router.asPath);
|
||||
};
|
||||
}, [router.asPath]);
|
||||
hiId && localStorage.setItem('inviterId', hiId);
|
||||
}, [hiId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{feConfigs?.systemTitle || 'AI'}</title>
|
||||
<title>{feConfigs?.systemTitle || process.env.SYSTEM_NAME || 'GPT'}</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="FastGPT is a knowledge-based question answering system built on the LLM. It offers out-of-the-box data processing and model invocation capabilities. Moreover, it allows for workflow orchestration through Flow visualization, thereby enabling complex question and answer scenarios!"
|
||||
|
@@ -2,7 +2,8 @@ import { Html, Head, Main, NextScript } from 'next/document';
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Html>
|
||||
<title>{process.env.SYSTEM_NAME || 'FastGPT'}</title>
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
|
@@ -25,8 +25,9 @@ function Error() {
|
||||
|
||||
return (
|
||||
<p>
|
||||
部分系统不兼容,导致页面崩溃。如果可以,请联系作者,反馈下具体操作和页面。大部分是 苹果 的
|
||||
safari 浏览器导致,可以尝试更换 chrome 浏览器。
|
||||
部分系统不兼容,导致页面崩溃。如果可以,请联系作者,反馈下具体操作和页面。 大部分是 苹果 的
|
||||
safari 浏览器导致,可以尝试更换 chrome
|
||||
浏览器。或者是因为开了中文翻译导致,请检查并关闭中文翻译。
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import ApiKeyTable from '@/components/support/apikey/Table';
|
||||
|
||||
const ApiKey = () => {
|
||||
|
@@ -16,7 +16,7 @@ import dayjs from 'dayjs';
|
||||
import { BillSourceMap } from '@fastgpt/global/support/wallet/bill/constants';
|
||||
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const BillDetail = ({ bill, onClose }: { bill: BillItemType; onClose: () => void }) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -30,7 +30,7 @@ const BillDetail = ({ bill, onClose }: { bill: BillItemType; onClose: () => void
|
||||
<ModalBody>
|
||||
<Flex alignItems={'center'} pb={4}>
|
||||
<Box flex={'0 0 80px'}>用户:</Box>
|
||||
<Box>{bill.username}</Box>
|
||||
<Box>{bill.memberName}</Box>
|
||||
</Flex>
|
||||
<Flex alignItems={'center'} pb={4}>
|
||||
<Box flex={'0 0 80px'}>订单号:</Box>
|
||||
|
@@ -55,7 +55,7 @@ const BillTable = () => {
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>{t('wallet.bill.bill username')}</Th>
|
||||
<Th>{t('user.team.Member Name')}</Th>
|
||||
<Th>{t('user.Time')}</Th>
|
||||
<Th>{t('user.Source')}</Th>
|
||||
<Th>{t('user.Application Name')}</Th>
|
||||
@@ -66,7 +66,7 @@ const BillTable = () => {
|
||||
<Tbody fontSize={'sm'}>
|
||||
{bills.map((item) => (
|
||||
<Tr key={item.id}>
|
||||
<Td>{item.username}</Td>
|
||||
<Td>{item.memberName}</Td>
|
||||
<Td>{dayjs(item.time).format('YYYY/MM/DD HH:mm:ss')}</Td>
|
||||
<Td>{BillSourceMap[item.source]}</Td>
|
||||
<Td>{t(item.appName) || '-'}</Td>
|
||||
|
@@ -1,5 +1,14 @@
|
||||
import React, { useCallback, useRef, useState } from 'react';
|
||||
import { Box, Flex, Button, useDisclosure, useTheme, Divider, Select } from '@chakra-ui/react';
|
||||
import React, { useCallback, useRef } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
Button,
|
||||
useDisclosure,
|
||||
useTheme,
|
||||
Divider,
|
||||
Select,
|
||||
Input
|
||||
} from '@chakra-ui/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { UserUpdateParams } from '@/types/user';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
@@ -16,10 +25,11 @@ import Loading from '@/components/Loading';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { getLangStore, LangEnum, langMap, setLangStore } from '@/web/common/utils/i18n';
|
||||
import { langMap, setLngStore } from '@/web/common/utils/i18n';
|
||||
import { useRouter } from 'next/router';
|
||||
import MySelect from '@/components/Select';
|
||||
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import { putUpdateMemberName } from '@/web/support/user/team/api';
|
||||
|
||||
const TeamMenu = dynamic(() => import('@/components/support/user/team/TeamMenu'));
|
||||
const PayModal = dynamic(() => import('./PayModal'), {
|
||||
@@ -63,8 +73,6 @@ const UserInfo = () => {
|
||||
multiple: false
|
||||
});
|
||||
|
||||
const [language, setLanguage] = useState<`${LangEnum}`>(getLangStore());
|
||||
|
||||
const onclickSave = useCallback(
|
||||
async (data: UserType) => {
|
||||
await updateUserInfo({
|
||||
@@ -153,6 +161,27 @@ const UserInfo = () => {
|
||||
ml={[0, 10]}
|
||||
mt={[6, 0]}
|
||||
>
|
||||
{feConfigs.isPlus && (
|
||||
<Flex mb={4} alignItems={'center'} w={['85%', '300px']}>
|
||||
<Box flex={'0 0 80px'}>{t('user.Member Name')}: </Box>
|
||||
<Input
|
||||
flex={1}
|
||||
defaultValue={userInfo?.team?.memberName || 'Member'}
|
||||
title={t('user.Edit name')}
|
||||
borderColor={'transparent'}
|
||||
pl={'10px'}
|
||||
transform={'translateX(-11px)'}
|
||||
maxLength={20}
|
||||
onBlur={(e) => {
|
||||
const val = e.target.value;
|
||||
if (val === userInfo?.team?.memberName) return;
|
||||
try {
|
||||
putUpdateMemberName(val);
|
||||
} catch (error) {}
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
<Flex alignItems={'center'} w={['85%', '300px']}>
|
||||
<Box flex={'0 0 80px'}>{t('user.Account')}: </Box>
|
||||
<Box flex={1}>{userInfo?.username}</Box>
|
||||
@@ -167,17 +196,15 @@ const UserInfo = () => {
|
||||
<Box flex={'0 0 80px'}>{t('user.Language')}: </Box>
|
||||
<Box flex={'1 0 0'}>
|
||||
<MySelect
|
||||
value={language}
|
||||
value={i18n.language}
|
||||
list={Object.entries(langMap).map(([key, lang]) => ({
|
||||
label: lang.label,
|
||||
value: key
|
||||
}))}
|
||||
onchange={(val: any) => {
|
||||
const lang = val;
|
||||
setLangStore(lang);
|
||||
setLanguage(lang);
|
||||
i18n?.changeLanguage?.(lang);
|
||||
router.reload();
|
||||
setLngStore(lang);
|
||||
router.replace(router.basePath, router.asPath, { locale: lang });
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { ModalBody, Box, Flex, Input, ModalFooter, Button } from '@chakra-ui/react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import type { UserType } from '@fastgpt/global/support/user/type.d';
|
||||
|
@@ -5,7 +5,7 @@ import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useRouter } from 'next/router';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Markdown from '@/components/Markdown';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { priceMd } from '@/web/common/system/staticData';
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { ModalBody, Box, Flex, Input, ModalFooter, Button } from '@chakra-ui/react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { updatePasswordByOld } from '@/web/support/user/api';
|
||||
|
@@ -12,7 +12,7 @@ import Tabs from '@/components/Tabs';
|
||||
import UserInfo from './components/Info';
|
||||
import { serviceSideProps } from '@/web/common/utils/i18n';
|
||||
import { feConfigs } from '@/web/common/system/staticData';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Script from 'next/script';
|
||||
|
||||
const Promotion = dynamic(() => import('./components/Promotion'));
|
||||
@@ -35,67 +35,64 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
const { t } = useTranslation();
|
||||
const { userInfo, setUserInfo } = useUserStore();
|
||||
|
||||
const tabList = useMemo(
|
||||
() => [
|
||||
{
|
||||
icon: 'meLight',
|
||||
label: t('user.Personal Information'),
|
||||
id: TabEnum.info
|
||||
},
|
||||
...(feConfigs?.isPlus
|
||||
? [
|
||||
{
|
||||
icon: 'billRecordLight',
|
||||
label: t('user.Usage Record'),
|
||||
id: TabEnum.bill
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(feConfigs?.show_promotion
|
||||
? [
|
||||
{
|
||||
icon: 'promotionLight',
|
||||
label: t('user.Promotion Record'),
|
||||
id: TabEnum.promotion
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(feConfigs?.show_pay && userInfo?.team.canWrite
|
||||
? [
|
||||
{
|
||||
icon: 'payRecordLight',
|
||||
label: t('user.Recharge Record'),
|
||||
id: TabEnum.pay
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(userInfo?.team.canWrite
|
||||
? [
|
||||
{
|
||||
icon: 'apikey',
|
||||
label: t('user.apikey.key'),
|
||||
id: TabEnum.apikey
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(feConfigs.isPlus
|
||||
? [
|
||||
{
|
||||
icon: 'informLight',
|
||||
label: t('user.Notice'),
|
||||
id: TabEnum.inform
|
||||
}
|
||||
]
|
||||
: []),
|
||||
const tabList = [
|
||||
{
|
||||
icon: 'meLight',
|
||||
label: t('user.Personal Information'),
|
||||
id: TabEnum.info
|
||||
},
|
||||
...(feConfigs?.isPlus
|
||||
? [
|
||||
{
|
||||
icon: 'billRecordLight',
|
||||
label: t('user.Usage Record'),
|
||||
id: TabEnum.bill
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(feConfigs?.show_promotion
|
||||
? [
|
||||
{
|
||||
icon: 'promotionLight',
|
||||
label: t('user.Promotion Record'),
|
||||
id: TabEnum.promotion
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(feConfigs?.show_pay && userInfo?.team.canWrite
|
||||
? [
|
||||
{
|
||||
icon: 'payRecordLight',
|
||||
label: t('user.Recharge Record'),
|
||||
id: TabEnum.pay
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(userInfo?.team.canWrite
|
||||
? [
|
||||
{
|
||||
icon: 'apikey',
|
||||
label: t('user.apikey.key'),
|
||||
id: TabEnum.apikey
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(feConfigs.isPlus
|
||||
? [
|
||||
{
|
||||
icon: 'informLight',
|
||||
label: t('user.Notice'),
|
||||
id: TabEnum.inform
|
||||
}
|
||||
]
|
||||
: []),
|
||||
|
||||
{
|
||||
icon: 'loginoutLight',
|
||||
label: t('user.Sign Out'),
|
||||
id: TabEnum.loginout
|
||||
}
|
||||
],
|
||||
[t, userInfo?.team.canWrite]
|
||||
);
|
||||
{
|
||||
icon: 'loginoutLight',
|
||||
label: t('user.Sign Out'),
|
||||
id: TabEnum.loginout
|
||||
}
|
||||
];
|
||||
|
||||
const { openConfirm, ConfirmModal } = useConfirm({
|
||||
content: '确认退出登录?'
|
||||
|
169
projects/app/src/pages/api/admin/initv46-2.ts
Normal file
169
projects/app/src/pages/api/admin/initv46-2.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { delay } from '@/utils/tools';
|
||||
import { PgClient } from '@fastgpt/service/common/pg';
|
||||
import {
|
||||
DatasetDataIndexTypeEnum,
|
||||
PgDatasetTableName
|
||||
} from '@fastgpt/global/core/dataset/constant';
|
||||
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
|
||||
import { getUserDefaultTeam } from '@fastgpt/service/support/user/team/controller';
|
||||
|
||||
let success = 0;
|
||||
/* pg 中的数据搬到 mongo dataset.datas 中,并做映射 */
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
const { limit = 50 } = req.body as { limit: number };
|
||||
await authCert({ req, authRoot: true });
|
||||
await connectToDatabase();
|
||||
success = 0;
|
||||
|
||||
try {
|
||||
await Promise.allSettled([
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ADD COLUMN data_id VARCHAR(50);`),
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ALTER COLUMN q DROP NOT NULL;`), // q can null
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ALTER COLUMN a DROP NOT NULL;`), // a can null
|
||||
PgClient.query(
|
||||
`ALTER TABLE ${PgDatasetTableName} ALTER COLUMN team_id TYPE VARCHAR(50) USING team_id::VARCHAR(50);`
|
||||
), // team_id varchar
|
||||
PgClient.query(
|
||||
`ALTER TABLE ${PgDatasetTableName} ALTER COLUMN tmb_id TYPE VARCHAR(50) USING tmb_id::VARCHAR(50);`
|
||||
), // tmb_id varchar
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ALTER COLUMN team_id SET NOT NULL;`), // team_id not null
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ALTER COLUMN tmb_id SET NOT NULL;`), // tmb_id not null
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ALTER COLUMN dataset_id SET NOT NULL;`), // dataset_id not null
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ALTER COLUMN collection_id SET NOT NULL;`) // collection_id not null
|
||||
]);
|
||||
} catch (error) {}
|
||||
|
||||
await initPgData();
|
||||
|
||||
jsonRes(res, {
|
||||
data: await init(limit),
|
||||
message:
|
||||
'初始化任务已开始,请注意日志进度。可通过 select count(id) from modeldata where data_id is null; 检查是否完全初始化,如果结果为 0 ,则完全初始化。'
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
type PgItemType = {
|
||||
id: string;
|
||||
q: string;
|
||||
a: string;
|
||||
dataset_id: string;
|
||||
collection_id: string;
|
||||
team_id: string;
|
||||
tmb_id: string;
|
||||
};
|
||||
|
||||
async function initPgData() {
|
||||
const limit = 10;
|
||||
const { rows } = await PgClient.query<{ user_id: string }>(`
|
||||
SELECT DISTINCT user_id FROM ${PgDatasetTableName} WHERE team_id='null';
|
||||
`);
|
||||
console.log('init pg', rows.length);
|
||||
let success = 0;
|
||||
for (let i = 0; i < limit; i++) {
|
||||
init(i);
|
||||
}
|
||||
async function init(index: number): Promise<any> {
|
||||
const userId = rows[index]?.user_id;
|
||||
if (!userId) return;
|
||||
try {
|
||||
const tmb = await getUserDefaultTeam({ userId });
|
||||
// update pg
|
||||
await PgClient.query(
|
||||
`Update ${PgDatasetTableName} set team_id = '${tmb.teamId}', tmb_id = '${tmb.tmbId}' where user_id = '${userId}' AND team_id='null';`
|
||||
);
|
||||
console.log(++success);
|
||||
init(index + limit);
|
||||
} catch (error) {
|
||||
if (error === 'default team not exist') {
|
||||
return;
|
||||
}
|
||||
console.log(error);
|
||||
await delay(1000);
|
||||
return init(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function init(limit: number): Promise<any> {
|
||||
const { rows: idList } = await PgClient.query<{ id: string }>(
|
||||
`SELECT id FROM ${PgDatasetTableName} WHERE data_id IS NULL`
|
||||
);
|
||||
|
||||
console.log('totalCount', idList.length);
|
||||
if (idList.length === 0) return;
|
||||
|
||||
for (let i = 0; i < limit; i++) {
|
||||
initData(i);
|
||||
}
|
||||
|
||||
async function initData(index: number): Promise<any> {
|
||||
const dataId = idList[index]?.id;
|
||||
if (!dataId) {
|
||||
console.log('done');
|
||||
return;
|
||||
}
|
||||
// get limit data where data_id is null
|
||||
const { rows } = await PgClient.query<PgItemType>(
|
||||
`SELECT id,q,a,dataset_id,collection_id,team_id,tmb_id FROM ${PgDatasetTableName} WHERE id=${dataId};`
|
||||
);
|
||||
const data = rows[0];
|
||||
if (!data) {
|
||||
console.log('done');
|
||||
return;
|
||||
}
|
||||
|
||||
let id = '';
|
||||
try {
|
||||
// create mongo data and update data_id
|
||||
const { _id } = await MongoDatasetData.create({
|
||||
teamId: data.team_id.trim(),
|
||||
tmbId: data.tmb_id.trim(),
|
||||
datasetId: data.dataset_id,
|
||||
collectionId: data.collection_id,
|
||||
q: data.q,
|
||||
a: data.a,
|
||||
indexes: [
|
||||
{
|
||||
defaultIndex: !data.a,
|
||||
type: data.a ? DatasetDataIndexTypeEnum.qa : DatasetDataIndexTypeEnum.chunk,
|
||||
dataId: data.id,
|
||||
text: data.q
|
||||
}
|
||||
]
|
||||
});
|
||||
id = _id;
|
||||
// update pg data_id
|
||||
await PgClient.query(
|
||||
`UPDATE ${PgDatasetTableName} SET data_id='${String(_id)}' WHERE id=${dataId};`
|
||||
);
|
||||
|
||||
console.log(++success);
|
||||
return initData(index + limit);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.log(data);
|
||||
|
||||
try {
|
||||
if (id) {
|
||||
await MongoDatasetData.findByIdAndDelete(id);
|
||||
}
|
||||
} catch (error) {}
|
||||
await delay(500);
|
||||
return initData(index);
|
||||
}
|
||||
}
|
||||
}
|
@@ -4,21 +4,14 @@ import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoBill } from '@fastgpt/service/support/wallet/bill/schema';
|
||||
import {
|
||||
createDefaultTeam,
|
||||
getTeamInfoByTmbId
|
||||
getUserDefaultTeam
|
||||
} from '@fastgpt/service/support/user/team/controller';
|
||||
import { MongoUser } from '@fastgpt/service/support/user/schema';
|
||||
import { UserModelSchema } from '@fastgpt/global/support/user/type';
|
||||
import { delay } from '@/utils/tools';
|
||||
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
|
||||
import {
|
||||
DatasetCollectionSchemaType,
|
||||
DatasetSchemaType,
|
||||
DatasetTrainingSchemaType
|
||||
} from '@fastgpt/global/core/dataset/type';
|
||||
import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||
import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
|
||||
import { connectionMongo } from '@fastgpt/service/common/mongo';
|
||||
import { Types } from 'mongoose';
|
||||
import { MongoDatasetTraining } from '@fastgpt/service/core/dataset/training/schema';
|
||||
import { PgClient } from '@fastgpt/service/common/pg';
|
||||
import { PgDatasetTableName } from '@fastgpt/global/core/dataset/constant';
|
||||
@@ -30,6 +23,7 @@ import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
|
||||
import { MongoPlugin } from '@fastgpt/service/core/plugin/schema';
|
||||
import { POST } from '@fastgpt/service/common/api/plusRequest';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import { getGFSCollection } from '@fastgpt/service/common/file/gridfs/controller';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
@@ -182,7 +176,7 @@ async function initMongoTeamId(limit: number) {
|
||||
|
||||
async function init(userId: string): Promise<any> {
|
||||
try {
|
||||
const tmb = await getTeamInfoByTmbId({ userId });
|
||||
const tmb = await getUserDefaultTeam({ userId });
|
||||
|
||||
await schema.updateMany(
|
||||
{
|
||||
@@ -225,7 +219,7 @@ async function initDatasetAndApp() {
|
||||
}
|
||||
async function initCollectionFileTeam(limit: number) {
|
||||
/* init user default Team */
|
||||
const DatasetFile = connectionMongo.connection.db.collection(`dataset.files`);
|
||||
const DatasetFile = getGFSCollection('dataset');
|
||||
const matchWhere = {
|
||||
$or: [{ 'metadata.teamId': { $exists: false } }, { 'metadata.teamId': null }]
|
||||
};
|
||||
@@ -264,7 +258,7 @@ async function initCollectionFileTeam(limit: number) {
|
||||
|
||||
async function init(userId: string): Promise<any> {
|
||||
try {
|
||||
const tmb = await getTeamInfoByTmbId({
|
||||
const tmb = await getUserDefaultTeam({
|
||||
userId
|
||||
});
|
||||
|
||||
@@ -295,8 +289,8 @@ async function initPgData() {
|
||||
// add column
|
||||
try {
|
||||
await Promise.all([
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ADD COLUMN team_id CHAR(50);`),
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ADD COLUMN tmb_id CHAR(50);`),
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ADD COLUMN team_id VARCHAR(50);`),
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ADD COLUMN tmb_id VARCHAR(50);`),
|
||||
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ALTER COLUMN user_id DROP NOT NULL;`)
|
||||
]);
|
||||
} catch (error) {
|
||||
@@ -316,7 +310,7 @@ async function initPgData() {
|
||||
const userId = rows[index]?.user_id;
|
||||
if (!userId) return;
|
||||
try {
|
||||
const tmb = await getTeamInfoByTmbId({ userId });
|
||||
const tmb = await getUserDefaultTeam({ userId });
|
||||
// update pg
|
||||
await PgClient.query(
|
||||
`Update ${PgDatasetTableName} set team_id = '${tmb.teamId}', tmb_id = '${tmb.tmbId}' where user_id = '${userId}' AND team_id IS NULL;`
|
||||
|
@@ -80,8 +80,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
try {
|
||||
await connectToDatabase();
|
||||
const { userId, teamId, tmbId } = await authCert({ req, authToken: true });
|
||||
console.log(req.body);
|
||||
|
||||
const { files, bucketName, metadata } = await upload.doUpload(req, res);
|
||||
|
||||
const upLoadResults = await Promise.all(
|
||||
|
@@ -4,15 +4,16 @@ import { connectToDatabase } from '@/service/mongo';
|
||||
import type { CreateQuestionGuideParams } from '@/global/core/ai/api.d';
|
||||
import { pushQuestionGuideBill } from '@/service/support/wallet/bill/push';
|
||||
import { createQuestionGuide } from '@fastgpt/service/core/ai/functions/createQuestionGuide';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import { authCertAndShareId } from '@fastgpt/service/support/permission/auth/common';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
const { messages } = req.body as CreateQuestionGuideParams;
|
||||
const { tmbId, teamId } = await authCert({
|
||||
const { messages, shareId } = req.body as CreateQuestionGuideParams;
|
||||
const { tmbId, teamId } = await authCertAndShareId({
|
||||
req,
|
||||
authToken: true
|
||||
authToken: true,
|
||||
shareId
|
||||
});
|
||||
|
||||
const qgModel = global.qgModels[0];
|
||||
|
@@ -3,10 +3,11 @@ import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
|
||||
import { getVectorModel } from '@/service/core/ai/model';
|
||||
import type { DatasetItemType } from '@/types/core/dataset';
|
||||
import type { DatasetItemType } from '@fastgpt/global/core/dataset/type.d';
|
||||
import { mongoRPermission } from '@fastgpt/global/support/permission/utils';
|
||||
import { authUserRole } from '@fastgpt/service/support/permission/auth/user';
|
||||
|
||||
/* get all dataset by teamId or tmbId */
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
@@ -20,7 +21,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
|
||||
const data = datasets.map((item) => ({
|
||||
...item.toJSON(),
|
||||
tags: item.tags.join(' '),
|
||||
vectorModel: getVectorModel(item.vectorModel),
|
||||
canWrite: String(item.tmbId) === tmbId,
|
||||
isOwner: teamOwner || String(item.tmbId) === tmbId
|
||||
|
@@ -30,15 +30,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
const collections = await findCollectionAndChild(collectionId, '_id metadata');
|
||||
const delIdList = collections.map((item) => item._id);
|
||||
|
||||
// delete pg data
|
||||
await delDataByCollectionId({ collectionIds: delIdList });
|
||||
|
||||
// delete training data
|
||||
await MongoDatasetTraining.deleteMany({
|
||||
datasetCollectionId: { $in: delIdList },
|
||||
collectionId: { $in: delIdList },
|
||||
teamId
|
||||
});
|
||||
|
||||
// delete pg data
|
||||
await delDataByCollectionId({ collectionIds: delIdList });
|
||||
|
||||
// delete file
|
||||
await Promise.all(
|
||||
collections.map((collection) => {
|
||||
|
@@ -27,8 +27,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
jsonRes<DatasetCollectionItemType>(res, {
|
||||
data: {
|
||||
...collection,
|
||||
datasetId: collection.datasetId._id,
|
||||
canWrite
|
||||
canWrite,
|
||||
sourceName: collection?.name,
|
||||
sourceId: collection?.metadata?.fileId || collection?.metadata?.rawLink
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
|
@@ -3,15 +3,15 @@ import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { DatasetTrainingCollectionName } from '@fastgpt/service/core/dataset/training/schema';
|
||||
import { Types } from '@fastgpt/service/common/mongo';
|
||||
import type { DatasetCollectionsListItemType } from '@/global/core/dataset/response';
|
||||
import type { DatasetCollectionsListItemType } from '@/global/core/dataset/type.d';
|
||||
import type { GetDatasetCollectionsProps } from '@/global/core/api/datasetReq';
|
||||
import { PagingData } from '@/types';
|
||||
import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
|
||||
import { countCollectionData } from '@/service/core/dataset/data/utils';
|
||||
import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
import { startQueue } from '@/service/utils/tools';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
import { getTeamInfoByTmbId } from '@fastgpt/service/support/user/team/controller';
|
||||
import { DatasetDataCollectionName } from '@fastgpt/service/core/dataset/data/schema';
|
||||
import { authUserRole } from '@fastgpt/service/support/permission/auth/user';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
@@ -30,7 +30,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
|
||||
// auth dataset and get my role
|
||||
const { tmbId } = await authDataset({ req, authToken: true, datasetId, per: 'r' });
|
||||
const { canWrite } = await getTeamInfoByTmbId({ tmbId });
|
||||
const { canWrite } = await authUserRole({ req, authToken: true });
|
||||
|
||||
const match = {
|
||||
datasetId: new Types.ObjectId(datasetId),
|
||||
@@ -59,7 +59,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
...item,
|
||||
dataAmount: 0,
|
||||
trainingAmount: 0,
|
||||
canWrite // admin or owner can write
|
||||
canWrite // admin or team owner can write
|
||||
}))
|
||||
),
|
||||
total: await MongoDatasetCollection.countDocuments(match)
|
||||
@@ -67,51 +67,75 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
});
|
||||
}
|
||||
|
||||
const collections: DatasetCollectionsListItemType[] = await MongoDatasetCollection.aggregate([
|
||||
{
|
||||
$match: match
|
||||
},
|
||||
{
|
||||
$lookup: {
|
||||
from: DatasetTrainingCollectionName,
|
||||
localField: '_id',
|
||||
foreignField: 'datasetCollectionId',
|
||||
as: 'trainings_amount'
|
||||
const [collections, total]: [DatasetCollectionsListItemType[], number] = await Promise.all([
|
||||
MongoDatasetCollection.aggregate([
|
||||
{
|
||||
$match: match
|
||||
},
|
||||
{
|
||||
$lookup: {
|
||||
from: DatasetTrainingCollectionName,
|
||||
let: { id: '$_id' },
|
||||
pipeline: [
|
||||
{
|
||||
$match: {
|
||||
$expr: {
|
||||
$eq: ['$collectionId', '$$id']
|
||||
}
|
||||
}
|
||||
},
|
||||
{ $project: { _id: 1 } }
|
||||
],
|
||||
as: 'trainings'
|
||||
}
|
||||
},
|
||||
{
|
||||
$lookup: {
|
||||
from: DatasetDataCollectionName,
|
||||
let: { id: '$_id' },
|
||||
pipeline: [
|
||||
{
|
||||
$match: {
|
||||
$expr: {
|
||||
$eq: ['$collectionId', '$$id']
|
||||
}
|
||||
}
|
||||
},
|
||||
{ $project: { _id: 1 } }
|
||||
],
|
||||
as: 'datas'
|
||||
}
|
||||
},
|
||||
// 统计子集合的数量和子训练的数量
|
||||
{
|
||||
$project: {
|
||||
_id: 1,
|
||||
parentId: 1,
|
||||
tmbId: 1,
|
||||
name: 1,
|
||||
type: 1,
|
||||
updateTime: 1,
|
||||
trainingAmount: { $size: '$trainings' },
|
||||
dataAmount: { $size: '$datas' },
|
||||
metadata: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
$sort: { updateTime: -1 }
|
||||
},
|
||||
{
|
||||
$skip: (pageNum - 1) * pageSize
|
||||
},
|
||||
{
|
||||
$limit: pageSize
|
||||
}
|
||||
},
|
||||
// 统计子集合的数量和子训练的数量
|
||||
{
|
||||
$project: {
|
||||
_id: 1,
|
||||
parentId: 1,
|
||||
tmbId: 1,
|
||||
name: 1,
|
||||
type: 1,
|
||||
updateTime: 1,
|
||||
trainingAmount: { $size: '$trainings_amount' },
|
||||
metadata: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
$sort: { updateTime: -1 }
|
||||
},
|
||||
{
|
||||
$skip: (pageNum - 1) * pageSize
|
||||
},
|
||||
{
|
||||
$limit: pageSize
|
||||
}
|
||||
]),
|
||||
MongoDatasetCollection.countDocuments(match)
|
||||
]);
|
||||
|
||||
const counts = await countCollectionData({
|
||||
collectionIds: collections.map((item) => item._id),
|
||||
datasetId
|
||||
});
|
||||
|
||||
const data = await Promise.all(
|
||||
collections.map(async (item, i) => ({
|
||||
...item,
|
||||
dataAmount: item.type === DatasetCollectionTypeEnum.folder ? undefined : counts[i],
|
||||
canWrite: String(item.tmbId) === tmbId || canWrite
|
||||
}))
|
||||
);
|
||||
@@ -126,7 +150,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
pageNum,
|
||||
pageSize,
|
||||
data,
|
||||
total: await MongoDatasetCollection.countDocuments(match)
|
||||
total
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import type { DatasetPathItemType } from '@/types/core/dataset';
|
||||
import type { ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type.d';
|
||||
import { getDatasetCollectionPaths } from '@fastgpt/service/core/dataset/collection/utils';
|
||||
import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
|
||||
@@ -22,7 +22,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
parentId
|
||||
});
|
||||
|
||||
jsonRes<DatasetPathItemType[]>(res, {
|
||||
jsonRes<ParentTreePathItemType[]>(res, {
|
||||
data: paths
|
||||
});
|
||||
} catch (err) {
|
||||
|
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
|
||||
import type { CreateDatasetParams } from '@/global/core/api/datasetReq.d';
|
||||
import type { CreateDatasetParams } from '@/global/core/dataset/api.d';
|
||||
import { createDefaultCollection } from './collection/create';
|
||||
import { authUserNotVisitor } from '@fastgpt/service/support/permission/auth/user';
|
||||
|
||||
|
@@ -1,10 +1,9 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { PgClient } from '@fastgpt/service/common/pg';
|
||||
import { withNextCors } from '@fastgpt/service/common/middle/cors';
|
||||
import { PgDatasetTableName } from '@fastgpt/global/core/dataset/constant';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { authDatasetData } from '@/service/support/permission/auth/dataset';
|
||||
import { deleteDataByDataId } from '@/service/core/dataset/data/controller';
|
||||
|
||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
@@ -20,11 +19,11 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
// 凭证校验
|
||||
await authDatasetData({ req, authToken: true, dataId, per: 'w' });
|
||||
|
||||
await PgClient.delete(PgDatasetTableName, {
|
||||
where: [['id', dataId]]
|
||||
});
|
||||
await deleteDataByDataId(dataId);
|
||||
|
||||
jsonRes(res);
|
||||
jsonRes(res, {
|
||||
data: 'success'
|
||||
});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
jsonRes(res, {
|
@@ -13,12 +13,9 @@ export type Response = {
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
let { dataId } = req.query as {
|
||||
const { dataId } = req.query as {
|
||||
dataId: string;
|
||||
};
|
||||
if (!dataId) {
|
||||
throw new Error('缺少参数');
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
const { datasetData } = await authDatasetData({ req, authToken: true, dataId, per: 'r' });
|
@@ -1,132 +0,0 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoUser } from '@fastgpt/service/support/user/schema';
|
||||
import { PgDatasetTableName } from '@fastgpt/global/core/dataset/constant';
|
||||
import { findAllChildrenIds } from '../delete';
|
||||
import QueryStream from 'pg-query-stream';
|
||||
import { PgClient } from '@fastgpt/service/common/pg';
|
||||
import { addLog } from '@fastgpt/service/common/mongo/controller';
|
||||
import { responseWriteController } from '@fastgpt/service/common/response';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
let { datasetId } = req.query as {
|
||||
datasetId: string;
|
||||
};
|
||||
|
||||
if (!datasetId || !global.pgClient) {
|
||||
throw new Error('缺少参数');
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
const { userId } = await authDataset({ req, authToken: true, datasetId, per: 'w' });
|
||||
|
||||
const exportIds = [datasetId, ...(await findAllChildrenIds(datasetId))];
|
||||
|
||||
const limitMinutesAgo = new Date(
|
||||
Date.now() - (global.feConfigs?.limit?.exportLimitMinutes || 0) * 60 * 1000
|
||||
);
|
||||
|
||||
// auth export times
|
||||
const authTimes = await MongoUser.findOne(
|
||||
{
|
||||
_id: userId,
|
||||
$or: [
|
||||
{ 'limit.exportKbTime': { $exists: false } },
|
||||
{ 'limit.exportKbTime': { $lte: limitMinutesAgo } }
|
||||
]
|
||||
},
|
||||
'_id limit'
|
||||
);
|
||||
|
||||
if (!authTimes) {
|
||||
const minutes = `${global.feConfigs?.limit?.exportLimitMinutes || 0} 分钟`;
|
||||
throw new Error(`上次导出未到 ${minutes},每 ${minutes}仅可导出一次。`);
|
||||
}
|
||||
|
||||
const { rows } = await PgClient.query(
|
||||
`SELECT count(id) FROM ${PgDatasetTableName} where dataset_id IN (${exportIds
|
||||
.map((id) => `'${id}'`)
|
||||
.join(',')})`
|
||||
);
|
||||
const total = rows?.[0]?.count || 0;
|
||||
|
||||
addLog.info(`export datasets: ${userId}`, { total });
|
||||
|
||||
if (total > 100000) {
|
||||
throw new Error('数据量超出 10 万,无法导出');
|
||||
}
|
||||
|
||||
// connect pg
|
||||
global.pgClient.connect((err, client, done) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.end('Error connecting to database');
|
||||
return;
|
||||
}
|
||||
if (!client) return;
|
||||
|
||||
// create pg select stream
|
||||
const query = new QueryStream(
|
||||
`SELECT q, a FROM ${PgDatasetTableName} where dataset_id IN (${exportIds
|
||||
.map((id) => `'${id}'`)
|
||||
.join(',')})`
|
||||
);
|
||||
const stream = client.query(query);
|
||||
|
||||
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
|
||||
res.setHeader('Content-Disposition', 'attachment; filename=dataset.csv; ');
|
||||
|
||||
const write = responseWriteController({
|
||||
res,
|
||||
readStream: stream
|
||||
});
|
||||
|
||||
write('index,content');
|
||||
|
||||
// parse data every row
|
||||
stream.on('data', ({ q, a }: { q: string; a: string }) => {
|
||||
if (res.closed) {
|
||||
return stream.destroy();
|
||||
}
|
||||
q = q.replace(/"/g, '""');
|
||||
a = a.replace(/"/g, '""');
|
||||
// source = source?.replace(/"/g, '""');
|
||||
|
||||
write(`\n"${q}","${a || ''}"`);
|
||||
});
|
||||
// finish
|
||||
stream.on('end', async () => {
|
||||
try {
|
||||
// update export time
|
||||
await MongoUser.findByIdAndUpdate(userId, {
|
||||
'limit.exportKbTime': new Date()
|
||||
});
|
||||
} catch (error) {}
|
||||
|
||||
// close response
|
||||
done();
|
||||
res.end();
|
||||
});
|
||||
stream.on('error', (err) => {
|
||||
done(err);
|
||||
res.end('Error exporting data');
|
||||
});
|
||||
});
|
||||
} catch (err) {
|
||||
res.status(500);
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
responseLimit: '100mb'
|
||||
}
|
||||
};
|
@@ -6,8 +6,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { withNextCors } from '@fastgpt/service/common/middle/cors';
|
||||
import { SetOneDatasetDataProps } from '@/global/core/api/datasetReq';
|
||||
import { countPromptTokens } from '@/global/common/tiktoken';
|
||||
import { countPromptTokens } from '@fastgpt/global/common/string/tiktoken';
|
||||
import { getVectorModel } from '@/service/core/ai/model';
|
||||
import { hasSameValue } from '@/service/core/dataset/data/utils';
|
||||
import { insertData2Dataset } from '@/service/core/dataset/data/controller';
|
||||
@@ -15,11 +14,12 @@ import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/
|
||||
import { getCollectionWithDataset } from '@fastgpt/service/core/dataset/controller';
|
||||
import { authTeamBalance } from '@/service/support/permission/auth/bill';
|
||||
import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
|
||||
import { InsertOneDatasetDataProps } from '@/global/core/dataset/api';
|
||||
|
||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
const { collectionId, q, a } = req.body as SetOneDatasetDataProps;
|
||||
const { collectionId, q, a, indexes } = req.body as InsertOneDatasetDataProps;
|
||||
|
||||
if (!q) {
|
||||
return Promise.reject('q is required');
|
||||
@@ -38,8 +38,6 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
per: 'w'
|
||||
});
|
||||
|
||||
await authTeamBalance(teamId);
|
||||
|
||||
// auth collection and get dataset
|
||||
const [
|
||||
{
|
||||
@@ -68,11 +66,12 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
const { insertId, tokenLen } = await insertData2Dataset({
|
||||
teamId,
|
||||
tmbId,
|
||||
datasetId,
|
||||
collectionId,
|
||||
q: formatQ,
|
||||
a: formatA,
|
||||
collectionId,
|
||||
datasetId,
|
||||
model: vectorModel
|
||||
model: vectorModel,
|
||||
indexes
|
||||
});
|
||||
|
||||
pushGenerateVectorBill({
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { PgClient } from '@fastgpt/service/common/pg';
|
||||
import { PgDatasetTableName } from '@fastgpt/global/core/dataset/constant';
|
||||
import type { DatasetDataListItemType } from '@/global/core/dataset/response.d';
|
||||
import type { DatasetDataListItemType } from '@/global/core/dataset/type.d';
|
||||
import type { GetDatasetDataListProps } from '@/global/core/api/datasetReq';
|
||||
import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
|
||||
import { PagingData } from '@/types';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
@@ -22,30 +22,29 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
|
||||
searchText = searchText.replace(/'/g, '');
|
||||
|
||||
const where: any = [
|
||||
['collection_id', collectionId],
|
||||
searchText ? `AND (q ILIKE '%${searchText}%' OR a ILIKE '%${searchText}%')` : ''
|
||||
];
|
||||
const match = {
|
||||
collectionId,
|
||||
...(searchText
|
||||
? {
|
||||
$or: [{ q: new RegExp(searchText, 'i') }, { a: new RegExp(searchText, 'i') }]
|
||||
}
|
||||
: {})
|
||||
};
|
||||
|
||||
const [searchRes, total] = await Promise.all([
|
||||
PgClient.select<DatasetDataListItemType>(PgDatasetTableName, {
|
||||
fields: ['id', 'q', 'a'],
|
||||
where,
|
||||
order: [{ field: 'id', mode: 'DESC' }],
|
||||
limit: pageSize,
|
||||
offset: pageSize * (pageNum - 1)
|
||||
}),
|
||||
PgClient.count(PgDatasetTableName, {
|
||||
fields: ['id'],
|
||||
where
|
||||
})
|
||||
const [data, total] = await Promise.all([
|
||||
MongoDatasetData.find(match, '_id datasetId collectionId q a indexes')
|
||||
.sort({ _id: -1 })
|
||||
.skip((pageNum - 1) * pageSize)
|
||||
.limit(pageSize)
|
||||
.lean(),
|
||||
MongoDatasetData.countDocuments(match)
|
||||
]);
|
||||
|
||||
jsonRes(res, {
|
||||
jsonRes<PagingData<DatasetDataListItemType>>(res, {
|
||||
data: {
|
||||
pageNum,
|
||||
pageSize,
|
||||
data: searchRes.rows,
|
||||
data,
|
||||
total
|
||||
}
|
||||
});
|
@@ -4,32 +4,27 @@ import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoDatasetTraining } from '@fastgpt/service/core/dataset/training/schema';
|
||||
import { withNextCors } from '@fastgpt/service/common/middle/cors';
|
||||
import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
import { TrainingModeEnum, TrainingTypeMap } from '@fastgpt/global/core/dataset/constant';
|
||||
import { startQueue } from '@/service/utils/tools';
|
||||
import { DatasetChunkItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import { countPromptTokens } from '@/global/common/tiktoken';
|
||||
import { countPromptTokens } from '@fastgpt/global/common/string/tiktoken';
|
||||
import type { PushDataResponse } from '@/global/core/api/datasetRes.d';
|
||||
import type { PushDataProps } from '@/global/core/api/datasetReq.d';
|
||||
import type { PushDatasetDataProps } from '@/global/core/dataset/api.d';
|
||||
import { PushDatasetDataChunkProps } from '@fastgpt/global/core/dataset/api';
|
||||
import { getVectorModel } from '@/service/core/ai/model';
|
||||
import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
import { getCollectionWithDataset } from '@fastgpt/service/core/dataset/controller';
|
||||
|
||||
const modeMap = {
|
||||
[TrainingModeEnum.index]: true,
|
||||
[TrainingModeEnum.qa]: true
|
||||
};
|
||||
|
||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
const { collectionId, data, mode = TrainingModeEnum.index } = req.body as PushDataProps;
|
||||
const { collectionId, data, mode = TrainingModeEnum.chunk } = req.body as PushDatasetDataProps;
|
||||
|
||||
if (!collectionId || !Array.isArray(data)) {
|
||||
throw new Error('collectionId or data is empty');
|
||||
}
|
||||
|
||||
if (modeMap[mode] === undefined) {
|
||||
throw new Error('Mode is not index or qa');
|
||||
if (!TrainingTypeMap[mode]) {
|
||||
throw new Error(`Mode is not ${Object.keys(TrainingTypeMap).join(', ')}`);
|
||||
}
|
||||
|
||||
if (data.length > 200) {
|
||||
@@ -68,8 +63,8 @@ export async function pushDataToDatasetCollection({
|
||||
mode,
|
||||
prompt,
|
||||
billId
|
||||
}: { teamId: string; tmbId: string } & PushDataProps): Promise<PushDataResponse> {
|
||||
// get vector model
|
||||
}: { teamId: string; tmbId: string } & PushDatasetDataProps): Promise<PushDataResponse> {
|
||||
// get dataset vector model
|
||||
const {
|
||||
datasetId: { _id: datasetId, vectorModel }
|
||||
} = await getCollectionWithDataset(collectionId);
|
||||
@@ -77,7 +72,7 @@ export async function pushDataToDatasetCollection({
|
||||
const vectorModelData = getVectorModel(vectorModel);
|
||||
|
||||
const modeMap = {
|
||||
[TrainingModeEnum.index]: {
|
||||
[TrainingModeEnum.chunk]: {
|
||||
maxToken: vectorModelData.maxToken * 1.5,
|
||||
model: vectorModelData.model
|
||||
},
|
||||
@@ -89,13 +84,12 @@ export async function pushDataToDatasetCollection({
|
||||
|
||||
// filter repeat or equal content
|
||||
const set = new Set();
|
||||
const filterResult: Record<string, DatasetChunkItemType[]> = {
|
||||
const filterResult: Record<string, PushDatasetDataChunkProps[]> = {
|
||||
success: [],
|
||||
overToken: [],
|
||||
repeat: [],
|
||||
error: []
|
||||
};
|
||||
|
||||
await Promise.all(
|
||||
data.map(async (item) => {
|
||||
if (!item.q) {
|
||||
@@ -128,13 +122,14 @@ export async function pushDataToDatasetCollection({
|
||||
teamId,
|
||||
tmbId,
|
||||
datasetId,
|
||||
datasetCollectionId: collectionId,
|
||||
collectionId,
|
||||
billId,
|
||||
mode,
|
||||
prompt,
|
||||
model: modeMap[mode].model,
|
||||
q: item.q,
|
||||
a: item.a
|
||||
a: item.a,
|
||||
indexes: item.indexes
|
||||
}))
|
||||
);
|
||||
|
||||
|
@@ -2,52 +2,50 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { withNextCors } from '@fastgpt/service/common/middle/cors';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
|
||||
import type { SetOneDatasetDataProps } from '@/global/core/api/datasetReq.d';
|
||||
import { updateData2Dataset } from '@/service/core/dataset/data/controller';
|
||||
import { authDatasetData } from '@/service/support/permission/auth/dataset';
|
||||
import { authTeamBalance } from '@/service/support/permission/auth/bill';
|
||||
import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
|
||||
import { UpdateDatasetDataProps } from '@/global/core/dataset/api';
|
||||
|
||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
const { id, collectionId, q = '', a } = req.body as SetOneDatasetDataProps;
|
||||
|
||||
if (!id || !collectionId) {
|
||||
throw new Error('缺少参数');
|
||||
}
|
||||
const { id, q = '', a, indexes } = req.body as UpdateDatasetDataProps;
|
||||
|
||||
// auth data permission
|
||||
const { datasetData, teamId, tmbId } = await authDatasetData({
|
||||
const {
|
||||
collection: {
|
||||
datasetId: { vectorModel }
|
||||
},
|
||||
teamId,
|
||||
tmbId
|
||||
} = await authDatasetData({
|
||||
req,
|
||||
authToken: true,
|
||||
dataId: id,
|
||||
per: 'w'
|
||||
});
|
||||
|
||||
// auth team balance
|
||||
await authTeamBalance(teamId);
|
||||
|
||||
// auth user and get kb
|
||||
const dataset = await MongoDataset.findById(datasetData.datasetId, 'vectorModel');
|
||||
|
||||
if (!dataset) {
|
||||
throw new Error("Can't find database");
|
||||
}
|
||||
|
||||
const { tokenLen } = await updateData2Dataset({
|
||||
dataId: id,
|
||||
q,
|
||||
a,
|
||||
model: dataset.vectorModel
|
||||
indexes,
|
||||
model: vectorModel
|
||||
});
|
||||
|
||||
pushGenerateVectorBill({
|
||||
teamId,
|
||||
tmbId,
|
||||
tokenLen: tokenLen,
|
||||
model: dataset.vectorModel
|
||||
});
|
||||
if (tokenLen) {
|
||||
pushGenerateVectorBill({
|
||||
teamId,
|
||||
tmbId,
|
||||
tokenLen: tokenLen,
|
||||
model: vectorModel
|
||||
});
|
||||
}
|
||||
|
||||
jsonRes(res);
|
||||
} catch (err) {
|
@@ -3,12 +3,12 @@ import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoDatasetTraining } from '@fastgpt/service/core/dataset/training/schema';
|
||||
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
|
||||
import { PgClient } from '@fastgpt/service/common/pg';
|
||||
import { PgDatasetTableName } from '@fastgpt/global/core/dataset/constant';
|
||||
import { delDatasetFiles } from '@fastgpt/service/core/dataset/file/controller';
|
||||
import { Types } from '@fastgpt/service/common/mongo';
|
||||
import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
import { delDataByDatasetId } from '@/service/core/dataset/data/controller';
|
||||
import { findDatasetIdTreeByTopDatasetId } from '@fastgpt/service/core/dataset/controller';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
@@ -24,17 +24,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
// auth owner
|
||||
await authDataset({ req, authToken: true, datasetId: id, per: 'owner' });
|
||||
|
||||
const deletedIds = [id, ...(await findAllChildrenIds(id))];
|
||||
const deletedIds = await findDatasetIdTreeByTopDatasetId(id);
|
||||
|
||||
// delete training data
|
||||
// delete training data(There could be a training mission)
|
||||
await MongoDatasetTraining.deleteMany({
|
||||
datasetId: { $in: deletedIds.map((id) => new Types.ObjectId(id)) }
|
||||
datasetId: { $in: deletedIds }
|
||||
});
|
||||
|
||||
// delete all pg data
|
||||
await PgClient.delete(PgDatasetTableName, {
|
||||
where: [`dataset_id IN (${deletedIds.map((id) => `'${id}'`).join(',')})`]
|
||||
});
|
||||
// delete all dataset.data and pg data
|
||||
await delDataByDatasetId({ datasetIds: deletedIds });
|
||||
|
||||
// delete related files
|
||||
await delDatasetFiles({ datasetId: id });
|
||||
@@ -57,17 +55,3 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function findAllChildrenIds(id: string) {
|
||||
// find children
|
||||
const children = await MongoDataset.find({ parentId: id });
|
||||
|
||||
let allChildrenIds = children.map((child) => String(child._id));
|
||||
|
||||
for (const child of children) {
|
||||
const grandChildrenIds = await findAllChildrenIds(child._id);
|
||||
allChildrenIds = allChildrenIds.concat(grandChildrenIds);
|
||||
}
|
||||
|
||||
return allChildrenIds;
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { getVectorModel } from '@/service/core/ai/model';
|
||||
import { DatasetItemType } from '@/types/core/dataset';
|
||||
import type { DatasetItemType } from '@fastgpt/global/core/dataset/type.d';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
@@ -27,7 +27,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
jsonRes<DatasetItemType>(res, {
|
||||
data: {
|
||||
...dataset,
|
||||
tags: dataset.tags.join(' '),
|
||||
vectorModel: getVectorModel(dataset.vectorModel),
|
||||
canWrite,
|
||||
isOwner
|
||||
|
117
projects/app/src/pages/api/core/dataset/exportAll.ts
Normal file
117
projects/app/src/pages/api/core/dataset/exportAll.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoUser } from '@fastgpt/service/support/user/schema';
|
||||
import { addLog } from '@fastgpt/service/common/mongo/controller';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
|
||||
import { findDatasetIdTreeByTopDatasetId } from '@fastgpt/service/core/dataset/controller';
|
||||
import { Readable } from 'stream';
|
||||
import type { Cursor } from '@fastgpt/service/common/mongo';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
let { datasetId } = req.query as {
|
||||
datasetId: string;
|
||||
};
|
||||
|
||||
if (!datasetId || !global.pgClient) {
|
||||
throw new Error('缺少参数');
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
const { userId } = await authDataset({ req, authToken: true, datasetId, per: 'w' });
|
||||
|
||||
const exportIds = await findDatasetIdTreeByTopDatasetId(datasetId);
|
||||
|
||||
const limitMinutesAgo = new Date(
|
||||
Date.now() - (global.feConfigs?.limit?.exportLimitMinutes || 0) * 60 * 1000
|
||||
);
|
||||
|
||||
// auth export times
|
||||
const authTimes = await MongoUser.findOne(
|
||||
{
|
||||
_id: userId,
|
||||
$or: [
|
||||
{ 'limit.exportKbTime': { $exists: false } },
|
||||
{ 'limit.exportKbTime': { $lte: limitMinutesAgo } }
|
||||
]
|
||||
},
|
||||
'_id limit'
|
||||
);
|
||||
|
||||
if (!authTimes) {
|
||||
const minutes = `${global.feConfigs?.limit?.exportLimitMinutes || 0} 分钟`;
|
||||
throw new Error(`上次导出未到 ${minutes},每 ${minutes}仅可导出一次。`);
|
||||
}
|
||||
|
||||
// auth max data
|
||||
const total = await MongoDatasetData.countDocuments({
|
||||
datasetId: { $in: exportIds }
|
||||
});
|
||||
|
||||
addLog.info(`export datasets: ${datasetId}`, { total });
|
||||
|
||||
if (total > 100000) {
|
||||
throw new Error('数据量超出 10 万,无法导出');
|
||||
}
|
||||
|
||||
res.setHeader('Content-Type', 'text/csv; charset=utf-8;');
|
||||
res.setHeader('Content-Disposition', 'attachment; filename=dataset.csv; ');
|
||||
|
||||
const cursor = MongoDatasetData.find<{
|
||||
_id: string;
|
||||
collectionId: { name: string };
|
||||
q: string;
|
||||
a: string;
|
||||
}>(
|
||||
{
|
||||
datasetId: { $in: exportIds }
|
||||
},
|
||||
'q a'
|
||||
).cursor();
|
||||
|
||||
function cursorToReadableStream(cursor: Cursor) {
|
||||
const readable = new Readable({
|
||||
objectMode: true,
|
||||
read() {}
|
||||
});
|
||||
|
||||
readable.push(`\uFEFFindex,content`);
|
||||
|
||||
cursor.on('data', (doc) => {
|
||||
const q = doc.q.replace(/"/g, '""') || '';
|
||||
const a = doc.a.replace(/"/g, '""') || '';
|
||||
|
||||
readable.push(`\n"${q}","${a}"`);
|
||||
});
|
||||
|
||||
cursor.on('end', async () => {
|
||||
readable.push(null);
|
||||
cursor.close();
|
||||
await MongoUser.findByIdAndUpdate(userId, {
|
||||
'limit.exportKbTime': new Date()
|
||||
});
|
||||
});
|
||||
|
||||
return readable;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const stream = cursorToReadableStream(cursor);
|
||||
stream.pipe(res);
|
||||
} catch (err) {
|
||||
res.status(500);
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
responseLimit: '100mb'
|
||||
}
|
||||
};
|
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { getVectorModel } from '@/service/core/ai/model';
|
||||
import type { DatasetItemType } from '@/types/core/dataset';
|
||||
import type { DatasetItemType } from '@fastgpt/global/core/dataset/type.d';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
|
||||
import { mongoRPermission } from '@fastgpt/global/support/permission/utils';
|
||||
@@ -27,7 +27,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
const data = await Promise.all(
|
||||
datasets.map(async (item) => ({
|
||||
...item.toJSON(),
|
||||
tags: item.tags.join(' '),
|
||||
vectorModel: getVectorModel(item.vectorModel),
|
||||
canWrite,
|
||||
isOwner: teamOwner || String(item.tmbId) === tmbId
|
||||
|
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
|
||||
import type { DatasetPathItemType } from '@/types/core/dataset';
|
||||
import type { ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type.d';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
@@ -19,7 +19,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
|
||||
await authDataset({ req, authToken: true, datasetId: parentId, per: 'r' });
|
||||
|
||||
jsonRes<DatasetPathItemType[]>(res, {
|
||||
jsonRes<ParentTreePathItemType[]>(res, {
|
||||
data: await getParents(parentId)
|
||||
});
|
||||
} catch (err) {
|
||||
@@ -30,7 +30,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
}
|
||||
}
|
||||
|
||||
async function getParents(parentId?: string): Promise<DatasetPathItemType[]> {
|
||||
async function getParents(parentId?: string): Promise<ParentTreePathItemType[]> {
|
||||
if (!parentId) {
|
||||
return [];
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
import { authTeamBalance } from '@/service/support/permission/auth/bill';
|
||||
import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
|
||||
import { countModelPrice } from '@/service/support/wallet/bill/utils';
|
||||
import { searchDatasetData } from '@/service/core/dataset/data/utils';
|
||||
import { searchDatasetData } from '@/service/core/dataset/data/pg';
|
||||
import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
|
||||
import { ModelTypeEnum } from '@/service/core/ai/model';
|
||||
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
|
||||
|
@@ -27,8 +27,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
url,
|
||||
data,
|
||||
{
|
||||
// @ts-ignore
|
||||
headers: req.headers
|
||||
headers: {
|
||||
...req.headers,
|
||||
// @ts-ignore
|
||||
rootkey: undefined
|
||||
}
|
||||
},
|
||||
method
|
||||
);
|
||||
|
@@ -4,7 +4,7 @@ import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { readFileSync } from 'fs';
|
||||
import type { InitDateResponse } from '@/global/common/api/systemRes';
|
||||
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import { getTikTokenEnc } from '@/global/common/tiktoken';
|
||||
import { getTikTokenEnc } from '@fastgpt/global/common/string/tiktoken';
|
||||
import { initHttpAgent } from '@fastgpt/service/common/middle/httpAgent';
|
||||
import {
|
||||
defaultChatModels,
|
||||
@@ -98,7 +98,9 @@ export function getInitConfig() {
|
||||
global.systemEnv = res.SystemParams
|
||||
? { ...defaultSystemEnv, ...res.SystemParams }
|
||||
: defaultSystemEnv;
|
||||
global.feConfigs = res.FeConfig ? { ...defaultFeConfigs, ...res.FeConfig } : defaultFeConfigs;
|
||||
global.feConfigs = res.FeConfig
|
||||
? { ...defaultFeConfigs, ...res.FeConfig, isPlus: !!res.SystemParams?.pluginBaseUrl }
|
||||
: defaultFeConfigs;
|
||||
|
||||
global.chatModels = res.ChatModels || defaultChatModels;
|
||||
global.qaModels = res.QAModels || defaultQAModels;
|
||||
|
@@ -8,10 +8,10 @@ import { getUserDetail } from '@/service/support/user/controller';
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
const { userId, tmbId } = await authCert({ req, authToken: true });
|
||||
const { tmbId } = await authCert({ req, authToken: true });
|
||||
|
||||
jsonRes(res, {
|
||||
data: await getUserDetail({ tmbId, userId })
|
||||
data: await getUserDetail({ tmbId })
|
||||
});
|
||||
} catch (err) {
|
||||
jsonRes(res, {
|
||||
|
@@ -170,7 +170,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
// auth app, get history
|
||||
const { history } = await getChatHistory({ chatId, tmbId: user.team.tmbId });
|
||||
|
||||
const isOwner = !shareId && String(user.team.tmbId) === String(app.tmbId);
|
||||
const isAppOwner = !shareId && String(user.team.tmbId) === String(app.tmbId);
|
||||
|
||||
/* format prompts */
|
||||
const prompts = history.concat(gptMessage2ChatType(messages));
|
||||
@@ -208,7 +208,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
teamId: user.team.teamId,
|
||||
tmbId: user.team.tmbId,
|
||||
variables,
|
||||
isOwner, // owner update use time
|
||||
updateUseTime: isAppOwner, // owner update use time
|
||||
shareId,
|
||||
source: (() => {
|
||||
if (shareId) {
|
||||
|
@@ -41,7 +41,7 @@ import { useRouter } from 'next/router';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { AppSchema } from '@fastgpt/global/core/app/type.d';
|
||||
import { delModelById } from '@/web/core/app/api';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { getGuideModule } from '@/global/core/app/modules/utils';
|
||||
|
||||
import dynamic from 'next/dynamic';
|
||||
@@ -481,8 +481,9 @@ const Settings = ({ appId }: { appId: string }) => {
|
||||
gridGap={[2, 4]}
|
||||
>
|
||||
{selectDatasets.map((item) => (
|
||||
<MyTooltip key={item._id} label={t('core.dataset.Read Dataset')} overflow={'hidden'}>
|
||||
<MyTooltip key={item._id} label={t('core.dataset.Read Dataset')}>
|
||||
<Flex
|
||||
overflow={'hidden'}
|
||||
alignItems={'center'}
|
||||
p={2}
|
||||
bg={'white'}
|
||||
|
@@ -20,7 +20,7 @@ import Avatar from '@/components/Avatar';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
import PermissionRadio from '@/components/support/permission/Radio';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const InfoModal = ({
|
||||
defaultApp,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import ApiKeyTable from '@/components/support/apikey/Table';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
|
||||
const API = ({ appId }: { appId: string }) => {
|
||||
|
@@ -38,7 +38,7 @@ import type { OutLinkEditType } from '@fastgpt/global/support/outLink/type.d';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import { OutLinkTypeEnum } from '@fastgpt/global/support/outLink/constant';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { feConfigs } from '@/web/common/system/staticData';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
|
@@ -3,7 +3,7 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { Box, Flex, Switch, type SwitchProps } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const QGSwitch = (props: SwitchProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
@@ -3,7 +3,7 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MySelect from '@/components/Select';
|
||||
import { TTSTypeEnum } from '@/constants/app';
|
||||
import { Text2SpeechVoiceEnum, openaiTTSModel } from '@fastgpt/global/core/ai/speech/constant';
|
||||
|
@@ -94,6 +94,7 @@ const MyApps = () => {
|
||||
label={userInfo?.team.canWrite ? t('app.To Settings') : t('app.To Chat')}
|
||||
>
|
||||
<Card
|
||||
lineHeight={1.5}
|
||||
h={'100%'}
|
||||
py={3}
|
||||
px={5}
|
||||
|
@@ -16,7 +16,7 @@ import { useRouter } from 'next/router';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import Tabs from '@/components/Tabs';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
|
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { Flex, Box, IconButton } from '@chakra-ui/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
|
@@ -20,7 +20,7 @@ import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
||||
import type { ChatHistoryItemType } from '@fastgpt/global/core/chat/type.d';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
||||
import PageContainer from '@/components/PageContainer';
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Box, Flex, useDisclosure } from '@chakra-ui/react';
|
||||
import { feConfigs } from '@/web/common/system/staticData';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import { useRouter } from 'next/router';
|
||||
import CommunityModal from '@/components/CommunityModal';
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Box, Flex, Button, Image } from '@chakra-ui/react';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { feConfigs } from '@/web/common/system/staticData';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import MyIcon from '@/components/Icon';
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { useMemo, useRef, useState } from 'react';
|
||||
import { ModalFooter, ModalBody, Input, Button } from '@chakra-ui/react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
|
||||
const EditFolderModal = ({
|
||||
|
@@ -11,7 +11,6 @@ import {
|
||||
Tbody,
|
||||
Image,
|
||||
MenuButton,
|
||||
useTheme,
|
||||
useDisclosure
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
@@ -24,7 +23,7 @@ import {
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { debounce } from 'lodash';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyInput from '@/components/MyInput';
|
||||
import dayjs from 'dayjs';
|
||||
@@ -35,13 +34,10 @@ import { usePagination } from '@/web/common/hooks/usePagination';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import MyMenu from '@/components/MyMenu';
|
||||
import { useEditTitle } from '@/web/common/hooks/useEditTitle';
|
||||
import type { DatasetCollectionsListItemType } from '@/global/core/dataset/response';
|
||||
import type { DatasetCollectionsListItemType } from '@/global/core/dataset/type.d';
|
||||
import EmptyTip from '@/components/EmptyTip';
|
||||
import { AddIcon } from '@chakra-ui/icons';
|
||||
import { FolderAvatarSrc, DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
|
||||
import { getCollectionIcon } from '@fastgpt/global/core/dataset/utils';
|
||||
|
||||
import EditFolderModal, { useEditFolder } from '../../component/EditFolderModal';
|
||||
import { TabEnum } from '..';
|
||||
import ParentPath from '@/components/common/ParentPaths';
|
||||
@@ -423,7 +419,11 @@ const CollectionCard = () => {
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
</Td>
|
||||
<Td fontSize={'md'}>{collection.dataAmount ?? '-'}</Td>
|
||||
<Td fontSize={'md'}>
|
||||
{collection.type === DatasetCollectionTypeEnum.folder
|
||||
? '-'
|
||||
: collection.dataAmount}
|
||||
</Td>
|
||||
<Td>{dayjs(collection.updateTime).format('YYYY/MM/DD HH:mm')}</Td>
|
||||
<Td>
|
||||
<Flex
|
||||
|
@@ -12,16 +12,17 @@ import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { debounce } from 'lodash';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useRouter } from 'next/router';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyInput from '@/components/MyInput';
|
||||
import { useLoading } from '@/web/common/hooks/useLoading';
|
||||
import InputDataModal, { RawSourceText, type InputDataType } from '../components/InputDataModal';
|
||||
import type { DatasetDataListItemType } from '@/global/core/dataset/response.d';
|
||||
import type { DatasetDataListItemType } from '@/global/core/dataset/type.d';
|
||||
import { TabEnum } from '..';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||
import { getDefaultIndex } from '@fastgpt/global/core/dataset/utils';
|
||||
|
||||
const DataCard = () => {
|
||||
const BoxRef = useRef<HTMLDivElement>(null);
|
||||
@@ -127,9 +128,8 @@ const DataCard = () => {
|
||||
onClick={() => {
|
||||
if (!collection) return;
|
||||
setEditInputData({
|
||||
collectionId: collection._id,
|
||||
sourceId: collection.metadata?.fileId || collection.metadata?.rawLink,
|
||||
sourceName: collection.name
|
||||
q: '',
|
||||
indexes: [getDefaultIndex({ dataId: `${Date.now()}` })]
|
||||
});
|
||||
}}
|
||||
>
|
||||
@@ -175,7 +175,7 @@ const DataCard = () => {
|
||||
>
|
||||
{datasetDataList.map((item) => (
|
||||
<Card
|
||||
key={item.id}
|
||||
key={item._id}
|
||||
cursor={'pointer'}
|
||||
pt={3}
|
||||
userSelect={'none'}
|
||||
@@ -186,12 +186,10 @@ const DataCard = () => {
|
||||
onClick={() => {
|
||||
if (!collection) return;
|
||||
setEditInputData({
|
||||
id: item.id,
|
||||
collectionId: collection._id,
|
||||
id: item._id,
|
||||
q: item.q,
|
||||
a: item.a,
|
||||
sourceId: collection.metadata?.fileId || collection.metadata?.rawLink,
|
||||
sourceName: collection.name
|
||||
indexes: item.indexes
|
||||
});
|
||||
}}
|
||||
>
|
||||
@@ -210,7 +208,7 @@ const DataCard = () => {
|
||||
</Box>
|
||||
<Flex py={2} px={4} h={'36px'} alignItems={'flex-end'} fontSize={'sm'}>
|
||||
<Box className={'textEllipsis'} flex={1} color={'myGray.500'}>
|
||||
ID:{item.id}
|
||||
ID:{item._id}
|
||||
</Box>
|
||||
{canWrite && (
|
||||
<IconButton
|
||||
@@ -228,7 +226,7 @@ const DataCard = () => {
|
||||
openConfirm(async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
await delOneDatasetDataById(item.id);
|
||||
await delOneDatasetDataById(item._id);
|
||||
getData(pageNum);
|
||||
} catch (error) {
|
||||
toast({
|
||||
@@ -262,11 +260,11 @@ const DataCard = () => {
|
||||
|
||||
{editInputData !== undefined && collection && (
|
||||
<InputDataModal
|
||||
datasetId={collection?.datasetId}
|
||||
defaultValues={editInputData}
|
||||
collectionId={collection._id}
|
||||
defaultValue={editInputData}
|
||||
onClose={() => setEditInputData(undefined)}
|
||||
onSuccess={() => getData(pageNum)}
|
||||
canWrite={canWrite}
|
||||
onDelete={() => getData(pageNum)}
|
||||
/>
|
||||
)}
|
||||
<ConfirmModal />
|
||||
|
@@ -2,7 +2,7 @@ import MyIcon from '@/components/Icon';
|
||||
import { useLoading } from '@/web/common/hooks/useLoading';
|
||||
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { splitText2Chunks } from '@/global/common/string/tools';
|
||||
import { splitText2Chunks } from '@fastgpt/global/common/string/textSplitter';
|
||||
import { simpleText } from '@fastgpt/global/common/string/tools';
|
||||
import {
|
||||
fileDownload,
|
||||
@@ -19,15 +19,13 @@ import { customAlphabet } from 'nanoid';
|
||||
import dynamic from 'next/dynamic';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import type { FetchResultItem } from '@fastgpt/global/common/plugin/types/pluginRes.d';
|
||||
import type {
|
||||
DatasetChunkItemType,
|
||||
DatasetCollectionSchemaType
|
||||
} from '@fastgpt/global/core/dataset/type';
|
||||
import type { DatasetCollectionSchemaType } from '@fastgpt/global/core/dataset/type';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import { getFileIcon } from '@fastgpt/global/common/file/icon';
|
||||
import { countPromptTokens } from '@/global/common/tiktoken';
|
||||
import { countPromptTokens } from '@fastgpt/global/common/string/tiktoken';
|
||||
import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
import type { PushDatasetDataChunkProps } from '@fastgpt/global/core/dataset/api.d';
|
||||
|
||||
const UrlFetchModal = dynamic(() => import('./UrlFetchModal'));
|
||||
const CreateFileModal = dynamic(() => import('./CreateFileModal'));
|
||||
@@ -37,7 +35,7 @@ const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
||||
export type FileItemType = {
|
||||
id: string; // fileId / raw Link
|
||||
filename: string;
|
||||
chunks: DatasetChunkItemType[];
|
||||
chunks: PushDatasetDataChunkProps[];
|
||||
text: string; // raw text
|
||||
icon: string;
|
||||
tokens: number; // total tokens
|
||||
@@ -152,7 +150,6 @@ const FileSelect = ({
|
||||
fileId
|
||||
}
|
||||
};
|
||||
console.log(fileItem);
|
||||
|
||||
onPushFiles([fileItem]);
|
||||
continue;
|
||||
|
@@ -3,7 +3,7 @@ import { Box, type BoxProps, Flex, useTheme, ModalCloseButton } from '@chakra-ui
|
||||
import MyRadio from '@/components/Radio/index';
|
||||
import dynamic from 'next/dynamic';
|
||||
import ChunkImport from './Chunk';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const QAImport = dynamic(() => import('./QA'), {});
|
||||
const CsvImport = dynamic(() => import('./Csv'), {});
|
||||
@@ -14,7 +14,7 @@ import { qaModelList } from '@/web/common/system/staticData';
|
||||
import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
|
||||
export enum ImportTypeEnum {
|
||||
index = 'index',
|
||||
chunk = 'chunk',
|
||||
qa = 'qa',
|
||||
csv = 'csv'
|
||||
}
|
||||
@@ -33,16 +33,16 @@ const ImportData = ({
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const { datasetDetail } = useDatasetStore();
|
||||
const [importType, setImportType] = useState<`${ImportTypeEnum}`>(ImportTypeEnum.index);
|
||||
const [importType, setImportType] = useState<`${ImportTypeEnum}`>(ImportTypeEnum.chunk);
|
||||
|
||||
const typeMap = useMemo(() => {
|
||||
const vectorModel = datasetDetail.vectorModel;
|
||||
const qaModel = qaModelList[0];
|
||||
const map = {
|
||||
[ImportTypeEnum.index]: {
|
||||
[ImportTypeEnum.chunk]: {
|
||||
defaultChunkLen: vectorModel?.defaultToken || 500,
|
||||
unitPrice: vectorModel?.price || 0.2,
|
||||
mode: TrainingModeEnum.index
|
||||
mode: TrainingModeEnum.chunk
|
||||
},
|
||||
[ImportTypeEnum.qa]: {
|
||||
defaultChunkLen: qaModel?.maxContext * 0.5 || 8000,
|
||||
@@ -52,7 +52,7 @@ const ImportData = ({
|
||||
[ImportTypeEnum.csv]: {
|
||||
defaultChunkLen: vectorModel?.defaultToken || 500,
|
||||
unitPrice: vectorModel?.price || 0.2,
|
||||
mode: TrainingModeEnum.index
|
||||
mode: TrainingModeEnum.chunk
|
||||
}
|
||||
};
|
||||
return map[importType];
|
||||
@@ -82,7 +82,7 @@ const ImportData = ({
|
||||
icon: 'indexImport',
|
||||
title: '直接分段',
|
||||
desc: '选择文本文件,直接将其按分段进行处理',
|
||||
value: ImportTypeEnum.index
|
||||
value: ImportTypeEnum.chunk
|
||||
},
|
||||
{
|
||||
icon: 'qaImport',
|
||||
@@ -110,7 +110,7 @@ const ImportData = ({
|
||||
onUploadSuccess={uploadSuccess}
|
||||
>
|
||||
<Box flex={'1 0 0'} h={0}>
|
||||
{importType === ImportTypeEnum.index && <ChunkImport />}
|
||||
{importType === ImportTypeEnum.chunk && <ChunkImport />}
|
||||
{importType === ImportTypeEnum.qa && <QAImport />}
|
||||
{importType === ImportTypeEnum.csv && <CsvImport />}
|
||||
</Box>
|
||||
|
@@ -12,7 +12,7 @@ import FileSelect, { FileItemType, Props as FileSelectProps } from './FileSelect
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { postDatasetCollection } from '@/web/core/dataset/api';
|
||||
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import { splitText2Chunks } from '@/global/common/string/tools';
|
||||
import { splitText2Chunks } from '@fastgpt/global/common/string/textSplitter';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
@@ -22,7 +22,7 @@ import DeleteIcon, { hoverDeleteStyles } from '@/components/Icon/delete';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import { chunksUpload } from '@/web/core/dataset/utils';
|
||||
import { postCreateTrainingBill } from '@/web/support/wallet/bill/api';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { ImportTypeEnum } from './ImportModal';
|
||||
|
||||
const filenameStyles = {
|
||||
@@ -39,7 +39,7 @@ type useImportStoreType = {
|
||||
setSuccessChunks: Dispatch<SetStateAction<number>>;
|
||||
isUnselectedFile: boolean;
|
||||
totalChunks: number;
|
||||
onclickUpload: (e: { files: FileItemType[] }) => void;
|
||||
onclickUpload: (e: { prompt?: string }) => void;
|
||||
onReSplitChunks: () => void;
|
||||
price: number;
|
||||
uploading: boolean;
|
||||
@@ -49,7 +49,7 @@ type useImportStoreType = {
|
||||
setReShowRePreview: Dispatch<SetStateAction<boolean>>;
|
||||
};
|
||||
const StateContext = createContext<useImportStoreType>({
|
||||
onclickUpload: function (e: { files: FileItemType[] }): void {
|
||||
onclickUpload: function (e: { prompt?: string }): void {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
uploading: false,
|
||||
@@ -125,7 +125,8 @@ const Provider = ({
|
||||
|
||||
/* start upload data */
|
||||
const { mutate: onclickUpload, isLoading: uploading } = useRequest({
|
||||
mutationFn: async () => {
|
||||
mutationFn: async (props?: { prompt?: string }) => {
|
||||
const { prompt } = props || {};
|
||||
let totalInsertion = 0;
|
||||
for await (const file of files) {
|
||||
const chunks = file.chunks;
|
||||
@@ -150,7 +151,8 @@ const Provider = ({
|
||||
mode,
|
||||
onUploading: (insertLen) => {
|
||||
setSuccessChunks((state) => state + insertLen);
|
||||
}
|
||||
},
|
||||
prompt
|
||||
});
|
||||
totalInsertion += insertLen;
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { QuestionOutlineIcon, InfoOutlineIcon } from '@chakra-ui/icons';
|
||||
import { Prompt_AgentQA } from '@/global/core/prompt/agent';
|
||||
import { replaceVariable } from '@/global/common/string/tools';
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import { useImportStore, SelectorContainer, PreviewFileOrChunk } from './Provider';
|
||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
|
||||
@@ -81,7 +81,10 @@ const QAImport = () => {
|
||||
重新生成预览
|
||||
</Button>
|
||||
)}
|
||||
<Button isDisabled={uploading} onClick={openConfirm(onclickUpload)}>
|
||||
<Button
|
||||
isDisabled={uploading}
|
||||
onClick={openConfirm(() => onclickUpload({ prompt: previewQAPrompt }))}
|
||||
>
|
||||
{uploading ? <Box>{Math.round((successChunks / totalChunks) * 100)}%</Box> : '确认导入'}
|
||||
</Button>
|
||||
</Flex>
|
||||
|
@@ -16,11 +16,11 @@ import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { UseFormReturn } from 'react-hook-form';
|
||||
import { compressImgAndUpload } from '@/web/common/file/controller';
|
||||
import type { DatasetItemType } from '@/types/core/dataset';
|
||||
import type { DatasetItemType } from '@fastgpt/global/core/dataset/type.d';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import Tag from '@/components/Tag';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import PermissionRadio from '@/components/support/permission/Radio';
|
||||
|
||||
export interface ComponentRef {
|
||||
@@ -208,13 +208,15 @@ const Info = (
|
||||
placeholder={'标签,使用空格分割。'}
|
||||
maxLength={30}
|
||||
onChange={(e) => {
|
||||
setValue('tags', e.target.value);
|
||||
setValue(
|
||||
'tags',
|
||||
e.target.value.split(' ').filter((item) => item)
|
||||
);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
<Flex w={'100%'} pl={['90px', '160px']} mt={2}>
|
||||
{getValues('tags')
|
||||
.split(' ')
|
||||
.filter((item) => item)
|
||||
.map((item, i) => (
|
||||
<Tag mr={2} mb={2} key={i} whiteSpace={'nowrap'}>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user