4.6.8-alpha (#804)

* perf: redirect request and err log replace

perf: dataset openapi

feat: session

fix: retry input error

feat: 468 doc

sub page

feat: standard sub

perf: rerank tip

perf: rerank tip

perf: api sdk

perf: openapi

sub plan

perf: sub ui

fix: ts

* perf: init log

* fix: variable select

* sub page

* icon

* perf: llm model config

* perf: menu ux

* perf: system store

* perf: publish app name

* fix: init data

* perf: flow edit ux

* fix: value type format and ux

* fix prompt editor default value (#13)

* fix prompt editor default value

* fix prompt editor update when not focus

* add key with variable

---------

Co-authored-by: Archer <545436317@qq.com>

* fix: value type

* doc

* i18n

* import path

* home page

* perf: mongo session running

* fix: ts

* perf: use toast

* perf: flow edit

* perf: sse response

* slider ui

* fetch error

* fix prompt editor rerender when not focus by key defaultvalue (#14)

* perf: prompt editor

* feat: dataset search concat

* perf: doc

* fix:ts

* perf: doc

* fix json editor onblur value (#15)

* faq

* vector model default config

* ipv6

---------

Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
This commit is contained in:
Archer
2024-02-01 21:57:41 +08:00
committed by GitHub
parent fc19c4cf09
commit 34602b25df
285 changed files with 10345 additions and 11223 deletions

View File

@@ -8,7 +8,7 @@ import { theme } from '@/web/styles/theme';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import NProgress from 'nprogress'; //nprogress module
import Router from 'next/router';
import { clientInitData, feConfigs } from '@/web/common/system/staticData';
import { clientInitData } from '@/web/common/system/staticData';
import { appWithTranslation, useTranslation } from 'next-i18next';
import { useRouter } from 'next/router';
import { useSystemStore } from '@/web/common/system/useSystemStore';
@@ -39,7 +39,7 @@ function App({ Component, pageProps }: AppProps) {
const router = useRouter();
const { hiId } = router.query as { hiId?: string };
const { i18n } = useTranslation();
const { loadGitStar } = useSystemStore();
const { loadGitStar, setInitd, feConfigs } = useSystemStore();
const [scripts, setScripts] = useState<FastGPTFeConfigsType['scripts']>([]);
const [title, setTitle] = useState(process.env.SYSTEM_NAME || 'AI');
@@ -65,6 +65,7 @@ function App({ Component, pageProps }: AppProps) {
}
setScripts(scripts || []);
setInitd();
})();
// add window error track

View File

@@ -107,7 +107,7 @@ const BillDetail = ({ bill, onClose }: { bill: BillItemType; onClose: () => void
</Flex>
<Flex alignItems={'center'} pb={4}>
<Box flex={'0 0 80px'}>{t('wallet.bill.Source')}:</Box>
<Box>{BillSourceMap[bill.source]?.label}</Box>
<Box>{t(BillSourceMap[bill.source]?.label)}</Box>
</Flex>
<Flex alignItems={'center'} pb={4}>
<Box flex={'0 0 80px'}>{t('wallet.bill.Total')}:</Box>
@@ -129,7 +129,7 @@ const BillDetail = ({ bill, onClose }: { bill: BillItemType; onClose: () => void
{hasCharsLen && <Th>{t('wallet.bill.Text Length')}</Th>}
{hasDuration && <Th>{t('wallet.bill.Duration')}</Th>}
{hasDatasetSize && (
<Th>{t('support.user.team.subscription.type.extraDatasetSize')}</Th>
<Th>{t('support.wallet.subscription.type.extraDatasetSize')}</Th>
)}
<Th>()</Th>
</Tr>

View File

@@ -45,7 +45,10 @@ const BillTable = () => {
const sourceList = useMemo(
() => [
{ label: t('common.All'), value: '' },
...Object.entries(BillSourceMap).map(([key, value]) => ({ label: value.label, value: key }))
...Object.entries(BillSourceMap).map(([key, value]) => ({
label: t(value.label),
value: key
}))
],
[t]
);
@@ -152,7 +155,7 @@ const BillTable = () => {
<Tr key={item.id}>
{/* <Td>{item.memberName}</Td> */}
<Td>{dayjs(item.time).format('YYYY/MM/DD HH:mm:ss')}</Td>
<Td>{BillSourceMap[item.source]?.label}</Td>
<Td>{t(BillSourceMap[item.source]?.label)}</Td>
<Td>{t(item.appName) || '-'}</Td>
<Td>{item.total}</Td>
<Td>

View File

@@ -13,14 +13,14 @@ import {
} from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
import { UserUpdateParams } from '@/types/user';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useUserStore } from '@/web/support/user/useUserStore';
import type { UserType } from '@fastgpt/global/support/user/type.d';
import { useQuery } from '@tanstack/react-query';
import dynamic from 'next/dynamic';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { compressImgFileAndUpload } from '@/web/common/file/controller';
import { feConfigs, systemVersion } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useTranslation } from 'next-i18next';
import { timezoneList } from '@fastgpt/global/common/time/timezone';
import Avatar from '@/components/Avatar';
@@ -44,6 +44,7 @@ const SubDatasetModal = dynamic(() => import('@/components/support/wallet/SubDat
const UserInfo = () => {
const theme = useTheme();
const router = useRouter();
const { feConfigs, systemVersion } = useSystemStore();
const { t, i18n } = useTranslation();
const { userInfo, updateUserInfo, initUserInfo } = useUserStore();
const timezones = useRef(timezoneList());
@@ -122,12 +123,11 @@ const UserInfo = () => {
}
});
const { data: datasetSub = { maxSize: 0, usedSize: 0 } } = useQuery(
['getTeamDatasetValidSub'],
getTeamDatasetValidSub
);
const {
data: teamSubPlan = { totalPoints: 0, usedPoints: 0, datasetMaxSize: 800, usedDatasetSize: 0 }
} = useQuery(['getTeamDatasetValidSub'], getTeamDatasetValidSub);
const datasetUsageMap = useMemo(() => {
const rate = datasetSub.usedSize / datasetSub.maxSize;
const rate = teamSubPlan.usedDatasetSize / teamSubPlan.datasetMaxSize;
const colorScheme = (() => {
if (rate < 0.5) return 'green';
@@ -138,10 +138,10 @@ const UserInfo = () => {
return {
colorScheme,
value: rate * 100,
maxSize: datasetSub.maxSize,
usedSize: datasetSub.usedSize
maxSize: teamSubPlan.datasetMaxSize || t('common.Unlimited'),
usedSize: teamSubPlan.usedDatasetSize
};
}, [datasetSub.maxSize, datasetSub.usedSize]);
}, [teamSubPlan.usedDatasetSize, teamSubPlan.datasetMaxSize, t]);
return (
<Box
@@ -276,7 +276,7 @@ const UserInfo = () => {
<Flex alignItems={'center'}>
<Box flex={'1 0 0'} fontSize={'md'}>
{t('support.user.team.Dataset usage')}:&nbsp;{datasetUsageMap.usedSize}/
{datasetSub.maxSize}
{datasetUsageMap.maxSize}
</Box>
{userInfo?.team?.canWrite && (
<Button size={'sm'} onClick={onOpenSubDatasetModal}>
@@ -316,7 +316,7 @@ const UserInfo = () => {
userSelect={'none'}
textDecoration={'none !important'}
>
<MyIcon name={'common/courseLight'} w={'18px'} />
<MyIcon name={'common/courseLight'} w={'18px'} color={'myGray.600'} />
<Box ml={2} flex={1}>
{t('system.Help Document')}
</Box>
@@ -366,7 +366,7 @@ const UserInfo = () => {
userSelect={'none'}
onClick={onOpenOpenai}
>
<Avatar src={'/imgs/openai.png'} w={'18px'} />
<MyIcon name={'common/openai'} w={'18px'} color={'myGray.600'} />
<Box ml={2} flex={1}>
OpenAI/OneAPI
</Box>

View File

@@ -32,7 +32,7 @@ const OpenAIAccountModal = ({
<MyModal
isOpen
onClose={onClose}
iconSrc="/imgs/modal/openai.svg"
iconSrc="common/openai"
title={t('user.OpenAI Account Setting')}
>
<ModalBody>

View File

@@ -1,7 +1,7 @@
import React, { useState, useCallback } from 'react';
import { ModalFooter, ModalBody, Button, Input, Box, Grid } from '@chakra-ui/react';
import { getPayCode, checkPayResult } from '@/web/support/wallet/pay/api';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useQuery } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import { getErrText } from '@fastgpt/global/common/error/utils';

View File

@@ -16,7 +16,7 @@ import type { PaySchema } from '@fastgpt/global/support/wallet/pay/type.d';
import dayjs from 'dayjs';
import { useQuery } from '@tanstack/react-query';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useLoading } from '@/web/common/hooks/useLoading';
import MyIcon from '@fastgpt/web/components/common/Icon';

View File

@@ -10,7 +10,6 @@ import SideTabs from '@/components/SideTabs';
import Tabs from '@/components/Tabs';
import UserInfo from './components/Info';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { feConfigs } from '@/web/common/system/staticData';
import { useTranslation } from 'next-i18next';
import Script from 'next/script';
@@ -35,6 +34,7 @@ enum TabEnum {
const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
const { t } = useTranslation();
const { userInfo, setUserInfo } = useUserStore();
const { feConfigs, isPc } = useSystemStore();
const tabList = [
{
@@ -116,7 +116,6 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
const router = useRouter();
const theme = useTheme();
const { isPc } = useSystemStore();
const setCurrentTab = useCallback(
(tab: string) => {

View File

@@ -22,10 +22,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
jsonRes<InitDateResponse>(res, {
data: {
feConfigs: global.feConfigs,
chatModels: global.chatModels,
qaModels: global.qaModels,
cqModels: global.cqModels,
extractModels: global.extractModels,
subPlans: global.subPlans,
llmModels: global.llmModels,
vectorModels: global.vectorModels,
reRankModels:
global.reRankModels?.map((item) => ({
@@ -33,7 +31,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
requestUrl: undefined,
requestAuth: undefined
})) || [],
qgModes: global.qgModels,
whisperModel: global.whisperModel,
audioSpeechModels: global.audioSpeechModels,
systemVersion: global.systemVersion || '0.0.0',
@@ -119,11 +116,8 @@ export async function initSystemConfig() {
...fileRes.systemEnv,
...(dbConfig.systemEnv || {})
},
chatModels: dbConfig.chatModels || fileRes.chatModels || [],
qaModels: dbConfig.qaModels || fileRes.qaModels || [],
cqModels: dbConfig.cqModels || fileRes.cqModels || [],
extractModels: dbConfig.extractModels || fileRes.extractModels || [],
qgModels: dbConfig.qgModels || fileRes.qgModels || [],
subPlans: dbConfig.subPlans || fileRes.subPlans,
llmModels: dbConfig.llmModels || fileRes.llmModels || [],
vectorModels: dbConfig.vectorModels || fileRes.vectorModels || [],
reRankModels: dbConfig.reRankModels || fileRes.reRankModels || [],
audioSpeechModels: dbConfig.audioSpeechModels || fileRes.audioSpeechModels || [],
@@ -133,12 +127,9 @@ export async function initSystemConfig() {
// set config
global.feConfigs = config.feConfigs;
global.systemEnv = config.systemEnv;
global.subPlans = config.subPlans;
global.chatModels = config.chatModels;
global.qaModels = config.qaModels;
global.cqModels = config.cqModels;
global.extractModels = config.extractModels;
global.qgModels = config.qgModels;
global.llmModels = config.llmModels;
global.vectorModels = config.vectorModels;
global.reRankModels = config.reRankModels;
global.audioSpeechModels = config.audioSpeechModels;
@@ -147,11 +138,8 @@ export async function initSystemConfig() {
console.log({
feConfigs: global.feConfigs,
systemEnv: global.systemEnv,
chatModels: global.chatModels,
qaModels: global.qaModels,
cqModels: global.cqModels,
extractModels: global.extractModels,
qgModels: global.qgModels,
subPlans: global.subPlans,
llmModels: global.llmModels,
vectorModels: global.vectorModels,
reRankModels: global.reRankModels,
audioSpeechModels: global.audioSpeechModels,

View File

@@ -17,7 +17,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
shareId
});
const qgModel = global.qgModels[0];
const qgModel = global.llmModels[0];
const { result, inputTokens, outputTokens } = await createQuestionGuide({
messages,

View File

@@ -6,6 +6,7 @@ import { MongoApp } from '@fastgpt/service/core/app/schema';
import { MongoOutLink } from '@fastgpt/service/support/outLink/schema';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
/* 获取我的模型 */
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
@@ -21,21 +22,33 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await authApp({ req, authToken: true, appId, per: 'owner' });
// 删除对应的聊天
await MongoChatItem.deleteMany({
appId
});
await MongoChat.deleteMany({
appId
});
// 删除分享链接
await MongoOutLink.deleteMany({
appId
});
// 删除模型
await MongoApp.deleteOne({
_id: appId
await mongoSessionRun(async (session) => {
await MongoChatItem.deleteMany(
{
appId
},
{ session }
);
await MongoChat.deleteMany(
{
appId
},
{ session }
);
// 删除分享链接
await MongoOutLink.deleteMany(
{
appId
},
{ session }
);
// delete app
await MongoApp.deleteOne(
{
_id: appId
},
{ session }
);
});
jsonRes(res);

View File

@@ -8,11 +8,11 @@ import type { AppSimpleEditFormType } from '@fastgpt/global/core/app/type.d';
import type { ModuleItemType } from '@fastgpt/global/core/module/type';
import { FormatForm2ModulesProps } from '@fastgpt/global/core/app/api';
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
import { getExtractModel } from '@/service/core/ai/model';
import { getLLMModel } from '@/service/core/ai/model';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
const { formData, chatModelMaxToken, chatModelList } = req.body as FormatForm2ModulesProps;
const { formData, chatModelMaxToken } = req.body as FormatForm2ModulesProps;
const modules = [
...(formData.dataset.datasets.length > 0
@@ -381,7 +381,7 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
key: 'usingReRank',
type: 'hidden',
label: '',
valueType: 'string',
valueType: 'boolean',
showTargetInApp: false,
showTargetInPlugin: false,
value: true,
@@ -676,7 +676,7 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
value: getExtractModel().model,
value: getLLMModel().model,
showTargetInApp: false,
showTargetInPlugin: false,
connected: false

View File

@@ -7,7 +7,7 @@ import { jsonRes } from '@fastgpt/service/common/response';
import type { AppSimpleEditFormType } from '@fastgpt/global/core/app/type.d';
import type { ModuleItemType } from '@fastgpt/global/core/module/type';
import { FormatForm2ModulesProps } from '@fastgpt/global/core/app/api';
import { getExtractModel } from '@/service/core/ai/model';
import { getLLMModel } from '@/service/core/ai/model';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -377,7 +377,7 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
key: 'usingReRank',
type: 'hidden',
label: '',
valueType: 'string',
valueType: 'boolean',
showTargetInApp: false,
showTargetInPlugin: false,
value: formData.dataset.usingReRank,
@@ -686,7 +686,7 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
value: getExtractModel().model,
value: getLLMModel().model,
showTargetInApp: false,
showTargetInPlugin: false,
connected: false

View File

@@ -6,7 +6,7 @@ import type { AppUpdateParams } from '@fastgpt/global/core/app/api';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import { getChatModel } from '@/service/core/ai/model';
import { getLLMModel } from '@/service/core/ai/model';
/* 获取我的模型 */
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
@@ -32,7 +32,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
if (item.flowType === FlowNodeTypeEnum.chatNode) {
const model =
item.inputs.find((item) => item.key === ModuleInputKeyEnum.aiModel)?.value || '';
const chatModel = getChatModel(model);
const chatModel = getLLMModel(model);
const quoteMaxToken = chatModel.quoteMaxToken || 3000;
maxTokens = Math.max(maxTokens, quoteMaxToken);
@@ -42,7 +42,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
modules.forEach((item) => {
if (item.flowType === FlowNodeTypeEnum.datasetSearchNode) {
item.inputs.forEach((input) => {
if (input.key === ModuleInputKeyEnum.datasetLimit) {
if (input.key === ModuleInputKeyEnum.datasetMaxTokens) {
const val = input.value as number;
if (val > maxTokens) {
input.value = maxTokens;

View File

@@ -5,6 +5,7 @@ import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
import { DelHistoryProps } from '@/global/core/chat/api';
import { autChatCrud } from '@/service/support/permission/auth/chat';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
/* clear chat history */
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
@@ -22,13 +23,21 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
per: 'w'
});
await MongoChatItem.deleteMany({
appId,
chatId
});
await MongoChat.findOneAndRemove({
appId,
chatId
await mongoSessionRun(async (session) => {
await MongoChatItem.deleteMany(
{
appId,
chatId
},
{ session }
);
await MongoChat.findOneAndRemove(
{
appId,
chatId
},
{ session }
);
});
jsonRes(res);

View File

@@ -21,12 +21,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
per: 'w'
});
const { _id } = await createOneCollection({
...body,
teamId,
tmbId
});
jsonRes(res, {
data: await createOneCollection({
...body,
teamId,
tmbId
})
data: _id
});
} catch (err) {
jsonRes(res, {

View File

@@ -1,13 +1,14 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { uploadFile } from '@fastgpt/service/common/file/gridfs/controller';
import { delFileByFileIdList, uploadFile } from '@fastgpt/service/common/file/gridfs/controller';
import { getUploadModel } from '@fastgpt/service/common/file/multer';
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
import { FileCreateDatasetCollectionParams } from '@fastgpt/global/core/dataset/api';
import { removeFilesByPaths } from '@fastgpt/service/common/file/utils';
import { createOneCollection } from '@fastgpt/service/core/dataset/collection/controller';
import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
/**
* Creates the multer uploader
@@ -18,7 +19,7 @@ const upload = getUploadModel({
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
let filePaths: string[] = [];
let fileId: string = '';
const { datasetId } = req.query as { datasetId: string };
try {
@@ -45,7 +46,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const { fileMetadata, collectionMetadata, ...collectionData } = data;
// upload file and create collection
const fileId = await uploadFile({
fileId = await uploadFile({
teamId,
tmbId,
bucketName,
@@ -56,7 +57,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
});
// create collection
const collectionId = await createOneCollection({
const { _id: collectionId } = await createOneCollection({
...collectionData,
metadata: collectionMetadata,
teamId,
@@ -69,6 +70,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
data: collectionId
});
} catch (error) {
if (fileId) {
try {
await delFileByFileIdList({
fileIdList: [fileId],
bucketName: BucketNameEnum.dataset
});
} catch (error) {}
}
jsonRes(res, {
code: 500,
error

View File

@@ -15,8 +15,10 @@ import { checkDatasetLimit } from '@fastgpt/service/support/permission/limit/dat
import { predictDataLimitLength } from '@fastgpt/global/core/dataset/utils';
import { createTrainingBill } from '@fastgpt/service/support/wallet/bill/controller';
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import { getQAModel, getVectorModel } from '@/service/core/ai/model';
import { getLLMModel, getVectorModel } from '@/service/core/ai/model';
import { reloadCollectionChunks } from '@fastgpt/service/core/dataset/collection/utils';
import { getStandardSubPlan } from '@/service/support/wallet/sub/utils';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -41,39 +43,51 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 1. check dataset limit
await checkDatasetLimit({
teamId,
freeSize: global.feConfigs?.subscription?.datasetStoreFreeSize,
insertLen: predictDataLimitLength(trainingType, new Array(10))
insertLen: predictDataLimitLength(trainingType, new Array(10)),
standardPlans: getStandardSubPlan()
});
// 2. create collection
const collectionId = await createOneCollection({
...body,
name: link,
teamId,
tmbId,
type: DatasetCollectionTypeEnum.link,
const { _id: collectionId } = await mongoSessionRun(async (session) => {
// 2. create collection
const collection = await createOneCollection({
...body,
name: link,
teamId,
tmbId,
type: DatasetCollectionTypeEnum.link,
trainingType,
chunkSize,
chunkSplitter,
qaPrompt,
trainingType,
chunkSize,
chunkSplitter,
qaPrompt,
rawLink: link
});
rawLink: link,
session
});
// 3. create bill and start sync
const { billId } = await createTrainingBill({
teamId,
tmbId,
appName: 'core.dataset.collection.Sync Collection',
billSource: BillSourceEnum.training,
vectorModel: getVectorModel(dataset.vectorModel).name,
agentModel: getQAModel(dataset.agentModel).name
});
await reloadCollectionChunks({
collectionId,
tmbId,
billId
// 3. create bill and start sync
const { billId } = await createTrainingBill({
teamId,
tmbId,
appName: 'core.dataset.collection.Sync Collection',
billSource: BillSourceEnum.training,
vectorModel: getVectorModel(dataset.vectorModel).name,
agentModel: getLLMModel(dataset.agentModel).name,
session
});
// load
await reloadCollectionChunks({
collection: {
...collection.toObject(),
datasetId: dataset
},
tmbId,
billId,
session
});
return collection;
});
jsonRes(res, {

View File

@@ -18,7 +18,8 @@ import { pushDataToTrainingQueue } from '@/service/core/dataset/data/controller'
import { hashStr } from '@fastgpt/global/common/string/tools';
import { createTrainingBill } from '@fastgpt/service/support/wallet/bill/controller';
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import { getQAModel, getVectorModel } from '@/service/core/ai/model';
import { getLLMModel, getVectorModel } from '@/service/core/ai/model';
import { getStandardSubPlan } from '@/service/support/wallet/sub/utils';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -52,12 +53,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 2. check dataset limit
await checkDatasetLimit({
teamId,
freeSize: global.feConfigs?.subscription?.datasetStoreFreeSize,
insertLen: predictDataLimitLength(trainingType, chunks)
insertLen: predictDataLimitLength(trainingType, chunks),
standardPlans: getStandardSubPlan()
});
// 3. create collection and training bill
const [collectionId, { billId }] = await Promise.all([
const [{ _id: collectionId }, { billId }] = await Promise.all([
createOneCollection({
...body,
teamId,
@@ -79,7 +80,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
appName: name,
billSource: BillSourceEnum.training,
vectorModel: getVectorModel(dataset.vectorModel)?.name,
agentModel: getQAModel(dataset.agentModel)?.name
agentModel: getLLMModel(dataset.agentModel)?.name
})
]);

View File

@@ -4,6 +4,7 @@ import { connectToDatabase } from '@/service/mongo';
import { findCollectionAndChild } from '@fastgpt/service/core/dataset/collection/utils';
import { delCollectionAndRelatedSources } from '@fastgpt/service/core/dataset/collection/controller';
import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/dataset';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -32,9 +33,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
});
// delete
await delCollectionAndRelatedSources({
collections
});
await mongoSessionRun((session) =>
delCollectionAndRelatedSources({
collections,
session
})
);
jsonRes(res);
} catch (err) {

View File

@@ -14,8 +14,9 @@ import {
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
import { createTrainingBill } from '@fastgpt/service/support/wallet/bill/controller';
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import { getQAModel, getVectorModel } from '@/service/core/ai/model';
import { getLLMModel, getVectorModel } from '@/service/core/ai/model';
import { createOneCollection } from '@fastgpt/service/core/dataset/collection/controller';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -27,7 +28,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
throw new Error('CollectionIdId is required');
}
const { collection, teamId, tmbId } = await authDatasetCollection({
const { collection, tmbId } = await authDatasetCollection({
req,
authToken: true,
collectionId,
@@ -51,44 +52,54 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
/* Not the same original text, create and reload */
const vectorModelData = getVectorModel(collection.datasetId.vectorModel);
const agentModelData = getQAModel(collection.datasetId.agentModel);
// create training bill
const { billId } = await createTrainingBill({
teamId: collection.teamId,
tmbId,
appName: 'core.dataset.collection.Sync Collection',
billSource: BillSourceEnum.training,
vectorModel: vectorModelData.name,
agentModel: agentModelData.name
});
const agentModelData = getLLMModel(collection.datasetId.agentModel);
// create a collection and delete old
const _id = await createOneCollection({
teamId: collection.teamId,
tmbId: collection.tmbId,
parentId: collection.parentId,
datasetId: collection.datasetId._id,
name: title || collection.name,
type: collection.type,
trainingType: collection.trainingType,
chunkSize: collection.chunkSize,
fileId: collection.fileId,
rawLink: collection.rawLink,
metadata: collection.metadata,
createTime: collection.createTime
});
await mongoSessionRun(async (session) => {
// create training bill
const { billId } = await createTrainingBill({
teamId: collection.teamId,
tmbId,
appName: 'core.dataset.collection.Sync Collection',
billSource: BillSourceEnum.training,
vectorModel: vectorModelData.name,
agentModel: agentModelData.name,
session
});
// start load
await reloadCollectionChunks({
collectionId: _id,
tmbId,
billId,
rawText
});
// create a collection and delete old
const newCol = await createOneCollection({
teamId: collection.teamId,
tmbId: collection.tmbId,
parentId: collection.parentId,
datasetId: collection.datasetId._id,
name: title || collection.name,
type: collection.type,
trainingType: collection.trainingType,
chunkSize: collection.chunkSize,
fileId: collection.fileId,
rawLink: collection.rawLink,
metadata: collection.metadata,
createTime: collection.createTime,
session
});
// delete old collection
await delCollectionAndRelatedSources({
collections: [collection]
// start load
await reloadCollectionChunks({
collection: {
...newCol.toObject(),
datasetId: collection.datasetId
},
tmbId,
billId,
rawText,
session
});
// delete old collection
await delCollectionAndRelatedSources({
collections: [collection],
session
});
});
jsonRes(res, {

View File

@@ -6,7 +6,7 @@ import type { CreateDatasetParams } from '@/global/core/dataset/api.d';
import { createDefaultCollection } from '@fastgpt/service/core/dataset/collection/controller';
import { authUserNotVisitor } from '@fastgpt/service/support/permission/auth/user';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { getQAModel, getVectorModel } from '@/service/core/ai/model';
import { getLLMModel, getVectorModel, getDatasetModel } from '@/service/core/ai/model';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -17,7 +17,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
type = DatasetTypeEnum.dataset,
avatar,
vectorModel = global.vectorModels[0].model,
agentModel = global.qaModels[0].model
agentModel = getDatasetModel().model
} = req.body as CreateDatasetParams;
// auth
@@ -25,7 +25,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// check model valid
const vectorModelStore = getVectorModel(vectorModel);
const agentModelStore = getQAModel(agentModel);
const agentModelStore = getLLMModel(agentModel);
if (!vectorModelStore || !agentModelStore) {
throw new Error('vectorModel or qaModel is invalid');
}

View File

@@ -17,6 +17,7 @@ import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
import { InsertOneDatasetDataProps } from '@/global/core/dataset/api';
import { simpleText } from '@fastgpt/global/common/string/tools';
import { checkDatasetLimit } from '@fastgpt/service/support/permission/limit/dataset';
import { getStandardSubPlan } from '@/service/support/wallet/sub/utils';
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -42,8 +43,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
await checkDatasetLimit({
teamId,
freeSize: global.feConfigs?.subscription?.datasetStoreFreeSize,
insertLen: 1
insertLen: 1,
standardPlans: getStandardSubPlan()
});
// auth collection and get dataset

View File

@@ -11,6 +11,7 @@ import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/
import { checkDatasetLimit } from '@fastgpt/service/support/permission/limit/dataset';
import { predictDataLimitLength } from '@fastgpt/global/core/dataset/utils';
import { pushDataToTrainingQueue } from '@/service/core/dataset/data/controller';
import { getStandardSubPlan } from '@/service/support/wallet/sub/utils';
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -37,8 +38,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
// auth dataset limit
await checkDatasetLimit({
teamId,
freeSize: global.feConfigs?.subscription?.datasetStoreFreeSize,
insertLen: predictDataLimitLength(collection.trainingType, data)
insertLen: predictDataLimitLength(collection.trainingType, data),
standardPlans: getStandardSubPlan()
});
jsonRes<PushDatasetDataResponse>(res, {

View File

@@ -5,6 +5,7 @@ import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
import { delDatasetRelevantData } from '@fastgpt/service/core/dataset/controller';
import { findDatasetAndAllChildren } from '@fastgpt/service/core/dataset/controller';
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -32,11 +33,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
});
// delete all dataset.data and pg data
await delDatasetRelevantData({ datasets });
// delete dataset data
await MongoDataset.deleteMany({
_id: { $in: datasets.map((d) => d._id) }
await mongoSessionRun(async (session) => {
// delete dataset data
await delDatasetRelevantData({ datasets, session });
await MongoDataset.deleteMany(
{
_id: { $in: datasets.map((d) => d._id) }
},
{ session }
);
});
jsonRes(res);

View File

@@ -1,7 +1,7 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { getQAModel, getVectorModel } from '@/service/core/ai/model';
import { getLLMModel, getVectorModel } from '@/service/core/ai/model';
import type { DatasetItemType } from '@fastgpt/global/core/dataset/type.d';
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
@@ -29,7 +29,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
data: {
...dataset,
vectorModel: getVectorModel(dataset.vectorModel),
agentModel: getQAModel(dataset.agentModel),
agentModel: getLLMModel(dataset.agentModel),
canWrite,
isOwner
}

View File

@@ -44,7 +44,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
// query extension
// const { queries } = await searchQueryExtension({
// query: text,
// model: global.chatModels[0].model
// model: global.llmModel[0].model
// });
const { searchRes, charsLength, ...result } = await searchDatasetData({

View File

@@ -17,6 +17,21 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await authRequestFromLocal({ req });
// string all value
Object.keys(obj).forEach((key) => {
let val = obj[key];
if (typeof val === 'object') {
val = JSON.stringify(val);
} else if (typeof val === 'number') {
val = String(val);
} else if (typeof val === 'boolean') {
val = val ? 'true' : 'false';
}
obj[key] = val;
});
const textResult = replaceVariable(text, obj);
res.json({

View File

@@ -20,7 +20,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const nanoid = customAlphabet(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890',
Math.floor(Math.random() * 14) + 24
Math.floor(Math.random() * 14) + 52
);
const apiKey = `${global.systemEnv?.openapiPrefix || 'fastgpt'}-${nanoid()}`;

View File

@@ -20,7 +20,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const baseUrl = openaiAccount?.baseUrl || openaiBaseUrl;
openaiAccount.baseUrl = baseUrl;
const ai = getAIApi(openaiAccount);
const ai = getAIApi({
userKey: openaiAccount
});
const response = await ai.chat.completions.create({
model: 'gpt-3.5-turbo',

View File

@@ -3,6 +3,7 @@ import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { checkDatasetLimit } from '@fastgpt/service/support/permission/limit/dataset';
import { getStandardSubPlan } from '@/service/support/wallet/sub/utils';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -22,8 +23,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await checkDatasetLimit({
teamId,
freeSize: global.feConfigs?.subscription?.datasetStoreFreeSize,
insertLen: numberSize
insertLen: numberSize,
standardPlans: getStandardSubPlan()
});
jsonRes(res);

View File

@@ -3,7 +3,7 @@ import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import { CreateTrainingBillProps } from '@fastgpt/global/support/wallet/bill/api.d';
import { getQAModel, getVectorModel } from '@/service/core/ai/model';
import { getLLMModel, getVectorModel } from '@/service/core/ai/model';
import { createTrainingBill } from '@fastgpt/service/support/wallet/bill/controller';
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
@@ -26,7 +26,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
appName: name,
billSource: BillSourceEnum.training,
vectorModel: getVectorModel(dataset.vectorModel).name,
agentModel: getQAModel(dataset.agentModel).name
agentModel: getLLMModel(dataset.agentModel).name
});
jsonRes<string>(res, {

View File

@@ -2,8 +2,9 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { getTeamDatasetValidSub } from '@fastgpt/service/support/wallet/sub/utils';
import { getVectorCountByTeamId } from '@fastgpt/service/common/vectorStore/controller';
import { getTeamSubPlanStatus } from '@fastgpt/service/support/wallet/sub/utils';
import { getStandardSubPlan } from '@/service/support/wallet/sub/utils';
import { FeTeamSubType } from '@fastgpt/global/support/wallet/sub/type';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -15,20 +16,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
authToken: true
});
const [{ sub, maxSize }, usedSize] = await Promise.all([
getTeamDatasetValidSub({
jsonRes<FeTeamSubType>(res, {
data: await getTeamSubPlanStatus({
teamId,
freeSize: global.feConfigs?.subscription?.datasetStoreFreeSize
}),
getVectorCountByTeamId(teamId)
]);
jsonRes(res, {
data: {
sub,
maxSize,
usedSize
}
standardPlans: getStandardSubPlan()
})
});
} catch (err) {
jsonRes(res, {

View File

@@ -5,12 +5,15 @@ import { withNextCors } from '@fastgpt/service/common/middle/cors';
import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
import { connectToDatabase } from '@/service/mongo';
import { authTeamBalance } from '@/service/support/permission/auth/bill';
import { getVectorsByText, GetVectorProps } from '@fastgpt/service/core/ai/embedding';
import { getVectorsByText } from '@fastgpt/service/core/ai/embedding';
import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
import { getBillSourceByAuthType } from '@fastgpt/global/support/wallet/bill/tools';
import { getVectorModel } from '@/service/core/ai/model';
type Props = GetVectorProps & {
type Props = {
input: string | string[];
model: string;
dimensions?: number;
billId?: string;
};
@@ -33,7 +36,10 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
await authTeamBalance(teamId);
const { charsLength, vectors } = await getVectorsByText({ input: query, model });
const { charsLength, vectors } = await getVectorsByText({
input: query,
model: getVectorModel(model)
});
res.json({
object: 'list',

View File

@@ -15,7 +15,7 @@ import ChatTest, { type ChatTestComponentRef } from '@/components/core/module/Fl
import { getFlowStore } from '@/components/core/module/Flow/FlowProvider';
import { flowNode2Modules, filterExportModules } from '@/components/core/module/utils';
import { useAppStore } from '@/web/core/app/store/useAppStore';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useConfirm } from '@/web/common/hooks/useConfirm';
const ImportSettings = dynamic(() => import('@/components/core/module/Flow/ImportSettings'));

View File

@@ -12,7 +12,7 @@ import {
} from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
import { AppSchema } from '@fastgpt/global/core/app/type.d';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { compressImgFileAndUpload } from '@/web/common/file/controller';
import { getErrText } from '@fastgpt/global/common/error/utils';

View File

@@ -9,7 +9,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
import { useCopyData } from '@/web/common/hooks/useCopyData';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { fileToBase64 } from '@/web/common/file/utils';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
enum UsingWayEnum {
link = 'link',
@@ -25,6 +25,7 @@ const SelectUsingWayModal = ({ share, onClose }: { share: OutLinkSchema; onClose
multiple: false,
fileType: 'image/*'
});
const { feConfigs } = useSystemStore();
const VariableTypeList = [
{

View File

@@ -39,19 +39,21 @@ import { useRequest } from '@/web/common/hooks/useRequest';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import { OutLinkTypeEnum } from '@fastgpt/global/support/outLink/constant';
import { useTranslation } from 'next-i18next';
import { useToast } from '@/web/common/hooks/useToast';
import { feConfigs } from '@/web/common/system/staticData';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import MyTooltip from '@/components/MyTooltip';
import MyModal from '@/components/MyModal';
import dayjs from 'dayjs';
import { getDocPath } from '@/web/common/system/doc';
import dynamic from 'next/dynamic';
import MyMenu from '@/components/MyMenu';
const SelectUsingWayModal = dynamic(() => import('./SelectUsingWayModal'));
const Share = ({ appId }: { appId: string }) => {
const { t } = useTranslation();
const { Loading, setIsLoading } = useLoading();
const { feConfigs } = useSystemStore();
const { copyData } = useCopyData();
const [editLinkData, setEditLinkData] = useState<OutLinkEditType>();
const [selectedLinkData, setSelectedLinkData] = useState<OutLinkSchema>();
@@ -135,40 +137,40 @@ const Share = ({ appId }: { appId: string }) => {
{item.lastTime ? t(formatTimeToChatTime(item.lastTime)) : t('common.Un used')}
</Td>
<Td display={'flex'} alignItems={'center'}>
<Menu autoSelect={false} isLazy>
<MenuButton
_hover={{ bg: 'myWhite.600 ' }}
cursor={'pointer'}
borderRadius={'md'}
>
<MyIcon name={'more'} w={'14px'} p={2} />
</MenuButton>
<MenuList color={'myGray.700'} minW={`120px !important`} zIndex={10}>
<MenuItem
onClick={() => {
<MyMenu
Button={
<MyIcon
name={'more'}
_hover={{ bg: 'myGray.100 ' }}
cursor={'pointer'}
borderRadius={'md'}
w={'14px'}
p={2}
/>
}
menuList={[
{
label: t('core.app.outLink.Select Mode'),
icon: 'copy',
onClick: () => {
setSelectedLinkData(item);
}}
py={[2, 3]}
>
<MyIcon name={'copy'} w={['14px', '16px']} />
<Box ml={[1, 2]}>{t('core.app.outLink.Select Mode')}</Box>
</MenuItem>
<MenuItem
onClick={() =>
}
},
{
label: t('common.Edit'),
icon: 'edit',
onClick: () =>
setEditLinkData({
_id: item._id,
name: item.name,
responseDetail: item.responseDetail,
limit: item.limit
})
}
py={[2, 3]}
>
<MyIcon name={'edit'} w={['14px', '16px']} />
<Box ml={[1, 2]}>{t('common.Edit')}</Box>
</MenuItem>
<MenuItem
onClick={async () => {
},
{
label: t('common.Delete'),
icon: 'delete',
onClick: async () => {
setIsLoading(true);
try {
await delShareChatById(item._id);
@@ -177,14 +179,10 @@ const Share = ({ appId }: { appId: string }) => {
console.log(error);
}
setIsLoading(false);
}}
py={[2, 3]}
>
<MyIcon name={'delete'} w={['14px', '16px']} />
<Box ml={[1, 2]}>{t('common.Delete')}</Box>
</MenuItem>
</MenuList>
</Menu>
}
}
]}
/>
</Td>
</Tr>
))}
@@ -249,6 +247,7 @@ function EditLinkModal({
onCreate: (id: string) => void;
onEdit: () => void;
}) {
const { feConfigs } = useSystemStore();
const { t } = useTranslation();
const {
register,

View File

@@ -18,7 +18,7 @@ const OutLink = ({ appId }: { appId: string }) => {
return (
<Box pt={[1, 5]}>
<Box fontWeight={'bold'} fontSize={['md', 'xl']} mb={2} px={[4, 8]}>
{t('core.app.External using')}
{t('core.app.navbar.Publish app')}
</Box>
<Box pb={[5, 7]} px={[4, 8]} borderBottom={theme.borders.base}>
<MyRadio

View File

@@ -3,7 +3,7 @@ import { Box, Flex, Button, IconButton } from '@chakra-ui/react';
import { useRequest } from '@/web/common/hooks/useRequest';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { useRouter } from 'next/router';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { AppSchema } from '@fastgpt/global/core/app/type.d';
import { delModelById } from '@/web/core/app/api';
import { useTranslation } from 'next-i18next';
@@ -116,12 +116,12 @@ const AppCard = ({ appId }: { appId: string }) => {
router.replace({
query: {
appId,
currentTab: 'outLink'
currentTab: 'publish'
}
});
}}
>
{t('core.app.navbar.External')}
{t('core.app.navbar.Publish')}
</Button>
{appDetail.isOwner && (
<Button

View File

@@ -18,7 +18,6 @@ const CfrEditModal = ({
}) => {
const { t } = useTranslation();
const [value, setValue] = useState(defaultValue);
const [, startTst] = useTransition();
return (
<MyModal
@@ -38,12 +37,10 @@ const CfrEditModal = ({
h={200}
showOpenModal={false}
placeholder={t('core.module.input.placeholder.cfr background')}
defaultValue={value}
onChange={useCallback((e: string) => {
startTst(() => {
setValue(e);
});
}, [])}
value={value}
onChange={(e) => {
setValue(e);
}}
/>
</Box>
</ModalBody>

View File

@@ -49,7 +49,7 @@ const ChatTest = ({ appId }: { appId: string }) => {
appName: `调试-${appDetail.name}`
},
onMessage: generatingMessage,
abortSignal: controller
abortCtrl: controller
});
return { responseText, responseData };

View File

@@ -15,7 +15,6 @@ import { useForm, useFieldArray } from 'react-hook-form';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { appModules2Form, getDefaultAppForm } from '@fastgpt/global/core/app/utils';
import type { AppSimpleEditFormType } from '@fastgpt/global/core/app/type.d';
import { chatModelList, simpleModeTemplates } from '@/web/common/system/staticData';
import { chatNodeSystemPromptTip, welcomeTextTip } from '@fastgpt/global/core/module/template/tip';
import { useRequest } from '@/web/common/hooks/useRequest';
import { useConfirm } from '@/web/common/hooks/useConfirm';
@@ -37,7 +36,7 @@ import MyTextarea from '@/components/common/Textarea/MyTextarea/index';
import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constants';
import SelectAiModel from '@/components/Select/SelectAiModel';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
import { formatVariablesIcon } from '@fastgpt/global/core/module/utils';
import { formatEditorVariablePickerIcon } from '@fastgpt/global/core/module/utils';
const DatasetSelectModal = dynamic(() => import('@/components/core/module/DatasetSelectModal'));
const DatasetParamsModal = dynamic(() => import('@/components/core/module/DatasetParamsModal'));
@@ -60,7 +59,7 @@ const EditForm = ({
const { t } = useTranslation();
const { appDetail, updateAppDetail } = useAppStore();
const { loadAllDatasets, allDatasets } = useDatasetStore();
const { isPc } = useSystemStore();
const { isPc, llmModelList, reRankModelList, simpleModeTemplates } = useSystemStore();
const [refresh, setRefresh] = useState(false);
const [, startTst] = useTransition();
@@ -100,12 +99,12 @@ const EditForm = ({
});
const variables = watch('userGuide.variables');
const formatVariables = useMemo(() => formatVariablesIcon(variables), [variables]);
const formatVariables = useMemo(() => formatEditorVariablePickerIcon(variables), [variables]);
const aiSystemPrompt = watch('aiSettings.systemPrompt');
const searchMode = watch('dataset.searchMode');
const chatModelSelectList = (() =>
chatModelList.map((item) => ({
llmModelList.map((item) => ({
value: item.model,
label: item.name
})))();
@@ -121,10 +120,10 @@ const EditForm = ({
const tokenLimit = useMemo(() => {
return (
chatModelList.find((item) => item.model === getValues('aiSettings.model'))?.quoteMaxToken ||
llmModelList.find((item) => item.model === getValues('aiSettings.model'))?.quoteMaxToken ||
3000
);
}, [getValues, refresh]);
}, [getValues, llmModelList]);
const datasetSearchMode = useMemo(() => {
if (!searchMode) return '';
@@ -280,7 +279,7 @@ const EditForm = ({
onchange={(val: any) => {
setValue('aiSettings.model', val);
const maxToken =
chatModelList.find((item) => item.model === getValues('aiSettings.model'))
llmModelList.find((item) => item.model === getValues('aiSettings.model'))
?.maxResponse || 4000;
const token = maxToken / 2;
setValue('aiSettings.maxToken', token);
@@ -301,7 +300,7 @@ const EditForm = ({
</Box>
{isInitd && (
<PromptEditor
defaultValue={aiSystemPrompt}
value={aiSystemPrompt}
onChange={(text) => {
startTst(() => {
setValue('aiSettings.systemPrompt', text);
@@ -350,6 +349,13 @@ const EditForm = ({
<Flex mt={1} color={'myGray.600'} fontSize={'sm'} mb={2}>
{t('core.dataset.search.search mode')}: {datasetSearchMode}
{', '}
{reRankModelList.length > 0 && (
<>
{t('core.dataset.search.ReRank')}:{' '}
{getValues('dataset.usingReRank') ? '✅' : '✖'}
</>
)}
{', '}
{t('core.dataset.search.Min Similarity')}: {getValues('dataset.similarity')}
{', '}
{t('core.dataset.search.Max Tokens')}: {getValues('dataset.limit')}

View File

@@ -2,9 +2,9 @@ import React, { useEffect, useMemo, useCallback } from 'react';
import { useRouter } from 'next/router';
import { Box, Flex, IconButton, useTheme } from '@chakra-ui/react';
import dynamic from 'next/dynamic';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useQuery } from '@tanstack/react-query';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import Tabs from '@/components/Tabs';
import SideTabs from '@/components/SideTabs';
@@ -27,7 +27,7 @@ const Logs = dynamic(() => import('./components/Logs'), {});
enum TabEnum {
'simpleEdit' = 'simpleEdit',
'adEdit' = 'adEdit',
'outLink' = 'outLink',
'publish' = 'publish',
'logs' = 'logs',
'startChat' = 'startChat'
}
@@ -36,6 +36,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
const { t } = useTranslation();
const router = useRouter();
const theme = useTheme();
const { feConfigs } = useSystemStore();
const { toast } = useToast();
const { appId } = router.query as { appId: string };
const { appDetail, loadAppDetail, clearAppModules } = useAppStore();
@@ -69,14 +70,14 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
}
]),
{
label: t('core.app.navbar.External'),
id: TabEnum.outLink,
label: t('core.app.navbar.Publish app'),
id: TabEnum.publish,
icon: 'support/outlink/shareLight'
},
{ label: t('app.Chat logs'), id: TabEnum.logs, icon: 'core/app/logsLight' },
{ label: t('core.Start chat'), id: TabEnum.startChat, icon: 'core/chat/chatLight' }
],
[t]
[feConfigs?.hide_app_flow, t]
);
const onCloseFlowEdit = useCallback(() => setCurrentTab(TabEnum.simpleEdit), [setCurrentTab]);
@@ -194,7 +195,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
<FlowEdit app={appDetail} onClose={onCloseFlowEdit} />
)}
{currentTab === TabEnum.logs && <Logs appId={appId} />}
{currentTab === TabEnum.outLink && <OutLink appId={appId} />}
{currentTab === TabEnum.publish && <OutLink appId={appId} />}
</Box>
</Flex>
</PageContainer>

View File

@@ -14,13 +14,12 @@ import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { useForm } from 'react-hook-form';
import { compressImgFileAndUpload } from '@/web/common/file/controller';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { postCreateApp } from '@/web/core/app/api';
import { useRouter } from 'next/router';
import { appTemplates } from '@/web/core/app/templates';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useRequest } from '@/web/common/hooks/useRequest';
import { feConfigs } from '@/web/common/system/staticData';
import Avatar from '@/components/Avatar';
import MyTooltip from '@/components/MyTooltip';
import MyModal from '@/components/MyModal';
@@ -39,7 +38,7 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: (
const { toast } = useToast();
const router = useRouter();
const theme = useTheme();
const { isPc } = useSystemStore();
const { isPc, feConfigs } = useSystemStore();
const { register, setValue, getValues, handleSubmit } = useForm<FormType>({
defaultValues: {
avatar: '/icon/logo.svg',

View File

@@ -1,20 +1,10 @@
import React, { useCallback, useEffect } from 'react';
import {
Box,
Grid,
Card,
useTheme,
Flex,
IconButton,
Button,
useDisclosure,
Image
} from '@chakra-ui/react';
import React, { useCallback } from 'react';
import { Box, Grid, Flex, IconButton, Button, useDisclosure } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import { useQuery } from '@tanstack/react-query';
import { AddIcon } from '@chakra-ui/icons';
import { delModelById } from '@/web/core/app/api';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { useTranslation } from 'next-i18next';
@@ -31,7 +21,6 @@ import { useUserStore } from '@/web/support/user/useUserStore';
const MyApps = () => {
const { toast } = useToast();
const { t } = useTranslation();
const theme = useTheme();
const router = useRouter();
const { userInfo } = useUserStore();
const { myApps, loadMyApps } = useAppStore();
@@ -76,9 +65,11 @@ const MyApps = () => {
<Box letterSpacing={1} fontSize={['20px', '24px']} color={'myGray.900'}>
{t('app.My Apps')}
</Box>
<Button leftIcon={<AddIcon />} variant={'primaryOutline'} onClick={onOpenCreateModal}>
{t('common.New Create')}
</Button>
{userInfo?.team?.canWrite && (
<Button leftIcon={<AddIcon />} variant={'primaryOutline'} onClick={onOpenCreateModal}>
{t('common.New Create')}
</Button>
)}
</Flex>
<Grid
py={[4, 6]}

View File

@@ -16,7 +16,7 @@ import { useQuery } from '@tanstack/react-query';
import { streamFetch } from '@/web/common/api/fetch';
import { useChatStore } from '@/web/core/chat/storeChat';
import { useLoading } from '@/web/common/hooks/useLoading';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
import type { ChatHistoryItemType } from '@fastgpt/global/core/chat/type.d';
@@ -80,7 +80,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
chatId: completionChatId
},
onMessage: generatingMessage,
abortSignal: controller
abortCtrl: controller
});
const newTitle =
@@ -126,7 +126,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
return { responseText, responseData, isNewChat: forbidRefresh.current };
},
[appId, chatId, histories, pushHistory, router, setChatData, updateHistory]
[appId, chatId, histories, pushHistory, router, setChatData, t, updateHistory]
);
// get chat app info
@@ -183,7 +183,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
setIsLoading(false);
return null;
},
[setIsLoading, setChatData, router, setLastChatAppId, setLastChatId, toast]
[setIsLoading, setChatData, setLastChatAppId, setLastChatId, toast, t, router]
);
// 初始化聊天框
useQuery(['init', { appId, chatId }], () => {

View File

@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
import Head from 'next/head';
import { useRouter } from 'next/router';
import { Box, Flex, useDisclosure, Drawer, DrawerOverlay, DrawerContent } from '@chakra-ui/react';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useQuery } from '@tanstack/react-query';
import { streamFetch } from '@/web/common/api/fetch';
@@ -82,7 +82,7 @@ const OutLink = ({
outLinkUid
},
onMessage: generatingMessage,
abortSignal: controller
abortCtrl: controller
});
const newTitle =

View File

@@ -55,7 +55,7 @@ import ParentPath from '@/components/common/ParentPaths';
import dynamic from 'next/dynamic';
import { useDrag } from '@/web/common/hooks/useDrag';
import SelectCollections from '@/web/core/dataset/components/SelectCollections';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import MyTooltip from '@/components/MyTooltip';
import { useUserStore } from '@/web/support/user/useUserStore';
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
@@ -381,8 +381,7 @@ const CollectionCard = () => {
<>
{userInfo?.team?.role !== TeamMemberRoleEnum.visitor && (
<MyMenu
offset={[-0, 10]}
width={120}
offset={[0, 5]}
Button={
<MenuButton
_hover={{
@@ -408,7 +407,7 @@ const CollectionCard = () => {
}
menuList={[
{
child: (
label: (
<Flex>
<MyIcon name={'common/folderFill'} w={'20px'} mr={2} />
{t('Folder')}
@@ -417,7 +416,7 @@ const CollectionCard = () => {
onClick: () => setEditFolderData({})
},
{
child: (
label: (
<Flex>
<MyIcon name={'core/dataset/manualCollection'} mr={2} w={'20px'} />
{t('core.dataset.Manual collection')}
@@ -433,7 +432,7 @@ const CollectionCard = () => {
}
},
{
child: (
label: (
<Flex>
<MyIcon name={'core/dataset/fileCollection'} mr={2} w={'20px'} />
{t('core.dataset.Text collection')}
@@ -442,7 +441,7 @@ const CollectionCard = () => {
onClick: onOpenFileSourceSelector
},
{
child: (
label: (
<Flex>
<MyIcon name={'core/dataset/tableCollection'} mr={2} w={'20px'} />
{t('core.dataset.Table collection')}
@@ -627,6 +626,7 @@ const CollectionCard = () => {
{collection.canWrite && userInfo?.team?.role !== TeamMemberRoleEnum.visitor && (
<MyMenu
width={100}
offset={[-70, 5]}
Button={
<MenuButton
w={'22px'}
@@ -655,7 +655,7 @@ const CollectionCard = () => {
...(collection.type === DatasetCollectionTypeEnum.link
? [
{
child: (
label: (
<Flex alignItems={'center'}>
<MyIcon name={'common/refreshLight'} w={'14px'} mr={2} />
{t('core.dataset.collection.Sync')}
@@ -669,7 +669,7 @@ const CollectionCard = () => {
]
: []),
{
child: (
label: (
<Flex alignItems={'center'}>
<MyIcon name={'common/file/move'} w={'14px'} mr={2} />
{t('Move')}
@@ -678,7 +678,7 @@ const CollectionCard = () => {
onClick: () => setMoveCollectionData({ collectionId: collection._id })
},
{
child: (
label: (
<Flex alignItems={'center'}>
<MyIcon name={'edit'} w={'14px'} mr={2} />
{t('Rename')}
@@ -696,7 +696,7 @@ const CollectionCard = () => {
})
},
{
child: (
label: (
<Flex alignItems={'center'}>
<MyIcon
mr={1}

View File

@@ -23,7 +23,7 @@ import {
} from '@/web/core/dataset/api';
import { DeleteIcon } from '@chakra-ui/icons';
import { useQuery } from '@tanstack/react-query';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { debounce } from 'lodash';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useConfirm } from '@/web/common/hooks/useConfirm';

View File

@@ -3,11 +3,11 @@ import MyModal from '@/components/MyModal';
import { useTranslation } from 'next-i18next';
import { Box, Button, Input, Link, ModalBody, ModalFooter } from '@chakra-ui/react';
import { strIsLink } from '@fastgpt/global/common/string/tools';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useForm } from 'react-hook-form';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { getDocPath } from '@/web/common/system/doc';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
type FormType = {
url?: string | undefined;
@@ -27,6 +27,7 @@ const WebsiteConfigModal = ({
defaultValue?: FormType;
}) => {
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const { toast } = useToast();
const { register, handleSubmit } = useForm({
defaultValues: defaultValue

View File

@@ -21,8 +21,8 @@ import { TrainingTypeMap } from '@fastgpt/global/core/dataset/constants';
import { ImportProcessWayEnum } from '@/web/core/dataset/constants';
import MyTooltip from '@/components/MyTooltip';
import { useImportStore } from '../Provider';
import { feConfigs } from '@/web/common/system/staticData';
import Tag from '@/components/Tag';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import MyModal from '@/components/MyModal';
import { Prompt_AgentQA } from '@/global/core/prompt/agent';
import Preview from '../components/Preview';
@@ -35,6 +35,7 @@ function DataProcess({
goToNext: () => void;
}) {
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const {
processParamsForm,
sources,

View File

@@ -21,7 +21,7 @@ import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { chunksUpload, fileCollectionCreate } from '@/web/core/dataset/utils';
import { ImportSourceItemType } from '@/web/core/dataset/type';
import { hashStr } from '@fastgpt/global/common/string/tools';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useRouter } from 'next/router';
import { TabEnum } from '../../../index';
import { postCreateDatasetLinkCollection, postDatasetCollection } from '@/web/core/dataset/api';

View File

@@ -29,7 +29,7 @@ const Preview = ({
.map((source) =>
source.chunks.slice(0, oneSourceChunkLength).map((chunk, i) => ({
...chunk,
chunkIndex: i + 1,
index: i + 1,
sourceName: source.sourceName,
sourceIcon: source.icon
}))
@@ -86,7 +86,7 @@ const Preview = ({
bg={'primary.50'}
borderRadius={'sm'}
>
# {chunk.chunkIndex}
# {chunk.index}
</Box>
<Flex ml={2} fontWeight={'bold'} alignItems={'center'} gap={1}>
<MyIcon name={chunk.sourceIcon as any} w={'14px'} />

View File

@@ -9,7 +9,7 @@ import { Box, Button, Flex, Input, Link, Textarea } from '@chakra-ui/react';
import { getNanoid } from '@fastgpt/global/common/string/tools';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { LinkCollectionIcon } from '@fastgpt/global/core/dataset/constants';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { getDocPath } from '@/web/common/system/doc';
import Loading from '@/components/Loading';
@@ -32,6 +32,7 @@ export default React.memo(LinkCollection);
const CustomLinkImport = ({ goToNext }: { goToNext: () => void }) => {
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const { sources, setSources, processParamsForm } = useImportStore();
const { register, reset, handleSubmit, watch } = useForm({
defaultValues: {

View File

@@ -15,7 +15,7 @@ import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants'
import MyTooltip from '@/components/MyTooltip';
import type { PreviewRawTextProps } from '../components/PreviewRawText';
import { useImportStore } from '../Provider';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import dynamic from 'next/dynamic';
import Loading from '@/components/Loading';
@@ -44,6 +44,7 @@ export default React.memo(FileLocal);
const SelectFile = React.memo(function SelectFile({ goToNext }: { goToNext: () => void }) {
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const { sources, setSources } = useImportStore();
// @ts-ignore
const [selectFiles, setSelectFiles] = useState<FileItemType[]>(sources);

View File

@@ -11,7 +11,7 @@ import { getNanoid } from '@fastgpt/global/common/string/tools';
import { useRequest } from '@/web/common/hooks/useRequest';
import MyTooltip from '@/components/MyTooltip';
import { useImportStore } from '../Provider';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import dynamic from 'next/dynamic';
import { fileDownload } from '@/web/common/file/utils';
@@ -43,6 +43,7 @@ const csvTemplate = `index,content
const SelectFile = React.memo(function SelectFile({ goToNext }: { goToNext: () => void }) {
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const { sources, setSources } = useImportStore();
// @ts-ignore
const [selectFiles, setSelectFiles] = useState<FileItemType[]>(sources);
@@ -61,10 +62,10 @@ const SelectFile = React.memo(function SelectFile({ goToNext }: { goToNext: () =
const filterData: FileItemType['chunks'] = data
.filter((item) => item[0])
.map((item, i) => ({
.map((item) => ({
q: item[0] || '',
a: item[1] || '',
chunkIndex: i
chunkIndex: 0
}));
const item: FileItemType = {

View File

@@ -14,7 +14,7 @@ import MyTooltip from '@/components/MyTooltip';
import { useTranslation } from 'next-i18next';
import PermissionRadio from '@/components/support/permission/Radio';
import MySelect from '@/components/Select';
import { qaModelList, vectorModelList } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useRequest } from '@/web/common/hooks/useRequest';
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
@@ -24,6 +24,7 @@ const Info = ({ datasetId }: { datasetId: string }) => {
const { getValues, setValue, register, handleSubmit } = useForm<DatasetItemType>({
defaultValues: datasetDetail
});
const { datasetModelList, vectorModelList } = useSystemStore();
const router = useRouter();
@@ -133,7 +134,7 @@ const Info = ({ datasetId }: { datasetId: string }) => {
</Box>
<Box flex={[1, '0 0 300px']}>{getValues('vectorModel').maxToken}</Box>
</Flex>
{qaModelList.length > 1 && (
{datasetModelList.length > 1 && (
<Flex mt={6} alignItems={'center'}>
<Box flex={['0 0 90px', '0 0 160px']} w={0}>
{t('core.ai.model.Dataset Agent Model')}
@@ -142,12 +143,12 @@ const Info = ({ datasetId }: { datasetId: string }) => {
<MySelect
w={'100%'}
value={getValues('agentModel').model}
list={qaModelList.map((item) => ({
list={datasetModelList.map((item) => ({
label: item.name,
value: item.model
}))}
onchange={(e) => {
const agentModel = qaModelList.find((item) => item.model === e);
const agentModel = datasetModelList.find((item) => item.model === e);
if (!agentModel) return;
setValue('agentModel', agentModel);
setRefresh((state) => !state);

View File

@@ -8,7 +8,7 @@ import {
getDatasetCollectionById,
getDatasetDataItemById
} from '@/web/core/dataset/api';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import MyIcon from '@fastgpt/web/components/common/Icon';
import MyModal from '@/components/MyModal';
import MyTooltip from '@/components/MyTooltip';
@@ -19,7 +19,6 @@ import { useRequest } from '@/web/common/hooks/useRequest';
import { countPromptTokens } from '@fastgpt/global/common/string/tiktoken';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { getDefaultIndex } from '@fastgpt/global/core/dataset/utils';
import { vectorModelList } from '@/web/common/system/staticData';
import { DatasetDataIndexTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { DatasetDataIndexItemType } from '@fastgpt/global/core/dataset/type';
import SideTabs from '@/components/SideTabs';
@@ -66,6 +65,7 @@ const InputDataModal = ({
const theme = useTheme();
const { toast } = useToast();
const [currentTab, setCurrentTab] = useState(TabEnum.content);
const { vectorModelList } = useSystemStore();
const { register, handleSubmit, reset, control } = useForm<InputDataType>();
const {
@@ -139,7 +139,7 @@ const InputDataModal = ({
vectorModelList[0];
return vectorModel?.maxToken || 3000;
}, [collection.datasetId.vectorModel]);
}, [collection.datasetId.vectorModel, vectorModelList]);
// import new data
const { mutate: sureImportData, isLoading: isImporting } = useRequest({

View File

@@ -21,7 +21,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
import { useRequest } from '@/web/common/hooks/useRequest';
import { formatTimeToChatTime } from '@/utils/tools';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { customAlphabet } from 'nanoid';
import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';

View File

@@ -1,7 +1,7 @@
import React, { useCallback, useMemo } from 'react';
import { useRouter } from 'next/router';
import { Box, Flex, IconButton, useTheme, Progress } from '@chakra-ui/react';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useQuery } from '@tanstack/react-query';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useSystemStore } from '@/web/common/system/useSystemStore';

View File

@@ -4,7 +4,7 @@ import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { useForm } from 'react-hook-form';
import { compressImgFileAndUpload } from '@/web/common/file/controller';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useRouter } from 'next/router';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useRequest } from '@/web/common/hooks/useRequest';
@@ -14,19 +14,21 @@ import MyModal from '@/components/MyModal';
import { postCreateDataset } from '@/web/core/dataset/api';
import type { CreateDatasetParams } from '@/global/core/dataset/api.d';
import MySelect from '@/components/Select';
import { vectorModelList, qaModelList } from '@/web/common/system/staticData';
import { useTranslation } from 'next-i18next';
import MyRadio from '@/components/common/MyRadio';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { feConfigs } from '@/web/common/system/staticData';
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: string }) => {
const { t } = useTranslation();
const [refresh, setRefresh] = useState(false);
const { toast } = useToast();
const router = useRouter();
const { isPc } = useSystemStore();
const { isPc, feConfigs, vectorModelList, datasetModelList } = useSystemStore();
const filterNotHiddenVectorModelList = vectorModelList.filter((item) => !item.hidden);
const { register, setValue, getValues, handleSubmit } = useForm<CreateDatasetParams>({
defaultValues: {
parentId,
@@ -34,8 +36,8 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
avatar: '/icon/logo.svg',
name: '',
intro: '',
vectorModel: vectorModelList[0].model,
agentModel: qaModelList[0].model
vectorModel: filterNotHiddenVectorModelList[0].model,
agentModel: datasetModelList[0].model
}
});
@@ -145,18 +147,25 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
bg={'myWhite.600'}
placeholder={t('common.Name')}
maxLength={30}
{...register('name')}
{...register('name', {
required: true
})}
/>
</Flex>
</Box>
{vectorModelList.length > 1 && (
{filterNotHiddenVectorModelList.length > 1 && (
<Flex mt={6} alignItems={'center'}>
<Box flex={'0 0 100px'}>{t('core.ai.model.Vector Model')}</Box>
<Flex alignItems={'center'} flex={'0 0 100px'}>
{t('core.ai.model.Vector Model')}
<MyTooltip label={t('core.dataset.embedding model tip')}>
<QuestionOutlineIcon ml={1} />
</MyTooltip>
</Flex>
<Box flex={1}>
<MySelect
w={'100%'}
value={getValues('vectorModel')}
list={vectorModelList.map((item) => ({
list={filterNotHiddenVectorModelList.map((item) => ({
label: item.name,
value: item.model
}))}
@@ -168,14 +177,14 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
</Box>
</Flex>
)}
{qaModelList.length > 1 && (
{datasetModelList.length > 1 && (
<Flex mt={6} alignItems={'center'}>
<Box flex={'0 0 100px'}>{t('core.ai.model.Dataset Agent Model')}</Box>
<Box flex={1}>
<MySelect
w={'100%'}
value={getValues('agentModel')}
list={qaModelList.map((item) => ({
list={datasetModelList.map((item) => ({
label: item.name,
value: item.model
}))}

View File

@@ -46,7 +46,7 @@ import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant'
import { DatasetItemType } from '@fastgpt/global/core/dataset/type';
import ParentPaths from '@/components/common/ParentPaths';
import DatasetTypeTag from '@/components/core/dataset/DatasetTypeTag';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { getErrText } from '@fastgpt/global/common/error/utils';
const CreateModal = dynamic(() => import('./component/CreateModal'), { ssr: false });
@@ -174,21 +174,19 @@ const Kb = () => {
{/* create icon */}
{userInfo?.team?.canWrite && (
<MyMenu
offset={[-30, 10]}
offset={[-30, 5]}
width={120}
Button={
<Button variant={'primaryOutline'} px={0}>
<MenuButton h={'100%'}>
<Flex alignItems={'center'} px={'20px'}>
<AddIcon mr={2} />
<Box>{t('common.Create New')}</Box>
</Flex>
</MenuButton>
<Flex alignItems={'center'} px={'20px'}>
<AddIcon mr={2} />
<Box>{t('common.Create New')}</Box>
</Flex>
</Button>
}
menuList={[
{
child: (
label: (
<Flex>
<MyIcon name={FolderIcon} w={'20px'} mr={1} />
{t('Folder')}
@@ -197,7 +195,7 @@ const Kb = () => {
onClick: () => setEditFolderData({})
},
{
child: (
label: (
<Flex>
<Image src={'/imgs/module/db.png'} alt={''} w={'20px'} mr={1} />
{t('core.dataset.Dataset')}
@@ -283,126 +281,129 @@ const Kb = () => {
}}
>
{userInfo?.team.canWrite && dataset.isOwner && (
<MyMenu
offset={[-30, 10]}
width={120}
Button={
<MenuButton
position={'absolute'}
top={3}
right={3}
w={'22px'}
h={'22px'}
borderRadius={'md'}
_hover={{
color: 'primary.500',
'& .icon': {
bg: 'myGray.100'
}
}}
onClick={(e) => {
e.stopPropagation();
}}
>
<MyIcon
className="icon"
name={'more'}
h={'16px'}
w={'16px'}
px={1}
py={1}
borderRadius={'md'}
cursor={'pointer'}
/>
</MenuButton>
}
menuList={[
...(dataset.permission === PermissionTypeEnum.private
? [
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'support/permission/publicLight'} w={'14px'} mr={2} />
{t('permission.Set Public')}
</Flex>
),
onClick: () => {
updateDataset({
id: dataset._id,
permission: PermissionTypeEnum.public
});
}
}
]
: [
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'support/permission/privateLight'} w={'14px'} mr={2} />
{t('permission.Set Private')}
</Flex>
),
onClick: () => {
updateDataset({
id: dataset._id,
permission: PermissionTypeEnum.private
});
}
}
]),
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'edit'} w={'14px'} mr={2} />
{t('Rename')}
</Flex>
),
onClick: () =>
onOpenTitleModal({
defaultVal: dataset.name,
onSuccess: (val) => {
if (val === dataset.name || !val) return;
updateDataset({ id: dataset._id, name: val });
}
})
},
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'common/file/move'} w={'14px'} mr={2} />
{t('Move')}
</Flex>
),
onClick: () => setMoveDataId(dataset._id)
},
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'export'} w={'14px'} mr={2} />
{t('Export')}
</Flex>
),
onClick: () => {
exportDataset(dataset);
}
},
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'delete'} w={'14px'} mr={2} />
{t('common.Delete')}
</Flex>
),
onClick: () => {
openConfirm(
() => onclickDelDataset(dataset._id),
undefined,
DeleteTipsMap.current[dataset.type]
)();
}
<Box
position={'absolute'}
top={3}
right={3}
borderRadius={'md'}
_hover={{
color: 'primary.500',
'& .icon': {
bg: 'myGray.100'
}
]}
/>
}}
onClick={(e) => {
e.stopPropagation();
}}
>
<MyMenu
width={120}
Button={
<Box w={'22px'} h={'22px'}>
<MyIcon
className="icon"
name={'more'}
h={'16px'}
w={'16px'}
px={1}
py={1}
borderRadius={'md'}
cursor={'pointer'}
/>
</Box>
}
menuList={[
...(dataset.permission === PermissionTypeEnum.private
? [
{
label: (
<Flex alignItems={'center'}>
<MyIcon name={'support/permission/publicLight'} w={'14px'} mr={2} />
{t('permission.Set Public')}
</Flex>
),
onClick: () => {
updateDataset({
id: dataset._id,
permission: PermissionTypeEnum.public
});
}
}
]
: [
{
label: (
<Flex alignItems={'center'}>
<MyIcon
name={'support/permission/privateLight'}
w={'14px'}
mr={2}
/>
{t('permission.Set Private')}
</Flex>
),
onClick: () => {
updateDataset({
id: dataset._id,
permission: PermissionTypeEnum.private
});
}
}
]),
{
label: (
<Flex alignItems={'center'}>
<MyIcon name={'edit'} w={'14px'} mr={2} />
{t('Rename')}
</Flex>
),
onClick: () =>
onOpenTitleModal({
defaultVal: dataset.name,
onSuccess: (val) => {
if (val === dataset.name || !val) return;
updateDataset({ id: dataset._id, name: val });
}
})
},
{
label: (
<Flex alignItems={'center'}>
<MyIcon name={'common/file/move'} w={'14px'} mr={2} />
{t('Move')}
</Flex>
),
onClick: () => setMoveDataId(dataset._id)
},
{
label: (
<Flex alignItems={'center'}>
<MyIcon name={'export'} w={'14px'} mr={2} />
{t('Export')}
</Flex>
),
onClick: () => {
exportDataset(dataset);
}
},
{
label: (
<Flex alignItems={'center'}>
<MyIcon name={'delete'} w={'14px'} mr={2} />
{t('common.Delete')}
</Flex>
),
onClick: () => {
openConfirm(
() => onclickDelDataset(dataset._id),
undefined,
DeleteTipsMap.current[dataset.type]
)();
}
}
]}
/>
</Box>
)}
<Flex alignItems={'center'} h={'38px'}>
<Avatar src={dataset.avatar} borderRadius={'md'} w={'28px'} />

View File

@@ -0,0 +1,21 @@
import { serviceSideProps } from '@/web/common/utils/i18n';
import React, { useEffect } from 'react';
import Loading from '@/components/Loading';
import { useRouter } from 'next/router';
const index = () => {
const router = useRouter();
useEffect(() => {
router.push('/app/list');
}, [router]);
return <Loading></Loading>;
};
export async function getServerSideProps(content: any) {
return {
props: {
...(await serviceSideProps(content))
}
};
}
export default index;

View File

@@ -5,8 +5,8 @@ import { PageTypeEnum } from '@/constants/user';
import { postFindPassword } from '@/web/support/user/api';
import { useSendCode } from '@/web/support/user/hooks/useSendCode';
import type { ResLogin } from '@/global/support/api/userRes.d';
import { useToast } from '@/web/common/hooks/useToast';
import { feConfigs } from '@/web/common/system/staticData';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useSystemStore } from '@/web/common/system/useSystemStore';
interface Props {
setPageType: Dispatch<`${PageTypeEnum}`>;
@@ -22,6 +22,7 @@ interface RegisterType {
const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
const { toast } = useToast();
const { feConfigs } = useSystemStore();
const {
register,
handleSubmit,

View File

@@ -16,8 +16,7 @@ import { PageTypeEnum } from '@/constants/user';
import { OAuthEnum } from '@fastgpt/global/support/user/constant';
import { postLogin } from '@/web/support/user/api';
import type { ResLogin } from '@/global/support/api/userRes';
import { useToast } from '@/web/common/hooks/useToast';
import { feConfigs } from '@/web/common/system/staticData';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { customAlphabet } from 'nanoid';
@@ -43,7 +42,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
const theme = useTheme();
const { lastRoute = '/app/list' } = router.query as { lastRoute: string };
const { toast } = useToast();
const { setLoginStore } = useSystemStore();
const { setLoginStore, feConfigs } = useSystemStore();
const {
register,
handleSubmit,

View File

@@ -1,14 +1,15 @@
import React, { useState, Dispatch, useCallback } from 'react';
import { FormControl, Box, Input, Button, FormErrorMessage, Flex } from '@chakra-ui/react';
import { FormControl, Box, Input, Button } from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
import { PageTypeEnum } from '@/constants/user';
import { postRegister } from '@/web/support/user/api';
import { useSendCode } from '@/web/support/user/hooks/useSendCode';
import type { ResLogin } from '@/global/support/api/userRes';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { postCreateApp } from '@/web/core/app/api';
import { appTemplates } from '@/web/core/app/templates';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useTranslation } from 'next-i18next';
interface Props {
loginSuccess: (e: ResLogin) => void;
@@ -24,6 +25,8 @@ interface RegisterType {
const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
const { toast } = useToast();
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const {
register,
handleSubmit,
@@ -68,7 +71,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
appTemplates.forEach((template) => {
postCreateApp({
avatar: template.avatar,
name: template.name,
name: t(template.name),
modules: template.modules,
type: template.type
});

View File

@@ -6,7 +6,7 @@ import { useChatStore } from '@/web/core/chat/storeChat';
import { useUserStore } from '@/web/support/user/useUserStore';
import { clearToken, setToken } from '@/web/support/user/auth';
import { postFastLogin } from '@/web/support/user/api';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import Loading from '@/components/Loading';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { useQuery } from '@tanstack/react-query';

View File

@@ -10,7 +10,6 @@ import LoginForm from './components/LoginForm';
import dynamic from 'next/dynamic';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { clearToken, setToken } from '@/web/support/user/auth';
import { feConfigs } from '@/web/common/system/staticData';
import CommunityModal from '@/components/CommunityModal';
import Script from 'next/script';
const RegisterForm = dynamic(() => import('./components/RegisterForm'));
@@ -19,7 +18,7 @@ const ForgetPasswordForm = dynamic(() => import('./components/ForgetPasswordForm
const Login = () => {
const router = useRouter();
const { lastRoute = '' } = router.query as { lastRoute: string };
const { isPc } = useSystemStore();
const { feConfigs } = useSystemStore();
const [pageType, setPageType] = useState<`${PageTypeEnum}`>(PageTypeEnum.login);
const { setUserInfo } = useUserStore();
const { setLastChatId, setLastChatAppId } = useChatStore();

View File

@@ -6,7 +6,7 @@ import { useChatStore } from '@/web/core/chat/storeChat';
import { useUserStore } from '@/web/support/user/useUserStore';
import { clearToken, setToken } from '@/web/support/user/auth';
import { oauthLogin } from '@/web/support/user/api';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import Loading from '@/components/Loading';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { getErrText } from '@fastgpt/global/common/error/utils';

View File

@@ -12,7 +12,7 @@ import { filterExportModules, flowNode2Modules } from '@/components/core/module/
import { putUpdatePlugin } from '@/web/core/plugin/api';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleItemType } from '@fastgpt/global/core/module/type';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
const ImportSettings = dynamic(() => import('@/components/core/module/Flow/ImportSettings'));
const PreviewPlugin = dynamic(() => import('./Preview'));

View File

@@ -9,7 +9,7 @@ import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { useQuery } from '@tanstack/react-query';
import { getOnePlugin } from '@/web/core/plugin/api';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import Loading from '@/components/Loading';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useTranslation } from 'next-i18next';

View File

@@ -4,7 +4,7 @@ import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { useForm } from 'react-hook-form';
import { compressImgFileAndUpload } from '@/web/common/file/controller';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useRouter } from 'next/router';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useRequest } from '@/web/common/hooks/useRequest';

View File

@@ -12,10 +12,12 @@ import Avatar from '@/components/Avatar';
import EditModal, { defaultForm, FormType } from './component/EditModal';
import { getUserPlugins } from '@/web/core/plugin/api';
import EmptyTip from '@/components/EmptyTip';
import { useUserStore } from '@/web/support/user/useUserStore';
const MyModules = () => {
const { t } = useTranslation();
const theme = useTheme();
const { userInfo } = useUserStore();
const router = useRouter();
const [editModalData, setEditModalData] = useState<FormType>();
@@ -37,13 +39,15 @@ const MyModules = () => {
{t('plugin.My Plugins')}({t('common.Beta')})
</Box>
</Flex>
<Button
leftIcon={<AddIcon />}
variant={'primaryOutline'}
onClick={() => setEditModalData(defaultForm)}
>
{t('common.New Create')}
</Button>
{userInfo?.team?.canWrite && (
<Button
leftIcon={<AddIcon />}
variant={'primaryOutline'}
onClick={() => setEditModalData(defaultForm)}
>
{t('common.New Create')}
</Button>
)}
</Flex>
<Grid
py={5}

View File

@@ -0,0 +1,304 @@
import {
Box,
Flex,
Grid,
NumberDecrementStepper,
NumberInput,
NumberIncrementStepper,
NumberInputField,
NumberInputStepper,
Button,
useDisclosure,
ModalBody,
ModalFooter
} from '@chakra-ui/react';
import { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
import { useTranslation } from 'next-i18next';
import React, { useEffect, useMemo, useState } from 'react';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
import MySelect from '@/components/Select';
import {
SubStatusEnum,
SubTypeEnum,
subSelectMap
} from '@fastgpt/global/support/wallet/sub/constants';
import { useRequest } from '@/web/common/hooks/useRequest';
import {
posCheckTeamDatasetSizeSub,
postUpdateTeamDatasetSizeSub,
putTeamDatasetSubStatus
} from '@/web/support/wallet/sub/api';
import { SubDatasetSizePreviewCheckResponse } from '@fastgpt/global/support/wallet/sub/api.d';
import { useRouter } from 'next/router';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { useUserStore } from '@/web/support/user/useUserStore';
import MyModal from '@/components/MyModal';
const ExtraPlan = ({ extraDatasetSize }: { extraDatasetSize?: TeamSubSchema }) => {
const { t } = useTranslation();
const { subPlans } = useSystemStore();
const extraDatasetPrice = subPlans?.extraDatasetSize?.price || 0;
const [datasetSize, setDatasetSize] = useState(0);
const [isRenew, setIsRenew] = useState('false');
const router = useRouter();
const { userInfo } = useUserStore();
const [confirmPayExtraDatasetSizeData, setConfirmPayExtraDatasetSizeData] =
useState<SubDatasetSizePreviewCheckResponse>();
useEffect(() => {
setDatasetSize((extraDatasetSize?.nextExtraDatasetSize || 0) / 1000);
setIsRenew(extraDatasetSize?.status === SubStatusEnum.active ? 'true' : 'false');
}, [extraDatasetSize]);
const { mutate: onUpdateExtraDatasetSizeStatus } = useRequest({
mutationFn: (e: 'true' | 'false') => {
setIsRenew(e);
return putTeamDatasetSubStatus({
status: subSelectMap[e],
type: SubTypeEnum.extraDatasetSize
});
},
successToast: t('common.Update success'),
errorToast: t('common.error.Update error')
});
const { mutate: onClickUpdateExtraDatasetPlan, isLoading: isPayingExtraDatasetSize } = useRequest(
{
mutationFn: () => postUpdateTeamDatasetSizeSub({ size: datasetSize }),
onSuccess() {
setTimeout(() => {
router.reload();
}, 100);
},
successToast: t('common.Update success'),
errorToast: t('common.error.Update error')
}
);
const { mutate: onClickPreviewCheck, isLoading: isFetchingPreviewCheck } = useRequest({
mutationFn: () =>
posCheckTeamDatasetSizeSub({
size: datasetSize
}),
onSuccess(res: SubDatasetSizePreviewCheckResponse) {
if (!res.payForNewSub) {
onClickUpdateExtraDatasetPlan('');
return;
} else {
setConfirmPayExtraDatasetSizeData(res);
}
},
errorToast: t('common.error.Update error')
});
return (
<Flex
mt={['40px', '90px']}
flexDirection={'column'}
alignItems={'center'}
position={'relative'}
>
<Box fontWeight={'bold'} fontSize={['24px', '36px']}>
{t('support.wallet.subscription.Extra plan')}
</Box>
<Box mt={8} mb={10} color={'myGray.500'} fontSize={'lg'}>
{t('support.wallet.subscription.Extra plan tip')}
</Box>
<Grid mt={8} gridTemplateColumns={['1fr', '1fr']}>
<Box
bg={'rgba(255, 255, 255, 0.90)'}
px={'32px'}
py={'24px'}
borderRadius={'2xl'}
borderWidth={'1px'}
borderColor={'myGray.150'}
boxShadow={'1.5'}
>
<Flex w={['100%', '500px']} borderBottomWidth={'1px'} borderBottomColor={'myGray.200'}>
<Box flex={'1 0 0'}>
<Box fontSize={'xl'} color={'primary.600'}>
{t('support.wallet.subscription.Extra dataset size')}
</Box>
<Box mt={3} fontSize={['32px', '38px']} fontWeight={'bold'}>
{extraDatasetPrice}/1k组{' '}
<Box ml={1} as={'span'} fontSize={'lg'} color={'myGray.600'} fontWeight={'normal'}>
/{t('common.month')}
</Box>
</Box>
</Box>
<MyIcon
transform={'translate(20px,-20px)'}
name={'support/pay/extraDatasetsize'}
fill={'none'}
/>
</Flex>
<Box>
<Flex mt={4}>
<Box flex={'0 0 200px'}>
{t('support.wallet.subscription.Current dataset store')}:{' '}
</Box>
<Box fontWeight={'bold'} flex={1}>
{extraDatasetSize?.currentExtraDatasetSize || 0}
{t('core.dataset.data.unit')}
</Box>
</Flex>
{extraDatasetSize?.nextExtraDatasetSize !== undefined && (
<Flex mt={4}>
<Box flex={'0 0 200px'}>
{t('support.wallet.subscription.Next sub dataset size')}:
</Box>
<Box fontWeight={'bold'} flex={1}>
{extraDatasetSize?.nextExtraDatasetSize || 0}
{t('core.dataset.data.unit')}
</Box>
</Flex>
)}
{!!extraDatasetSize?.startTime && (
<Flex mt={3}>
<Box flex={'0 0 200px'}>: </Box>
<Box>{formatTime2YMDHM(extraDatasetSize?.startTime)}</Box>
</Flex>
)}
{!!extraDatasetSize?.expiredTime && (
<Flex mt={3}>
<Box flex={'0 0 200px'}>: </Box>
<Box>{formatTime2YMDHM(extraDatasetSize?.expiredTime)}</Box>
</Flex>
)}
<Flex mt={3} alignItems={'center'}>
<Box flex={'0 0 200px'}>: </Box>
<MySelect
value={isRenew}
size={'sm'}
w={'180px'}
bg={'myGray.50'}
boxShadow={'none'}
list={[
{ label: '自动续费', value: 'true' },
{ label: '不自动续费', value: 'false' }
]}
onchange={(e) => {
if (!extraDatasetSize) return;
onUpdateExtraDatasetSizeStatus(e);
}}
/>
</Flex>
<Flex mt={4} alignItems={'center'}>
<Box flex={'0 0 200px'}>
{t('support.wallet.subscription.Update extra dataset size')}
</Box>
<Flex alignItems={'center'} mt={1} w={'180px'} position={'relative'}>
<NumberInput
size={'sm'}
flex={1}
min={0}
max={10000}
step={1}
value={datasetSize}
position={'relative'}
onChange={(e) => {
setDatasetSize(Number(e));
}}
>
<NumberInputField pr={'30px'} value={datasetSize} step={1} min={0} max={10000} />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
<Box position={'absolute'} right={'20px'} color={'myGray.500'} fontSize={'xs'}>
000{t('core.dataset.data.unit')}
</Box>
</Flex>
</Flex>
<Button
isDisabled={datasetSize * 1000 === extraDatasetSize?.nextExtraDatasetSize}
mt={6}
w={'100%'}
variant={'primaryGhost'}
isLoading={isPayingExtraDatasetSize || isFetchingPreviewCheck}
onClick={onClickPreviewCheck}
>
{t('common.change')}
</Button>
</Box>
</Box>
</Grid>
{/* extra dataset size modal */}
{!!confirmPayExtraDatasetSizeData && (
<MyModal
isOpen
onClose={() => setConfirmPayExtraDatasetSizeData(undefined)}
title={t('support.wallet.Confirm pay')}
iconSrc="common/confirm/rightTip"
>
<ModalBody px={8} py={5}>
<Flex>
<Box flex={'0 0 120px'} color={'myGray.600'}>
</Box>
<Box>{extraDatasetSize?.currentExtraDatasetSize || 0}</Box>
</Flex>
<Flex mt={4}>
<Box flex={'0 0 120px'} color={'myGray.600'}>
</Box>
<Box>{confirmPayExtraDatasetSizeData.newSubSize}</Box>
</Flex>
<Flex mt={4}>
<Box flex={'0 0 120px'} color={'myGray.600'}>
</Box>
<Box>{formatStorePrice2Read(confirmPayExtraDatasetSizeData.newPlanPrice)}</Box>
</Flex>
<Flex mt={4}>
<Box flex={'0 0 120px'} color={'myGray.600'}>
</Box>
<Box>30</Box>
</Flex>
{/* <Flex>
<Box flex={'0 0 120px'}>账号余额:</Box>
<Box>{formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)}元</Box>
</Flex> */}
</ModalBody>
<ModalFooter mx={8} px={0} borderTopWidth={'1px'} borderTopColor={'myGray.200'}>
<Box color={'myGray.600'}></Box>
{confirmPayExtraDatasetSizeData.balanceEnough ? (
<>
<Box flex={'1 0 0'}>
{formatStorePrice2Read(userInfo?.team?.balance).toFixed(2)}
</Box>
<Button
isLoading={isPayingExtraDatasetSize}
onClick={() => onClickUpdateExtraDatasetPlan('')}
>
{formatStorePrice2Read(confirmPayExtraDatasetSizeData.payPrice).toFixed(2)}
</Button>
</>
) : (
<>
<Box color={'red.600'} flex={'1 0 0'}>
</Box>
<Button
isLoading={isPayingExtraDatasetSize}
onClick={() => router.push('/account')}
>
</Button>
</>
)}
</ModalFooter>
</MyModal>
)}
</Flex>
);
};
export default React.memo(ExtraPlan);

View File

@@ -0,0 +1,42 @@
import React from 'react';
import { Box, Button, Flex, Grid } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
const FAQ = () => {
const { t } = useTranslation();
const faqs = [{ title: '怎么付费', describe: '2222' }];
return (
<Flex
mt={['40px', '90px']}
pb={'10vh'}
flexDirection={'column'}
alignItems={'center'}
position={'relative'}
>
<Box fontWeight={'bold'} fontSize={['24px', '36px']}>
{t('support.wallet.subscription.FAQ')}
</Box>
<Grid mt={4} gridTemplateColumns={['1fr', '1fr 1fr']} gap={4} w={'100%'}>
<Box
py={2}
px={4}
borderRadius={'lg'}
borderWidth={'1px'}
borderColor={'myGray.150'}
bg={'rgba(255,255,255,0.9)'}
_hover={{
borderColor: 'primary.300'
}}
>
<Box fontSize={'lg'} fontWeight={'500'}>
</Box>
<Box color={'myGray.500'}>2222</Box>
</Box>
</Grid>
</Flex>
);
};
export default FAQ;

View File

@@ -0,0 +1,122 @@
import React from 'react';
import { Box, Flex, Grid } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import { useSystemStore } from '@/web/common/system/useSystemStore';
const Points = () => {
const { t } = useTranslation();
const { llmModelList, audioSpeechModelList, vectorModelList, whisperModel } = useSystemStore();
return (
<Flex
mt={['40px', '90px']}
flexDirection={'column'}
alignItems={'center'}
position={'relative'}
>
<Box fontWeight={'bold'} fontSize={['24px', '36px']}>
{t('support.wallet.subscription.Ai points')}
</Box>
<Grid gap={6} mt={['30px', '48px']} w={'100%'}>
<Box
display={['block', 'flex']}
borderRadius={'xl'}
borderWidth={'1px'}
borderColor={'myGray.150'}
bg={'rgba(255,255,255,0.9)'}
overflow={'hidden'}
>
<Box
flex={1}
borderRightWidth={'1px'}
borderRightColor={'myGray.150'}
py={4}
px={6}
fontSize={'lg'}
fontWeight={'bold'}
>
AI语言模型
</Box>
<Box flex={4} textAlign={'center'}>
{llmModelList?.map((item, i) => (
<Flex key={item.model} py={4} bg={i % 2 !== 0 ? 'myGray.50' : ''}>
<Box flex={'1 0 0'}>{item.name}</Box>
<Box flex={'1 0 0'}>5 / 1000</Box>
</Flex>
))}
</Box>
</Box>
<Box
display={['block', 'flex']}
borderRadius={'xl'}
borderWidth={'1px'}
borderColor={'myGray.150'}
bg={'rgba(255,255,255,0.9)'}
overflow={'hidden'}
>
<Box flex={1} borderRightWidth={'1px'} borderRightColor={'myGray.150'} py={4} px={6}>
<Box fontSize={'lg'} fontWeight={'bold'}>
</Box>
<Box fontSize={'sm'} mt={1} color={'myGray.500'}>
&
</Box>
</Box>
<Box flex={4} textAlign={'center'}>
{vectorModelList?.map((item, i) => (
<Flex key={item.model} py={4} bg={i % 2 !== 0 ? 'myGray.50' : ''}>
<Box flex={'1 0 0'}>{item.name}</Box>
<Box flex={'1 0 0'}>5 / 1000</Box>
</Flex>
))}
</Box>
</Box>
<Box
display={['block', 'flex']}
borderRadius={'xl'}
borderWidth={'1px'}
borderColor={'myGray.150'}
bg={'rgba(255,255,255,0.9)'}
overflow={'hidden'}
>
<Box flex={1} borderRightWidth={'1px'} borderRightColor={'myGray.150'} py={4} px={6}>
<Box fontSize={'lg'} fontWeight={'bold'}>
</Box>
</Box>
<Box flex={4} textAlign={'center'}>
{audioSpeechModelList?.map((item, i) => (
<Flex key={item.model} py={4} bg={i % 2 !== 0 ? 'myGray.50' : ''}>
<Box flex={'1 0 0'}>{item.name}</Box>
<Box flex={'1 0 0'}>5 / 1000</Box>
</Flex>
))}
</Box>
</Box>
<Box
display={['block', 'flex']}
borderRadius={'xl'}
borderWidth={'1px'}
borderColor={'myGray.150'}
bg={'rgba(255,255,255,0.9)'}
overflow={'hidden'}
>
<Box flex={1} borderRightWidth={'1px'} borderRightColor={'myGray.150'} py={4} px={6}>
<Box fontSize={'lg'} fontWeight={'bold'}>
</Box>
</Box>
<Box flex={4} textAlign={'center'} h={'100%'}>
<Flex py={4}>
<Box flex={'1 0 0'}>{whisperModel?.name}</Box>
<Box flex={'1 0 0'}>{whisperModel?.inputPrice} / </Box>
</Flex>
</Box>
</Box>
</Grid>
</Flex>
);
};
export default React.memo(Points);

View File

@@ -0,0 +1,340 @@
import React, { useMemo, useState } from 'react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { Box, Button, Flex, Grid } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import { StandardSubLevelEnum, SubModeEnum } from '@fastgpt/global/support/wallet/sub/constants';
import { useUserStore } from '@/web/support/user/useUserStore';
import { postCheckStandardSub, postUpdateStandardSub } from '@/web/support/wallet/sub/api';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants';
import { StandardSubPlanParams } from '@fastgpt/global/support/wallet/sub/api';
import { useRequest } from '@/web/common/hooks/useRequest';
import { StandardSubPlanUpdateResponse } from '@fastgpt/global/support/wallet/sub/api.d';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
const Standard = ({
standardPlan,
refetchTeamSubPlan
}: {
standardPlan?: TeamSubSchema;
refetchTeamSubPlan: () => void;
}) => {
const { t } = useTranslation();
const { subPlans, feConfigs } = useSystemStore();
const { toast } = useToast();
const { ConfirmModal, openConfirm } = useConfirm({});
const [selectSubMode, setSelectSubMode] = useState<`${SubModeEnum}`>(SubModeEnum.month);
const standardSubList = useMemo(() => {
return subPlans?.standard
? Object.entries(subPlans.standard).map(([level, value]) => {
return {
price: value.price * (selectSubMode === SubModeEnum.month ? 1 : 10),
level: level as `${StandardSubLevelEnum}`,
...standardSubLevelMap[level as `${StandardSubLevelEnum}`],
maxTeamMember: value.maxTeamMember,
maxAppAmount: value.maxAppAmount,
maxDatasetAmount: value.maxDatasetAmount,
chatHistoryStoreDuration: value.chatHistoryStoreDuration,
maxDatasetSize: value.maxDatasetSize,
customApiKey: value.customApiKey,
customCopyright: value.customCopyright,
trainingWeight: value.trainingWeight,
reRankWeight: value.reRankWeight,
totalPoints: value.totalPoints * (selectSubMode === SubModeEnum.month ? 1 : 12),
websiteSyncInterval: value.websiteSyncInterval
};
})
: [];
}, [subPlans?.standard, selectSubMode]);
const { mutate: onclickUpdateStandardPlan, isLoading: isUpdatingStandardPlan } = useRequest({
mutationFn: (data: StandardSubPlanParams) => postUpdateStandardSub(data),
onSuccess() {
refetchTeamSubPlan();
},
successToast: t('support.wallet.subscription.Standard update success'),
errorToast: t('support.wallet.subscription.Standard update fail')
});
const { mutate: onclickPreCheckStandPlan, isLoading: isCheckingStandardPlan } = useRequest({
mutationFn: (data: StandardSubPlanParams) => postCheckStandardSub(data),
onSuccess(res: StandardSubPlanUpdateResponse) {
if (!res.balanceEnough) {
return toast({
status: 'warning',
title: t('support.wallet.Balance not enough tip')
});
}
if (res.payPrice === undefined) {
onclickUpdateStandardPlan({
level: res.nextSubLevel,
mode: res.nextMode
});
} else if (res.payPrice > 0) {
openConfirm(
() =>
onclickUpdateStandardPlan({
level: res.nextSubLevel,
mode: res.nextMode
}),
undefined,
t('support.wallet.subscription.Standard plan pay confirm', {
payPrice: formatStorePrice2Read(res.payPrice).toFixed(2)
})
)();
} else {
openConfirm(
() =>
onclickUpdateStandardPlan({
level: res.nextSubLevel,
mode: res.nextMode
}),
undefined,
t('support.wallet.subscription.Refund plan and pay confirm', {
amount: formatStorePrice2Read(Math.abs(res.payPrice)).toFixed(2)
})
)();
}
}
});
return (
<Flex flexDirection={'column'} alignItems={'center'} position={'relative'}>
<Box fontWeight={'bold'} fontSize={['24px', '36px']}>
{t('support.wallet.subscription.Sub plan')}
</Box>
<Box mt={8} mb={10} color={'myGray.500'} fontSize={'lg'}>
{t('support.wallet.subscription.Sub plan tip')}
</Box>
<Box>
<RowTabs
list={[
{ label: t('support.wallet.subscription.mode.Month'), value: SubModeEnum.month },
{
label: (
<Flex>
{t('support.wallet.subscription.mode.Year')}
<Box color={selectSubMode === SubModeEnum.month ? 'red.600' : 'auto'}>
({t('support.wallet.subscription.mode.Year sale')})
</Box>
</Flex>
),
value: SubModeEnum.year
}
]}
value={selectSubMode}
onChange={(e) => setSelectSubMode(e as `${SubModeEnum}`)}
/>
</Box>
{/* card */}
<Grid
mt={[10, '48px']}
gridTemplateColumns={['1fr', 'repeat(2,1fr)', 'repeat(4,1fr)']}
gap={[4, 6, 8]}
w={'100%'}
>
{standardSubList.map((item) => (
<Box
key={item.level}
bg={'rgba(255, 255, 255, 0.90)'}
p={'28px'}
borderRadius={'2xl'}
borderWidth={'1px'}
borderColor={'myGray.150'}
boxShadow={'1.5'}
>
<Box fontSize={'lg'} fontWeight={'500'}>
{t(item.label)}
</Box>
<Box fontSize={['32px', '42px']} fontWeight={'bold'}>
{item.price}
</Box>
<Box color={'myGray.500'} h={'40px'}>
{t(item.desc, { title: feConfigs?.systemTitle })}
</Box>
{(() => {
if (item.level === StandardSubLevelEnum.free && selectSubMode === SubModeEnum.year) {
return (
<Button isDisabled mt={4} mb={6} w={'100%'} variant={'solid'}>
{t('support.wallet.subscription.Nonsupport')}
</Button>
);
}
if (
item.level === standardPlan?.currentSubLevel &&
selectSubMode === standardPlan?.currentMode
) {
return (
<Button mt={4} mb={6} w={'100%'} variant={'whiteBase'} isDisabled>
{t('support.wallet.subscription.Current plan')}
</Button>
);
}
if (
item.level === standardPlan?.nextSubLevel &&
selectSubMode === standardPlan?.nextMode
) {
return (
<Button mt={4} mb={6} w={'100%'} variant={'whiteBase'} isDisabled>
{t('support.wallet.subscription.Next plan')}
</Button>
);
}
return (
<Button
mt={4}
mb={6}
w={'100%'}
variant={'primaryGhost'}
isLoading={isUpdatingStandardPlan || isCheckingStandardPlan}
onClick={() =>
onclickPreCheckStandPlan({
level: item.level,
mode: selectSubMode
})
}
>
{t('support.wallet.subscription.Buy now')}
</Button>
);
})()}
{/* function list */}
<Grid gap={4}>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<Box color={'myGray.600'}>
{t('support.wallet.subscription.function.Max members', {
amount: item.maxTeamMember
})}
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<Box color={'myGray.600'}>
{t('support.wallet.subscription.function.Max app', {
amount: item.maxAppAmount
})}
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<Box color={'myGray.600'}>
{t('support.wallet.subscription.function.Max dataset', {
amount: item.maxDatasetAmount
})}
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<Box color={'myGray.600'}>
{t('support.wallet.subscription.function.History store', {
amount: item.chatHistoryStoreDuration
})}
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<Box color={'myGray.600'}>
{t('support.wallet.subscription.function.Max dataset size', {
amount: item.maxDatasetSize
})}
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<Box color={'myGray.600'}>
{t('support.wallet.subscription.function.Points', {
amount: item.totalPoints
})}
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<Box color={'myGray.600'}>
{t('support.wallet.subscription.Training weight', {
weight: item.trainingWeight
})}
</Box>
</Flex>
{!!item.customApiKey && (
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<Box color={'myGray.600'}>API Key</Box>
</Flex>
)}
{!!item.websiteSyncInterval && (
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<Box color={'myGray.600'}>{item.websiteSyncInterval} h/ web站点同步</Box>
</Flex>
)}
</Grid>
</Box>
))}
</Grid>
<ConfirmModal />
</Flex>
);
};
export default React.memo(Standard);
const RowTabs = ({
list,
value,
onChange
}: {
list: {
icon?: string;
label: string | React.ReactNode;
value: string;
}[];
value: string;
onChange: (e: string) => void;
}) => {
return (
<Box
display={'inline-flex'}
px={'3px'}
py={'3px'}
borderRadius={'md'}
borderWidth={'1px'}
borderColor={'primary.300'}
bg={'primary.50'}
gap={'4px'}
>
{list.map((item) => (
<Flex
key={item.value}
alignItems={'center'}
justifyContent={'center'}
cursor={'pointer'}
borderRadius={'md'}
px={'12px'}
py={'7px'}
userSelect={'none'}
w={['150px', '170px']}
{...(value === item.value
? {
color: 'white',
boxShadow: '1.5',
bg: 'primary.600'
}
: {
onClick: () => onChange(item.value)
})}
>
{item.icon && <MyIcon name={item.icon as any} mr={1} w={'14px'} />}
<Box>{item.label}</Box>
</Flex>
))}
</Box>
);
};

View File

@@ -0,0 +1,57 @@
import React from 'react';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { Box, Image } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import { useUserStore } from '@/web/support/user/useUserStore';
import { getTeamDatasetValidSub } from '@/web/support/wallet/sub/api';
import { useQuery } from '@tanstack/react-query';
import StandardPlan from './components/Standard';
import ExtraPlan from './components/ExtraPlan';
import PointsCard from './components/Points';
import FAQ from './components/FAQ';
const PriceBox = () => {
const { t } = useTranslation();
const { userInfo } = useUserStore();
const { data: teamSubPlan, refetch: refetchTeamSubPlan } = useQuery(
['getTeamDatasetValidSub'],
getTeamDatasetValidSub,
{
enabled: !!userInfo
}
);
return (
<Box
h={'100%'}
overflow={'overlay'}
w={'100%'}
px={['20px', '5vw']}
py={['30px', '80px']}
backgroundImage={'url(/imgs/priceBg.svg)'}
backgroundSize={'cover'}
backgroundRepeat={'no-repeat'}
>
{/* standard sub */}
<StandardPlan standardPlan={teamSubPlan?.standard} refetchTeamSubPlan={refetchTeamSubPlan} />
<ExtraPlan extraDatasetSize={teamSubPlan?.extraDatasetSize} />
{/* points */}
<PointsCard />
{/* question */}
<FAQ />
</Box>
);
};
export default PriceBox;
export async function getServerSideProps(context: any) {
return {
props: { ...(await serviceSideProps(context)) }
};
}

View File

@@ -3,7 +3,7 @@ import { Box, Flex } from '@chakra-ui/react';
import { ChevronRightIcon } from '@chakra-ui/icons';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useRouter } from 'next/router';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { useTranslation } from 'next-i18next';
import { getDocPath } from '@/web/common/system/doc';
@@ -11,6 +11,7 @@ import { getDocPath } from '@/web/common/system/doc';
const Tools = () => {
const { t } = useTranslation();
const router = useRouter();
const { feConfigs } = useSystemStore();
const list = [
{
icon: 'core/dataset/datasetLight',

View File

@@ -1,6 +1,7 @@
import React from 'react';
import Price from '@/components/support/wallet/Price';
import { useRouter } from 'next/router';
import { serviceSideProps } from '@/web/common/utils/i18n';
const PriceBox = () => {
const router = useRouter();
@@ -8,3 +9,9 @@ const PriceBox = () => {
};
export default PriceBox;
export async function getServerSideProps(context: any) {
return {
props: { ...(await serviceSideProps(context)) }
};
}