{name} |
{apiKey} |
- {Math.round(usagePoints)} |
+ {usage} |
{feConfigs?.isPlus && (
<>
- {limit?.maxUsagePoints && limit?.maxUsagePoints > -1
- ? `${limit?.maxUsagePoints}`
+ {limit?.credit && limit?.credit > -1
+ ? `${limit?.credit}`
: t('common.Unlimited')}
|
@@ -334,15 +334,15 @@ function EditKeyModal({
<>
- {t('support.outlink.Max usage points')}:
-
+ {t('common.Max credit')}:
+
import('./EditModal'));
const InviteModal = dynamic(() => import('./InviteModal'));
-const TeamTagsAsync = dynamic(() => import('../TeamTagsAsync'));
const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
const theme = useTheme();
const { t } = useTranslation();
const { Loading } = useLoading();
const { toast } = useToast();
- const [teamsTags, setTeamTags] = useState();
const { ConfirmModal: ConfirmRemoveMemberModal, openConfirm: openRemoveMember } = useConfirm();
const { ConfirmModal: ConfirmLeaveTeamModal, openConfirm: openLeaveConfirm } = useConfirm({
@@ -69,11 +61,6 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
const { userInfo, initUserInfo } = useUserStore();
const [editTeamData, setEditTeamData] = useState();
const { isOpen: isOpenInvite, onOpen: onOpenInvite, onClose: onCloseInvite } = useDisclosure();
- const {
- isOpen: isOpenTeamTagsAsync,
- onOpen: onOpenTeamTagsAsync,
- onClose: onCloseTeamTagsAsync
- } = useDisclosure();
const {
data: myTeams = [],
@@ -89,8 +76,6 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
mutationFn: async (teamId: string) => {
const token = await putSwitchTeam(teamId);
token && setToken(token);
- // get team tags
- await getTeamsTags(teamId);
return initUserInfo();
},
errorToast: t('user.team.Switch Team Failed')
@@ -101,11 +86,6 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
['getMembers', userInfo?.team?.teamId],
() => {
if (!userInfo?.team?.teamId) return [];
- // get team tags
- getTeamsTags(userInfo.team.teamId).then((res: any) => {
- setTeamTags(res);
- });
-
return getTeamMembers(userInfo.team.teamId);
}
);
@@ -128,9 +108,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
mutationFn: async (teamId?: string) => {
if (!teamId) return;
// change to personal team
- // get members
await onSwitchTeam(defaultTeam.teamId);
-
return delLeaveTeam(teamId);
},
onSuccess() {
@@ -206,7 +184,6 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
bg: 'myGray.100'
}
})}
- onClick={() => onSwitchTeam(team.teamId)}
>
void }) => {
: {})}
>
{team.teamName}
- {/* {userInfo?.team?.teamId === team.teamId && (
-
- {teamsTags.slice(0, 3).map((item: any, index) => {
- return (
-
- {item.label}
-
- );
- })}
-
- )} */}
{userInfo?.team?.teamId === team.teamId ? (
@@ -263,7 +229,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
borderBottomColor={'myGray.100'}
mb={3}
>
-
+
{userInfo.team.teamName}
{userInfo.team.role === TeamMemberRoleEnum.owner && (
@@ -313,27 +279,6 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
{t('user.team.Invite Member')}
)}
- {userInfo.team.role === TeamMemberRoleEnum.owner && (
- }
- onClick={() => {
- if (userInfo.team.maxSize <= members.length) {
- toast({
- status: 'warning',
- title: t('user.team.Team Tags Async', { max: userInfo.team.maxSize })
- });
- } else {
- onOpenTeamTagsAsync();
- }
- }}
- >
- {t('user.team.Team Tags Async')}
-
- )}
{userInfo.team.role !== TeamMemberRoleEnum.owner && (
- }
- >
-
-
-
- {t('同步链接')}
-
-
-
-
-
- {t('分享链接')}
-
- {/* code */}
-
-
-
- {linkUrl}
-
- {
- copyData(linkUrl);
- }}
- />
-
-
-
-
-
- {t('标签列表')}
-
-
- {_teamsTags.map((item, index) => {
- return (
-
-
- {item.label}
-
- );
- })}
-
- } onClick={asyncTags}>
- 立即同步
-
-
-
-
-
-
-
-
- >
- );
-};
-
-export default React.memo(TeamTagsAsync);
diff --git a/projects/app/src/components/support/wallet/Price.tsx b/projects/app/src/components/support/wallet/Price.tsx
new file mode 100644
index 000000000..f102ec2a2
--- /dev/null
+++ b/projects/app/src/components/support/wallet/Price.tsx
@@ -0,0 +1,97 @@
+import React from 'react';
+import { Box, CloseButton } from '@chakra-ui/react';
+import { useSystemStore } from '@/web/common/system/useSystemStore';
+import ReactDOM from 'react-dom';
+
+import Markdown from '@/components/Markdown';
+
+const Price = ({ onClose }: { onClose: () => void }) => {
+ const { llmModelList, vectorModelList, audioSpeechModelList, whisperModel } = useSystemStore();
+
+ const list = [
+ {
+ title: 'AI语言模型',
+ describe: '',
+ md: `
+| 模型 | 输入价格(¥) | 输出价格(¥) |
+| --- | --- | --- |
+${llmModelList
+ ?.map((item) => `| ${item.name} | ${item.inputPrice}/1k tokens | ${item.outputPrice}/1k tokens |`)
+ .join('\n')}`
+ },
+ {
+ title: '索引模型(文档训练 & 文档检索)',
+ describe: '',
+ md: `
+| 模型 | 价格(¥) |
+| --- | --- |
+${vectorModelList?.map((item) => `| ${item.name} | ${item.inputPrice}/1k 字符 |`).join('\n')}
+ `
+ },
+ {
+ title: '语音播放',
+ describe: '',
+ md: `
+| 模型 | 价格(¥) |
+| --- | --- |
+${audioSpeechModelList
+ ?.map((item) => `| ${item.name} | ${item.inputPrice}/1k 字符 | - |`)
+ .join('\n')}`
+ },
+ ...(whisperModel
+ ? [
+ {
+ title: '语音输入',
+ describe: '',
+ md: `
+| 模型 | 价格(¥) |
+| --- | --- |
+| ${whisperModel.name} | ${whisperModel.inputPrice}/分钟 | - |`
+ }
+ ]
+ : [])
+ ];
+
+ return ReactDOM.createPortal(
+
+
+
+
+ {list.map((item) => (
+
+
+ {item.title}
+
+
+
+
+
+ ))}
+
+
+ ,
+ // @ts-ignore
+ document.querySelector('body')
+ );
+};
+
+export default Price;
diff --git a/projects/app/src/components/support/wallet/QRCodePayModal.tsx b/projects/app/src/components/support/wallet/QRCodePayModal.tsx
deleted file mode 100644
index 521479154..000000000
--- a/projects/app/src/components/support/wallet/QRCodePayModal.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import MyModal from '@/components/MyModal';
-import React, { useEffect } from 'react';
-import { useTranslation } from 'next-i18next';
-import { Box, ModalBody, ModalFooter } from '@chakra-ui/react';
-import { useQuery } from '@tanstack/react-query';
-import { checkBalancePayResult } from '@/web/support/wallet/bill/api';
-import { useToast } from '@fastgpt/web/hooks/useToast';
-import { useRouter } from 'next/router';
-import { getErrText } from '@fastgpt/global/common/error/utils';
-
-export type QRPayProps = {
- readPrice: number;
- codeUrl: string;
- billId: string;
-};
-
-const QRCodePayModal = ({
- readPrice,
- codeUrl,
- billId,
- onSuccess
-}: QRPayProps & { onSuccess?: () => any }) => {
- const router = useRouter();
- const { t } = useTranslation();
- const { toast } = useToast();
- const dom = document.getElementById('payQRCode');
-
- useEffect(() => {
- if (dom && window.QRCode) {
- new window.QRCode(dom, {
- text: codeUrl,
- width: 128,
- height: 128,
- colorDark: '#000000',
- colorLight: '#ffffff',
- correctLevel: window.QRCode.CorrectLevel.H
- });
- }
- }, [dom]);
-
- useQuery(
- [billId],
- () => {
- if (!billId) return null;
- return checkBalancePayResult(billId);
- },
- {
- enabled: !!billId,
- refetchInterval: 3000,
- onSuccess: async (res) => {
- if (!res) return;
-
- try {
- await onSuccess?.();
- toast({
- title: res,
- status: 'success'
- });
- } catch (error) {
- toast({
- title: getErrText(error),
- status: 'error'
- });
- }
-
- setTimeout(() => {
- router.reload();
- }, 1000);
- }
- }
- );
-
- return (
-
-
- 请微信扫码支付: {readPrice}元,请勿关闭页面
-
-
-
-
- );
-};
-
-export default React.memo(QRCodePayModal);
diff --git a/projects/app/src/components/support/wallet/StandardPlanContentList.tsx b/projects/app/src/components/support/wallet/StandardPlanContentList.tsx
deleted file mode 100644
index 6a5eda487..000000000
--- a/projects/app/src/components/support/wallet/StandardPlanContentList.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import { useSystemStore } from '@/web/common/system/useSystemStore';
-import { StandardSubLevelEnum, SubModeEnum } from '@fastgpt/global/support/wallet/sub/constants';
-import React, { useMemo } from 'react';
-import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants';
-import { Box, Flex, Grid } from '@chakra-ui/react';
-import MyIcon from '@fastgpt/web/components/common/Icon';
-import { useTranslation } from 'next-i18next';
-
-const StandardPlanContentList = ({
- level,
- mode
-}: {
- level: `${StandardSubLevelEnum}`;
- mode: `${SubModeEnum}`;
-}) => {
- const { t } = useTranslation();
- const { subPlans } = useSystemStore();
-
- const planContent = useMemo(() => {
- const plan = subPlans?.standard?.[level];
- if (!plan) return;
- return {
- price: plan.price * (mode === SubModeEnum.month ? 1 : 10),
- level: level as `${StandardSubLevelEnum}`,
- ...standardSubLevelMap[level as `${StandardSubLevelEnum}`],
- maxTeamMember: plan.maxTeamMember,
- maxAppAmount: plan.maxAppAmount,
- maxDatasetAmount: plan.maxDatasetAmount,
- chatHistoryStoreDuration: plan.chatHistoryStoreDuration,
- maxDatasetSize: plan.maxDatasetSize,
- permissionCustomApiKey: plan.permissionCustomApiKey,
- permissionCustomCopyright: plan.permissionCustomCopyright,
- trainingWeight: plan.trainingWeight,
- permissionReRank: plan.permissionReRank,
- totalPoints: plan.totalPoints * (mode === SubModeEnum.month ? 1 : 12),
- permissionWebsiteSync: plan.permissionWebsiteSync
- };
- }, [subPlans?.standard, level, mode]);
-
- return planContent ? (
-
-
-
-
- {t('support.wallet.subscription.function.Max members', {
- amount: planContent.maxTeamMember
- })}
-
-
-
-
-
- {t('support.wallet.subscription.function.Max app', {
- amount: planContent.maxAppAmount
- })}
-
-
-
-
-
- {t('support.wallet.subscription.function.Max dataset', {
- amount: planContent.maxDatasetAmount
- })}
-
-
-
-
-
- {t('support.wallet.subscription.function.History store', {
- amount: planContent.chatHistoryStoreDuration
- })}
-
-
-
-
-
- {t('support.wallet.subscription.function.Max dataset size', {
- amount: planContent.maxDatasetSize
- })}
-
-
-
-
-
-
- {t('support.wallet.subscription.function.Points', {
- amount: planContent.totalPoints
- })}
-
-
-
-
-
-
- {t('support.wallet.subscription.Training weight', {
- weight: planContent.trainingWeight
- })}
-
-
- {!!planContent.permissionReRank && (
-
-
- 检索结果重排
-
- )}
- {!!planContent.permissionWebsiteSync && (
-
-
- Web站点同步
-
- )}
-
- ) : null;
-};
-
-export default StandardPlanContentList;
diff --git a/projects/app/src/components/support/wallet/SubDatasetModal.tsx b/projects/app/src/components/support/wallet/SubDatasetModal.tsx
new file mode 100644
index 000000000..dcc100b10
--- /dev/null
+++ b/projects/app/src/components/support/wallet/SubDatasetModal.tsx
@@ -0,0 +1,240 @@
+import React, { useState } from 'react';
+import MyModal from '@/components/MyModal';
+import { useTranslation } from 'next-i18next';
+import {
+ Box,
+ Flex,
+ ModalBody,
+ NumberInput,
+ NumberInputField,
+ NumberInputStepper,
+ NumberIncrementStepper,
+ NumberDecrementStepper,
+ ModalFooter,
+ Button
+} from '@chakra-ui/react';
+import { useQuery } from '@tanstack/react-query';
+import {
+ getTeamDatasetValidSub,
+ posCheckTeamDatasetSizeSub,
+ postUpdateTeamDatasetSizeSub,
+ putTeamDatasetSubStatus
+} from '@/web/support/wallet/sub/api';
+import Markdown from '@/components/Markdown';
+import MyTooltip from '@/components/MyTooltip';
+import { QuestionOutlineIcon } from '@chakra-ui/icons';
+import { useConfirm } from '@/web/common/hooks/useConfirm';
+import { useRequest } from '@/web/common/hooks/useRequest';
+import { useRouter } from 'next/router';
+import { useSystemStore } from '@/web/common/system/useSystemStore';
+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 { SubDatasetSizePreviewCheckResponse } from '@fastgpt/global/support/wallet/sub/api.d';
+import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
+import { useUserStore } from '@/web/support/user/useUserStore';
+
+const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
+ const { subPlans } = useSystemStore();
+ const datasetStorePrice = subPlans?.extraDatasetSize?.price || 0;
+
+ const { t } = useTranslation();
+ const router = useRouter();
+ const { ConfirmModal, openConfirm } = useConfirm({});
+ const { userInfo } = useUserStore();
+ const [datasetSize, setDatasetSize] = useState(0);
+ const [isRenew, setIsRenew] = useState('false');
+
+ const { data: teamSubPlan } = useQuery(['getTeamDatasetValidSub'], getTeamDatasetValidSub, {
+ onSuccess(res) {
+ setIsRenew(res?.extraDatasetSize?.status === SubStatusEnum.active ? 'true' : 'false');
+ setDatasetSize((res?.extraDatasetSize?.nextExtraDatasetSize || 0) / 1000);
+ }
+ });
+
+ const { mutate: onClickUpdateSub, isLoading: isPaying } = 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) {
+ onClickUpdateSub('');
+ return;
+ } else {
+ openConfirm(
+ () => {
+ if (!res.balanceEnough) return;
+ onClickUpdateSub('');
+ },
+ undefined,
+
+
+ 当前额外容量:
+ {teamSubPlan?.extraDatasetSize?.currentExtraDatasetSize || 0}条
+
+
+ 新的额外容量:
+ {res.newSubSize}条
+
+
+ 新套餐价格:
+ {formatStorePrice2Read(res.newPlanPrice)}元
+
+
+ 本次需支付:
+ {formatStorePrice2Read(res.payPrice)}元
+
+
+ 有效时长:
+ 30天
+
+
+ 账号余额:
+ {formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)}元
+
+ {!res.balanceEnough && (
+
+ 账号余额不足,请先充值余额再购买额外容量。
+
+ )}
+
+ )();
+ }
+ },
+ errorToast: t('common.error.Update error')
+ });
+ const { mutate: onUpdateStatus } = 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 isLoading = isPaying || isFetchingPreviewCheck;
+
+ return (
+
+
+ <>
+
+ {t('support.user.Price')}
+
+
+
+
+
+ >
+
+ {t('support.wallet.subscription.Current dataset store')}:
+
+ {teamSubPlan?.extraDatasetSize?.currentExtraDatasetSize || 0}
+ {t('core.dataset.data.unit')}
+
+
+ {teamSubPlan?.extraDatasetSize?.nextExtraDatasetSize !== undefined && (
+
+ {t('support.wallet.subscription.Next sub dataset size')}:
+
+ {teamSubPlan?.extraDatasetSize?.nextExtraDatasetSize || 0}
+ {t('core.dataset.data.unit')}
+
+
+ )}
+ {!!teamSubPlan?.extraDatasetSize?.startTime && (
+
+ 订阅开始时间:
+ {formatTime2YMDHM(teamSubPlan?.extraDatasetSize?.startTime)}
+
+ )}
+ {!!teamSubPlan?.extraDatasetSize?.expiredTime && (
+
+ 订阅到期时间:
+ {formatTime2YMDHM(teamSubPlan?.extraDatasetSize?.expiredTime)}
+
+ )}
+
+ 是否自动续费:
+
+
+
+ {t('support.wallet.subscription.Update extra dataset size')}
+
+ {
+ setDatasetSize(Number(e));
+ }}
+ >
+
+
+
+
+
+
+ 000{t('core.dataset.data.unit')}
+
+
+
+
+
+ {datasetSize * 1000 !== teamSubPlan?.extraDatasetSize?.nextExtraDatasetSize && (
+
+ )}
+
+
+
+
+ );
+};
+
+export default SubDatasetModal;
diff --git a/projects/app/src/constants/app.ts b/projects/app/src/constants/app.ts
index de53fbab3..53651df43 100644
--- a/projects/app/src/constants/app.ts
+++ b/projects/app/src/constants/app.ts
@@ -15,8 +15,7 @@ export const defaultApp: AppDetailType = {
tmbId: '',
permission: 'private',
isOwner: false,
- canWrite: false,
- teamTags: ['']
+ canWrite: false
};
export const defaultOutLinkForm: OutLinkEditType = {
@@ -24,7 +23,7 @@ export const defaultOutLinkForm: OutLinkEditType = {
responseDetail: false,
limit: {
QPM: 100,
- maxUsagePoints: -1
+ credit: -1
}
};
diff --git a/projects/app/src/global/core/chat/api.d.ts b/projects/app/src/global/core/chat/api.d.ts
index 654005c81..db20bed4d 100644
--- a/projects/app/src/global/core/chat/api.d.ts
+++ b/projects/app/src/global/core/chat/api.d.ts
@@ -14,12 +14,6 @@ export type InitChatProps = {
chatId?: string;
loadCustomFeedbacks?: boolean;
};
-/* ---------- chat ----------- */
-export type chatByTeamProps = {
- teamId?: string;
- appId?: string;
- outLinkUid?: string;
-};
export type InitOutLinkChatProps = {
chatId?: string;
shareId?: string;
@@ -45,7 +39,6 @@ export type InitChatResponse = {
/* ---------- history ----------- */
export type getHistoriesProps = {
appId?: string;
- authToken?: string;
// share chat
shareId?: string;
outLinkUid?: string; // authToken/uid
diff --git a/projects/app/src/global/core/prompt/AIChat.ts b/projects/app/src/global/core/prompt/AIChat.ts
index ea2a18f80..a89f3cd87 100644
--- a/projects/app/src/global/core/prompt/AIChat.ts
+++ b/projects/app/src/global/core/prompt/AIChat.ts
@@ -4,34 +4,42 @@ export const Prompt_QuoteTemplateList: PromptTemplateItem[] = [
{
title: '标准模板',
desc: '标准提示词,用于结构不固定的知识库。',
- value: `{{q}}
-{{a}}`
+ value: `
+{{q}}
+{{a}}
+`
},
{
title: '问答模板',
desc: '适合 QA 问答结构的知识库,可以让AI较为严格的按预设内容回答',
- value: `
+ value: `
+<问题>
{{q}}
-
-
+问题>
+<答案>
{{a}}
-`
+答案>
+`
},
{
title: '标准严格模板',
desc: '在标准模板基础上,对模型的回答做更严格的要求。',
- value: `{{q}}
-{{a}}`
+ value: `
+{{q}}
+{{a}}
+`
},
{
title: '严格问答模板',
desc: '在问答模板基础上,对模型的回答做更严格的要求。',
- value: `
+ value: `
+<问题>
{{q}}
-
-
+问题>
+<答案>
{{a}}
-`
+答案>
+`
}
];
@@ -39,16 +47,14 @@ export const Prompt_QuotePromptList: PromptTemplateItem[] = [
{
title: '标准模板',
desc: '',
- value: `使用 标记中的内容作为你的知识:
+ value: `使用 标记中的内容作为你的知识:
-
{{quote}}
-
回答要求:
- 如果你不清楚答案,你需要澄清。
-- 避免提及你是从 获取的知识。
-- 保持答案与 中描述的一致。
+- 避免提及你是从 获取的知识。
+- 保持答案与 中描述的一致。
- 使用 Markdown 语法优化回答格式。
- 使用与问题相同的语言回答。
@@ -59,9 +65,7 @@ export const Prompt_QuotePromptList: PromptTemplateItem[] = [
desc: '',
value: `使用 标记中的问答对进行回答。
-
{{quote}}
-
回答要求:
- 选择其中一个或多个问答对进行回答。
@@ -74,20 +78,18 @@ export const Prompt_QuotePromptList: PromptTemplateItem[] = [
{
title: '标准严格模板',
desc: '',
- value: `忘记你已有的知识,仅使用 标记中的内容作为你的知识:
+ value: `忘记你已有的知识,仅使用 标记中的内容作为你的知识:
-
{{quote}}
-
思考流程:
-1. 判断问题是否与 标记中的内容有关。
+1. 判断问题是否与 标记中的内容有关。
2. 如果有关,你按下面的要求回答。
3. 如果无关,你直接拒绝回答本次问题。
回答要求:
-- 避免提及你是从 获取的知识。
-- 保持答案与 中描述的一致。
+- 避免提及你是从 获取的知识。
+- 保持答案与 中描述的一致。
- 使用 Markdown 语法优化回答格式。
- 使用与问题相同的语言回答。
@@ -98,9 +100,7 @@ export const Prompt_QuotePromptList: PromptTemplateItem[] = [
desc: '',
value: `忘记你已有的知识,仅使用 标记中的问答对进行回答。
-
{{quote}}
-}
思考流程:
1. 判断问题是否与 标记中的内容有关。
diff --git a/projects/app/src/pages/_error.tsx b/projects/app/src/pages/_error.tsx
index f2acb97a9..1c119ad0a 100644
--- a/projects/app/src/pages/_error.tsx
+++ b/projects/app/src/pages/_error.tsx
@@ -2,7 +2,6 @@ import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { useSystemStore } from '@/web/common/system/useSystemStore';
-import { Box } from '@chakra-ui/react';
function Error() {
const router = useRouter();
@@ -25,12 +24,11 @@ function Error() {
}, []);
return (
-
- {`出现未捕获的异常。
-1. 私有部署用户,90%由于配置文件不正确导致。
-2. 部分系统不兼容相关API。大部分是苹果的safari 浏览器导致,可以尝试更换 chrome。
-3. 请关闭浏览器翻译功能,部分翻译导致页面崩溃。`}
-
+
+ 部分系统不兼容,导致页面崩溃。如果可以,请联系作者,反馈下具体操作和页面。 大部分是 苹果 的
+ safari 浏览器导致,可以尝试更换 chrome
+ 浏览器。或者是因为开了中文翻译导致,请检查并关闭中文翻译。
+
);
}
diff --git a/projects/app/src/pages/account/components/BillDetail.tsx b/projects/app/src/pages/account/components/BillDetail.tsx
new file mode 100644
index 000000000..6d089c2cf
--- /dev/null
+++ b/projects/app/src/pages/account/components/BillDetail.tsx
@@ -0,0 +1,160 @@
+import React, { useMemo } from 'react';
+import {
+ ModalBody,
+ Flex,
+ Box,
+ Table,
+ Thead,
+ Tbody,
+ Tr,
+ Th,
+ Td,
+ TableContainer
+} from '@chakra-ui/react';
+import { BillItemType } from '@fastgpt/global/support/wallet/bill/type.d';
+import dayjs from 'dayjs';
+import { BillSourceMap } from '@fastgpt/global/support/wallet/bill/constants';
+import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
+import MyModal from '@/components/MyModal';
+import { useTranslation } from 'next-i18next';
+
+const BillDetail = ({ bill, onClose }: { bill: BillItemType; onClose: () => void }) => {
+ const { t } = useTranslation();
+ const filterBillList = useMemo(
+ () => bill.list.filter((item) => item && item.moduleName),
+ [bill.list]
+ );
+
+ const {
+ hasModel,
+ hasTokens,
+ hasInputTokens,
+ hasOutputTokens,
+ hasCharsLen,
+ hasDuration,
+ hasDataLen,
+ hasDatasetSize
+ } = useMemo(() => {
+ let hasModel = false;
+ let hasTokens = false;
+ let hasInputTokens = false;
+ let hasOutputTokens = false;
+ let hasCharsLen = false;
+ let hasDuration = false;
+ let hasDataLen = false;
+ let hasDatasetSize = false;
+
+ bill.list.forEach((item) => {
+ if (item.model !== undefined) {
+ hasModel = true;
+ }
+ if (typeof item.tokenLen === 'number') {
+ hasTokens = true;
+ }
+ if (typeof item.inputTokens === 'number') {
+ hasInputTokens = true;
+ }
+ if (typeof item.outputTokens === 'number') {
+ hasOutputTokens = true;
+ }
+ if (typeof item.charsLength === 'number') {
+ hasCharsLen = true;
+ }
+ if (typeof item.duration === 'number') {
+ hasDuration = true;
+ }
+ if (typeof item.datasetSize === 'number') {
+ hasDatasetSize = true;
+ }
+ });
+
+ return {
+ hasModel,
+ hasTokens,
+ hasInputTokens,
+ hasOutputTokens,
+ hasCharsLen,
+ hasDuration,
+ hasDataLen,
+ hasDatasetSize
+ };
+ }, [bill.list]);
+
+ return (
+
+
+ {/*
+ {t('wallet.bill.bill username')}:
+ {t(bill.memberName)}
+ */}
+
+ {t('wallet.bill.Number')}:
+ {bill.id}
+
+
+ {t('wallet.bill.Time')}:
+ {dayjs(bill.time).format('YYYY/MM/DD HH:mm:ss')}
+
+
+ {t('wallet.bill.App name')}:
+ {t(bill.appName) || '-'}
+
+
+ {t('wallet.bill.Source')}:
+ {t(BillSourceMap[bill.source]?.label)}
+
+
+ {t('wallet.bill.Total')}:
+ {bill.total}元
+
+
+
+ {t('wallet.bill.Bill Module')}
+
+
+
+
+
+ {t('wallet.bill.Module name')} |
+ {hasModel && {t('wallet.bill.Ai model')} | }
+ {hasTokens && {t('wallet.bill.Token Length')} | }
+ {hasInputTokens && {t('wallet.bill.Input Token Length')} | }
+ {hasOutputTokens && {t('wallet.bill.Output Token Length')} | }
+ {hasCharsLen && {t('wallet.bill.Text Length')} | }
+ {hasDuration && {t('wallet.bill.Duration')} | }
+ {hasDatasetSize && (
+ {t('support.wallet.subscription.type.extraDatasetSize')} |
+ )}
+ 费用(¥) |
+
+
+
+ {filterBillList.map((item, i) => (
+
+ {t(item.moduleName)} |
+ {hasModel && {item.model ?? '-'} | }
+ {hasTokens && {item.tokenLen ?? '-'} | }
+ {hasInputTokens && {item.inputTokens ?? '-'} | }
+ {hasOutputTokens && {item.outputTokens ?? '-'} | }
+ {hasCharsLen && {item.charsLength ?? '-'} | }
+ {hasDuration && {item.duration ?? '-'} | }
+ {hasDatasetSize && {item.datasetSize ?? '-'} | }
+ {formatStorePrice2Read(item.amount)} |
+
+ ))}
+
+
+
+
+
+
+ );
+};
+
+export default BillDetail;
diff --git a/projects/app/src/pages/account/components/BillTable.tsx b/projects/app/src/pages/account/components/BillTable.tsx
index eb382a952..8ea7eddd5 100644
--- a/projects/app/src/pages/account/components/BillTable.tsx
+++ b/projects/app/src/pages/account/components/BillTable.tsx
@@ -1,6 +1,5 @@
-import React, { useState, useCallback, useMemo, useEffect } from 'react';
+import React, { useEffect, useMemo, useState } from 'react';
import {
- Button,
Table,
Thead,
Tbody,
@@ -10,38 +9,43 @@ import {
TableContainer,
Flex,
Box,
- ModalBody
+ Button
} from '@chakra-ui/react';
-import { getBills, checkBalancePayResult } from '@/web/support/wallet/bill/api';
-import type { BillSchemaType } from '@fastgpt/global/support/wallet/bill/type.d';
+import { BillSourceEnum, BillSourceMap } from '@fastgpt/global/support/wallet/bill/constants';
+import { getUserBills } from '@/web/support/wallet/bill/api';
+import type { BillItemType } from '@fastgpt/global/support/wallet/bill/type';
+import { usePagination } from '@/web/common/hooks/usePagination';
+import { useLoading } from '@/web/common/hooks/useLoading';
import dayjs from 'dayjs';
-import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools';
-import { useToast } from '@fastgpt/web/hooks/useToast';
import MyIcon from '@fastgpt/web/components/common/Icon';
+import DateRangePicker, { type DateRangeType } from '@/components/DateRangePicker';
+import { addDays } from 'date-fns';
+import dynamic from 'next/dynamic';
+import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useTranslation } from 'next-i18next';
import MySelect from '@/components/Select';
-import {
- BillTypeEnum,
- billPayWayMap,
- billStatusMap,
- billTypeMap
-} from '@fastgpt/global/support/wallet/bill/constants';
-import { usePagination } from '@/web/common/hooks/usePagination';
-import MyBox from '@/components/common/MyBox';
-import { useRequest } from '@/web/common/hooks/useRequest';
-import MyModal from '@/components/MyModal';
-import { standardSubLevelMap, subModeMap } from '@fastgpt/global/support/wallet/sub/constants';
+import { useQuery } from '@tanstack/react-query';
+import { useUserStore } from '@/web/support/user/useUserStore';
+import { getTeamMembers } from '@/web/support/user/team/api';
+import Avatar from '@/components/Avatar';
+const BillDetail = dynamic(() => import('./BillDetail'));
const BillTable = () => {
const { t } = useTranslation();
- const { toast } = useToast();
- const [billType, setBillType] = useState<`${BillTypeEnum}` | ''>('');
- const [billDetail, setBillDetail] = useState();
+ const { Loading } = useLoading();
+ const [dateRange, setDateRange] = useState({
+ from: addDays(new Date(), -7),
+ to: new Date()
+ });
+ const [billSource, setBillSource] = useState<`${BillSourceEnum}` | ''>('');
+ const { isPc } = useSystemStore();
+ const { userInfo } = useUserStore();
+ const [billDetail, setBillDetail] = useState();
- const billTypeList = useMemo(
+ const sourceList = useMemo(
() => [
{ label: t('common.All'), value: '' },
- ...Object.entries(billTypeMap).map(([key, value]) => ({
+ ...Object.entries(BillSourceMap).map(([key, value]) => ({
label: t(value.label),
value: key
}))
@@ -49,193 +53,134 @@ const BillTable = () => {
[t]
);
+ const [selectTmbId, setSelectTmbId] = useState(userInfo?.team?.tmbId);
+ const { data: members = [] } = useQuery(['getMembers', userInfo?.team?.teamId], () => {
+ if (!userInfo?.team?.teamId) return [];
+ return getTeamMembers(userInfo.team.teamId);
+ });
+ const tmbList = useMemo(
+ () =>
+ members.map((item) => ({
+ label: (
+
+
+ {item.memberName}
+
+ ),
+ value: item.tmbId
+ })),
+ [members]
+ );
+
const {
data: bills,
isLoading,
Pagination,
- getData,
- total
- } = usePagination({
- api: getBills,
- pageSize: 20,
+ getData
+ } = usePagination({
+ api: getUserBills,
+ pageSize: isPc ? 20 : 10,
params: {
- type: billType
+ dateStart: dateRange.from || new Date(),
+ dateEnd: addDays(dateRange.to || new Date(), 1),
+ source: billSource,
+ teamMemberId: selectTmbId
},
defaultRequest: false
});
- const { mutate: handleRefreshPayOrder, isLoading: isRefreshing } = useRequest({
- mutationFn: async (payId: string) => {
- try {
- const data = await checkBalancePayResult(payId);
- toast({
- title: data,
- status: 'success'
- });
- } catch (error: any) {
- toast({
- title: error?.message,
- status: 'warning'
- });
- console.log(error);
- }
- try {
- getData(1);
- } catch (error) {}
- }
- });
-
useEffect(() => {
getData(1);
- }, [billType]);
+ }, [billSource, selectTmbId]);
return (
-
-
+
+
+ {tmbList.length > 1 && userInfo?.team?.canWrite && (
+
+
+ {t('support.user.team.member')}
+
+
+
+ )}
+
+
+ getData(1)}
+ />
+
+
+
+
- # |
+ {/* {t('user.team.Member Name')} | */}
+ {t('user.Time')} |
{
- setBillType(e);
+ setBillSource(e);
}}
w={'130px'}
>
|
- {t('user.Time')} |
- {t('support.wallet.Amount')} |
- {t('support.wallet.bill.Status')} |
+ {t('user.Application Name')} |
+ {t('user.Total Amount')} |
|
- {bills.map((item, i) => (
-
- {i + 1} |
- {t(billTypeMap[item.type]?.label)} |
+ {bills.map((item) => (
+
+ {/* {item.memberName} | */}
+ {dayjs(item.time).format('YYYY/MM/DD HH:mm:ss')} |
+ {t(BillSourceMap[item.source]?.label)} |
+ {t(item.appName) || '-'} |
+ {item.total}元 |
- {item.createTime ? dayjs(item.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'}
- |
- {formatStorePrice2Read(item.price)}元 |
- {t(billStatusMap[item.status]?.label)} |
-
- {item.status === 'NOTPAY' && (
-
- )}
- |
))}
- {total >= 20 && (
-
-
-
- )}
- {!isLoading && bills.length === 0 && (
-
-
-
- {t('support.wallet.noBill')}
-
-
- )}
- {!!billDetail && (
- setBillDetail(undefined)} />
+ {!isLoading && bills.length === 0 && (
+
+
+
+ 无使用记录~
+
+
)}
-
+
+
+ {!!billDetail && setBillDetail(undefined)} />}
+
);
};
-export default BillTable;
-
-function BillDetailModal({ bill, onClose }: { bill: BillSchemaType; onClose: () => void }) {
- const { t } = useTranslation();
-
- return (
-
-
-
- {t('support.wallet.bill.Number')}:
- {bill.orderId}
-
-
- {t('support.wallet.usage.Time')}:
- {dayjs(bill.createTime).format('YYYY/MM/DD HH:mm:ss')}
-
-
- {t('support.wallet.bill.Status')}:
- {t(billStatusMap[bill.status]?.label)}
-
- {!!bill.metadata?.payWay && (
-
- {t('support.wallet.bill.payWay.Way')}:
- {t(billPayWayMap[bill.metadata.payWay]?.label)}
-
- )}
-
- {t('support.wallet.Amount')}:
- {formatStorePrice2Read(bill.price)}元
-
-
- {t('support.wallet.bill.Type')}:
- {t(billTypeMap[bill.type]?.label)}
-
- {!!bill.metadata?.subMode && (
-
- {t('support.wallet.subscription.mode.Period')}:
- {t(subModeMap[bill.metadata.subMode]?.label)}
-
- )}
- {!!bill.metadata?.standSubLevel && (
-
- {t('support.wallet.subscription.Stand plan level')}:
- {t(standardSubLevelMap[bill.metadata.standSubLevel]?.label)}
-
- )}
- {bill.metadata?.datasetSize !== undefined && (
-
- {t('support.wallet.subscription.Extra dataset size')}:
- {bill.metadata?.datasetSize}
-
- )}
- {bill.metadata?.extraPoints !== undefined && (
-
- {t('support.wallet.subscription.Extra ai points')}:
- {bill.metadata.extraPoints}
-
- )}
-
-
- );
-}
+export default React.memo(BillTable);
diff --git a/projects/app/src/pages/account/components/Info.tsx b/projects/app/src/pages/account/components/Info.tsx
index 6f6d45a75..a957475be 100644
--- a/projects/app/src/pages/account/components/Info.tsx
+++ b/projects/app/src/pages/account/components/Info.tsx
@@ -1,14 +1,15 @@
-import React, { useCallback, useMemo } from 'react';
+import React, { useCallback, useMemo, useRef } from 'react';
import {
Box,
Flex,
Button,
useDisclosure,
useTheme,
+ Divider,
+ Select,
Input,
Link,
- Progress,
- Grid
+ Progress
} from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
import { UserUpdateParams } from '@/types/user';
@@ -21,68 +22,35 @@ import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { compressImgFileAndUpload } from '@/web/common/file/controller';
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';
import MyIcon from '@fastgpt/web/components/common/Icon';
import MyTooltip from '@/components/MyTooltip';
+import { langMap, setLngStore } from '@/web/common/utils/i18n';
import { useRouter } from 'next/router';
-import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools';
+import MySelect from '@/components/Select';
+import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import { putUpdateMemberName } from '@/web/support/user/team/api';
import { getDocPath } from '@/web/common/system/doc';
+import { getTeamDatasetValidSub } from '@/web/support/wallet/sub/api';
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
-import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants';
-import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
-import { AI_POINT_USAGE_CARD_ROUTE } from '@/web/support/wallet/sub/constants';
-import StandardPlanContentList from '@/components/support/wallet/StandardPlanContentList';
-const StandDetailModal = dynamic(() => import('./standardDetailModal'));
const TeamMenu = dynamic(() => import('@/components/support/user/team/TeamMenu'));
const PayModal = dynamic(() => import('./PayModal'));
const UpdatePswModal = dynamic(() => import('./UpdatePswModal'));
const OpenAIAccountModal = dynamic(() => import('./OpenAIAccountModal'));
+const SubDatasetModal = dynamic(() => import('@/components/support/wallet/SubDatasetModal'));
-const Account = () => {
- const { isPc } = useSystemStore();
-
- const { initUserInfo } = useUserStore();
-
- useQuery(['init'], initUserInfo);
-
- return (
-
- {isPc ? (
-
-
-
-
-
-
-
-
-
-
-
- ) : (
- <>
-
-
-
- >
- )}
-
- );
-};
-
-export default React.memo(Account);
-
-const MyInfo = () => {
+const UserInfo = () => {
const theme = useTheme();
- const { feConfigs } = useSystemStore();
- const { t } = useTranslation();
- const { userInfo, updateUserInfo } = useUserStore();
+ const router = useRouter();
+ const { feConfigs, systemVersion } = useSystemStore();
+ const { t, i18n } = useTranslation();
+ const { userInfo, updateUserInfo, initUserInfo } = useUserStore();
+ const timezones = useRef(timezoneList());
const { reset } = useForm({
defaultValues: userInfo as UserType
});
- const { isPc } = useSystemStore();
const { toast } = useToast();
const {
@@ -95,11 +63,13 @@ const MyInfo = () => {
onClose: onCloseUpdatePsw,
onOpen: onOpenUpdatePsw
} = useDisclosure();
+ const { isOpen: isOpenOpenai, onClose: onCloseOpenai, onOpen: onOpenOpenai } = useDisclosure();
const {
- isOpen: isOpenStandardModal,
- onClose: onCloseStandardModal,
- onOpen: onOpenStandardModal
+ isOpen: isOpenSubDatasetModal,
+ onClose: onCloseSubDatasetModal,
+ onOpen: onOpenSubDatasetModal
} = useDisclosure();
+
const { File, onOpen: onOpenSelectFile } = useSelectFile({
fileType: '.jpg,.png',
multiple: false
@@ -147,73 +117,81 @@ const MyInfo = () => {
[onclickSave, t, toast, userInfo]
);
+ useQuery(['init'], initUserInfo, {
+ onSuccess(res) {
+ reset(res);
+ }
+ });
+
+ const {
+ data: teamSubPlan = { totalPoints: 0, usedPoints: 0, datasetMaxSize: 800, usedDatasetSize: 0 }
+ } = useQuery(['getTeamDatasetValidSub'], getTeamDatasetValidSub);
+ const datasetUsageMap = useMemo(() => {
+ const rate = teamSubPlan.usedDatasetSize / teamSubPlan.datasetMaxSize;
+
+ const colorScheme = (() => {
+ if (rate < 0.5) return 'green';
+ if (rate < 0.8) return 'yellow';
+ return 'red';
+ })();
+
+ return {
+ colorScheme,
+ value: rate * 100,
+ maxSize: teamSubPlan.datasetMaxSize || t('common.Unlimited'),
+ usedSize: teamSubPlan.usedDatasetSize
+ };
+ }, [teamSubPlan.usedDatasetSize, teamSubPlan.datasetMaxSize, t]);
+
return (
-
- {/* user info */}
- {isPc && (
-
-
- {t('support.user.User self info')}
-
- )}
-
-
- {isPc ? (
-
- {t('support.user.Avatar')}:
-
-
-
-
-
-
-
- ) : (
-
+
+
+
-
-
-
-
-
+
+
+
-
-
- {t('user.Replace')}
-
-
- )}
+
+
+ {t('user.Replace')}
+
+
+
{feConfigs.isPlus && (
-
+
{t('user.Member Name')}:
{
@@ -226,265 +204,109 @@ const MyInfo = () => {
/>
)}
-
+
{t('user.Account')}:
{userInfo?.username}
- {feConfigs.isPlus && (
-
- {t('user.Password')}:
- *****
-
- {t('user.Change')}
-
-
- )}
-
+
{t('user.Team')}:
- {feConfigs.isPlus && (
-
-
-
- {t('user.team.Balance')}:
-
-
- {formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)} 元
-
- {feConfigs?.show_pay && userInfo?.team?.canWrite && (
-
- {t('user.Pay')}
-
- )}
-
-
- )}
-
- {isOpenPayModal && }
- {isOpenUpdatePsw && }
-
-
- );
-};
-const PlanUsage = () => {
- const { isPc } = useSystemStore();
- const router = useRouter();
- const { t } = useTranslation();
- const { userInfo, initUserInfo, teamPlanStatus } = useUserStore();
- const { reset } = useForm({
- defaultValues: userInfo as UserType
- });
-
- const planName = useMemo(() => {
- if (!teamPlanStatus?.standard?.currentSubLevel) return '';
- return standardSubLevelMap[teamPlanStatus.standard.currentSubLevel].label;
- }, [teamPlanStatus?.standard?.currentSubLevel]);
- const standardPlan = teamPlanStatus?.standard;
-
- useQuery(['init'], initUserInfo, {
- onSuccess(res) {
- reset(res);
- }
- });
-
- const datasetUsageMap = useMemo(() => {
- if (!teamPlanStatus) {
- return {
- colorScheme: 'green',
- value: 0,
- maxSize: t('common.Unlimited'),
- usedSize: 0
- };
- }
- const rate = teamPlanStatus.usedDatasetSize / teamPlanStatus.datasetMaxSize;
-
- const colorScheme = (() => {
- if (rate < 0.5) return 'green';
- if (rate < 0.8) return 'yellow';
- return 'red';
- })();
-
- return {
- colorScheme,
- value: rate * 100,
- maxSize: teamPlanStatus.datasetMaxSize || t('common.Unlimited'),
- usedSize: teamPlanStatus.usedDatasetSize
- };
- }, [teamPlanStatus, t]);
- const aiPointsUsageMap = useMemo(() => {
- if (!teamPlanStatus) {
- return {
- colorScheme: 'green',
- value: 0,
- maxSize: t('common.Unlimited'),
- usedSize: 0
- };
- }
-
- const rate = teamPlanStatus.usedPoints / teamPlanStatus.totalPoints;
-
- const colorScheme = (() => {
- if (rate < 0.5) return 'green';
- if (rate < 0.8) return 'yellow';
- return 'red';
- })();
-
- return {
- colorScheme,
- value: rate * 100,
- maxSize: teamPlanStatus.totalPoints || t('common.Unlimited'),
- usedSize: teamPlanStatus.usedPoints
- };
- }, [teamPlanStatus, t]);
-
- return standardPlan ? (
-
-
-
-
- {t('support.wallet.subscription.Team plan and usage')}
-
- router.push(AI_POINT_USAGE_CARD_ROUTE)}
- >
- {t('support.user.Price')}
-
- {/*
- 套餐详情
- */}
-
-
-
+
+ {t('user.Language')}:
-
- {t('support.wallet.subscription.Current plan')}
-
-
- {t(planName)}
-
-
- {t('common.Expired Time')}:
- {formatTime2YMDHM(standardPlan?.expiredTime)}
-
+ ({
+ label: lang.label,
+ value: key
+ }))}
+ onchange={(val: any) => {
+ const lang = val;
+ setLngStore(lang);
+ router.replace(router.basePath, router.asPath, { locale: lang });
+ }}
+ />
- router.push('/price')}>
- {t('support.wallet.subscription.Upgrade plan')}
+
+
+ {t('user.Timezone')}:
+
+
+
+ {t('user.Password')}:
+ *****
+
+ {t('user.Change')}
-
-
-
-
-
-
-
-
-
-
- {t('support.user.team.Dataset usage')}
-
- {datasetUsageMap.usedSize}/{datasetUsageMap.maxSize}
+ {feConfigs.isPlus && (
+ <>
+
+
+
+ {t('user.team.Balance')}:
+
+
+ {formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)} 元
+
+ {feConfigs?.show_pay && userInfo?.team?.canWrite && (
+
+ {t('user.Pay')}
+
+ )}
+
+
+ {feConfigs?.show_pay && (
+
+
+
+ {t('support.user.team.Dataset usage')}: {datasetUsageMap.usedSize}/
+ {datasetUsageMap.maxSize}
+
+ {userInfo?.team?.canWrite && (
+
+ {t('support.wallet.Buy more')}
+
+ )}
+
+
+
+
-
-
-
-
-
-
-
-
-
- {t('support.wallet.subscription.AI points')}
-
- {Math.round(teamPlanStatus.usedPoints)}/{teamPlanStatus.totalPoints}
-
-
-
-
-
-
-
-
-
-
- ) : null;
-};
-const Other = () => {
- const theme = useTheme();
- const { toast } = useToast();
- const { feConfigs, systemVersion } = useSystemStore();
- const { t } = useTranslation();
- const { userInfo, updateUserInfo, initUserInfo, teamPlanStatus } = useUserStore();
- const { reset } = useForm({
- defaultValues: userInfo as UserType
- });
+ )}
+ >
+ )}
- const { isOpen: isOpenOpenai, onClose: onCloseOpenai, onOpen: onOpenOpenai } = useDisclosure();
-
- const onclickSave = useCallback(
- async (data: UserType) => {
- await updateUserInfo({
- avatar: data.avatar,
- timezone: data.timezone,
- openaiAccount: data.openaiAccount
- });
- reset(data);
- toast({
- title: '更新数据成功',
- status: 'success'
- });
- },
- [reset, toast, updateUserInfo]
- );
-
- return (
-
-
{feConfigs?.docUrl && (
{
)}
-
-
-
- {t('common.system.Help Chatbot')}
-
-
-
- {feConfigs?.show_openai_account && (
-
-
+
- OpenAI/OneAPI 账号
+ {t('common.system.Help Chatbot')}
-
-
+
)}
-
+ {feConfigs?.show_openai_account && (
+ <>
+
+
+
+
+
+ OpenAI/OneAPI 账号
+
+
+
+
+ >
+ )}
+
+
+ {isOpenPayModal && }
+ {isOpenUpdatePsw && }
{isOpenOpenai && userInfo && (
{
onClose={onCloseOpenai}
/>
)}
+ {isOpenSubDatasetModal && }
+
);
};
+
+export default React.memo(UserInfo);
diff --git a/projects/app/src/pages/account/components/InfoOld.tsx b/projects/app/src/pages/account/components/InfoOld.tsx
deleted file mode 100644
index 83e16173f..000000000
--- a/projects/app/src/pages/account/components/InfoOld.tsx
+++ /dev/null
@@ -1,439 +0,0 @@
-import React, { useCallback, useMemo, useRef } from 'react';
-import {
- Box,
- Flex,
- Button,
- useDisclosure,
- useTheme,
- Divider,
- Select,
- Input,
- Link,
- Progress
-} from '@chakra-ui/react';
-import { useForm } from 'react-hook-form';
-import { UserUpdateParams } from '@/types/user';
-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 { useSystemStore } from '@/web/common/system/useSystemStore';
-import { useTranslation } from 'next-i18next';
-import { timezoneList } from '@fastgpt/global/common/time/timezone';
-import Avatar from '@/components/Avatar';
-import MyIcon from '@fastgpt/web/components/common/Icon';
-import MyTooltip from '@/components/MyTooltip';
-import { langMap, setLngStore } from '@/web/common/utils/i18n';
-import { useRouter } from 'next/router';
-import MySelect from '@/components/Select';
-import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools';
-import { putUpdateMemberName } from '@/web/support/user/team/api';
-import { getDocPath } from '@/web/common/system/doc';
-import { getTeamPlanStatus } from '@/web/support/wallet/sub/api';
-import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
-
-const TeamMenu = dynamic(() => import('@/components/support/user/team/TeamMenu'));
-const PayModal = dynamic(() => import('./PayModal'));
-const UpdatePswModal = dynamic(() => import('./UpdatePswModal'));
-const OpenAIAccountModal = dynamic(() => import('./OpenAIAccountModal'));
-
-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());
- const { reset } = useForm({
- defaultValues: userInfo as UserType
- });
-
- const { toast } = useToast();
- const {
- isOpen: isOpenPayModal,
- onClose: onClosePayModal,
- onOpen: onOpenPayModal
- } = useDisclosure();
- const {
- isOpen: isOpenUpdatePsw,
- onClose: onCloseUpdatePsw,
- onOpen: onOpenUpdatePsw
- } = useDisclosure();
- const { isOpen: isOpenOpenai, onClose: onCloseOpenai, onOpen: onOpenOpenai } = useDisclosure();
-
- const { File, onOpen: onOpenSelectFile } = useSelectFile({
- fileType: '.jpg,.png',
- multiple: false
- });
-
- const onclickSave = useCallback(
- async (data: UserType) => {
- await updateUserInfo({
- avatar: data.avatar,
- timezone: data.timezone,
- openaiAccount: data.openaiAccount
- });
- reset(data);
- toast({
- title: '更新数据成功',
- status: 'success'
- });
- },
- [reset, toast, updateUserInfo]
- );
-
- const onSelectFile = useCallback(
- async (e: File[]) => {
- const file = e[0];
- if (!file || !userInfo) return;
- try {
- const src = await compressImgFileAndUpload({
- type: MongoImageTypeEnum.userAvatar,
- file,
- maxW: 300,
- maxH: 300
- });
-
- onclickSave({
- ...userInfo,
- avatar: src
- });
- } catch (err: any) {
- toast({
- title: typeof err === 'string' ? err : t('common.error.Select avatar failed'),
- status: 'warning'
- });
- }
- },
- [onclickSave, t, toast, userInfo]
- );
-
- useQuery(['init'], initUserInfo, {
- onSuccess(res) {
- reset(res);
- }
- });
-
- const {
- data: teamSubPlan = {
- totalPoints: 0,
- usedPoints: 0,
- datasetMaxSize: 800,
- usedDatasetSize: 0
- }
- } = useQuery(['getTeamPlanStatus'], getTeamPlanStatus);
- const datasetUsageMap = useMemo(() => {
- const rate = teamSubPlan.usedDatasetSize / teamSubPlan.datasetMaxSize;
-
- const colorScheme = (() => {
- if (rate < 0.5) return 'green';
- if (rate < 0.8) return 'yellow';
- return 'red';
- })();
-
- return {
- colorScheme,
- value: rate * 100,
- maxSize: teamSubPlan.datasetMaxSize || t('common.Unlimited'),
- usedSize: teamSubPlan.usedDatasetSize
- };
- }, [teamSubPlan.usedDatasetSize, teamSubPlan.datasetMaxSize, t]);
- const aiPointsUsageMap = useMemo(() => {
- const rate = teamSubPlan.usedPoints / teamSubPlan.totalPoints;
-
- const colorScheme = (() => {
- if (rate < 0.5) return 'green';
- if (rate < 0.8) return 'yellow';
- return 'red';
- })();
-
- return {
- colorScheme,
- value: rate * 100,
- maxSize: teamSubPlan.totalPoints || t('common.Unlimited'),
- usedSize: teamSubPlan.usedPoints
- };
- }, [teamSubPlan.usedPoints, teamSubPlan.totalPoints, t]);
-
- return (
-
-
-
-
-
-
-
-
-
-
- {t('user.Replace')}
-
-
-
- {feConfigs.isPlus && (
-
- {t('user.Member Name')}:
- {
- const val = e.target.value;
- if (val === userInfo?.team?.memberName) return;
- try {
- putUpdateMemberName(val);
- } catch (error) {}
- }}
- />
-
- )}
-
- {t('user.Account')}:
- {userInfo?.username}
-
-
- {t('user.Team')}:
-
-
-
-
-
- {t('user.Language')}:
-
- ({
- label: lang.label,
- value: key
- }))}
- onchange={(val: any) => {
- const lang = val;
- setLngStore(lang);
- router.replace(router.basePath, router.asPath, { locale: lang });
- }}
- />
-
-
-
- {t('user.Timezone')}:
-
-
-
- {t('user.Password')}:
- *****
-
- {t('user.Change')}
-
-
- {feConfigs.isPlus && (
- <>
-
-
-
- {t('user.team.Balance')}:
-
-
- {formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)} 元
-
- {feConfigs?.show_pay && userInfo?.team?.canWrite && (
-
- {t('user.Pay')}
-
- )}
-
-
- {feConfigs?.show_pay && (
- <>
-
-
-
- {t('support.user.team.Dataset usage')}: {datasetUsageMap.usedSize}/
- {datasetUsageMap.maxSize}
-
- {userInfo?.team?.canWrite && (
- router.push('/price')}>
- {t('support.wallet.Buy more')}
-
- )}
-
-
-
-
-
-
-
-
- AI积分: {Math.round(teamSubPlan.usedPoints)}/{teamSubPlan.totalPoints}
-
-
-
-
-
-
- >
- )}
- >
- )}
-
- {feConfigs?.docUrl && (
-
-
-
- {t('system.Help Document')}
-
-
-
- V{systemVersion}
-
-
- )}
- {feConfigs?.chatbotUrl && (
-
-
-
- {t('common.system.Help Chatbot')}
-
-
- )}
- {feConfigs?.show_openai_account && (
- <>
-
-
-
-
-
-
- OpenAI/OneAPI 账号
-
-
-
-
- >
- )}
-
-
- {isOpenPayModal && }
- {isOpenUpdatePsw && }
- {isOpenOpenai && userInfo && (
-
- onclickSave({
- ...userInfo,
- openaiAccount: data
- })
- }
- onClose={onCloseOpenai}
- />
- )}
-
-
- );
-};
-
-export default React.memo(UserInfo);
diff --git a/projects/app/src/pages/account/components/PayModal.tsx b/projects/app/src/pages/account/components/PayModal.tsx
index cbcb8d23d..a397f409f 100644
--- a/projects/app/src/pages/account/components/PayModal.tsx
+++ b/projects/app/src/pages/account/components/PayModal.tsx
@@ -1,45 +1,37 @@
import React, { useState, useCallback } from 'react';
import { ModalFooter, ModalBody, Button, Input, Box, Grid } from '@chakra-ui/react';
-import { getWxPayQRCode } from '@/web/support/wallet/bill/api';
+import { getPayCode, checkPayResult } from '@/web/support/wallet/pay/api';
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';
import { useTranslation } from 'next-i18next';
+import Markdown from '@/components/Markdown';
import MyModal from '@/components/MyModal';
-import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants';
-import QRCodePayModal, { type QRPayProps } from '@/components/support/wallet/QRCodePayModal';
-
-const PayModal = ({
- onClose,
- defaultValue,
- onSuccess
-}: {
- defaultValue?: number;
- onClose: () => void;
- onSuccess?: () => any;
-}) => {
+const PayModal = ({ onClose }: { onClose: () => void }) => {
const router = useRouter();
const { t } = useTranslation();
const { toast } = useToast();
- const [inputVal, setInputVal] = useState(defaultValue);
+ const [inputVal, setInputVal] = useState('');
const [loading, setLoading] = useState(false);
- const [qrPayData, setQRPayData] = useState();
+ const [payId, setPayId] = useState('');
const handleClickPay = useCallback(async () => {
if (!inputVal || inputVal <= 0 || isNaN(+inputVal)) return;
setLoading(true);
try {
// 获取支付二维码
- const res = await getWxPayQRCode({
- type: BillTypeEnum.balance,
- balance: inputVal
- });
- setQRPayData({
- readPrice: res.readPrice,
- codeUrl: res.codeUrl,
- billId: res.billId
+ const res = await getPayCode(inputVal);
+ new window.QRCode(document.getElementById('payQRCode'), {
+ text: res.codeUrl,
+ width: 128,
+ height: 128,
+ colorDark: '#000000',
+ colorLight: '#ffffff',
+ correctLevel: window.QRCode.CorrectLevel.H
});
+ setPayId(res.payId);
} catch (err) {
toast({
title: getErrText(err),
@@ -49,48 +41,84 @@ const PayModal = ({
setLoading(false);
}, [inputVal, toast]);
+ useQuery(
+ [payId],
+ () => {
+ if (!payId) return null;
+ return checkPayResult(payId);
+ },
+ {
+ enabled: !!payId,
+ refetchInterval: 3000,
+ onSuccess(res) {
+ if (!res) return;
+ toast({
+ title: res,
+ status: 'success'
+ });
+ router.reload();
+ }
+ }
+ );
+
return (
-
+
-
- {[10, 20, 50, 100, 200, 500].map((item) => (
- setInputVal(item)}
- >
- {item}元
-
- ))}
-
-
- {
- setInputVal(Math.floor(+e.target.value));
- }}
- >
+ {!payId && (
+ <>
+
+ {[10, 20, 50, 100, 200, 500].map((item) => (
+ setInputVal(item)}
+ >
+ {item}元
+
+ ))}
+
+
+ {
+ setInputVal(Math.floor(+e.target.value));
+ }}
+ >
+
+ >
+ )}
+ {/* 付费二维码 */}
+
+ {payId && 请微信扫码支付: {inputVal}元,请勿关闭页面}
+
-
- {t('common.Close')}
-
-
- 获取充值二维码
-
+ {!payId && (
+ <>
+
+ {t('common.Close')}
+
+
+ 获取充值二维码
+
+ >
+ )}
-
- {!!qrPayData && }
);
};
diff --git a/projects/app/src/pages/account/components/PayRecordTable.tsx b/projects/app/src/pages/account/components/PayRecordTable.tsx
new file mode 100644
index 000000000..e5567764b
--- /dev/null
+++ b/projects/app/src/pages/account/components/PayRecordTable.tsx
@@ -0,0 +1,108 @@
+import React, { useState, useCallback } from 'react';
+import {
+ Button,
+ Table,
+ Thead,
+ Tbody,
+ Tr,
+ Th,
+ Td,
+ TableContainer,
+ Flex,
+ Box
+} from '@chakra-ui/react';
+import { getPayOrders, checkPayResult } from '@/web/support/wallet/pay/api';
+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 '@fastgpt/web/hooks/useToast';
+import { useLoading } from '@/web/common/hooks/useLoading';
+import MyIcon from '@fastgpt/web/components/common/Icon';
+
+const PayRecordTable = () => {
+ const { Loading, setIsLoading } = useLoading();
+ const [payOrders, setPayOrders] = useState([]);
+ const { toast } = useToast();
+
+ const { isInitialLoading, refetch } = useQuery(['initPayOrder'], getPayOrders, {
+ onSuccess(res) {
+ setPayOrders(res);
+ }
+ });
+
+ const handleRefreshPayOrder = useCallback(
+ async (payId: string) => {
+ setIsLoading(true);
+
+ try {
+ const data = await checkPayResult(payId);
+ toast({
+ title: data,
+ status: 'success'
+ });
+ } catch (error: any) {
+ toast({
+ title: error?.message,
+ status: 'warning'
+ });
+ console.log(error);
+ }
+ try {
+ refetch();
+ } catch (error) {}
+
+ setIsLoading(false);
+ },
+ [refetch, setIsLoading, toast]
+ );
+
+ return (
+
+ {!isInitialLoading && payOrders.length === 0 ? (
+
+
+
+ 无支付记录~
+
+
+ ) : (
+
+
+
+
+ 订单号 |
+ 时间 |
+ 金额 |
+ 状态 |
+ |
+
+
+
+ {payOrders.map((item) => (
+
+ {item.orderId} |
+
+ {item.createTime ? dayjs(item.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'}
+ |
+ {formatStorePrice2Read(item.price)}元 |
+ {item.status} |
+
+ {item.status === 'NOTPAY' && (
+ handleRefreshPayOrder(item._id)} size={'sm'}>
+ 更新
+
+ )}
+ |
+
+ ))}
+
+
+
+ )}
+
+
+ );
+};
+
+export default PayRecordTable;
diff --git a/projects/app/src/pages/account/components/UsageDetail.tsx b/projects/app/src/pages/account/components/UsageDetail.tsx
deleted file mode 100644
index d75cd5c2c..000000000
--- a/projects/app/src/pages/account/components/UsageDetail.tsx
+++ /dev/null
@@ -1,119 +0,0 @@
-import React, { useMemo } from 'react';
-import {
- ModalBody,
- Flex,
- Box,
- Table,
- Thead,
- Tbody,
- Tr,
- Th,
- Td,
- TableContainer
-} from '@chakra-ui/react';
-import { UsageItemType } from '@fastgpt/global/support/wallet/usage/type.d';
-import dayjs from 'dayjs';
-import { UsageSourceMap } from '@fastgpt/global/support/wallet/usage/constants';
-import MyModal from '@/components/MyModal';
-import { useTranslation } from 'next-i18next';
-import { formatNumber } from '@fastgpt/global/common/math/tools';
-
-const UsageDetail = ({ usage, onClose }: { usage: UsageItemType; onClose: () => void }) => {
- const { t } = useTranslation();
- const filterBillList = useMemo(
- () => usage.list.filter((item) => item && item.moduleName),
- [usage.list]
- );
-
- const { hasModel, hasCharsLen, hasDuration } = useMemo(() => {
- let hasModel = false;
- let hasCharsLen = false;
- let hasDuration = false;
- let hasDataLen = false;
-
- usage.list.forEach((item) => {
- if (item.model !== undefined) {
- hasModel = true;
- }
-
- if (typeof item.charsLength === 'number') {
- hasCharsLen = true;
- }
- if (typeof item.duration === 'number') {
- hasDuration = true;
- }
- });
-
- return {
- hasModel,
- hasCharsLen,
- hasDuration,
- hasDataLen
- };
- }, [usage.list]);
-
- return (
-
-
-
- {t('support.wallet.bill.Number')}:
- {usage.id}
-
-
- {t('support.wallet.usage.Time')}:
- {dayjs(usage.time).format('YYYY/MM/DD HH:mm:ss')}
-
-
- {t('support.wallet.usage.App name')}:
- {t(usage.appName) || '-'}
-
-
- {t('support.wallet.usage.Source')}:
- {t(UsageSourceMap[usage.source]?.label)}
-
-
- {t('support.wallet.usage.Total points')}:
- {formatNumber(usage.totalPoints)}
-
-
-
- {t('support.wallet.usage.Bill Module')}
-
-
-
-
-
- {t('support.wallet.usage.Module name')} |
- {hasModel && {t('support.wallet.usage.Ai model')} | }
- {hasCharsLen && {t('support.wallet.usage.Text Length')} | }
- {hasDuration && {t('support.wallet.usage.Duration')} | }
-
- {t('support.wallet.usage.Total points')} |
-
-
-
- {filterBillList.map((item, i) => (
-
- {t(item.moduleName)} |
- {hasModel && {item.model ?? '-'} | }
- {hasCharsLen && {item.charsLength ?? '-'} | }
- {hasDuration && {item.duration ?? '-'} | }
- {formatNumber(item.amount)} |
-
- ))}
-
-
-
-
-
-
- );
-};
-
-export default UsageDetail;
diff --git a/projects/app/src/pages/account/components/UsageTable.tsx b/projects/app/src/pages/account/components/UsageTable.tsx
deleted file mode 100644
index d73f779de..000000000
--- a/projects/app/src/pages/account/components/UsageTable.tsx
+++ /dev/null
@@ -1,189 +0,0 @@
-import React, { useEffect, useMemo, useState } from 'react';
-import {
- Table,
- Thead,
- Tbody,
- Tr,
- Th,
- Td,
- TableContainer,
- Flex,
- Box,
- Button
-} from '@chakra-ui/react';
-import { UsageSourceEnum, UsageSourceMap } from '@fastgpt/global/support/wallet/usage/constants';
-import { getUserUsages } from '@/web/support/wallet/usage/api';
-import type { UsageItemType } from '@fastgpt/global/support/wallet/usage/type';
-import { usePagination } from '@/web/common/hooks/usePagination';
-import { useLoading } from '@/web/common/hooks/useLoading';
-import dayjs from 'dayjs';
-import MyIcon from '@fastgpt/web/components/common/Icon';
-import DateRangePicker, { type DateRangeType } from '@/components/DateRangePicker';
-import { addDays } from 'date-fns';
-import dynamic from 'next/dynamic';
-import { useSystemStore } from '@/web/common/system/useSystemStore';
-import { useTranslation } from 'next-i18next';
-import MySelect from '@/components/Select';
-import { useQuery } from '@tanstack/react-query';
-import { useUserStore } from '@/web/support/user/useUserStore';
-import { getTeamMembers } from '@/web/support/user/team/api';
-import Avatar from '@/components/Avatar';
-import { formatNumber } from '../../../../../../packages/global/common/math/tools';
-const UsageDetail = dynamic(() => import('./UsageDetail'));
-
-const UsageTable = () => {
- const { t } = useTranslation();
- const { Loading } = useLoading();
- const [dateRange, setDateRange] = useState({
- from: addDays(new Date(), -7),
- to: new Date()
- });
- const [usageSource, setUsageSource] = useState<`${UsageSourceEnum}` | ''>('');
- const { isPc } = useSystemStore();
- const { userInfo } = useUserStore();
- const [usageDetail, setUsageDetail] = useState();
-
- const sourceList = useMemo(
- () => [
- { label: t('common.All'), value: '' },
- ...Object.entries(UsageSourceMap).map(([key, value]) => ({
- label: t(value.label),
- value: key
- }))
- ],
- [t]
- );
-
- const [selectTmbId, setSelectTmbId] = useState(userInfo?.team?.tmbId);
- const { data: members = [] } = useQuery(['getMembers', userInfo?.team?.teamId], () => {
- if (!userInfo?.team?.teamId) return [];
- return getTeamMembers(userInfo.team.teamId);
- });
- const tmbList = useMemo(
- () =>
- members.map((item) => ({
- label: (
-
-
- {item.memberName}
-
- ),
- value: item.tmbId
- })),
- [members]
- );
-
- const {
- data: usages,
- isLoading,
- Pagination,
- getData
- } = usePagination({
- api: getUserUsages,
- pageSize: isPc ? 20 : 10,
- params: {
- dateStart: dateRange.from || new Date(),
- dateEnd: addDays(dateRange.to || new Date(), 1),
- source: usageSource,
- teamMemberId: selectTmbId
- },
- defaultRequest: false
- });
-
- useEffect(() => {
- getData(1);
- }, [usageSource, selectTmbId]);
-
- return (
-
-
- {tmbList.length > 1 && userInfo?.team?.canWrite && (
-
-
- {t('support.user.team.member')}
-
-
-
- )}
-
-
- getData(1)}
- />
-
-
-
-
-
-
-
- {/* {t('user.team.Member Name')} | */}
- {t('user.Time')} |
-
- {
- setUsageSource(e);
- }}
- w={'130px'}
- >
- |
- {t('user.Application Name')} |
- {t('support.wallet.usage.Total points')} |
- |
-
-
-
- {usages.map((item) => (
-
- {/* {item.memberName} | */}
- {dayjs(item.time).format('YYYY/MM/DD HH:mm:ss')} |
- {t(UsageSourceMap[item.source]?.label) || '-'} |
- {t(item.appName) || '-'} |
- {formatNumber(item.totalPoints) || 0} |
-
- setUsageDetail(item)}>
- 详情
-
- |
-
- ))}
-
-
-
-
- {!isLoading && usages.length === 0 && (
-
-
-
- 无使用记录~
-
-
- )}
-
-
- {!!usageDetail && (
- setUsageDetail(undefined)} />
- )}
-
- );
-};
-
-export default React.memo(UsageTable);
diff --git a/projects/app/src/pages/account/components/standardDetailModal.tsx b/projects/app/src/pages/account/components/standardDetailModal.tsx
deleted file mode 100644
index 2c313980b..000000000
--- a/projects/app/src/pages/account/components/standardDetailModal.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react';
-import { ModalBody, Box, Flex, Input, ModalFooter, Button } from '@chakra-ui/react';
-import MyModal from '@/components/MyModal';
-import { useTranslation } from 'next-i18next';
-import { useForm } from 'react-hook-form';
-import { useRequest } from '@/web/common/hooks/useRequest';
-import type { UserType } from '@fastgpt/global/support/user/type.d';
-
-const StandDetailModal = ({ onClose }: { onClose: () => void }) => {
- const { t } = useTranslation();
-
- return (
-
-
-
-
- );
-};
-
-export default StandDetailModal;
diff --git a/projects/app/src/pages/account/index.tsx b/projects/app/src/pages/account/index.tsx
index 49ce40a7a..774a41562 100644
--- a/projects/app/src/pages/account/index.tsx
+++ b/projects/app/src/pages/account/index.tsx
@@ -14,16 +14,18 @@ import { useTranslation } from 'next-i18next';
import Script from 'next/script';
const Promotion = dynamic(() => import('./components/Promotion'));
-const UsageTable = dynamic(() => import('./components/UsageTable'));
const BillTable = dynamic(() => import('./components/BillTable'));
+const PayRecordTable = dynamic(() => import('./components/PayRecordTable'));
const InformTable = dynamic(() => import('./components/InformTable'));
const ApiKeyTable = dynamic(() => import('./components/ApiKeyTable'));
+const PriceBox = dynamic(() => import('@/components/support/wallet/Price'));
enum TabEnum {
'info' = 'info',
'promotion' = 'promotion',
- 'usage' = 'usage',
'bill' = 'bill',
+ 'price' = 'price',
+ 'pay' = 'pay',
'inform' = 'inform',
'apikey' = 'apikey',
'loginout' = 'loginout'
@@ -43,18 +45,27 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
...(feConfigs?.isPlus
? [
{
- icon: 'support/usage/usageRecordLight',
+ icon: 'support/bill/billRecordLight',
label: t('user.Usage Record'),
- id: TabEnum.usage
+ id: TabEnum.bill
}
]
: []),
...(feConfigs?.show_pay && userInfo?.team.canWrite
? [
{
- icon: 'support/bill/payRecordLight',
- label: t('support.wallet.Bills'),
- id: TabEnum.bill
+ icon: 'support/pay/payRecordLight',
+ label: t('user.Recharge Record'),
+ id: TabEnum.pay
+ }
+ ]
+ : []),
+ ...(feConfigs?.show_pay
+ ? [
+ {
+ icon: 'support/pay/priceLight',
+ label: t('support.user.Price'),
+ id: TabEnum.price
}
]
: []),
@@ -97,6 +108,11 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
const { openConfirm, ConfirmModal } = useConfirm({
content: '确认退出登录?'
});
+ const {
+ isOpen: isOpenPriceBox,
+ onOpen: onOpenPriceBox,
+ onClose: onClosePriceBox
+ } = useDisclosure();
const router = useRouter();
const theme = useTheme();
@@ -108,6 +124,8 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
setUserInfo(null);
router.replace('/login');
})();
+ } else if (tab === TabEnum.price) {
+ onOpenPriceBox();
} else {
router.replace({
query: {
@@ -116,7 +134,7 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
});
}
},
- [openConfirm, router, setUserInfo]
+ [onOpenPriceBox, openConfirm, router, setUserInfo]
);
return (
@@ -160,14 +178,16 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
{currentTab === TabEnum.info && }
{currentTab === TabEnum.promotion && }
- {currentTab === TabEnum.usage && }
{currentTab === TabEnum.bill && }
+ {currentTab === TabEnum.pay && }
{currentTab === TabEnum.inform && }
{currentTab === TabEnum.apikey && }
+
+ {isOpenPriceBox && }
>
);
};
diff --git a/projects/app/src/pages/api/admin/initv468.ts b/projects/app/src/pages/api/admin/initv468.ts
deleted file mode 100644
index 02caa11f1..000000000
--- a/projects/app/src/pages/api/admin/initv468.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-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 { PgClient } from '@fastgpt/service/common/vectorStore/pg';
-import { PgDatasetTableName } from '@fastgpt/global/common/vectorStore/constants';
-import { MongoImage } from '@fastgpt/service/common/file/image/schema';
-import { MongoImageSchemaType } from '@fastgpt/global/common/file/image/type';
-import { delay } from '@fastgpt/global/common/system/utils';
-import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
-import { getNanoid } from '@fastgpt/global/common/string/tools';
-import { MongoApp } from '@fastgpt/service/core/app/schema';
-import { ModuleItemType } from '@fastgpt/global/core/module/type';
-import { DYNAMIC_INPUT_KEY, ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
-
-let success = 0;
-let deleteImg = 0;
-
-export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- try {
- // 设置所有app为 inited = false
- const result = await MongoApp.updateMany({}, { $set: { inited: false } });
- console.log(result);
-
- await initApp();
-
- jsonRes(res, {
- message: 'success'
- });
- } catch (error) {
- console.log(error);
-
- jsonRes(res, {
- code: 500,
- error
- });
- }
-}
-
-const systemKeys: string[] = [
- ModuleInputKeyEnum.switch,
- ModuleInputKeyEnum.httpMethod,
- ModuleInputKeyEnum.httpReqUrl,
- ModuleInputKeyEnum.httpHeaders,
- DYNAMIC_INPUT_KEY,
- ModuleInputKeyEnum.addInputParam
-];
-const initApp = async (): Promise => {
- const app = await MongoApp.findOne({ inited: false }).sort({ updateTime: -1 });
- if (!app) {
- return;
- }
-
- try {
- const modules = JSON.parse(JSON.stringify(app.modules)) as ModuleItemType[];
- let update = false;
- // 找到http模块
- modules.forEach((module) => {
- if (module.flowType === 'httpRequest') {
- const method = module.inputs.find((input) => input.key === ModuleInputKeyEnum.httpMethod);
- if (method?.value === 'POST') {
- module.inputs.forEach((input) => {
- // 更新非系统字段的key
- if (!systemKeys.includes(input.key)) {
- // 更新output的target
- modules.forEach((item) => {
- item.outputs.forEach((output) => {
- output.targets.forEach((target) => {
- if (target.moduleId === module.moduleId && target.key === input.key) {
- target.key = `data.${input.key}`;
- }
- });
- });
- });
- // 更新key
- input.key = `data.${input.key}`;
- update = true;
- }
- });
- }
- }
- });
-
- if (update) {
- console.log('update http app');
- app.modules = modules;
- }
- app.inited = true;
- await app.save();
-
- console.log(++success);
- return initApp();
- } catch (error) {
- console.log(error);
-
- await delay(1000);
- return initApp();
- }
-};
diff --git a/projects/app/src/pages/api/admin/initv469.ts b/projects/app/src/pages/api/admin/initv469.ts
deleted file mode 100644
index 54bf086ca..000000000
--- a/projects/app/src/pages/api/admin/initv469.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-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 { MongoUsage } from '@fastgpt/service/support/wallet/usage/schema';
-import { connectionMongo } from '@fastgpt/service/common/mongo';
-
-/* pg 中的数据搬到 mongo dataset.datas 中,并做映射 */
-export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- try {
- await connectToDatabase();
- await authCert({ req, authRoot: true });
-
- // 检查 usage 是否有记录
- const totalUsages = await MongoUsage.countDocuments();
- if (totalUsages === 0) {
- // 重命名 bills 集合成 usages
- await connectionMongo.connection.db.renameCollection('bills', 'usages', {
- // 强制
- dropTarget: true
- });
- }
-
- jsonRes(res, {
- message: 'success'
- });
- } catch (error) {
- console.log(error);
-
- jsonRes(res, {
- code: 500,
- error
- });
- }
-}
diff --git a/projects/app/src/pages/api/common/file/upload.ts b/projects/app/src/pages/api/common/file/upload.ts
index efa9b2ad7..3f3d135e5 100644
--- a/projects/app/src/pages/api/common/file/upload.ts
+++ b/projects/app/src/pages/api/common/file/upload.ts
@@ -16,7 +16,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
let filePaths: string[] = [];
try {
- const { teamId, tmbId } = await authCert({ req, authToken: true });
+ const { userId, teamId, tmbId } = await authCert({ req, authToken: true });
const { file, bucketName, metadata } = await upload.doUpload(req, res);
diff --git a/projects/app/src/pages/api/core/ai/agent/createQuestionGuide.ts b/projects/app/src/pages/api/core/ai/agent/createQuestionGuide.ts
index a51329085..722c4983d 100644
--- a/projects/app/src/pages/api/core/ai/agent/createQuestionGuide.ts
+++ b/projects/app/src/pages/api/core/ai/agent/createQuestionGuide.ts
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import type { CreateQuestionGuideParams } from '@/global/core/ai/api.d';
-import { pushQuestionGuideUsage } from '@/service/support/wallet/usage/push';
+import { pushQuestionGuideBill } from '@/service/support/wallet/bill/push';
import { createQuestionGuide } from '@fastgpt/service/core/ai/functions/createQuestionGuide';
import { authCertOrShareId } from '@fastgpt/service/support/permission/auth/common';
@@ -19,7 +19,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const qgModel = global.llmModels[0];
- const { result, charsLength } = await createQuestionGuide({
+ const { result, inputTokens, outputTokens } = await createQuestionGuide({
messages,
model: qgModel.model
});
@@ -28,8 +28,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
data: result
});
- pushQuestionGuideUsage({
- charsLength,
+ pushQuestionGuideBill({
+ inputTokens,
+ outputTokens,
teamId,
tmbId
});
diff --git a/projects/app/src/pages/api/core/app/create.ts b/projects/app/src/pages/api/core/app/create.ts
index dadfbedb7..26e3bfe24 100644
--- a/projects/app/src/pages/api/core/app/create.ts
+++ b/projects/app/src/pages/api/core/app/create.ts
@@ -6,7 +6,6 @@ import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { authUserNotVisitor } from '@fastgpt/service/support/permission/auth/user';
import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constants';
-import { checkTeamAppLimit } from '@/service/support/permission/teamLimit';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
@@ -26,7 +25,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const { teamId, tmbId } = await authUserNotVisitor({ req, authToken: true });
// 上限校验
- await checkTeamAppLimit(teamId);
+ const authCount = await MongoApp.countDocuments({
+ teamId
+ });
+ if (authCount >= 50) {
+ throw new Error('每个团队上限 50 个应用');
+ }
// 创建模型
const response = await MongoApp.create({
diff --git a/projects/app/src/pages/api/core/app/data/totalUsage.ts b/projects/app/src/pages/api/core/app/data/totalUsage.ts
new file mode 100644
index 000000000..137c2edaa
--- /dev/null
+++ b/projects/app/src/pages/api/core/app/data/totalUsage.ts
@@ -0,0 +1,51 @@
+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 { Types } from '@fastgpt/service/common/mongo';
+import { MongoBill } from '@fastgpt/service/support/wallet/bill/schema';
+
+export default async function handler(req: NextApiRequest, res: NextApiResponse) {
+ try {
+ await connectToDatabase();
+ const { appId, start, end } = req.body as { appId: string; start: number; end: number };
+ const { userId } = await authCert({ req, authToken: true });
+
+ const result = await MongoBill.aggregate([
+ {
+ $match: {
+ appId: new Types.ObjectId(appId),
+ userId: new Types.ObjectId(userId),
+ time: { $gte: new Date(start) }
+ }
+ },
+ {
+ $group: {
+ _id: {
+ year: { $year: '$time' },
+ month: { $month: '$time' },
+ day: { $dayOfMonth: '$time' }
+ },
+ total: { $sum: '$total' }
+ }
+ },
+ {
+ $project: {
+ _id: 0,
+ date: { $dateFromParts: { year: '$_id.year', month: '$_id.month', day: '$_id.day' } },
+ total: 1
+ }
+ },
+ { $sort: { date: 1 } }
+ ]);
+
+ jsonRes(res, {
+ data: result
+ });
+ } catch (err) {
+ jsonRes(res, {
+ code: 500,
+ error: err
+ });
+ }
+}
diff --git a/projects/app/src/pages/api/core/app/form2Modules/fastgpt-simple.ts b/projects/app/src/pages/api/core/app/form2Modules/fastgpt-simple.ts
index 320a12b69..3a23b4842 100644
--- a/projects/app/src/pages/api/core/app/form2Modules/fastgpt-simple.ts
+++ b/projects/app/src/pages/api/core/app/form2Modules/fastgpt-simple.ts
@@ -92,7 +92,7 @@ function simpleChatTemplate({ formData, maxToken }: Props): ModuleItemType[] {
},
{
key: 'model',
- type: 'selectLLMModel',
+ type: 'selectChatModel',
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
@@ -471,7 +471,7 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
},
{
key: 'model',
- type: 'selectLLMModel',
+ type: 'selectChatModel',
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
diff --git a/projects/app/src/pages/api/core/app/form2Modules/fastgpt-universal.ts b/projects/app/src/pages/api/core/app/form2Modules/fastgpt-universal.ts
index 9f4c706cb..8b9a18263 100644
--- a/projects/app/src/pages/api/core/app/form2Modules/fastgpt-universal.ts
+++ b/projects/app/src/pages/api/core/app/form2Modules/fastgpt-universal.ts
@@ -88,7 +88,7 @@ function simpleChatTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
},
{
key: 'model',
- type: 'selectLLMModel',
+ type: 'selectChatModel',
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
@@ -498,7 +498,7 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
},
{
key: 'model',
- type: 'selectLLMModel',
+ type: 'selectChatModel',
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
diff --git a/projects/app/src/pages/api/core/app/update.ts b/projects/app/src/pages/api/core/app/update.ts
index 01498ab5f..d8c00fb3f 100644
--- a/projects/app/src/pages/api/core/app/update.ts
+++ b/projects/app/src/pages/api/core/app/update.ts
@@ -12,7 +12,7 @@ import { getLLMModel } from '@/service/core/ai/model';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
await connectToDatabase();
- const { name, avatar, type, simpleTemplateId, intro, modules, permission, teamTags } =
+ const { name, avatar, type, simpleTemplateId, intro, modules, permission } =
req.body as AppUpdateParams;
const { appId } = req.query as { appId: string };
@@ -65,7 +65,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
avatar,
intro,
permission,
- teamTags: teamTags,
...(modules && {
modules
})
diff --git a/projects/app/src/pages/api/core/app/updateTeamTasg.ts b/projects/app/src/pages/api/core/app/updateTeamTasg.ts
deleted file mode 100644
index 8b3a750b9..000000000
--- a/projects/app/src/pages/api/core/app/updateTeamTasg.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-import type { NextApiRequest, NextApiResponse } from 'next';
-import { jsonRes } from '@fastgpt/service/common/response';
-import { connectToDatabase } from '@/service/mongo';
-import { MongoApp } from '@fastgpt/service/core/app/schema';
-import type { AppUpdateParams } from '@fastgpt/global/core/app/api';
-import { authApp } from '@fastgpt/service/support/permission/auth/app';
-import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
-import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
-import { getLLMModel } from '@/service/core/ai/model';
-
-/* 获取我的模型 */
-export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- try {
- await connectToDatabase();
- const { name, avatar, type, simpleTemplateId, intro, modules, permission, teamTags } =
- req.body as AppUpdateParams;
- const { appId } = req.query as { appId: string };
-
- if (!appId) {
- throw new Error('appId is empty');
- }
-
- // 凭证校验
- await authApp({ req, authToken: true, appId, per: permission ? 'owner' : 'w' });
-
- // check modules
- // 1. dataset search limit, less than model quoteMaxToken
- if (modules) {
- let maxTokens = 3000;
-
- modules.forEach((item) => {
- if (item.flowType === FlowNodeTypeEnum.chatNode) {
- const model =
- item.inputs.find((item) => item.key === ModuleInputKeyEnum.aiModel)?.value || '';
- const chatModel = getLLMModel(model);
- const quoteMaxToken = chatModel.quoteMaxToken || 3000;
-
- maxTokens = Math.max(maxTokens, quoteMaxToken);
- }
- });
-
- modules.forEach((item) => {
- if (item.flowType === FlowNodeTypeEnum.datasetSearchNode) {
- item.inputs.forEach((input) => {
- if (input.key === ModuleInputKeyEnum.datasetMaxTokens) {
- const val = input.value as number;
- if (val > maxTokens) {
- input.value = maxTokens;
- }
- }
- });
- }
- });
- }
-
- // 更新模型
- await MongoApp.findOneAndUpdate(
- {
- _id: appId
- },
- {
- name,
- type,
- simpleTemplateId,
- avatar,
- intro,
- permission,
- teamTags: teamTags,
- ...(modules && {
- modules
- })
- }
- );
-
- jsonRes(res);
- } catch (err) {
- jsonRes(res, {
- code: 500,
- error: err
- });
- }
-}
diff --git a/projects/app/src/pages/api/core/chat/chatTest.ts b/projects/app/src/pages/api/core/chat/chatTest.ts
index bee667a46..f9b7aeddc 100644
--- a/projects/app/src/pages/api/core/chat/chatTest.ts
+++ b/projects/app/src/pages/api/core/chat/chatTest.ts
@@ -4,13 +4,13 @@ import { sseErrRes } from '@fastgpt/service/common/response';
import { sseResponseEventEnum } from '@fastgpt/service/common/response/constant';
import { responseWrite } from '@fastgpt/service/common/response';
import type { ModuleItemType } from '@fastgpt/global/core/module/type.d';
-import { pushChatUsage } from '@/service/support/wallet/usage/push';
-import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
+import { pushChatBill } from '@/service/support/wallet/bill/push';
+import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import type { ChatItemType } from '@fastgpt/global/core/chat/type';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { dispatchModules } from '@/service/moduleDispatch';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
-import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
+import { getUserAndAuthBalance } from '@fastgpt/service/support/user/controller';
export type Props = {
history: ChatItemType[];
@@ -50,10 +50,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
]);
// auth balance
- const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
+ const user = await getUserAndAuthBalance({
+ tmbId,
+ minBalance: 0
+ });
/* start process */
- const { responseData, moduleDispatchBills } = await dispatchModules({
+ const { responseData } = await dispatchModules({
res,
mode: 'test',
teamId,
@@ -82,13 +85,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
});
res.end();
- pushChatUsage({
+ pushChatBill({
appName,
appId,
teamId,
tmbId,
- source: UsageSourceEnum.fastgpt,
- moduleDispatchBills
+ source: BillSourceEnum.fastgpt,
+ response: responseData
});
} catch (err: any) {
res.status(500);
diff --git a/projects/app/src/pages/api/core/chat/clearHistories.ts b/projects/app/src/pages/api/core/chat/clearHistories.ts
index 8a5424053..99947245f 100644
--- a/projects/app/src/pages/api/core/chat/clearHistories.ts
+++ b/projects/app/src/pages/api/core/chat/clearHistories.ts
@@ -14,13 +14,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
await connectToDatabase();
const { appId, shareId, outLinkUid } = req.query as ClearHistoriesProps;
- let chatAppId = appId;
-
const match = await (async () => {
if (shareId && outLinkUid) {
- const { appId, uid } = await authOutLink({ shareId, outLinkUid });
+ const { uid } = await authOutLink({ shareId, outLinkUid });
- chatAppId = appId;
return {
shareId,
outLinkUid: uid
@@ -44,11 +41,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const idList = list.map((item) => item.chatId);
await MongoChatItem.deleteMany({
- appId: chatAppId,
+ appId,
chatId: { $in: idList }
});
await MongoChat.deleteMany({
- appId: chatAppId,
+ appId,
chatId: { $in: idList }
});
diff --git a/projects/app/src/pages/api/core/chat/getHistories.ts b/projects/app/src/pages/api/core/chat/getHistories.ts
index 97ca87fc6..c81f8cae6 100644
--- a/projects/app/src/pages/api/core/chat/getHistories.ts
+++ b/projects/app/src/pages/api/core/chat/getHistories.ts
@@ -28,13 +28,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}
};
}
- if (appId && outLinkUid) {
- return {
- shareId,
- outLinkUid: outLinkUid,
- source: ChatSourceEnum.team
- };
- }
if (appId) {
const { tmbId } = await authCert({ req, authToken: true });
return {
@@ -43,7 +36,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
source: ChatSourceEnum.online
};
}
-
return Promise.reject('Params are error');
})();
diff --git a/projects/app/src/pages/api/core/chat/item/getSpeech.ts b/projects/app/src/pages/api/core/chat/item/getSpeech.ts
index eb7db258c..17d9a647b 100644
--- a/projects/app/src/pages/api/core/chat/item/getSpeech.ts
+++ b/projects/app/src/pages/api/core/chat/item/getSpeech.ts
@@ -3,9 +3,9 @@ import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { GetChatSpeechProps } from '@/global/core/chat/api.d';
import { text2Speech } from '@fastgpt/service/core/ai/audio/speech';
-import { pushAudioSpeechUsage } from '@/service/support/wallet/usage/push';
+import { pushAudioSpeechBill } from '@/service/support/wallet/bill/push';
import { authCertOrShareId } from '@fastgpt/service/support/permission/auth/common';
-import { authType2UsageSource } from '@/service/support/wallet/usage/utils';
+import { authType2BillSource } from '@/service/support/wallet/bill/utils';
import { getAudioSpeechModel } from '@/service/core/ai/model';
import { MongoTTSBuffer } from '@fastgpt/service/common/buffer/tts/schema';
@@ -54,12 +54,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
speed: ttsConfig.speed,
onSuccess: async ({ model, buffer }) => {
try {
- pushAudioSpeechUsage({
+ pushAudioSpeechBill({
model: model,
charsLength: input.length,
tmbId,
teamId,
- source: authType2UsageSource({ authType })
+ source: authType2BillSource({ authType })
});
await MongoTTSBuffer.create({
diff --git a/projects/app/src/pages/api/core/chat/outLink/getInforByTeamId.ts b/projects/app/src/pages/api/core/chat/outLink/getInforByTeamId.ts
deleted file mode 100644
index 224d9a074..000000000
--- a/projects/app/src/pages/api/core/chat/outLink/getInforByTeamId.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import type { NextApiRequest, NextApiResponse } from 'next';
-import { jsonRes } from '@fastgpt/service/common/response';
-import { connectToDatabase } from '@/service/mongo';
-import type { chatByTeamProps } from '@/global/core/chat/api.d';
-import axios from 'axios';
-import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
-import { getChatItems } from '@fastgpt/service/core/chat/controller';
-import { selectShareResponse } from '@/utils/service/core/chat';
-export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- try {
- await connectToDatabase();
-
- let { teamId, appId, outLinkUid } = req.query as chatByTeamProps;
-
- const history = await MongoChatItem.find({
- appId: appId,
- outLinkUid: outLinkUid,
- teamId: teamId
- });
-
- jsonRes(res, {
- data: history
- });
- } catch (err) {
- jsonRes(res, {
- code: 500,
- data: req.query,
- error: err
- });
- }
-}
-
-export const config = {
- api: {
- responseLimit: '10mb'
- }
-};
diff --git a/projects/app/src/pages/api/core/chat/team/init.ts b/projects/app/src/pages/api/core/chat/team/init.ts
deleted file mode 100644
index 47b5f0e6f..000000000
--- a/projects/app/src/pages/api/core/chat/team/init.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-import type { NextApiRequest, NextApiResponse } from 'next';
-import { jsonRes } from '@fastgpt/service/common/response';
-import { connectToDatabase } from '@/service/mongo';
-import { getGuideModule } from '@fastgpt/global/core/module/utils';
-import { getChatModelNameListByModules } from '@/service/core/app/module';
-import { ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
-import type { InitChatProps, InitChatResponse } from '@/global/core/chat/api.d';
-import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
-import { MongoApp } from '@fastgpt/service/core/app/schema';
-import { getChatItems } from '@fastgpt/service/core/chat/controller';
-import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
-
-export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- try {
- await connectToDatabase();
-
- let { appId, chatId, outLinkUid } = req.query as {
- chatId?: string;
- appId?: string;
- outLinkUid?: string;
- };
-
- if (!appId) {
- return jsonRes(res, {
- code: 501,
- message: "You don't have an app yet"
- });
- }
-
- // auth app permission
- const [chat, app] = await Promise.all([
- // authApp({
- // req,
- // authToken: false,
- // appId,
- // per: 'r'
- // }),
- chatId ? MongoChat.findOne({ appId, chatId }) : undefined,
- MongoApp.findById(appId).lean()
- ]);
- if (!app) {
- throw new Error(AppErrEnum.unExist);
- }
-
- // auth chat permission
- // if (chat && chat.outLinkUid !== outLinkUid) {
- // throw new Error(ChatErrEnum.unAuthChat);
- // }
- // // auth chat permission
- // if (chat && !app.canWrite && String(tmbId) !== String(chat?.tmbId)) {
- // throw new Error(ChatErrEnum.unAuthChat);
- // }
-
- // get app and history
- const { history } = await getChatItems({
- appId,
- chatId,
- limit: 30,
- field: `dataId obj value adminFeedback userBadFeedback userGoodFeedback ${ModuleOutputKeyEnum.responseData}`
- });
-
- jsonRes(res, {
- data: {
- chatId,
- appId,
- title: chat?.title || '新对话',
- userAvatar: undefined,
- variables: chat?.variables || {},
- history,
- app: {
- userGuideModule: getGuideModule(app.modules),
- chatModels: getChatModelNameListByModules(app.modules),
- name: app.name,
- avatar: app.avatar,
- intro: app.intro
- }
- }
- });
- } catch (err) {
- jsonRes(res, {
- code: 500,
- error: err
- });
- }
-}
-
-export const config = {
- api: {
- responseLimit: '10mb'
- }
-};
diff --git a/projects/app/src/pages/api/core/chat/teamInit.ts b/projects/app/src/pages/api/core/chat/teamInit.ts
deleted file mode 100644
index a3087e15c..000000000
--- a/projects/app/src/pages/api/core/chat/teamInit.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import type { NextApiRequest, NextApiResponse } from 'next';
-import { jsonRes } from '@fastgpt/service/common/response';
-import { connectToDatabase } from '@/service/mongo';
-import { authApp } from '@fastgpt/service/support/permission/auth/app';
-import { getGuideModule } from '@fastgpt/global/core/module/utils';
-import { getChatModelNameListByModules } from '@/service/core/app/module';
-import { ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
-import type { InitChatProps, InitChatResponse } from '@/global/core/chat/api.d';
-import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
-import { getChatItems } from '@fastgpt/service/core/chat/controller';
-import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
-
-export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- try {
- await connectToDatabase();
-
- let { appId, chatId, loadCustomFeedbacks } = req.query as InitChatProps;
-
- if (!appId) {
- return jsonRes(res, {
- code: 501,
- message: "You don't have an app yet"
- });
- }
-
- // auth app permission
- const [{ app, tmbId }, chat] = await Promise.all([
- authApp({
- req,
- authToken: true,
- appId,
- per: 'r'
- }),
- chatId ? MongoChat.findOne({ appId, chatId }) : undefined
- ]);
-
- // // auth chat permission
- // if (chat && !app.canWrite && String(tmbId) !== String(chat?.tmbId)) {
- // throw new Error(ChatErrEnum.unAuthChat);
- // }
-
- // get app and history
- const { history } = await getChatItems({
- appId,
- chatId,
- limit: 30,
- field: `dataId obj value adminFeedback userBadFeedback userGoodFeedback ${
- ModuleOutputKeyEnum.responseData
- } ${loadCustomFeedbacks ? 'customFeedbacks' : ''}`
- });
-
- jsonRes(res, {
- data: {
- chatId,
- appId,
- title: chat?.title || '新对话',
- userAvatar: undefined,
- variables: chat?.variables || {},
- history,
- app: {
- userGuideModule: getGuideModule(app.modules),
- chatModels: getChatModelNameListByModules(app.modules),
- name: app.name,
- avatar: app.avatar,
- intro: app.intro
- }
- }
- });
- } catch (err) {
- jsonRes(res, {
- code: 500,
- error: err
- });
- }
-}
-
-export const config = {
- api: {
- responseLimit: '10mb'
- }
-};
diff --git a/projects/app/src/pages/api/core/chat/updateHistory.ts b/projects/app/src/pages/api/core/chat/updateHistory.ts
index 634604894..634336c9a 100644
--- a/projects/app/src/pages/api/core/chat/updateHistory.ts
+++ b/projects/app/src/pages/api/core/chat/updateHistory.ts
@@ -24,7 +24,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
await MongoChat.findOneAndUpdate(
{ appId, chatId },
{
- updateTime: new Date(),
...(customTitle !== undefined && { customTitle }),
...(top !== undefined && { top })
}
diff --git a/projects/app/src/pages/api/core/dataset/collection/create/link.ts b/projects/app/src/pages/api/core/dataset/collection/create/link.ts
index 317bd3fa5..15f0ac26a 100644
--- a/projects/app/src/pages/api/core/dataset/collection/create/link.ts
+++ b/projects/app/src/pages/api/core/dataset/collection/create/link.ts
@@ -11,12 +11,13 @@ import {
TrainingModeEnum,
DatasetCollectionTypeEnum
} from '@fastgpt/global/core/dataset/constants';
-import { checkDatasetLimit } from '@/service/support/permission/teamLimit';
+import { checkDatasetLimit } from '@fastgpt/service/support/permission/limit/dataset';
import { predictDataLimitLength } from '@fastgpt/global/core/dataset/utils';
-import { createTrainingUsage } from '@fastgpt/service/support/wallet/usage/controller';
-import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
+import { createTrainingBill } from '@fastgpt/service/support/wallet/bill/controller';
+import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
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) {
@@ -42,7 +43,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 1. check dataset limit
await checkDatasetLimit({
teamId,
- insertLen: predictDataLimitLength(trainingType, new Array(10))
+ insertLen: predictDataLimitLength(trainingType, new Array(10)),
+ standardPlans: getStandardSubPlan()
});
const { _id: collectionId } = await mongoSessionRun(async (session) => {
@@ -64,11 +66,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
});
// 3. create bill and start sync
- const { billId } = await createTrainingUsage({
+ const { billId } = await createTrainingBill({
teamId,
tmbId,
appName: 'core.dataset.collection.Sync Collection',
- billSource: UsageSourceEnum.training,
+ billSource: BillSourceEnum.training,
vectorModel: getVectorModel(dataset.vectorModel).name,
agentModel: getLLMModel(dataset.agentModel).name,
session
diff --git a/projects/app/src/pages/api/core/dataset/collection/create/text.ts b/projects/app/src/pages/api/core/dataset/collection/create/text.ts
index 891baf297..b24a1724c 100644
--- a/projects/app/src/pages/api/core/dataset/collection/create/text.ts
+++ b/projects/app/src/pages/api/core/dataset/collection/create/text.ts
@@ -12,13 +12,14 @@ import {
DatasetCollectionTypeEnum
} from '@fastgpt/global/core/dataset/constants';
import { splitText2Chunks } from '@fastgpt/global/common/string/textSplitter';
-import { checkDatasetLimit } from '@/service/support/permission/teamLimit';
+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 { hashStr } from '@fastgpt/global/common/string/tools';
-import { createTrainingUsage } from '@fastgpt/service/support/wallet/usage/controller';
-import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
+import { createTrainingBill } from '@fastgpt/service/support/wallet/bill/controller';
+import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
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) {
try {
@@ -52,7 +53,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 2. check dataset limit
await checkDatasetLimit({
teamId,
- insertLen: predictDataLimitLength(trainingType, chunks)
+ insertLen: predictDataLimitLength(trainingType, chunks),
+ standardPlans: getStandardSubPlan()
});
// 3. create collection and training bill
@@ -72,11 +74,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
hashRawText: hashStr(text),
rawTextLength: text.length
}),
- createTrainingUsage({
+ createTrainingBill({
teamId,
tmbId,
appName: name,
- billSource: UsageSourceEnum.training,
+ billSource: BillSourceEnum.training,
vectorModel: getVectorModel(dataset.vectorModel)?.name,
agentModel: getLLMModel(dataset.agentModel)?.name
})
diff --git a/projects/app/src/pages/api/core/dataset/collection/sync/link.ts b/projects/app/src/pages/api/core/dataset/collection/sync/link.ts
index 0e93e43bd..7c0104c99 100644
--- a/projects/app/src/pages/api/core/dataset/collection/sync/link.ts
+++ b/projects/app/src/pages/api/core/dataset/collection/sync/link.ts
@@ -12,8 +12,8 @@ import {
DatasetCollectionTypeEnum
} from '@fastgpt/global/core/dataset/constants';
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
-import { createTrainingUsage } from '@fastgpt/service/support/wallet/usage/controller';
-import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
+import { createTrainingBill } from '@fastgpt/service/support/wallet/bill/controller';
+import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
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';
@@ -56,11 +56,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await mongoSessionRun(async (session) => {
// create training bill
- const { billId } = await createTrainingUsage({
+ const { billId } = await createTrainingBill({
teamId: collection.teamId,
tmbId,
appName: 'core.dataset.collection.Sync Collection',
- billSource: UsageSourceEnum.training,
+ billSource: BillSourceEnum.training,
vectorModel: vectorModelData.name,
agentModel: agentModelData.name,
session
diff --git a/projects/app/src/pages/api/core/dataset/create.ts b/projects/app/src/pages/api/core/dataset/create.ts
index eef14e167..c1dccb8c1 100644
--- a/projects/app/src/pages/api/core/dataset/create.ts
+++ b/projects/app/src/pages/api/core/dataset/create.ts
@@ -7,7 +7,6 @@ import { createDefaultCollection } from '@fastgpt/service/core/dataset/collectio
import { authUserNotVisitor } from '@fastgpt/service/support/permission/auth/user';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { getLLMModel, getVectorModel, getDatasetModel } from '@/service/core/ai/model';
-import { checkTeamDatasetLimit } from '@/service/support/permission/teamLimit';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
@@ -32,7 +31,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
}
// check limit
- await checkTeamDatasetLimit(teamId);
+ const authCount = await MongoDataset.countDocuments({
+ teamId,
+ type: DatasetTypeEnum.dataset
+ });
+ if (authCount >= 50) {
+ throw new Error('每个团队上限 50 个知识库');
+ }
const { _id } = await MongoDataset.create({
name,
diff --git a/projects/app/src/pages/api/core/dataset/data/delete.ts b/projects/app/src/pages/api/core/dataset/data/delete.ts
index 708f21ada..b945d3e56 100644
--- a/projects/app/src/pages/api/core/dataset/data/delete.ts
+++ b/projects/app/src/pages/api/core/dataset/data/delete.ts
@@ -3,7 +3,8 @@ import { jsonRes } from '@fastgpt/service/common/response';
import { withNextCors } from '@fastgpt/service/common/middle/cors';
import { connectToDatabase } from '@/service/mongo';
import { authDatasetData } from '@/service/support/permission/auth/dataset';
-import { deleteDatasetData } from '@/service/core/dataset/data/controller';
+import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
+import { deleteDatasetDataVector } from '@fastgpt/service/common/vectorStore/controller';
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
@@ -25,7 +26,19 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
per: 'w'
});
- await deleteDatasetData(datasetData);
+ // update mongo data update time
+ await MongoDatasetData.findByIdAndUpdate(dataId, {
+ updateTime: new Date()
+ });
+
+ // delete vector data
+ await deleteDatasetDataVector({
+ teamId,
+ idList: datasetData.indexes.map((item) => item.dataId)
+ });
+
+ // delete mongo data
+ await MongoDatasetData.findByIdAndDelete(dataId);
jsonRes(res, {
data: 'success'
diff --git a/projects/app/src/pages/api/core/dataset/data/insertData.ts b/projects/app/src/pages/api/core/dataset/data/insertData.ts
index 7ca9773ea..a8ec06bf1 100644
--- a/projects/app/src/pages/api/core/dataset/data/insertData.ts
+++ b/projects/app/src/pages/api/core/dataset/data/insertData.ts
@@ -12,10 +12,12 @@ import { hasSameValue } from '@/service/core/dataset/data/utils';
import { insertData2Dataset } from '@/service/core/dataset/data/controller';
import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/dataset';
import { getCollectionWithDataset } from '@fastgpt/service/core/dataset/controller';
-import { pushGenerateVectorUsage } from '@/service/support/wallet/usage/push';
+import { authTeamBalance } from '@/service/support/permission/auth/bill';
+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 '@/service/support/permission/teamLimit';
+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) {
try {
@@ -41,7 +43,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
await checkDatasetLimit({
teamId,
- insertLen: 1
+ insertLen: 1,
+ standardPlans: getStandardSubPlan()
});
// auth collection and get dataset
@@ -49,7 +52,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
{
datasetId: { _id: datasetId, vectorModel }
}
- ] = await Promise.all([getCollectionWithDataset(collectionId)]);
+ ] = await Promise.all([getCollectionWithDataset(collectionId), authTeamBalance(teamId)]);
// format data
const formatQ = simpleText(q);
@@ -87,7 +90,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
indexes: formatIndexes
});
- pushGenerateVectorUsage({
+ pushGenerateVectorBill({
teamId,
tmbId,
charsLength,
diff --git a/projects/app/src/pages/api/core/dataset/data/pushData.ts b/projects/app/src/pages/api/core/dataset/data/pushData.ts
index 476cd4532..8e50ef333 100644
--- a/projects/app/src/pages/api/core/dataset/data/pushData.ts
+++ b/projects/app/src/pages/api/core/dataset/data/pushData.ts
@@ -8,9 +8,10 @@ import type {
PushDatasetDataResponse
} from '@fastgpt/global/core/dataset/api.d';
import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/dataset';
-import { checkDatasetLimit } from '@/service/support/permission/teamLimit';
+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) {
try {
@@ -37,7 +38,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
// auth dataset limit
await checkDatasetLimit({
teamId,
- insertLen: predictDataLimitLength(collection.trainingType, data)
+ insertLen: predictDataLimitLength(collection.trainingType, data),
+ standardPlans: getStandardSubPlan()
});
jsonRes(res, {
diff --git a/projects/app/src/pages/api/core/dataset/data/update.ts b/projects/app/src/pages/api/core/dataset/data/update.ts
index 4cd8f5bfe..7f7102d4b 100644
--- a/projects/app/src/pages/api/core/dataset/data/update.ts
+++ b/projects/app/src/pages/api/core/dataset/data/update.ts
@@ -4,9 +4,9 @@ import { withNextCors } from '@fastgpt/service/common/middle/cors';
import { connectToDatabase } from '@/service/mongo';
import { updateData2Dataset } from '@/service/core/dataset/data/controller';
import { authDatasetData } from '@/service/support/permission/auth/dataset';
-import { pushGenerateVectorUsage } from '@/service/support/wallet/usage/push';
+import { authTeamBalance } from '@/service/support/permission/auth/bill';
+import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
import { UpdateDatasetDataProps } from '@/global/core/dataset/api';
-import { checkDatasetLimit } from '@/service/support/permission/teamLimit';
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
@@ -29,10 +29,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
});
// auth team balance
- await checkDatasetLimit({
- teamId,
- insertLen: 1
- });
+ await authTeamBalance(teamId);
const { charsLength } = await updateData2Dataset({
dataId: id,
@@ -42,7 +39,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
model: vectorModel
});
- pushGenerateVectorUsage({
+ pushGenerateVectorBill({
teamId,
tmbId,
charsLength,
diff --git a/projects/app/src/pages/api/core/dataset/searchTest.ts b/projects/app/src/pages/api/core/dataset/searchTest.ts
index cce91385c..6358ba381 100644
--- a/projects/app/src/pages/api/core/dataset/searchTest.ts
+++ b/projects/app/src/pages/api/core/dataset/searchTest.ts
@@ -4,16 +4,14 @@ import { withNextCors } from '@fastgpt/service/common/middle/cors';
import type { SearchTestProps, SearchTestResponse } from '@/global/core/dataset/api.d';
import { connectToDatabase } from '@/service/mongo';
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
-import { pushGenerateVectorUsage } from '@/service/support/wallet/usage/push';
+import { authTeamBalance } from '@/service/support/permission/auth/bill';
+import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
import { searchDatasetData } from '@/service/core/dataset/data/controller';
import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
-import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
+import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import { getLLMModel } from '@/service/core/ai/model';
+import { queryExtension } from '@fastgpt/service/core/ai/functions/queryExtension';
import { datasetSearchQueryExtension } from '@fastgpt/service/core/dataset/search/utils';
-import {
- checkTeamAIPoints,
- checkTeamReRankPermission
-} from '@/service/support/permission/teamLimit';
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
@@ -45,7 +43,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
per: 'r'
});
// auth balance
- await checkTeamAIPoints(teamId);
+ await authTeamBalance(teamId);
// query extension
const extensionModel =
@@ -67,27 +65,28 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
similarity,
datasetIds: [datasetId],
searchMode,
- usingReRank: usingReRank && (await checkTeamReRankPermission(teamId))
+ usingReRank
});
// push bill
- const { totalPoints } = pushGenerateVectorUsage({
+ const { total } = pushGenerateVectorBill({
teamId,
tmbId,
charsLength,
model: dataset.vectorModel,
- source: apikey ? UsageSourceEnum.api : UsageSourceEnum.fastgpt,
+ source: apikey ? BillSourceEnum.api : BillSourceEnum.fastgpt,
...(aiExtensionResult &&
extensionModel && {
extensionModel: extensionModel.name,
- extensionCharsLength: aiExtensionResult.charsLength
+ extensionInputTokens: aiExtensionResult.inputTokens,
+ extensionOutputTokens: aiExtensionResult.outputTokens
})
});
if (apikey) {
updateApiKeyUsage({
apikey,
- totalPoints: totalPoints
+ usage: total
});
}
diff --git a/projects/app/src/pages/api/core/plugin/create.ts b/projects/app/src/pages/api/core/plugin/create.ts
index b5fe5c26d..c0f4ab035 100644
--- a/projects/app/src/pages/api/core/plugin/create.ts
+++ b/projects/app/src/pages/api/core/plugin/create.ts
@@ -4,7 +4,6 @@ import { connectToDatabase } from '@/service/mongo';
import type { CreateOnePluginParams } from '@fastgpt/global/core/plugin/controller';
import { authUserNotVisitor } from '@fastgpt/service/support/permission/auth/user';
import { MongoPlugin } from '@fastgpt/service/core/plugin/schema';
-import { checkTeamPluginLimit } from '@/service/support/permission/teamLimit';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
@@ -12,8 +11,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const { teamId, tmbId } = await authUserNotVisitor({ req, authToken: true });
const body = req.body as CreateOnePluginParams;
- await checkTeamPluginLimit(teamId);
-
const { _id } = await MongoPlugin.create({
...body,
teamId,
diff --git a/projects/app/src/pages/api/plugins/textEditor/index.ts b/projects/app/src/pages/api/plugins/textEditor/index.ts
index 35ad8de80..c7aa2c06a 100644
--- a/projects/app/src/pages/api/plugins/textEditor/index.ts
+++ b/projects/app/src/pages/api/plugins/textEditor/index.ts
@@ -34,6 +34,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
});
const textResult = replaceVariable(text, obj);
+
res.json({
text: textResult
});
diff --git a/projects/app/src/pages/api/support/user/account/update.ts b/projects/app/src/pages/api/support/user/account/update.ts
index af55c441d..7b29daad3 100644
--- a/projects/app/src/pages/api/support/user/account/update.ts
+++ b/projects/app/src/pages/api/support/user/account/update.ts
@@ -5,7 +5,6 @@ import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { UserUpdateParams } from '@/types/user';
import { getAIApi, openaiBaseUrl } from '@fastgpt/service/core/ai/config';
import { connectToDatabase } from '@/service/mongo';
-import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
/* update user info */
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
@@ -13,12 +12,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await connectToDatabase();
const { avatar, timezone, openaiAccount } = req.body as UserUpdateParams;
- const { tmbId } = await authCert({ req, authToken: true });
- const tmb = await MongoTeamMember.findById(tmbId);
- if (!tmb) {
- throw new Error('can not find it');
- }
- const userId = tmb.userId;
+ const { userId } = await authCert({ req, authToken: true });
+
// auth key
if (openaiAccount?.key) {
console.log('auth user openai key', openaiAccount?.key);
diff --git a/projects/app/src/pages/api/support/user/account/updatePasswordByOld.ts b/projects/app/src/pages/api/support/user/account/updatePasswordByOld.ts
index 86712d749..ad4eec2bf 100644
--- a/projects/app/src/pages/api/support/user/account/updatePasswordByOld.ts
+++ b/projects/app/src/pages/api/support/user/account/updatePasswordByOld.ts
@@ -3,7 +3,6 @@ import { jsonRes } from '@fastgpt/service/common/response';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoUser } from '@fastgpt/service/support/user/schema';
import { connectToDatabase } from '@/service/mongo';
-import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
@@ -14,12 +13,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
throw new Error('Params is missing');
}
- const { tmbId } = await authCert({ req, authToken: true });
- const tmb = await MongoTeamMember.findById(tmbId);
- if (!tmb) {
- throw new Error('can not find it');
- }
- const userId = tmb.userId;
+ const { userId } = await authCert({ req, authToken: true });
+
// auth old password
const user = await MongoUser.findOne({
_id: userId,
diff --git a/projects/app/src/pages/api/support/user/team/limit/datasetSizeLimit.ts b/projects/app/src/pages/api/support/user/team/limit/datasetSizeLimit.ts
index e7f9856f2..4d22ffec3 100644
--- a/projects/app/src/pages/api/support/user/team/limit/datasetSizeLimit.ts
+++ b/projects/app/src/pages/api/support/user/team/limit/datasetSizeLimit.ts
@@ -2,7 +2,8 @@ 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 { checkDatasetLimit } from '@/service/support/permission/teamLimit';
+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) {
try {
@@ -22,7 +23,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await checkDatasetLimit({
teamId,
- insertLen: numberSize
+ insertLen: numberSize,
+ standardPlans: getStandardSubPlan()
});
jsonRes(res);
diff --git a/projects/app/src/pages/api/support/wallet/usage/createTrainingUsage.ts b/projects/app/src/pages/api/support/wallet/bill/createTrainingBill.ts
similarity index 68%
rename from projects/app/src/pages/api/support/wallet/usage/createTrainingUsage.ts
rename to projects/app/src/pages/api/support/wallet/bill/createTrainingBill.ts
index 2cbc3d63b..fec583d69 100644
--- a/projects/app/src/pages/api/support/wallet/usage/createTrainingUsage.ts
+++ b/projects/app/src/pages/api/support/wallet/bill/createTrainingBill.ts
@@ -1,16 +1,16 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
-import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
-import { CreateTrainingUsageProps } from '@fastgpt/global/support/wallet/usage/api.d';
+import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
+import { CreateTrainingBillProps } from '@fastgpt/global/support/wallet/bill/api.d';
import { getLLMModel, getVectorModel } from '@/service/core/ai/model';
-import { createTrainingUsage } from '@fastgpt/service/support/wallet/usage/controller';
+import { createTrainingBill } from '@fastgpt/service/support/wallet/bill/controller';
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
await connectToDatabase();
- const { name, datasetId } = req.body as CreateTrainingUsageProps;
+ const { name, datasetId } = req.body as CreateTrainingBillProps;
const { teamId, tmbId, dataset } = await authDataset({
req,
@@ -20,11 +20,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
per: 'w'
});
- const { billId } = await createTrainingUsage({
+ const { billId } = await createTrainingBill({
teamId,
tmbId,
appName: name,
- billSource: UsageSourceEnum.training,
+ billSource: BillSourceEnum.training,
vectorModel: getVectorModel(dataset.vectorModel).name,
agentModel: getLLMModel(dataset.agentModel).name
});
diff --git a/projects/app/src/pages/api/support/wallet/sub/getTeamSubStatus.ts b/projects/app/src/pages/api/support/wallet/sub/getTeamSubStatus.ts
index 074bedf7e..83eb283fd 100644
--- a/projects/app/src/pages/api/support/wallet/sub/getTeamSubStatus.ts
+++ b/projects/app/src/pages/api/support/wallet/sub/getTeamSubStatus.ts
@@ -2,21 +2,22 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
-import { getTeamSubPlans } from '@fastgpt/service/support/wallet/sub/utils';
+import { getTeamSubPlanStatus } from '@fastgpt/service/support/wallet/sub/utils';
import { getStandardSubPlan } from '@/service/support/wallet/sub/utils';
-import { FeTeamPlanStatusType } from '@fastgpt/global/support/wallet/sub/type';
+import { FeTeamSubType } from '@fastgpt/global/support/wallet/sub/type';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
await connectToDatabase();
+ // 凭证校验
const { teamId } = await authCert({
req,
authToken: true
});
- jsonRes(res, {
- data: await getTeamSubPlans({
+ jsonRes(res, {
+ data: await getTeamSubPlanStatus({
teamId,
standardPlans: getStandardSubPlan()
})
diff --git a/projects/app/src/pages/api/v1/audio/transcriptions.ts b/projects/app/src/pages/api/v1/audio/transcriptions.ts
index 1c6997d51..189ab13c4 100644
--- a/projects/app/src/pages/api/v1/audio/transcriptions.ts
+++ b/projects/app/src/pages/api/v1/audio/transcriptions.ts
@@ -6,7 +6,7 @@ import { getUploadModel } from '@fastgpt/service/common/file/multer';
import { removeFilesByPaths } from '@fastgpt/service/common/file/utils';
import fs from 'fs';
import { getAIApi } from '@fastgpt/service/core/ai/config';
-import { pushWhisperUsage } from '@/service/support/wallet/usage/push';
+import { pushWhisperBill } from '@/service/support/wallet/bill/push';
const upload = getUploadModel({
maxSize: 2
@@ -40,7 +40,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
model: global.whisperModel.model
});
- pushWhisperUsage({
+ pushWhisperBill({
teamId,
tmbId,
duration
diff --git a/projects/app/src/pages/api/v1/chat/completions.ts b/projects/app/src/pages/api/v1/chat/completions.ts
index 9f06f9bd3..f703072ab 100644
--- a/projects/app/src/pages/api/v1/chat/completions.ts
+++ b/projects/app/src/pages/api/v1/chat/completions.ts
@@ -13,16 +13,16 @@ import { gptMessage2ChatType, textAdaptGptResponse } from '@/utils/adapt';
import { getChatItems } from '@fastgpt/service/core/chat/controller';
import { saveChat } from '@/service/utils/chat/saveChat';
import { responseWrite } from '@fastgpt/service/common/response';
-import { pushChatUsage } from '@/service/support/wallet/usage/push';
+import { pushChatBill } from '@/service/support/wallet/bill/push';
import { authOutLinkChatStart } from '@/service/support/permission/auth/outLink';
-import { pushResult2Remote, addOutLinkUsage } from '@fastgpt/service/support/outLink/tools';
+import { pushResult2Remote, updateOutLinkUsage } from '@fastgpt/service/support/outLink/tools';
import requestIp from 'request-ip';
-import { getUsageSourceByAuthType } from '@fastgpt/global/support/wallet/usage/tools';
+import { getBillSourceByAuthType } from '@fastgpt/global/support/wallet/bill/tools';
import { selectShareResponse } from '@/utils/service/core/chat';
import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
import { connectToDatabase } from '@/service/mongo';
-import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
+import { getUserAndAuthBalance } from '@fastgpt/service/support/user/controller';
import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { autChatCrud } from '@/service/support/permission/auth/chat';
@@ -35,14 +35,9 @@ type FastGptShareChatProps = {
shareId?: string;
outLinkUid?: string;
};
-type FastGptTeamShareChatProps = {
- teamId?: string;
- outLinkUid?: string;
-};
export type Props = ChatCompletionCreateParams &
FastGptWebChatProps &
- FastGptShareChatProps &
- FastGptTeamShareChatProps & {
+ FastGptShareChatProps & {
messages: ChatMessageItemType[];
stream?: boolean;
detail?: boolean;
@@ -65,7 +60,6 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
const {
chatId,
appId,
- teamId,
shareId,
outLinkUid,
stream = false,
@@ -103,96 +97,90 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
}
/* auth app permission */
- const { teamId, tmbId, user, app, responseDetail, authType, apikey, canWrite, outLinkUserId } =
- await (async () => {
- if (shareId && outLinkUid) {
- const { teamId, tmbId, user, appId, authType, responseDetail, uid } =
- await authOutLinkChatStart({
- shareId,
- ip: originIp,
- outLinkUid,
- question: question.value
- });
- const app = await MongoApp.findById(appId);
-
- if (!app) {
- return Promise.reject('app is empty');
- }
-
- return {
- teamId,
- tmbId,
- user,
- app,
- responseDetail,
- apikey: '',
- authType,
- canWrite: false,
- outLinkUserId: uid
- };
- }
-
- const {
- appId: apiKeyAppId,
- teamId,
- tmbId,
- authType,
- apikey
- } = await authCert({
- req,
- authToken: true,
- authApiKey: true
+ const { user, app, responseDetail, authType, apikey, canWrite, uid } = await (async () => {
+ if (shareId && outLinkUid) {
+ const { user, appId, authType, responseDetail, uid } = await authOutLinkChatStart({
+ shareId,
+ ip: originIp,
+ outLinkUid,
+ question: question.value
});
+ const app = await MongoApp.findById(appId);
- const user = await getUserChatInfoAndAuthTeamPoints(tmbId);
-
- // openapi key
- if (authType === AuthUserTypeEnum.apikey) {
- if (!apiKeyAppId) {
- return Promise.reject(
- 'Key is error. You need to use the app key rather than the account key.'
- );
- }
- const app = await MongoApp.findById(apiKeyAppId);
-
- if (!app) {
- return Promise.reject('app is empty');
- }
-
- return {
- teamId,
- tmbId,
- user,
- app,
- responseDetail: detail,
- apikey,
- authType,
- canWrite: true
- };
+ if (!app) {
+ return Promise.reject('app is empty');
+ }
+
+ return {
+ user,
+ app,
+ responseDetail,
+ apikey: '',
+ authType,
+ canWrite: false,
+ uid
+ };
+ }
+
+ const {
+ appId: apiKeyAppId,
+ tmbId,
+ authType,
+ apikey
+ } = await authCert({
+ req,
+ authToken: true,
+ authApiKey: true
+ });
+
+ const user = await getUserAndAuthBalance({
+ tmbId,
+ minBalance: 0
+ });
+
+ // openapi key
+ if (authType === AuthUserTypeEnum.apikey) {
+ if (!apiKeyAppId) {
+ return Promise.reject(
+ 'Key is error. You need to use the app key rather than the account key.'
+ );
+ }
+ const app = await MongoApp.findById(apiKeyAppId);
+
+ if (!app) {
+ return Promise.reject('app is empty');
}
- // token auth
- if (!appId) {
- return Promise.reject('appId is empty');
- }
- const { app, canWrite } = await authApp({
- req,
- authToken: true,
- appId,
- per: 'r'
- });
-
return {
- teamId,
- tmbId,
user,
app,
responseDetail: detail,
apikey,
authType,
- canWrite: canWrite || false
+ canWrite: true
};
- })();
+ }
+
+ // token auth
+ if (!appId) {
+ return Promise.reject('appId is empty');
+ }
+ const { app, canWrite } = await authApp({
+ req,
+ authToken: true,
+ appId,
+ per: 'r'
+ });
+
+ return {
+ user,
+ app,
+ responseDetail: detail,
+ apikey,
+ authType,
+ canWrite: canWrite || false
+ };
+ })();
// auth chat permission
await autChatCrud({
@@ -213,17 +201,16 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
limit: 30,
field: `dataId obj value`
});
-
const concatHistories = history.concat(chatMessages);
const responseChatItemId: string | undefined = messages[messages.length - 1].dataId;
/* start flow controller */
- const { responseData, moduleDispatchBills, answerText } = await dispatchModules({
+ const { responseData, answerText } = await dispatchModules({
res,
mode: 'chat',
user,
- teamId: String(teamId),
- tmbId: String(tmbId),
+ teamId: String(user.team.teamId),
+ tmbId: String(user.team.tmbId),
appId: String(app._id),
chatId,
responseChatItemId,
@@ -236,19 +223,18 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
stream,
detail
});
- console.log('af');
// save chat
if (chatId) {
await saveChat({
chatId,
appId: app._id,
- teamId: teamId,
- tmbId: tmbId,
+ teamId: user.team.teamId,
+ tmbId: user.team.tmbId,
variables,
- updateUseTime: !shareId && String(tmbId) === String(app.tmbId), // owner update use time
+ updateUseTime: !shareId && String(user.team.tmbId) === String(app.tmbId), // owner update use time
shareId,
- outLinkUid: outLinkUserId,
+ outLinkUid: uid,
source: (() => {
if (shareId) {
return ChatSourceEnum.share;
@@ -319,29 +305,29 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
}
// add record
- const { totalPoints } = pushChatUsage({
+ const { total } = pushChatBill({
appName: app.name,
appId: app._id,
- teamId: teamId,
- tmbId: tmbId,
- source: getUsageSourceByAuthType({ shareId, authType }),
- moduleDispatchBills
+ teamId: user.team.teamId,
+ tmbId: user.team.tmbId,
+ source: getBillSourceByAuthType({ shareId, authType }),
+ response: responseData
});
if (shareId) {
- pushResult2Remote({ outLinkUid, shareId, appName: app.name, responseData });
- addOutLinkUsage({
+ pushResult2Remote({ outLinkUid, shareId, responseData });
+ updateOutLinkUsage({
shareId,
- totalPoints
+ total
});
}
if (apikey) {
updateApiKeyUsage({
apikey,
- totalPoints
+ usage: total
});
}
- } catch (err) {
+ } catch (err: any) {
if (stream) {
sseErrRes(res, err);
res.end();
diff --git a/projects/app/src/pages/api/v1/embeddings.ts b/projects/app/src/pages/api/v1/embeddings.ts
index 3f82ecf87..a363ecb78 100644
--- a/projects/app/src/pages/api/v1/embeddings.ts
+++ b/projects/app/src/pages/api/v1/embeddings.ts
@@ -2,13 +2,13 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { withNextCors } from '@fastgpt/service/common/middle/cors';
-import { pushGenerateVectorUsage } from '@/service/support/wallet/usage/push';
+import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
import { connectToDatabase } from '@/service/mongo';
+import { authTeamBalance } from '@/service/support/permission/auth/bill';
import { getVectorsByText } from '@fastgpt/service/core/ai/embedding';
import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
-import { getUsageSourceByAuthType } from '@fastgpt/global/support/wallet/usage/tools';
+import { getBillSourceByAuthType } from '@fastgpt/global/support/wallet/bill/tools';
import { getVectorModel } from '@/service/core/ai/model';
-import { checkTeamAIPoints } from '@/service/support/permission/teamLimit';
type Props = {
input: string | string[];
@@ -34,7 +34,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
authApiKey: true
});
- await checkTeamAIPoints(teamId);
+ await authTeamBalance(teamId);
const { charsLength, vectors } = await getVectorsByText({
input: query,
@@ -55,19 +55,19 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
}
});
- const { totalPoints } = pushGenerateVectorUsage({
+ const { total } = pushGenerateVectorBill({
teamId,
tmbId,
charsLength,
model,
billId,
- source: getUsageSourceByAuthType({ authType })
+ source: getBillSourceByAuthType({ authType })
});
if (apikey) {
updateApiKeyUsage({
apikey,
- totalPoints: totalPoints
+ usage: total
});
}
} catch (err) {
diff --git a/projects/app/src/pages/api/v1/rerank.ts b/projects/app/src/pages/api/v1/rerank.ts
new file mode 100644
index 000000000..c73ab0b6c
--- /dev/null
+++ b/projects/app/src/pages/api/v1/rerank.ts
@@ -0,0 +1,50 @@
+import type { NextApiRequest, NextApiResponse } from 'next';
+import { jsonRes } from '@fastgpt/service/common/response';
+import { authCert } from '@fastgpt/service/support/permission/auth/common';
+import { withNextCors } from '@fastgpt/service/common/middle/cors';
+import { pushReRankBill } from '@/service/support/wallet/bill/push';
+import { connectToDatabase } from '@/service/mongo';
+import { authTeamBalance } from '@/service/support/permission/auth/bill';
+import { PostReRankProps, PostReRankResponse } from '@fastgpt/global/core/ai/api';
+import { reRankRecall } from '@/service/core/ai/rerank';
+import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
+
+export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse) {
+ let { query, inputs } = req.body as PostReRankProps;
+ try {
+ await connectToDatabase();
+ const { teamId, tmbId, apikey } = await authCert({
+ req,
+ authApiKey: true
+ });
+ await authTeamBalance(teamId);
+
+ // max 150 length
+ inputs = inputs.slice(0, 150);
+
+ const result = await reRankRecall({ query, inputs });
+
+ const { total } = pushReRankBill({
+ teamId,
+ tmbId,
+ source: 'api',
+ inputs
+ });
+
+ if (apikey) {
+ updateApiKeyUsage({
+ apikey,
+ usage: total
+ });
+ }
+
+ jsonRes(res, {
+ data: result
+ });
+ } catch (err) {
+ jsonRes(res, {
+ code: 500,
+ error: err
+ });
+ }
+});
diff --git a/projects/app/src/pages/app/detail/components/Charts/TotalUsage.tsx b/projects/app/src/pages/app/detail/components/Charts/TotalUsage.tsx
new file mode 100644
index 000000000..8822483ef
--- /dev/null
+++ b/projects/app/src/pages/app/detail/components/Charts/TotalUsage.tsx
@@ -0,0 +1,201 @@
+import React, { useEffect, useMemo, useRef } from 'react';
+import * as echarts from 'echarts';
+import { useSystemStore } from '@/web/common/system/useSystemStore';
+import { getAppTotalUsage } from '@/web/core/app/api';
+import { useQuery } from '@tanstack/react-query';
+import dayjs from 'dayjs';
+import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
+import Loading from '@/components/Loading';
+import { Box } from '@chakra-ui/react';
+
+const map = {
+ blue: {
+ backgroundColor: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ {
+ offset: 0,
+ color: 'rgba(3, 190, 232, 0.42)' // 0% 处的颜色
+ },
+ {
+ offset: 1,
+ color: 'rgba(0, 182, 240, 0)'
+ }
+ ],
+ global: false // 缺省为 false
+ },
+ lineColor: '#36ADEF'
+ },
+ deepBlue: {
+ backgroundColor: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ {
+ offset: 0,
+ color: 'rgba(47, 112, 237, 0.42)' // 0% 处的颜色
+ },
+ {
+ offset: 1,
+ color: 'rgba(94, 159, 235, 0)'
+ }
+ ],
+ global: false
+ },
+ lineColor: '#3293EC'
+ },
+ purple: {
+ backgroundColor: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ {
+ offset: 0,
+ color: 'rgba(211, 190, 255, 0.42)' // 0% 处的颜色
+ },
+ {
+ offset: 1,
+ color: 'rgba(52, 60, 255, 0)'
+ }
+ ],
+ global: false // 缺省为 false
+ },
+ lineColor: '#8172D8'
+ },
+ green: {
+ backgroundColor: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ {
+ offset: 0,
+ color: 'rgba(4, 209, 148, 0.42)' // 0% 处的颜色
+ },
+ {
+ offset: 1,
+ color: 'rgba(19, 217, 181, 0)'
+ }
+ ],
+ global: false // 缺省为 false
+ },
+ lineColor: '#00A9A6',
+ max: 100
+ }
+};
+
+const TokenUsage = ({ appId }: { appId: string }) => {
+ const { screenWidth } = useSystemStore();
+
+ const Dom = useRef(null);
+ const myChart = useRef();
+ const { data = [] } = useQuery(['init'], () => getAppTotalUsage({ appId }));
+
+ const option = useMemo(
+ () => ({
+ xAxis: {
+ type: 'category',
+ show: false,
+ boundaryGap: false,
+ data: data.map((item) => item.date)
+ },
+ yAxis: {
+ type: 'value',
+ splitNumber: 3,
+ min: 0
+ },
+ grid: {
+ show: false,
+ left: 5,
+ right: 5,
+ top: 0,
+ bottom: 5
+ },
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'line'
+ },
+ formatter: (e: any[]) => {
+ const data = e[0];
+ if (!data) return '';
+
+ return `
+
+ ${dayjs(data.axisValue).format('YYYY/MM/DD')}
+ ${formatStorePrice2Read(e[0]?.value || 0)}元
+
+`;
+ }
+ },
+ series: [
+ {
+ data: data.map((item) => item.total),
+ type: 'line',
+ showSymbol: true,
+ animationDuration: 1000,
+ animationEasingUpdate: 'linear',
+ areaStyle: {
+ color: map['blue'].backgroundColor
+ },
+ lineStyle: {
+ width: '1',
+ color: map['blue'].lineColor
+ },
+ itemStyle: {
+ width: 1.5,
+ color: map['blue'].lineColor
+ },
+ emphasis: {
+ // highlight
+ disabled: true
+ }
+ }
+ ]
+ }),
+ [data]
+ );
+
+ // init chart
+ useEffect(() => {
+ if (!Dom.current || myChart?.current?.getOption()) return;
+ myChart.current = echarts.init(Dom.current);
+ myChart.current && myChart.current.setOption(option);
+
+ setTimeout(() => {
+ myChart.current?.resize();
+ }, 500);
+ }, []);
+
+ // data changed, update
+ useEffect(() => {
+ if (!myChart.current || !myChart?.current?.getOption()) return;
+ myChart.current.setOption(option);
+ }, [data, option]);
+
+ // resize chart
+ useEffect(() => {
+ if (!myChart.current || !myChart.current.getOption()) return;
+ myChart.current.resize();
+ }, [screenWidth]);
+
+ return (
+
+
+
+ );
+};
+
+export default React.memo(TokenUsage);
diff --git a/projects/app/src/pages/app/detail/components/OutLink/Share.tsx b/projects/app/src/pages/app/detail/components/OutLink/Share.tsx
index 048028f33..ee7980ea3 100644
--- a/projects/app/src/pages/app/detail/components/OutLink/Share.tsx
+++ b/projects/app/src/pages/app/detail/components/OutLink/Share.tsx
@@ -36,6 +36,7 @@ import { useForm } from 'react-hook-form';
import { defaultOutLinkForm } from '@/constants/app';
import type { OutLinkEditType, OutLinkSchema } from '@fastgpt/global/support/outLink/type.d';
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 '@fastgpt/web/hooks/useToast';
@@ -93,7 +94,7 @@ const Share = ({ appId }: { appId: string }) => {
{t('common.Name')} |
- {t('support.outlink.Usage points')} |
+ {t('common.Price used')} |
{t('core.app.share.Is response quote')} |
{feConfigs?.isPlus && (
<>
@@ -111,11 +112,11 @@ const Share = ({ appId }: { appId: string }) => {
{item.name} |
- {Math.round(item.usagePoints)}
+ {formatStorePrice2Read(item.total)}
{feConfigs?.isPlus
? `${
- item.limit?.maxUsagePoints && item.limit.maxUsagePoints > -1
- ? ` / ${item.limit.maxUsagePoints}`
+ item.limit && item.limit.credit > -1
+ ? ` / ¥${item.limit.credit}`
: ` / ${t('common.Unlimited')}`
}`
: ''}
@@ -314,15 +315,15 @@ function EditLinkModal({
- {t('support.outlink.Max usage points')}
-
+ {t('common.Max credit')}
+
import('../InfoModal'));
const AppCard = ({ appId }: { appId: string }) => {
@@ -22,7 +20,6 @@ const AppCard = ({ appId }: { appId: string }) => {
const { toast } = useToast();
const { appDetail } = useAppStore();
const [settingAppInfo, setSettingAppInfo] = useState();
- const [TeamTagsSet, setTeamTagsSet] = useState();
const { openConfirm: openConfirmDel, ConfirmModal: ConfirmDelModal } = useConfirm({
content: t('app.Confirm Del App Tip')
@@ -126,17 +123,6 @@ const AppCard = ({ appId }: { appId: string }) => {
>
{t('core.app.navbar.Publish')}
- {appDetail.isOwner && (
- }
- onClick={() => setTeamTagsSet(appDetail)}
- >
- {t('common.Team Tags Set')}
-
- )}
{appDetail.isOwner && (
{
+
{settingAppInfo && (
setSettingAppInfo(undefined)} />
)}
- {TeamTagsSet && (
- setTeamTagsSet(undefined)} />
- )}
>
);
};
diff --git a/projects/app/src/pages/app/detail/components/SimpleEdit/tagsEditModal.tsx b/projects/app/src/pages/app/detail/components/SimpleEdit/tagsEditModal.tsx
deleted file mode 100644
index 37e0737d7..000000000
--- a/projects/app/src/pages/app/detail/components/SimpleEdit/tagsEditModal.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import React, { useCallback, useState, useEffect } from 'react';
-import MyModal from '@/components/MyModal';
-import { useTranslation } from 'next-i18next';
-import { Button, Flex, Box, ModalFooter, ModalBody } from '@chakra-ui/react';
-import TagsEdit from '@/components/TagEdit';
-import { useToast } from '@fastgpt/web/hooks/useToast';
-import { AppSchema } from '@fastgpt/global/core/app/type.d';
-import { TeamTagsSchema } from '@fastgpt/global/support/user/team/type';
-import { useAppStore } from '@/web/core/app/store/useAppStore';
-import { useRequest } from '@/web/common/hooks/useRequest';
-import { getTeamsTags } from '@/web/support/user/team/api';
-const TagsEditModal = ({ appDetail, onClose }: { appDetail?: any; onClose: () => void }) => {
- const { t } = useTranslation();
- const [teamsTags, setTeamTags] = useState>([]);
- const [selectedTags, setSelectedTags] = useState(appDetail?.teamTags);
- const { toast } = useToast();
- const { replaceAppDetail } = useAppStore();
-
- // submit config
- const { mutate: saveSubmitSuccess, isLoading: btnLoading } = useRequest({
- mutationFn: async () => {
- await replaceAppDetail(appDetail._id, {
- teamTags: selectedTags
- });
- },
- onSuccess() {
- onClose();
- toast({
- title: t('common.Update Success'),
- status: 'success'
- });
- },
- errorToast: t('common.Update Failed')
- });
- //
-
- // // 点击选择标签
- // const clickTag = (tagId :Number) => {
- // const index = selectedTags.indexOf(tagId);
- // if (index === -1) {
- // // 如果 num 不在数组 arr 中,添加它
- // setSelectedTags([tagId,...selectedTags])
- // } else {
- // const _selectedTags = [...selectedTags];
- // _selectedTags.splice(index, 1);
- // console.log('_selectedTags',_selectedTags);
- // // 如果 num 已经在数组 arr 中,移除它
- // setSelectedTags(_selectedTags);
- // }
- // }
-
- useEffect(() => {
- // get team tags
- getTeamsTags(appDetail?.teamId).then((res: any) => {
- setTeamTags(res?.list);
- });
- }, []);
-
- return (
-
-
- {/*
- {teamsTags.map((item,index) => {
- return -1 ? 'green':'blue' }
- onClick={() => clickTag(item._id)}
- >
- {item.label}
-
- })}
- */}
-
-
- {t('团队标签')}
-
- ) => setSelectedTags(item)}
- />
-
-
-
- {t('common.Close')}
-
- saveSubmitSuccess(e)}>
- {t('common.Save')}
-
-
-
-
- );
-};
-export default TagsEditModal;
diff --git a/projects/app/src/pages/app/list/component/CreateModal.tsx b/projects/app/src/pages/app/list/component/CreateModal.tsx
index fa3039bd6..e0b107357 100644
--- a/projects/app/src/pages/app/list/component/CreateModal.tsx
+++ b/projects/app/src/pages/app/list/component/CreateModal.tsx
@@ -8,12 +8,8 @@ import {
Input,
Grid,
useTheme,
- Card,
- Text,
- HStack,
- Tag
+ Card
} from '@chakra-ui/react';
-import { AddIcon } from '@chakra-ui/icons';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { useForm } from 'react-hook-form';
import { compressImgFileAndUpload } from '@/web/common/file/controller';
diff --git a/projects/app/src/pages/app/list/index.tsx b/projects/app/src/pages/app/list/index.tsx
index ace56978c..88db3bac8 100644
--- a/projects/app/src/pages/app/list/index.tsx
+++ b/projects/app/src/pages/app/list/index.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useState, useEffect } from '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';
@@ -8,6 +8,7 @@ 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';
+
import MyIcon from '@fastgpt/web/components/common/Icon';
import PageContainer from '@/components/PageContainer';
import Avatar from '@/components/Avatar';
@@ -23,7 +24,6 @@ const MyApps = () => {
const router = useRouter();
const { userInfo } = useUserStore();
const { myApps, loadMyApps } = useAppStore();
- const [teamsTags, setTeamTags] = useState([]);
const { openConfirm, ConfirmModal } = useConfirm({
title: '删除提示',
content: '确认删除该应用所有信息?'
@@ -65,9 +65,11 @@ const MyApps = () => {
{t('app.My Apps')}
- } variant={'primaryOutline'} onClick={onOpenCreateModal}>
- {t('common.New Create')}
-
+ {userInfo?.team?.canWrite && (
+ } variant={'primaryOutline'} onClick={onOpenCreateModal}>
+ {t('common.New Create')}
+
+ )}
{
))}
- {/* (
-
- ) */}
-
{myApps.length === 0 && (
diff --git a/projects/app/src/pages/chat/team.tsx b/projects/app/src/pages/chat/team.tsx
deleted file mode 100644
index b5fe8a3a0..000000000
--- a/projects/app/src/pages/chat/team.tsx
+++ /dev/null
@@ -1,521 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
-import Head from 'next/head';
-import { getTeamChatInfo } from '@/web/core/chat/api';
-import { useRouter } from 'next/router';
-import {
- Box,
- Flex,
- useDisclosure,
- Drawer,
- DrawerOverlay,
- DrawerContent,
- useTheme
-} from '@chakra-ui/react';
-import Avatar from '@/components/Avatar';
-import { useToast } from '@fastgpt/web/hooks/useToast';
-import { useQuery } from '@tanstack/react-query';
-import { useSystemStore } from '@/web/common/system/useSystemStore';
-import SideBar from '@/components/SideBar';
-import PageContainer from '@/components/PageContainer';
-import { getChatListById } from '@/web/core/chat/api';
-import ChatHistorySlider from './components/ChatHistorySlider';
-import ChatHeader from './components/ChatHeader';
-import { serviceSideProps } from '@/web/common/utils/i18n';
-import { useTranslation } from 'next-i18next';
-import { checkChatSupportSelectFileByChatModels } from '@/web/core/chat/utils';
-import { useChatStore } from '@/web/core/chat/storeChat';
-import { customAlphabet } from 'nanoid';
-import { useLoading } from '@/web/common/hooks/useLoading';
-const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
-import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
-import { streamFetch } from '@/web/common/api/fetch';
-import { useTeamShareChatStore } from '@/web/core/chat/storeTeamChat';
-import type {
- ChatHistoryItemType,
- chatAppListSchema,
- teamInfoType
-} from '@fastgpt/global/core/chat/type.d';
-import { chatContentReplaceBlock } from '@fastgpt/global/core/chat/utils';
-import { ChatStatusEnum } from '@fastgpt/global/core/chat/constants';
-import { POST } from '@/web/common/api/request';
-const OutLink = ({
- teamId,
- appId,
- chatId,
- authToken
-}: {
- teamId: string;
- appId: string;
- chatId: string;
- authToken: string;
-}) => {
- const { t } = useTranslation();
- const router = useRouter();
- const { toast } = useToast();
- const theme = useTheme();
- const [myApps, setMyApps] = useState>([]);
- const { isPc } = useSystemStore();
- const ChatBoxRef = useRef(null);
- const [teamInfo, setTeamInfo] = useState();
- const { Loading, setIsLoading } = useLoading();
- const forbidRefresh = useRef(false);
-
- const { isOpen: isOpenSlider, onClose: onCloseSlider, onOpen: onOpenSlider } = useDisclosure();
- const {
- histories,
- loadHistories,
- lastChatAppId,
- setLastChatAppId,
- lastChatId,
- setLastChatId,
- pushHistory,
- updateHistory,
- delOneHistory,
- chatData,
- setChatData,
- delOneHistoryItem,
- clearHistories
- } = useChatStore();
- const {
- localUId,
- teamShareChatHistory, // abandon
- clearLocalHistory // abandon
- } = useTeamShareChatStore();
-
- const outLinkUid: string = authToken || localUId;
-
- // 纯网络获取流程
- const loadApps = useCallback(async () => {
- try {
- if (!teamId) {
- toast({
- status: 'error',
- title: t('core.chat.You need to a chat app')
- });
- return;
- }
- // 根据teamId 获取教研token以及用户tags,然后通过是否为
- // 根据获取历史记录列表
- const res = await getChatListById({ teamId, authToken });
- const { apps = [], teamInfo } = res;
- setMyApps(apps);
- setTeamInfo(teamInfo);
- if (apps.length <= 0) {
- toast({
- status: 'error',
- title: t('core.chat.You need to a chat app')
- });
- }
- //
- return null;
- } catch (error: any) {
- toast({
- status: 'warning',
- title: error?.message
- });
- }
- }, [outLinkUid, router, t, toast]);
-
- const startChat = useCallback(
- async ({ messages, controller, generatingMessage, variables }: StartChatFnProps) => {
- console.log('res', 13);
- const prompts = messages.slice(-2);
- const completionChatId = chatId ? chatId : nanoid();
-
- const { responseText, responseData } = await streamFetch({
- data: {
- messages: prompts,
- variables,
- appId,
- teamId: teamId,
- outLinkUid: outLinkUid,
- chatId: completionChatId
- },
- onMessage: generatingMessage,
- abortCtrl: controller
- });
-
- const newTitle =
- chatContentReplaceBlock(prompts[0].content).slice(0, 20) ||
- prompts[1]?.value?.slice(0, 20) ||
- t('core.chat.New Chat');
-
- // new chat
- if (completionChatId !== chatId) {
- const newHistory: ChatHistoryItemType = {
- chatId: completionChatId,
- updateTime: new Date(),
- title: newTitle,
- appId,
- top: false
- };
- pushHistory(newHistory);
- if (controller.signal.reason !== 'leave') {
- forbidRefresh.current = true;
- router.replace({
- query: {
- chatId: completionChatId,
- appId,
- teamId: teamId,
- authToken: authToken
- }
- });
- }
- } else {
- // update chat
- const currentChat = histories.find((item) => item.chatId === chatId);
- currentChat &&
- updateHistory({
- ...currentChat,
- updateTime: new Date(),
- title: newTitle
- });
- }
- // update chat window
- setChatData((state) => ({
- ...state,
- title: newTitle,
- history: ChatBoxRef.current?.getChatHistories() || state.history
- }));
-
- return { responseText, responseData, isNewChat: forbidRefresh.current };
- },
- [appId, chatId, histories, pushHistory, router, setChatData, updateHistory]
- );
-
- const { isFetching } = useQuery(['init', appId, teamId], async () => {
- console.log('res', 3);
- if (!teamId) {
- toast({
- status: 'error',
- title: t('core.chat.You need to a chat app')
- });
- return;
- }
- return teamId && loadApps();
- });
-
- useQuery(['loadHistories', appId], () => {
- console.log('res', 1);
- teamId && appId ? loadHistories({ appId, outLinkUid }) : null;
- });
- // 初始化聊天框
- useQuery(['init', { appId, chatId }], () => {
- if (!teamId) {
- toast({
- status: 'error',
- title: t('core.chat.You need to a chat app')
- });
- return;
- }
- // pc: redirect to latest model chat
- if (!appId && lastChatAppId) {
- return router.replace({
- query: {
- appId: lastChatAppId,
- chatId: lastChatId,
- teamId: teamId,
- authToken: authToken
- }
- });
- }
- if (!appId && myApps[0]) {
- return router.replace({
- query: {
- appId: myApps[0]._id,
- chatId: lastChatId,
- teamId: teamId,
- authToken: authToken
- }
- });
- }
- if (!appId) {
- (async () => {
- const { apps = [] } = await getChatListById({ teamId, authToken });
- setMyApps(apps);
- if (apps.length === 0) {
- toast({
- status: 'error',
- title: t('core.chat.You need to a chat app')
- });
- } else {
- router.replace({
- query: {
- appId: apps[0]._id,
- chatId: lastChatId,
- teamId: teamId,
- authToken: authToken
- }
- });
- }
- })();
- return;
- }
-
- // store id
- appId && setLastChatAppId(appId);
- setLastChatId(chatId);
- return loadChatInfo({
- appId,
- chatId,
- loading: appId !== chatData.appId
- });
- });
-
- // get chat app info
- const loadChatInfo = useCallback(
- async ({
- appId,
- chatId,
- loading = false
- }: {
- appId: string;
- chatId: string;
- loading?: boolean;
- }) => {
- try {
- if (!teamId) {
- toast({
- status: 'error',
- title: t('core.chat.You need to a chat app')
- });
- return;
- }
- loading && setIsLoading(true);
- const res = await getTeamChatInfo({ appId, chatId, outLinkUid });
- console.log('res', res);
- const history = res.history.map((item) => ({
- ...item,
- status: ChatStatusEnum.finish
- }));
-
- setChatData({
- ...res,
- history
- });
-
- // have records.
- ChatBoxRef.current?.resetHistory(history);
- ChatBoxRef.current?.resetVariables(res.variables);
- if (res.history.length > 0) {
- setTimeout(() => {
- ChatBoxRef.current?.scrollToBottom('auto');
- }, 500);
- }
- } catch (e: any) {
- // reset all chat tore
- setLastChatAppId('');
- setLastChatId('');
- toast({
- title: t('core.chat.Failed to initialize chat'),
- status: 'error'
- });
- if (e?.code === 501) {
- //router.replace('/app/list');
- } else if (chatId) {
- router.replace({
- query: {
- ...router.query,
- chatId: ''
- }
- });
- }
- }
- setIsLoading(false);
- return null;
- },
- [setIsLoading, setChatData, router, setLastChatAppId, setLastChatId, toast]
- );
- // 监测路由改变
- useEffect(() => {
- const activeHistory = teamShareChatHistory.filter((item) => !item.delete);
- if (!localUId || !teamId || activeHistory.length === 0) return;
- (async () => {
- try {
- await POST('/core/chat/initLocalShareHistoryV464', {
- outLinkUid: localUId,
- chatIds: teamShareChatHistory.map((item) => item.chatId)
- });
- clearLocalHistory();
- // router.reload();
- } catch (error) {
- toast({
- status: 'warning',
- title: t('core.shareChat.Init Error')
- });
- }
- })();
- }, [clearLocalHistory, localUId, router, teamShareChatHistory, teamId, t, toast]);
-
- return (
-
- {/* pc show myself apps */}
-
-
-
- {myApps.map((item) => (
- {
- router.replace({
- query: {
- appId: item._id,
- teamId: teamId,
- authToken: authToken
- }
- });
- }
- })}
- >
-
-
- {item.name}
-
-
- ))}
-
-
-
-
-
- {((children: React.ReactNode) => {
- return isPc || !appId ? (
- {children}
- ) : (
-
-
- {children}
-
- );
- })(
- ({
- id: item.chatId,
- title: item.title,
- customTitle: item.customTitle,
- top: item.top
- }))}
- onChangeChat={(chatId) => {
- router.replace({
- query: {
- chatId: chatId || '',
- appId,
- teamId: teamId,
- authToken: authToken
- }
- });
- if (!isPc) {
- onCloseSlider();
- }
- }}
- onDelHistory={(e) => delOneHistory({ ...e, appId })}
- onClearHistory={() => {
- clearHistories({ appId });
- router.replace({
- query: {
- appId,
- teamId: teamId,
- authToken: authToken
- }
- });
- }}
- onSetHistoryTop={(e) => {
- updateHistory({ ...e, appId });
- }}
- onSetCustomTitle={async (e) => {
- updateHistory({
- appId,
- chatId: e.chatId,
- title: e.title,
- customTitle: e.title
- });
- }}
- />
- )}
- {/* chat container */}
-
- {/* header */}
-
- {/* chat box */}
-
- {}}
- onStartChat={startChat}
- onDelMessage={(e) =>
- delOneHistoryItem({ ...e, appId: chatData.appId, chatId, outLinkUid })
- }
- appId={chatData.appId}
- chatId={chatId}
- outLinkUid={outLinkUid}
- />
-
-
-
-
-
- );
-};
-
-export async function getServerSideProps(context: any) {
- const teamId = context?.query?.teamId || '';
- const appId = context?.query?.appId || '';
- const chatId = context?.query?.chatId || '';
- const authToken: string = context?.query?.authToken || '';
-
- return {
- props: {
- teamId,
- appId,
- chatId,
- authToken,
- ...(await serviceSideProps(context))
- }
- };
-}
-
-export default OutLink;
diff --git a/projects/app/src/pages/dataset/detail/components/Import/Provider.tsx b/projects/app/src/pages/dataset/detail/components/Import/Provider.tsx
index fb6c5525c..00a8d479d 100644
--- a/projects/app/src/pages/dataset/detail/components/Import/Provider.tsx
+++ b/projects/app/src/pages/dataset/detail/components/Import/Provider.tsx
@@ -1,5 +1,6 @@
import React, { useContext, useCallback, createContext, useState, useMemo, useEffect } from 'react';
+import { formatModelPrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import { splitText2Chunks } from '@fastgpt/global/common/string/textSplitter';
import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constants';
import { useTranslation } from 'next-i18next';
@@ -33,7 +34,7 @@ type useImportStoreType = {
totalChunkChars: number;
totalChunks: number;
chunkSize: number;
- predictPoints: number;
+ predictPrice: number;
priceTip: string;
uploadRate: number;
splitSources2Chunks: () => void;
@@ -53,7 +54,7 @@ const StateContext = createContext({
totalChunkChars: 0,
totalChunks: 0,
chunkSize: 0,
- predictPoints: 0,
+ predictPrice: 0,
priceTip: '',
uploadRate: 50,
splitSources2Chunks: () => {}
@@ -104,9 +105,10 @@ const Provider = ({
chunkSize: embeddingChunkSize,
showChunkInput: true,
showPromptInput: false,
- charsPointsPrice: vectorModel.charsPointsPrice,
+ inputPrice: vectorModel.inputPrice,
+ outputPrice: 0,
priceTip: t('core.dataset.import.Embedding Estimated Price Tips', {
- price: vectorModel.charsPointsPrice
+ price: vectorModel.inputPrice
}),
uploadRate: 150
},
@@ -118,9 +120,10 @@ const Provider = ({
chunkSize: agentModel.maxContext * 0.55 || 6000,
showChunkInput: false,
showPromptInput: true,
- charsPointsPrice: agentModel.charsPointsPrice,
+ inputPrice: agentModel.inputPrice,
+ outputPrice: agentModel.outputPrice,
priceTip: t('core.dataset.import.QA Estimated Price Tips', {
- price: agentModel?.charsPointsPrice
+ price: agentModel?.inputPrice
}),
uploadRate: 30
}
@@ -148,12 +151,15 @@ const Provider = ({
() => sources.reduce((sum, file) => sum + file.chunkChars, 0),
[sources]
);
- const predictPoints = useMemo(() => {
+ const predictPrice = useMemo(() => {
if (mode === TrainingModeEnum.qa) {
- return +(((totalChunkChars * 1.5) / 1000) * agentModel.charsPointsPrice).toFixed(2);
+ const inputTotal = totalChunkChars * selectModelStaticParam.inputPrice;
+ const outputTotal = totalChunkChars * 0.5 * selectModelStaticParam.inputPrice;
+
+ return formatModelPrice2Read(inputTotal + outputTotal);
}
- return +((totalChunkChars / 1000) * vectorModel.charsPointsPrice).toFixed(2);
- }, [agentModel.charsPointsPrice, mode, totalChunkChars, vectorModel.charsPointsPrice]);
+ return formatModelPrice2Read(totalChunkChars * selectModelStaticParam.inputPrice);
+ }, [mode, selectModelStaticParam.inputPrice, totalChunkChars]);
const totalChunks = useMemo(
() => sources.reduce((sum, file) => sum + file.chunks.length, 0),
[sources]
@@ -172,8 +178,7 @@ const Provider = ({
return {
...file,
chunkChars: chars,
- chunks: chunks.map((chunk, i) => ({
- chunkIndex: i,
+ chunks: chunks.map((chunk) => ({
q: chunk,
a: ''
}))
@@ -193,7 +198,7 @@ const Provider = ({
totalChunkChars,
totalChunks,
chunkSize,
- predictPoints,
+ predictPrice,
splitSources2Chunks
};
return {children};
diff --git a/projects/app/src/pages/dataset/detail/components/Import/commonProgress/DataProcess.tsx b/projects/app/src/pages/dataset/detail/components/Import/commonProgress/DataProcess.tsx
index d34e536a2..2f3eef5cf 100644
--- a/projects/app/src/pages/dataset/detail/components/Import/commonProgress/DataProcess.tsx
+++ b/projects/app/src/pages/dataset/detail/components/Import/commonProgress/DataProcess.tsx
@@ -46,7 +46,7 @@ function DataProcess({
maxChunkSize,
totalChunkChars,
totalChunks,
- predictPoints,
+ predictPrice,
showRePreview,
splitSources2Chunks,
priceTip
@@ -275,7 +275,7 @@ function DataProcess({
{feConfigs?.show_pay && (
- {t('core.dataset.import.Estimated points', { points: predictPoints })}
+ {t('core.dataset.import.Estimated Price', { amount: predictPrice, unit: '元' })}
)}
diff --git a/projects/app/src/pages/dataset/detail/components/Import/commonProgress/Upload.tsx b/projects/app/src/pages/dataset/detail/components/Import/commonProgress/Upload.tsx
index c3bd68733..f7e0475d6 100644
--- a/projects/app/src/pages/dataset/detail/components/Import/commonProgress/Upload.tsx
+++ b/projects/app/src/pages/dataset/detail/components/Import/commonProgress/Upload.tsx
@@ -16,7 +16,7 @@ import { useImportStore, type FormType } from '../Provider';
import { useTranslation } from 'next-i18next';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useRequest } from '@/web/common/hooks/useRequest';
-import { postCreateTrainingUsage } from '@/web/support/wallet/usage/api';
+import { postCreateTrainingBill } from '@/web/support/wallet/bill/api';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { chunksUpload, fileCollectionCreate } from '@/web/core/dataset/utils';
import { ImportSourceItemType } from '@/web/core/dataset/type';
@@ -54,7 +54,7 @@ const Upload = ({ showPreviewChunks }: { showPreviewChunks: boolean }) => {
// Batch create collection and upload chunks
for await (const item of uploadList) {
- const billId = await postCreateTrainingUsage({
+ const billId = await postCreateTrainingBill({
name: item.sourceName,
datasetId: datasetDetail._id
});
diff --git a/projects/app/src/pages/dataset/detail/components/InputDataModal.tsx b/projects/app/src/pages/dataset/detail/components/InputDataModal.tsx
index ab7e133e0..14bfb5ddb 100644
--- a/projects/app/src/pages/dataset/detail/components/InputDataModal.tsx
+++ b/projects/app/src/pages/dataset/detail/components/InputDataModal.tsx
@@ -19,6 +19,7 @@ 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 { DatasetDataIndexTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { DatasetDataIndexItemType } from '@fastgpt/global/core/dataset/type';
import SideTabs from '@/components/SideTabs';
import DeleteIcon from '@fastgpt/web/components/common/Icon/delete';
@@ -161,10 +162,9 @@ const InputDataModal = ({
q: e.q,
a: e.a,
// remove dataId
- indexes: e.indexes.map((index) => ({
- ...index,
- dataId: undefined
- }))
+ indexes: e.indexes.map((index) =>
+ index.defaultIndex ? getDefaultIndex({ q: e.q, a: e.a }) : index
+ )
});
return {
@@ -195,7 +195,7 @@ const InputDataModal = ({
id: dataId,
...e,
indexes: e.indexes.map((index) =>
- index.defaultIndex ? getDefaultIndex({ q: e.q, a: e.a, dataId: index.dataId }) : index
+ index.defaultIndex ? getDefaultIndex({ q: e.q, a: e.a }) : index
)
});
@@ -278,7 +278,7 @@ const InputDataModal = ({
bg={i % 2 !== 0 ? 'myWhite.400' : ''}
_hover={{
'& .delete': {
- display: index.defaultIndex ? 'none' : 'block'
+ display: index.defaultIndex && indexes.length === 1 ? 'none' : 'block'
}
}}
>
@@ -331,6 +331,7 @@ const InputDataModal = ({
onClick={() =>
appendIndexes({
defaultIndex: false,
+ type: DatasetDataIndexTypeEnum.chunk,
text: '',
dataId: `${Date.now()}`
})
@@ -382,47 +383,45 @@ const InputTab = ({
const [inputType, setInputType] = useState(InputTypeEnum.q);
return (
-
-
-
-
- *
-
- {t('core.dataset.data.Main Content')}
-
-
-
-
- ),
- value: InputTypeEnum.q
- },
- {
- label: (
-
- {t('core.dataset.data.Auxiliary Data')}
-
-
-
-
- ),
- value: InputTypeEnum.a
- }
- ]}
- value={inputType}
- onChange={(e) => setInputType(e as InputTypeEnum)}
- />
-
+
+
+
+ *
+
+ {t('core.dataset.data.Main Content')}
+
+
+
+
+ ),
+ value: InputTypeEnum.q
+ },
+ {
+ label: (
+
+ {t('core.dataset.data.Auxiliary Data')}
+
+
+
+
+ ),
+ value: InputTypeEnum.a
+ }
+ ]}
+ value={inputType}
+ onChange={(e) => setInputType(e as InputTypeEnum)}
+ />
-
+
{inputType === InputTypeEnum.q && (
)}
-
+
);
};
diff --git a/projects/app/src/pages/dataset/detail/index.tsx b/projects/app/src/pages/dataset/detail/index.tsx
index 8836024f9..b8488ab00 100644
--- a/projects/app/src/pages/dataset/detail/index.tsx
+++ b/projects/app/src/pages/dataset/detail/index.tsx
@@ -27,7 +27,6 @@ import {
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { useRequest } from '@/web/common/hooks/useRequest';
import DatasetTypeTag from '@/components/core/dataset/DatasetTypeTag';
-import Head from 'next/head';
const DataCard = dynamic(() => import('./components/DataCard'));
const Test = dynamic(() => import('./components/Test'));
@@ -146,9 +145,7 @@ const Detail = ({ datasetId, currentTab }: { datasetId: string; currentTab: `${T
return (
<>
-
- {datasetDetail?.name}
-
+
{isPc ? (
diff --git a/projects/app/src/pages/price/components/ExtraPlan.tsx b/projects/app/src/pages/price/components/ExtraPlan.tsx
index e917a93f3..407ffca3c 100644
--- a/projects/app/src/pages/price/components/ExtraPlan.tsx
+++ b/projects/app/src/pages/price/components/ExtraPlan.tsx
@@ -7,111 +7,92 @@ import {
NumberIncrementStepper,
NumberInputField,
NumberInputStepper,
- Button
+ Button,
+ useDisclosure,
+ ModalBody,
+ ModalFooter
} from '@chakra-ui/react';
+import { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
import { useTranslation } from 'next-i18next';
-import React, { useCallback, useState } from 'react';
+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 { useForm } from 'react-hook-form';
-import { useToast } from '@fastgpt/web/hooks/useToast';
-import { getErrText } from '@fastgpt/global/common/error/utils';
-import { getWxPayQRCode } from '@/web/support/wallet/bill/api';
-import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants';
-import QRCodePayModal, { type QRPayProps } from '@/components/support/wallet/QRCodePayModal';
+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 = () => {
+const ExtraPlan = ({ extraDatasetSize }: { extraDatasetSize?: TeamSubSchema }) => {
const { t } = useTranslation();
- const router = useRouter();
- const { toast } = useToast();
const { subPlans } = useSystemStore();
- const [loading, setLoading] = useState(false);
- const [qrPayData, setQRPayData] = useState();
-
- // extra dataset
const extraDatasetPrice = subPlans?.extraDatasetSize?.price || 0;
- const { register: registerDatasetSize, handleSubmit: handleSubmitDatasetSize } = useForm({
- defaultValues: {
- datasetSize: 0,
- month: 1
- }
- });
- const onclickBuyDatasetSize = useCallback(
- async ({ datasetSize, month }: { datasetSize: number; month: number }) => {
- try {
- const datasetSizePayAmount = datasetSize * month * extraDatasetPrice;
- if (datasetSizePayAmount === 0) {
- return toast({
- status: 'warning',
- title: '购买数量不能为0'
- });
- }
- setLoading(true);
+ const [datasetSize, setDatasetSize] = useState(0);
+ const [isRenew, setIsRenew] = useState('false');
+ const router = useRouter();
+ const { userInfo } = useUserStore();
- const res = await getWxPayQRCode({
- type: BillTypeEnum.extraDatasetSub,
- month,
- extraDatasetSize: datasetSize
- });
- setQRPayData({
- readPrice: res.readPrice,
- codeUrl: res.codeUrl,
- billId: res.billId
- });
- } catch (err) {
- toast({
- title: getErrText(err),
- status: 'error'
- });
- }
- setLoading(false);
+ const [confirmPayExtraDatasetSizeData, setConfirmPayExtraDatasetSizeData] =
+ useState();
+
+ 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
+ });
},
- [extraDatasetPrice, toast]
- );
-
- // extra ai points
- const extraPointsPrice = subPlans?.extraPoints?.price || 0;
- const { register: registerExtraPoints, handleSubmit: handleSubmitExtraPoints } = useForm({
- defaultValues: {
- points: 0,
- month: 1
- }
+ successToast: t('common.Update success'),
+ errorToast: t('common.error.Update error')
});
- const onclickBuyExtraPoints = useCallback(
- async ({ points, month }: { points: number; month: number }) => {
- try {
- const payAmount = points * month * extraPointsPrice;
- if (payAmount === 0) {
- return toast({
- status: 'warning',
- title: '购买数量不能为0'
- });
- }
- setLoading(true);
-
- const res = await getWxPayQRCode({
- type: BillTypeEnum.extraPoints,
- month,
- extraPoints: points
- });
-
- setQRPayData({
- readPrice: res.readPrice,
- codeUrl: res.codeUrl,
- billId: res.billId
- });
- } catch (err) {
- toast({
- title: getErrText(err),
- status: 'error'
- });
- }
- setLoading(false);
- },
- [extraPointsPrice, toast]
+ 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 (
{
alignItems={'center'}
position={'relative'}
>
-
);
};
diff --git a/projects/app/src/pages/price/components/FAQ.tsx b/projects/app/src/pages/price/components/FAQ.tsx
index f95431c85..201226417 100644
--- a/projects/app/src/pages/price/components/FAQ.tsx
+++ b/projects/app/src/pages/price/components/FAQ.tsx
@@ -4,40 +4,7 @@ import { useTranslation } from 'next-i18next';
const FAQ = () => {
const { t } = useTranslation();
- const faqs = [
- {
- title: '订阅套餐会自动续费么?',
- desc: '当前套餐过期后,系统会自动根据“未来套餐”进行续费,系统会尝试从账户余额进行扣费,如果您需要自动续费,请在账户余额中预留额度。'
- },
- {
- title: '能否切换订阅套餐?',
- desc: '当前套餐价格大于新套餐时,无法立即切换,将会在当前套餐过期后以“续费”形式进行切换。\n当前套餐价格小于新套餐时,系统会自动计算当前套餐剩余余额,您可支付差价进行套餐切换。'
- },
- {
- title: '什么是AI积分?',
- desc: '每次调用AI模型时,都会消耗一定的AI积分。具体的计算标准可参考上方的“AI 积分计算标准”。'
- },
- {
- title: 'AI积分会过期么?',
- desc: '会过期。当前套餐过期后,AI积分将会清空,并更新为新套餐的AI积分。年度套餐的AI积分时长为1年,而不是每个月。'
- },
- {
- title: '知识库索引怎么计算?',
- desc: '知识库索引是系统存储的最小单位。通常每条知识库数据对应一条索引,但也会有多条索引的情况。你可以在知识库数据的编辑面板,查看该数据的索引数量和具体内容。'
- },
- {
- title: '额外资源包可以叠加么?',
- desc: '可以的。每次购买的资源包都是独立的,在其有效期内将会叠加使用。AI积分会优先扣除最先过期的资源包。'
- },
- {
- title: '知识库索引超出会删除么?',
- desc: '不会,知识库索引超出时,仅无法插入新的知识库索引。'
- },
- {
- title: '免费版数据会清除么?',
- desc: '免费版用户15天无使用记录后,会自动清除所有知识库内容。'
- }
- ];
+ const faqs = [{ title: '怎么付费', describe: '2222' }];
return (
{
{t('support.wallet.subscription.FAQ')}
- {faqs.map((item, i) => (
-
- {item.title}
-
- {item.desc}
-
+
+
+ 怎么付费
- ))}
+ 2222
+
);
diff --git a/projects/app/src/pages/price/components/Points.tsx b/projects/app/src/pages/price/components/Points.tsx
index 98292329c..1cc6141db 100644
--- a/projects/app/src/pages/price/components/Points.tsx
+++ b/projects/app/src/pages/price/components/Points.tsx
@@ -15,7 +15,7 @@ const Points = () => {
alignItems={'center'}
position={'relative'}
>
-
+
{t('support.wallet.subscription.Ai points')}
@@ -42,7 +42,7 @@ const Points = () => {
{llmModelList?.map((item, i) => (
{item.name}
- {item.charsPointsPrice}积分 / 1000字符
+ 5积分 / 1000字符
))}
@@ -67,7 +67,7 @@ const Points = () => {
{vectorModelList?.map((item, i) => (
{item.name}
- {item.charsPointsPrice}积分 / 1000字符
+ 5积分 / 1000字符
))}
@@ -89,7 +89,7 @@ const Points = () => {
{audioSpeechModelList?.map((item, i) => (
{item.name}
- {item.charsPointsPrice}积分 / 1000字符
+ 5积分 / 1000字符
))}
@@ -110,7 +110,7 @@ const Points = () => {
{whisperModel?.name}
- {whisperModel?.charsPointsPrice}积分 / 分钟
+ {whisperModel?.inputPrice}积分 / 分钟
diff --git a/projects/app/src/pages/price/components/Standard.tsx b/projects/app/src/pages/price/components/Standard.tsx
index 9150f8eab..4023cd0e4 100644
--- a/projects/app/src/pages/price/components/Standard.tsx
+++ b/projects/app/src/pages/price/components/Standard.tsx
@@ -1,8 +1,9 @@
import React, { useMemo, useState } from 'react';
import MyIcon from '@fastgpt/web/components/common/Icon';
-import { Box, Button, Flex, Grid, ModalBody, ModalFooter } from '@chakra-ui/react';
+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';
@@ -10,21 +11,9 @@ 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 { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools';
+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';
-import MyModal from '@/components/MyModal';
-import QRCodePayModal, { type QRPayProps } from '@/components/support/wallet/QRCodePayModal';
-import { getWxPayQRCode } from '@/web/support/wallet/bill/api';
-import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants';
-import StandardPlanContentList from '@/components/support/wallet/StandardPlanContentList';
-
-type ConfirmPayModalProps = {
- teamBalance: number;
- totalPrice: number;
- payPrice: number;
-
- planProps: StandardSubPlanParams;
-};
const Standard = ({
standardPlan,
@@ -36,7 +25,7 @@ const Standard = ({
const { t } = useTranslation();
const { subPlans, feConfigs } = useSystemStore();
const { toast } = useToast();
- const [confirmPayData, setConfirmPayData] = useState();
+ const { ConfirmModal, openConfirm } = useConfirm({});
const [selectSubMode, setSelectSubMode] = useState<`${SubModeEnum}`>(SubModeEnum.month);
@@ -52,12 +41,12 @@ const Standard = ({
maxDatasetAmount: value.maxDatasetAmount,
chatHistoryStoreDuration: value.chatHistoryStoreDuration,
maxDatasetSize: value.maxDatasetSize,
- permissionCustomApiKey: value.permissionCustomApiKey,
- permissionCustomCopyright: value.permissionCustomCopyright,
+ customApiKey: value.customApiKey,
+ customCopyright: value.customCopyright,
trainingWeight: value.trainingWeight,
- permissionReRank: value.permissionReRank,
+ reRankWeight: value.reRankWeight,
totalPoints: value.totalPoints * (selectSubMode === SubModeEnum.month ? 1 : 12),
- permissionWebsiteSync: value.permissionWebsiteSync
+ websiteSyncInterval: value.websiteSyncInterval
};
})
: [];
@@ -75,21 +64,41 @@ const Standard = ({
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 {
- setConfirmPayData({
- teamBalance: res.teamBalance,
- totalPrice: res.planPrice,
- payPrice: res.payPrice,
- planProps: {
- level: res.nextSubLevel,
- mode: res.nextMode
- }
- });
+ 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)
+ })
+ )();
}
}
});
@@ -129,114 +138,148 @@ const Standard = ({
gap={[4, 6, 8]}
w={'100%'}
>
- {standardSubList.map((item) => {
- const isCurrentPlan =
- item.level === standardPlan?.currentSubLevel &&
- selectSubMode === standardPlan?.currentMode;
-
- return (
-
-
- {t(item.label)}
-
-
- ¥{item.price}
-
-
- {t(item.desc, { title: feConfigs?.systemTitle })}
-
- {(() => {
- if (
- item.level === StandardSubLevelEnum.free &&
- selectSubMode === SubModeEnum.year
- ) {
- return (
-
- {t('support.wallet.subscription.Nonsupport')}
-
- );
- }
- if (
- item.level === standardPlan?.nextSubLevel &&
- selectSubMode === standardPlan?.nextMode
- ) {
- return (
-
- {t('support.wallet.subscription.Next plan')}
-
- );
- }
- if (isCurrentPlan) {
- return (
-
- onclickPreCheckStandPlan({
- level: item.level,
- mode: selectSubMode
- })
- }
- >
- {t('support.wallet.subscription.Current plan')}
-
- );
- }
-
+ {standardSubList.map((item) => (
+
+
+ {t(item.label)}
+
+
+ ¥{item.price}
+
+
+ {t(item.desc, { title: feConfigs?.systemTitle })}
+
+ {(() => {
+ if (item.level === StandardSubLevelEnum.free && selectSubMode === SubModeEnum.year) {
return (
-
- onclickPreCheckStandPlan({
- level: item.level,
- mode: selectSubMode
- })
- }
- >
- {t('support.wallet.subscription.Buy now')}
+
+ {t('support.wallet.subscription.Nonsupport')}
);
- })()}
+ }
+ if (
+ item.level === standardPlan?.currentSubLevel &&
+ selectSubMode === standardPlan?.currentMode
+ ) {
+ return (
+
+ {t('support.wallet.subscription.Current plan')}
+
+ );
+ }
+ if (
+ item.level === standardPlan?.nextSubLevel &&
+ selectSubMode === standardPlan?.nextMode
+ ) {
+ return (
+
+ {t('support.wallet.subscription.Next plan')}
+
+ );
+ }
+ return (
+
+ onclickPreCheckStandPlan({
+ level: item.level,
+ mode: selectSubMode
+ })
+ }
+ >
+ {t('support.wallet.subscription.Buy now')}
+
+ );
+ })()}
- {/* function list */}
-
-
- );
- })}
+ {/* function list */}
+
+
+
+
+ {t('support.wallet.subscription.function.Max members', {
+ amount: item.maxTeamMember
+ })}
+
+
+
+
+
+ {t('support.wallet.subscription.function.Max app', {
+ amount: item.maxAppAmount
+ })}
+
+
+
+
+
+ {t('support.wallet.subscription.function.Max dataset', {
+ amount: item.maxDatasetAmount
+ })}
+
+
+
+
+
+ {t('support.wallet.subscription.function.History store', {
+ amount: item.chatHistoryStoreDuration
+ })}
+
+
+
+
+
+ {t('support.wallet.subscription.function.Max dataset size', {
+ amount: item.maxDatasetSize
+ })}
+
+
+
+
+
+ {t('support.wallet.subscription.function.Points', {
+ amount: item.totalPoints
+ })}
+
+
+
+
+
+ {t('support.wallet.subscription.Training weight', {
+ weight: item.trainingWeight
+ })}
+
+
+ {!!item.customApiKey && (
+
+
+ 个人API Key
+
+ )}
+ {!!item.websiteSyncInterval && (
+
+
+ {item.websiteSyncInterval} h/次 web站点同步
+
+ )}
+
+
+ ))}
- {!!confirmPayData && (
- setConfirmPayData(undefined)}
- onConfirmPay={() => onclickUpdateStandardPlan(confirmPayData.planProps)}
- />
- )}
+
);
};
@@ -295,87 +338,3 @@ const RowTabs = ({
);
};
-
-const ConfirmPayModal = ({
- teamBalance,
- totalPrice,
- payPrice,
- onClose,
- onConfirmPay
-}: ConfirmPayModalProps & { onClose: () => void; onConfirmPay: () => void }) => {
- const { t } = useTranslation();
- const [qrPayData, setQRPayData] = useState();
-
- const formatPayPrice = Math.ceil(formatStorePrice2Read(payPrice));
- const formatTeamBalance = Math.floor(formatStorePrice2Read(teamBalance));
-
- const { mutate: handleClickPay, isLoading } = useRequest({
- mutationFn: async (amount: number) => {
- // 获取支付二维码
- return getWxPayQRCode({
- type: BillTypeEnum.balance,
- balance: amount
- });
- },
- onSuccess(res) {
- setQRPayData({
- readPrice: res.readPrice,
- codeUrl: res.codeUrl,
- billId: res.billId
- });
- }
- });
-
- return (
-
-
-
- 新套餐价格
- {formatStorePrice2Read(totalPrice)}元
-
-
- 旧套餐余额
- {Math.floor(formatStorePrice2Read(totalPrice - payPrice))}元
-
-
- 需支付
- {formatPayPrice}元
-
-
-
- 账号余额:
-
- {formatTeamBalance}元
-
- {teamBalance >= payPrice ? (
-
- 确认支付
-
- ) : (
- {
- handleClickPay(Math.ceil(formatStorePrice2Read(payPrice - teamBalance)));
- }}
- >
- 余额不足,去充值
-
- )}
-
-
- {!!qrPayData && }
-
- );
-};
diff --git a/projects/app/src/pages/price/index.tsx b/projects/app/src/pages/price/index.tsx
index 7d4ab8534..264e77a1c 100644
--- a/projects/app/src/pages/price/index.tsx
+++ b/projects/app/src/pages/price/index.tsx
@@ -3,56 +3,48 @@ 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 { getTeamPlanStatus } from '@/web/support/wallet/sub/api';
+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';
-import { getToken } from '@/web/support/user/auth';
-import Script from 'next/script';
const PriceBox = () => {
const { t } = useTranslation();
const { userInfo } = useUserStore();
const { data: teamSubPlan, refetch: refetchTeamSubPlan } = useQuery(
- ['getTeamPlanStatus'],
- getTeamPlanStatus,
+ ['getTeamDatasetValidSub'],
+ getTeamDatasetValidSub,
{
- enabled: !!getToken() || !!userInfo
+ enabled: !!userInfo
}
);
return (
- <>
-
-
- {/* standard sub */}
-
+
+ {/* standard sub */}
+
-
+
- {/* points */}
-
+ {/* points */}
+
- {/* question */}
-
-
- >
+ {/* question */}
+
+
);
};
diff --git a/projects/app/src/pages/tools/index.tsx b/projects/app/src/pages/tools/index.tsx
index 667a871f7..4ce14692a 100644
--- a/projects/app/src/pages/tools/index.tsx
+++ b/projects/app/src/pages/tools/index.tsx
@@ -40,15 +40,6 @@ const Tools = () => {
link: getDocPath('/docs/intro')
}
]
- : []),
- ...(feConfigs?.show_pay
- ? [
- {
- icon: 'support/bill/priceLight',
- label: '计费说明',
- link: '/price'
- }
- ]
: [])
];
diff --git a/projects/app/src/pages/tools/price.tsx b/projects/app/src/pages/tools/price.tsx
new file mode 100644
index 000000000..6a997eb34
--- /dev/null
+++ b/projects/app/src/pages/tools/price.tsx
@@ -0,0 +1,17 @@
+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();
+ return ;
+};
+
+export default PriceBox;
+
+export async function getServerSideProps(context: any) {
+ return {
+ props: { ...(await serviceSideProps(context)) }
+ };
+}
diff --git a/projects/app/src/service/core/dataset/data/controller.ts b/projects/app/src/service/core/dataset/data/controller.ts
index 1da3d4552..37bc16e41 100644
--- a/projects/app/src/service/core/dataset/data/controller.ts
+++ b/projects/app/src/service/core/dataset/data/controller.ts
@@ -6,9 +6,11 @@ import {
} from '@fastgpt/global/core/dataset/controller';
import {
insertDatasetDataVector,
- recallFromVectorStore
+ recallFromVectorStore,
+ updateDatasetDataVector
} from '@fastgpt/service/common/vectorStore/controller';
import {
+ DatasetDataIndexTypeEnum,
DatasetSearchModeEnum,
DatasetSearchModeMap,
SearchScoreTypeEnum
@@ -20,7 +22,6 @@ import { deleteDatasetDataVector } from '@fastgpt/service/common/vectorStore/con
import { getVectorsByText } from '@fastgpt/service/core/ai/embedding';
import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
import {
- DatasetDataItemType,
DatasetDataSchemaType,
DatasetDataWithCollectionType,
SearchDataResponseItemType
@@ -34,7 +35,7 @@ import type {
} from '@fastgpt/global/core/dataset/api.d';
import { pushDataListToTrainingQueue } from '@fastgpt/service/core/dataset/training/controller';
import { getVectorModel } from '../../ai/model';
-import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
+import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
export async function pushDataToTrainingQueue(
props: {
@@ -77,7 +78,7 @@ export async function insertData2Dataset({
return Promise.reject("teamId and tmbId can't be the same");
}
- const qaStr = getDefaultIndex({ q, a }).text;
+ const qaStr = `${q}\n${a}`.trim();
// empty indexes check, if empty, create default index
indexes =
@@ -85,16 +86,10 @@ export async function insertData2Dataset({
? indexes.map((index) => ({
...index,
dataId: undefined,
- defaultIndex: index.text.trim() === qaStr
+ defaultIndex: indexes?.length === 1 && index.text === qaStr ? true : index.defaultIndex
}))
: [getDefaultIndex({ q, a })];
- if (!indexes.find((index) => index.defaultIndex)) {
- indexes.unshift(getDefaultIndex({ q, a }));
- }
-
- indexes = indexes.slice(0, 6);
-
// insert to vector store
const result = await Promise.all(
indexes.map((item) =>
@@ -133,10 +128,8 @@ export async function insertData2Dataset({
/**
* update data
* 1. compare indexes
- * 2. insert new pg data
- * session run:
- * 3. update mongo data(session run)
- * 4. delete old pg data
+ * 2. update pg data
+ * 3. update mongo data
*/
export async function updateData2Dataset({
dataId,
@@ -148,30 +141,31 @@ export async function updateData2Dataset({
if (!Array.isArray(indexes)) {
return Promise.reject('indexes is required');
}
- const qaStr = getDefaultIndex({ q, a }).text;
+ const qaStr = `${q}\n${a}`.trim();
// patch index and update pg
const mongoData = await MongoDatasetData.findById(dataId);
if (!mongoData) return Promise.reject('core.dataset.error.Data not found');
- // remove defaultIndex
- let formatIndexes = indexes.map((index) => ({
- ...index,
- text: index.text.trim(),
- defaultIndex: index.text.trim() === qaStr
- }));
- if (!formatIndexes.find((index) => index.defaultIndex)) {
- const defaultIndex = mongoData.indexes.find((index) => index.defaultIndex);
- formatIndexes.unshift(defaultIndex ? defaultIndex : getDefaultIndex({ q, a }));
+ // make sure have one index
+ if (indexes.length === 0) {
+ const databaseDefaultIndex = mongoData.indexes.find((index) => index.defaultIndex);
+
+ indexes = [
+ getDefaultIndex({
+ q,
+ a,
+ dataId: databaseDefaultIndex ? String(databaseDefaultIndex.dataId) : undefined
+ })
+ ];
}
- formatIndexes = formatIndexes.slice(0, 6);
// patch indexes, create, update, delete
const patchResult: PatchIndexesProps[] = [];
// find database indexes in new Indexes, if have not, delete it
for (const item of mongoData.indexes) {
- const index = formatIndexes.find((index) => index.dataId === item.dataId);
+ const index = indexes.find((index) => index.dataId === item.dataId);
if (!index) {
patchResult.push({
type: 'delete',
@@ -179,34 +173,35 @@ export async function updateData2Dataset({
});
}
}
- for (const item of formatIndexes) {
+ for (const item of indexes) {
const index = mongoData.indexes.find((index) => index.dataId === item.dataId);
// in database, update
if (index) {
- // default index update
- if (index.defaultIndex && index.text !== qaStr) {
- patchResult.push({
- type: 'update',
- index: {
- //@ts-ignore
- ...index.toObject(),
- text: qaStr
- }
- });
- continue;
- }
- // custom index update
+ // manual update index
if (index.text !== item.text) {
patchResult.push({
type: 'update',
index: item
});
- continue;
+ } else if (index.defaultIndex && index.text !== qaStr) {
+ // update default index
+ patchResult.push({
+ type: 'update',
+ index: {
+ ...item,
+ type:
+ item.type === DatasetDataIndexTypeEnum.qa && !a
+ ? DatasetDataIndexTypeEnum.chunk
+ : item.type,
+ text: qaStr
+ }
+ });
+ } else {
+ patchResult.push({
+ type: 'unChange',
+ index: item
+ });
}
- patchResult.push({
- type: 'unChange',
- index: item
- });
} else {
// not in database, create
patchResult.push({
@@ -220,12 +215,10 @@ export async function updateData2Dataset({
mongoData.updateTime = new Date();
await mongoData.save();
- // insert vector
- const clonePatchResult2Insert: PatchIndexesProps[] = JSON.parse(JSON.stringify(patchResult));
- const insertResult = await Promise.all(
- clonePatchResult2Insert.map(async (item) => {
- // insert new vector and update dateId
- if (item.type === 'create' || item.type === 'update') {
+ // update vector
+ const result = await Promise.all(
+ patchResult.map(async (item) => {
+ if (item.type === 'create') {
const result = await insertDatasetDataVector({
query: item.index.text,
model: getVectorModel(model),
@@ -236,54 +229,50 @@ export async function updateData2Dataset({
item.index.dataId = result.insertId;
return result;
}
+ if (item.type === 'update' && item.index.dataId) {
+ const result = await updateDatasetDataVector({
+ teamId: mongoData.teamId,
+ datasetId: mongoData.datasetId,
+ collectionId: mongoData.collectionId,
+ id: item.index.dataId,
+ query: item.index.text,
+ model: getVectorModel(model)
+ });
+ item.index.dataId = result.insertId;
+
+ return result;
+ }
+ if (item.type === 'delete' && item.index.dataId) {
+ await deleteDatasetDataVector({
+ teamId: mongoData.teamId,
+ id: item.index.dataId
+ });
+ return {
+ charsLength: 0
+ };
+ }
return {
charsLength: 0
};
})
);
- const charsLength = insertResult.reduce((acc, cur) => acc + cur.charsLength, 0);
- // console.log(clonePatchResult2Insert);
- await mongoSessionRun(async (session) => {
- // update mongo
- const newIndexes = clonePatchResult2Insert
- .filter((item) => item.type !== 'delete')
- .map((item) => item.index);
- // update mongo other data
- mongoData.q = q || mongoData.q;
- mongoData.a = a ?? mongoData.a;
- mongoData.fullTextToken = jiebaSplit({ text: mongoData.q + mongoData.a });
- // @ts-ignore
- mongoData.indexes = newIndexes;
- await mongoData.save({ session });
- // delete vector
- const deleteIdList = patchResult
- .filter((item) => item.type === 'delete' || item.type === 'update')
- .map((item) => item.index.dataId)
- .filter(Boolean);
- if (deleteIdList.length > 0) {
- await deleteDatasetDataVector({
- teamId: mongoData.teamId,
- idList: deleteIdList as string[]
- });
- }
- });
+ const charsLength = result.reduce((acc, cur) => acc + cur.charsLength, 0);
+ const newIndexes = patchResult.filter((item) => item.type !== 'delete').map((item) => item.index);
+
+ // update mongo other data
+ mongoData.q = q || mongoData.q;
+ mongoData.a = a ?? mongoData.a;
+ mongoData.fullTextToken = jiebaSplit({ text: mongoData.q + mongoData.a });
+ // @ts-ignore
+ mongoData.indexes = newIndexes;
+ await mongoData.save();
return {
charsLength
};
}
-export const deleteDatasetData = async (data: DatasetDataItemType) => {
- await mongoSessionRun(async (session) => {
- await MongoDatasetData.findByIdAndDelete(data.id, { session });
- await deleteDatasetDataVector({
- teamId: data.teamId,
- idList: data.indexes.map((item) => item.dataId)
- });
- });
-};
-
type SearchDatasetDataProps = {
teamId: string;
model: string;
@@ -388,7 +377,7 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
a: data.a,
chunkIndex: data.chunkIndex,
datasetId: String(data.datasetId),
- collectionId: String(data.collectionId?._id),
+ collectionId: String(data.collectionId._id),
sourceName: data.collectionId.name || '',
sourceId: data.collectionId?.fileId || data.collectionId?.rawLink,
score: [{ type: SearchScoreTypeEnum.embedding, value: data.score, index }]
@@ -492,7 +481,7 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
}))
});
- if (results.length === 0) {
+ if (!Array.isArray(results)) {
usingReRank = false;
return [];
}
diff --git a/projects/app/src/service/events/generateQA.ts b/projects/app/src/service/events/generateQA.ts
index f6fc889cc..9af87b4c8 100644
--- a/projects/app/src/service/events/generateQA.ts
+++ b/projects/app/src/service/events/generateQA.ts
@@ -1,6 +1,6 @@
import { MongoDatasetTraining } from '@fastgpt/service/core/dataset/training/schema';
-import { pushQAUsage } from '@/service/support/wallet/usage/push';
-import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constants';
+import { pushQABill } from '@/service/support/wallet/bill/push';
+import { DatasetDataIndexTypeEnum, TrainingModeEnum } from '@fastgpt/global/core/dataset/constants';
import { sendOneInform } from '../support/user/inform/api';
import { getAIApi } from '@fastgpt/service/core/ai/config';
import type { ChatMessageItemType } from '@fastgpt/global/core/ai/type.d';
@@ -9,12 +9,12 @@ import { splitText2Chunks } from '@fastgpt/global/common/string/textSplitter';
import { replaceVariable } from '@fastgpt/global/common/string/tools';
import { Prompt_AgentQA } from '@/global/core/prompt/agent';
import { getErrText } from '@fastgpt/global/common/error/utils';
+import { authTeamBalance } from '../support/permission/auth/bill';
import type { PushDatasetDataChunkProps } from '@fastgpt/global/core/dataset/api.d';
+import { UserErrEnum } from '@fastgpt/global/common/error/code/user';
import { lockTrainingDataByTeamId } from '@fastgpt/service/core/dataset/training/controller';
import { pushDataToTrainingQueue } from '@/service/core/dataset/data/controller';
import { getLLMModel } from '../core/ai/model';
-import { checkTeamAIPoints } from '../support/permission/teamLimit';
-import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
const reduceQueue = () => {
global.qaQueueLen = global.qaQueueLen > 0 ? global.qaQueueLen - 1 : 0;
@@ -89,16 +89,16 @@ export async function generateQA(): Promise {
// auth balance
try {
- await checkTeamAIPoints(data.teamId);
+ await authTeamBalance(data.teamId);
} catch (error: any) {
- if (error?.statusText === TeamErrEnum.aiPointsNotEnough) {
+ if (error?.statusText === UserErrEnum.balanceNotEnough) {
// send inform and lock data
try {
sendOneInform({
type: 'system',
title: '文本训练任务中止',
content:
- '该团队账号的AI积分不足,文本训练任务中止,重新充值后将会继续。暂停的任务将在 7 天后被删除。',
+ '该团队账号余额不足,文本训练任务中止,重新充值后将会继续。暂停的任务将在 7 天后被删除。',
tmbId: data.tmbId
});
console.log('余额不足,暂停【QA】生成任务');
@@ -161,7 +161,7 @@ ${replaceVariable(Prompt_AgentQA.fixedText, { text })}`;
// add bill
if (insertLen > 0) {
- pushQAUsage({
+ pushQABill({
teamId: data.teamId,
tmbId: data.tmbId,
charsLength: `${prompt}${answer}`.length,
@@ -230,6 +230,7 @@ function formatSplitText(text: string, rawText: string) {
indexes: [
{
defaultIndex: true,
+ type: DatasetDataIndexTypeEnum.qa,
text: `${q}\n${a.trim().replace(/\n\s*/g, '\n')}`
}
]
@@ -247,6 +248,7 @@ function formatSplitText(text: string, rawText: string) {
indexes: [
{
defaultIndex: true,
+ type: DatasetDataIndexTypeEnum.chunk,
text: chunk
}
]
diff --git a/projects/app/src/service/events/generateVector.ts b/projects/app/src/service/events/generateVector.ts
index 8cf766065..3a8a64bac 100644
--- a/projects/app/src/service/events/generateVector.ts
+++ b/projects/app/src/service/events/generateVector.ts
@@ -4,10 +4,10 @@ import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constants';
import { sendOneInform } from '../support/user/inform/api';
import { addLog } from '@fastgpt/service/common/system/log';
import { getErrText } from '@fastgpt/global/common/error/utils';
-import { checkTeamAIPoints } from '../support/permission/teamLimit';
-import { pushGenerateVectorUsage } from '@/service/support/wallet/usage/push';
+import { authTeamBalance } from '@/service/support/permission/auth/bill';
+import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
+import { UserErrEnum } from '@fastgpt/global/common/error/code/user';
import { lockTrainingDataByTeamId } from '@fastgpt/service/core/dataset/training/controller';
-import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
const reduceQueue = () => {
global.vectorQueueLen = global.vectorQueueLen > 0 ? global.vectorQueueLen - 1 : 0;
@@ -93,16 +93,16 @@ export async function generateVector(): Promise {
// auth balance
try {
- await checkTeamAIPoints(data.teamId);
+ await authTeamBalance(data.teamId);
} catch (error: any) {
- if (error?.statusText === TeamErrEnum.aiPointsNotEnough) {
+ if (error?.statusText === UserErrEnum.balanceNotEnough) {
// send inform and lock data
try {
sendOneInform({
type: 'system',
title: '文本训练任务中止',
content:
- '该团队账号AI积分不足,文本训练任务中止,重新充值后将会继续。暂停的任务将在 7 天后被删除。',
+ '该团队账号余额不足,文本训练任务中止,重新充值后将会继续。暂停的任务将在 7 天后被删除。',
tmbId: data.tmbId
});
console.log('余额不足,暂停【向量】生成任务');
@@ -138,7 +138,7 @@ export async function generateVector(): Promise {
});
// push bill
- pushGenerateVectorUsage({
+ pushGenerateVectorBill({
teamId: data.teamId,
tmbId: data.tmbId,
charsLength,
diff --git a/projects/app/src/service/moduleDispatch/agent/classifyQuestion.ts b/projects/app/src/service/moduleDispatch/agent/classifyQuestion.ts
index 6eba9ad04..e7e350a0b 100644
--- a/projects/app/src/service/moduleDispatch/agent/classifyQuestion.ts
+++ b/projects/app/src/service/moduleDispatch/agent/classifyQuestion.ts
@@ -1,12 +1,9 @@
import { adaptChat2GptMessages } from '@fastgpt/global/core/chat/adapt';
-import { ChatContextFilter, countMessagesChars } from '@fastgpt/service/core/chat/utils';
+import { ChatContextFilter } from '@fastgpt/service/core/chat/utils';
import type { moduleDispatchResType, ChatItemType } from '@fastgpt/global/core/chat/type.d';
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import { getAIApi } from '@fastgpt/service/core/ai/config';
-import type {
- ClassifyQuestionAgentItemType,
- ModuleDispatchResponse
-} from '@fastgpt/global/core/module/type.d';
+import type { ClassifyQuestionAgentItemType } from '@fastgpt/global/core/module/type.d';
import { ModuleInputKeyEnum, ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
import type { ModuleDispatchProps } from '@fastgpt/global/core/module/type.d';
import { replaceVariable } from '@fastgpt/global/common/string/tools';
@@ -14,7 +11,7 @@ import { Prompt_CQJson } from '@/global/core/prompt/agent';
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
import { ModelTypeEnum, getLLMModel } from '@/service/core/ai/model';
import { getHistories } from '../utils';
-import { formatModelChars2Points } from '@/service/support/wallet/usage/utils';
+import { formatModelPrice2Store } from '@/service/support/wallet/bill/utils';
type Props = ModuleDispatchProps<{
[ModuleInputKeyEnum.aiModel]: string;
@@ -23,9 +20,10 @@ type Props = ModuleDispatchProps<{
[ModuleInputKeyEnum.userChatInput]: string;
[ModuleInputKeyEnum.agents]: ClassifyQuestionAgentItemType[];
}>;
-type CQResponse = ModuleDispatchResponse<{
+type CQResponse = {
+ [ModuleOutputKeyEnum.responseData]: moduleDispatchResType;
[key: string]: any;
-}>;
+};
const agentFunName = 'classify_question';
@@ -33,7 +31,6 @@ const agentFunName = 'classify_question';
export const dispatchClassifyQuestion = async (props: Props): Promise => {
const {
user,
- module: { name },
histories,
params: { model, history = 6, agents, userChatInput }
} = props as Props;
@@ -46,7 +43,7 @@ export const dispatchClassifyQuestion = async (props: Props): Promise {
+ const { arg, inputTokens, outputTokens } = await (async () => {
if (cqModel.toolChoice) {
return toolChoice({
...props,
@@ -63,31 +60,25 @@ export const dispatchClassifyQuestion = async (props: Props): Promise item.key === arg?.type) || agents[agents.length - 1];
- const { totalPoints, modelName } = formatModelChars2Points({
+ const { total, modelName } = formatModelPrice2Store({
model: cqModel.model,
- charsLength,
- modelType: ModelTypeEnum.llm
+ inputLen: inputTokens,
+ outputLen: outputTokens,
+ type: ModelTypeEnum.llm
});
return {
[result.key]: true,
[ModuleOutputKeyEnum.responseData]: {
- totalPoints: user.openaiAccount?.key ? 0 : totalPoints,
+ price: user.openaiAccount?.key ? 0 : total,
model: modelName,
query: userChatInput,
- charsLength,
+ inputTokens,
+ outputTokens,
cqList: agents,
cqResult: result.value,
contextTotalLen: chatHistories.length + 2
- },
- [ModuleOutputKeyEnum.moduleDispatchBills]: [
- {
- moduleName: name,
- totalPoints,
- model: modelName,
- charsLength
- }
- ]
+ }
};
};
@@ -158,13 +149,11 @@ ${systemPrompt}
const arg = JSON.parse(
response?.choices?.[0]?.message?.tool_calls?.[0]?.function?.arguments || ''
);
- const functionChars =
- agentFunction.description.length +
- agentFunction.parameters.properties.type.description.length;
return {
arg,
- charsLength: countMessagesChars(messages) + functionChars
+ inputTokens: response.usage?.prompt_tokens || 0,
+ outputTokens: response.usage?.completion_tokens || 0
};
} catch (error) {
console.log(agentFunction.parameters);
@@ -174,7 +163,8 @@ ${systemPrompt}
return {
arg: {},
- charsLength: 0
+ inputTokens: 0,
+ outputTokens: 0
};
}
}
@@ -216,7 +206,8 @@ async function completions({
agents.find((item) => answer.includes(item.key) || answer.includes(item.value))?.key || '';
return {
- charsLength: countMessagesChars(messages),
+ inputTokens: data.usage?.prompt_tokens || 0,
+ outputTokens: data.usage?.completion_tokens || 0,
arg: { type: id }
};
}
diff --git a/projects/app/src/service/moduleDispatch/agent/extract.ts b/projects/app/src/service/moduleDispatch/agent/extract.ts
index 2b8418ca2..75cbf55a0 100644
--- a/projects/app/src/service/moduleDispatch/agent/extract.ts
+++ b/projects/app/src/service/moduleDispatch/agent/extract.ts
@@ -1,12 +1,9 @@
import { adaptChat2GptMessages } from '@fastgpt/global/core/chat/adapt';
-import { ChatContextFilter, countMessagesChars } from '@fastgpt/service/core/chat/utils';
+import { ChatContextFilter } from '@fastgpt/service/core/chat/utils';
import type { moduleDispatchResType, ChatItemType } from '@fastgpt/global/core/chat/type.d';
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import { getAIApi } from '@fastgpt/service/core/ai/config';
-import type {
- ContextExtractAgentItemType,
- ModuleDispatchResponse
-} from '@fastgpt/global/core/module/type';
+import type { ContextExtractAgentItemType } from '@fastgpt/global/core/module/type';
import { ModuleInputKeyEnum, ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
import type { ModuleDispatchProps } from '@fastgpt/global/core/module/type.d';
import { Prompt_ExtractJson } from '@/global/core/prompt/agent';
@@ -14,7 +11,7 @@ import { replaceVariable } from '@fastgpt/global/common/string/tools';
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
import { getHistories } from '../utils';
import { ModelTypeEnum, getLLMModel } from '@/service/core/ai/model';
-import { formatModelChars2Points } from '@/service/support/wallet/usage/utils';
+import { formatModelPrice2Store } from '@/service/support/wallet/bill/utils';
type Props = ModuleDispatchProps<{
[ModuleInputKeyEnum.history]?: ChatItemType[];
@@ -23,18 +20,18 @@ type Props = ModuleDispatchProps<{
[ModuleInputKeyEnum.description]: string;
[ModuleInputKeyEnum.aiModel]: string;
}>;
-type Response = ModuleDispatchResponse<{
+type Response = {
[ModuleOutputKeyEnum.success]?: boolean;
[ModuleOutputKeyEnum.failed]?: boolean;
[ModuleOutputKeyEnum.contextExtractFields]: string;
-}>;
+ [ModuleOutputKeyEnum.responseData]: moduleDispatchResType;
+};
const agentFunName = 'extract_json_data';
export async function dispatchContentExtract(props: Props): Promise {
const {
user,
- module: { name },
histories,
params: { content, history = 6, model, description, extractKeys }
} = props;
@@ -46,7 +43,7 @@ export async function dispatchContentExtract(props: Props): Promise {
const extractModel = getLLMModel(model);
const chatHistories = getHistories(history, histories);
- const { arg, charsLength } = await (async () => {
+ const { arg, inputTokens, outputTokens } = await (async () => {
if (extractModel.toolChoice) {
return toolChoice({
...props,
@@ -83,10 +80,11 @@ export async function dispatchContentExtract(props: Props): Promise {
}
}
- const { totalPoints, modelName } = formatModelChars2Points({
+ const { total, modelName } = formatModelPrice2Store({
model: extractModel.model,
- charsLength,
- modelType: ModelTypeEnum.llm
+ inputLen: inputTokens,
+ outputLen: outputTokens,
+ type: ModelTypeEnum.llm
});
return {
@@ -95,22 +93,15 @@ export async function dispatchContentExtract(props: Props): Promise {
[ModuleOutputKeyEnum.contextExtractFields]: JSON.stringify(arg),
...arg,
[ModuleOutputKeyEnum.responseData]: {
- totalPoints: user.openaiAccount?.key ? 0 : totalPoints,
+ price: user.openaiAccount?.key ? 0 : total,
model: modelName,
query: content,
- charsLength,
+ inputTokens,
+ outputTokens,
extractDescription: description,
extractResult: arg,
contextTotalLen: chatHistories.length + 2
- },
- [ModuleOutputKeyEnum.moduleDispatchBills]: [
- {
- moduleName: name,
- totalPoints,
- model: modelName,
- charsLength
- }
- ]
+ }
};
}
@@ -202,12 +193,10 @@ ${description || '根据用户要求获取适当的 JSON 字符串。'}
}
})();
- const functionChars =
- description.length + extractKeys.reduce((sum, item) => sum + item.desc.length, 0);
-
return {
rawResponse: response?.choices?.[0]?.message?.tool_calls?.[0]?.function?.arguments || '',
- charsLength: countMessagesChars(messages) + functionChars,
+ inputTokens: response.usage?.prompt_tokens || 0,
+ outputTokens: response.usage?.completion_tokens || 0,
arg
};
}
@@ -249,6 +238,8 @@ Human: ${content}`
stream: false
});
const answer = data.choices?.[0].message?.content || '';
+ const inputTokens = data.usage?.prompt_tokens || 0;
+ const outputTokens = data.usage?.completion_tokens || 0;
// parse response
const start = answer.indexOf('{');
@@ -257,7 +248,8 @@ Human: ${content}`
if (start === -1 || end === -1)
return {
rawResponse: answer,
- charsLength: countMessagesChars(messages),
+ inputTokens,
+ outputTokens,
arg: {}
};
@@ -269,14 +261,15 @@ Human: ${content}`
try {
return {
rawResponse: answer,
- charsLength: countMessagesChars(messages),
-
+ inputTokens,
+ outputTokens,
arg: JSON.parse(jsonStr) as Record
};
} catch (error) {
return {
rawResponse: answer,
- charsLength: countMessagesChars(messages),
+ inputTokens,
+ outputTokens,
arg: {}
};
}
diff --git a/projects/app/src/service/moduleDispatch/chat/oneapi.ts b/projects/app/src/service/moduleDispatch/chat/oneapi.ts
index 80ec8e999..b1c6512e1 100644
--- a/projects/app/src/service/moduleDispatch/chat/oneapi.ts
+++ b/projects/app/src/service/moduleDispatch/chat/oneapi.ts
@@ -1,16 +1,16 @@
import type { NextApiResponse } from 'next';
-import { ChatContextFilter, countMessagesChars } from '@fastgpt/service/core/chat/utils';
+import { ChatContextFilter } from '@fastgpt/service/core/chat/utils';
import type { moduleDispatchResType, ChatItemType } from '@fastgpt/global/core/chat/type.d';
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import { sseResponseEventEnum } from '@fastgpt/service/common/response/constant';
import { textAdaptGptResponse } from '@/utils/adapt';
import { getAIApi } from '@fastgpt/service/core/ai/config';
import type { ChatCompletion, StreamChatType } from '@fastgpt/global/core/ai/type.d';
-import { formatModelChars2Points } from '@/service/support/wallet/usage/utils';
+import { formatModelPrice2Store } from '@/service/support/wallet/bill/utils';
import type { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
import { postTextCensor } from '@/service/common/censor';
import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/global/core/ai/constant';
-import type { ModuleDispatchResponse, ModuleItemType } from '@fastgpt/global/core/module/type.d';
+import type { ModuleItemType } from '@fastgpt/global/core/module/type.d';
import { countMessagesTokens, sliceMessagesTB } from '@fastgpt/global/common/string/tiktoken';
import { adaptChat2GptMessages } from '@fastgpt/global/core/chat/adapt';
import { Prompt_QuotePromptList, Prompt_QuoteTemplateList } from '@/global/core/prompt/AIChat';
@@ -32,10 +32,11 @@ export type ChatProps = ModuleDispatchProps<
[ModuleInputKeyEnum.aiChatDatasetQuote]?: SearchDataResponseItemType[];
}
>;
-export type ChatResponse = ModuleDispatchResponse<{
+export type ChatResponse = {
[ModuleOutputKeyEnum.answerText]: string;
+ [ModuleOutputKeyEnum.responseData]: moduleDispatchResType;
[ModuleOutputKeyEnum.history]: ChatItemType[];
-}>;
+};
/* request openai chat */
export const dispatchChatCompletion = async (props: ChatProps): Promise => {
@@ -45,7 +46,7 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise {
+ const { answerText, inputTokens, outputTokens, completeMessages } = await (async () => {
if (stream) {
// sse response
const { answer } = await streamResponse({
@@ -171,6 +172,17 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise = {};
+ filterQuoteQA.forEach((item) => {
+ if (sortQuoteQAMap[item.collectionId]) {
+ sortQuoteQAMap[item.collectionId].push(item);
+ } else {
+ sortQuoteQAMap[item.collectionId] = [item];
+ }
+ });
+ const sortQuoteQAList = Object.values(sortQuoteQAMap);
+
+ sortQuoteQAList.forEach((qaList) => {
+ qaList.sort((a, b) => a.chunkIndex - b.chunkIndex);
+ });
+
+ const flatQuoteList = sortQuoteQAList.flat();
+
const quoteText =
- filterQuoteQA.length > 0
- ? `${filterQuoteQA.map((item, index) => getValue(item, index).trim()).join('\n------\n')}`
+ flatQuoteList.length > 0
+ ? `${flatQuoteList.map((item, index) => getValue(item, index)).join('\n')}`
: '';
return {
- filterQuoteQA: filterQuoteQA,
+ filterQuoteQA: flatQuoteList,
quoteText
};
}
diff --git a/projects/app/src/service/moduleDispatch/dataset/search.ts b/projects/app/src/service/moduleDispatch/dataset/search.ts
index 7d4c5a8c0..54ba4feb0 100644
--- a/projects/app/src/service/moduleDispatch/dataset/search.ts
+++ b/projects/app/src/service/moduleDispatch/dataset/search.ts
@@ -1,19 +1,15 @@
import type { moduleDispatchResType } from '@fastgpt/global/core/chat/type.d';
-import { formatModelChars2Points } from '@/service/support/wallet/usage/utils';
+import { formatModelPrice2Store } from '@/service/support/wallet/bill/utils';
import type { SelectedDatasetType } from '@fastgpt/global/core/module/api.d';
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
-import type {
- ModuleDispatchProps,
- ModuleDispatchResponse
-} from '@fastgpt/global/core/module/type.d';
+import type { ModuleDispatchProps } from '@fastgpt/global/core/module/type.d';
import { ModelTypeEnum, getLLMModel, getVectorModel } from '@/service/core/ai/model';
import { searchDatasetData } from '@/service/core/dataset/data/controller';
import { ModuleInputKeyEnum, ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
+import { queryExtension } from '@fastgpt/service/core/ai/functions/queryExtension';
import { getHistories } from '../utils';
import { datasetSearchQueryExtension } from '@fastgpt/service/core/dataset/search/utils';
-import { ChatModuleBillType } from '@fastgpt/global/support/wallet/bill/type';
-import { checkTeamReRankPermission } from '@/service/support/permission/teamLimit';
type DatasetSearchProps = ModuleDispatchProps<{
[ModuleInputKeyEnum.datasetSelectList]: SelectedDatasetType;
@@ -26,11 +22,12 @@ type DatasetSearchProps = ModuleDispatchProps<{
[ModuleInputKeyEnum.datasetSearchExtensionModel]: string;
[ModuleInputKeyEnum.datasetSearchExtensionBg]: string;
}>;
-export type DatasetSearchResponse = ModuleDispatchResponse<{
+export type DatasetSearchResponse = {
+ [ModuleOutputKeyEnum.responseData]: moduleDispatchResType;
[ModuleOutputKeyEnum.datasetIsEmpty]?: boolean;
[ModuleOutputKeyEnum.datasetUnEmpty]?: boolean;
[ModuleOutputKeyEnum.datasetQuoteQA]: SearchDataResponseItemType[];
-}>;
+};
export async function dispatchDatasetSearch(
props: DatasetSearchProps
@@ -38,7 +35,6 @@ export async function dispatchDatasetSearch(
const {
teamId,
histories,
- module,
params: {
datasets = [],
similarity,
@@ -77,8 +73,6 @@ export async function dispatchDatasetSearch(
histories: getHistories(6, histories)
});
- // console.log(concatQueries, rewriteQuery, aiExtensionResult);
-
// get vector
const vectorModel = getVectorModel(datasets[0]?.vectorModel?.model);
@@ -97,18 +91,18 @@ export async function dispatchDatasetSearch(
limit,
datasetIds: datasets.map((item) => item.datasetId),
searchMode,
- usingReRank: usingReRank && (await checkTeamReRankPermission(teamId))
+ usingReRank
});
// count bill results
// vector
- const { totalPoints, modelName } = formatModelChars2Points({
+ const { total, modelName } = formatModelPrice2Store({
model: vectorModel.model,
- charsLength,
- modelType: ModelTypeEnum.vector
+ inputLen: charsLength,
+ type: ModelTypeEnum.vector
});
- const responseData: moduleDispatchResType & { totalPoints: number } = {
- totalPoints,
+ const responseData: moduleDispatchResType & { price: number } = {
+ price: total,
query: concatQueries.join('\n'),
model: modelName,
charsLength,
@@ -117,42 +111,28 @@ export async function dispatchDatasetSearch(
searchMode,
searchUsingReRank: searchUsingReRank
};
- const moduleDispatchBills: ChatModuleBillType[] = [
- {
- totalPoints,
- moduleName: module.name,
- model: modelName,
- charsLength
- }
- ];
if (aiExtensionResult) {
- const { totalPoints, modelName } = formatModelChars2Points({
+ const { total, modelName } = formatModelPrice2Store({
model: aiExtensionResult.model,
- charsLength: aiExtensionResult.charsLength,
- modelType: ModelTypeEnum.llm
+ inputLen: aiExtensionResult.inputTokens,
+ outputLen: aiExtensionResult.outputTokens,
+ type: ModelTypeEnum.llm
});
- responseData.totalPoints += totalPoints;
- responseData.charsLength = aiExtensionResult.charsLength;
+ responseData.price += total;
+ responseData.inputTokens = aiExtensionResult.inputTokens;
+ responseData.outputTokens = aiExtensionResult.outputTokens;
responseData.extensionModel = modelName;
responseData.extensionResult =
aiExtensionResult.extensionQueries?.join('\n') ||
JSON.stringify(aiExtensionResult.extensionQueries);
-
- moduleDispatchBills.push({
- totalPoints,
- moduleName: 'core.module.template.Query extension',
- model: modelName,
- charsLength: aiExtensionResult.charsLength
- });
}
return {
isEmpty: searchRes.length === 0 ? true : undefined,
unEmpty: searchRes.length > 0 ? true : undefined,
quoteQA: searchRes,
- responseData,
- moduleDispatchBills
+ responseData
};
}
diff --git a/projects/app/src/service/moduleDispatch/index.ts b/projects/app/src/service/moduleDispatch/index.ts
index 1acdbe24b..5c79497a5 100644
--- a/projects/app/src/service/moduleDispatch/index.ts
+++ b/projects/app/src/service/moduleDispatch/index.ts
@@ -23,12 +23,11 @@ import { dispatchContentExtract } from './agent/extract';
import { dispatchHttpRequest } from './tools/http';
import { dispatchHttp468Request } from './tools/http468';
import { dispatchAppRequest } from './tools/runApp';
-import { dispatchQueryExtension } from './tools/queryExternsion';
+import { dispatchCFR } from './tools/cfr';
import { dispatchRunPlugin } from './plugin/run';
import { dispatchPluginInput } from './plugin/runInput';
import { dispatchPluginOutput } from './plugin/runOutput';
import { valueTypeFormat } from './utils';
-import { ChatModuleBillType } from '@fastgpt/global/support/wallet/bill/type';
const callbackMap: Record<`${FlowNodeTypeEnum}`, Function> = {
[FlowNodeTypeEnum.historyNode]: dispatchHistory,
@@ -45,7 +44,7 @@ const callbackMap: Record<`${FlowNodeTypeEnum}`, Function> = {
[FlowNodeTypeEnum.pluginModule]: dispatchRunPlugin,
[FlowNodeTypeEnum.pluginInput]: dispatchPluginInput,
[FlowNodeTypeEnum.pluginOutput]: dispatchPluginOutput,
- [FlowNodeTypeEnum.queryExtension]: dispatchQueryExtension,
+ [FlowNodeTypeEnum.cfr]: dispatchCFR,
// none
[FlowNodeTypeEnum.userGuide]: () => Promise.resolve()
@@ -83,19 +82,16 @@ export async function dispatchModules({
// let storeData: Record = {}; // after module used
let chatResponse: ChatHistoryItemResType[] = []; // response request and save to database
let chatAnswerText = ''; // AI answer
- let chatModuleBills: ChatModuleBillType[] = [];
let runningTime = Date.now();
function pushStore(
{ inputs = [] }: RunningModuleItemType,
{
answerText = '',
- responseData,
- moduleDispatchBills
+ responseData
}: {
answerText?: string;
responseData?: ChatHistoryItemResType | ChatHistoryItemResType[];
- moduleDispatchBills?: ChatModuleBillType[];
}
) {
const time = Date.now();
@@ -109,9 +105,6 @@ export async function dispatchModules({
});
}
}
- if (moduleDispatchBills) {
- chatModuleBills = chatModuleBills.concat(moduleDispatchBills);
- }
runningTime = time;
const isResponseAnswerText =
@@ -165,7 +158,6 @@ export async function dispatchModules({
const filterModules = nextRunModules.filter((module) => {
if (set.has(module.moduleId)) return false;
set.add(module.moduleId);
- ``;
return true;
});
@@ -207,7 +199,8 @@ export async function dispatchModules({
user,
stream,
detail,
- module,
+ outputs: module.outputs,
+ inputs: module.inputs,
params
};
@@ -244,11 +237,10 @@ export async function dispatchModules({
? params[ModuleOutputKeyEnum.userChatInput]
: undefined,
...dispatchRes,
- [ModuleOutputKeyEnum.responseData]: formatResponseData,
- [ModuleOutputKeyEnum.moduleDispatchBills]:
- dispatchRes[ModuleOutputKeyEnum.moduleDispatchBills]
+ [ModuleOutputKeyEnum.responseData]: formatResponseData
});
}
+
// start process width initInput
const initModules = runningModules.filter((item) => initRunningModuleType[item.flowType]);
@@ -274,8 +266,7 @@ export async function dispatchModules({
return {
[ModuleOutputKeyEnum.answerText]: chatAnswerText,
- [ModuleOutputKeyEnum.responseData]: chatResponse,
- [ModuleOutputKeyEnum.moduleDispatchBills]: chatModuleBills
+ [ModuleOutputKeyEnum.responseData]: chatResponse
};
}
diff --git a/projects/app/src/service/moduleDispatch/plugin/run.ts b/projects/app/src/service/moduleDispatch/plugin/run.ts
index a90b88384..3e192aa68 100644
--- a/projects/app/src/service/moduleDispatch/plugin/run.ts
+++ b/projects/app/src/service/moduleDispatch/plugin/run.ts
@@ -1,7 +1,4 @@
-import type {
- ModuleDispatchProps,
- ModuleDispatchResponse
-} from '@fastgpt/global/core/module/type.d';
+import type { ModuleDispatchProps } from '@fastgpt/global/core/module/type.d';
import { dispatchModules } from '../index';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import {
@@ -17,9 +14,10 @@ type RunPluginProps = ModuleDispatchProps<{
[ModuleInputKeyEnum.pluginId]: string;
[key: string]: any;
}>;
-type RunPluginResponse = ModuleDispatchResponse<{
+type RunPluginResponse = {
[ModuleOutputKeyEnum.answerText]: string;
-}>;
+ [ModuleOutputKeyEnum.responseData]?: moduleDispatchResType;
+};
export const dispatchRunPlugin = async (props: RunPluginProps): Promise => {
const {
@@ -60,7 +58,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise ({
...module,
@@ -78,9 +76,9 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise sum + (item.totalPoints || 0), 0),
+ price: responseData.reduce((sum, item) => sum + (item.price || 0), 0),
runningTime: responseData.reduce((sum, item) => sum + (item.runningTime || 0), 0),
pluginOutput: output?.pluginOutput,
pluginDetail:
@@ -91,14 +89,6 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise sum + (item.totalPoints || 0), 0),
- model: plugin.name,
- charsLength: 0
- }
- ],
...(output ? output.pluginOutput : {})
};
};
diff --git a/projects/app/src/service/moduleDispatch/plugin/runOutput.ts b/projects/app/src/service/moduleDispatch/plugin/runOutput.ts
index 04cc9bd93..492f949be 100644
--- a/projects/app/src/service/moduleDispatch/plugin/runOutput.ts
+++ b/projects/app/src/service/moduleDispatch/plugin/runOutput.ts
@@ -14,7 +14,7 @@ export const dispatchPluginOutput = (props: PluginOutputProps): PluginOutputResp
return {
responseData: {
- totalPoints: 0,
+ price: 0,
pluginOutput: params
}
};
diff --git a/projects/app/src/service/moduleDispatch/tools/cfr.ts b/projects/app/src/service/moduleDispatch/tools/cfr.ts
new file mode 100644
index 000000000..0aa6f0b5d
--- /dev/null
+++ b/projects/app/src/service/moduleDispatch/tools/cfr.ts
@@ -0,0 +1,64 @@
+import type { ChatItemType, moduleDispatchResType } from '@fastgpt/global/core/chat/type.d';
+import type { ModuleDispatchProps } from '@fastgpt/global/core/module/type.d';
+import { ModuleInputKeyEnum, ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
+import { ModelTypeEnum, getLLMModel } from '@/service/core/ai/model';
+import { formatModelPrice2Store } from '@/service/support/wallet/bill/utils';
+import { queryCfr } from '@fastgpt/service/core/ai/functions/cfr';
+import { getHistories } from '../utils';
+
+type Props = ModuleDispatchProps<{
+ [ModuleInputKeyEnum.aiModel]: string;
+ [ModuleInputKeyEnum.aiSystemPrompt]?: string;
+ [ModuleInputKeyEnum.history]?: ChatItemType[] | number;
+ [ModuleInputKeyEnum.userChatInput]: string;
+}>;
+type Response = {
+ [ModuleOutputKeyEnum.text]: string;
+ [ModuleOutputKeyEnum.responseData]?: moduleDispatchResType;
+};
+
+export const dispatchCFR = async ({
+ histories,
+ params: { model, systemPrompt, history, userChatInput }
+}: Props): Promise => {
+ if (!userChatInput) {
+ return Promise.reject('Question is empty');
+ }
+
+ // none
+ // first chat and no system prompt
+ if (systemPrompt === 'none' || (histories.length === 0 && !systemPrompt)) {
+ return {
+ [ModuleOutputKeyEnum.text]: userChatInput
+ };
+ }
+
+ const cfrModel = getLLMModel(model);
+ const chatHistories = getHistories(history, histories);
+
+ const { cfrQuery, inputTokens, outputTokens } = await queryCfr({
+ chatBg: systemPrompt,
+ query: userChatInput,
+ histories: chatHistories,
+ model: cfrModel.model
+ });
+
+ const { total, modelName } = formatModelPrice2Store({
+ model: cfrModel.model,
+ inputLen: inputTokens,
+ outputLen: outputTokens,
+ type: ModelTypeEnum.llm
+ });
+
+ return {
+ [ModuleOutputKeyEnum.responseData]: {
+ price: total,
+ model: modelName,
+ inputTokens,
+ outputTokens,
+ query: userChatInput,
+ textOutput: cfrQuery
+ },
+ [ModuleOutputKeyEnum.text]: cfrQuery
+ };
+};
diff --git a/projects/app/src/service/moduleDispatch/tools/http.ts b/projects/app/src/service/moduleDispatch/tools/http.ts
index 02cdc4320..bedf74863 100644
--- a/projects/app/src/service/moduleDispatch/tools/http.ts
+++ b/projects/app/src/service/moduleDispatch/tools/http.ts
@@ -1,8 +1,5 @@
import type { moduleDispatchResType } from '@fastgpt/global/core/chat/type.d';
-import type {
- ModuleDispatchProps,
- ModuleDispatchResponse
-} from '@fastgpt/global/core/module/type.d';
+import type { ModuleDispatchProps } from '@fastgpt/global/core/module/type.d';
import {
DYNAMIC_INPUT_KEY,
ModuleInputKeyEnum,
@@ -19,10 +16,11 @@ type HttpRequestProps = ModuleDispatchProps<{
[ModuleInputKeyEnum.httpHeaders]: string;
[key: string]: any;
}>;
-type HttpResponse = ModuleDispatchResponse<{
+type HttpResponse = {
[ModuleOutputKeyEnum.failed]?: boolean;
+ [ModuleOutputKeyEnum.responseData]: moduleDispatchResType;
[key: string]: any;
-}>;
+};
const flatDynamicParams = (params: Record) => {
const dynamicParams = params[DYNAMIC_INPUT_KEY];
@@ -40,7 +38,7 @@ export const dispatchHttpRequest = async (props: HttpRequestProps): Promise;
[key: string]: any;
}>;
-type HttpResponse = ModuleDispatchResponse<{
+type HttpResponse = {
[ModuleOutputKeyEnum.failed]?: boolean;
+ [ModuleOutputKeyEnum.responseData]: moduleDispatchResType;
[key: string]: any;
-}>;
+};
const UNDEFINED_SIGN = 'UNDEFINED_SIGN';
@@ -39,7 +38,7 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise 0 ? params : undefined,
body: Object.keys(requestBody).length > 0 ? requestBody : undefined,
headers: Object.keys(headers).length > 0 ? headers : undefined,
@@ -132,8 +131,8 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise 0 ? params : undefined,
body: Object.keys(requestBody).length > 0 ? requestBody : undefined,
headers: Object.keys(headers).length > 0 ? headers : undefined,
diff --git a/projects/app/src/service/moduleDispatch/tools/queryExternsion.ts b/projects/app/src/service/moduleDispatch/tools/queryExternsion.ts
deleted file mode 100644
index 732a546cc..000000000
--- a/projects/app/src/service/moduleDispatch/tools/queryExternsion.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
-import type {
- ModuleDispatchProps,
- ModuleDispatchResponse
-} from '@fastgpt/global/core/module/type.d';
-import { ModuleInputKeyEnum, ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
-import { ModelTypeEnum, getLLMModel } from '@/service/core/ai/model';
-import { formatModelChars2Points } from '@/service/support/wallet/usage/utils';
-import { queryExtension } from '@fastgpt/service/core/ai/functions/queryExtension';
-import { getHistories } from '../utils';
-import { hashStr } from '@fastgpt/global/common/string/tools';
-
-type Props = ModuleDispatchProps<{
- [ModuleInputKeyEnum.aiModel]: string;
- [ModuleInputKeyEnum.aiSystemPrompt]?: string;
- [ModuleInputKeyEnum.history]?: ChatItemType[] | number;
- [ModuleInputKeyEnum.userChatInput]: string;
-}>;
-type Response = ModuleDispatchResponse<{
- [ModuleOutputKeyEnum.text]: string;
-}>;
-
-export const dispatchQueryExtension = async ({
- histories,
- module,
- params: { model, systemPrompt, history, userChatInput }
-}: Props): Promise => {
- if (!userChatInput) {
- return Promise.reject('Question is empty');
- }
-
- const queryExtensionModel = getLLMModel(model);
- const chatHistories = getHistories(history, histories);
-
- const { extensionQueries, charsLength } = await queryExtension({
- chatBg: systemPrompt,
- query: userChatInput,
- histories: chatHistories,
- model: queryExtensionModel.model
- });
-
- extensionQueries.unshift(userChatInput);
-
- const { totalPoints, modelName } = formatModelChars2Points({
- model: queryExtensionModel.model,
- charsLength,
- modelType: ModelTypeEnum.llm
- });
-
- const set = new Set();
- const filterSameQueries = extensionQueries.filter((item) => {
- // 删除所有的标点符号与空格等,只对文本进行比较
- const str = hashStr(item.replace(/[^\p{L}\p{N}]/gu, ''));
- if (set.has(str)) return false;
- set.add(str);
- return true;
- });
-
- return {
- [ModuleOutputKeyEnum.responseData]: {
- totalPoints,
- model: modelName,
- charsLength,
- query: userChatInput,
- textOutput: JSON.stringify(filterSameQueries)
- },
- [ModuleOutputKeyEnum.moduleDispatchBills]: [
- {
- moduleName: module.name,
- totalPoints,
- model: modelName,
- charsLength
- }
- ],
- [ModuleOutputKeyEnum.text]: JSON.stringify(filterSameQueries)
- };
-};
diff --git a/projects/app/src/service/moduleDispatch/tools/runApp.ts b/projects/app/src/service/moduleDispatch/tools/runApp.ts
index b3e2db834..a8db9fe31 100644
--- a/projects/app/src/service/moduleDispatch/tools/runApp.ts
+++ b/projects/app/src/service/moduleDispatch/tools/runApp.ts
@@ -1,8 +1,5 @@
import type { moduleDispatchResType, ChatItemType } from '@fastgpt/global/core/chat/type.d';
-import type {
- ModuleDispatchProps,
- ModuleDispatchResponse
-} from '@fastgpt/global/core/module/type.d';
+import type { ModuleDispatchProps } from '@fastgpt/global/core/module/type.d';
import { SelectAppItemType } from '@fastgpt/global/core/module/type';
import { dispatchModules } from '../index';
import { MongoApp } from '@fastgpt/service/core/app/schema';
@@ -18,10 +15,11 @@ type Props = ModuleDispatchProps<{
[ModuleInputKeyEnum.history]?: ChatItemType[] | number;
app: SelectAppItemType;
}>;
-type Response = ModuleDispatchResponse<{
+type Response = {
+ [ModuleOutputKeyEnum.responseData]: moduleDispatchResType[];
[ModuleOutputKeyEnum.answerText]: string;
[ModuleOutputKeyEnum.history]: ChatItemType[];
-}>;
+};
export const dispatchAppRequest = async (props: Props): Promise => {
const {
@@ -32,7 +30,6 @@ export const dispatchAppRequest = async (props: Props): Promise => {
histories,
params: { userChatInput, history, app }
} = props;
- let start = Date.now();
if (!userChatInput) {
return Promise.reject('Input is empty');
@@ -59,7 +56,7 @@ export const dispatchAppRequest = async (props: Props): Promise => {
const chatHistories = getHistories(history, histories);
- const { responseData, moduleDispatchBills, answerText } = await dispatchModules({
+ const { responseData, answerText } = await dispatchModules({
...props,
appId: app.id,
modules: appData.modules,
@@ -81,20 +78,7 @@ export const dispatchAppRequest = async (props: Props): Promise => {
]);
return {
- [ModuleOutputKeyEnum.responseData]: {
- moduleLogo: appData.avatar,
- query: userChatInput,
- textOutput: answerText,
- totalPoints: responseData.reduce((sum, item) => sum + (item.totalPoints || 0), 0)
- },
- [ModuleOutputKeyEnum.moduleDispatchBills]: [
- {
- moduleName: appData.name,
- totalPoints: responseData.reduce((sum, item) => sum + (item.totalPoints || 0), 0),
- charsLength: 0,
- model: appData.name
- }
- ],
+ responseData,
answerText: answerText,
history: completeMessages
};
diff --git a/projects/app/src/service/mongo.ts b/projects/app/src/service/mongo.ts
index 7378f713a..1500015b9 100644
--- a/projects/app/src/service/mongo.ts
+++ b/projects/app/src/service/mongo.ts
@@ -1,5 +1,5 @@
import { startQueue } from './utils/tools';
-import { PRICE_SCALE } from '@fastgpt/global/support/wallet/constants';
+import { PRICE_SCALE } from '@fastgpt/global/support/wallet/bill/constants';
import { MongoUser } from '@fastgpt/service/support/user/schema';
import { connectMongo } from '@fastgpt/service/common/mongo/init';
import { hashStr } from '@fastgpt/global/common/string/tools';
diff --git a/projects/app/src/service/support/permission/auth/bill.ts b/projects/app/src/service/support/permission/auth/bill.ts
new file mode 100644
index 000000000..3b9d81085
--- /dev/null
+++ b/projects/app/src/service/support/permission/auth/bill.ts
@@ -0,0 +1,9 @@
+import { GET } from '@fastgpt/service/common/api/plusRequest';
+import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
+
+export const authTeamBalance = async (teamId: string) => {
+ if (FastGPTProUrl) {
+ return GET('/support/permission/authBalance', { teamId });
+ }
+ return true;
+};
diff --git a/projects/app/src/service/support/permission/auth/dataset.ts b/projects/app/src/service/support/permission/auth/dataset.ts
index 6aec479e0..f7c0491c6 100644
--- a/projects/app/src/service/support/permission/auth/dataset.ts
+++ b/projects/app/src/service/support/permission/auth/dataset.ts
@@ -24,7 +24,6 @@ export async function authDatasetData({
const data: DatasetDataItemType = {
id: String(datasetData._id),
- teamId: datasetData.teamId,
q: datasetData.q,
a: datasetData.a,
chunkIndex: datasetData.chunkIndex,
diff --git a/projects/app/src/service/support/permission/auth/outLink.ts b/projects/app/src/service/support/permission/auth/outLink.ts
index bd921159a..5a32e4ea4 100644
--- a/projects/app/src/service/support/permission/auth/outLink.ts
+++ b/projects/app/src/service/support/permission/auth/outLink.ts
@@ -6,7 +6,7 @@ import type {
AuthOutLinkResponse
} from '@fastgpt/global/support/outLink/api.d';
import { authOutLinkValid } from '@fastgpt/service/support/permission/auth/outLink';
-import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
+import { getUserAndAuthBalance } from '@fastgpt/service/support/user/controller';
import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
import { OutLinkErrEnum } from '@fastgpt/global/common/error/code/outLink';
import { OutLinkSchema } from '@fastgpt/global/support/outLink/type';
@@ -58,15 +58,13 @@ export async function authOutLinkChatStart({
// get outLink and app
const { shareChat, appId } = await authOutLinkValid({ shareId });
- // check ai points and chat limit
- const [{ user }, { uid }] = await Promise.all([
- getUserChatInfoAndAuthTeamPoints(shareChat.tmbId),
+ // check balance and chat limit
+ const [user, { uid }] = await Promise.all([
+ getUserAndAuthBalance({ tmbId: shareChat.tmbId, minBalance: 0 }),
authOutLinkChatLimit({ outLink: shareChat, ip, outLinkUid, question })
]);
return {
- teamId: shareChat.teamId,
- tmbId: shareChat.tmbId,
authType: AuthUserTypeEnum.token,
responseDetail: shareChat.responseDetail,
user,
diff --git a/projects/app/src/service/support/permission/auth/team.ts b/projects/app/src/service/support/permission/auth/team.ts
deleted file mode 100644
index b985882a0..000000000
--- a/projects/app/src/service/support/permission/auth/team.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { UserErrEnum } from '@fastgpt/global/common/error/code/user';
-import { TeamMemberWithUserSchema } from '@fastgpt/global/support/user/team/type';
-import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
-import { checkTeamAIPoints } from '../teamLimit';
-
-export async function getUserChatInfoAndAuthTeamPoints(tmbId: string) {
- const tmb = (await MongoTeamMember.findById(tmbId, 'teamId userId').populate(
- 'userId',
- 'timezone openaiAccount'
- )) as TeamMemberWithUserSchema;
- if (!tmb) return Promise.reject(UserErrEnum.unAuthUser);
-
- await checkTeamAIPoints(tmb.teamId);
-
- return {
- user: tmb.userId
- };
-}
diff --git a/projects/app/src/service/support/permission/auth/teamChat.ts b/projects/app/src/service/support/permission/auth/teamChat.ts
deleted file mode 100644
index 468c9943e..000000000
--- a/projects/app/src/service/support/permission/auth/teamChat.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { POST } from '@fastgpt/service/common/api/plusRequest';
-import type {
- AuthOutLinkChatProps,
- AuthOutLinkLimitProps,
- AuthOutLinkInitProps,
- AuthOutLinkResponse
-} from '@fastgpt/global/support/outLink/api.d';
-import { getUserChatInfoAndAuthTeamPoints } from './team';
-import { MongoTeam } from '@fastgpt/service/support/user/team/teamSchema';
-import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
-export function authOutLinkInit(data: AuthOutLinkInitProps): Promise {
- if (!global.feConfigs?.isPlus) return Promise.resolve({ uid: data.outLinkUid });
- return POST('/support/outLink/authInit', data);
-}
-export function authOutLinkChatLimit(data: AuthOutLinkLimitProps): Promise {
- if (!global.feConfigs?.isPlus) return Promise.resolve({ uid: data.outLinkUid });
- return POST('/support/outLink/authChatStart', data);
-}
-
-export async function authTeamShareChatStart({
- teamId,
- ip,
- outLinkUid,
- question
-}: AuthOutLinkChatProps & {
- teamId: string;
-}) {
- // get outLink and app
- const res: any = await MongoTeam.findById(teamId);
-
- // check balance and chat limit
- const tmb = await MongoTeamMember.findOne({ teamId, userId: String(res.ownerId) });
-
- if (!tmb) {
- throw new Error('can not find it');
- }
-
- const { user } = await getUserChatInfoAndAuthTeamPoints(String(tmb._id));
-
- return {
- user,
- uid: outLinkUid
- };
-}
diff --git a/projects/app/src/service/support/permission/teamLimit.ts b/projects/app/src/service/support/permission/teamLimit.ts
deleted file mode 100644
index b1e2c35da..000000000
--- a/projects/app/src/service/support/permission/teamLimit.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-import { getVectorCountByTeamId } from '@fastgpt/service/common/vectorStore/controller';
-import { getTeamSubPlans, getTeamStandPlan } from '@fastgpt/service/support/wallet/sub/utils';
-import { getStandardSubPlan } from '../wallet/sub/utils';
-import { MongoApp } from '@fastgpt/service/core/app/schema';
-import { MongoPlugin } from '@fastgpt/service/core/plugin/schema';
-import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
-import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
-import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
-
-export const checkDatasetLimit = async ({
- teamId,
- insertLen = 0
-}: {
- teamId: string;
- insertLen?: number;
-}) => {
- const [{ totalPoints, usedPoints, datasetMaxSize }, usedSize] = await Promise.all([
- getTeamSubPlans({ teamId, standardPlans: getStandardSubPlan() }),
- getVectorCountByTeamId(teamId)
- ]);
-
- if (usedSize + insertLen >= datasetMaxSize) {
- return Promise.reject(TeamErrEnum.datasetSizeNotEnough);
- }
-
- if (usedPoints >= totalPoints) {
- return Promise.reject(TeamErrEnum.aiPointsNotEnough);
- }
- return;
-};
-
-export const checkTeamAIPoints = async (teamId: string) => {
- const { totalPoints, usedPoints } = await getTeamSubPlans({
- teamId,
- standardPlans: getStandardSubPlan()
- });
-
- if (usedPoints >= totalPoints) {
- return Promise.reject(TeamErrEnum.aiPointsNotEnough);
- }
-
- return {
- totalPoints,
- usedPoints
- };
-};
-
-export const checkTeamDatasetLimit = async (teamId: string) => {
- const [{ standardConstants }, datasetCount] = await Promise.all([
- getTeamStandPlan({ teamId, standardPlans: getStandardSubPlan() }),
- MongoDataset.countDocuments({
- teamId,
- type: DatasetTypeEnum.dataset
- })
- ]);
-
- if (standardConstants && datasetCount >= standardConstants.maxDatasetAmount) {
- return Promise.reject(TeamErrEnum.datasetAmountNotEnough);
- }
-};
-export const checkTeamAppLimit = async (teamId: string) => {
- const [{ standardConstants }, appCount] = await Promise.all([
- getTeamStandPlan({ teamId, standardPlans: getStandardSubPlan() }),
- MongoApp.count({ teamId })
- ]);
-
- if (standardConstants && appCount >= standardConstants.maxAppAmount) {
- return Promise.reject(TeamErrEnum.appAmountNotEnough);
- }
-};
-export const checkTeamPluginLimit = async (teamId: string) => {
- const [{ standardConstants }, pluginCount] = await Promise.all([
- getTeamStandPlan({ teamId, standardPlans: getStandardSubPlan() }),
- MongoPlugin.count({ teamId })
- ]);
-
- if (standardConstants && pluginCount >= standardConstants.maxAppAmount) {
- return Promise.reject(TeamErrEnum.pluginAmountNotEnough);
- }
-};
-
-export const checkTeamReRankPermission = async (teamId: string) => {
- const { standardConstants } = await getTeamStandPlan({
- teamId,
- standardPlans: getStandardSubPlan()
- });
-
- if (standardConstants && !standardConstants?.permissionReRank) {
- return false;
- }
- return true;
-};
-export const checkTeamWebSyncPermission = async (teamId: string) => {
- const { standardConstants } = await getTeamStandPlan({
- teamId,
- standardPlans: getStandardSubPlan()
- });
-
- if (standardConstants && !standardConstants?.permissionWebsiteSync) {
- return Promise.reject(TeamErrEnum.websiteSyncNotEnough);
- }
-};
diff --git a/projects/app/src/service/support/wallet/bill/controller.ts b/projects/app/src/service/support/wallet/bill/controller.ts
new file mode 100644
index 000000000..e6edfcd6b
--- /dev/null
+++ b/projects/app/src/service/support/wallet/bill/controller.ts
@@ -0,0 +1,23 @@
+import { ConcatBillProps, CreateBillProps } from '@fastgpt/global/support/wallet/bill/api';
+import { addLog } from '@fastgpt/service/common/system/log';
+import { POST } from '@fastgpt/service/common/api/plusRequest';
+import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
+
+export function createBill(data: CreateBillProps) {
+ if (!FastGPTProUrl) return;
+ if (data.total === 0) {
+ addLog.info('0 Bill', data);
+ }
+ try {
+ POST('/support/wallet/bill/createBill', data);
+ } catch (error) {}
+}
+export function concatBill(data: ConcatBillProps) {
+ if (!FastGPTProUrl) return;
+ if (data.total === 0) {
+ addLog.info('0 Bill', data);
+ }
+ try {
+ POST('/support/wallet/bill/concatBill', data);
+ } catch (error) {}
+}
diff --git a/projects/app/src/service/support/wallet/bill/push.ts b/projects/app/src/service/support/wallet/bill/push.ts
new file mode 100644
index 000000000..4bb3819cd
--- /dev/null
+++ b/projects/app/src/service/support/wallet/bill/push.ts
@@ -0,0 +1,327 @@
+import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
+import { ModelTypeEnum } from '@/service/core/ai/model';
+import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type.d';
+import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
+import { addLog } from '@fastgpt/service/common/system/log';
+import { PostReRankProps } from '@fastgpt/global/core/ai/api';
+import { createBill, concatBill } from './controller';
+import { formatModelPrice2Store } from '@/service/support/wallet/bill/utils';
+
+export const pushChatBill = ({
+ appName,
+ appId,
+ teamId,
+ tmbId,
+ source,
+ response
+}: {
+ appName: string;
+ appId: string;
+ teamId: string;
+ tmbId: string;
+ source: `${BillSourceEnum}`;
+ response: ChatHistoryItemResType[];
+}) => {
+ const total = response.reduce((sum, item) => sum + (item.price || 0), 0);
+
+ createBill({
+ teamId,
+ tmbId,
+ appName,
+ appId,
+ total,
+ source,
+ list: response.map((item) => ({
+ moduleName: item.moduleName,
+ amount: item.price || 0,
+ model: item.model,
+ inputTokens: item.inputTokens,
+ outputTokens: item.outputTokens,
+ charsLength: item.charsLength
+ }))
+ });
+ addLog.info(`finish completions`, {
+ source,
+ teamId,
+ tmbId,
+ price: formatStorePrice2Read(total)
+ });
+ return { total };
+};
+
+export const pushQABill = async ({
+ teamId,
+ tmbId,
+ model,
+ charsLength,
+ billId
+}: {
+ teamId: string;
+ tmbId: string;
+ model: string;
+ charsLength: number;
+ billId: string;
+}) => {
+ // 计算价格
+ const { total } = formatModelPrice2Store({
+ model,
+ inputLen: charsLength,
+ type: ModelTypeEnum.llm
+ });
+
+ concatBill({
+ billId,
+ teamId,
+ tmbId,
+ total,
+ charsLength,
+ listIndex: 1
+ });
+
+ return { total };
+};
+
+export const pushGenerateVectorBill = ({
+ billId,
+ teamId,
+ tmbId,
+ charsLength,
+ model,
+ source = BillSourceEnum.fastgpt,
+ extensionModel,
+ extensionInputTokens,
+ extensionOutputTokens
+}: {
+ billId?: string;
+ teamId: string;
+ tmbId: string;
+ charsLength: number;
+ model: string;
+ source?: `${BillSourceEnum}`;
+
+ extensionModel?: string;
+ extensionInputTokens?: number;
+ extensionOutputTokens?: number;
+}) => {
+ const { total: totalVector, modelName: vectorModelName } = formatModelPrice2Store({
+ model,
+ inputLen: charsLength,
+ type: ModelTypeEnum.vector
+ });
+
+ const { extensionTotal, extensionModelName } = (() => {
+ if (!extensionModel || !extensionInputTokens || !extensionOutputTokens)
+ return {
+ extensionTotal: 0,
+ extensionModelName: ''
+ };
+ const { total, modelName } = formatModelPrice2Store({
+ model: extensionModel,
+ inputLen: extensionInputTokens,
+ outputLen: extensionOutputTokens,
+ type: ModelTypeEnum.llm
+ });
+ return {
+ extensionTotal: total,
+ extensionModelName: modelName
+ };
+ })();
+
+ const total = totalVector + extensionTotal;
+
+ // 插入 Bill 记录
+ if (billId) {
+ concatBill({
+ teamId,
+ tmbId,
+ total: totalVector,
+ billId,
+ charsLength,
+ listIndex: 0
+ });
+ } else {
+ createBill({
+ teamId,
+ tmbId,
+ appName: 'wallet.moduleName.index',
+ total,
+ source,
+ list: [
+ {
+ moduleName: 'wallet.moduleName.index',
+ amount: totalVector,
+ model: vectorModelName,
+ charsLength
+ },
+ ...(extensionModel !== undefined
+ ? [
+ {
+ moduleName: 'core.module.template.Query extension',
+ amount: extensionTotal,
+ model: extensionModelName,
+ inputTokens: extensionInputTokens,
+ outputTokens: extensionOutputTokens
+ }
+ ]
+ : [])
+ ]
+ });
+ }
+ return { total };
+};
+
+export const pushQuestionGuideBill = ({
+ inputTokens,
+ outputTokens,
+ teamId,
+ tmbId
+}: {
+ inputTokens: number;
+ outputTokens: number;
+ teamId: string;
+ tmbId: string;
+}) => {
+ const qgModel = global.llmModels[0];
+ const { total, modelName } = formatModelPrice2Store({
+ inputLen: inputTokens,
+ outputLen: outputTokens,
+ model: qgModel.model,
+ type: ModelTypeEnum.llm
+ });
+
+ createBill({
+ teamId,
+ tmbId,
+ appName: 'wallet.bill.Next Step Guide',
+ total,
+ source: BillSourceEnum.fastgpt,
+ list: [
+ {
+ moduleName: 'wallet.bill.Next Step Guide',
+ amount: total,
+ model: modelName,
+ inputTokens,
+ outputTokens
+ }
+ ]
+ });
+};
+
+export function pushAudioSpeechBill({
+ appName = 'wallet.bill.Audio Speech',
+ model,
+ charsLength,
+ teamId,
+ tmbId,
+ source = BillSourceEnum.fastgpt
+}: {
+ appName?: string;
+ model: string;
+ charsLength: number;
+ teamId: string;
+ tmbId: string;
+ source: `${BillSourceEnum}`;
+}) {
+ const { total, modelName } = formatModelPrice2Store({
+ model,
+ inputLen: charsLength,
+ type: ModelTypeEnum.audioSpeech
+ });
+
+ createBill({
+ teamId,
+ tmbId,
+ appName,
+ total,
+ source,
+ list: [
+ {
+ moduleName: appName,
+ amount: total,
+ model: modelName,
+ charsLength
+ }
+ ]
+ });
+}
+
+export function pushWhisperBill({
+ teamId,
+ tmbId,
+ duration
+}: {
+ teamId: string;
+ tmbId: string;
+ duration: number;
+}) {
+ const whisperModel = global.whisperModel;
+
+ if (!whisperModel) return;
+
+ const { total, modelName } = formatModelPrice2Store({
+ model: whisperModel.model,
+ inputLen: duration,
+ type: ModelTypeEnum.whisper,
+ multiple: 60
+ });
+
+ const name = 'wallet.bill.Whisper';
+
+ createBill({
+ teamId,
+ tmbId,
+ appName: name,
+ total,
+ source: BillSourceEnum.fastgpt,
+ list: [
+ {
+ moduleName: name,
+ amount: total,
+ model: modelName,
+ duration
+ }
+ ]
+ });
+}
+
+export function pushReRankBill({
+ teamId,
+ tmbId,
+ source,
+ inputs
+}: {
+ teamId: string;
+ tmbId: string;
+ source: `${BillSourceEnum}`;
+ inputs: PostReRankProps['inputs'];
+}) {
+ const reRankModel = global.reRankModels[0];
+ if (!reRankModel) return { total: 0 };
+
+ const charsLength = inputs.reduce((sum, item) => sum + item.text.length, 0);
+
+ const { total, modelName } = formatModelPrice2Store({
+ model: reRankModel.model,
+ inputLen: charsLength,
+ type: ModelTypeEnum.rerank
+ });
+ const name = 'wallet.bill.ReRank';
+
+ createBill({
+ teamId,
+ tmbId,
+ appName: name,
+ total,
+ source,
+ list: [
+ {
+ moduleName: name,
+ amount: total,
+ model: modelName,
+ charsLength
+ }
+ ]
+ });
+
+ return { total };
+}
diff --git a/projects/app/src/service/support/wallet/bill/utils.ts b/projects/app/src/service/support/wallet/bill/utils.ts
new file mode 100644
index 000000000..d880ce76e
--- /dev/null
+++ b/projects/app/src/service/support/wallet/bill/utils.ts
@@ -0,0 +1,54 @@
+import { ModelTypeEnum, getModelMap } from '@/service/core/ai/model';
+import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
+import { BillSourceEnum, PRICE_SCALE } from '@fastgpt/global/support/wallet/bill/constants';
+
+export function authType2BillSource({
+ authType,
+ shareId,
+ source
+}: {
+ authType?: `${AuthUserTypeEnum}`;
+ shareId?: string;
+ source?: `${BillSourceEnum}`;
+}) {
+ if (source) return source;
+ if (shareId) return BillSourceEnum.shareLink;
+ if (authType === AuthUserTypeEnum.apikey) return BillSourceEnum.api;
+ return BillSourceEnum.fastgpt;
+}
+
+export const formatModelPrice2Store = ({
+ model,
+ inputLen = 0,
+ outputLen = 0,
+ type,
+ multiple = 1000
+}: {
+ model: string;
+ inputLen: number;
+ outputLen?: number;
+ type: `${ModelTypeEnum}`;
+ multiple?: number;
+}) => {
+ const modelData = getModelMap?.[type]?.(model);
+ if (!modelData)
+ return {
+ inputTotal: 0,
+ outputTotal: 0,
+ total: 0,
+ modelName: ''
+ };
+ const inputTotal = modelData.inputPrice
+ ? Math.ceil(modelData.inputPrice * (inputLen / multiple) * PRICE_SCALE)
+ : 0;
+ const outputTotal = modelData.outputPrice
+ ? Math.ceil(modelData.outputPrice * (outputLen / multiple) * PRICE_SCALE)
+ : 0;
+
+ return {
+ modelName: modelData.name,
+ inputTotal: inputTotal,
+ outputTotal: outputTotal,
+ total: inputTotal + outputTotal
+ };
+};
diff --git a/projects/app/src/service/support/wallet/usage/controller.ts b/projects/app/src/service/support/wallet/usage/controller.ts
deleted file mode 100644
index ba287cef1..000000000
--- a/projects/app/src/service/support/wallet/usage/controller.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { ConcatUsageProps, CreateUsageProps } from '@fastgpt/global/support/wallet/usage/api';
-import { addLog } from '@fastgpt/service/common/system/log';
-import { POST } from '@fastgpt/service/common/api/plusRequest';
-import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
-
-export function createUsage(data: CreateUsageProps) {
- if (!FastGPTProUrl) return;
- if (data.totalPoints === 0) {
- addLog.info('0 totalPoints', data);
- }
- try {
- POST('/support/wallet/usage/createUsage', data);
- } catch (error) {}
-}
-export function concatUsage(data: ConcatUsageProps) {
- if (!FastGPTProUrl) return;
- if (data.totalPoints === 0) {
- addLog.info('0 totalPoints', data);
- }
- try {
- POST('/support/wallet/usage/concatUsage', data);
- } catch (error) {}
-}
diff --git a/projects/app/src/service/support/wallet/usage/push.ts b/projects/app/src/service/support/wallet/usage/push.ts
deleted file mode 100644
index edf34a939..000000000
--- a/projects/app/src/service/support/wallet/usage/push.ts
+++ /dev/null
@@ -1,274 +0,0 @@
-import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
-import { ModelTypeEnum } from '@/service/core/ai/model';
-import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type.d';
-import { addLog } from '@fastgpt/service/common/system/log';
-import { createUsage, concatUsage } from './controller';
-import { formatModelChars2Points } from '@/service/support/wallet/usage/utils';
-import { ChatModuleBillType } from '@fastgpt/global/support/wallet/bill/type';
-
-export const pushChatUsage = ({
- appName,
- appId,
- teamId,
- tmbId,
- source,
- moduleDispatchBills
-}: {
- appName: string;
- appId: string;
- teamId: string;
- tmbId: string;
- source: `${UsageSourceEnum}`;
- moduleDispatchBills: ChatModuleBillType[];
-}) => {
- const totalPoints = moduleDispatchBills.reduce((sum, item) => sum + (item.totalPoints || 0), 0);
-
- createUsage({
- teamId,
- tmbId,
- appName,
- appId,
- totalPoints,
- source,
- list: moduleDispatchBills.map((item) => ({
- moduleName: item.moduleName,
- amount: item.totalPoints || 0,
- model: item.model,
- charsLength: item.charsLength
- }))
- });
- addLog.info(`finish completions`, {
- source,
- teamId,
- tmbId,
- totalPoints
- });
- return { totalPoints };
-};
-
-export const pushQAUsage = async ({
- teamId,
- tmbId,
- model,
- charsLength,
- billId
-}: {
- teamId: string;
- tmbId: string;
- model: string;
- charsLength: number;
- billId: string;
-}) => {
- // 计算价格
- const { totalPoints } = formatModelChars2Points({
- model,
- modelType: ModelTypeEnum.llm,
- charsLength
- });
-
- concatUsage({
- billId,
- teamId,
- tmbId,
- totalPoints,
- charsLength,
- listIndex: 1
- });
-
- return { totalPoints };
-};
-
-export const pushGenerateVectorUsage = ({
- billId,
- teamId,
- tmbId,
- charsLength,
- model,
- source = UsageSourceEnum.fastgpt,
- extensionModel,
- extensionCharsLength
-}: {
- billId?: string;
- teamId: string;
- tmbId: string;
- charsLength: number;
- model: string;
- source?: `${UsageSourceEnum}`;
-
- extensionModel?: string;
- extensionCharsLength?: number;
-}) => {
- const { totalPoints: totalVector, modelName: vectorModelName } = formatModelChars2Points({
- modelType: ModelTypeEnum.vector,
- model,
- charsLength
- });
-
- const { extensionTotalPoints, extensionModelName } = (() => {
- if (!extensionModel || !extensionCharsLength)
- return {
- extensionTotalPoints: 0,
- extensionModelName: ''
- };
- const { totalPoints, modelName } = formatModelChars2Points({
- modelType: ModelTypeEnum.llm,
- model: extensionModel,
- charsLength: extensionCharsLength
- });
- return {
- extensionTotalPoints: totalPoints,
- extensionModelName: modelName
- };
- })();
-
- const totalPoints = totalVector + extensionTotalPoints;
-
- // 插入 Bill 记录
- if (billId) {
- concatUsage({
- teamId,
- tmbId,
- totalPoints,
- billId,
- charsLength,
- listIndex: 0
- });
- } else {
- createUsage({
- teamId,
- tmbId,
- appName: 'support.wallet.moduleName.index',
- totalPoints,
- source,
- list: [
- {
- moduleName: 'support.wallet.moduleName.index',
- amount: totalVector,
- model: vectorModelName,
- charsLength
- },
- ...(extensionModel !== undefined
- ? [
- {
- moduleName: 'core.module.template.Query extension',
- amount: extensionTotalPoints,
- model: extensionModelName,
- charsLength: extensionCharsLength
- }
- ]
- : [])
- ]
- });
- }
- return { totalPoints };
-};
-
-export const pushQuestionGuideUsage = ({
- charsLength,
- teamId,
- tmbId
-}: {
- charsLength: number;
- teamId: string;
- tmbId: string;
-}) => {
- const qgModel = global.llmModels[0];
- const { totalPoints, modelName } = formatModelChars2Points({
- charsLength,
- model: qgModel.model,
- modelType: ModelTypeEnum.llm
- });
-
- createUsage({
- teamId,
- tmbId,
- appName: 'core.app.Next Step Guide',
- totalPoints,
- source: UsageSourceEnum.fastgpt,
- list: [
- {
- moduleName: 'core.app.Next Step Guide',
- amount: totalPoints,
- model: modelName,
- charsLength
- }
- ]
- });
-};
-
-export function pushAudioSpeechUsage({
- appName = 'support.wallet.bill.Audio Speech',
- model,
- charsLength,
- teamId,
- tmbId,
- source = UsageSourceEnum.fastgpt
-}: {
- appName?: string;
- model: string;
- charsLength: number;
- teamId: string;
- tmbId: string;
- source: `${UsageSourceEnum}`;
-}) {
- const { totalPoints, modelName } = formatModelChars2Points({
- model,
- charsLength,
- modelType: ModelTypeEnum.audioSpeech
- });
-
- createUsage({
- teamId,
- tmbId,
- appName,
- totalPoints,
- source,
- list: [
- {
- moduleName: appName,
- amount: totalPoints,
- model: modelName,
- charsLength
- }
- ]
- });
-}
-
-export function pushWhisperUsage({
- teamId,
- tmbId,
- duration
-}: {
- teamId: string;
- tmbId: string;
- duration: number;
-}) {
- const whisperModel = global.whisperModel;
-
- if (!whisperModel) return;
-
- const { totalPoints, modelName } = formatModelChars2Points({
- model: whisperModel.model,
- charsLength: duration,
- modelType: ModelTypeEnum.whisper,
- multiple: 60
- });
-
- const name = 'support.wallet.bill.Whisper';
-
- createUsage({
- teamId,
- tmbId,
- appName: name,
- totalPoints,
- source: UsageSourceEnum.fastgpt,
- list: [
- {
- moduleName: name,
- amount: totalPoints,
- model: modelName,
- duration
- }
- ]
- });
-}
diff --git a/projects/app/src/service/support/wallet/usage/utils.ts b/projects/app/src/service/support/wallet/usage/utils.ts
deleted file mode 100644
index 00f655c5c..000000000
--- a/projects/app/src/service/support/wallet/usage/utils.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { ModelTypeEnum, getModelMap } from '@/service/core/ai/model';
-import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
-import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
-
-export function authType2UsageSource({
- authType,
- shareId,
- source
-}: {
- authType?: `${AuthUserTypeEnum}`;
- shareId?: string;
- source?: `${UsageSourceEnum}`;
-}) {
- if (source) return source;
- if (shareId) return UsageSourceEnum.shareLink;
- if (authType === AuthUserTypeEnum.apikey) return UsageSourceEnum.api;
- return UsageSourceEnum.fastgpt;
-}
-
-export const formatModelChars2Points = ({
- model,
- charsLength = 0,
- modelType,
- multiple = 1000
-}: {
- model: string;
- charsLength: number;
- modelType: `${ModelTypeEnum}`;
- multiple?: number;
-}) => {
- const modelData = getModelMap?.[modelType]?.(model);
- if (!modelData)
- return {
- totalPoints: 0,
- modelName: ''
- };
-
- const totalPoints = (modelData.charsPointsPrice || 0) * (charsLength / multiple);
-
- return {
- modelName: modelData.name,
- totalPoints
- };
-};
diff --git a/projects/app/src/service/utils/chat/saveChat.ts b/projects/app/src/service/utils/chat/saveChat.ts
index 0872dccf0..f80c1a69c 100644
--- a/projects/app/src/service/utils/chat/saveChat.ts
+++ b/projects/app/src/service/utils/chat/saveChat.ts
@@ -5,7 +5,6 @@ import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
import { addLog } from '@fastgpt/service/common/system/log';
import { chatContentReplaceBlock } from '@fastgpt/global/core/chat/utils';
-import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
type Props = {
chatId: string;
@@ -47,54 +46,61 @@ export async function saveChat({
...chat?.metadata,
...metadata
};
- const title =
- chatContentReplaceBlock(content[0].value).slice(0, 20) ||
- content[1]?.value?.slice(0, 20) ||
- 'Chat';
- await mongoSessionRun(async (session) => {
- await MongoChatItem.insertMany(
+ const promise: any[] = [
+ MongoChatItem.insertMany(
content.map((item) => ({
chatId,
teamId,
tmbId,
appId,
...item
- })),
- { session }
- );
+ }))
+ )
+ ];
- if (chat) {
- chat.title = title;
- chat.updateTime = new Date();
- chat.metadata = metadataUpdate;
- await chat.save({ session });
- } else {
- MongoChat.create(
- [
- {
- chatId,
- teamId,
- tmbId,
- appId,
- variables,
- title,
- source,
- shareId,
- outLinkUid,
- metadata: metadataUpdate
- }
- ],
- { session }
- );
- }
- });
+ const title =
+ chatContentReplaceBlock(content[0].value).slice(0, 20) ||
+ content[1]?.value?.slice(0, 20) ||
+ 'Chat';
+
+ if (chat) {
+ promise.push(
+ MongoChat.updateOne(
+ { appId, chatId },
+ {
+ title,
+ updateTime: new Date(),
+ metadata: metadataUpdate
+ }
+ )
+ );
+ } else {
+ promise.push(
+ MongoChat.create({
+ chatId,
+ teamId,
+ tmbId,
+ appId,
+ variables,
+ title,
+ source,
+ shareId,
+ outLinkUid,
+ metadata: metadataUpdate
+ })
+ );
+ }
if (updateUseTime && source === ChatSourceEnum.online) {
- MongoApp.findByIdAndUpdate(appId, {
- updateTime: new Date()
- });
+ promise.push(
+ MongoApp.findByIdAndUpdate(appId, {
+ updateTime: new Date()
+ })
+ );
}
+
+ await Promise.all(promise);
} catch (error) {
addLog.error(`update chat history error`, error);
}
diff --git a/projects/app/src/types/i18n.d.ts b/projects/app/src/types/i18n.d.ts
index 4db8b6a81..ac61588b9 100644
--- a/projects/app/src/types/i18n.d.ts
+++ b/projects/app/src/types/i18n.d.ts
@@ -1,5 +1,5 @@
import 'i18next';
-//import common from '../../public/locales/en/common.json';
+// import common from '../../public/locales/en/common.json';
interface I18nNamespaces {
common: any;
diff --git a/projects/app/src/types/user.d.ts b/projects/app/src/types/user.d.ts
index 149496523..cad515972 100644
--- a/projects/app/src/types/user.d.ts
+++ b/projects/app/src/types/user.d.ts
@@ -1,5 +1,6 @@
-import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
+import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import type { UserModelSchema } from '@fastgpt/global/support/user/type';
+import { BillSchema } from '@fastgpt/global/support/wallet/bill/type.d';
export interface UserUpdateParams {
balance?: number;
diff --git a/projects/app/src/web/common/api/fetch.ts b/projects/app/src/web/common/api/fetch.ts
index ef1dab066..74469be56 100644
--- a/projects/app/src/web/common/api/fetch.ts
+++ b/projects/app/src/web/common/api/fetch.ts
@@ -34,7 +34,7 @@ export const streamFetch = ({
// response data
let responseText = '';
- let remainTextList: string[] = [];
+ let remainText = '';
let errMsg = '';
let responseData: ChatHistoryItemResType[] = [];
let finished = false;
@@ -60,23 +60,22 @@ export const streamFetch = ({
function animateResponseText() {
// abort message
if (abortCtrl.signal.aborted) {
- const remainText = remainTextList.join('');
onMessage({ text: remainText });
responseText += remainText;
return finish();
}
- if (remainTextList.length > 0) {
- const fetchCount = Math.max(1, Math.round(remainTextList.length / 60));
- const fetchText = remainTextList.slice(0, fetchCount).join('');
+ if (remainText) {
+ const fetchCount = Math.max(1, Math.round(remainText.length / 60));
+ const fetchText = remainText.slice(0, fetchCount);
onMessage({ text: fetchText });
responseText += fetchText;
- remainTextList = remainTextList.slice(fetchCount);
+ remainText = remainText.slice(fetchCount);
}
- if (finished && remainTextList.length === 0) {
+ if (finished && !remainText) {
return finish();
}
@@ -126,10 +125,7 @@ export const streamFetch = ({
try {
failedFinish(await res.clone().json());
} catch {
- const errText = await res.clone().text();
- if (!errText.startsWith('event: error')) {
- failedFinish();
- }
+ failedFinish(await res.clone().text());
}
}
},
@@ -149,13 +145,11 @@ export const streamFetch = ({
if (event === sseResponseEventEnum.answer) {
const text: string = parseJson?.choices?.[0]?.delta?.content || '';
-
- for (const item of text) {
- remainTextList.push(item);
- }
+ remainText += text;
} else if (event === sseResponseEventEnum.response) {
const text: string = parseJson?.choices?.[0]?.delta?.content || '';
- remainTextList.push(text);
+ onMessage({ text });
+ responseText += text;
} else if (
event === sseResponseEventEnum.moduleStatus &&
parseJson?.name &&
diff --git a/projects/app/src/web/core/app/api.ts b/projects/app/src/web/core/app/api.ts
index 72cf960a7..e60e4e08a 100644
--- a/projects/app/src/web/core/app/api.ts
+++ b/projects/app/src/web/core/app/api.ts
@@ -15,7 +15,6 @@ export const getMyApps = () => GET('/core/app/list');
*/
export const postCreateApp = (data: CreateAppParams) => POST('/core/app/create', data);
-export const getMyAppsByTags = (data: {}) => POST(`/proApi/core/chat/team/getApps`, data);
/**
* 根据 ID 删除模型
*/
@@ -31,12 +30,7 @@ export const getModelById = (id: string) => GET(`/core/app/detail
*/
export const putAppById = (id: string, data: AppUpdateParams) =>
PUT(`/core/app/update?appId=${id}`, data);
-export const replaceAppById = (id: string, data: AppUpdateParams) =>
- PUT(`/core/app/updateTeamTasg?appId=${id}`, data);
-// updateTeamTasg
-export const putAppTagsById = (id: string, data: AppUpdateParams) =>
- PUT(`/core/app/updateTeamTasg?appId=${id}`, data);
/* 共享市场 */
/**
* 获取共享市场模型
diff --git a/projects/app/src/web/core/app/store/useAppStore.ts b/projects/app/src/web/core/app/store/useAppStore.ts
index d04653ba8..2bc8c685e 100644
--- a/projects/app/src/web/core/app/store/useAppStore.ts
+++ b/projects/app/src/web/core/app/store/useAppStore.ts
@@ -1,7 +1,7 @@
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
-import { getMyApps, getModelById, putAppById, replaceAppById } from '@/web/core/app/api';
+import { getMyApps, getModelById, putAppById } from '@/web/core/app/api';
import { defaultApp } from '@/constants/app';
import type { AppUpdateParams } from '@fastgpt/global/core/app/api.d';
import { AppDetailType, AppListItemType } from '@fastgpt/global/core/app/type.d';
@@ -12,7 +12,6 @@ type State = {
appDetail: AppDetailType;
loadAppDetail: (id: string, init?: boolean) => Promise;
updateAppDetail(appId: string, data: AppUpdateParams): Promise;
- replaceAppDetail(appId: string, data: AppUpdateParams): Promise;
clearAppModules(): void;
};
@@ -48,15 +47,6 @@ export const useAppStore = create()(
};
});
},
- async replaceAppDetail(appId: string, data: AppUpdateParams) {
- await replaceAppById(appId, { ...get().appDetail, ...data });
- set((state) => {
- state.appDetail = {
- ...state.appDetail,
- ...data
- };
- });
- },
clearAppModules() {
set((state) => {
state.appDetail = {
diff --git a/projects/app/src/web/core/app/templates.ts b/projects/app/src/web/core/app/templates.ts
index b4dc367b4..804f56259 100644
--- a/projects/app/src/web/core/app/templates.ts
+++ b/projects/app/src/web/core/app/templates.ts
@@ -121,7 +121,7 @@ export const appTemplates: (AppItemType & {
},
{
key: 'model',
- type: 'selectLLMModel',
+ type: 'selectChatModel',
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
@@ -569,7 +569,7 @@ export const appTemplates: (AppItemType & {
},
{
key: 'model',
- type: 'selectLLMModel',
+ type: 'selectChatModel',
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
@@ -882,7 +882,7 @@ export const appTemplates: (AppItemType & {
},
{
key: 'model',
- type: 'selectLLMModel',
+ type: 'selectChatModel',
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
@@ -1115,7 +1115,7 @@ export const appTemplates: (AppItemType & {
},
{
key: 'model',
- type: 'selectLLMModel',
+ type: 'selectCQModel',
valueType: 'string',
label: 'core.module.input.label.Classify model',
required: true,
@@ -1345,7 +1345,7 @@ export const appTemplates: (AppItemType & {
},
{
key: 'model',
- type: 'selectLLMModel',
+ type: 'selectChatModel',
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
diff --git a/projects/app/src/web/core/chat/api.ts b/projects/app/src/web/core/chat/api.ts
index c0176b20e..601eaa009 100644
--- a/projects/app/src/web/core/chat/api.ts
+++ b/projects/app/src/web/core/chat/api.ts
@@ -1,6 +1,5 @@
import { GET, POST, DELETE, PUT } from '@/web/common/api/request';
-import type { ChatHistoryItemType, chatAppListSchema } from '@fastgpt/global/core/chat/type.d';
-
+import type { ChatHistoryItemType } from '@fastgpt/global/core/chat/type.d';
import type {
CloseCustomFeedbackParams,
InitChatProps,
@@ -17,31 +16,13 @@ import type {
} from '@/global/core/chat/api.d';
import { UpdateChatFeedbackProps } from '@fastgpt/global/core/chat/api';
-/**
- * 根据队伍ID和获取
- */
-export const getChatListById = (data: { teamId: string; authToken: string }) =>
- GET(`/proApi/core/chat/init`, data);
-
-/**
- * 获取团队分享的对话列表 initTeamChat
- * @param data
- * @returns
- */
-export const getinitTeamChat = (data: { teamId: string; authToken: string; appId: string }) =>
- GET(`/proApi/core/chat/initTeamChat`, data);
-
/**
* 获取初始化聊天内容
*/
export const getInitChatInfo = (data: InitChatProps) =>
GET(`/core/chat/init`, data);
-export const getInitChatInfoTeam = (data: InitChatProps) =>
- GET(`/core/chat/init`, data);
export const getInitOutLinkChatInfo = (data: InitOutLinkChatProps) =>
GET(`/core/chat/outLink/init`, data);
-export const getTeamChatInfo = (data: { appId: string; chatId: string; outLinkUid?: string }) =>
- GET(`/core/chat/team/init`, data);
/**
* get current window history(appid or shareId)
diff --git a/projects/app/src/web/core/chat/storeTeamChat.ts b/projects/app/src/web/core/chat/storeTeamChat.ts
deleted file mode 100644
index 82521d91b..000000000
--- a/projects/app/src/web/core/chat/storeTeamChat.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { create } from 'zustand';
-import { devtools, persist } from 'zustand/middleware';
-import { immer } from 'zustand/middleware/immer';
-import type { ChatHistoryItemType } from '@fastgpt/global/core/chat/type.d';
-import { customAlphabet } from 'nanoid';
-const nanoid = customAlphabet(
- 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ1234567890_',
- 24
-);
-
-type State = {
- localUId: string;
- teamShareChatHistory: (ChatHistoryItemType & { delete?: boolean })[];
- clearLocalHistory: (shareId?: string) => void;
-};
-
-export const useTeamShareChatStore = create()(
- devtools(
- persist(
- immer((set, get) => ({
- localUId: `shareChat-${Date.now()}-${nanoid()}`,
- teamShareChatHistory: [], // old version field
- clearLocalHistory() {
- // abandon
- set((state) => {
- state.teamShareChatHistory = state.teamShareChatHistory.map((item) => ({
- ...item,
- delete: true
- }));
- });
- }
- })),
- {
- name: 'shareChatStore',
- partialize: (state) => ({
- localUId: state.localUId,
- shareChatHistory: state.teamShareChatHistory
- })
- }
- )
- )
-);
diff --git a/projects/app/src/web/core/dataset/store/dataset.ts b/projects/app/src/web/core/dataset/store/dataset.ts
index 4f458fe9a..9084a7a66 100644
--- a/projects/app/src/web/core/dataset/store/dataset.ts
+++ b/projects/app/src/web/core/dataset/store/dataset.ts
@@ -12,7 +12,7 @@ import {
import { defaultDatasetDetail } from '@/constants/dataset';
import type { DatasetUpdateBody } from '@fastgpt/global/core/dataset/api.d';
import { DatasetStatusEnum } from '@fastgpt/global/core/dataset/constants';
-import { postCreateTrainingUsage } from '@/web/support/wallet/usage/api';
+import { postCreateTrainingBill } from '@/web/support/wallet/bill/api';
import { checkTeamWebSyncLimit } from '@/web/support/user/team/api';
type State = {
@@ -89,17 +89,19 @@ export const useDatasetStore = create()(
async startWebsiteSync() {
await checkTeamWebSyncLimit();
- const billId = await postCreateTrainingUsage({
- name: 'core.dataset.training.Website Sync',
- datasetId: get().datasetDetail._id
- });
-
- return postWebsiteSync({ datasetId: get().datasetDetail._id, billId }).then(() => {
+ const [_, billId] = await Promise.all([
get().updateDataset({
id: get().datasetDetail._id,
status: DatasetStatusEnum.syncing
- });
- });
+ }),
+ postCreateTrainingBill({
+ name: 'core.dataset.training.Website Sync',
+ datasetId: get().datasetDetail._id
+ })
+ ]);
+ try {
+ postWebsiteSync({ datasetId: get().datasetDetail._id, billId });
+ } catch (error) {}
}
})),
{
diff --git a/projects/app/src/web/core/dataset/utils.ts b/projects/app/src/web/core/dataset/utils.ts
index 6334fbad9..8bd91851f 100644
--- a/projects/app/src/web/core/dataset/utils.ts
+++ b/projects/app/src/web/core/dataset/utils.ts
@@ -68,6 +68,12 @@ export async function chunksUpload({
});
}
+ // add chunk index
+ chunks = chunks.map((chunk) => ({
+ ...chunk,
+ chunkIndex: chunk.chunkIndex
+ }));
+
let successInsert = 0;
let retryTimes = 10;
for (let i = 0; i < chunks.length; i += rate) {
diff --git a/projects/app/src/web/core/modules/template/system.ts b/projects/app/src/web/core/modules/template/system.ts
index 7370a4e0f..45f4001b5 100644
--- a/projects/app/src/web/core/modules/template/system.ts
+++ b/projects/app/src/web/core/modules/template/system.ts
@@ -13,7 +13,7 @@ import { RunAppModule } from '@fastgpt/global/core/module/template/system/runApp
import { PluginInputModule } from '@fastgpt/global/core/module/template/system/pluginInput';
import { PluginOutputModule } from '@fastgpt/global/core/module/template/system/pluginOutput';
import { RunPluginModule } from '@fastgpt/global/core/module/template/system/runPlugin';
-import { AiQueryExtension } from '@fastgpt/global/core/module/template/system/queryExtension';
+import { AiCFR } from '@fastgpt/global/core/module/template/system/coreferenceResolution';
import type {
FlowModuleTemplateType,
@@ -31,8 +31,7 @@ export const appSystemModuleTemplates: FlowModuleTemplateType[] = [
RunAppModule,
ClassifyQuestionModule,
ContextExtractModule,
- HttpModule468,
- AiQueryExtension
+ HttpModule468
];
export const pluginSystemModuleTemplates: FlowModuleTemplateType[] = [
PluginInputModule,
@@ -44,8 +43,7 @@ export const pluginSystemModuleTemplates: FlowModuleTemplateType[] = [
RunAppModule,
ClassifyQuestionModule,
ContextExtractModule,
- HttpModule468,
- AiQueryExtension
+ HttpModule468
];
export const moduleTemplatesFlat: FlowModuleTemplateType[] = [
@@ -63,7 +61,7 @@ export const moduleTemplatesFlat: FlowModuleTemplateType[] = [
PluginInputModule,
PluginOutputModule,
RunPluginModule,
- AiQueryExtension
+ AiCFR
];
export const moduleTemplatesList: moduleTemplateListType = [
diff --git a/projects/app/src/web/styles/theme.ts b/projects/app/src/web/styles/theme.ts
index e8ef45529..56debed72 100644
--- a/projects/app/src/web/styles/theme.ts
+++ b/projects/app/src/web/styles/theme.ts
@@ -217,7 +217,7 @@ const Button = defineStyleConfig({
const Input: ComponentStyleConfig = {
baseStyle: {
- fontsize: '1rem'
+ fontsize: '14px'
},
sizes: {
sm: defineStyle({
@@ -368,11 +368,12 @@ export const theme = extendTheme({
styles: {
global: {
'html, body': {
- fontSize: '14px',
color: 'myGray.900',
+ fontSize: 'md',
fontWeight: 400,
height: '100%',
overflow: 'hidden'
+ // lineHeight: 'unset'
},
a: {
color: 'primary.600'
@@ -471,16 +472,16 @@ export const theme = extendTheme({
body: 'PingFang,Noto Sans,-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"'
},
fontSizes: {
- xs: '0.8rem',
- sm: '0.93rem',
- md: '1rem',
- lg: '1.15rem',
- xl: '1.3rem',
- '2xl': '1.45rem',
- '3xl': '1.6rem',
- '4xl': '1.75rem',
- '5xl': '1.9rem',
- '6xl': '2.05rem'
+ xs: '12px',
+ sm: '13px',
+ md: '14px',
+ lg: '16px',
+ xl: '18px',
+ '2xl': '20px',
+ '3xl': '24px',
+ '4xl': '28px',
+ '5xl': '32px',
+ '6xl': '36px'
},
borders: {
sm: '1px solid #E8EBF0',
diff --git a/projects/app/src/web/support/user/team/api.ts b/projects/app/src/web/support/user/team/api.ts
index b114e0ef2..1c30a99f4 100644
--- a/projects/app/src/web/support/user/team/api.ts
+++ b/projects/app/src/web/support/user/team/api.ts
@@ -8,7 +8,6 @@ import {
UpdateTeamMemberProps,
UpdateTeamProps
} from '@fastgpt/global/support/user/team/controller.d';
-import type { TeamTagsSchema } from '@fastgpt/global/support/user/team/type';
import {
TeamItemType,
TeamMemberItemType,
@@ -24,14 +23,6 @@ export const putUpdateTeam = (data: UpdateTeamProps) =>
PUT(`/proApi/support/user/team/update`, data);
export const putSwitchTeam = (teamId: string) =>
PUT(`/proApi/support/user/team/switch`, { teamId });
-export const updateTags = (teamId: string, tagsUrl: string) =>
- POST(`/proApi/support/user/team/tags/asyncTags`, { teamId, tagsUrl });
-export const getTeamsTags = (teamId: string) =>
- GET(`/proApi/support/user/team/tags/list`, { teamId });
-export const putUpdateTeamTags = (data: any) =>
- PUT(`/proApi/support/user/team/tags/updateUrl`, data);
-export const insertTeamsTags = (tags: Array) =>
- POST(`/proApi/support/user/team/tags/create`, tags);
/* --------------- team member ---------------- */
export const getTeamMembers = (teamId: string) =>
diff --git a/projects/app/src/web/support/user/useUserStore.ts b/projects/app/src/web/support/user/useUserStore.ts
index 338f9be93..7d0109d67 100644
--- a/projects/app/src/web/support/user/useUserStore.ts
+++ b/projects/app/src/web/support/user/useUserStore.ts
@@ -3,17 +3,14 @@ import { devtools, persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
import type { UserUpdateParams } from '@/types/user';
import type { UserType } from '@fastgpt/global/support/user/type.d';
+import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import { getTokenLogin, putUserInfo } from '@/web/support/user/api';
-import { FeTeamPlanStatusType } from '@fastgpt/global/support/wallet/sub/type';
-import { getTeamPlanStatus } from '@/web/support/wallet/sub/api';
type State = {
userInfo: UserType | null;
initUserInfo: () => Promise;
setUserInfo: (user: UserType | null) => void;
updateUserInfo: (user: UserUpdateParams) => Promise;
- teamPlanStatus: FeTeamPlanStatusType | null;
- initTeamPlanStatus: () => Promise;
};
export const useUserStore = create()(
@@ -22,22 +19,19 @@ export const useUserStore = create()(
immer((set, get) => ({
userInfo: null,
async initUserInfo() {
- get().initTeamPlanStatus();
-
const res = await getTokenLogin();
get().setUserInfo(res);
- //设置html的fontsize
- const html = document?.querySelector('html');
- if (html) {
- // html.style.fontSize = '16px';
- }
-
return res;
},
setUserInfo(user: UserType | null) {
set((state) => {
- state.userInfo = user ? user : null;
+ state.userInfo = user
+ ? {
+ ...user,
+ balance: formatStorePrice2Read(user.balance)
+ }
+ : null;
});
},
async updateUserInfo(user: UserUpdateParams) {
@@ -57,15 +51,6 @@ export const useUserStore = create()(
});
return Promise.reject(error);
}
- },
- teamPlanStatus: null,
- initTeamPlanStatus() {
- return getTeamPlanStatus().then((res) => {
- set((state) => {
- state.teamPlanStatus = res;
- });
- return res;
- });
}
})),
{
diff --git a/projects/app/src/web/support/wallet/bill/api.ts b/projects/app/src/web/support/wallet/bill/api.ts
index ab4a17009..43dede5ea 100644
--- a/projects/app/src/web/support/wallet/bill/api.ts
+++ b/projects/app/src/web/support/wallet/bill/api.ts
@@ -1,22 +1,10 @@
-import { RequestPaging } from '@/types';
import { GET, POST } from '@/web/common/api/request';
-import { CreateBillProps, CreateBillResponse } from '@fastgpt/global/support/wallet/bill/api';
-import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants';
-import type { BillSchemaType } from '@fastgpt/global/support/wallet/bill/type.d';
+import { CreateTrainingBillProps } from '@fastgpt/global/support/wallet/bill/api.d';
+import type { PagingData, RequestPaging } from '@/types';
+import type { BillItemType } from '@fastgpt/global/support/wallet/bill/type';
-export const getBills = (
- data: RequestPaging & {
- type?: `${BillTypeEnum}`;
- }
-) => POST(`/proApi/support/wallet/bill/list`, data);
+export const getUserBills = (data: RequestPaging) =>
+ POST>(`/proApi/support/wallet/bill/getBill`, data);
-export const getWxPayQRCode = (data: CreateBillProps) =>
- POST(`/proApi/support/wallet/bill/create`, data);
-
-export const checkBalancePayResult = (payId: string) =>
- GET(`/proApi/support/wallet/bill/checkPayResult`, { payId }).then((data) => {
- try {
- GET('/common/system/unlockTask');
- } catch (error) {}
- return data;
- });
+export const postCreateTrainingBill = (data: CreateTrainingBillProps) =>
+ POST(`/support/wallet/bill/createTrainingBill`, data);
diff --git a/projects/app/src/web/support/wallet/pay/api.ts b/projects/app/src/web/support/wallet/pay/api.ts
new file mode 100644
index 000000000..a57c83774
--- /dev/null
+++ b/projects/app/src/web/support/wallet/pay/api.ts
@@ -0,0 +1,17 @@
+import { GET } from '@/web/common/api/request';
+import type { PaySchema } from '@fastgpt/global/support/wallet/pay/type.d';
+export const getPayOrders = () => GET(`/proApi/support/wallet/pay/getPayOrders`);
+
+export const getPayCode = (amount: number) =>
+ GET<{
+ codeUrl: string;
+ payId: string;
+ }>(`/proApi/support/wallet/pay/getPayCode`, { amount });
+
+export const checkPayResult = (payId: string) =>
+ GET(`/proApi/support/wallet/pay/checkPayResult`, { payId }).then((data) => {
+ try {
+ GET('/common/system/unlockTask');
+ } catch (error) {}
+ return data;
+ });
diff --git a/projects/app/src/web/support/wallet/sub/api.ts b/projects/app/src/web/support/wallet/sub/api.ts
index 89b1a4037..421a817f2 100644
--- a/projects/app/src/web/support/wallet/sub/api.ts
+++ b/projects/app/src/web/support/wallet/sub/api.ts
@@ -1,20 +1,30 @@
import { GET, POST, PUT, DELETE } from '@/web/common/api/request';
import {
StandardSubPlanParams,
- StandardSubPlanUpdateResponse
+ StandardSubPlanUpdateResponse,
+ SubDatasetSizeParams,
+ SubDatasetSizePreviewCheckResponse
} from '@fastgpt/global/support/wallet/sub/api';
import { SubStatusEnum, SubTypeEnum } from '@fastgpt/global/support/wallet/sub/constants';
-import { FeTeamPlanStatusType } from '@fastgpt/global/support/wallet/sub/type';
+import { FeTeamSubType } from '@fastgpt/global/support/wallet/sub/type';
export const putTeamDatasetSubStatus = (data: {
status: `${SubStatusEnum}`;
type: `${SubTypeEnum}`;
}) => POST('/proApi/support/wallet/sub/updateStatus', data);
-export const getTeamPlanStatus = () =>
- GET(`/support/wallet/sub/getTeamSubStatus`);
+export const getTeamDatasetValidSub = () =>
+ GET(`/support/wallet/sub/getTeamSubStatus`);
export const postCheckStandardSub = (data: StandardSubPlanParams) =>
POST('/proApi/support/wallet/sub/standard/preCheck', data);
export const postUpdateStandardSub = (data: StandardSubPlanParams) =>
POST('/proApi/support/wallet/sub/standard/update', data);
+
+export const posCheckTeamDatasetSizeSub = (data: SubDatasetSizeParams) =>
+ POST(
+ '/proApi/support/wallet/sub/extraDatasetSize/preCheck',
+ data
+ );
+export const postUpdateTeamDatasetSizeSub = (data: SubDatasetSizeParams) =>
+ POST('/proApi/support/wallet/sub/extraDatasetSize/update', data);
diff --git a/projects/app/src/web/support/wallet/sub/constants.ts b/projects/app/src/web/support/wallet/sub/constants.ts
deleted file mode 100644
index 483ca31ac..000000000
--- a/projects/app/src/web/support/wallet/sub/constants.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export const AI_POINT_USAGE_CARD_ROUTE = '/price#point-card';
-export const EXTRA_PLAN_CARD_ROUTE = '/price#extra-plan';
diff --git a/projects/app/src/web/support/wallet/usage/api.ts b/projects/app/src/web/support/wallet/usage/api.ts
deleted file mode 100644
index 41b32be3d..000000000
--- a/projects/app/src/web/support/wallet/usage/api.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { GET, POST } from '@/web/common/api/request';
-import { CreateTrainingUsageProps } from '@fastgpt/global/support/wallet/usage/api.d';
-import type { PagingData, RequestPaging } from '@/types';
-import type { UsageItemType } from '@fastgpt/global/support/wallet/usage/type';
-
-export const getUserUsages = (data: RequestPaging) =>
- POST>(`/proApi/support/wallet/usage/getUsage`, data);
-
-export const postCreateTrainingUsage = (data: CreateTrainingUsageProps) =>
- POST(`/support/wallet/usage/createTrainingUsage`, data);
| |