This commit is contained in:
Archer
2023-12-31 14:12:51 +08:00
committed by GitHub
parent ccca0468da
commit 9ccfda47b7
270 changed files with 8182 additions and 1295 deletions

View File

@@ -14,7 +14,7 @@ import {
import { BillItemType } from '@fastgpt/global/support/wallet/bill/type.d';
import dayjs from 'dayjs';
import { BillSourceMap } from '@fastgpt/global/support/wallet/bill/constants';
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import MyModal from '@/components/MyModal';
import { useTranslation } from 'next-i18next';
@@ -25,49 +25,107 @@ const BillDetail = ({ bill, onClose }: { bill: BillItemType; onClose: () => void
[bill.list]
);
const {
hasModel,
hasTokens,
hasInputTokens,
hasOutputTokens,
hasTextLen,
hasDuration,
hasDataLen
} = useMemo(() => {
let hasModel = false;
let hasTokens = false;
let hasInputTokens = false;
let hasOutputTokens = false;
let hasTextLen = false;
let hasDuration = false;
let hasDataLen = false;
bill.list.forEach((item) => {
if (item.model !== undefined) {
hasModel = true;
}
if (item.tokenLen !== undefined) {
hasTokens = true;
}
if (item.inputTokens !== undefined) {
hasInputTokens = true;
}
if (item.outputTokens !== undefined) {
hasOutputTokens = true;
}
if (item.textLen !== undefined) {
hasTextLen = true;
}
if (item.duration !== undefined) {
hasDuration = true;
}
if (item.dataLen !== undefined) {
hasDataLen = true;
}
});
return {
hasModel,
hasTokens,
hasInputTokens,
hasOutputTokens,
hasTextLen,
hasDuration,
hasDataLen
};
}, [bill.list]);
return (
<MyModal
isOpen={true}
onClose={onClose}
iconSrc="/imgs/modal/bill.svg"
title={t('user.Bill Detail')}
maxW={['90vw', '700px']}
>
<ModalBody>
<Flex alignItems={'center'} pb={4}>
<Box flex={'0 0 80px'}>:</Box>
<Box flex={'0 0 80px'}>{t('wallet.bill.bill username')}:</Box>
<Box>{t(bill.memberName)}</Box>
</Flex>
<Flex alignItems={'center'} pb={4}>
<Box flex={'0 0 80px'}>:</Box>
<Box flex={'0 0 80px'}>{t('wallet.bill.Number')}:</Box>
<Box>{bill.id}</Box>
</Flex>
<Flex alignItems={'center'} pb={4}>
<Box flex={'0 0 80px'}>:</Box>
<Box flex={'0 0 80px'}>{t('wallet.bill.Time')}:</Box>
<Box>{dayjs(bill.time).format('YYYY/MM/DD HH:mm:ss')}</Box>
</Flex>
<Flex alignItems={'center'} pb={4}>
<Box flex={'0 0 80px'}>:</Box>
<Box flex={'0 0 80px'}>{t('wallet.bill.App name')}:</Box>
<Box>{t(bill.appName) || '-'}</Box>
</Flex>
<Flex alignItems={'center'} pb={4}>
<Box flex={'0 0 80px'}>:</Box>
<Box flex={'0 0 80px'}>{t('wallet.bill.Source')}:</Box>
<Box>{BillSourceMap[bill.source]}</Box>
</Flex>
<Flex alignItems={'center'} pb={4}>
<Box flex={'0 0 80px'}>:</Box>
<Box flex={'0 0 80px'}>{t('wallet.bill.Total')}:</Box>
<Box fontWeight={'bold'}>{bill.total}</Box>
</Flex>
<Box pb={4}>
<Box flex={'0 0 80px'} mb={1}>
{t('wallet.bill.Bill Module')}
</Box>
<TableContainer>
<Table>
<Thead>
<Tr>
<Th></Th>
<Th>AI模型</Th>
<Th>Token长度</Th>
<Th>{t('wallet.bill.Module name')}</Th>
{hasModel && <Th>{t('wallet.bill.Ai model')}</Th>}
{hasTokens && <Th>{t('wallet.bill.Token Length')}</Th>}
{hasInputTokens && <Th>{t('wallet.bill.Input Token Length')}</Th>}
{hasOutputTokens && <Th>{t('wallet.bill.Output Token Length')}</Th>}
{hasTextLen && <Th>{t('wallet.bill.Text Length')}</Th>}
{hasDuration && <Th>{t('wallet.bill.Duration')}</Th>}
{hasDataLen && <Th>{t('wallet.bill.Data Length')}</Th>}
<Th>()</Th>
</Tr>
</Thead>
@@ -75,9 +133,15 @@ const BillDetail = ({ bill, onClose }: { bill: BillItemType; onClose: () => void
{filterBillList.map((item, i) => (
<Tr key={i}>
<Td>{t(item.moduleName)}</Td>
<Td>{item.model || '-'}</Td>
<Td>{item.tokenLen || '-'}</Td>
<Td>{formatPrice(item.amount)}</Td>
{hasModel && <Td>{item.model ?? '-'}</Td>}
{hasTokens && <Td>{item.tokenLen ?? '-'}</Td>}
{hasInputTokens && <Td>{item.inputTokens ?? '-'}</Td>}
{hasOutputTokens && <Td>{item.outputTokens ?? '-'}</Td>}
{hasTextLen && <Td>{item.textLen ?? '-'}</Td>}
{hasDuration && <Td>{item.duration ?? '-'}</Td>}
{hasDataLen && <Td>{item.dataLen ?? '-'}</Td>}
<Td>{formatStorePrice2Read(item.amount)}</Td>
</Tr>
))}
</Tbody>

View File

@@ -29,7 +29,7 @@ import MyTooltip from '@/components/MyTooltip';
import { langMap, setLngStore } from '@/web/common/utils/i18n';
import { useRouter } from 'next/router';
import MySelect from '@/components/Select';
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import { putUpdateMemberName } from '@/web/support/user/team/api';
import { getDocPath } from '@/web/common/system/doc';
@@ -239,7 +239,7 @@ const UserInfo = () => {
{t('user.team.Balance')}:&nbsp;
</Box>
<Box flex={1}>
<strong>{formatPrice(userInfo?.team?.balance).toFixed(3)}</strong>
<strong>{formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)}</strong>
</Box>
{feConfigs?.show_pay && userInfo?.team?.canWrite && (
<Button size={['sm', 'md']} ml={5} onClick={onOpenPayModal}>

View File

@@ -8,7 +8,6 @@ import { getErrText } from '@fastgpt/global/common/error/utils';
import { useTranslation } from 'next-i18next';
import Markdown from '@/components/Markdown';
import MyModal from '@/components/MyModal';
import { priceMd } from '@/web/common/system/staticData';
const PayModal = ({ onClose }: { onClose: () => void }) => {
const router = useRouter();
@@ -68,13 +67,12 @@ const PayModal = ({ onClose }: { onClose: () => void }) => {
onClose={payId ? undefined : onClose}
title={t('user.Pay')}
iconSrc="/imgs/modal/pay.svg"
isCentered={!payId}
>
<ModalBody px={0} minH={payId ? 'auto' : '70vh'} display={'flex'} flexDirection={'column'}>
<ModalBody px={0} display={'flex'} flexDirection={'column'}>
{!payId && (
<>
<Grid gridTemplateColumns={'repeat(4,1fr)'} gridGap={5} mb={4} px={6}>
{[10, 20, 50, 100].map((item) => (
<Grid gridTemplateColumns={'repeat(3,1fr)'} gridGap={5} mb={4} px={6}>
{[10, 20, 50, 100, 200, 500].map((item) => (
<Button
key={item}
variant={item === inputVal ? 'solid' : 'outline'}
@@ -84,7 +82,7 @@ const PayModal = ({ onClose }: { onClose: () => void }) => {
</Button>
))}
</Grid>
<Box mb={4} px={6}>
<Box px={6}>
<Input
value={inputVal}
type={'number'}
@@ -95,9 +93,6 @@ const PayModal = ({ onClose }: { onClose: () => void }) => {
}}
></Input>
</Box>
<Box flex={[1, '1 0 0']} overflow={'overlay'} px={6}>
<Markdown source={priceMd} />
</Box>
</>
)}
{/* 付费二维码 */}

View File

@@ -15,7 +15,7 @@ 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 { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import { useToast } from '@/web/common/hooks/useToast';
import { useLoading } from '@/web/common/hooks/useLoading';
import MyIcon from '@/components/Icon';
@@ -85,7 +85,7 @@ const PayRecordTable = () => {
<Td>
{item.createTime ? dayjs(item.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'}
</Td>
<Td>{formatPrice(item.price)}</Td>
<Td>{formatStorePrice2Read(item.price)}</Td>
<Td>{item.status}</Td>
<Td>
{item.status === 'NOTPAY' && (

View File

@@ -1,9 +1,8 @@
import React, { useCallback, useMemo, useRef } from 'react';
import { Box, Flex, useTheme } from '@chakra-ui/react';
import React, { useCallback } from 'react';
import { Box, Flex, useDisclosure, useTheme } from '@chakra-ui/react';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useRouter } from 'next/router';
import dynamic from 'next/dynamic';
import { clearToken } from '@/web/support/user/auth';
import { useUserStore } from '@/web/support/user/useUserStore';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import PageContainer from '@/components/PageContainer';
@@ -20,11 +19,13 @@ 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',
'bill' = 'bill',
'price' = 'price',
'pay' = 'pay',
'inform' = 'inform',
'apikey' = 'apikey',
@@ -50,6 +51,15 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
}
]
: []),
...(feConfigs?.isPlus && feConfigs?.show_pay
? [
{
icon: 'support/pay/priceLight',
label: t('support.user.Price'),
id: TabEnum.price
}
]
: []),
...(feConfigs?.show_promotion
? [
{
@@ -97,6 +107,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();
@@ -109,6 +124,8 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
setUserInfo(null);
router.replace('/login');
})();
} else if (tab === TabEnum.price) {
onOpenPriceBox();
} else {
router.replace({
query: {
@@ -117,7 +134,7 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
});
}
},
[openConfirm, router, setUserInfo]
[onOpenPriceBox, openConfirm, router, setUserInfo]
);
return (
@@ -169,6 +186,8 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
</Flex>
<ConfirmModal />
</PageContainer>
{isOpenPriceBox && <PriceBox onClose={onClosePriceBox} />}
</>
);
};

View File

@@ -2,11 +2,9 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { delay } from '@fastgpt/global/common/system/utils';
import { PgClient } from '@fastgpt/service/common/pg';
import {
DatasetDataIndexTypeEnum,
PgDatasetTableName
} from '@fastgpt/global/core/dataset/constant';
import { PgClient } from '@fastgpt/service/common/vectorStore/pg';
import { DatasetDataIndexTypeEnum } from '@fastgpt/global/core/dataset/constant';
import { PgDatasetTableName } from '@fastgpt/global/common/vectorStore/constants';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';

View File

@@ -2,8 +2,8 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { delay } from '@fastgpt/global/common/system/utils';
import { PgClient } from '@fastgpt/service/common/pg';
import { PgDatasetTableName } from '@fastgpt/global/core/dataset/constant';
import { PgClient } from '@fastgpt/service/common/vectorStore/pg';
import { PgDatasetTableName } from '@fastgpt/global/common/vectorStore/constants';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';

View File

@@ -13,8 +13,8 @@ import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant';
import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
import { MongoDatasetTraining } from '@fastgpt/service/core/dataset/training/schema';
import { PgClient } from '@fastgpt/service/common/pg';
import { PgDatasetTableName } from '@fastgpt/global/core/dataset/constant';
import { PgClient } from '@fastgpt/service/common/vectorStore/pg';
import { PgDatasetTableName } from '@fastgpt/global/common/vectorStore/constants';
import { MongoOutLink } from '@fastgpt/service/support/outLink/schema';
import { MongoOpenApi } from '@fastgpt/service/support/openapi/schema';
import { MongoApp } from '@fastgpt/service/core/app/schema';

View File

@@ -1,80 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { delay } from '@fastgpt/global/common/system/utils';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constant';
import { ModuleIOValueTypeEnum, ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import { ModuleItemType } from '@fastgpt/global/core/module/type';
let success = 0;
/* pg 中的数据搬到 mongo dataset.datas 中,并做映射 */
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
const { limit = 50 } = req.body as { limit: number };
await authCert({ req, authRoot: true });
await connectToDatabase();
success = 0;
console.log('total', await MongoApp.countDocuments());
await initApp(limit);
jsonRes(res, {
message: 'success'
});
} catch (error) {
console.log(error);
jsonRes(res, {
code: 500,
error
});
}
}
export async function initApp(limit = 50): Promise<any> {
try {
const apps = await MongoApp.find({ inited: false }).limit(limit);
if (apps.length === 0) return;
const result = await Promise.allSettled(
apps.map(async (app) => {
// 遍历app的modules找到 datasetSearch, 如果 rerank=true searchMode = embFullTextReRank, 否则等于embedding
const modules = JSON.parse(JSON.stringify(app.modules)) as ModuleItemType[];
modules.forEach((module) => {
if (module.flowType === FlowNodeTypeEnum.datasetSearchNode) {
module.inputs.forEach((input, i) => {
if (input.key === 'rerank') {
const val = !!input.value as boolean;
module.inputs.splice(i, 1, {
key: ModuleInputKeyEnum.datasetSearchMode,
type: FlowNodeInputTypeEnum.hidden,
label: 'core.dataset.search.Mode',
valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: false,
showTargetInPlugin: false,
value: val
? DatasetSearchModeEnum.embFullTextReRank
: DatasetSearchModeEnum.embedding
});
}
});
}
});
app.modules = modules;
app.inited = true;
await app.save();
})
);
success += result.filter((item) => item.status === 'fulfilled').length;
console.log(`success: ${success}`);
return initApp(limit);
} catch (error) {
console.log(error);
await delay(1000);
return initApp(limit);
}
}

View File

@@ -4,7 +4,7 @@ import { connectToDatabase } from '@/service/mongo';
import { delay } from '@fastgpt/global/common/system/utils';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
import { jiebaSplit } from '@/service/core/dataset/utils';
import { jiebaSplit } from '@/service/common/string/jieba';
let success = 0;
/* pg 中的数据搬到 mongo dataset.datas 中,并做映射 */

View File

@@ -4,7 +4,7 @@ import { connectToDatabase } from '@/service/mongo';
import { delay } from '@fastgpt/global/common/system/utils';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
import { jiebaSplit } from '@/service/core/dataset/utils';
import { jiebaSplit } from '@/service/common/string/jieba';
let success = 0;
/* pg 中的数据搬到 mongo dataset.datas 中,并做映射 */

View File

@@ -2,8 +2,8 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { PgClient } from '@fastgpt/service/common/pg';
import { PgDatasetTableName } from '@fastgpt/global/core/dataset/constant';
import { PgClient } from '@fastgpt/service/common/vectorStore/pg';
import { PgDatasetTableName } from '@fastgpt/global/common/vectorStore/constants';
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
import { connectToDatabase } from '@/service/mongo';

View File

@@ -4,7 +4,6 @@ import { jsonRes } from '@fastgpt/service/common/response';
import { readFileSync, readdirSync } from 'fs';
import type { InitDateResponse } from '@/global/common/api/systemRes';
import type { FastGPTConfigFileType } from '@fastgpt/global/common/system/types/index.d';
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import { getTikTokenEnc } from '@fastgpt/global/common/string/tiktoken';
import { initHttpAgent } from '@fastgpt/service/common/middle/httpAgent';
import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constants';
@@ -33,8 +32,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
requestUrl: undefined,
requestAuth: undefined
})) || [],
qgModes: global.qgModels,
whisperModel: global.whisperModel,
audioSpeechModels: global.audioSpeechModels,
priceMd: global.priceMd,
systemVersion: global.systemVersion || '0.0.0',
simpleModeTemplates: global.simpleModeTemplates
}
@@ -73,7 +73,6 @@ export async function getInitConfig() {
await getSimpleModeTemplates();
getSystemVersion();
countModelPrice();
getSystemPlugin();
console.log({
@@ -88,7 +87,6 @@ export async function getInitConfig() {
reRankModels: global.reRankModels,
audioSpeechModels: global.audioSpeechModels,
whisperModel: global.whisperModel,
price: global.priceMd,
simpleModeTemplates: global.simpleModeTemplates,
communityPlugins: global.communityPlugins
});
@@ -123,22 +121,20 @@ export async function initSystemConfig() {
// set config
global.feConfigs = {
isPlus: !!config.systemEnv.pluginBaseUrl,
isPlus: !!config.systemEnv?.pluginBaseUrl,
...config.feConfigs
};
global.systemEnv = config.systemEnv;
global.chatModels = config.chatModels || [];
global.qaModels = config.qaModels || [];
global.cqModels = config.cqModels || [];
global.extractModels = config.extractModels || [];
global.qgModels = config.qgModels || [];
global.vectorModels = config.vectorModels || [];
global.reRankModels = config.reRankModels || [];
global.audioSpeechModels = config.audioSpeechModels || [];
global.chatModels = config.chatModels;
global.qaModels = config.qaModels;
global.cqModels = config.cqModels;
global.extractModels = config.extractModels;
global.qgModels = config.qgModels;
global.vectorModels = config.vectorModels;
global.reRankModels = config.reRankModels;
global.audioSpeechModels = config.audioSpeechModels;
global.whisperModel = config.whisperModel;
global.priceMd = '';
}
export function initGlobal() {
@@ -168,38 +164,6 @@ export function getSystemVersion() {
}
}
export function countModelPrice() {
global.priceMd = `| 计费项 | 价格: 元/ 1K tokens(包含上下文)|
| --- | --- |
${global.vectorModels
?.map((item) => `| 索引-${item.name} | ${formatPrice(item.price, 1000)} |`)
.join('\n')}
${global.chatModels
?.map((item) => `| 对话-${item.name} | ${formatPrice(item.price, 1000)} |`)
.join('\n')}
${global.qaModels
?.map((item) => `| 文件QA拆分-${item.name} | ${formatPrice(item.price, 1000)} |`)
.join('\n')}
${global.cqModels
?.map((item) => `| 问题分类-${item.name} | ${formatPrice(item.price, 1000)} |`)
.join('\n')}
${global.extractModels
?.map((item) => `| 内容提取-${item.name} | ${formatPrice(item.price, 1000)} |`)
.join('\n')}
${global.qgModels
?.map((item) => `| 下一步指引-${item.name} | ${formatPrice(item.price, 1000)} |`)
.join('\n')}
${global.audioSpeechModels
?.map((item) => `| 语音播放-${item.name} | ${formatPrice(item.price, 1000)} |`)
.join('\n')}
${
global.whisperModel
? `| 语音输入-${global.whisperModel.name} | ${global.whisperModel.price}/分钟 |`
: ''
}
`;
}
async function getSimpleModeTemplates() {
if (global.simpleModeTemplates && global.simpleModeTemplates.length > 0) return;

View File

@@ -2,14 +2,13 @@ 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 { countModelPrice, initSystemConfig } from './getInitData';
import { initSystemConfig } from './getInitData';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
await connectToDatabase();
await authCert({ req, authRoot: true });
await initSystemConfig();
countModelPrice();
console.log(`refresh config`);
console.log({
@@ -23,8 +22,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
vectorModels: global.vectorModels,
reRankModels: global.reRankModels,
audioSpeechModels: global.audioSpeechModels,
whisperModel: global.whisperModel,
price: global.priceMd
whisperModel: global.whisperModel
});
} catch (error) {
console.log(error);

View File

@@ -19,7 +19,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const qgModel = global.qgModels[0];
const { result, tokens } = await createQuestionGuide({
const { result, inputTokens, outputTokens } = await createQuestionGuide({
messages,
model: qgModel.model
});
@@ -29,7 +29,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
});
pushQuestionGuideBill({
tokens: tokens,
inputTokens,
outputTokens,
teamId,
tmbId
});

View File

@@ -374,11 +374,21 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
{
key: 'searchMode',
type: 'hidden',
label: 'core.dataset.search.Mode',
label: '',
valueType: 'string',
showTargetInApp: false,
showTargetInPlugin: false,
value: DatasetSearchModeEnum.embFullTextReRank,
value: DatasetSearchModeEnum.mixedRecall,
connected: false
},
{
key: 'usingReRank',
type: 'hidden',
label: '',
valueType: 'string',
showTargetInApp: false,
showTargetInPlugin: false,
value: true,
connected: false
},
{

View File

@@ -377,6 +377,16 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
value: formData.dataset.searchMode,
connected: false
},
{
key: 'usingReRank',
type: 'hidden',
label: '',
valueType: 'string',
showTargetInApp: false,
showTargetInPlugin: false,
value: formData.dataset.usingReRank,
connected: false
},
{
key: 'datasetParamsModal',
type: 'selectDatasetParamsModal',

View File

@@ -56,7 +56,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
try {
pushAudioSpeechBill({
model: model,
textLength: input.length,
textLen: input.length,
tmbId,
teamId,
source: authType2BillSource({ authType })

View File

@@ -6,10 +6,7 @@ import { Types } from '@fastgpt/service/common/mongo';
import type { DatasetCollectionsListItemType } from '@/global/core/dataset/type.d';
import type { GetDatasetCollectionsProps } from '@/global/core/api/datasetReq';
import { PagingData } from '@/types';
import {
DatasetColCollectionName,
MongoDatasetCollection
} from '@fastgpt/service/core/dataset/collection/schema';
import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constant';
import { startQueue } from '@/service/utils/tools';
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';

View File

@@ -69,7 +69,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
a: formatA
});
const { insertId, tokenLen } = await insertData2Dataset({
const { insertId, tokens } = await insertData2Dataset({
teamId,
tmbId,
datasetId,
@@ -84,7 +84,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
pushGenerateVectorBill({
teamId,
tmbId,
tokenLen: tokenLen,
tokens,
model: vectorModelData.model
});

View File

@@ -30,7 +30,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
// auth team balance
await authTeamBalance(teamId);
const { tokenLen } = await updateData2Dataset({
const { tokens } = await updateData2Dataset({
dataId: id,
q,
a,
@@ -38,14 +38,12 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
model: vectorModel
});
if (tokenLen) {
pushGenerateVectorBill({
teamId,
tmbId,
tokenLen: tokenLen,
model: vectorModel
});
}
pushGenerateVectorBill({
teamId,
tmbId,
tokens,
model: vectorModel
});
jsonRes(res);
} catch (err) {

View File

@@ -6,7 +6,7 @@ import { connectToDatabase } from '@/service/mongo';
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
import { authTeamBalance } from '@/service/support/permission/auth/bill';
import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
import { searchDatasetData } from '@/service/core/dataset/data/pg';
import { searchDatasetData } from '@/service/core/dataset/data/controller';
import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import { searchQueryExtension } from '@fastgpt/service/core/ai/functions/queryExtension';
@@ -14,7 +14,7 @@ import { searchQueryExtension } from '@fastgpt/service/core/ai/functions/queryEx
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
await connectToDatabase();
const { datasetId, text, limit = 20, searchMode } = req.body as SearchTestProps;
const { datasetId, text, limit = 20, searchMode, usingReRank } = req.body as SearchTestProps;
if (!datasetId || !text) {
throw new Error('缺少参数');
@@ -40,20 +40,21 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
// model: global.chatModels[0].model
// });
const { searchRes, tokenLen } = await searchDatasetData({
const { searchRes, tokens } = await searchDatasetData({
rawQuery: text,
queries: [text],
model: dataset.vectorModel,
limit: Math.min(limit * 800, 30000),
datasetIds: [datasetId],
searchMode
searchMode,
usingReRank
});
// push bill
const { total } = pushGenerateVectorBill({
teamId,
tmbId,
tokenLen: tokenLen,
tokens,
model: dataset.vectorModel,
source: apikey ? BillSourceEnum.api : BillSourceEnum.fastgpt
});

View File

@@ -3,20 +3,39 @@ import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { MongoDatasetTraining } from '@fastgpt/service/core/dataset/training/schema';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { GetTrainingQueueProps } from '@/global/core/dataset/api';
/* 拆分数据成QA */
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
await connectToDatabase();
await authCert({ req, authToken: true });
const { vectorModel, agentModel } = req.query as GetTrainingQueueProps;
// split queue data
const result = await MongoDatasetTraining.countDocuments({
lockTime: { $lt: new Date('2040/1/1') }
});
// get queue data
// 分别统计 model = vectorModel和agentModel的数量
const data = await MongoDatasetTraining.aggregate([
{
$match: {
lockTime: { $lt: new Date('2040/1/1') },
$or: [{ model: { $eq: vectorModel } }, { model: { $eq: agentModel } }]
}
},
{
$group: {
_id: '$model',
count: { $sum: 1 }
}
}
]);
const vectorTrainingCount = data.find((item) => item._id === vectorModel)?.count || 0;
const agentTrainingCount = data.find((item) => item._id === agentModel)?.count || 0;
jsonRes(res, {
data: result
data: {
vectorTrainingCount,
agentTrainingCount
}
});
} catch (err) {
jsonRes(res, {

View File

@@ -5,7 +5,7 @@ import { withNextCors } from '@fastgpt/service/common/middle/cors';
import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
import { connectToDatabase } from '@/service/mongo';
import { authTeamBalance } from '@/service/support/permission/auth/bill';
import { getVectorsByText, GetVectorProps } from '@/service/core/ai/vector';
import { getVectorsByText, GetVectorProps } from '@fastgpt/service/core/ai/embedding';
import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
import { getBillSourceByAuthType } from '@fastgpt/global/support/wallet/bill/tools';
@@ -30,7 +30,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
await authTeamBalance(teamId);
const { tokenLen, vectors } = await getVectorsByText({ input, model });
const { tokens, vectors } = await getVectorsByText({ input, model });
jsonRes(res, {
data: {
@@ -42,8 +42,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
})),
model,
usage: {
prompt_tokens: tokenLen,
total_tokens: tokenLen
prompt_tokens: tokens,
total_tokens: tokens
}
}
});
@@ -51,7 +51,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
const { total } = pushGenerateVectorBill({
teamId,
tmbId,
tokenLen,
tokens,
model,
billId,
source: getBillSourceByAuthType({ authType })

View File

@@ -42,11 +42,9 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
data: result
});
} catch (err) {
console.log(err);
jsonRes<PostReRankResponse>(res, {
data: inputs.map((input) => ({
id: input.id
}))
jsonRes(res, {
code: 500,
error: err
});
}
});

View File

@@ -4,7 +4,7 @@ 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 { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import Loading from '@/components/Loading';
import { Box } from '@chakra-ui/react';
@@ -135,7 +135,7 @@ const TokenUsage = ({ appId }: { appId: string }) => {
return `
<div>
<div>${dayjs(data.axisValue).format('YYYY/MM/DD')}</div>
<div>${formatPrice(e[0]?.value || 0)}元</div>
<div>${formatStorePrice2Read(e[0]?.value || 0)}元</div>
</div>
`;
}

View File

@@ -47,7 +47,7 @@ const Render = ({ app, onClose }: Props) => {
return <Flow templates={moduleTemplates} Header={<Header app={app} onClose={onClose} />} />;
};
export default React.memo(function AdEdit(props: Props) {
export default React.memo(function FlowEdit(props: Props) {
return (
<FlowProvider mode={'app'} filterAppIds={[props.app._id]}>
<Render {...props} />

View File

@@ -9,6 +9,7 @@ import MyIcon from '@/components/Icon';
import { useCopyData } from '@/web/common/hooks/useCopyData';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { fileToBase64 } from '@/web/common/file/utils';
import { feConfigs } from '@/web/common/system/staticData';
enum UsingWayEnum {
link = 'link',
@@ -70,7 +71,8 @@ const SelectUsingWayModal = ({ share, onClose }: { share: OutLinkSchema; onClose
setRefresh(!refresh);
});
const linkUrl = `${location?.origin}/chat/share?shareId=${share?.shareId}${
const baseUrl = feConfigs?.customSharePageDomain || location?.origin;
const linkUrl = `${baseUrl}/chat/share?shareId=${share?.shareId}${
getValues('showHistory') ? '' : '&showHistory=0'
}`;
@@ -91,7 +93,7 @@ const SelectUsingWayModal = ({ share, onClose }: { share: OutLinkSchema; onClose
[UsingWayEnum.script]: {
blockTitle: t('core.app.outLink.Script block title'),
code: `<script
src="${location?.origin}/js/iframe.js"
src="${baseUrl}/js/iframe.js"
id="chatbot-iframe"
data-bot-src="${linkUrl}"
data-default-open="${getValues('scriptDefaultOpen') ? 'true' : 'false'}"

View File

@@ -36,7 +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 { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import { OutLinkTypeEnum } from '@fastgpt/global/support/outLink/constant';
import { useTranslation } from 'next-i18next';
import { useToast } from '@/web/common/hooks/useToast';
@@ -113,7 +113,7 @@ const Share = ({ appId }: { appId: string }) => {
<Tr key={item._id}>
<Td>{item.name}</Td>
<Td>
{formatPrice(item.total)}
{formatStorePrice2Read(item.total)}
{feConfigs?.isPlus
? `${
item.limit && item.limit.credit > -1

View File

@@ -19,7 +19,6 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
import { appModules2Form, getDefaultAppForm } from '@fastgpt/global/core/app/utils';
import type { AppSimpleEditFormType } from '@fastgpt/global/core/app/type.d';
import { chatModelList, simpleModeTemplates } from '@/web/common/system/staticData';
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import { chatNodeSystemPromptTip, welcomeTextTip } from '@fastgpt/global/core/module/template/tip';
import type { ModuleItemType } from '@fastgpt/global/core/module/type';
import { useRequest } from '@/web/common/hooks/useRequest';
@@ -51,6 +50,7 @@ import VariableEdit from '@/components/core/module/Flow/components/modules/Varia
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import PromptTextarea from '@/components/common/Textarea/PromptTextarea/index';
import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constant';
import SelectAiModel from '@/components/Select/SelectAiModel';
const InfoModal = dynamic(() => import('../InfoModal'));
const DatasetSelectModal = dynamic(() => import('@/components/core/module/DatasetSelectModal'));
@@ -109,7 +109,7 @@ function ConfigForm({
const chatModelSelectList = useMemo(() => {
return chatModelList.map((item) => ({
value: item.model,
label: `${item.name} (${formatPrice(item.price, 1000)} 元/1k tokens)`
label: item.name
}));
}, [refresh]);
@@ -278,7 +278,7 @@ function ConfigForm({
<Flex alignItems={'center'} mt={5}>
<Box {...LabelStyles}>{t('core.ai.Model')}</Box>
<Box flex={'1 0 0'}>
<MySelect
<SelectAiModel
width={'100%'}
value={getValues(`aiSettings.model`)}
list={chatModelSelectList}
@@ -502,7 +502,28 @@ function ConfigForm({
)}
{isOpenDatasetParams && (
<DatasetParamsModal
{...getValues('dataset')}
// {...getValues('dataset')}
searchMode={getValues('dataset.searchMode')}
searchEmptyText={
selectSimpleTemplate?.systemForm?.dataset?.searchEmptyText
? getValues('dataset.searchEmptyText')
: undefined
}
limit={
selectSimpleTemplate?.systemForm?.dataset?.limit
? getValues('dataset.limit')
: undefined
}
similarity={
selectSimpleTemplate?.systemForm?.dataset?.similarity
? getValues('dataset.similarity')
: undefined
}
usingReRank={
selectSimpleTemplate?.systemForm?.dataset?.usingReRank
? getValues('dataset.usingReRank')
: undefined
}
maxTokens={tokenLimit}
onClose={onCloseKbParams}
onSuccess={(e) => {

View File

@@ -17,7 +17,7 @@ import { serviceSideProps } from '@/web/common/utils/i18n';
import { useAppStore } from '@/web/core/app/store/useAppStore';
import Head from 'next/head';
const AdEdit = dynamic(() => import('./components/AdEdit'), {
const FlowEdit = dynamic(() => import('./components/FlowEdit'), {
loading: () => <Loading />
});
const OutLink = dynamic(() => import('./components/OutLink'), {});
@@ -173,7 +173,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
<Box flex={'1 0 0'} h={[0, '100%']} overflow={['overlay', '']}>
{currentTab === TabEnum.simpleEdit && <SimpleEdit appId={appId} />}
{currentTab === TabEnum.adEdit && appDetail && (
<AdEdit app={appDetail} onClose={() => setCurrentTab(TabEnum.simpleEdit)} />
<FlowEdit app={appDetail} onClose={() => setCurrentTab(TabEnum.simpleEdit)} />
)}
{currentTab === TabEnum.logs && <Logs appId={appId} />}
{currentTab === TabEnum.outLink && <OutLink appId={appId} />}

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React from 'react';
import {
Box,
Flex,
@@ -8,10 +8,10 @@ import {
NumberInputStepper,
NumberIncrementStepper,
NumberDecrementStepper,
Input
Input,
Grid
} from '@chakra-ui/react';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
@@ -25,7 +25,7 @@ const ChunkImport = () => {
const { t } = useTranslation();
const { datasetDetail } = useDatasetStore();
const vectorModel = datasetDetail.vectorModel;
const unitPrice = vectorModel?.price || 0.2;
const unitPrice = vectorModel?.inputPrice || 0.002;
const {
chunkLen,
@@ -33,6 +33,7 @@ const ChunkImport = () => {
setCustomSplitChar,
successChunks,
totalChunks,
totalTokens,
isUnselectedFile,
price,
onclickUpload,
@@ -108,21 +109,27 @@ const ChunkImport = () => {
/>
</Box>
</Box>
{/* price */}
<Flex mt={4} alignItems={'center'}>
<Box>
{t('core.dataset.import.Estimated Price')}
<MyTooltip
label={t('core.dataset.import.Estimated Price Tips', {
price: formatPrice(unitPrice, 1000)
})}
forceShow
>
<QuestionOutlineIcon ml={1} />
</MyTooltip>
</Box>
<Box ml={4}>{t('common.price.Amount', { amount: price, unit: '元' })}</Box>
</Flex>
<Grid mt={4} gridTemplateColumns={'1fr 1fr'} gridGap={2}>
<Flex alignItems={'center'}>
<Box>{t('core.dataset.import.Total tokens')}</Box>
<Box>{totalTokens}</Box>
</Flex>
{/* price */}
<Flex alignItems={'center'}>
<Box>
{t('core.dataset.import.Estimated Price')}
<MyTooltip
label={t('core.dataset.import.Embedding Estimated Price Tips', {
price: unitPrice
})}
forceShow
>
<QuestionOutlineIcon ml={1} />
</MyTooltip>
</Box>
<Box ml={4}>{t('common.price.Amount', { amount: price, unit: '元' })}</Box>
</Flex>
</Grid>
<Flex mt={3}>
{showRePreview && (
<Button variant={'whitePrimary'} mr={4} onClick={onReSplitChunks}>

View File

@@ -1,8 +1,11 @@
import React from 'react';
import { Box, Flex, Button } from '@chakra-ui/react';
import { Box, Flex, Button, Grid } from '@chakra-ui/react';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { useImportStore, SelectorContainer, PreviewFileOrChunk } from './Provider';
import { useTranslation } from 'next-i18next';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
const fileExtension = '.csv';
const csvTemplate = `index,content
@@ -12,8 +15,19 @@ const csvTemplate = `index,content
const CsvImport = () => {
const { t } = useTranslation();
const { successChunks, totalChunks, isUnselectedFile, onclickUpload, uploading } =
useImportStore();
const {
successChunks,
totalChunks,
isUnselectedFile,
onclickUpload,
uploading,
totalTokens,
price
} = useImportStore();
const { datasetDetail } = useDatasetStore();
const vectorModel = datasetDetail.vectorModel;
const unitPrice = vectorModel?.inputPrice || 0.002;
const { openConfirm, ConfirmModal } = useConfirm({
content: t('core.dataset.import.Import Tip')
@@ -31,6 +45,27 @@ const CsvImport = () => {
}}
tip={t('dataset.import csv tip')}
>
<Grid mt={4} gridTemplateColumns={'1fr 1fr'} gridGap={2}>
<Flex alignItems={'center'}>
<Box>{t('core.dataset.import.Total tokens')}</Box>
<Box>{totalTokens}</Box>
</Flex>
{/* price */}
<Flex alignItems={'center'}>
<Box>
{t('core.dataset.import.Estimated Price')}
<MyTooltip
label={t('core.dataset.import.Embedding Estimated Price Tips', {
price: unitPrice
})}
forceShow
>
<QuestionOutlineIcon ml={1} />
</MyTooltip>
</Box>
<Box ml={4}>{t('common.price.Amount', { amount: price, unit: '元' })}</Box>
</Flex>
</Grid>
<Flex mt={3}>
<Button isDisabled={uploading} onClick={openConfirm(onclickUpload)}>
{uploading ? (

View File

@@ -44,32 +44,36 @@ const ImportData = ({
[ImportTypeEnum.chunk]: {
defaultChunkLen: vectorModel?.defaultToken || 500,
chunkOverlapRatio: 0.2,
unitPrice: vectorModel?.price || 0.2,
inputPrice: vectorModel?.inputPrice || 0,
outputPrice: 0,
mode: TrainingModeEnum.chunk,
collectionTrainingType: DatasetCollectionTrainingModeEnum.chunk
},
[ImportTypeEnum.qa]: {
defaultChunkLen: agentModel?.maxContext * 0.55 || 8000,
chunkOverlapRatio: 0,
unitPrice: agentModel?.price || 3,
inputPrice: agentModel?.inputPrice || 0,
outputPrice: agentModel?.outputPrice || 0,
mode: TrainingModeEnum.qa,
collectionTrainingType: DatasetCollectionTrainingModeEnum.qa
},
[ImportTypeEnum.csv]: {
defaultChunkLen: 0,
chunkOverlapRatio: 0,
unitPrice: vectorModel?.price || 0.2,
inputPrice: vectorModel?.inputPrice || 0,
outputPrice: 0,
mode: TrainingModeEnum.chunk,
collectionTrainingType: DatasetCollectionTrainingModeEnum.manual
}
};
return map[importType];
}, [
agentModel?.inputPrice,
agentModel?.maxContext,
agentModel?.price,
agentModel?.outputPrice,
importType,
vectorModel?.defaultToken,
vectorModel?.price
vectorModel?.inputPrice
]);
const TitleStyle: BoxProps = {

View File

@@ -11,7 +11,7 @@ import React, {
import FileSelect, { FileItemType, Props as FileSelectProps } from './FileSelect';
import { useRequest } from '@/web/common/hooks/useRequest';
import { postDatasetCollection } from '@/web/core/dataset/api';
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import { formatModelPrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import { splitText2Chunks } from '@fastgpt/global/common/string/textSplitter';
import { hashStr } from '@fastgpt/global/common/string/tools';
import { useToast } from '@/web/common/hooks/useToast';
@@ -43,6 +43,7 @@ type useImportStoreType = {
setSuccessChunks: Dispatch<SetStateAction<number>>;
isUnselectedFile: boolean;
totalChunks: number;
totalTokens: number;
onclickUpload: (e?: { prompt?: string }) => void;
onReSplitChunks: () => void;
price: number;
@@ -68,6 +69,7 @@ const StateContext = createContext<useImportStoreType>({
isUnselectedFile: false,
totalChunks: 0,
totalTokens: 0,
onReSplitChunks: function (): void {
throw new Error('Function not implemented.');
},
@@ -100,7 +102,8 @@ export const useImportStore = () => useContext(StateContext);
const Provider = ({
datasetId,
parentId,
unitPrice,
inputPrice,
outputPrice,
mode,
collectionTrainingType,
vectorModel,
@@ -113,7 +116,8 @@ const Provider = ({
}: {
datasetId: string;
parentId: string;
unitPrice: number;
inputPrice: number;
outputPrice: number;
mode: `${TrainingModeEnum}`;
collectionTrainingType: `${DatasetCollectionTrainingModeEnum}`;
vectorModel: string;
@@ -140,9 +144,17 @@ const Provider = ({
[files]
);
const totalTokens = useMemo(() => files.reduce((sum, file) => sum + file.tokens, 0), [files]);
const price = useMemo(() => {
return formatPrice(files.reduce((sum, file) => sum + file.tokens, 0) * unitPrice);
}, [files, unitPrice]);
if (mode === TrainingModeEnum.qa) {
const inputTotal = totalTokens * inputPrice;
const outputTotal = totalTokens * 0.5 * outputPrice;
return formatModelPrice2Read(inputTotal + outputTotal);
}
return formatModelPrice2Read(totalTokens * inputPrice);
}, [inputPrice, mode, outputPrice, totalTokens]);
/* start upload data */
const { mutate: onclickUpload, isLoading: uploading } = useRequest({
@@ -249,6 +261,7 @@ const Provider = ({
setSuccessChunks,
isUnselectedFile,
totalChunks,
totalTokens,
price,
onReSplitChunks,
onclickUpload,

View File

@@ -1,7 +1,6 @@
import React, { useState } from 'react';
import { Box, Flex, Button, Textarea } from '@chakra-ui/react';
import { Box, Flex, Button, Textarea, Grid } from '@chakra-ui/react';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { Prompt_AgentQA } from '@/global/core/prompt/agent';
@@ -15,11 +14,11 @@ const QAImport = () => {
const { t } = useTranslation();
const { datasetDetail } = useDatasetStore();
const agentModel = datasetDetail.agentModel;
const unitPrice = agentModel?.price || 3;
const {
successChunks,
totalChunks,
totalTokens,
isUnselectedFile,
price,
onclickUpload,
@@ -55,20 +54,28 @@ const QAImport = () => {
</Box>
</Box>
{/* price */}
<Flex py={5} alignItems={'center'}>
<Box>
{t('core.dataset.import.Estimated Price')}
<MyTooltip
label={t('core.dataset.import.Estimated Price Tips', {
price: formatPrice(unitPrice, 1000)
})}
forceShow
>
<QuestionOutlineIcon ml={1} />
</MyTooltip>
</Box>
<Box ml={4}>{t('common.price.Amount', { amount: price, unit: '元' })}</Box>
</Flex>
<Grid mt={4} gridTemplateColumns={'1fr 1fr'} gridGap={2}>
<Flex alignItems={'center'}>
<Box>{t('core.dataset.import.Total tokens')}</Box>
<Box>{totalTokens}</Box>
</Flex>
{/* price */}
<Flex alignItems={'center'}>
<Box>
{t('core.dataset.import.Estimated Price')}
<MyTooltip
label={t('core.dataset.import.QA Estimated Price Tips', {
inputPrice: agentModel?.inputPrice,
outputPrice: agentModel?.outputPrice
})}
forceShow
>
<QuestionOutlineIcon ml={1} />
</MyTooltip>
</Box>
<Box ml={4}>{t('common.price.Amount', { amount: price, unit: '元' })}</Box>
</Flex>
</Grid>
<Flex mt={3}>
{showRePreview && (
<Button variant={'whitePrimary'} mr={4} onClick={onReSplitChunks}>

View File

@@ -1,22 +1,12 @@
import React, { useEffect, useMemo, useState } from 'react';
import {
Box,
Textarea,
Button,
Flex,
useTheme,
Grid,
Progress,
Switch,
useDisclosure
} from '@chakra-ui/react';
import { Box, Textarea, Button, Flex, useTheme, Grid, useDisclosure } from '@chakra-ui/react';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { useSearchTestStore, SearchTestStoreItemType } from '@/web/core/dataset/store/searchTest';
import { getDatasetDataItemById, postSearchText } from '@/web/core/dataset/api';
import MyIcon from '@/components/Icon';
import { useRequest } from '@/web/common/hooks/useRequest';
import { formatTimeToChatTime } from '@/utils/tools';
import InputDataModal, { type InputDataType } from './InputDataModal';
import InputDataModal, { RawSourceText, type InputDataType } from './InputDataModal';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useToast } from '@/web/common/hooks/useToast';
@@ -45,6 +35,7 @@ const Test = ({ datasetId }: { datasetId: string }) => {
const [searchMode, setSearchMode] = useState<`${DatasetSearchModeEnum}`>(
DatasetSearchModeEnum.embedding
);
const [usingReRank, setUsingReRank] = useState(false);
const searchModeData = DatasetSearchModeMap[searchMode];
const {
@@ -59,7 +50,8 @@ const Test = ({ datasetId }: { datasetId: string }) => {
);
const { mutate, isLoading } = useRequest({
mutationFn: () => postSearchText({ datasetId, text: inputText.trim(), searchMode, limit: 30 }),
mutationFn: () =>
postSearchText({ datasetId, text: inputText.trim(), searchMode, usingReRank, limit: 20 }),
onSuccess(res: SearchTestResponse) {
if (!res || res.list.length === 0) {
return toast({
@@ -73,7 +65,8 @@ const Test = ({ datasetId }: { datasetId: string }) => {
text: inputText.trim(),
time: new Date(),
results: res.list,
duration: res.duration
duration: res.duration,
searchMode
};
pushDatasetTestItem(testItem);
setDatasetTestItem(testItem);
@@ -123,8 +116,8 @@ const Test = ({ datasetId }: { datasetId: string }) => {
variant={'unstyled'}
maxLength={datasetDetail.vectorModel.maxToken}
placeholder={t('core.dataset.test.Test Text Placeholder')}
value={inputText}
onChange={(e) => setInputText(e.target.value)}
defaultValue={inputText}
onBlur={(e) => setInputText(e.target.value)}
/>
<Flex alignItems={'center'} justifyContent={'flex-end'}>
<Box mx={3} color={'myGray.500'}>
@@ -142,8 +135,9 @@ const Test = ({ datasetId }: { datasetId: string }) => {
</Flex>
<Box mt={2}>
<Flex py={2} fontWeight={'bold'} borderBottom={theme.borders.sm}>
<Box w={'80px'}>{t('core.dataset.search.search mode')}</Box>
<Box flex={1}>{t('core.dataset.test.Test Text')}</Box>
<Box w={'80px'}>{t('common.Time')}</Box>
<Box w={'70px'}>{t('common.Time')}</Box>
<Box w={'14px'}></Box>
</Flex>
{testHistories.map((item) => (
@@ -159,12 +153,27 @@ const Test = ({ datasetId }: { datasetId: string }) => {
}
}}
cursor={'pointer'}
fontSize={'sm'}
onClick={() => setDatasetTestItem(item)}
>
<Box w={'80px'}>
{DatasetSearchModeMap[item.searchMode] ? (
<Flex alignItems={'center'}>
<MyIcon
name={DatasetSearchModeMap[item.searchMode].icon as any}
w={'12px'}
mr={'1px'}
/>
{t(DatasetSearchModeMap[item.searchMode].title)}
</Flex>
) : (
'-'
)}
</Box>
<Box flex={1} mr={2}>
{item.text}
</Box>
<Box w={'80px'}>{formatTimeToChatTime(item.time)}</Box>
<Box w={'70px'}>{formatTimeToChatTime(item.time)}</Box>
<MyTooltip label={t('core.dataset.test.delete test history')}>
<Box w={'14px'} h={'14px'}>
<MyIcon
@@ -232,7 +241,7 @@ const Test = ({ datasetId }: { datasetId: string }) => {
<Box
key={item.id}
pb={2}
borderRadius={'sm'}
borderRadius={'lg'}
border={theme.borders.base}
_notLast={{ mb: 2 }}
cursor={'pointer'}
@@ -267,12 +276,19 @@ const Test = ({ datasetId }: { datasetId: string }) => {
border={theme.borders.base}
px={2}
fontSize={'sm'}
mr={1}
mr={3}
borderRadius={'md'}
>
# {index + 1}
</Box>
<MyIcon name={'kbTest'} w={'14px'} />
<RawSourceText
fontWeight={'bold'}
color={'black'}
sourceName={item.sourceName}
sourceId={item.sourceId}
canView
/>
{/* <MyIcon name={'kbTest'} w={'14px'} />
<Progress
mx={2}
flex={'1 0 0'}
@@ -281,7 +297,7 @@ const Test = ({ datasetId }: { datasetId: string }) => {
borderRadius={'20px'}
colorScheme="gray"
/>
<Box>{item.score.toFixed(4)}</Box>
<Box>{item.score.toFixed(4)}</Box> */}
</Flex>
<Box px={2} fontSize={'xs'} color={'myGray.600'} wordBreak={'break-word'}>
<Box>{item.q}</Box>
@@ -335,9 +351,11 @@ const Test = ({ datasetId }: { datasetId: string }) => {
{isOpenSelectMode && (
<DatasetParamsModal
searchMode={searchMode}
usingReRank={usingReRank}
onClose={onCloseSelectMode}
onSuccess={(e) => {
setSearchMode(e.searchMode);
e.usingReRank !== undefined && setUsingReRank(e.usingReRank);
}}
/>
)}

View File

@@ -1,6 +1,6 @@
import React, { useCallback } from 'react';
import React, { useCallback, useMemo } from 'react';
import { useRouter } from 'next/router';
import { Box, Flex, IconButton, useTheme } from '@chakra-ui/react';
import { Box, Flex, IconButton, useTheme, Progress } from '@chakra-ui/react';
import { useToast } from '@/web/common/hooks/useToast';
import { useQuery } from '@tanstack/react-query';
import { getErrText } from '@fastgpt/global/common/error/utils';
@@ -92,9 +92,55 @@ const Detail = ({ datasetId, currentTab }: { datasetId: string; currentTab: `${T
}
});
const { data: trainingQueueLen = 0 } = useQuery(['getTrainingQueueLen'], getTrainingQueueLen, {
refetchInterval: 10000
});
const { data: { vectorTrainingCount = 0, agentTrainingCount = 0 } = {} } = useQuery(
['getTrainingQueueLen'],
() =>
getTrainingQueueLen({
vectorModel: datasetDetail.vectorModel.model,
agentModel: datasetDetail.agentModel.model
}),
{
refetchInterval: 10000
}
);
const { vectorTrainingMap, agentTrainingMap } = useMemo(() => {
const vectorTrainingMap = (() => {
if (vectorTrainingCount < 1000)
return {
colorSchema: 'green',
tip: t('core.dataset.training.Leisure')
};
if (vectorTrainingCount < 10000)
return {
colorSchema: 'yellow',
tip: t('core.dataset.training.Waiting')
};
return {
colorSchema: 'red',
tip: t('core.dataset.training.Full')
};
})();
const agentTrainingMap = (() => {
if (agentTrainingCount < 100)
return {
colorSchema: 'green',
tip: t('core.dataset.training.Leisure')
};
if (agentTrainingCount < 1000)
return {
colorSchema: 'yellow',
tip: t('core.dataset.training.Waiting')
};
return {
colorSchema: 'red',
tip: t('core.dataset.training.Full')
};
})();
return {
vectorTrainingMap,
agentTrainingMap
};
}, [agentTrainingCount, t, vectorTrainingCount]);
return (
<>
@@ -155,19 +201,32 @@ const Detail = ({ datasetId, currentTab }: { datasetId: string; currentTab: `${T
setCurrentTab(e);
}}
/>
<Box textAlign={'center'}>
<Flex justifyContent={'center'} alignItems={'center'}>
<MyIcon mr={1} name="overviewLight" w={'16px'} color={'green.500'} />
<Box>{t('dataset.System Data Queue')}</Box>
<MyTooltip
label={t('dataset.Queue Desc', { title: feConfigs?.systemTitle })}
placement={'top'}
>
<QuestionOutlineIcon ml={1} w={'16px'} />
</MyTooltip>
</Flex>
<Box mt={1} fontWeight={'bold'}>
{trainingQueueLen}
<Box>
<Box mb={3}>
<Box fontSize={'sm'}>
{t('core.dataset.training.Agent queue')}({agentTrainingMap.tip})
</Box>
<Progress
value={100}
size={'xs'}
colorScheme={agentTrainingMap.colorSchema}
borderRadius={'10px'}
isAnimated
hasStripe
/>
</Box>
<Box mb={3}>
<Box fontSize={'sm'}>
{t('core.dataset.training.Vector queue')}({vectorTrainingMap.tip})
</Box>
<Progress
value={100}
size={'xs'}
colorScheme={vectorTrainingMap.colorSchema}
borderRadius={'10px'}
isAnimated
hasStripe
/>
</Box>
</Box>
<Flex

View File

@@ -1,5 +1,5 @@
import React, { useState, Dispatch, useCallback } from 'react';
import { FormControl, Box, Input, Button, FormErrorMessage, Flex } from '@chakra-ui/react';
import { FormControl, Box, Input, Button } from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
import { PageTypeEnum } from '@/constants/user';
import { postFindPassword } from '@/web/support/user/api';
@@ -76,7 +76,14 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
<Box fontWeight={'bold'} fontSize={'2xl'} textAlign={'center'}>
{feConfigs?.systemTitle}
</Box>
<Box mt={'42px'}>
<Box
mt={'42px'}
onKeyDown={(e) => {
if (e.keyCode === 13 && !e.shiftKey && !requesting) {
handleSubmit(onclickFindPassword)();
}
}}
>
<FormControl isInvalid={!!errors.username}>
<Input
bg={'myGray.50'}

View File

@@ -124,7 +124,14 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
{feConfigs?.systemTitle}
</Box>
</Flex>
<Box mt={'42px'}>
<Box
mt={'42px'}
onKeyDown={(e) => {
if (e.keyCode === 13 && !e.shiftKey && !requesting) {
handleSubmit(onclickLogin)();
}
}}
>
<FormControl isInvalid={!!errors.username}>
<Input
bg={'myGray.50'}
@@ -197,7 +204,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
</>
)}
{/* oauth */}
{feConfigs?.show_register && (
{feConfigs?.show_register && oAuthList.length > 0 && (
<>
<Box mt={'80px'} position={'relative'}>
<Divider />

View File

@@ -90,7 +90,14 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
<Box fontWeight={'bold'} fontSize={'2xl'} textAlign={'center'}>
{feConfigs?.systemTitle}
</Box>
<Box mt={'42px'}>
<Box
mt={'42px'}
onKeyDown={(e) => {
if (e.keyCode === 13 && !e.shiftKey && !requesting) {
handleSubmit(onclickRegister)();
}
}}
>
<FormControl isInvalid={!!errors.username}>
<Input
bg={'myGray.50'}

View File

@@ -85,7 +85,7 @@ const Render = ({ pluginId }: Props) => {
);
};
export default function AdEdit(props: any) {
export default function FlowEdit(props: any) {
return (
<FlowProvider mode={'plugin'} filterAppIds={[]}>
<Render {...props} />