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:
@@ -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>
|
||||
|
||||
@@ -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 查看具体报错信息。
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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')}: </Box>
|
||||
<Box {...labelStyles}>{t('common:contact_way')}: </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')}: </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>
|
||||
)}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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++;
|
||||
|
||||
82
projects/app/src/pages/api/admin/initv491.ts
Normal file
82
projects/app/src/pages/api/admin/initv491.ts
Normal 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);
|
||||
@@ -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
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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,
|
||||
|
||||
255
projects/app/src/pages/api/core/chat/quote/getCollectionQuote.ts
Normal file
255
projects/app/src/pages/api/core/chat/quote/getCollectionQuote.ts
Normal 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
|
||||
};
|
||||
}
|
||||
64
projects/app/src/pages/api/core/chat/quote/getQuote.ts
Normal file
64
projects/app/src/pages/api/core/chat/quote/getQuote.ts
Normal 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);
|
||||
@@ -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);
|
||||
@@ -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
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
133
projects/app/src/pages/api/core/dataset/collection/export.ts
Normal file
133
projects/app/src/pages/api/core/dataset/collection/export.ts
Normal 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
|
||||
);
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
@@ -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(),
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -37,6 +37,7 @@ async function handler(
|
||||
responseDetail,
|
||||
showRawSource,
|
||||
showNodeStatus,
|
||||
// showFullText,
|
||||
limit,
|
||||
app
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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}>
|
||||
|
||||
@@ -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 ?? '',
|
||||
|
||||
@@ -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}>
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 = ({
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user