V4.8.17 feature (#3485)

* feat: add third party account config (#3443)

* temp

* editor workflow variable style

* add team to dispatch

* i18n

* delete console

* change openai account position

* fix

* fix

* fix

* fix

* fix

* 4.8.17 test (#3461)

* perf: external provider config

* perf: ui

* feat: add template config (#3434)

* change template position

* template config

* delete console

* delete

* fix

* fix

* perf: Mongo visutal field (#3464)

* remve invalid code

* perf: team member visutal code

* perf: virtual search; perf: search test data

* fix: ts

* fix: image response headers

* perf: template code

* perf: auth layout;perf: auto save (#3472)

* perf: auth layout

* perf: auto save

* perf: auto save

* fix: template guide display & http input support external variables (#3475)

* fix: template guide display

* http editor support external workflow variables

* perf: auto save;fix: ifelse checker line break; (#3478)

* perf: auto save

* perf: auto save

* fix: ifelse checker line break

* perf: doc

* perf: doc

* fix: update var type error

* 4.8.17 test (#3479)

* perf: auto save

* perf: auto save

* perf: template code

* 4.8.17 test (#3480)

* perf: auto save

* perf: auto save

* perf: model price model

* feat: add react memo

* perf: model provider filter

* fix: ts (#3481)

* perf: auto save

* perf: auto save

* fix: ts

* simple app tool select (#3473)

* workflow plugin userguide & simple tool ui

* simple tool filter

* reuse component

* change component to hook

* fix

* perf: too selector modal (#3484)

* perf: auto save

* perf: auto save

* perf: markdown render

* perf: too selector

* fix: app version require tmbId

* perf: templates refresh

* perf: templates refresh

* hide auto save error tip

* perf: toolkit guide

---------

Co-authored-by: heheer <heheer@sealos.io>
This commit is contained in:
Archer
2024-12-27 20:05:12 +08:00
committed by GitHub
parent a209856d48
commit b520988c64
207 changed files with 2943 additions and 1378 deletions

View File

@@ -45,8 +45,9 @@ async function handler(req: ApiRequestProps<CreateAppBody>) {
// 上限校验
await checkTeamAppLimit(teamId);
const tmb = await MongoTeamMember.findById({ _id: tmbId });
const user = await MongoUser.findById({ _id: tmb?.userId });
const tmb = await MongoTeamMember.findById({ _id: tmbId }, 'userId').populate<{
user: { avatar: string; username: string };
}>('user', 'avatar username');
// 创建app
const appId = await onCreateApp({
@@ -59,8 +60,8 @@ async function handler(req: ApiRequestProps<CreateAppBody>) {
chatConfig,
teamId,
tmbId,
userAvatar: user?.avatar,
username: user?.username
userAvatar: tmb?.user?.avatar,
username: tmb?.user?.username
});
pushTrack.createApp({
@@ -132,6 +133,7 @@ export const onCreateApp = async ({
await MongoAppVersion.create(
[
{
tmbId,
appId,
nodes: modules,
edges,

View File

@@ -45,7 +45,8 @@ async function handler(
currentCost: plugin.currentCost,
hasTokenFee: plugin.hasTokenFee,
author: plugin.author,
instructions: plugin.userGuide
instructions: plugin.userGuide,
courseUrl: plugin.courseUrl
}))
.filter((item) => {
if (searchKey) {

View File

@@ -1,8 +1,8 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { NextAPI } from '@/service/middleware/entry';
import { TemplateMarketItemType } from '@fastgpt/global/core/workflow/type';
import { getTemplateMarketItemDetail } from '@/service/core/app/template';
import { AppTemplateSchemaType } from '@fastgpt/global/core/app/type';
import { getAppTemplatesAndLoadThem } from '@fastgpt/templates/register';
type Props = {
templateId: string;
@@ -11,11 +11,13 @@ type Props = {
async function handler(
req: NextApiRequest,
res: NextApiResponse<any>
): Promise<TemplateMarketItemType | undefined> {
): Promise<AppTemplateSchemaType | undefined> {
await authCert({ req, authToken: true });
const { templateId } = req.query as Props;
return getTemplateMarketItemDetail(templateId);
const templateMarketItems: AppTemplateSchemaType[] = await getAppTemplatesAndLoadThem();
return templateMarketItems.find((item) => item.templateId === templateId);
}
export default NextAPI(handler);

View File

@@ -1,16 +1,53 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import type { NextApiResponse } from 'next';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { NextAPI } from '@/service/middleware/entry';
import { TemplateMarketListItemType } from '@fastgpt/global/core/workflow/type';
import { getTemplateMarketItemList } from '@/service/core/app/template';
import { getAppTemplatesAndLoadThem } from '@fastgpt/templates/register';
import { AppTemplateSchemaType } from '@fastgpt/global/core/app/type';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { ApiRequestProps } from '@fastgpt/service/type/next';
export type ListParams = {
isQuickTemplate?: boolean;
type?: AppTypeEnum | 'all';
};
async function handler(
req: NextApiRequest,
req: ApiRequestProps<ListParams>,
res: NextApiResponse<any>
): Promise<TemplateMarketListItemType[]> {
): Promise<AppTemplateSchemaType[]> {
await authCert({ req, authToken: true });
return getTemplateMarketItemList();
const { isQuickTemplate = false, type = 'all' } = req.query;
const templateMarketItems = await getAppTemplatesAndLoadThem();
let filteredItems = templateMarketItems.filter((item) => {
if (!item.isActive) return false;
if (type === 'all') return true;
return item.type === type;
});
if (isQuickTemplate) {
if (filteredItems.some((item) => item.isQuickTemplate !== undefined)) {
filteredItems = filteredItems.filter((item) => item.isQuickTemplate);
} else {
filteredItems = filteredItems.slice(0, 3);
}
}
return filteredItems.map((item) => {
return {
templateId: item.templateId,
name: item.name,
intro: item.intro,
avatar: item.avatar,
tags: item.tags,
type: item.type,
author: item.author,
userGuide: item.userGuide,
workflow: {}
};
});
}
export default NextAPI(handler);

View File

@@ -11,12 +11,9 @@ import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
async function handler(
req: ApiRequestProps<PostPublishAppProps>,
res: NextApiResponse<any>
): Promise<{}> {
async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiResponse<any>) {
const { appId } = req.query as { appId: string };
const { nodes = [], edges = [], chatConfig, isPublish, versionName } = req.body;
const { nodes = [], edges = [], chatConfig, isPublish, versionName, autoSave } = req.body;
const { app, tmbId } = await authApp({ appId, req, per: WritePermissionVal, authToken: true });
@@ -25,6 +22,15 @@ async function handler(
isPlugin: app.type === AppTypeEnum.plugin
});
if (autoSave) {
return MongoApp.findByIdAndUpdate(appId, {
modules: formatNodes,
edges,
chatConfig,
updateTime: new Date()
});
}
await mongoSessionRun(async (session) => {
// create version histories
const [{ _id }] = await MongoAppVersion.create(
@@ -70,8 +76,6 @@ async function handler(
}
);
});
return {};
}
export default NextAPI(handler);

View File

@@ -10,7 +10,7 @@ import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants'
import type { AIChatItemType, UserChatItemType } from '@fastgpt/global/core/chat/type';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch';
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
import { getUserChatInfoAndAuthTeamPoints } from '@fastgpt/service/support/permission/auth/team';
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
import {
concatHistories,
@@ -115,7 +115,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
})();
const limit = getMaxHistoryLimitFromNodes(nodes);
const [{ histories }, chatDetail, { user }] = await Promise.all([
const [{ histories }, chatDetail, { timezone, externalProvider }] = await Promise.all([
getChatItems({
appId,
chatId,
@@ -158,7 +158,8 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
res,
requestOrigin: req.headers.origin,
mode: 'test',
user,
timezone,
externalProvider,
uid: tmbId,
runningAppInfo: {
@@ -204,7 +205,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
const { text: userInteractiveVal } = chatValue2RuntimePrompt(userQuestion.value);
const newTitle = isPlugin
? variables.cTime ?? getSystemTime(user.timezone)
? variables.cTime ?? getSystemTime(timezone)
: getChatTitleFromChatMessage(userQuestion);
const aiResponse: AIChatItemType & { dataId?: string } = {

View File

@@ -11,6 +11,7 @@ import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
import { getAppLatestVersion } from '@fastgpt/service/core/app/version/controller';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { NextAPI } from '@/service/middleware/entry';
import { UserModelSchema } from '@fastgpt/global/support/user/type';
async function handler(req: NextApiRequest, res: NextApiResponse) {
let { chatId, shareId, outLinkUid } = req.query as InitOutLinkChatProps;
@@ -20,7 +21,9 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
// auth app permission
const [tmb, chat, app] = await Promise.all([
MongoTeamMember.findById(outLinkConfig.tmbId, '_id userId').populate('userId', 'avatar').lean(),
MongoTeamMember.findById(outLinkConfig.tmbId, '_id userId')
.populate<{ user: UserModelSchema }>('user', 'avatar')
.lean(),
MongoChat.findOne({ appId, chatId, shareId }).lean(),
MongoApp.findById(appId).lean()
]);
@@ -45,8 +48,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
chatId,
appId: app._id,
title: chat?.title,
//@ts-ignore
userAvatar: tmb?.userId?.avatar,
userAvatar: tmb?.user?.avatar,
variables: chat?.variables,
app: {
chatConfig: getAppChatConfig({

View File

@@ -66,9 +66,9 @@ async function handler(
return {
type: DatasetSourceReadTypeEnum.apiFile,
sourceId: collection.apiFileId,
apiServer: collection.datasetId.apiServer,
feishuServer: collection.datasetId.feishuServer,
yuqueServer: collection.datasetId.yuqueServer
apiServer: collection.dataset.apiServer,
feishuServer: collection.dataset.feishuServer,
yuqueServer: collection.dataset.yuqueServer
};
}
if (collection.type === DatasetCollectionTypeEnum.externalFile) {
@@ -90,12 +90,12 @@ async function handler(
return mongoSessionRun(async (session) => {
const { collectionId } = await createCollectionAndInsertData({
dataset: collection.datasetId,
dataset: collection.dataset,
rawText,
createCollectionParams: {
teamId: collection.teamId,
tmbId: collection.tmbId,
datasetId: collection.datasetId._id,
datasetId: collection.dataset._id,
name: collection.name,
type: collection.type,

View File

@@ -25,7 +25,7 @@ async function handler(req: NextApiRequest) {
// find all delete id
const collections = await findCollectionAndChild({
teamId,
datasetId: collection.datasetId._id,
datasetId: collection.datasetId,
collectionId,
fields: '_id teamId datasetId fileId metadata'
});

View File

@@ -37,7 +37,7 @@ async function handler(req: NextApiRequest): Promise<DatasetCollectionItemType>
...collection,
...getCollectionSourceData(collection),
tags: await collectionTagsToTagLabel({
datasetId: collection.datasetId._id,
datasetId: collection.datasetId,
tags: collection.tags
}),
permission,

View File

@@ -148,9 +148,9 @@ async function handler(
return collection.rawLink;
}
if (collection.type === DatasetCollectionTypeEnum.apiFile && collection.apiFileId) {
const apiServer = collection.datasetId.apiServer;
const feishuServer = collection.datasetId.feishuServer;
const yuqueServer = collection.datasetId.yuqueServer;
const apiServer = collection.dataset.apiServer;
const feishuServer = collection.dataset.feishuServer;
const yuqueServer = collection.dataset.yuqueServer;
if (apiServer) {
return useApiDatasetRequest({ apiServer }).getFilePreviewUrl({
@@ -170,11 +170,8 @@ async function handler(
return '';
}
if (collection.type === DatasetCollectionTypeEnum.externalFile) {
if (collection.externalFileId && collection.datasetId.externalReadUrl) {
return collection.datasetId.externalReadUrl.replace(
'{{fileId}}',
collection.externalFileId
);
if (collection.externalFileId && collection.dataset.externalReadUrl) {
return collection.dataset.externalReadUrl.replace('{{fileId}}', collection.externalFileId);
}
if (collection.externalFileUrl) {
return collection.externalFileUrl;

View File

@@ -100,7 +100,7 @@ async function handler(req: ApiRequestProps<UpdateDatasetCollectionParams>) {
const collectionTags = await createOrGetCollectionTags({
tags,
teamId,
datasetId: collection.datasetId._id,
datasetId: collection.datasetId,
session
});

View File

@@ -45,7 +45,7 @@ async function handler(req: NextApiRequest) {
// auth collection and get dataset
const [
{
datasetId: { _id: datasetId, vectorModel }
dataset: { _id: datasetId, vectorModel }
}
] = await Promise.all([getCollectionWithDataset(collectionId)]);

View File

@@ -31,7 +31,7 @@ async function handler(
const queryReg = new RegExp(`${replaceRegChars(searchText)}`, 'i');
const match = {
teamId,
datasetId: collection.datasetId._id,
datasetId: collection.datasetId,
collectionId,
...(searchText.trim()
? {

View File

@@ -1,9 +1,6 @@
/* push data to training queue */
import type { NextApiRequest, NextApiResponse } from 'next';
import type {
PushDatasetDataProps,
PushDatasetDataResponse
} from '@fastgpt/global/core/dataset/api.d';
import type { PushDatasetDataProps } from '@fastgpt/global/core/dataset/api.d';
import { authDatasetCollection } from '@fastgpt/service/support/permission/dataset/auth';
import { checkDatasetLimit } from '@fastgpt/service/support/permission/teamLimit';
import { predictDataLimitLength } from '@fastgpt/global/core/dataset/utils';
@@ -42,9 +39,9 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
...body,
teamId,
tmbId,
datasetId: collection.datasetId._id,
agentModel: collection.datasetId.agentModel,
vectorModel: collection.datasetId.vectorModel
datasetId: collection.datasetId,
agentModel: collection.dataset.agentModel,
vectorModel: collection.dataset.vectorModel
});
}

View File

@@ -12,7 +12,7 @@ async function handler(req: ApiRequestProps<UpdateDatasetDataProps>) {
// auth data permission
const {
collection: {
datasetId: { vectorModel }
dataset: { vectorModel }
},
teamId,
tmbId

View File

@@ -32,7 +32,7 @@ async function handler(
const queryReg = new RegExp(`${replaceRegChars(searchText)}`, 'i');
const match = {
teamId,
datasetId: collection.datasetId._id,
datasetId: collection.datasetId,
collectionId,
...(searchText.trim()
? {

View File

@@ -4,7 +4,7 @@ import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants'
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
import { getUserChatInfoAndAuthTeamPoints } from '@fastgpt/service/support/permission/auth/team';
import { PostWorkflowDebugProps, PostWorkflowDebugResponse } from '@/global/core/workflow/api';
import { NextAPI } from '@/service/middleware/entry';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
@@ -37,7 +37,7 @@ async function handler(
]);
// auth balance
const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
const { timezone, externalProvider } = await getUserChatInfoAndAuthTeamPoints(tmbId);
/* start process */
const { flowUsages, flowResponses, debugResponse, newVariables } = await dispatchWorkFlow({
@@ -50,7 +50,8 @@ async function handler(
tmbId
},
uid: tmbId,
user,
timezone,
externalProvider,
runtimeNodes: nodes,
runtimeEdges: edges,
variables,