4.8 preview (#1288)

* Revert "lafAccount add pat & re request when token invalid (#76)" (#77)

This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be.

* perf: workflow ux

* system config

* Newflow (#89)

* docs: Add doc for Xinference (#1266)

Signed-off-by: Carson Yang <yangchuansheng33@gmail.com>

* Revert "lafAccount add pat & re request when token invalid (#76)" (#77)

This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be.

* perf: workflow ux

* system config

* Revert "lafAccount add pat & re request when token invalid (#76)" (#77)

This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be.

* Revert "lafAccount add pat & re request when token invalid (#76)" (#77)

This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be.

* Revert "lafAccount add pat & re request when token invalid (#76)" (#77)

This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be.

* rename code

* move code

* update flow

* input type selector

* perf: workflow runtime

* feat: node adapt newflow

* feat: adapt plugin

* feat: 360 connection

* check workflow

* perf: flow 性能

* change plugin input type (#81)

* change plugin input type

* plugin label mode

* perf: nodecard

* debug

* perf: debug ui

* connection ui

* change workflow ui (#82)

* feat: workflow debug

* adapt openAPI for new workflow (#83)

* adapt openAPI for new workflow

* i18n

* perf: plugin debug

* plugin input ui

* delete

* perf: global variable select

* fix rebase

* perf: workflow performance

* feat: input render type icon

* input icon

* adapt flow (#84)

* adapt newflow

* temp

* temp

* fix

* feat: app schedule trigger

* feat: app schedule trigger

* perf: schedule ui

* feat: ioslatevm run js code

* perf: workflow varialbe table ui

* feat: adapt simple mode

* feat: adapt input params

* output

* feat: adapt tamplate

* fix: ts

* add if-else module (#86)

* perf: worker

* if else node

* perf: tiktoken worker

* fix: ts

* perf: tiktoken

* fix if-else node (#87)

* fix if-else node

* type

* fix

* perf: audio render

* perf: Parallel worker

* log

* perf: if else node

* adapt plugin

* prompt

* perf: reference ui

* reference ui

* handle ux

* template ui and plugin tool

* adapt v1 workflow

* adapt v1 workflow completions

* perf: time variables

* feat: workflow keyboard shortcuts

* adapt v1 workflow

* update workflow example doc (#88)

* fix: simple mode select tool

---------

Signed-off-by: Carson Yang <yangchuansheng33@gmail.com>
Co-authored-by: Carson Yang <yangchuansheng33@gmail.com>
Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>

* doc

* perf: extract node

* extra node field

* update plugin version

* doc

* variable

* change doc & fix prompt editor (#90)

* fold workflow code

* value type label

---------

Signed-off-by: Carson Yang <yangchuansheng33@gmail.com>
Co-authored-by: Carson Yang <yangchuansheng33@gmail.com>
Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
This commit is contained in:
Archer
2024-04-25 17:51:20 +08:00
committed by GitHub
parent b08d81f887
commit 439c819ff1
505 changed files with 23570 additions and 18215 deletions

View File

@@ -1,45 +0,0 @@
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/vectorStore/pg';
import { PgDatasetTableName } from '@fastgpt/global/common/vectorStore/constants';
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
import { connectToDatabase } from '@/service/mongo';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
const { limit = 50, maxSize = 3 } = req.body as { limit: number; maxSize: number };
await authCert({ req, authRoot: true });
await connectToDatabase();
try {
await PgClient.query(
`ALTER TABLE ${PgDatasetTableName} ADD COLUMN createTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP;`
);
} catch (error) {
console.log(error);
}
try {
const result = await MongoChatItem.updateMany(
{ userFeedback: { $exists: true } },
{ $rename: { userFeedback: 'userBadFeedback' } }
);
console.log(result);
} catch (error) {
console.log(error);
}
jsonRes(res, {
data: {}
});
} catch (error) {
console.log(error);
jsonRes(res, {
code: 500,
error
});
}
}

View File

@@ -1,106 +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';
let success = 0;
let deleteImg = 0;
/* pg 中的数据搬到 mongo dataset.datas 中,并做映射 */
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
const { test = false } = req.body as { test: boolean };
await authCert({ req, authRoot: true });
await connectToDatabase();
success = 0;
deleteImg = 0;
// 取消 pg tmb_id 和 data_id 的null
await PgClient.query(`ALTER TABLE ${PgDatasetTableName} ALTER COLUMN tmb_id DROP NOT NULL;`);
await PgClient.query(`ALTER TABLE ${PgDatasetTableName} ALTER COLUMN data_id DROP NOT NULL;`);
// 重新绑定 images 和 collections
const images = await MongoImage.find(
{ 'metadata.fileId': { $exists: true } },
'_id metadata'
).lean();
// 去除 fileId 相同的数据
const fileIdMap = new Map<string, MongoImageSchemaType>();
images.forEach((image) => {
// @ts-ignore
const fileId = image.metadata?.fileId;
if (!fileIdMap.has(fileId) && fileId) {
fileIdMap.set(fileId, image);
}
});
const images2 = Array.from(fileIdMap.values());
console.log('total image list', images2.length);
for await (const image of images2) {
await initImages(image, test);
}
jsonRes(res, {
data: success,
message: 'success'
});
} catch (error) {
console.log(error);
jsonRes(res, {
code: 500,
error
});
}
}
export const initImages = async (image: MongoImageSchemaType, test: boolean): Promise<any> => {
try {
//@ts-ignore
const fileId = image.metadata.fileId as string;
if (!fileId) return;
// 找到集合
const collection = await MongoDatasetCollection.findOne({ fileId }, '_id metadata').lean();
if (!collection) {
deleteImg++;
console.log('deleteImg', deleteImg);
if (test) return;
return MongoImage.deleteOne({ _id: image._id });
}
const relatedImageId = getNanoid(24);
// update image
if (!test) {
await Promise.all([
MongoImage.updateMany(
{ 'metadata.fileId': fileId },
{ $set: { 'metadata.relatedId': relatedImageId } }
),
MongoDatasetCollection.findByIdAndUpdate(collection._id, {
$set: {
'metadata.relatedImgId': relatedImageId
}
})
]);
}
success++;
console.log('success', success);
} catch (error) {
console.log(error);
await delay(1000);
return initImages(image, test);
}
};

View File

@@ -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<any> => {
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();
}
};

View File

@@ -14,7 +14,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
name = 'APP',
avatar,
type = AppTypeEnum.advanced,
modules
modules,
edges
} = req.body as CreateAppParams;
if (!name || !Array.isArray(modules)) {
@@ -34,7 +35,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
teamId,
tmbId,
modules,
type
edges,
type,
version: 'v2'
});
jsonRes(res, {

View File

@@ -4,16 +4,27 @@ 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 { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { getLLMModel } from '@fastgpt/service/core/ai/model';
import { getGuideModule, splitGuideModule } from '@fastgpt/global/core/workflow/utils';
import { getNextTimeByCronStringAndTimezone } from '@fastgpt/global/common/string/time';
import { getScheduleTriggerApp } from '@/service/core/app/utils';
/* 获取我的模型 */
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
await connectToDatabase();
const { name, avatar, type, intro, modules, permission, teamTags } =
req.body as AppUpdateParams;
const {
name,
avatar,
type,
intro,
modules: nodes,
edges,
permission,
teamTags
} = req.body as AppUpdateParams;
const { appId } = req.query as { appId: string };
if (!appId) {
@@ -23,18 +34,18 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 凭证校验
await authApp({ req, authToken: true, appId, per: permission ? 'owner' : 'w' });
// check modules
// format nodes data
// 1. dataset search limit, less than model quoteMaxToken
if (modules) {
if (nodes) {
let maxTokens = 3000;
modules.forEach((item) => {
nodes.forEach((item) => {
if (
item.flowType === FlowNodeTypeEnum.chatNode ||
item.flowType === FlowNodeTypeEnum.tools
item.flowNodeType === FlowNodeTypeEnum.chatNode ||
item.flowNodeType === FlowNodeTypeEnum.tools
) {
const model =
item.inputs.find((item) => item.key === ModuleInputKeyEnum.aiModel)?.value || '';
item.inputs.find((item) => item.key === NodeInputKeyEnum.aiModel)?.value || '';
const chatModel = getLLMModel(model);
const quoteMaxToken = chatModel.quoteMaxToken || 3000;
@@ -42,10 +53,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
}
});
modules.forEach((item) => {
if (item.flowType === FlowNodeTypeEnum.datasetSearchNode) {
nodes.forEach((item) => {
if (item.flowNodeType === FlowNodeTypeEnum.datasetSearchNode) {
item.inputs.forEach((input) => {
if (input.key === ModuleInputKeyEnum.datasetMaxTokens) {
if (input.key === NodeInputKeyEnum.datasetMaxTokens) {
const val = input.value as number;
if (val > maxTokens) {
input.value = maxTokens;
@@ -55,6 +66,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
}
});
}
// 2. get schedule plan
const { scheduledTriggerConfig } = splitGuideModule(getGuideModule(nodes || []));
// 更新模型
await MongoApp.updateOne(
@@ -67,13 +80,23 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
avatar,
intro,
permission,
version: 'v2',
teamTags: teamTags,
...(modules && {
modules
})
...(nodes && {
modules: nodes
}),
...(edges && {
edges
}),
scheduledTriggerConfig,
scheduledTriggerNextTime: scheduledTriggerConfig
? getNextTimeByCronStringAndTimezone(scheduledTriggerConfig)
: null
}
);
getScheduleTriggerApp();
jsonRes(res);
} catch (err) {
jsonRes(res, {

View File

@@ -4,8 +4,8 @@ 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 { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { getLLMModel } from '@fastgpt/service/core/ai/model';
/* 获取我的模型 */
@@ -29,9 +29,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
let maxTokens = 3000;
modules.forEach((item) => {
if (item.flowType === FlowNodeTypeEnum.chatNode) {
if (item.flowNodeType === FlowNodeTypeEnum.chatNode) {
const model =
item.inputs.find((item) => item.key === ModuleInputKeyEnum.aiModel)?.value || '';
item.inputs.find((item) => item.key === NodeInputKeyEnum.aiModel)?.value || '';
const chatModel = getLLMModel(model);
const quoteMaxToken = chatModel.quoteMaxToken || 3000;
@@ -40,9 +40,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
});
modules.forEach((item) => {
if (item.flowType === FlowNodeTypeEnum.datasetSearchNode) {
if (item.flowNodeType === FlowNodeTypeEnum.datasetSearchNode) {
item.inputs.forEach((input) => {
if (input.key === ModuleInputKeyEnum.datasetMaxTokens) {
if (input.key === NodeInputKeyEnum.datasetMaxTokens) {
const val = input.value as number;
if (val > maxTokens) {
input.value = maxTokens;

View File

@@ -1,9 +1,8 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { connectToDatabase } from '@/service/mongo';
import { sseErrRes } from '@fastgpt/service/common/response';
import { SseResponseEventEnum } from '@fastgpt/global/core/module/runtime/constants';
import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/constants';
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 type { ChatItemType, ChatItemValueItemType } from '@fastgpt/global/core/chat/type';
@@ -11,13 +10,15 @@ import { authApp } from '@fastgpt/service/support/permission/auth/app';
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 { setEntryEntries } from '@fastgpt/service/core/workflow/dispatch/utils';
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
import { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
import { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
export type Props = {
history: ChatItemType[];
prompt: ChatItemValueItemType[];
modules: ModuleItemType[];
nodes: RuntimeNodeItemType[];
edges: RuntimeEdgeItemType[];
variables: Record<string, any>;
appId: string;
appName: string;
@@ -32,14 +33,25 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
res.end();
});
let { modules = [], history = [], prompt, variables = {}, appName, appId } = req.body as Props;
const {
nodes = [],
edges = [],
history = [],
prompt,
variables = {},
appName,
appId
} = req.body as Props;
try {
await connectToDatabase();
if (!history || !modules || !prompt || prompt.length === 0) {
if (!history || !nodes || !prompt || prompt.length === 0) {
throw new Error('Prams Error');
}
if (!Array.isArray(modules)) {
throw new Error('history is not array');
if (!Array.isArray(nodes)) {
throw new Error('Nodes is not array');
}
if (!Array.isArray(edges)) {
throw new Error('Edges is not array');
}
/* user auth */
@@ -64,13 +76,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
tmbId,
user,
appId,
modules: setEntryEntries(modules),
variables,
inputFiles: files,
histories: history,
startParams: {
runtimeNodes: nodes,
runtimeEdges: edges,
variables: {
...variables,
userChatInput: text
},
inputFiles: files,
histories: history,
stream: true,
detail: true,
maxRunTimes: 200

View File

@@ -2,13 +2,13 @@ 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 { getGuideModule } from '@fastgpt/global/core/workflow/utils';
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
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';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/module/runtime/constants';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {

View File

@@ -2,9 +2,9 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import type { InitChatResponse, InitOutLinkChatProps } from '@/global/core/chat/api.d';
import { getGuideModule } from '@fastgpt/global/core/module/utils';
import { getChatModelNameListByModules } from '@/service/core/app/module';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/module/runtime/constants';
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import { getChatItems } from '@fastgpt/service/core/chat/controller';
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
import { authOutLink } from '@/service/support/permission/auth/outLink';

View File

@@ -1,9 +1,9 @@
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 { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/module/runtime/constants';
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import type { InitChatResponse, InitTeamChatProps } from '@/global/core/chat/api.d';
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
import { MongoApp } from '@fastgpt/service/core/app/schema';

View File

@@ -2,14 +2,14 @@ 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 { getGuideModule } from '@fastgpt/global/core/workflow/utils';
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/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';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/module/runtime/constants';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {

View File

@@ -6,7 +6,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { withNextCors } from '@fastgpt/service/common/middle/cors';
import { countPromptTokens } from '@fastgpt/global/common/string/tiktoken';
import { countPromptTokens } from '@fastgpt/service/common/string/tiktoken/index';
import { getVectorModel } from '@fastgpt/service/core/ai/model';
import { hasSameValue } from '@/service/core/dataset/data/utils';
import { insertData2Dataset } from '@/service/core/dataset/data/controller';
@@ -60,7 +60,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
}));
// token check
const token = countPromptTokens(formatQ, 'system');
const token = await countPromptTokens(formatQ + formatA, '');
const vectorModelData = getVectorModel(vectorModel);
if (token > vectorModelData.maxToken) {

View File

@@ -24,7 +24,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
...body,
parentId: null,
teamId,
tmbId
tmbId,
version: 'v2'
}
],
{ session }
@@ -43,7 +44,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
pluginUid: item.name
},
teamId,
tmbId
tmbId,
version: 'v2'
})),
{
session
@@ -59,7 +61,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const { _id } = await MongoPlugin.create({
...body,
teamId,
tmbId
tmbId,
version: 'v2'
});
jsonRes(res, {
data: _id

View File

@@ -15,7 +15,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
if (!pluginId) {
throw new Error('缺少参数');
}
await authPluginCrud({ req, authToken: true, id: pluginId, per: 'owner' });
await authPluginCrud({ req, authToken: true, pluginId, per: 'owner' });
await mongoSessionRun(async (session) => {
await MongoPlugin.deleteMany(

View File

@@ -7,7 +7,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
try {
const { id } = req.query as { id: string };
await connectToDatabase();
const { plugin } = await authPluginCrud({ req, authToken: true, id, per: 'r' });
const { plugin } = await authPluginCrud({ req, authToken: true, pluginId: id, per: 'r' });
jsonRes(res, {
data: plugin

View File

@@ -4,9 +4,9 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { getPluginPreviewModule } from '@fastgpt/service/core/plugin/controller';
import { getPluginPreviewNode } from '@fastgpt/service/core/plugin/controller';
import { authPluginCanUse } from '@fastgpt/service/support/permission/auth/plugin';
import { FlowNodeTemplateType } from '@fastgpt/global/core/module/type';
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/index.d';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
@@ -17,7 +17,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await authPluginCanUse({ id, teamId, tmbId });
jsonRes<FlowNodeTemplateType>(res, {
data: await getPluginPreviewModule({ id })
data: await getPluginPreviewNode({ id })
});
} catch (err) {
jsonRes(res, {

View File

@@ -2,9 +2,9 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { FlowNodeTemplateType } from '@fastgpt/global/core/module/type';
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/module/constants';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/index.d';
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -14,8 +14,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const data: FlowNodeTemplateType[] =
global.communityPlugins?.map((plugin) => ({
id: plugin.id,
pluginId: plugin.id,
templateType: plugin.templateType ?? FlowNodeTemplateTypeEnum.other,
flowType: FlowNodeTypeEnum.pluginModule,
flowNodeType: FlowNodeTypeEnum.pluginModule,
avatar: plugin.avatar,
name: plugin.name,
intro: plugin.intro,

View File

@@ -3,9 +3,9 @@ import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoPlugin } from '@fastgpt/service/core/plugin/schema';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { FlowNodeTemplateType } from '@fastgpt/global/core/module/type';
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/module/constants';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/index.d';
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -39,9 +39,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const data: FlowNodeTemplateType[] = userPlugins.map((plugin) => ({
id: String(plugin._id),
parentId: String(plugin.parentId),
pluginId: String(plugin._id),
pluginType: plugin.type,
templateType: FlowNodeTemplateTypeEnum.personalPlugin,
flowType: FlowNodeTypeEnum.pluginModule,
flowNodeType: FlowNodeTypeEnum.pluginModule,
avatar: plugin.avatar,
name: plugin.name,
intro: plugin.intro,

View File

@@ -13,19 +13,25 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await connectToDatabase();
const body = req.body as UpdatePluginParams;
const { id, ...props } = body;
const { id, modules, edges, ...props } = body;
const { teamId, tmbId } = await authPluginCrud({ req, authToken: true, id, per: 'owner' });
const { teamId, tmbId } = await authPluginCrud({
req,
authToken: true,
pluginId: id,
per: 'owner'
});
const updateData = {
name: props.name,
intro: props.intro,
avatar: props.avatar,
parentId: props.parentId,
...(props.modules &&
props.modules.length > 0 && {
modules: props.modules
}),
version: 'v2',
...(modules && {
modules: modules
}),
...(edges && { edges }),
metadata: props.metadata
};
@@ -98,7 +104,8 @@ const updateHttpChildrenPlugin = async ({
pluginUid: plugin.name
},
teamId,
tmbId
tmbId,
version: 'v2'
}
],
{
@@ -111,7 +118,14 @@ const updateHttpChildrenPlugin = async ({
for await (const plugin of schemaPlugins) {
const dbPlugin = dbPlugins.find((p) => plugin.name === p.metadata?.pluginUid);
if (dbPlugin) {
await MongoPlugin.findByIdAndUpdate(dbPlugin._id, plugin, { session });
await MongoPlugin.findByIdAndUpdate(
dbPlugin._id,
{
...plugin,
version: 'v2'
},
{ session }
);
}
}
};

View File

@@ -0,0 +1,97 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { connectToDatabase } from '@/service/mongo';
import { jsonRes } from '@fastgpt/service/common/response';
import { pushChatUsage } from '@/service/support/wallet/usage/push';
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
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 { PostWorkflowDebugProps, PostWorkflowDebugResponse } from '@/global/core/workflow/api';
import { authPluginCrud } from '@fastgpt/service/support/permission/auth/plugin';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const {
nodes = [],
edges = [],
variables = {},
appId,
pluginId
} = req.body as PostWorkflowDebugProps;
try {
await connectToDatabase();
if (!nodes) {
throw new Error('Prams Error');
}
if (!Array.isArray(nodes)) {
throw new Error('Nodes is not array');
}
if (!Array.isArray(edges)) {
throw new Error('Edges is not array');
}
/* user auth */
const [{ teamId, tmbId }] = await Promise.all([
authCert({
req,
authToken: true
}),
appId && authApp({ req, authToken: true, appId, per: 'r' }),
pluginId && authPluginCrud({ req, authToken: true, pluginId, per: 'r' })
]);
// auth balance
const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
/* start process */
const { flowUsages, flowResponses, debugResponse } = await dispatchWorkFlow({
res,
mode: 'debug',
teamId,
tmbId,
user,
appId,
runtimeNodes: nodes,
runtimeEdges: edges,
variables: {
...variables,
userChatInput: ''
},
inputFiles: [],
histories: [],
stream: false,
detail: true,
maxRunTimes: 200
});
pushChatUsage({
appName: '工作流Debug',
appId,
teamId,
tmbId,
source: UsageSourceEnum.fastgpt,
flowUsages
});
jsonRes<PostWorkflowDebugResponse>(res, {
data: {
...debugResponse,
flowResponses
}
});
} catch (err: any) {
jsonRes(res, {
code: 500,
error: err
});
}
}
export const config = {
api: {
bodyParser: {
sizeLimit: '10mb'
},
responseLimit: '20mb'
}
};

View File

@@ -1,7 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { withNextCors } from '@fastgpt/service/common/middle/cors';
import ChatCompletion from '@/pages/api/v1/chat/completions';
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse) {
return ChatCompletion(req, res);
});

View File

@@ -1,71 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
type Props = HttpBodyType<{
input: string;
rule?: string;
}>;
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
const { input, rule = '' } = req.body as Props;
await authRequestFromLocal({ req });
const result = (() => {
if (typeof input === 'string') {
const defaultReg: any[] = [
'',
undefined,
'undefined',
null,
'null',
false,
'false',
0,
'0',
'none'
];
const customReg = rule.split('\n');
defaultReg.push(...customReg);
return !defaultReg.find((item) => {
const reg = typeof item === 'string' ? stringToRegex(item) : null;
if (reg) {
return reg.test(input);
}
return input === item;
});
}
return !!input;
})();
res.json({
...(result
? {
true: true
}
: {
false: false
})
});
} catch (err) {
console.log(err);
res.status(500).send(getErrText(err));
}
}
function stringToRegex(str: string) {
const regexFormat = /^\/(.+)\/([gimuy]*)$/;
const match = str.match(regexFormat);
if (match) {
const [, pattern, flags] = match;
return new RegExp(pattern, flags);
} else {
return null;
}
}

View File

@@ -1,35 +1,25 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
import type { HttpBodyType } from '@fastgpt/global/core/workflow/api.d';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { addCustomFeedbacks } from '@fastgpt/service/core/chat/controller';
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
type Props = HttpBodyType<{
appId: string;
chatId?: string;
responseChatItemId?: string;
defaultFeedback: string;
customFeedback: string;
}>;
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
const {
appId,
chatId,
responseChatItemId: chatItemId,
defaultFeedback,
customFeedback
customFeedback,
system_addInputParam: { appId, chatId, responseChatItemId: chatItemId }
} = req.body as Props;
await authRequestFromLocal({ req });
const feedback = customFeedback || defaultFeedback;
if (!feedback) {
return res.json({
response: ''
});
if (!customFeedback) {
return res.json({});
}
// wait the chat finish
@@ -38,19 +28,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
appId,
chatId,
chatItemId,
feedbacks: [feedback]
feedbacks: [customFeedback]
});
}, 60000);
if (!chatId || !chatItemId) {
return res.json({
response: `\\n\\n**自动反馈调试**: ${feedback}\\n\\n`
[NodeOutputKeyEnum.answerText]: `\\n\\n**自动反馈调试**: "${customFeedback}"\\n\\n`
});
}
return res.json({
response: ''
});
return res.json({});
} catch (err) {
console.log(err);
res.status(500).send(getErrText(err));

View File

@@ -1,8 +1,9 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
import type { HttpBodyType } from '@fastgpt/global/core/workflow/api.d';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { replaceVariable } from '@fastgpt/global/common/string/tools';
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
type Props = HttpBodyType<{
text: string;
@@ -11,10 +12,7 @@ type Props = HttpBodyType<{
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
const {
text,
DYNAMIC_INPUT_KEY: { ...obj }
} = req.body as Props;
const { text, [NodeInputKeyEnum.addInputParam]: obj } = req.body as Props;
await authRequestFromLocal({ req });

View File

@@ -8,7 +8,7 @@ import { getAIApi } from '@fastgpt/service/core/ai/config';
import { pushWhisperUsage } from '@/service/support/wallet/usage/push';
import { authChatCert } from '@/service/support/permission/auth/chat';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { getGuideModule, splitGuideModule } from '@fastgpt/global/core/module/utils';
import { getGuideModule, splitGuideModule } from '@fastgpt/global/core/workflow/utils';
import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
const upload = getUploadModel({

View File

@@ -5,11 +5,16 @@ import { sseErrRes, jsonRes } from '@fastgpt/service/common/response';
import { addLog } from '@fastgpt/service/common/system/log';
import { withNextCors } from '@fastgpt/service/common/middle/cors';
import { ChatRoleEnum, ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
import { SseResponseEventEnum } from '@fastgpt/global/core/module/runtime/constants';
import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch';
import type { ChatCompletionCreateParams } from '@fastgpt/global/core/ai/type.d';
import type { ChatCompletionMessageParam } from '@fastgpt/global/core/ai/type.d';
import { textAdaptGptResponse } from '@fastgpt/global/core/module/runtime/utils';
import {
getDefaultEntryNodeIds,
initWorkflowEdgeStatus,
storeNodes2RuntimeNodes,
textAdaptGptResponse
} from '@fastgpt/global/core/workflow/runtime/utils';
import { GPTMessages2Chats, chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
import { getChatItems } from '@fastgpt/service/core/chat/controller';
import { saveChat } from '@/service/utils/chat/saveChat';
@@ -32,9 +37,11 @@ import { AuthOutLinkChatProps } from '@fastgpt/global/support/outLink/api';
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
import { setEntryEntries } from '@fastgpt/service/core/workflow/dispatch/utils';
import { UserChatItemType } from '@fastgpt/global/core/chat/type';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/module/runtime/constants';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import { dispatchWorkFlowV1 } from '@fastgpt/service/core/workflow/dispatchV1';
import { setEntryEntries } from '@fastgpt/service/core/workflow/dispatchV1/utils';
type FastGptWebChatProps = {
chatId?: string; // undefined: nonuse history, '': new chat, 'xxxxx': use history
@@ -167,51 +174,79 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
const responseChatItemId: string | undefined = messages[messages.length - 1].dataId;
/* start flow controller */
const { flowResponses, flowUsages, assistantResponses } = await dispatchWorkFlow({
res,
mode: 'chat',
user,
teamId: String(teamId),
tmbId: String(tmbId),
appId: String(app._id),
chatId,
responseChatItemId,
modules: setEntryEntries(app.modules),
variables,
inputFiles: files,
histories: concatHistories,
startParams: {
userChatInput: text
},
stream,
detail,
maxRunTimes: 200
});
const { flowResponses, flowUsages, assistantResponses } = await (async () => {
if (app.version === 'v2') {
return dispatchWorkFlow({
res,
mode: 'chat',
user,
teamId: String(teamId),
tmbId: String(tmbId),
appId: String(app._id),
chatId,
responseChatItemId,
runtimeNodes: storeNodes2RuntimeNodes(app.modules, getDefaultEntryNodeIds(app.modules)),
runtimeEdges: initWorkflowEdgeStatus(app.edges),
variables: {
...variables,
userChatInput: text
},
inputFiles: files,
histories: concatHistories,
stream,
detail,
maxRunTimes: 200
});
}
return dispatchWorkFlowV1({
res,
mode: 'chat',
user,
teamId: String(teamId),
tmbId: String(tmbId),
appId: String(app._id),
chatId,
responseChatItemId,
//@ts-ignore
modules: setEntryEntries(app.modules),
variables,
inputFiles: files,
histories: concatHistories,
startParams: {
userChatInput: text
},
stream,
detail,
maxRunTimes: 200
});
})();
// save chat
if (chatId) {
const isOwnerUse = !shareId && !spaceTeamId && String(tmbId) === String(app.tmbId);
const source = (() => {
if (shareId) {
return ChatSourceEnum.share;
}
if (authType === 'apikey') {
return ChatSourceEnum.api;
}
if (spaceTeamId) {
return ChatSourceEnum.team;
}
return ChatSourceEnum.online;
})();
await saveChat({
chatId,
appId: app._id,
teamId,
tmbId: tmbId,
variables,
updateUseTime: isOwnerUse, // owner update use time
isUpdateUseTime: isOwnerUse && source === ChatSourceEnum.online, // owner update use time
shareId,
outLinkUid: outLinkUserId,
source: (() => {
if (shareId) {
return ChatSourceEnum.share;
}
if (authType === 'apikey') {
return ChatSourceEnum.api;
}
if (spaceTeamId) {
return ChatSourceEnum.team;
}
return ChatSourceEnum.online;
})(),
source,
content: [
question,
{