V4.9.2 feature (#4354)
* feat: custom dataset split sign (#4221) * feat: custom dataset split sign * feat: custom dataset split sign * add external variable debug (#4204) * add external variable debug * fix ui * plugin variables * perf: custom varialbe (#4225) * fix: invite link (#4229) * fix: invite link * feat: create invite link and copy it directly * feat: sync api collection will refresh title;perf: invite link ux (#4237) * update queue * feat: sync api collection will refresh title * sync collection * remove lock * perf: invite link ux * fix ts (#4239) * sync collection * remove lock * fix ts * fix: ts * Sso (#4235) * feat: redirect url can be inner url (#4138) * fix: update new user sync api (#4145) * feat: post all params to backend (#4151) * pref: sso getauthurl api (#4172) * pref: sso getauthurl api * pref: sso * solve the rootorglist (#4234) --------- Co-authored-by: gggaaallleee <91131304+gggaaallleee@users.noreply.github.com> * fix variable sync & popover button height (#4227) * fix variable sync & popover button height * required * feat: node prompt version (#4141) * feat: node prompt version * fix * delete unused code * fix * fix code * update prompt version (#4242) * sync collection * remove lock * update prompt version * perf: ai proxy (#4265) * sync collection * remove lock * perf: ai proxy * fix: member count (#4269) * feat: chunk index independent config (#4271) * sync collection * remove lock * feat: chunk index independent config * feat: add max chunksize to split chunk function * remove log * update doc * remove * remove log * fix input form label overflow (#4266) * add model test log (#4272) * sync collection * remove lock * add model test log * update ui * update log * fix: channel test * preview chunk ui * test model ux * test model log * perf: dataset selector * fix: system plugin auth * update nextjs * perf: ai proxy log remove retry log;perf: workflow type auto parse;add chunk spliter test (#4296) * sync collection * remove lock * perf: workflow type auto parse * add chunk spliter test * perf: ai proxy log remove retry log * udpate ai proxy field * pref: member/org/gourp list (#4295) * refactor: org api * refactor: org api * pref: member/org/group list * feat: change group owner api * fix: manage org member * pref: member search * tmp org api rewrite (#4304) * sync collection * remove lock * tmp org api rewrite * perf: text splitter (#4313) * sync collection * remove lock * perf: text splitter * update comment * update search filter code (#4317) * sync collection * remove lock * update search filter code * pref: member/group/org (#4316) * feat: change group owner api * pref: member/org/group * fix: member modal select clb * fix: search member when change owner * fix: member list, login button (#4322) * perf: member group (#4324) * sync collection * remove lock * perf: member group * fix: ts (#4325) * sync collection * remove lock * fix: ts * fix: group (#4330) * perf: intro wrap (#4346) * sync collection * remove lock * perf: intro wrap * pref: member list (#4344) * chore: search member new api * chore: permission * fix: ts error * fix: member modal * perf: long org name ui (#4347) * sync collection * remove lock * perf: long org name ui * perf: member tableui (#4353) * fix: ts (#4357) * docs: Add SSO Markdown Doc (#4334) * add sso doc * fix comment * update sso doc (#4358) * pref: useScrollPagination support debounce and throttle. (#4355) * pref: useScrollPagination support debounce and throttle. * fix: useScrollPagination loading * fix: isloading * fix: org search path hide * fix: simple app all_app button (#4365) * add qwen long (#4363) --------- Co-authored-by: heheer <heheer@sealos.io> Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com> Co-authored-by: gggaaallleee <91131304+gggaaallleee@users.noreply.github.com>
This commit is contained in:
@@ -294,7 +294,7 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
|
||||
title={t('account_info:click_modify_nickname')}
|
||||
borderColor={'transparent'}
|
||||
transform={'translateX(-11px)'}
|
||||
maxLength={20}
|
||||
maxLength={100}
|
||||
onBlur={async (e) => {
|
||||
const val = e.target.value;
|
||||
if (val === userInfo?.team?.memberName) return;
|
||||
|
||||
@@ -48,7 +48,7 @@ const Team = () => {
|
||||
const { t } = useTranslation();
|
||||
const { userInfo } = useUserStore();
|
||||
|
||||
const { setEditTeamData, isLoading, teamSize } = useContextSelector(TeamContext, (v) => v);
|
||||
const { setEditTeamData, teamSize } = useContextSelector(TeamContext, (v) => v);
|
||||
|
||||
const Tabs = useMemo(
|
||||
() => (
|
||||
@@ -75,7 +75,7 @@ const Team = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<AccountContainer isLoading={isLoading}>
|
||||
<AccountContainer>
|
||||
<Flex h={'100%'} flexDirection={'column'}>
|
||||
{/* header */}
|
||||
<Flex
|
||||
|
||||
@@ -35,11 +35,17 @@ async function handler(
|
||||
|
||||
if (!modelData) return Promise.reject('Model not found');
|
||||
|
||||
if (channelId) {
|
||||
delete modelData.requestUrl;
|
||||
delete modelData.requestAuth;
|
||||
}
|
||||
|
||||
const headers: Record<string, string> = channelId
|
||||
? {
|
||||
'Aiproxy-Channel': String(channelId)
|
||||
}
|
||||
: {};
|
||||
addLog.debug(`Test model`, modelData);
|
||||
|
||||
if (modelData.type === 'llm') {
|
||||
return testLLMModel(modelData, headers);
|
||||
@@ -63,10 +69,6 @@ async function handler(
|
||||
export default NextAPI(handler);
|
||||
|
||||
const testLLMModel = async (model: LLMModelItemType, headers: Record<string, string>) => {
|
||||
const ai = getAIApi({
|
||||
timeout: 10000
|
||||
});
|
||||
|
||||
const requestBody = llmCompletionsBodyFormat(
|
||||
{
|
||||
model: model.model,
|
||||
@@ -75,6 +77,7 @@ const testLLMModel = async (model: LLMModelItemType, headers: Record<string, str
|
||||
},
|
||||
model
|
||||
);
|
||||
|
||||
const { response, isStreamResponse } = await createChatCompletion({
|
||||
body: requestBody,
|
||||
options: {
|
||||
@@ -144,7 +147,7 @@ const testTTSModel = async (model: TTSModelType, headers: Record<string, string>
|
||||
const testSTTModel = async (model: STTModelType, headers: Record<string, string>) => {
|
||||
const path = isProduction ? '/app/data/test.mp3' : 'data/test.mp3';
|
||||
const { text } = await aiTranscriptions({
|
||||
model: model.model,
|
||||
model,
|
||||
fileStream: fs.createReadStream(path),
|
||||
headers
|
||||
});
|
||||
|
||||
@@ -41,7 +41,7 @@ async function handler(req: NextApiRequest): CreateCollectionResponse {
|
||||
return Promise.reject(DatasetErrEnum.sameApiCollection);
|
||||
}
|
||||
|
||||
const content = await readApiServerFileContent({
|
||||
const { title, rawText } = await readApiServerFileContent({
|
||||
apiServer,
|
||||
feishuServer,
|
||||
yuqueServer,
|
||||
@@ -53,14 +53,14 @@ async function handler(req: NextApiRequest): CreateCollectionResponse {
|
||||
|
||||
const { collectionId, insertResults } = await createCollectionAndInsertData({
|
||||
dataset,
|
||||
rawText: content,
|
||||
rawText,
|
||||
relatedId: apiFileId,
|
||||
createCollectionParams: {
|
||||
...body,
|
||||
teamId,
|
||||
tmbId,
|
||||
type: DatasetCollectionTypeEnum.apiFile,
|
||||
name,
|
||||
name: title || name,
|
||||
apiFileId,
|
||||
metadata: {
|
||||
relatedImgId: apiFileId
|
||||
|
||||
@@ -2,8 +2,7 @@ import { reTrainingDatasetFileCollectionParams } from '@fastgpt/global/core/data
|
||||
import { createCollectionAndInsertData } from '@fastgpt/service/core/dataset/collection/controller';
|
||||
import {
|
||||
DatasetCollectionTypeEnum,
|
||||
DatasetSourceReadTypeEnum,
|
||||
TrainingModeEnum
|
||||
DatasetSourceReadTypeEnum
|
||||
} from '@fastgpt/global/core/dataset/constants';
|
||||
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||
import { hashStr } from '@fastgpt/global/common/string/tools';
|
||||
@@ -77,7 +76,7 @@ async function handler(
|
||||
return Promise.reject(i18nT('dataset:collection_not_support_retraining'));
|
||||
})();
|
||||
|
||||
const rawText = await readDatasetSourceRawText({
|
||||
const { title, rawText } = await readDatasetSourceRawText({
|
||||
teamId,
|
||||
tmbId,
|
||||
customPdfParse,
|
||||
@@ -100,7 +99,7 @@ async function handler(
|
||||
teamId: collection.teamId,
|
||||
tmbId: collection.tmbId,
|
||||
datasetId: collection.dataset._id,
|
||||
name: collection.name,
|
||||
name: title || collection.name,
|
||||
type: collection.type,
|
||||
|
||||
customPdfParse,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
import type { NextApiRequest } from 'next';
|
||||
import { countPromptTokens } from '@fastgpt/service/common/string/tiktoken/index';
|
||||
import { getEmbeddingModel } from '@fastgpt/service/core/ai/model';
|
||||
import { getEmbeddingModel, getLLMModel } from '@fastgpt/service/core/ai/model';
|
||||
import { hasSameValue } from '@/service/core/dataset/data/utils';
|
||||
import { insertData2Dataset } from '@/service/core/dataset/data/controller';
|
||||
import { authDatasetCollection } from '@fastgpt/service/support/permission/dataset/auth';
|
||||
@@ -16,6 +16,7 @@ import { checkDatasetLimit } from '@fastgpt/service/support/permission/teamLimit
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||
import { getLLMMaxChunkSize } from '@fastgpt/global/core/dataset/training/utils';
|
||||
|
||||
async function handler(req: NextApiRequest) {
|
||||
const { collectionId, q, a, indexes } = req.body as InsertOneDatasetDataProps;
|
||||
@@ -45,7 +46,7 @@ async function handler(req: NextApiRequest) {
|
||||
// auth collection and get dataset
|
||||
const [
|
||||
{
|
||||
dataset: { _id: datasetId, vectorModel }
|
||||
dataset: { _id: datasetId, vectorModel, agentModel }
|
||||
}
|
||||
] = await Promise.all([getCollectionWithDataset(collectionId)]);
|
||||
|
||||
@@ -60,9 +61,11 @@ async function handler(req: NextApiRequest) {
|
||||
// token check
|
||||
const token = await countPromptTokens(formatQ + formatA, '');
|
||||
const vectorModelData = getEmbeddingModel(vectorModel);
|
||||
const llmModelData = getLLMModel(agentModel);
|
||||
const maxChunkSize = getLLMMaxChunkSize(llmModelData);
|
||||
|
||||
if (token > vectorModelData.maxToken) {
|
||||
return Promise.reject('Q Over Tokens');
|
||||
if (token > maxChunkSize) {
|
||||
return Promise.reject(`Content over max chunk size: ${maxChunkSize}`);
|
||||
}
|
||||
|
||||
// Duplicate data check
|
||||
@@ -82,7 +85,7 @@ async function handler(req: NextApiRequest) {
|
||||
q: formatQ,
|
||||
a: formatA,
|
||||
chunkIndex: 0,
|
||||
model: vectorModelData.model,
|
||||
embeddingModel: vectorModelData.model,
|
||||
indexes: formatIndexes
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { DatasetSourceReadTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import {
|
||||
ChunkSettingModeEnum,
|
||||
DataChunkSplitModeEnum,
|
||||
DatasetCollectionDataProcessModeEnum,
|
||||
DatasetSourceReadTypeEnum
|
||||
} from '@fastgpt/global/core/dataset/constants';
|
||||
import { rawText2Chunks, readDatasetSourceRawText } from '@fastgpt/service/core/dataset/read';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { ApiRequestProps } from '@fastgpt/service/type/next';
|
||||
@@ -8,100 +13,130 @@ import {
|
||||
} from '@fastgpt/global/support/permission/constant';
|
||||
import { authCollectionFile } from '@fastgpt/service/support/permission/auth/file';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
|
||||
import {
|
||||
computeChunkSize,
|
||||
computeChunkSplitter,
|
||||
getLLMMaxChunkSize
|
||||
} from '@fastgpt/global/core/dataset/training/utils';
|
||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||
import { getLLMModel } from '@fastgpt/service/core/ai/model';
|
||||
|
||||
export type PostPreviewFilesChunksProps = {
|
||||
datasetId: string;
|
||||
type: DatasetSourceReadTypeEnum;
|
||||
sourceId: string;
|
||||
|
||||
chunkSize: number;
|
||||
overlapRatio: number;
|
||||
customSplitChar?: string;
|
||||
customPdfParse?: boolean;
|
||||
|
||||
trainingType: DatasetCollectionDataProcessModeEnum;
|
||||
|
||||
// Chunk settings
|
||||
chunkSettingMode: ChunkSettingModeEnum;
|
||||
chunkSplitMode: DataChunkSplitModeEnum;
|
||||
chunkSize: number;
|
||||
chunkSplitter?: string;
|
||||
overlapRatio: number;
|
||||
|
||||
// Read params
|
||||
selector?: string;
|
||||
isQAImport?: boolean;
|
||||
externalFileId?: string;
|
||||
};
|
||||
export type PreviewChunksResponse = {
|
||||
q: string;
|
||||
a: string;
|
||||
}[];
|
||||
chunks: {
|
||||
q: string;
|
||||
a: string;
|
||||
}[];
|
||||
total: number;
|
||||
};
|
||||
|
||||
async function handler(
|
||||
req: ApiRequestProps<PostPreviewFilesChunksProps>
|
||||
): Promise<PreviewChunksResponse> {
|
||||
const {
|
||||
let {
|
||||
type,
|
||||
sourceId,
|
||||
customPdfParse = false,
|
||||
|
||||
trainingType,
|
||||
chunkSettingMode,
|
||||
chunkSplitMode,
|
||||
chunkSize,
|
||||
customSplitChar,
|
||||
chunkSplitter,
|
||||
|
||||
overlapRatio,
|
||||
selector,
|
||||
isQAImport,
|
||||
datasetId,
|
||||
externalFileId,
|
||||
customPdfParse = false
|
||||
externalFileId
|
||||
} = req.body;
|
||||
|
||||
if (!sourceId) {
|
||||
throw new Error('sourceId is empty');
|
||||
}
|
||||
if (chunkSize > 30000) {
|
||||
throw new Error('chunkSize is too large, should be less than 30000');
|
||||
|
||||
const fileAuthRes =
|
||||
type === DatasetSourceReadTypeEnum.fileLocal
|
||||
? await authCollectionFile({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
fileId: sourceId,
|
||||
per: OwnerPermissionVal
|
||||
})
|
||||
: undefined;
|
||||
|
||||
const { dataset, teamId, tmbId } = await authDataset({
|
||||
req,
|
||||
authApiKey: true,
|
||||
authToken: true,
|
||||
datasetId,
|
||||
per: WritePermissionVal
|
||||
});
|
||||
|
||||
if (fileAuthRes && String(fileAuthRes.tmbId) !== String(tmbId) && !fileAuthRes.isRoot) {
|
||||
return Promise.reject(CommonErrEnum.unAuthFile);
|
||||
}
|
||||
|
||||
const { teamId, tmbId, apiServer, feishuServer, yuqueServer } = await (async () => {
|
||||
if (type === DatasetSourceReadTypeEnum.fileLocal) {
|
||||
const res = await authCollectionFile({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
fileId: sourceId,
|
||||
per: OwnerPermissionVal
|
||||
});
|
||||
return {
|
||||
teamId: res.teamId,
|
||||
tmbId: res.tmbId
|
||||
};
|
||||
}
|
||||
const { dataset, teamId, tmbId } = await authDataset({
|
||||
req,
|
||||
authApiKey: true,
|
||||
authToken: true,
|
||||
datasetId,
|
||||
per: WritePermissionVal
|
||||
});
|
||||
return {
|
||||
teamId,
|
||||
tmbId,
|
||||
apiServer: dataset.apiServer,
|
||||
feishuServer: dataset.feishuServer,
|
||||
yuqueServer: dataset.yuqueServer
|
||||
};
|
||||
})();
|
||||
chunkSize = computeChunkSize({
|
||||
trainingType,
|
||||
chunkSettingMode,
|
||||
chunkSplitMode,
|
||||
chunkSize,
|
||||
llmModel: getLLMModel(dataset.agentModel)
|
||||
});
|
||||
|
||||
const rawText = await readDatasetSourceRawText({
|
||||
chunkSplitter = computeChunkSplitter({
|
||||
chunkSettingMode,
|
||||
chunkSplitMode,
|
||||
chunkSplitter
|
||||
});
|
||||
|
||||
const { rawText } = await readDatasetSourceRawText({
|
||||
teamId,
|
||||
tmbId,
|
||||
type,
|
||||
sourceId,
|
||||
selector,
|
||||
isQAImport,
|
||||
apiServer,
|
||||
feishuServer,
|
||||
yuqueServer,
|
||||
apiServer: dataset.apiServer,
|
||||
feishuServer: dataset.feishuServer,
|
||||
yuqueServer: dataset.yuqueServer,
|
||||
externalFileId,
|
||||
customPdfParse
|
||||
});
|
||||
|
||||
return rawText2Chunks({
|
||||
const chunks = rawText2Chunks({
|
||||
rawText,
|
||||
chunkLen: chunkSize,
|
||||
chunkSize,
|
||||
maxSize: getLLMMaxChunkSize(getLLMModel(dataset.agentModel)),
|
||||
overlapRatio,
|
||||
customReg: customSplitChar ? [customSplitChar] : [],
|
||||
customReg: chunkSplitter ? [chunkSplitter] : [],
|
||||
isQAImport: isQAImport
|
||||
}).slice(0, 10);
|
||||
});
|
||||
return {
|
||||
chunks: chunks.slice(0, 10),
|
||||
total: chunks.length
|
||||
};
|
||||
}
|
||||
export default NextAPI(handler);
|
||||
|
||||
@@ -1,27 +1,31 @@
|
||||
import type { NextApiRequest } from 'next';
|
||||
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';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { readFromSecondary } from '@fastgpt/service/common/mongo/utils';
|
||||
import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
|
||||
export type GetQueueLenResponse = {
|
||||
vectorTrainingCount: number;
|
||||
qaTrainingCount: number;
|
||||
autoTrainingCount: number;
|
||||
imageTrainingCount: number;
|
||||
};
|
||||
|
||||
async function handler(req: NextApiRequest) {
|
||||
await authCert({ req, authToken: true });
|
||||
const { vectorModel, agentModel } = req.query as GetTrainingQueueProps;
|
||||
|
||||
// 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 } }]
|
||||
lockTime: { $lt: new Date('2040/1/1') }
|
||||
}
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: '$model',
|
||||
_id: '$mode',
|
||||
count: { $sum: 1 }
|
||||
}
|
||||
}
|
||||
@@ -31,12 +35,16 @@ async function handler(req: NextApiRequest) {
|
||||
}
|
||||
);
|
||||
|
||||
const vectorTrainingCount = data.find((item) => item._id === vectorModel)?.count || 0;
|
||||
const agentTrainingCount = data.find((item) => item._id === agentModel)?.count || 0;
|
||||
const vectorTrainingCount = data.find((item) => item._id === TrainingModeEnum.chunk)?.count || 0;
|
||||
const qaTrainingCount = data.find((item) => item._id === TrainingModeEnum.qa)?.count || 0;
|
||||
const autoTrainingCount = data.find((item) => item._id === TrainingModeEnum.auto)?.count || 0;
|
||||
const imageTrainingCount = data.find((item) => item._id === TrainingModeEnum.image)?.count || 0;
|
||||
|
||||
return {
|
||||
vectorTrainingCount,
|
||||
agentTrainingCount
|
||||
qaTrainingCount,
|
||||
autoTrainingCount,
|
||||
imageTrainingCount
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
// }
|
||||
|
||||
const result = await aiTranscriptions({
|
||||
model: getDefaultSTTModel().model,
|
||||
model: getDefaultSTTModel(),
|
||||
fileStream: fs.createReadStream(file.path)
|
||||
});
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ const provider = () => {
|
||||
const { initd, loginStore, setLoginStore } = useSystemStore();
|
||||
const { setUserInfo } = useUserStore();
|
||||
const router = useRouter();
|
||||
const { code, state, error } = router.query as { code: string; state: string; error?: string };
|
||||
const { state, error, ...props } = router.query as Record<string, string>;
|
||||
const { toast } = useToast();
|
||||
|
||||
const loginSuccess = useCallback(
|
||||
@@ -31,12 +31,12 @@ const provider = () => {
|
||||
[setUserInfo, router, loginStore?.lastRoute]
|
||||
);
|
||||
|
||||
const authCode = useCallback(
|
||||
async (code: string) => {
|
||||
const authProps = useCallback(
|
||||
async (props: Record<string, string>) => {
|
||||
try {
|
||||
const res = await oauthLogin({
|
||||
type: loginStore?.provider || OAuthEnum.sso,
|
||||
code,
|
||||
props,
|
||||
callbackUrl: `${location.origin}/login/provider`,
|
||||
inviterId: localStorage.getItem('inviterId') || undefined,
|
||||
bd_vid: sessionStorage.getItem('bd_vid') || undefined,
|
||||
@@ -86,8 +86,8 @@ const provider = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('SSO', { initd, loginStore, code, state });
|
||||
if (!code || !initd) return;
|
||||
console.log('SSO', { initd, loginStore, props, state });
|
||||
if (!props || !initd) return;
|
||||
|
||||
if (isOauthLogging) return;
|
||||
|
||||
@@ -107,10 +107,10 @@ const provider = () => {
|
||||
}, 1000);
|
||||
return;
|
||||
} else {
|
||||
authCode(code);
|
||||
authProps(props);
|
||||
}
|
||||
})();
|
||||
}, [initd, authCode, code, error, loginStore, loginStore?.state, router, state, t, toast]);
|
||||
}, [initd, authProps, error, loginStore, loginStore?.state, router, state, t, toast, props]);
|
||||
|
||||
return <Loading />;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user