4.6.4-alpha (#582)

This commit is contained in:
Archer
2023-12-08 15:01:11 +08:00
committed by GitHub
parent 54d52d8d25
commit b58249fc3a
66 changed files with 962 additions and 527 deletions

View File

@@ -2,7 +2,10 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { delFileById, getGFSCollection } from '@fastgpt/service/common/file/gridfs/controller';
import {
delFileByFileIdList,
getGFSCollection
} from '@fastgpt/service/common/file/gridfs/controller';
import { addLog } from '@fastgpt/service/common/mongo/controller';
import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
import { delay } from '@fastgpt/global/common/system/utils';
@@ -77,7 +80,7 @@ export async function checkFiles(start: Date, end: Date, limit: number) {
// 3. if not found, delete file
if (hasCollection === 0) {
await delFileById({ bucketName: 'dataset', fileId: String(_id) });
await delFileByFileIdList({ bucketName: 'dataset', fileIdList: [String(_id)] });
console.log('delete file', _id);
deleteFileAmount++;
}

View File

@@ -4,6 +4,7 @@ import { connectToDatabase } from '@/service/mongo';
import { authFileToken } from '@fastgpt/service/support/permission/controller';
import { detect } from 'jschardet';
import { getDownloadStream, getFileById } from '@fastgpt/service/common/file/gridfs/controller';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -22,6 +23,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
getDownloadStream({ bucketName, fileId })
]);
if (!file) {
return Promise.reject(CommonErrEnum.fileNotFound);
}
// get encoding
let buffers: Buffer = Buffer.from([]);
for await (const chunk of encodeStream) {

View File

@@ -1,21 +1,22 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { authCertOrShareId } from '@fastgpt/service/support/permission/auth/common';
import { uploadMongoImg } from '@fastgpt/service/common/file/image/controller';
type Props = { base64Img: string; expiredTime?: Date };
import { UploadImgProps } from '@fastgpt/global/common/file/api';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
await connectToDatabase();
const { teamId } = await authCert({ req, authToken: true });
const { base64Img, expiredTime } = req.body as Props;
const { base64Img, expiredTime, metadata, shareId } = req.body as UploadImgProps;
const { teamId } = await authCertOrShareId({ req, shareId, authToken: true });
const data = await uploadMongoImg({
teamId,
base64Img,
expiredTime
expiredTime,
metadata
});
jsonRes(res, { data });

View File

@@ -4,13 +4,14 @@ 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 { authCertAndShareId } from '@fastgpt/service/support/permission/auth/common';
import { authCertOrShareId } from '@fastgpt/service/support/permission/auth/common';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
await connectToDatabase();
const { messages, shareId } = req.body as CreateQuestionGuideParams;
const { tmbId, teamId } = await authCertAndShareId({
const { tmbId, teamId } = await authCertOrShareId({
req,
authToken: true,
shareId

View File

@@ -4,6 +4,9 @@ import { connectToDatabase } from '@/service/mongo';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import type { AppUpdateParams } from '@fastgpt/global/core/app/api';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import { getChatModel } from '@/service/core/ai/model';
/* 获取我的模型 */
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
@@ -20,6 +23,36 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 凭证校验
await authApp({ req, authToken: true, appId, per: permission ? 'owner' : 'w' });
// check modules
// 1. dataset search limit, less than model quoteMaxToken
if (modules) {
let maxTokens = 3000;
modules.forEach((item) => {
if (item.flowType === FlowNodeTypeEnum.chatNode) {
const model =
item.inputs.find((item) => item.key === ModuleInputKeyEnum.aiModel)?.value || '';
const chatModel = getChatModel(model);
const quoteMaxToken = chatModel.quoteMaxToken || 3000;
maxTokens = Math.max(maxTokens, quoteMaxToken);
}
});
modules.forEach((item) => {
if (item.flowType === FlowNodeTypeEnum.datasetSearchNode) {
item.inputs.forEach((input) => {
if (input.key === ModuleInputKeyEnum.datasetLimit) {
const val = input.value as number;
if (val > maxTokens) {
input.value = maxTokens;
}
}
});
}
});
}
// 更新模型
await MongoApp.updateOne(
{

View File

@@ -10,6 +10,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
await connectToDatabase();
const { chatId, contentId, shareId, outLinkUid } = req.query as DeleteChatItemProps;
if (!contentId || !chatId) {
return jsonRes(res);
}
await autChatCrud({
req,
authToken: true,

View File

@@ -4,7 +4,7 @@ import { connectToDatabase } from '@/service/mongo';
import { GetChatSpeechProps } from '@/global/core/chat/api.d';
import { text2Speech } from '@fastgpt/service/core/ai/audio/speech';
import { pushAudioSpeechBill } from '@/service/support/wallet/bill/push';
import { authCertAndShareId } from '@fastgpt/service/support/permission/auth/common';
import { authCertOrShareId } from '@fastgpt/service/support/permission/auth/common';
import { authType2BillSource } from '@/service/support/wallet/bill/utils';
import { getAudioSpeechModel } from '@/service/core/ai/model';
import { MongoTTSBuffer } from '@fastgpt/service/common/buffer/tts/schema';
@@ -25,7 +25,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
throw new Error('model or voice not found');
}
const { teamId, tmbId, authType } = await authCertAndShareId({ req, authToken: true, shareId });
const { teamId, tmbId, authType } = await authCertOrShareId({ req, authToken: true, shareId });
const ttsModel = getAudioSpeechModel(ttsConfig.model);
const voiceData = ttsModel.voices?.find((item) => item.value === ttsConfig.voice);

View File

@@ -24,13 +24,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
});
// find all delete id
const collections = await findCollectionAndChild(collectionId, '_id metadata');
const collections = await findCollectionAndChild(collectionId, '_id fileId');
const delIdList = collections.map((item) => item._id);
// delete
await delCollectionRelevantData({
collectionIds: delIdList,
fileIds: collections.map((item) => item.metadata?.fileId).filter(Boolean)
fileIds: collections.map((item) => item?.fileId || '').filter(Boolean)
});
// delete collection

View File

@@ -4,7 +4,6 @@ import { connectToDatabase } from '@/service/mongo';
import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/dataset';
import { loadingOneChunkCollection } from '@fastgpt/service/core/dataset/collection/utils';
import { delCollectionRelevantData } from '@fastgpt/service/core/dataset/data/controller';
import { createOneCollection } from '@fastgpt/service/core/dataset/collection/controller';
import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constant';
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';

View File

@@ -15,8 +15,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
throw new Error('缺少参数');
}
// 凭证校验
await authDataset({ req, authToken: true, datasetId: id, per: 'owner' });
if (permission) {
await authDataset({ req, authToken: true, datasetId: id, per: 'owner' });
} else {
await authDataset({ req, authToken: true, datasetId: id, per: 'w' });
}
await MongoDataset.findOneAndUpdate(
{

View File

@@ -21,7 +21,6 @@ import type { AppSimpleEditFormType } from '@fastgpt/global/core/app/type.d';
import { chatModelList, simpleModeTemplates } from '@/web/common/system/staticData';
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import { chatNodeSystemPromptTip, welcomeTextTip } from '@fastgpt/global/core/module/template/tip';
import type { VariableItemType } from '@fastgpt/global/core/module/type.d';
import type { ModuleItemType } from '@fastgpt/global/core/module/type';
import { useRequest } from '@/web/common/hooks/useRequest';
import { useConfirm } from '@/web/common/hooks/useConfirm';
@@ -67,7 +66,6 @@ function ConfigForm({
}) {
const theme = useTheme();
const router = useRouter();
const { toast } = useToast();
const { t } = useTranslation();
const { appDetail, updateAppDetail } = useAppStore();
const { loadAllDatasets, allDatasets } = useDatasetStore();
@@ -124,6 +122,13 @@ function ConfigForm({
[getValues, refresh]
);
const tokenLimit = useMemo(() => {
return (
chatModelList.find((item) => item.model === getValues('aiSettings.model'))?.quoteMaxToken ||
3000
);
}, [getValues, refresh]);
const { mutate: onSubmitSave, isLoading: isSaving } = useRequest({
mutationFn: async (data: AppSimpleEditFormType) => {
const modules = await postForm2Modules(data, data.templateId);
@@ -361,8 +366,8 @@ function ConfigForm({
)}
</Flex>
<Flex mt={1} color={'myGray.600'} fontSize={['sm', 'md']}>
{t('core.dataset.Similarity')}: {getValues('dataset.similarity')},{' '}
{t('core.dataset.Search Top K')}: {getValues('dataset.limit')}
{t('core.dataset.search.Min Similarity')}: {getValues('dataset.similarity')},{' '}
{t('core.dataset.search.Max Tokens')}: {getValues('dataset.limit')}
{getValues('dataset.searchEmptyText') === ''
? ''
: t('core.dataset.Set Empty Result Tip')}
@@ -458,6 +463,7 @@ function ConfigForm({
{isOpenDatasetParams && (
<DatasetParamsModal
{...getValues('dataset')}
maxTokens={tokenLimit}
onClose={onCloseKbParams}
onSuccess={(e) => {
setValue('dataset', {

View File

@@ -15,6 +15,7 @@ import Loading from '@/components/Loading';
import SimpleEdit from './components/SimpleEdit';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { useAppStore } from '@/web/core/app/store/useAppStore';
import Head from 'next/head';
const AdEdit = dynamic(() => import('./components/AdEdit'), {
loading: () => <Loading />
@@ -92,90 +93,95 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
});
return (
<PageContainer>
<Flex flexDirection={['column', 'row']} h={'100%'}>
{/* pc tab */}
<Box
display={['none', 'flex']}
flexDirection={'column'}
p={4}
w={'180px'}
borderRight={theme.borders.base}
>
<Flex mb={4} alignItems={'center'}>
<Avatar src={appDetail.avatar} w={'34px'} borderRadius={'lg'} />
<Box ml={2} fontWeight={'bold'} fontSize={'sm'}>
<>
<Head>
<title>{appDetail.name}</title>
</Head>
<PageContainer>
<Flex flexDirection={['column', 'row']} h={'100%'}>
{/* pc tab */}
<Box
display={['none', 'flex']}
flexDirection={'column'}
p={4}
w={'180px'}
borderRight={theme.borders.base}
>
<Flex mb={4} alignItems={'center'}>
<Avatar src={appDetail.avatar} w={'34px'} borderRadius={'lg'} />
<Box ml={2} fontWeight={'bold'} fontSize={'sm'}>
{appDetail.name}
</Box>
</Flex>
<SideTabs
flex={1}
mx={'auto'}
mt={2}
w={'100%'}
list={tabList}
activeId={currentTab}
onChange={(e: any) => {
if (e === 'startChat') {
router.push(`/chat?appId=${appId}`);
} else {
setCurrentTab(e);
}
}}
/>
<Flex
alignItems={'center'}
cursor={'pointer'}
py={2}
px={3}
borderRadius={'md'}
_hover={{ bg: 'myGray.100' }}
onClick={() => router.replace('/app/list')}
>
<IconButton
mr={3}
icon={<MyIcon name={'backFill'} w={'18px'} color={'myBlue.600'} />}
bg={'white'}
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
h={'28px'}
size={'sm'}
borderRadius={'50%'}
aria-label={''}
/>
</Flex>
</Box>
{/* phone tab */}
<Box display={['block', 'none']} textAlign={'center'} py={3}>
<Box className="textlg" fontSize={'xl'} fontWeight={'bold'}>
{appDetail.name}
</Box>
</Flex>
<SideTabs
flex={1}
mx={'auto'}
mt={2}
w={'100%'}
list={tabList}
activeId={currentTab}
onChange={(e: any) => {
if (e === 'startChat') {
router.push(`/chat?appId=${appId}`);
} else {
setCurrentTab(e);
}
}}
/>
<Flex
alignItems={'center'}
cursor={'pointer'}
py={2}
px={3}
borderRadius={'md'}
_hover={{ bg: 'myGray.100' }}
onClick={() => router.replace('/app/list')}
>
<IconButton
mr={3}
icon={<MyIcon name={'backFill'} w={'18px'} color={'myBlue.600'} />}
bg={'white'}
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
h={'28px'}
<Tabs
mx={'auto'}
mt={2}
w={'100%'}
list={tabList}
size={'sm'}
borderRadius={'50%'}
aria-label={''}
activeId={currentTab}
onChange={(e: any) => {
if (e === 'startChat') {
router.push(`/chat?appId=${appId}`);
} else {
setCurrentTab(e);
}
}}
/>
</Flex>
</Box>
{/* phone tab */}
<Box display={['block', 'none']} textAlign={'center'} py={3}>
<Box className="textlg" fontSize={'xl'} fontWeight={'bold'}>
{appDetail.name}
</Box>
<Tabs
mx={'auto'}
mt={2}
w={'100%'}
list={tabList}
size={'sm'}
activeId={currentTab}
onChange={(e: any) => {
if (e === 'startChat') {
router.push(`/chat?appId=${appId}`);
} else {
setCurrentTab(e);
}
}}
/>
</Box>
<Box flex={'1 0 0'} h={[0, '100%']} overflow={['overlay', '']}>
{currentTab === TabEnum.simpleEdit && <SimpleEdit appId={appId} />}
{currentTab === TabEnum.adEdit && appDetail && (
<AdEdit app={appDetail} onClose={() => setCurrentTab(TabEnum.simpleEdit)} />
)}
{currentTab === TabEnum.logs && <Logs appId={appId} />}
{currentTab === TabEnum.outLink && <OutLink appId={appId} />}
</Box>
</Flex>
</PageContainer>
<Box flex={'1 0 0'} h={[0, '100%']} overflow={['overlay', '']}>
{currentTab === TabEnum.simpleEdit && <SimpleEdit appId={appId} />}
{currentTab === TabEnum.adEdit && appDetail && (
<AdEdit app={appDetail} onClose={() => setCurrentTab(TabEnum.simpleEdit)} />
)}
{currentTab === TabEnum.logs && <Logs appId={appId} />}
{currentTab === TabEnum.outLink && <OutLink appId={appId} />}
</Box>
</Flex>
</PageContainer>
</>
);
};

View File

@@ -1,7 +1,7 @@
import React, { useCallback, useRef } from 'react';
import Head from 'next/head';
import { useRouter } from 'next/router';
import { getInitChatInfo, putChatHistory } from '@/web/core/chat/api';
import { getInitChatInfo } from '@/web/core/chat/api';
import {
Box,
Flex,

View File

@@ -116,7 +116,9 @@ const OutLink = ({
updateHistory({
...currentChat,
updateTime: new Date(),
title: newTitle
title: newTitle,
shareId,
outLinkUid
});
}
@@ -148,7 +150,7 @@ const OutLink = ({
return { responseText, responseData, isNewChat: forbidRefresh.current };
},
[chatId, shareId, outLinkUid, setChatData, appId, updateHistory, router, histories]
[chatId, shareId, outLinkUid, setChatData, appId, pushHistory, router, histories, updateHistory]
);
const loadChatInfo = useCallback(
@@ -309,13 +311,19 @@ const OutLink = ({
});
}}
onSetHistoryTop={(e) => {
updateHistory(e);
updateHistory({
...e,
shareId,
outLinkUid
});
}}
onSetCustomTitle={async (e) => {
updateHistory({
chatId: e.chatId,
title: e.title,
customTitle: e.title
customTitle: e.title,
shareId,
outLinkUid
});
}}
/>
@@ -349,7 +357,7 @@ const OutLink = ({
feedbackType={'user'}
onUpdateVariable={(e) => {}}
onStartChat={startChat}
onDelMessage={(e) => delOneHistoryItem({ ...e, chatId })}
onDelMessage={(e) => delOneHistoryItem({ ...e, chatId, shareId, outLinkUid })}
/>
</Box>
</Flex>

View File

@@ -173,7 +173,9 @@ const FileSelect = ({
case 'pdf':
return readPdfContent(file);
case 'docx':
return readDocContent(file);
return readDocContent(file, {
fileId
});
}
return '';
})();

View File

@@ -408,7 +408,7 @@ export function RawSourceText({
await getFileAndOpen(sourceId as string);
} catch (error) {
toast({
title: getErrText(error, '获取文件地址失败'),
title: t(getErrText(error, 'error.fileNotFound')),
status: 'error'
});
}

View File

@@ -9,7 +9,6 @@ import { oauthLogin } from '@/web/support/user/api';
import { useToast } from '@/web/common/hooks/useToast';
import Loading from '@/components/Loading';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { useQuery } from '@tanstack/react-query';
import { getErrText } from '@fastgpt/global/common/error/utils';
const provider = ({ code, state }: { code: string; state: string }) => {