V4.9.1 feature (#4206)

* fix: remove DefaultTeam (#4037)

* fix :Get application bound knowledge base information logical rewrite (#4057)

* fix :Get application bound knowledge base information logical rewrite

* fix :Get application bound knowledge base information logical rewrite

* fix :Get application bound knowledge base information logical rewrite

* fix :Get application bound knowledge base information logical rewrite

* update package

* fix: import dataset step error;perf: ai proxy avatar (#4074)

* perf: pg config params

* perf: ai proxy avatar

* fix: import dataset step error

* feat: data input ux

* perf: app dataset rewite

* fix: 文本提取不支持arrayString,arrayNumber等jsonSchema (#4079)

* update doc ;perf: model test (#4098)

* perf: extract array

* update doc

* perf: model test

* perf: model test

* perf: think tag parse (#4102)

* chat quote reader (#3912)

* init chat quote full text reader

* linked structure

* dataset data linked

* optimize code

* fix ts build

* test finish

* delete log

* fix

* fix ts

* fix ts

* remove nextId

* initial scroll

* fix

* fix

* perf: chunk read   (#4109)

* package

* perf: chunk read

* feat: api dataset support pdf parse;fix: chunk reader auth (#4117)

* feat: api dataset support pdf parse

* fix: chunk reader auth

* feat: invitation link (#3979)

* feat: invitation link schema and apis

* feat: add invitation link

* feat: member status: active, leave, forbidden

* fix: expires show hours and minutes

* feat: invalid invitation link hint

* fix: typo

* chore: fix typo & i18n

* fix

* pref: fe

* feat: add ttl index for 30-day-clean-up

* perf: invite member code (#4118)

* perf: invite member code

* fix: ts

* fix: model test channel id;fix: quote reader (#4123)

* fix: model test channel id

* fix: quote reader

* fix chat quote reader (#4125)

* perf: model test;perf: sidebar trigger (#4127)

* fix: import dataset step error;perf: ai proxy avatar (#4074)

* perf: pg config params

* perf: ai proxy avatar

* fix: import dataset step error

* feat: data input ux

* perf: app dataset rewite

* perf: model test

* perf: sidebar trigger

* lock

* update nanoid version

* fix: select component ux

* fix: ts

* fix: vitest

* remove test

* fix: prompt toolcall ui (#4139)

* load log error adapt

* fix: prompt toolcall ui

* perf: commercial function tip

* update package

* pref: copy link (#4147)

* fix(i18n): namespace (#4143)

* hiden dataset source (#4152)

* hiden dataset source

* perf: reader

* chore: move all tests into a single folder (#4160)

* fix modal close scroll (#4162)

* fix modal close scroll

* update refresh

* feat: rerank modal select and weight (#4164)

* fix loadInitData refresh (#4169)

* fix

* fix

* form input number default & api dataset max token

* feat: mix search weight (#4170)

* feat: mix search weight

* feat: svg render

* fix: avatar error remove (#4173)

* fix: avatar error remove

* fix: index

* fix: guide

* fix: auth

* update package;fix: input data model ui (#4181)

* update package

* fix: ts

* update config

* update jieba package

* add type sign

* fix: input data ui

* fix: page title refresh (#4186)

* fix: ts

* update jieba package

* fix: page title refresh

* fix: remove member length check when opening invite create modal (#4193)

* add env to check internal ip (#4187)

* fix: ts

* update jieba package

* add env to check internal ip

* package

* fix: jieba

* reset package

* update config

* fix: jieba package

* init shell

* init version

* change team reload

* update jieba package (#4200)

* update jieba package

* package

* update package

* remove invalid code

* action

* package (#4201)

* package

* update package

* remove invalid code

* package

* remove i18n tip (#4202)

* doc (#4205)

* fix: i18n (#4208)

* fix: next config (#4207)

* reset package

* i18n

* update config

* i18n

* remove log

---------

Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
Co-authored-by: gggaaallleee <91131304+gggaaallleee@users.noreply.github.com>
Co-authored-by: shilin <39396378+shilin66@users.noreply.github.com>
Co-authored-by: heheer <heheer@sealos.io>
This commit is contained in:
Archer
2025-03-18 14:40:41 +08:00
committed by GitHub
parent 56793114d8
commit e75d81d05a
316 changed files with 10626 additions and 8464 deletions

View File

@@ -15,6 +15,7 @@ import { ReactElement, useEffect } from 'react';
import { NextPage } from 'next';
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
import SystemStoreContextProvider from '@fastgpt/web/context/useSystem';
import { useRouter } from 'next/router';
type NextPageWithLayout = NextPage & {
setLayout?: (page: ReactElement) => JSX.Element;
@@ -23,6 +24,15 @@ type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout;
};
// 哪些路由有自定义 Head
const routesWithCustomHead = [
'/chat',
'/chat/share',
'chat/team',
'/app/detail/',
'/dataset/detail'
];
function App({ Component, pageProps }: AppPropsWithLayout) {
const { feConfigs, scripts, title } = useInitApp();
const { t } = useTranslation();
@@ -42,17 +52,23 @@ function App({ Component, pageProps }: AppPropsWithLayout) {
const setLayout = Component.setLayout || ((page) => <>{page}</>);
const router = useRouter();
const showHead = !router?.pathname || !routesWithCustomHead.includes(router.pathname);
return (
<>
<NextHead
title={title}
desc={
feConfigs?.systemDescription ||
process.env.SYSTEM_DESCRIPTION ||
`${title}${t('app:intro')}`
}
icon={getWebReqUrl(feConfigs?.favicon || process.env.SYSTEM_FAVICON)}
/>
{showHead && (
<NextHead
title={title}
desc={
feConfigs?.systemDescription ||
process.env.SYSTEM_DESCRIPTION ||
`${title}${t('app:intro')}`
}
icon={getWebReqUrl(feConfigs?.favicon || process.env.SYSTEM_FAVICON)}
/>
)}
{scripts?.map((item, i) => <Script key={i} strategy="lazyOnload" {...item}></Script>)}
<QueryClientContext>

View File

@@ -1,6 +1,6 @@
import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { Box } from '@chakra-ui/react';
import { TrackEventName } from '@/web/common/system/constants';
@@ -57,7 +57,7 @@ function Error() {
<Box whiteSpace={'pre-wrap'}>
{`出现未捕获的异常。
1. 私有部署用户90%是由于模型配置不正确/模型未启用导致。。
2. 部分系统不兼容相关API。大部分是苹果的safari 浏览器导致,可以尝试更换 chrome。
2. 部分系统不兼容相关API。大部分是苹果的safari 浏览器导致,可以尝试更换 chrome。
3. 请关闭浏览器翻译功能,部分翻译导致页面崩溃。
排除3后打开控制台的 console 查看具体报错信息。

View File

@@ -3,7 +3,7 @@ import ApiKeyTable from '@/components/support/apikey/Table';
import { useTranslation } from 'next-i18next';
import { Box } from '@chakra-ui/react';
import AccountContainer, { TabEnum } from '@/pageComponents/account/AccountContainer';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
const ApiKey = () => {
const { t } = useTranslation();

View File

@@ -6,7 +6,7 @@ import { useTranslation } from 'next-i18next';
import ApplyInvoiceModal from '@/pageComponents/account/bill/ApplyInvoiceModal';
import { useRouter } from 'next/router';
import AccountContainer from '@/pageComponents/account/AccountContainer';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
export enum InvoiceTabEnum {
bill = 'bill',

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useMemo } from 'react';
import React, { useCallback, useEffect, useMemo } from 'react';
import {
Box,
Flex,
@@ -39,11 +39,12 @@ import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
import AccountContainer from '@/pageComponents/account/AccountContainer';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { useRouter } from 'next/router';
import TeamSelector from '@/pageComponents/account/TeamSelector';
import { getWorkorderURL } from '@/web/common/workorder/api';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useMount } from 'ahooks';
const StandDetailModal = dynamic(
() => import('@/pageComponents/account/info/standardDetailModal'),
@@ -64,7 +65,9 @@ const Info = () => {
const standardPlan = teamPlanStatus?.standardConstants;
const { isOpen: isOpenContact, onClose: onCloseContact, onOpen: onOpenContact } = useDisclosure();
useQuery(['init'], initUserInfo);
useMount(() => {
initUserInfo();
});
return (
<AccountContainer>
@@ -260,7 +263,7 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
)}
{feConfigs?.isPlus && (
<Flex mt={6} alignItems={'center'}>
<Box {...labelStyles}>{t('account_info:contact')}:&nbsp;</Box>
<Box {...labelStyles}>{t('common:contact_way')}:&nbsp;</Box>
<Box flex={1} {...(!userInfo?.contact ? { color: 'red.600' } : {})}>
{userInfo?.contact ? userInfo?.contact : t('account_info:please_bind_contact')}
</Box>
@@ -274,7 +277,7 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
<Flex mt={6} alignItems={'center'}>
<Box {...labelStyles}>{t('account_info:user_team_team_name')}:&nbsp;</Box>
<Flex flex={'1 0 0'} w={0} align={'center'}>
<TeamSelector height={'28px'} w={'100%'} showManage onChange={initUserInfo} />
<TeamSelector height={'28px'} w={'100%'} showManage />
</Flex>
</Flex>
)}

View File

@@ -7,7 +7,7 @@ import { useLoading } from '@fastgpt/web/hooks/useLoading';
import { useTranslation } from 'next-i18next';
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
import AccountContainer from '@/pageComponents/account/AccountContainer';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
const InformTable = () => {
const { t } = useTranslation();

View File

@@ -1,4 +1,4 @@
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import React, { useMemo, useState } from 'react';
import AccountContainer from '@/pageComponents/account/AccountContainer';
import { Box, Flex } from '@chakra-ui/react';

View File

@@ -26,7 +26,7 @@ import { useLoading } from '@fastgpt/web/hooks/useLoading';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
import AccountContainer from '@/pageComponents/account/AccountContainer';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
const Promotion = () => {
const { t } = useTranslation();

View File

@@ -10,7 +10,7 @@ import { UserUpdateParams } from '@/types/user';
import TimezoneSelect from '@fastgpt/web/components/common/MySelect/TimezoneSelect';
import I18nLngSelector from '@/components/Select/I18nLngSelector';
import AccountContainer from '@/pageComponents/account/AccountContainer';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
const Individuation = () => {
const { t } = useTranslation();

View File

@@ -1,4 +1,4 @@
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import AccountContainer from '@/pageComponents/account/AccountContainer';
import { Box, Flex } from '@chakra-ui/react';
import Icon from '@fastgpt/web/components/common/Icon';
@@ -20,6 +20,9 @@ const PermissionManage = dynamic(
);
const GroupManage = dynamic(() => import('@/pageComponents/account/team/GroupManage/index'));
const OrgManage = dynamic(() => import('@/pageComponents/account/team/OrgManage/index'));
const HandleInviteModal = dynamic(
() => import('@/pageComponents/account/team/Invite/HandleInviteModal')
);
export enum TeamTabEnum {
member = 'member',
@@ -30,15 +33,22 @@ export enum TeamTabEnum {
const Team = () => {
const router = useRouter();
const invitelinkid = useMemo(() => {
const _id = router.query.invitelinkid;
if (!_id && typeof _id !== 'string') {
return '';
} else {
return _id as string;
}
}, [router.query.invitelinkid]);
const { teamTab = TeamTabEnum.member } = router.query as { teamTab: `${TeamTabEnum}` };
const { t } = useTranslation();
const { userInfo } = useUserStore();
const { setEditTeamData, isLoading, teamSize, refetchMembers } = useContextSelector(
TeamContext,
(v) => v
);
const { setEditTeamData, isLoading, teamSize } = useContextSelector(TeamContext, (v) => v);
const Tabs = useMemo(
() => (
@@ -88,7 +98,7 @@ const Team = () => {
</Box>
</Flex>
<Flex align={'center'} ml={6}>
<TeamSelector height={'28px'} onChange={refetchMembers} />
<TeamSelector height={'28px'} />
</Flex>
{userInfo?.team?.role === TeamMemberRoleEnum.owner && (
<Flex align={'center'} justify={'center'} ml={2} p={'0.44rem'}>
@@ -142,6 +152,7 @@ const Team = () => {
{teamTab === TeamTabEnum.permission && <PermissionManage Tabs={Tabs} />}
</Box>
</Flex>
{invitelinkid && <HandleInviteModal invitelinkid={invitelinkid} />}
</AccountContainer>
);
};

View File

@@ -9,7 +9,7 @@ import dynamic from 'next/dynamic';
import { useState, useMemo } from 'react';
import WorkflowVariableModal from '@/pageComponents/account/thirdParty/WorkflowVariableModal';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { GET } from '@/web/common/api/request';
import type { checkUsageResponse } from '@/pages/api/support/user/team/thirtdParty/checkUsage';

View File

@@ -9,7 +9,7 @@ import { useTranslation } from 'next-i18next';
import { useUserStore } from '@/web/support/user/useUserStore';
import Avatar from '@fastgpt/web/components/common/Avatar';
import AccountContainer from '@/pageComponents/account/AccountContainer';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination';
import { getTeamMembers } from '@/web/support/user/team/api';
import FillRowTabs from '@fastgpt/web/components/common/Tabs/FillRowTabs';
@@ -130,7 +130,7 @@ const UsageTable = () => {
{ label: t('account_usage:every_month'), value: 'month' }
]}
value={unit}
onchange={setUnit}
onChange={setUnit}
/>
)} */}
</Flex>
@@ -199,8 +199,6 @@ const UsageTable = () => {
[
t,
dateRange,
usageTab,
unit,
userInfo?.team?.permission.hasManagePer,
tmbList,
selectTmbIds,

View File

@@ -1,7 +1,7 @@
import { NextAPI } from '@/service/middleware/entry';
import { delay } from '@fastgpt/global/common/system/utils';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { jiebaSplit } from '@fastgpt/service/common/string/jieba';
import { jiebaSplit } from '@fastgpt/service/common/string/jieba/index';
import { MongoDatasetDataText } from '@fastgpt/service/core/dataset/data/dataTextSchema';
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
@@ -44,7 +44,7 @@ const restore = async () => {
const data = await MongoDatasetData.findOne({ fullTextToken: { $exists: false } });
if (!data) return;
data.fullTextToken = jiebaSplit({ text: `${data.q}\n${data.a}`.trim() });
data.fullTextToken = await jiebaSplit({ text: `${data.q}\n${data.a}`.trim() });
await data.save();
success++;

View File

@@ -0,0 +1,82 @@
import { NextAPI } from '@/service/middleware/entry';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { NextApiRequest, NextApiResponse } from 'next';
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
import { jiebaSplit } from '@fastgpt/service/common/string/jieba';
import { addLog } from '@fastgpt/service/common/system/log';
import { delay } from '@fastgpt/global/common/system/utils';
import { MongoDatasetDataText } from '@fastgpt/service/core/dataset/data/dataTextSchema';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { DatasetDataTextSchemaType } from '@fastgpt/global/core/dataset/type';
import type { AnyBulkWriteOperation } from '@fastgpt/service/common/mongo';
const updateData = async () => {
let success = 0;
while (true) {
try {
const time = Date.now();
const data = await MongoDatasetData.find({
initJieba: { $exists: false },
updateTime: { $lte: time } // 只需要取旧的数据
})
.limit(1000)
.lean();
if (data.length === 0) {
console.log('更新分词完成');
break;
}
const dataTextOps: AnyBulkWriteOperation<DatasetDataTextSchemaType>[] = [];
const datasetDataIds: string[] = [];
// 先进行分词处理
for await (const item of data) {
const text = `${item.q} ${item.a}`.trim();
try {
const tokens = await jiebaSplit({ text });
dataTextOps.push({
updateOne: {
filter: { dataId: item._id },
update: { $set: { fullTextToken: tokens } }
}
});
datasetDataIds.push(item._id);
} catch (error) {
console.log(`分词处理错误: ${item._id}`, error);
}
}
await mongoSessionRun(async (session) => {
if (dataTextOps.length > 0) {
await MongoDatasetDataText.bulkWrite(dataTextOps, { session, ordered: true });
}
if (datasetDataIds.length > 0) {
await MongoDatasetData.updateMany(
{ _id: { $in: datasetDataIds } },
{ $set: { initJieba: true } },
{
session
}
);
}
});
success += dataTextOps.length;
console.log(`成功 ${success}`);
} catch (error) {
addLog.error('更新所有旧的 jieba 分词失败', error);
await delay(1000);
}
}
};
async function handler(req: NextApiRequest, _res: NextApiResponse) {
await authCert({ req, authRoot: true });
console.log('更新所有旧的 jieba 分词');
updateData();
return { success: true };
}
export default NextAPI(handler);

View File

@@ -1,15 +1,15 @@
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { authSystemAdmin } from '@fastgpt/service/support/permission/user/auth';
import { findModelFromAlldata, getReRankModel } from '@fastgpt/service/core/ai/model';
import { findModelFromAlldata } from '@fastgpt/service/core/ai/model';
import {
EmbeddingModelItemType,
LLMModelItemType,
ReRankModelItemType,
RerankModelItemType,
STTModelType,
TTSModelType
} from '@fastgpt/global/core/ai/model.d';
import { getAIApi } from '@fastgpt/service/core/ai/config';
import { createChatCompletion, getAIApi } from '@fastgpt/service/core/ai/config';
import { addLog } from '@fastgpt/service/common/system/log';
import { getVectorsByText } from '@fastgpt/service/core/ai/embedding';
import { reRankRecall } from '@fastgpt/service/core/ai/rerank';
@@ -18,7 +18,7 @@ import { isProduction } from '@fastgpt/global/common/system/constants';
import * as fs from 'fs';
import { llmCompletionsBodyFormat } from '@fastgpt/service/core/ai/utils';
export type testQuery = { model: string };
export type testQuery = { model: string; channelId?: number };
export type testBody = {};
@@ -30,25 +30,31 @@ async function handler(
): Promise<testResponse> {
await authSystemAdmin({ req });
const { model } = req.query;
const { model, channelId } = req.query;
const modelData = findModelFromAlldata(model);
if (!modelData) return Promise.reject('Model not found');
const headers: Record<string, string> = channelId
? {
'Aiproxy-Channel': String(channelId)
}
: {};
if (modelData.type === 'llm') {
return testLLMModel(modelData);
return testLLMModel(modelData, headers);
}
if (modelData.type === 'embedding') {
return testEmbeddingModel(modelData);
return testEmbeddingModel(modelData, headers);
}
if (modelData.type === 'tts') {
return testTTSModel(modelData);
return testTTSModel(modelData, headers);
}
if (modelData.type === 'stt') {
return testSTTModel(modelData);
return testSTTModel(modelData, headers);
}
if (modelData.type === 'rerank') {
return testReRankModel(modelData);
return testReRankModel(modelData, headers);
}
return Promise.reject('Model type not supported');
@@ -56,7 +62,7 @@ async function handler(
export default NextAPI(handler);
const testLLMModel = async (model: LLMModelItemType) => {
const testLLMModel = async (model: LLMModelItemType, headers: Record<string, string>) => {
const ai = getAIApi({
timeout: 10000
});
@@ -65,39 +71,53 @@ const testLLMModel = async (model: LLMModelItemType) => {
{
model: model.model,
messages: [{ role: 'user', content: 'hi' }],
stream: false,
max_tokens: 10
stream: true
},
model
);
const response = await ai.chat.completions.create(requestBody, {
...(model.requestUrl ? { path: model.requestUrl } : {}),
headers: model.requestAuth
? {
Authorization: `Bearer ${model.requestAuth}`
}
: undefined
const { response, isStreamResponse } = await createChatCompletion({
body: requestBody,
options: {
headers: {
Accept: 'application/json, text/plain, */*',
...headers
}
}
});
const responseText = response.choices?.[0]?.message?.content;
// @ts-ignore
const reasoning_content = response.choices?.[0]?.message?.reasoning_content;
if (!responseText && !reasoning_content) {
return Promise.reject('Model response empty');
if (isStreamResponse) {
for await (const part of response) {
const content = part.choices?.[0]?.delta?.content || '';
// @ts-ignore
const reasoningContent = part.choices?.[0]?.delta?.reasoning_content || '';
if (content || reasoningContent) {
response?.controller?.abort();
return;
}
}
} else {
addLog.info(`Model not stream response`);
const answer = response.choices?.[0]?.message?.content || '';
if (answer) {
return answer;
}
}
addLog.info(`Model test response: ${responseText}`);
return Promise.reject('Model response empty');
};
const testEmbeddingModel = async (model: EmbeddingModelItemType) => {
const testEmbeddingModel = async (
model: EmbeddingModelItemType,
headers: Record<string, string>
) => {
return getVectorsByText({
input: 'Hi',
model
model,
headers
});
};
const testTTSModel = async (model: TTSModelType) => {
const testTTSModel = async (model: TTSModelType, headers: Record<string, string>) => {
const ai = getAIApi({
timeout: 10000
});
@@ -112,29 +132,30 @@ const testTTSModel = async (model: TTSModelType) => {
model.requestUrl
? {
path: model.requestUrl,
headers: model.requestAuth
? {
Authorization: `Bearer ${model.requestAuth}`
}
: undefined
headers: {
...(model.requestAuth ? { Authorization: `Bearer ${model.requestAuth}` } : {}),
...headers
}
}
: {}
: { headers }
);
};
const testSTTModel = async (model: STTModelType) => {
const testSTTModel = async (model: STTModelType, headers: Record<string, string>) => {
const path = isProduction ? '/app/data/test.mp3' : 'data/test.mp3';
const { text } = await aiTranscriptions({
model: model.model,
fileStream: fs.createReadStream(path)
fileStream: fs.createReadStream(path),
headers
});
addLog.info(`STT result: ${text}`);
};
const testReRankModel = async (model: ReRankModelItemType) => {
const testReRankModel = async (model: RerankModelItemType, headers: Record<string, string>) => {
await reRankRecall({
model,
query: 'Hi',
documents: [{ id: '1', text: 'Hi' }]
documents: [{ id: '1', text: 'Hi' }],
headers
});
};

View File

@@ -4,7 +4,7 @@ import { NextAPI } from '@/service/middleware/entry';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { checkNode } from '@/service/core/app/utils';
import { rewriteAppWorkflowToDetail } from '@fastgpt/service/core/app/utils';
/* 获取应用详情 */
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { appId } = req.query as { appId: string };
@@ -13,7 +13,18 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
Promise.reject(CommonErrEnum.missingParams);
}
// 凭证校验
const { app } = await authApp({ req, authToken: true, appId, per: ReadPermissionVal });
const { app, teamId, isRoot } = await authApp({
req,
authToken: true,
appId,
per: ReadPermissionVal
});
await rewriteAppWorkflowToDetail({
nodes: app.modules,
teamId,
isRoot
});
if (!app.permission.hasWritePer) {
return {

View File

@@ -6,6 +6,7 @@ import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'
import { AppVersionSchemaType } from '@fastgpt/global/core/app/version';
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
import { checkNode } from '@/service/core/app/utils';
import { rewriteAppWorkflowToDetail } from '@fastgpt/service/core/app/utils';
type Props = {
versionId: string;
@@ -18,13 +19,24 @@ async function handler(
): Promise<AppVersionSchemaType> {
const { versionId, appId } = req.query as Props;
const { app } = await authApp({ req, authToken: true, appId, per: WritePermissionVal });
const { app, teamId, isRoot } = await authApp({
req,
authToken: true,
appId,
per: WritePermissionVal
});
const result = await MongoAppVersion.findById(versionId).lean();
if (!result) {
return Promise.reject('version not found');
}
await rewriteAppWorkflowToDetail({
nodes: result.nodes,
teamId,
isRoot
});
return {
...result,
nodes: await Promise.all(

View File

@@ -6,6 +6,7 @@ import { getAppLatestVersion } from '@fastgpt/service/core/app/version/controlle
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
import { rewriteAppWorkflowToDetail } from '@fastgpt/service/core/app/utils';
export type getLatestVersionQuery = {
appId: string;
@@ -23,13 +24,19 @@ async function handler(
req: ApiRequestProps<getLatestVersionBody, getLatestVersionQuery>,
res: ApiResponseType<any>
): Promise<getLatestVersionResponse> {
const { app } = await authApp({
const { app, isRoot, teamId } = await authApp({
req,
authToken: true,
appId: req.query.appId,
per: WritePermissionVal
});
await rewriteAppWorkflowToDetail({
nodes: app.modules,
teamId,
isRoot
});
return getAppLatestVersion(req.query.appId, app);
}

View File

@@ -1,35 +0,0 @@
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
import { getRootUser } from '@test/datas/users';
import { Call } from '@test/utils/request';
import { describe, expect, it } from 'vitest';
import handler, { type versionListBody, type versionListResponse } from './list';
describe('app version list test', () => {
it('should return app version list', async () => {
const root = await getRootUser();
const app = await MongoApp.create({
name: 'test',
tmbId: root.tmbId,
teamId: root.teamId
});
await MongoAppVersion.create(
[...Array(10).keys()].map((i) => ({
tmbId: root.tmbId,
appId: app._id,
versionName: `v${i}`
}))
);
const res = await Call<versionListBody, {}, versionListResponse>(handler, {
auth: root,
body: {
pageSize: 10,
offset: 0,
appId: app._id
}
});
expect(res.code).toBe(200);
expect(res.data.total).toBe(10);
expect(res.data.list.length).toBe(10);
});
});

View File

@@ -10,6 +10,7 @@ import { PostPublishAppProps } from '@/global/core/app/api';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { rewriteAppWorkflowToSimple } from '@fastgpt/service/core/app/utils';
async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiResponse<any>) {
const { appId } = req.query as { appId: string };
@@ -22,6 +23,8 @@ async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiRe
isPlugin: app.type === AppTypeEnum.plugin
});
await rewriteAppWorkflowToSimple(formatNodes);
if (autoSave) {
return MongoApp.findByIdAndUpdate(appId, {
modules: formatNodes,

View File

@@ -0,0 +1,255 @@
import { NextAPI } from '@/service/middleware/entry';
import { authChatCrud, authCollectionInChat } from '@/service/support/permission/auth/chat';
import { DatasetDataSchemaType } from '@fastgpt/global/core/dataset/type';
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { LinkedListResponse, LinkedPaginationProps } from '@fastgpt/web/common/fetch/type';
import { FilterQuery, Types } from 'mongoose';
import { quoteDataFieldSelector, QuoteDataItemType } from '@/service/core/chat/constants';
import { processChatTimeFilter } from '@/service/core/chat/utils';
import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
import { getCollectionWithDataset } from '@fastgpt/service/core/dataset/controller';
export type GetCollectionQuoteProps = LinkedPaginationProps & {
chatId: string;
chatItemDataId: string;
collectionId: string;
appId: string;
shareId?: string;
outLinkUid?: string;
teamId?: string;
teamToken?: string;
};
export type GetCollectionQuoteRes = LinkedListResponse<QuoteDataItemType>;
type BaseMatchType = FilterQuery<DatasetDataSchemaType>;
async function handler(
req: ApiRequestProps<GetCollectionQuoteProps>
): Promise<GetCollectionQuoteRes> {
const {
initialId,
initialIndex,
prevId,
prevIndex,
nextId,
nextIndex,
collectionId,
chatItemDataId,
appId,
chatId,
shareId,
outLinkUid,
teamId,
teamToken,
pageSize = 15
} = req.body;
const limitedPageSize = Math.min(pageSize, 30);
const [collection, { chat, showRawSource }, { chatItem }] = await Promise.all([
getCollectionWithDataset(collectionId),
authChatCrud({
req,
authToken: true,
appId,
chatId,
shareId,
outLinkUid,
teamId,
teamToken
}),
authCollectionInChat({ appId, chatId, chatItemDataId, collectionIds: [collectionId] })
]);
if (!showRawSource) {
return Promise.reject(ChatErrEnum.unAuthChat);
}
if (!chat) return Promise.reject(ChatErrEnum.unAuthChat);
const baseMatch: BaseMatchType = {
teamId: collection.teamId,
datasetId: collection.datasetId,
collectionId,
$or: [
{ updateTime: { $lt: new Date(chatItem.time) } },
{ history: { $elemMatch: { updateTime: { $lt: new Date(chatItem.time) } } } }
]
};
if (initialId && initialIndex !== undefined) {
return await handleInitialLoad({
initialId,
initialIndex,
pageSize: limitedPageSize,
chatTime: chatItem.time,
baseMatch
});
}
if ((prevId && prevIndex !== undefined) || (nextId && nextIndex !== undefined)) {
return await handlePaginatedLoad({
prevId,
prevIndex,
nextId,
nextIndex,
pageSize: limitedPageSize,
chatTime: chatItem.time,
baseMatch
});
}
return { list: [], hasMorePrev: false, hasMoreNext: false };
}
export default NextAPI(handler);
async function handleInitialLoad({
initialId,
initialIndex,
pageSize,
chatTime,
baseMatch
}: {
initialId: string;
initialIndex: number;
pageSize: number;
chatTime: Date;
baseMatch: BaseMatchType;
}): Promise<GetCollectionQuoteRes> {
const centerNode = await MongoDatasetData.findOne(
{
_id: new Types.ObjectId(initialId)
},
quoteDataFieldSelector
).lean();
if (!centerNode) {
const list = await MongoDatasetData.find(baseMatch, quoteDataFieldSelector)
.sort({ chunkIndex: 1, _id: -1 })
.limit(pageSize)
.lean();
const hasMoreNext = list.length === pageSize;
return {
list: processChatTimeFilter(list, chatTime),
hasMorePrev: false,
hasMoreNext
};
}
const prevHalfSize = Math.floor(pageSize / 2);
const nextHalfSize = pageSize - prevHalfSize - 1;
const { list: prevList, hasMore: hasMorePrev } = await getPrevNodes(
initialId,
initialIndex,
prevHalfSize,
baseMatch
);
const { list: nextList, hasMore: hasMoreNext } = await getNextNodes(
initialId,
initialIndex,
nextHalfSize,
baseMatch
);
const resultList = [...prevList, centerNode, ...nextList];
return {
list: processChatTimeFilter(resultList, chatTime),
hasMorePrev,
hasMoreNext
};
}
async function handlePaginatedLoad({
prevId,
prevIndex,
nextId,
nextIndex,
pageSize,
chatTime,
baseMatch
}: {
prevId: string | undefined;
prevIndex: number | undefined;
nextId: string | undefined;
nextIndex: number | undefined;
pageSize: number;
chatTime: Date;
baseMatch: BaseMatchType;
}): Promise<GetCollectionQuoteRes> {
const { list, hasMore } =
prevId && prevIndex !== undefined
? await getPrevNodes(prevId, prevIndex, pageSize, baseMatch)
: await getNextNodes(nextId!, nextIndex!, pageSize, baseMatch);
const processedList = processChatTimeFilter(list, chatTime);
return {
list: processedList,
hasMorePrev: !!prevId && hasMore,
hasMoreNext: !!nextId && hasMore
};
}
async function getPrevNodes(
initialId: string,
initialIndex: number,
limit: number,
baseMatch: BaseMatchType
): Promise<{
list: DatasetDataSchemaType[];
hasMore: boolean;
}> {
const match: BaseMatchType = {
...baseMatch,
$or: [
{ chunkIndex: { $lte: initialIndex } },
{ chunkIndex: initialIndex, _id: { $lte: new Types.ObjectId(initialId) } }
]
};
const list = await MongoDatasetData.find(match, quoteDataFieldSelector)
.sort({ chunkIndex: -1, _id: 1 })
.limit(limit)
.lean();
return {
list: list.filter((item) => String(item._id) !== initialId).reverse(),
hasMore: list.length === limit
};
}
async function getNextNodes(
initialId: string,
initialIndex: number,
limit: number,
baseMatch: BaseMatchType
): Promise<{
list: DatasetDataSchemaType[];
hasMore: boolean;
}> {
const match: BaseMatchType = {
...baseMatch,
$or: [
{ chunkIndex: { $gte: initialIndex } },
{ chunkIndex: initialIndex, _id: { $gte: new Types.ObjectId(initialId) } }
]
};
const list = await MongoDatasetData.find(match, quoteDataFieldSelector)
.sort({ chunkIndex: 1, _id: -1 })
.limit(limit)
.lean();
return {
list: list.filter((item) => String(item._id) !== initialId),
hasMore: list.length === limit
};
}

View File

@@ -0,0 +1,64 @@
import { NextAPI } from '@/service/middleware/entry';
import { authChatCrud, authCollectionInChat } from '@/service/support/permission/auth/chat';
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { quoteDataFieldSelector, QuoteDataItemType } from '@/service/core/chat/constants';
import { processChatTimeFilter } from '@/service/core/chat/utils';
import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
export type GetQuoteDataProps = {
datasetDataIdList: string[];
collectionIdList: string[];
chatId: string;
chatItemDataId: string;
appId: string;
shareId?: string;
outLinkUid?: string;
teamId?: string;
teamToken?: string;
};
export type GetQuoteDataRes = QuoteDataItemType[];
async function handler(req: ApiRequestProps<GetQuoteDataProps>): Promise<GetQuoteDataRes> {
const {
appId,
chatId,
chatItemDataId,
shareId,
outLinkUid,
teamId,
teamToken,
collectionIdList,
datasetDataIdList
} = req.body;
const [chat, { chatItem }] = await Promise.all([
authChatCrud({
req,
authToken: true,
appId,
chatId,
shareId,
outLinkUid,
teamId,
teamToken
}),
authCollectionInChat({ appId, chatId, chatItemDataId, collectionIds: collectionIdList })
]);
if (!chat) return Promise.reject(ChatErrEnum.unAuthChat);
const list = await MongoDatasetData.find(
{ _id: { $in: datasetDataIdList }, collectionId: { $in: collectionIdList } },
quoteDataFieldSelector
).lean();
const quoteList = processChatTimeFilter(list, chatItem.time);
return quoteList;
}
export default NextAPI(handler);

View File

@@ -1,38 +0,0 @@
import type { NextApiRequest } from 'next';
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
import { getEmbeddingModel } from '@fastgpt/service/core/ai/model';
import type { DatasetSimpleItemType } from '@fastgpt/global/core/dataset/type.d';
import { NextAPI } from '@/service/middleware/entry';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
/* get all dataset by teamId or tmbId */
async function handler(req: NextApiRequest): Promise<DatasetSimpleItemType[]> {
const { teamId } = await authUserPer({
req,
authToken: true,
authApiKey: true,
per: ReadPermissionVal
});
const myDatasets = await MongoDataset.find({
teamId,
type: {
$ne: DatasetTypeEnum.folder
}
})
.sort({
updateTime: -1
})
.lean();
return myDatasets.map((item) => ({
_id: item._id,
avatar: item.avatar,
name: item.name,
vectorModel: getEmbeddingModel(item.vectorModel)
}));
}
export default NextAPI(handler);

View File

@@ -2,11 +2,7 @@ import type { NextApiRequest } from 'next';
import type { ApiDatasetCreateDatasetCollectionParams } from '@fastgpt/global/core/dataset/api.d';
import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
import { createCollectionAndInsertData } from '@fastgpt/service/core/dataset/collection/controller';
import {
TrainingModeEnum,
DatasetCollectionTypeEnum,
DatasetCollectionDataProcessModeEnum
} from '@fastgpt/global/core/dataset/constants';
import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
@@ -16,7 +12,8 @@ import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
async function handler(req: NextApiRequest): CreateCollectionResponse {
const { name, apiFileId, ...body } = req.body as ApiDatasetCreateDatasetCollectionParams;
const { name, apiFileId, customPdfParse, ...body } =
req.body as ApiDatasetCreateDatasetCollectionParams;
const { teamId, tmbId, dataset } = await authDataset({
req,
@@ -50,7 +47,8 @@ async function handler(req: NextApiRequest): CreateCollectionResponse {
yuqueServer,
apiFileId,
teamId,
tmbId
tmbId,
customPdfParse
});
const { collectionId, insertResults } = await createCollectionAndInsertData({
@@ -62,11 +60,12 @@ async function handler(req: NextApiRequest): CreateCollectionResponse {
teamId,
tmbId,
type: DatasetCollectionTypeEnum.apiFile,
name: name,
name,
apiFileId,
metadata: {
relatedImgId: apiFileId
}
},
customPdfParse
}
});

View File

@@ -0,0 +1,133 @@
import { NextAPI } from '@/service/middleware/entry';
import { authChatCrud, authCollectionInChat } from '@/service/support/permission/auth/chat';
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { useIPFrequencyLimit } from '@fastgpt/service/common/middle/reqFrequencyLimit';
import { readFromSecondary } from '@fastgpt/service/common/mongo/utils';
import { responseWriteController } from '@fastgpt/service/common/response';
import { addLog } from '@fastgpt/service/common/system/log';
import { getCollectionWithDataset } from '@fastgpt/service/core/dataset/controller';
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
import { authDatasetCollection } from '@fastgpt/service/support/permission/dataset/auth';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { NextApiResponse } from 'next';
export type ExportCollectionBody = {
collectionId: string;
appId?: string;
chatId?: string;
chatItemDataId?: string;
chatTime: Date;
} & OutLinkChatAuthProps;
async function handler(req: ApiRequestProps<ExportCollectionBody, {}>, res: NextApiResponse) {
const {
collectionId,
appId,
chatId,
chatItemDataId,
shareId,
outLinkUid,
teamId,
teamToken,
chatTime
} = req.body;
const { collection, teamId: userTeamId } = await (async () => {
if (!appId || !chatId || !chatItemDataId) {
return authDatasetCollection({
req,
authToken: true,
authApiKey: true,
collectionId: req.body.collectionId,
per: ReadPermissionVal
});
}
/*
1. auth chat read permission
2. auth collection quote in chat
3. auth outlink open show quote
*/
const [authRes, collection] = await Promise.all([
authChatCrud({
req,
authToken: true,
appId,
chatId,
shareId,
outLinkUid,
teamId,
teamToken
}),
getCollectionWithDataset(collectionId),
authCollectionInChat({ appId, chatId, chatItemDataId, collectionIds: [collectionId] })
]);
if (!authRes.showRawSource) {
return Promise.reject(DatasetErrEnum.unAuthDatasetFile);
}
return {
...authRes,
collection
};
})();
const where = {
teamId: userTeamId,
datasetId: collection.datasetId,
collectionId,
...(chatTime
? {
$or: [
{ updateTime: { $lt: new Date(chatTime) } },
{ history: { $elemMatch: { updateTime: { $lt: new Date(chatTime) } } } }
]
}
: {})
};
res.setHeader('Content-Type', 'text/csv; charset=utf-8;');
res.setHeader('Content-Disposition', 'attachment; filename=data.csv; ');
const cursor = MongoDatasetData.find(where, 'q a', {
...readFromSecondary,
batchSize: 1000
})
.sort({ chunkIndex: 1 })
.limit(50000)
.cursor();
const write = responseWriteController({
res,
readStream: cursor
});
write(`\uFEFFindex,content`);
cursor.on('data', (doc) => {
const q = doc.q.replace(/"/g, '""') || '';
const a = doc.a.replace(/"/g, '""') || '';
write(`\n"${q}","${a}"`);
});
cursor.on('end', () => {
cursor.close();
res.end();
});
cursor.on('error', (err) => {
addLog.error(`export usage error`, err);
res.status(500);
res.end();
});
}
export default NextAPI(
useIPFrequencyLimit({ id: 'export-usage', seconds: 60, limit: 1, force: true }),
handler
);

View File

@@ -7,9 +7,7 @@ import { BucketNameEnum, ReadFileBaseUrl } from '@fastgpt/global/common/file/con
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
import { AIChatItemType, ChatHistoryItemResType } from '@fastgpt/global/core/chat/type';
import { authChatCrud } from '@/service/support/permission/auth/chat';
import { authChatCrud, authCollectionInChat } from '@/service/support/permission/auth/chat';
import { getCollectionWithDataset } from '@fastgpt/service/core/dataset/controller';
import { useApiDatasetRequest } from '@fastgpt/service/core/dataset/apiDataset/api';
import { POST } from '@fastgpt/service/common/api/plusRequest';
@@ -21,7 +19,7 @@ export type readCollectionSourceBody = {
appId?: string;
chatId?: string;
chatItemId?: string;
chatItemDataId?: string;
} & OutLinkChatAuthProps;
export type readCollectionSourceResponse = {
@@ -29,61 +27,10 @@ export type readCollectionSourceResponse = {
value: string;
};
const authCollectionInChat = async ({
collectionId,
appId,
chatId,
chatItemId
}: {
collectionId: string;
appId: string;
chatId: string;
chatItemId: string;
}) => {
try {
const chatItem = (await MongoChatItem.findOne(
{
appId,
chatId,
dataId: chatItemId
},
'responseData'
).lean()) as AIChatItemType;
if (!chatItem) return Promise.reject(DatasetErrEnum.unAuthDatasetFile);
// 找 responseData 里,是否有该文档 id
const responseData = chatItem.responseData || [];
const flatResData: ChatHistoryItemResType[] =
responseData
?.map((item) => {
return [
item,
...(item.pluginDetail || []),
...(item.toolDetail || []),
...(item.loopDetail || [])
];
})
.flat() || [];
if (
flatResData.some((item) => {
if (item.quoteList) {
return item.quoteList.some((quote) => quote.collectionId === collectionId);
}
return false;
})
) {
return true;
}
} catch (error) {}
return Promise.reject(DatasetErrEnum.unAuthDatasetFile);
};
async function handler(
req: ApiRequestProps<readCollectionSourceBody, readCollectionSourceQuery>
): Promise<readCollectionSourceResponse> {
const { collectionId, appId, chatId, chatItemId, shareId, outLinkUid, teamId, teamToken } =
const { collectionId, appId, chatId, chatItemDataId, shareId, outLinkUid, teamId, teamToken } =
req.body;
const {
@@ -92,7 +39,7 @@ async function handler(
tmbId: uid,
authType
} = await (async () => {
if (!appId || !chatId || !chatItemId) {
if (!appId || !chatId || !chatItemDataId) {
return authDatasetCollection({
req,
authToken: true,
@@ -119,7 +66,7 @@ async function handler(
teamToken
}),
getCollectionWithDataset(collectionId),
authCollectionInChat({ appId, chatId, chatItemId, collectionId })
authCollectionInChat({ appId, chatId, chatItemDataId, collectionIds: [collectionId] })
]);
if (!authRes.showRawSource) {

View File

@@ -0,0 +1,56 @@
import type { NextApiRequest } from 'next';
import { NextAPI } from '@/service/middleware/entry';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
export type GetQuotePermissionResponse =
| {
datasetName: string;
permission: {
hasWritePer: boolean;
hasReadPer: boolean;
};
}
| undefined;
async function handler(req: NextApiRequest): Promise<GetQuotePermissionResponse> {
const { id: datasetId } = req.query as {
id?: string;
};
if (!datasetId) {
return Promise.reject('datasetId is required');
}
try {
const { permission, dataset } = await authDataset({
req,
authToken: true,
authApiKey: true,
datasetId,
per: ReadPermissionVal
});
return {
datasetName: dataset.name,
permission: {
hasReadPer: permission.hasReadPer,
hasWritePer: permission.hasWritePer
}
};
} catch (error) {
if (error === DatasetErrEnum.unAuthDataset) {
return {
datasetName: '',
permission: {
hasWritePer: false,
hasReadPer: false
}
};
}
return Promise.reject(error);
}
}
export default NextAPI(handler);

View File

@@ -45,7 +45,7 @@ async function handler(
const [list, total] = await Promise.all([
MongoDatasetData.find(match, '_id datasetId collectionId q a chunkIndex')
.sort({ chunkIndex: 1, updateTime: -1 })
.sort({ chunkIndex: 1, _id: -1 })
.skip(offset)
.limit(pageSize)
.lean(),

View File

@@ -16,6 +16,7 @@ import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { useIPFrequencyLimit } from '@fastgpt/service/common/middle/reqFrequencyLimit';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { getRerankModel } from '@fastgpt/service/core/ai/model';
async function handler(req: ApiRequestProps<SearchTestProps>): Promise<SearchTestResponse> {
const {
@@ -24,7 +25,11 @@ async function handler(req: ApiRequestProps<SearchTestProps>): Promise<SearchTes
limit = 1500,
similarity,
searchMode,
embeddingWeight,
usingReRank,
rerankModel,
rerankWeight,
datasetSearchUsingExtensionQuery = false,
datasetSearchExtensionModel,
@@ -63,7 +68,10 @@ async function handler(req: ApiRequestProps<SearchTestProps>): Promise<SearchTes
similarity,
datasetIds: [datasetId],
searchMode,
usingReRank: usingReRank && (await checkTeamReRankPermission(teamId))
embeddingWeight,
usingReRank: usingReRank && (await checkTeamReRankPermission(teamId)),
rerankModel: getRerankModel(rerankModel),
rerankWeight
};
const { searchRes, tokens, queryExtensionResult, deepSearchResult, ...result } = datasetDeepSearch
? await deepRagSearch({

View File

@@ -37,6 +37,7 @@ async function handler(
responseDetail,
showRawSource,
showNodeStatus,
// showFullText,
limit,
app
});

View File

@@ -59,6 +59,7 @@ import { getWorkflowResponseWrite } from '@fastgpt/service/core/workflow/dispatc
import { WORKFLOW_MAX_RUN_TIMES } from '@fastgpt/service/core/workflow/constants';
import { getPluginInputsFromStoreNodes } from '@fastgpt/global/core/app/plugin/utils';
import { ExternalProviderType } from '@fastgpt/global/core/workflow/runtime/type';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
type FastGptWebChatProps = {
chatId?: string; // undefined: get histories from messages, '': new chat, 'xxxxx': get histories from db

View File

@@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
import { Box } from '@chakra-ui/react';
import dynamic from 'next/dynamic';
import Loading from '@fastgpt/web/components/common/MyLoading';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import NextHead from '@/components/common/NextHead';
import { useContextSelector } from 'use-context-selector';
import AppContextProvider, { AppContext } from '@/pageComponents/app/detail/context';

View File

@@ -1,7 +1,7 @@
import React, { useMemo, useState } from 'react';
import { Box, Flex, Button, useDisclosure, Input, InputGroup } from '@chakra-ui/react';
import { AddIcon } from '@chakra-ui/icons';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { useUserStore } from '@/web/support/user/useUserStore';
import { useTranslation } from 'next-i18next';
import dynamic from 'next/dynamic';

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useMemo } from 'react';
import React, { useCallback, useEffect, useMemo, useState, useRef } from 'react';
import NextHead from '@/components/common/NextHead';
import { useRouter } from 'next/router';
import { getInitChatInfo } from '@/web/core/chat/api';
@@ -15,7 +15,7 @@ import ChatHistorySlider from '@/pageComponents/chat/ChatHistorySlider';
import SliderApps from '@/pageComponents/chat/SliderApps';
import ChatHeader from '@/pageComponents/chat/ChatHeader';
import { useUserStore } from '@/web/support/user/useUserStore';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { getChatTitleFromChatMessage } from '@fastgpt/global/core/chat/utils';
import { GPTMessages2Chats } from '@fastgpt/global/core/chat/adapt';
import { getMyApps } from '@/web/core/app/api';
@@ -36,6 +36,7 @@ import ChatItemContextProvider, { ChatItemContext } from '@/web/core/chat/contex
import ChatRecordContextProvider, {
ChatRecordContext
} from '@/web/core/chat/context/chatRecordContext';
import ChatQuoteList from '@/pageComponents/chat/ChatQuoteList';
const CustomPluginRunBox = dynamic(() => import('@/pageComponents/chat/CustomPluginRunBox'));
@@ -58,6 +59,8 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
const isPlugin = useContextSelector(ChatItemContext, (v) => v.isPlugin);
const chatBoxData = useContextSelector(ChatItemContext, (v) => v.chatBoxData);
const setChatBoxData = useContextSelector(ChatItemContext, (v) => v.setChatBoxData);
const quoteData = useContextSelector(ChatItemContext, (v) => v.quoteData);
const setQuoteData = useContextSelector(ChatItemContext, (v) => v.setQuoteData);
const chatRecords = useContextSelector(ChatRecordContext, (v) => v.chatRecords);
const totalRecordsCount = useContextSelector(ChatRecordContext, (v) => v.totalRecordsCount);
@@ -138,13 +141,14 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
},
[appId, chatId, onUpdateHistoryTitle, setChatBoxData, forbidLoadChat]
);
const RenderHistorySlider = useMemo(() => {
const Children = (
<ChatHistorySlider confirmClearText={t('common:core.chat.Confirm to clear history')} />
);
return isPc || !appId ? (
<SideBar>{Children}</SideBar>
<SideBar externalTrigger={!!quoteData}>{Children}</SideBar>
) : (
<Drawer
isOpen={isOpenSlider}
@@ -157,64 +161,82 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
<DrawerContent maxWidth={'75vw'}>{Children}</DrawerContent>
</Drawer>
);
}, [appId, isOpenSlider, isPc, onCloseSlider, t]);
}, [t, isPc, appId, isOpenSlider, onCloseSlider, quoteData]);
return (
<Flex h={'100%'}>
<NextHead title={chatBoxData.app.name} icon={chatBoxData.app.avatar}></NextHead>
{/* pc show myself apps */}
{isPc && (
<Box borderRight={theme.borders.base} w={'220px'} flexShrink={0}>
<Box borderRight={theme.borders.base} flex={'0 0 220px'}>
<SliderApps apps={myApps} activeAppId={appId} />
</Box>
)}
<PageContainer isLoading={loading} flex={'1 0 0'} w={0} p={[0, '16px']} position={'relative'}>
<Flex h={'100%'} flexDirection={['column', 'row']}>
{/* pc always show history. */}
{RenderHistorySlider}
{/* chat container */}
<Flex
position={'relative'}
h={[0, '100%']}
w={['100%', 0]}
flex={'1 0 0'}
flexDirection={'column'}
>
{/* header */}
<ChatHeader
totalRecordsCount={totalRecordsCount}
apps={myApps}
history={chatRecords}
showHistory
/>
{(!quoteData || isPc) && (
<PageContainer
isLoading={loading}
flex={'1 0 0'}
w={0}
p={[0, '16px']}
position={'relative'}
>
<Flex h={'100%'} flexDirection={['column', 'row']}>
{/* pc always show history. */}
{RenderHistorySlider}
{/* chat container */}
<Flex
position={'relative'}
h={[0, '100%']}
w={['100%', 0]}
flex={'1 0 0'}
flexDirection={'column'}
>
{/* header */}
<ChatHeader
totalRecordsCount={totalRecordsCount}
apps={myApps}
history={chatRecords}
showHistory
/>
{/* chat box */}
<Box flex={'1 0 0'} bg={'white'}>
{isPlugin ? (
<CustomPluginRunBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
onNewChat={() => onChangeChatId(getNanoid())}
onStartChat={onStartChat}
/>
) : (
<ChatBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
showEmptyIntro
feedbackType={'user'}
onStartChat={onStartChat}
chatType={'chat'}
isReady={!loading}
/>
)}
</Box>
{/* chat box */}
<Box flex={'1 0 0'} bg={'white'}>
{isPlugin ? (
<CustomPluginRunBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
onNewChat={() => onChangeChatId(getNanoid())}
onStartChat={onStartChat}
/>
) : (
<ChatBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
showEmptyIntro
feedbackType={'user'}
onStartChat={onStartChat}
chatType={'chat'}
isReady={!loading}
/>
)}
</Box>
</Flex>
</Flex>
</Flex>
</PageContainer>
</PageContainer>
)}
{quoteData && (
<PageContainer flex={'1 0 0'} w={0} maxW={'560px'}>
<ChatQuoteList
rawSearch={quoteData.rawSearch}
metadata={quoteData.metadata}
onClose={() => setQuoteData(undefined)}
/>
</PageContainer>
)}
</Flex>
);
};
@@ -278,6 +300,7 @@ const Render = (props: { appId: string; isStandalone?: string }) => {
showRouteToAppDetail={isStandalone !== '1'}
showRouteToDatasetDetail={isStandalone !== '1'}
isShowReadRawSource={true}
// isShowFullText={true}
showNodeStatus
>
<ChatRecordContextProvider params={chatRecordProviderParams}>

View File

@@ -11,7 +11,7 @@ import type { StartChatFnProps } from '@/components/core/chat/ChatContainer/type
import PageContainer from '@/components/PageContainer';
import ChatHeader from '@/pageComponents/chat/ChatHeader';
import ChatHistorySlider from '@/pageComponents/chat/ChatHistorySlider';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { useTranslation } from 'next-i18next';
import { getInitOutLinkChatInfo } from '@/web/core/chat/api';
import { getChatTitleFromChatMessage } from '@fastgpt/global/core/chat/utils';
@@ -37,6 +37,7 @@ import { useChatStore } from '@/web/core/chat/context/useChatStore';
import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
import { useI18nLng } from '@fastgpt/web/hooks/useI18n';
import { AppSchema } from '@fastgpt/global/core/app/type';
import ChatQuoteList from '@/pageComponents/chat/ChatQuoteList';
const CustomPluginRunBox = dynamic(() => import('@/pageComponents/chat/CustomPluginRunBox'));
@@ -49,6 +50,7 @@ type Props = {
authToken: string;
customUid: string;
showRawSource: boolean;
// showFullText: boolean;
showNodeStatus: boolean;
};
@@ -81,6 +83,8 @@ const OutLink = (props: Props) => {
const resetVariables = useContextSelector(ChatItemContext, (v) => v.resetVariables);
const isPlugin = useContextSelector(ChatItemContext, (v) => v.isPlugin);
const setChatBoxData = useContextSelector(ChatItemContext, (v) => v.setChatBoxData);
const quoteData = useContextSelector(ChatItemContext, (v) => v.quoteData);
const setQuoteData = useContextSelector(ChatItemContext, (v) => v.setQuoteData);
const chatRecords = useContextSelector(ChatRecordContext, (v) => v.chatRecords);
const totalRecordsCount = useContextSelector(ChatRecordContext, (v) => v.totalRecordsCount);
@@ -217,7 +221,7 @@ const OutLink = (props: Props) => {
if (showHistory !== '1') return null;
return isPc ? (
<SideBar>{Children}</SideBar>
<SideBar externalTrigger={!!quoteData}>{Children}</SideBar>
) : (
<Drawer
isOpen={isOpenSlider}
@@ -232,7 +236,7 @@ const OutLink = (props: Props) => {
</DrawerContent>
</Drawer>
);
}, [isOpenSlider, isPc, onCloseSlider, showHistory, t]);
}, [isOpenSlider, isPc, onCloseSlider, quoteData, showHistory, t]);
return (
<>
@@ -241,56 +245,71 @@ const OutLink = (props: Props) => {
desc={props.appIntro || data?.app?.intro}
icon={props.appAvatar || data?.app?.avatar}
/>
<PageContainer
isLoading={loading}
<Flex
h={'full'}
gap={4}
{...(isEmbed
? { p: '0 !important', insertProps: { borderRadius: '0', boxShadow: 'none' } }
: { p: [0, 5] })}
>
<Flex h={'100%'} flexDirection={['column', 'row']}>
{RenderHistoryList}
{(!quoteData || isPc) && (
<PageContainer flex={'1 0 0'} w={0} isLoading={loading} p={'0 !important'}>
<Flex h={'100%'} flexDirection={['column', 'row']}>
{RenderHistoryList}
{/* chat container */}
<Flex
position={'relative'}
h={[0, '100%']}
w={['100%', 0]}
flex={'1 0 0'}
flexDirection={'column'}
>
{/* header */}
{showHead === '1' ? (
<ChatHeader
history={chatRecords}
totalRecordsCount={totalRecordsCount}
showHistory={showHistory === '1'}
/>
) : null}
{/* chat box */}
<Box flex={1} bg={'white'}>
{isPlugin ? (
<CustomPluginRunBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
onNewChat={() => onChangeChatId(getNanoid())}
onStartChat={startChat}
/>
) : (
<ChatBox
isReady={!loading}
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
feedbackType={'user'}
onStartChat={startChat}
chatType="share"
/>
)}
</Box>
</Flex>
</Flex>
</PageContainer>
{/* chat container */}
<Flex
position={'relative'}
h={[0, '100%']}
w={['100%', 0]}
flex={'1 0 0'}
flexDirection={'column'}
>
{/* header */}
{showHead === '1' ? (
<ChatHeader
history={chatRecords}
totalRecordsCount={totalRecordsCount}
showHistory={showHistory === '1'}
/>
) : null}
{/* chat box */}
<Box flex={1} bg={'white'}>
{isPlugin ? (
<CustomPluginRunBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
onNewChat={() => onChangeChatId(getNanoid())}
onStartChat={startChat}
/>
) : (
<ChatBox
isReady={!loading}
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
feedbackType={'user'}
onStartChat={startChat}
chatType="share"
/>
)}
</Box>
</Flex>
</Flex>
</PageContainer>
)}
{quoteData && (
<PageContainer flex={'1 0 0'} w={0} maxW={'560px'} p={'0 !important'}>
<ChatQuoteList
rawSearch={quoteData.rawSearch}
metadata={quoteData.metadata}
onClose={() => setQuoteData(undefined)}
/>
</PageContainer>
)}
</Flex>
</>
);
};
@@ -340,6 +359,7 @@ const Render = (props: Props) => {
showRouteToAppDetail={false}
showRouteToDatasetDetail={false}
isShowReadRawSource={props.showRawSource}
// isShowFullText={props.showFullText}
showNodeStatus={props.showNodeStatus}
>
<ChatRecordContextProvider params={chatRecordProviderParams}>
@@ -383,6 +403,7 @@ export async function getServerSideProps(context: any) {
appAvatar: app?.associatedApp?.avatar ?? '',
appIntro: app?.associatedApp?.intro ?? 'AI',
showRawSource: app?.showRawSource ?? false,
// showFullText: app?.showFullText ?? false,
showNodeStatus: app?.showNodeStatus ?? false,
shareId: shareId ?? '',
authToken: authToken ?? '',

View File

@@ -8,7 +8,7 @@ import PageContainer from '@/components/PageContainer';
import { getMyTokensApps } from '@/web/core/chat/api';
import ChatHistorySlider from '@/pageComponents/chat/ChatHistorySlider';
import ChatHeader from '@/pageComponents/chat/ChatHeader';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { useTranslation } from 'next-i18next';
import ChatBox from '@/components/core/chat/ChatContainer/ChatBox';
import type { StartChatFnProps } from '@/components/core/chat/ChatContainer/type';
@@ -33,6 +33,7 @@ import ChatRecordContextProvider, {
import { useChatStore } from '@/web/core/chat/context/useChatStore';
import { useMount } from 'ahooks';
import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
import ChatQuoteList from '@/pageComponents/chat/ChatQuoteList';
const CustomPluginRunBox = dynamic(() => import('@/pageComponents/chat/CustomPluginRunBox'));
type Props = { appId: string; chatId: string; teamId: string; teamToken: string };
@@ -63,6 +64,8 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
const resetVariables = useContextSelector(ChatItemContext, (v) => v.resetVariables);
const chatBoxData = useContextSelector(ChatItemContext, (v) => v.chatBoxData);
const setChatBoxData = useContextSelector(ChatItemContext, (v) => v.setChatBoxData);
const quoteData = useContextSelector(ChatItemContext, (v) => v.quoteData);
const setQuoteData = useContextSelector(ChatItemContext, (v) => v.setQuoteData);
const chatRecords = useContextSelector(ChatRecordContext, (v) => v.chatRecords);
const totalRecordsCount = useContextSelector(ChatRecordContext, (v) => v.totalRecordsCount);
@@ -163,7 +166,7 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
);
return isPc || !appId ? (
<SideBar>{Children}</SideBar>
<SideBar externalTrigger={!!quoteData}>{Children}</SideBar>
) : (
<Drawer
isOpen={isOpenSlider}
@@ -176,7 +179,7 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
<DrawerContent maxWidth={'75vw'}>{Children}</DrawerContent>
</Drawer>
);
}, [appId, isOpenSlider, isPc, onCloseSlider, t]);
}, [appId, isOpenSlider, isPc, onCloseSlider, quoteData, t]);
return (
<Flex h={'100%'}>
@@ -188,49 +191,66 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
</Box>
)}
<PageContainer isLoading={loading} flex={'1 0 0'} w={0} p={[0, '16px']} position={'relative'}>
<Flex h={'100%'} flexDirection={['column', 'row']} bg={'white'}>
{RenderHistoryList}
{/* chat container */}
<Flex
position={'relative'}
h={[0, '100%']}
w={['100%', 0]}
flex={'1 0 0'}
flexDirection={'column'}
>
{/* header */}
<ChatHeader
totalRecordsCount={totalRecordsCount}
apps={myApps}
history={chatRecords}
showHistory
/>
{/* chat box */}
<Box flex={1}>
{chatBoxData.app.type === AppTypeEnum.plugin ? (
<CustomPluginRunBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
onNewChat={() => onChangeChatId(getNanoid())}
onStartChat={startChat}
/>
) : (
<ChatBox
isReady={!loading}
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
feedbackType={'user'}
onStartChat={startChat}
chatType="team"
/>
)}
</Box>
{(!quoteData || isPc) && (
<PageContainer
isLoading={loading}
flex={'1 0 0'}
w={0}
p={[0, '16px']}
position={'relative'}
>
<Flex h={'100%'} flexDirection={['column', 'row']} bg={'white'}>
{RenderHistoryList}
{/* chat container */}
<Flex
position={'relative'}
h={[0, '100%']}
w={['100%', 0]}
flex={'1 0 0'}
flexDirection={'column'}
>
{/* header */}
<ChatHeader
totalRecordsCount={totalRecordsCount}
apps={myApps}
history={chatRecords}
showHistory
/>
{/* chat box */}
<Box flex={1}>
{chatBoxData.app.type === AppTypeEnum.plugin ? (
<CustomPluginRunBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
onNewChat={() => onChangeChatId(getNanoid())}
onStartChat={startChat}
/>
) : (
<ChatBox
isReady={!loading}
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
feedbackType={'user'}
onStartChat={startChat}
chatType="team"
/>
)}
</Box>
</Flex>
</Flex>
</Flex>
</PageContainer>
</PageContainer>
)}
{quoteData && (
<PageContainer flex={'1 0 0'} w={0} maxW={'560px'}>
<ChatQuoteList
rawSearch={quoteData.rawSearch}
metadata={quoteData.metadata}
onClose={() => setQuoteData(undefined)}
/>
</PageContainer>
)}
</Flex>
);
};
@@ -300,6 +320,7 @@ const Render = (props: Props) => {
showRouteToAppDetail={false}
showRouteToDatasetDetail={false}
isShowReadRawSource={true}
// isShowFullText={true}
showNodeStatus
>
<ChatRecordContextProvider params={chatRecordProviderParams}>

View File

@@ -5,7 +5,7 @@ import { useToast } from '@fastgpt/web/hooks/useToast';
import { getErrText } from '@fastgpt/global/common/error/utils';
import dynamic from 'next/dynamic';
import PageContainer from '@/components/PageContainer';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { useTranslation } from 'next-i18next';
import MetaDataCard from '@/pageComponents/dataset/detail/MetaDataCard';
import NavBar from '@/pageComponents/dataset/detail/NavBar';

View File

@@ -2,7 +2,7 @@ import React, { useCallback, useMemo, useState } from 'react';
import { Box, Flex, Button, InputGroup, InputLeftElement, Input } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import ParentPaths from '@/components/common/folder/Path';
import List from '@/pageComponents/dataset/list/List';
import { DatasetsContext } from './context';
@@ -70,7 +70,7 @@ const Dataset = () => {
) {
return toast({
status: 'warning',
title: t('common:common.system.Commercial version function')
title: t('common:commercial_function_tip')
});
}
setCreateDatasetType(e);

View File

@@ -1,4 +1,4 @@
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import React, { useEffect } from 'react';
import Loading from '@fastgpt/web/components/common/MyLoading';
import { useRouter } from 'next/router';

View File

@@ -6,7 +6,7 @@ import { clearToken } from '@/web/support/user/auth';
import { postFastLogin } from '@/web/support/user/api';
import { useToast } from '@fastgpt/web/hooks/useToast';
import Loading from '@fastgpt/web/components/common/MyLoading';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useTranslation } from 'next-i18next';
const FastLogin = ({

View File

@@ -17,7 +17,7 @@ import { useRouter } from 'next/router';
import { useUserStore } from '@/web/support/user/useUserStore';
import { useChatStore } from '@/web/core/chat/context/useChatStore';
import dynamic from 'next/dynamic';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { clearToken } from '@/web/support/user/auth';
import Script from 'next/script';
import Loading from '@fastgpt/web/components/common/MyLoading';

View File

@@ -7,7 +7,7 @@ import { clearToken } from '@/web/support/user/auth';
import { oauthLogin } from '@/web/support/user/api';
import { useToast } from '@fastgpt/web/hooks/useToast';
import Loading from '@fastgpt/web/components/common/MyLoading';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useTranslation } from 'next-i18next';
import { OAuthEnum } from '@fastgpt/global/support/user/constant';

View File

@@ -4,7 +4,7 @@ import { ChevronRightIcon } from '@chakra-ui/icons';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useRouter } from 'next/router';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { useTranslation } from 'next-i18next';
import { getDocPath } from '@/web/common/system/doc';

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { Box, Flex, HStack, VStack } from '@chakra-ui/react';
import { useUserStore } from '@/web/support/user/useUserStore';
import { getTeamPlanStatus } from '@/web/support/user/team/api';

View File

@@ -1,4 +1,4 @@
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
import { serviceSideProps } from '@/web/common/i18n/utils';
import { getPluginGroups, getSystemPlugTemplates } from '@/web/core/app/api/plugin';
import { Box, Flex, Grid, useDisclosure } from '@chakra-ui/react';
import Avatar from '@fastgpt/web/components/common/Avatar';