mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 13:03:50 +00:00
4.8.6 merge (#1943)
* Dataset collection forbid (#1885) * perf: tool call support same id * feat: collection forbid * feat: collection forbid * Inheritance Permission for apps (#1897) * feat: app schema define chore: references of authapp * feat: authApp method inheritance * feat: create and update api * feat: update * feat: inheritance Permission controller for app. * feat: abstract version of inheritPermission * feat: ancestorId for apps * chore: update app * fix: inheritPermission abstract version * feat: update folder defaultPermission * feat: app update api * chore: inheritance frontend * chore: app list api * feat: update defaultPermission in app deatil * feat: backend api finished * feat: app inheritance permission fe * fix: app update defaultpermission causes collaborator miss * fix: ts error * chore: adjust the codes * chore: i18n chore: i18n * chore: fe adjust and i18n * chore: adjust the code * feat: resume api; chore: rewrite update api and inheritPermission methods * chore: something * chore: fe code adjusting * feat: frontend adjusting * chore: fe code adjusting * chore: adjusting the code * perf: fe loading * format * Inheritance fix (#1908) * fix: SlideCard * fix: authapp did not return parent app for inheritance app * fix: fe adjusting * feat: fe adjusing * perf: inherit per ux * doc * fix: ts errors (#1916) * perf: inherit permission * fix: permission inherit * Workflow type (#1938) * perf: workflow type tmp workflow perf: workflow type feat: custom field config * perf: dynamic input * perf: node classify * perf: node classify * perf: node classify * perf: node classify * fix: workflow custom input * feat: text editor and customFeedback move to basic nodes * feat: community system plugin * fix: ts * feat: exprEval plugin * perf: workflow type * perf: plugin important * fix: default templates * perf: markdown hr css * lock * perf: fetch url * perf: new plugin version * fix: chat histories update * fix: collection paths invalid * perf: app card ui --------- Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Types, connectionMongo } from '../../mongo';
|
||||
import { Types, connectionMongo, ReadPreference } from '../../mongo';
|
||||
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
|
||||
import fsp from 'fs/promises';
|
||||
import fs from 'fs';
|
||||
@@ -17,7 +17,9 @@ export function getGFSCollection(bucket: `${BucketNameEnum}`) {
|
||||
}
|
||||
export function getGridBucket(bucket: `${BucketNameEnum}`) {
|
||||
return new connectionMongo.mongo.GridFSBucket(connectionMongo.connection.db, {
|
||||
bucketName: bucket
|
||||
bucketName: bucket,
|
||||
// @ts-ignore
|
||||
readPreference: ReadPreference.SECONDARY_PREFERRED // Read from secondary node
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -10,3 +10,5 @@ export const connectionMongo = (() => {
|
||||
|
||||
return global.mongodb;
|
||||
})();
|
||||
|
||||
export const ReadPreference = mongoose.mongo.ReadPreference;
|
||||
|
@@ -43,6 +43,10 @@ export async function connectMongo({
|
||||
maxIdleTimeMS: 300000,
|
||||
retryWrites: true,
|
||||
retryReads: true
|
||||
|
||||
// readPreference: 'secondaryPreferred',
|
||||
// readConcern: { level: 'local' },
|
||||
// writeConcern: { w: 'majority', j: true }
|
||||
});
|
||||
|
||||
console.log('mongo connected');
|
||||
|
@@ -1,20 +1,22 @@
|
||||
import { addLog } from '../system/log';
|
||||
import { connectionMongo, ClientSession } from './index';
|
||||
|
||||
const timeout = 60000;
|
||||
|
||||
export const mongoSessionRun = async <T = unknown>(fn: (session: ClientSession) => Promise<T>) => {
|
||||
const session = await connectionMongo.startSession();
|
||||
let committed = false;
|
||||
|
||||
try {
|
||||
session.startTransaction();
|
||||
session.startTransaction({
|
||||
maxCommitTimeMS: timeout
|
||||
});
|
||||
const result = await fn(session);
|
||||
|
||||
await session.commitTransaction();
|
||||
committed = true;
|
||||
|
||||
return result as T;
|
||||
} catch (error) {
|
||||
if (!committed) {
|
||||
if (!session.transaction.isCommitted) {
|
||||
await session.abortTransaction();
|
||||
} else {
|
||||
addLog.warn('Un catch mongo session error', { error });
|
||||
|
4
packages/service/common/mongo/utils.ts
Normal file
4
packages/service/common/mongo/utils.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export const readFromSecondary = {
|
||||
readPreference: 'secondaryPreferred',
|
||||
readConcern: 'local'
|
||||
};
|
@@ -24,6 +24,9 @@ export type InsertVectorControllerProps = InsertVectorProps & {
|
||||
export type EmbeddingRecallProps = {
|
||||
teamId: string;
|
||||
datasetIds: string[];
|
||||
|
||||
forbidCollectionIdList: string[];
|
||||
// forbidEmbIndexIdList: string[];
|
||||
// similarity?: number;
|
||||
// efSearch?: number;
|
||||
};
|
||||
|
@@ -213,14 +213,19 @@ export class MilvusCtrl {
|
||||
};
|
||||
embRecall = async (props: EmbeddingRecallCtrlProps): Promise<EmbeddingRecallResponse> => {
|
||||
const client = await this.getClient();
|
||||
const { teamId, datasetIds, vector, limit, retry = 2 } = props;
|
||||
const { teamId, datasetIds, vector, limit, forbidCollectionIdList, retry = 2 } = props;
|
||||
|
||||
const forbidColQuery =
|
||||
forbidCollectionIdList.length > 0
|
||||
? `and (collectionId not in [${forbidCollectionIdList.map((id) => `"${String(id)}"`).join(',')}])`
|
||||
: '';
|
||||
|
||||
try {
|
||||
const { results } = await client.search({
|
||||
collection_name: DatasetVectorTableName,
|
||||
data: vector,
|
||||
limit,
|
||||
filter: `(teamId == "${teamId}") and (datasetId in [${datasetIds.map((id) => `"${String(id)}"`).join(',')}])`,
|
||||
filter: `(teamId == "${teamId}") and (datasetId in [${datasetIds.map((id) => `"${String(id)}"`).join(',')}]) ${forbidColQuery}`,
|
||||
output_fields: ['collectionId']
|
||||
});
|
||||
|
||||
|
@@ -118,9 +118,29 @@ export class PgVectorCtrl {
|
||||
}
|
||||
};
|
||||
embRecall = async (props: EmbeddingRecallCtrlProps): Promise<EmbeddingRecallResponse> => {
|
||||
const { teamId, datasetIds, vector, limit, retry = 2 } = props;
|
||||
const { teamId, datasetIds, vector, limit, forbidCollectionIdList, retry = 2 } = props;
|
||||
|
||||
const forbidCollectionSql =
|
||||
forbidCollectionIdList.length > 0
|
||||
? `AND collection_id NOT IN (${forbidCollectionIdList.map((id) => `'${String(id)}'`).join(',')})`
|
||||
: 'AND collection_id IS NOT NULL';
|
||||
// const forbidDataSql =
|
||||
// forbidEmbIndexIdList.length > 0 ? `AND id NOT IN (${forbidEmbIndexIdList.join(',')})` : '';
|
||||
|
||||
try {
|
||||
// const explan: any = await PgClient.query(
|
||||
// `BEGIN;
|
||||
// SET LOCAL hnsw.ef_search = ${global.systemEnv?.pgHNSWEfSearch || 100};
|
||||
// EXPLAIN ANALYZE select id, collection_id, vector <#> '[${vector}]' AS score
|
||||
// from ${DatasetVectorTableName}
|
||||
// where team_id='${teamId}'
|
||||
// AND dataset_id IN (${datasetIds.map((id) => `'${String(id)}'`).join(',')})
|
||||
// ${forbidCollectionSql}
|
||||
// order by score limit ${limit};
|
||||
// COMMIT;`
|
||||
// );
|
||||
// console.log(explan[2].rows);
|
||||
|
||||
const results: any = await PgClient.query(
|
||||
`
|
||||
BEGIN;
|
||||
@@ -129,6 +149,7 @@ export class PgVectorCtrl {
|
||||
from ${DatasetVectorTableName}
|
||||
where team_id='${teamId}'
|
||||
AND dataset_id IN (${datasetIds.map((id) => `'${String(id)}'`).join(',')})
|
||||
${forbidCollectionSql}
|
||||
order by score limit ${limit};
|
||||
COMMIT;`
|
||||
);
|
||||
|
@@ -1,13 +1,15 @@
|
||||
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/node.d';
|
||||
import { FlowNodeTypeEnum, defaultNodeVersion } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { pluginData2FlowNodeIO } from '@fastgpt/global/core/workflow/utils';
|
||||
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||
import type { PluginRuntimeType, PluginTemplateType } from '@fastgpt/global/core/plugin/type.d';
|
||||
import type { PluginRuntimeType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { getHandleConfig } from '@fastgpt/global/core/workflow/template/utils';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { MongoApp } from '../schema';
|
||||
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
|
||||
import { getCommunityPlugins } from '@fastgpt/plugins/register';
|
||||
|
||||
/*
|
||||
plugin id rule:
|
||||
@@ -32,11 +34,15 @@ export async function splitCombinePluginId(id: string) {
|
||||
return { source, pluginId: id };
|
||||
}
|
||||
|
||||
const getPluginTemplateById = async (id: string): Promise<PluginTemplateType> => {
|
||||
const getPluginTemplateById = async (
|
||||
id: string
|
||||
): Promise<SystemPluginTemplateItemType & { teamId?: string }> => {
|
||||
const { source, pluginId } = await splitCombinePluginId(id);
|
||||
|
||||
if (source === PluginSourceEnum.community) {
|
||||
const item = global.communityPlugins?.find((plugin) => plugin.id === pluginId);
|
||||
const item = [...global.communityPlugins, ...getCommunityPlugins()].find(
|
||||
(plugin) => plugin.id === pluginId
|
||||
);
|
||||
if (!item) return Promise.reject('plugin not found');
|
||||
|
||||
return cloneDeep(item);
|
||||
@@ -52,12 +58,15 @@ const getPluginTemplateById = async (id: string): Promise<PluginTemplateType> =>
|
||||
avatar: item.avatar,
|
||||
intro: item.intro,
|
||||
showStatus: true,
|
||||
source: PluginSourceEnum.personal,
|
||||
nodes: item.modules,
|
||||
edges: item.edges,
|
||||
templateType: FlowNodeTemplateTypeEnum.personalPlugin,
|
||||
workflow: {
|
||||
nodes: item.modules,
|
||||
edges: item.edges
|
||||
},
|
||||
templateType: FlowNodeTemplateTypeEnum.teamApp,
|
||||
isTool: true,
|
||||
version: item?.pluginData?.nodeVersion || defaultNodeVersion
|
||||
version: item?.pluginData?.nodeVersion || defaultNodeVersion,
|
||||
originCost: 0,
|
||||
currentCost: 0
|
||||
};
|
||||
}
|
||||
return Promise.reject('plugin not found');
|
||||
@@ -80,7 +89,7 @@ export async function getPluginPreviewNode({ id }: { id: string }): Promise<Flow
|
||||
version: plugin.version,
|
||||
sourceHandle: getHandleConfig(true, true, true, true),
|
||||
targetHandle: getHandleConfig(true, true, true, true),
|
||||
...pluginData2FlowNodeIO(plugin.nodes)
|
||||
...pluginData2FlowNodeIO(plugin.workflow.nodes)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -93,7 +102,7 @@ export async function getPluginRuntimeById(id: string): Promise<PluginRuntimeTyp
|
||||
name: plugin.name,
|
||||
avatar: plugin.avatar,
|
||||
showStatus: plugin.showStatus,
|
||||
nodes: plugin.nodes,
|
||||
edges: plugin.edges
|
||||
nodes: plugin.workflow.nodes,
|
||||
edges: plugin.workflow.edges
|
||||
};
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import {
|
||||
TeamMemberCollectionName
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
import { AppDefaultPermissionVal } from '@fastgpt/global/support/permission/app/constant';
|
||||
import { getPermissionSchema } from '@fastgpt/global/support/permission/utils';
|
||||
|
||||
export const AppCollectionName = 'apps';
|
||||
|
||||
@@ -108,11 +109,7 @@ const AppSchema = new Schema({
|
||||
type: Boolean
|
||||
},
|
||||
|
||||
// the default permission of a app
|
||||
defaultPermission: {
|
||||
type: Number,
|
||||
default: AppDefaultPermissionVal
|
||||
}
|
||||
...getPermissionSchema(AppDefaultPermissionVal)
|
||||
});
|
||||
|
||||
try {
|
||||
|
@@ -48,12 +48,15 @@ const DatasetCollectionSchema = new Schema({
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
},
|
||||
forbid: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
|
||||
// chunk filed
|
||||
trainingType: {
|
||||
type: String,
|
||||
enum: Object.keys(TrainingTypeMap),
|
||||
required: true
|
||||
enum: Object.keys(TrainingTypeMap)
|
||||
},
|
||||
chunkSize: {
|
||||
type: Number,
|
||||
@@ -91,23 +94,25 @@ const DatasetCollectionSchema = new Schema({
|
||||
}
|
||||
});
|
||||
|
||||
export const MongoDatasetCollection: Model<DatasetCollectionSchemaType> =
|
||||
models[DatasetColCollectionName] || model(DatasetColCollectionName, DatasetCollectionSchema);
|
||||
|
||||
try {
|
||||
// auth file
|
||||
DatasetCollectionSchema.index({ teamId: 1, fileId: 1 }, { background: true });
|
||||
DatasetCollectionSchema.index({ teamId: 1, fileId: 1 });
|
||||
|
||||
// list collection; deep find collections
|
||||
DatasetCollectionSchema.index(
|
||||
{
|
||||
teamId: 1,
|
||||
datasetId: 1,
|
||||
parentId: 1,
|
||||
updateTime: -1
|
||||
},
|
||||
{ background: true }
|
||||
);
|
||||
DatasetCollectionSchema.index({
|
||||
teamId: 1,
|
||||
datasetId: 1,
|
||||
parentId: 1,
|
||||
updateTime: -1
|
||||
});
|
||||
|
||||
// get forbid
|
||||
// DatasetCollectionSchema.index({ teamId: 1, datasetId: 1, forbid: 1 });
|
||||
|
||||
MongoDatasetCollection.syncIndexes({ background: true });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
export const MongoDatasetCollection: Model<DatasetCollectionSchemaType> =
|
||||
models[DatasetColCollectionName] || model(DatasetColCollectionName, DatasetCollectionSchema);
|
||||
|
@@ -53,29 +53,6 @@ export async function findCollectionAndChild({
|
||||
return [collection, ...childCollections];
|
||||
}
|
||||
|
||||
export async function getDatasetCollectionPaths({
|
||||
parentId = ''
|
||||
}: {
|
||||
parentId?: string;
|
||||
}): Promise<ParentTreePathItemType[]> {
|
||||
async function find(parentId?: string): Promise<ParentTreePathItemType[]> {
|
||||
if (!parentId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const parent = await MongoDatasetCollection.findOne({ _id: parentId }, 'name parentId');
|
||||
|
||||
if (!parent) return [];
|
||||
|
||||
const paths = await find(parent.parentId);
|
||||
paths.push({ parentId, parentName: parent.name });
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
return await find(parentId);
|
||||
}
|
||||
|
||||
export function getCollectionUpdateTime({ name, time }: { time?: Date; name: string }) {
|
||||
if (time) return time;
|
||||
if (name.startsWith('手动') || ['manual', 'mark'].includes(name)) return new Date('2999/9/9');
|
||||
|
@@ -37,7 +37,7 @@ export async function findDatasetAndAllChildren({
|
||||
return datasets;
|
||||
};
|
||||
const [dataset, childDatasets] = await Promise.all([
|
||||
MongoDataset.findById(datasetId),
|
||||
MongoDataset.findById(datasetId).lean(),
|
||||
find(datasetId)
|
||||
]);
|
||||
|
||||
|
@@ -77,27 +77,27 @@ const DatasetDataSchema = new Schema({
|
||||
rebuilding: Boolean
|
||||
});
|
||||
|
||||
try {
|
||||
// list collection and count data; list data; delete collection(relate data)
|
||||
DatasetDataSchema.index(
|
||||
{ teamId: 1, datasetId: 1, collectionId: 1, chunkIndex: 1, updateTime: -1 },
|
||||
{ background: true }
|
||||
);
|
||||
// full text index
|
||||
DatasetDataSchema.index({ teamId: 1, datasetId: 1, fullTextToken: 'text' }, { background: true });
|
||||
// Recall vectors after data matching
|
||||
DatasetDataSchema.index(
|
||||
{ teamId: 1, datasetId: 1, collectionId: 1, 'indexes.dataId': 1 },
|
||||
{ background: true }
|
||||
);
|
||||
DatasetDataSchema.index({ updateTime: 1 }, { background: true });
|
||||
// rebuild data
|
||||
DatasetDataSchema.index({ rebuilding: 1, teamId: 1, datasetId: 1 }, { background: true });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
export const MongoDatasetData: Model<DatasetDataSchemaType> =
|
||||
models[DatasetDataCollectionName] || model(DatasetDataCollectionName, DatasetDataSchema);
|
||||
|
||||
MongoDatasetData.syncIndexes();
|
||||
try {
|
||||
// list collection and count data; list data; delete collection(relate data)
|
||||
DatasetDataSchema.index({
|
||||
teamId: 1,
|
||||
datasetId: 1,
|
||||
collectionId: 1,
|
||||
chunkIndex: 1,
|
||||
updateTime: -1
|
||||
});
|
||||
// full text index
|
||||
DatasetDataSchema.index({ teamId: 1, datasetId: 1, fullTextToken: 'text' });
|
||||
// Recall vectors after data matching
|
||||
DatasetDataSchema.index({ teamId: 1, datasetId: 1, collectionId: 1, 'indexes.dataId': 1 });
|
||||
DatasetDataSchema.index({ updateTime: 1 });
|
||||
// rebuild data
|
||||
DatasetDataSchema.index({ rebuilding: 1, teamId: 1, datasetId: 1 });
|
||||
|
||||
MongoDatasetData.syncIndexes({ background: true });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
@@ -74,11 +74,6 @@ const DatasetSchema = new Schema({
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
permission: {
|
||||
type: String,
|
||||
enum: Object.keys(PermissionTypeMap),
|
||||
default: PermissionTypeEnum.private
|
||||
},
|
||||
websiteConfig: {
|
||||
type: {
|
||||
url: {
|
||||
|
@@ -12,13 +12,14 @@ import {
|
||||
DatasetDataWithCollectionType,
|
||||
SearchDataResponseItemType
|
||||
} from '@fastgpt/global/core/dataset/type';
|
||||
import { MongoDatasetCollection } from '../collection/schema';
|
||||
import { DatasetColCollectionName, MongoDatasetCollection } from '../collection/schema';
|
||||
import { reRankRecall } from '../../../core/ai/rerank';
|
||||
import { countPromptTokens } from '../../../common/string/tiktoken/index';
|
||||
import { datasetSearchResultConcat } from '@fastgpt/global/core/dataset/search/utils';
|
||||
import { hashStr } from '@fastgpt/global/common/string/tools';
|
||||
import { jiebaSplit } from '../../../common/string/jieba';
|
||||
import { getCollectionSourceData } from '@fastgpt/global/core/dataset/collection/utils';
|
||||
import { Types } from '../../../common/mongo';
|
||||
|
||||
type SearchDatasetDataProps = {
|
||||
teamId: string;
|
||||
@@ -50,9 +51,6 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
||||
usingReRank = usingReRank && global.reRankModels.length > 0;
|
||||
|
||||
// Compatible with topk limit
|
||||
if (maxTokens < 50) {
|
||||
maxTokens = 1500;
|
||||
}
|
||||
let set = new Set<string>();
|
||||
let usingSimilarityFilter = false;
|
||||
|
||||
@@ -75,7 +73,29 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
||||
fullTextLimit: 60
|
||||
};
|
||||
};
|
||||
const embeddingRecall = async ({ query, limit }: { query: string; limit: number }) => {
|
||||
const getForbidData = async () => {
|
||||
const collections = await MongoDatasetCollection.find(
|
||||
{
|
||||
teamId,
|
||||
datasetId: { $in: datasetIds },
|
||||
forbid: true
|
||||
},
|
||||
'_id'
|
||||
);
|
||||
|
||||
return {
|
||||
forbidCollectionIdList: collections.map((item) => String(item._id))
|
||||
};
|
||||
};
|
||||
const embeddingRecall = async ({
|
||||
query,
|
||||
limit,
|
||||
forbidCollectionIdList
|
||||
}: {
|
||||
query: string;
|
||||
limit: number;
|
||||
forbidCollectionIdList: string[];
|
||||
}) => {
|
||||
const { vectors, tokens } = await getVectorsByText({
|
||||
model: getVectorModel(model),
|
||||
input: query,
|
||||
@@ -86,7 +106,8 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
||||
teamId,
|
||||
datasetIds,
|
||||
vector: vectors[0],
|
||||
limit
|
||||
limit,
|
||||
forbidCollectionIdList
|
||||
});
|
||||
|
||||
// get q and a
|
||||
@@ -161,27 +182,66 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
||||
|
||||
let searchResults = (
|
||||
await Promise.all(
|
||||
datasetIds.map((id) =>
|
||||
MongoDatasetData.find(
|
||||
datasetIds.map(async (id) => {
|
||||
return MongoDatasetData.aggregate([
|
||||
{
|
||||
teamId,
|
||||
datasetId: id,
|
||||
$text: { $search: jiebaSplit({ text: query }) }
|
||||
$match: {
|
||||
teamId: new Types.ObjectId(teamId),
|
||||
datasetId: new Types.ObjectId(id),
|
||||
$text: { $search: jiebaSplit({ text: query }) }
|
||||
}
|
||||
},
|
||||
{
|
||||
score: { $meta: 'textScore' },
|
||||
_id: 1,
|
||||
datasetId: 1,
|
||||
collectionId: 1,
|
||||
q: 1,
|
||||
a: 1,
|
||||
chunkIndex: 1
|
||||
$addFields: {
|
||||
score: { $meta: 'textScore' }
|
||||
}
|
||||
},
|
||||
{
|
||||
$sort: {
|
||||
score: { $meta: 'textScore' }
|
||||
}
|
||||
},
|
||||
{
|
||||
$limit: limit
|
||||
},
|
||||
{
|
||||
$lookup: {
|
||||
from: DatasetColCollectionName,
|
||||
let: { collectionId: '$collectionId' },
|
||||
pipeline: [
|
||||
{
|
||||
$match: {
|
||||
$expr: { $eq: ['$_id', '$$collectionId'] },
|
||||
forbid: { $eq: false } // 直接在lookup阶段过滤
|
||||
}
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
_id: 1 // 只需要_id字段来确认匹配
|
||||
}
|
||||
}
|
||||
],
|
||||
as: 'collection'
|
||||
}
|
||||
},
|
||||
{
|
||||
$match: {
|
||||
collection: { $ne: [] }
|
||||
}
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
_id: 1,
|
||||
datasetId: 1,
|
||||
collectionId: 1,
|
||||
q: 1,
|
||||
a: 1,
|
||||
chunkIndex: 1,
|
||||
score: 1
|
||||
}
|
||||
}
|
||||
)
|
||||
.sort({ score: { $meta: 'textScore' } })
|
||||
.limit(limit)
|
||||
.lean()
|
||||
)
|
||||
]);
|
||||
})
|
||||
)
|
||||
).flat() as (DatasetDataSchemaType & { score: number })[];
|
||||
|
||||
@@ -255,27 +315,6 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
const filterResultsByMaxTokens = async (
|
||||
list: SearchDataResponseItemType[],
|
||||
maxTokens: number
|
||||
) => {
|
||||
const results: SearchDataResponseItemType[] = [];
|
||||
let totalTokens = 0;
|
||||
|
||||
for await (const item of list) {
|
||||
totalTokens += await countPromptTokens(item.q + item.a);
|
||||
|
||||
if (totalTokens > maxTokens + 500) {
|
||||
break;
|
||||
}
|
||||
results.push(item);
|
||||
if (totalTokens > maxTokens) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return results.length === 0 ? list.slice(0, 1) : results;
|
||||
};
|
||||
const multiQueryRecall = async ({
|
||||
embeddingLimit,
|
||||
fullTextLimit
|
||||
@@ -288,12 +327,15 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
||||
const fullTextRecallResList: SearchDataResponseItemType[][] = [];
|
||||
let totalTokens = 0;
|
||||
|
||||
const { forbidCollectionIdList } = await getForbidData();
|
||||
|
||||
await Promise.all(
|
||||
queries.map(async (query) => {
|
||||
const [{ tokens, embeddingRecallResults }, { fullTextRecallResults }] = await Promise.all([
|
||||
embeddingRecall({
|
||||
query,
|
||||
limit: embeddingLimit
|
||||
limit: embeddingLimit,
|
||||
forbidCollectionIdList
|
||||
}),
|
||||
fullTextRecall({
|
||||
query,
|
||||
@@ -397,8 +439,28 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
||||
return filterSameDataResults;
|
||||
})();
|
||||
|
||||
// token filter
|
||||
const filterMaxTokensResult = await (async () => {
|
||||
const results: SearchDataResponseItemType[] = [];
|
||||
let totalTokens = 0;
|
||||
|
||||
for await (const item of scoreFilter) {
|
||||
totalTokens += await countPromptTokens(item.q + item.a);
|
||||
|
||||
if (totalTokens > maxTokens + 500) {
|
||||
break;
|
||||
}
|
||||
results.push(item);
|
||||
if (totalTokens > maxTokens) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return results.length === 0 ? scoreFilter.slice(0, 1) : results;
|
||||
})();
|
||||
|
||||
return {
|
||||
searchRes: await filterResultsByMaxTokens(scoreFilter, maxTokens),
|
||||
searchRes: filterMaxTokensResult,
|
||||
tokens,
|
||||
searchMode,
|
||||
limit: maxTokens,
|
||||
|
3
packages/service/core/plugin/type.d.ts
vendored
3
packages/service/core/plugin/type.d.ts
vendored
@@ -1,6 +1,7 @@
|
||||
import { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d';
|
||||
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
|
||||
|
||||
declare global {
|
||||
var communityPluginsV1: PluginTemplateType[];
|
||||
var communityPlugins: PluginTemplateType[];
|
||||
var communityPlugins: SystemPluginTemplateItemType[];
|
||||
}
|
||||
|
@@ -3,10 +3,10 @@ import { countMessagesTokens } from '../../../../common/string/tiktoken/index';
|
||||
import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
|
||||
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { getAIApi } from '../../../ai/config';
|
||||
import type { ClassifyQuestionAgentItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ClassifyQuestionAgentItemType } from '@fastgpt/global/core/workflow/template/system/classifyQuestion/type';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import { Prompt_CQJson } from '@fastgpt/global/core/ai/prompt/agent';
|
||||
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||
|
@@ -7,10 +7,10 @@ import {
|
||||
} from '../../../../common/string/tiktoken/index';
|
||||
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { getAIApi } from '../../../ai/config';
|
||||
import type { ContextExtractAgentItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ContextExtractAgentItemType } from '@fastgpt/global/core/workflow/template/system/contextExtract/type';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { Prompt_ExtractJson } from '@fastgpt/global/core/ai/prompt/agent';
|
||||
import { replaceVariable, sliceJsonStr } from '@fastgpt/global/common/string/tools';
|
||||
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
|
||||
export type AnswerProps = ModuleDispatchProps<{}>;
|
||||
|
@@ -377,31 +377,41 @@ async function streamResponse({
|
||||
if (toolCall.function?.arguments === undefined) {
|
||||
toolCall.function.arguments = '';
|
||||
}
|
||||
toolCalls.push({
|
||||
...toolCall,
|
||||
toolName: toolNode.name,
|
||||
toolAvatar: toolNode.avatar
|
||||
});
|
||||
|
||||
if (detail) {
|
||||
responseWrite({
|
||||
write,
|
||||
event: SseResponseEventEnum.toolCall,
|
||||
data: JSON.stringify({
|
||||
tool: {
|
||||
id: toolCall.id,
|
||||
toolName: toolNode.name,
|
||||
toolAvatar: toolNode.avatar,
|
||||
functionName: toolCall.function.name,
|
||||
params: toolCall.function.arguments,
|
||||
response: ''
|
||||
}
|
||||
})
|
||||
// Get last tool call
|
||||
const lastToolCall = toolCalls[toolCalls.length - 1];
|
||||
|
||||
// new tool
|
||||
if (lastToolCall?.id !== toolCall.id) {
|
||||
toolCalls.push({
|
||||
...toolCall,
|
||||
toolName: toolNode.name,
|
||||
toolAvatar: toolNode.avatar
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
if (detail) {
|
||||
responseWrite({
|
||||
write,
|
||||
event: SseResponseEventEnum.toolCall,
|
||||
data: JSON.stringify({
|
||||
tool: {
|
||||
id: toolCall.id,
|
||||
toolName: toolNode.name,
|
||||
toolAvatar: toolNode.avatar,
|
||||
functionName: toolCall.function.name,
|
||||
params: toolCall.function.arguments,
|
||||
response: ''
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
// last tool, update params
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* arg 插入最后一个工具的参数里 */
|
||||
|
@@ -3,7 +3,7 @@ import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workfl
|
||||
import type {
|
||||
ModuleDispatchProps,
|
||||
DispatchNodeResponseType
|
||||
} from '@fastgpt/global/core/workflow/type/index.d';
|
||||
} from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||
import type { DispatchFlowResponse } from '../../type.d';
|
||||
|
@@ -36,7 +36,7 @@ import {
|
||||
} from '@fastgpt/global/core/ai/prompt/AIChat';
|
||||
import type { AIChatNodeProps } from '@fastgpt/global/core/workflow/runtime/type.d';
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { responseWrite, responseWriteController } from '../../../../common/response';
|
||||
import { getLLMModel, ModelTypeEnum } from '../../../ai/model';
|
||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import axios from 'axios';
|
||||
@@ -8,7 +8,7 @@ import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runti
|
||||
type RunCodeType = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.codeType]: 'js';
|
||||
[NodeInputKeyEnum.code]: string;
|
||||
[key: string]: any;
|
||||
[NodeInputKeyEnum.addInputParam]: Record<string, any>;
|
||||
}>;
|
||||
type RunCodeResponse = DispatchNodeResultType<{
|
||||
[NodeOutputKeyEnum.error]?: any;
|
||||
@@ -18,7 +18,7 @@ type RunCodeResponse = DispatchNodeResultType<{
|
||||
|
||||
export const dispatchRunCode = async (props: RunCodeType): Promise<RunCodeResponse> => {
|
||||
const {
|
||||
params: { codeType, code, ...customVariables }
|
||||
params: { codeType, code, [NodeInputKeyEnum.addInputParam]: customVariables }
|
||||
} = props;
|
||||
|
||||
const sandBoxRequestUrl = `${process.env.SANDBOX_URL}/sandbox/js`;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { datasetSearchResultConcat } from '@fastgpt/global/core/dataset/search/utils';
|
||||
import { filterSearchResultsByMaxChars } from '../../utils';
|
||||
|
@@ -5,7 +5,7 @@ import {
|
||||
import { formatModelChars2Points } from '../../../../support/wallet/usage/utils';
|
||||
import type { SelectedDatasetType } from '@fastgpt/global/core/workflow/api.d';
|
||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { ModelTypeEnum, getLLMModel, getVectorModel } from '../../../ai/model';
|
||||
import { searchDatasetData } from '../../../dataset/search/controller';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
|
@@ -2,15 +2,20 @@ import { NextApiResponse } from 'next';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import type { ChatDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type {
|
||||
ChatDispatchProps,
|
||||
ModuleDispatchProps
|
||||
} from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type {
|
||||
AIChatItemValueItemType,
|
||||
ChatHistoryItemResType,
|
||||
ToolRunResponseItemType
|
||||
} from '@fastgpt/global/core/chat/type.d';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import {
|
||||
FlowNodeInputTypeEnum,
|
||||
FlowNodeTypeEnum
|
||||
} from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import { responseWriteNodeStatus } from '../../../common/response';
|
||||
import { getSystemTime } from '@fastgpt/global/common/time/timezone';
|
||||
@@ -47,6 +52,8 @@ import { dispatchUpdateVariable } from './tools/runUpdateVar';
|
||||
import { addLog } from '../../../common/system/log';
|
||||
import { surrenderProcess } from '../../../common/system/tools';
|
||||
import { dispatchRunCode } from './code/run';
|
||||
import { dispatchTextEditor } from './tools/textEditor';
|
||||
import { dispatchCustomFeedback } from './tools/customFeedback';
|
||||
|
||||
const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
||||
@@ -68,6 +75,8 @@ const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||
[FlowNodeTypeEnum.ifElseNode]: dispatchIfElse,
|
||||
[FlowNodeTypeEnum.variableUpdate]: dispatchUpdateVariable,
|
||||
[FlowNodeTypeEnum.code]: dispatchRunCode,
|
||||
[FlowNodeTypeEnum.textEditor]: dispatchTextEditor,
|
||||
[FlowNodeTypeEnum.customFeedback]: dispatchCustomFeedback,
|
||||
|
||||
// none
|
||||
[FlowNodeTypeEnum.systemConfig]: dispatchSystemConfig,
|
||||
@@ -259,8 +268,26 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
}
|
||||
/* Inject data into module input */
|
||||
function getNodeRunParams(node: RuntimeNodeItemType) {
|
||||
const params: Record<string, any> = {};
|
||||
if (node.flowNodeType === FlowNodeTypeEnum.pluginInput) {
|
||||
return node.inputs.reduce<Record<string, any>>((acc, item) => {
|
||||
acc[item.key] = valueTypeFormat(item.value, item.valueType);
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
// common nodes
|
||||
const dynamicInput = node.inputs.find(
|
||||
(item) => item.renderTypeList[0] === FlowNodeInputTypeEnum.addInputParam
|
||||
);
|
||||
const params: Record<string, any> = dynamicInput
|
||||
? {
|
||||
[dynamicInput.key]: {}
|
||||
}
|
||||
: {};
|
||||
|
||||
node.inputs.forEach((input) => {
|
||||
if (input.key === dynamicInput?.key) return;
|
||||
|
||||
// replace {{}} variables
|
||||
let value = replaceVariable(input.value, variables);
|
||||
|
||||
@@ -270,7 +297,13 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
nodes: runtimeNodes,
|
||||
variables
|
||||
});
|
||||
// format valueType
|
||||
|
||||
// concat dynamic inputs
|
||||
if (input.canEdit && dynamicInput && params[dynamicInput.key]) {
|
||||
params[dynamicInput.key][input.key] = valueTypeFormat(value, input.valueType);
|
||||
}
|
||||
|
||||
// Not dynamic input
|
||||
params[input.key] = valueTypeFormat(value, input.valueType);
|
||||
});
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
||||
import { UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
export type UserChatInputProps = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.userChatInput]: string;
|
||||
[NodeInputKeyEnum.inputFiles]: UserChatItemValueItemType['file'][];
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { dispatchWorkFlow } from '../index';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { getPluginRuntimeById, splitCombinePluginId } from '../../../app/plugin/controller';
|
||||
import {
|
||||
@@ -11,7 +10,6 @@ import {
|
||||
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { updateToolInputValue } from '../agent/runTool/utils';
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import { authAppByTmbId } from '../../../../support/permission/app/auth';
|
||||
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||
@@ -50,41 +48,6 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
||||
(item) => item.flowNodeType === FlowNodeTypeEnum.pluginInput
|
||||
);
|
||||
if (!inputModule) return Promise.reject('Plugin error, It has no set input.');
|
||||
const hasDynamicInput = inputModule.inputs.find(
|
||||
(input) => input.key === NodeInputKeyEnum.addInputParam
|
||||
);
|
||||
|
||||
const startParams: Record<string, any> = (() => {
|
||||
if (!hasDynamicInput) return data;
|
||||
|
||||
const params: Record<string, any> = {
|
||||
[NodeInputKeyEnum.addInputParam]: {}
|
||||
};
|
||||
|
||||
for (const key in data) {
|
||||
if (key === NodeInputKeyEnum.addInputParam) continue;
|
||||
|
||||
const input = inputModule.inputs.find((input) => input.key === key);
|
||||
if (input) {
|
||||
params[key] = data[key];
|
||||
} else {
|
||||
params[NodeInputKeyEnum.addInputParam][key] = data[key];
|
||||
}
|
||||
}
|
||||
|
||||
return params;
|
||||
})();
|
||||
|
||||
// replace input by dynamic variables
|
||||
if (hasDynamicInput) {
|
||||
for (const key in startParams) {
|
||||
if (key === NodeInputKeyEnum.addInputParam) continue;
|
||||
startParams[key] = replaceVariable(
|
||||
startParams[key],
|
||||
startParams[NodeInputKeyEnum.addInputParam]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const { flowResponses, flowUsages, assistantResponses } = await dispatchWorkFlow({
|
||||
...props,
|
||||
@@ -96,7 +59,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
||||
showStatus: false,
|
||||
inputs: updateToolInputValue({
|
||||
inputs: node.inputs,
|
||||
params: startParams
|
||||
params: data
|
||||
})
|
||||
};
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
|
||||
export type PluginInputProps = ModuleDispatchProps<{
|
||||
[key: string]: any;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type.d';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
|
||||
|
@@ -4,7 +4,7 @@ import {
|
||||
} from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { responseWrite } from '../../../../common/response';
|
||||
import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
export type AnswerProps = ModuleDispatchProps<{
|
||||
|
@@ -0,0 +1,54 @@
|
||||
import {
|
||||
DispatchNodeResponseKeyEnum,
|
||||
SseResponseEventEnum
|
||||
} from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { addCustomFeedbacks } from '../../../chat/controller';
|
||||
import { responseWrite } from '../../../../common/response';
|
||||
import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
|
||||
type Props = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.textareaInput]: string;
|
||||
}>;
|
||||
type Response = DispatchNodeResultType<{}>;
|
||||
|
||||
export const dispatchCustomFeedback = (props: Record<string, any>): Response => {
|
||||
const {
|
||||
res,
|
||||
app: { _id: appId },
|
||||
chatId,
|
||||
responseChatItemId: chatItemId,
|
||||
stream,
|
||||
detail,
|
||||
params: { system_textareaInput: feedbackText = '' }
|
||||
} = props as Props;
|
||||
|
||||
setTimeout(() => {
|
||||
addCustomFeedbacks({
|
||||
appId,
|
||||
chatId,
|
||||
chatItemId,
|
||||
feedbacks: [feedbackText]
|
||||
});
|
||||
}, 60000);
|
||||
|
||||
if (stream) {
|
||||
if (!chatId || !chatItemId) {
|
||||
responseWrite({
|
||||
res,
|
||||
event: detail ? SseResponseEventEnum.fastAnswer : undefined,
|
||||
data: textAdaptGptResponse({
|
||||
text: `\n\n**自定义反馈成功: (仅调试模式下展示该内容)**: "${feedbackText}"\n\n`
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||
textOutput: feedbackText
|
||||
}
|
||||
};
|
||||
};
|
@@ -1,4 +1,4 @@
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import {
|
||||
NodeInputKeyEnum,
|
||||
NodeOutputKeyEnum,
|
||||
@@ -16,6 +16,7 @@ import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/ty
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { responseWrite } from '../../../../common/response';
|
||||
import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { getCommunityCb } from '@fastgpt/plugins/register';
|
||||
|
||||
type PropsArrType = {
|
||||
key: string;
|
||||
@@ -65,14 +66,17 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
||||
return Promise.reject('Http url is empty');
|
||||
}
|
||||
|
||||
const concatVariables = {
|
||||
const systemVariables = {
|
||||
appId,
|
||||
chatId,
|
||||
responseChatItemId,
|
||||
histories: histories?.slice(-10) || []
|
||||
};
|
||||
const concatVariables = {
|
||||
...variables,
|
||||
histories: histories?.slice(-10) || [],
|
||||
...body,
|
||||
...dynamicInput
|
||||
// ...dynamicInput,
|
||||
...systemVariables
|
||||
};
|
||||
|
||||
const allVariables = {
|
||||
@@ -116,13 +120,23 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
||||
})();
|
||||
|
||||
try {
|
||||
const { formatResponse, rawResponse } = await fetchData({
|
||||
method: httpMethod,
|
||||
url: httpReqUrl,
|
||||
headers,
|
||||
body: requestBody,
|
||||
params
|
||||
});
|
||||
const { formatResponse, rawResponse } = await (async () => {
|
||||
const communityPluginCb = await getCommunityCb();
|
||||
if (communityPluginCb[httpReqUrl]) {
|
||||
const pluginResult = await communityPluginCb[httpReqUrl](requestBody);
|
||||
return {
|
||||
formatResponse: pluginResult,
|
||||
rawResponse: pluginResult
|
||||
};
|
||||
}
|
||||
return fetchData({
|
||||
method: httpMethod,
|
||||
url: httpReqUrl,
|
||||
headers,
|
||||
body: requestBody,
|
||||
params
|
||||
});
|
||||
})();
|
||||
|
||||
// format output value type
|
||||
const results: Record<string, any> = {};
|
||||
@@ -183,7 +197,7 @@ async function fetchData({
|
||||
headers: Record<string, any>;
|
||||
body: Record<string, any>;
|
||||
params: Record<string, any>;
|
||||
}): Promise<Record<string, any>> {
|
||||
}) {
|
||||
const { data: response } = await axios({
|
||||
method,
|
||||
baseURL: `http://${SERVICE_LOCAL_HOST}`,
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { ModelTypeEnum, getLLMModel } from '../../../../core/ai/model';
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import { SelectAppItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { SelectAppItemType } from '@fastgpt/global/core/workflow/template/system/runApp/type';
|
||||
import { dispatchWorkFlow } from '../index';
|
||||
import { responseWrite } from '../../../../common/response';
|
||||
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||
|
@@ -10,7 +10,7 @@ import {
|
||||
IfElseConditionType,
|
||||
IfElseListItemType
|
||||
} from '@fastgpt/global/core/workflow/template/system/ifElse/type';
|
||||
import { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { getElseIFLabel, getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||
import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { replaceRegChars } from '@fastgpt/global/common/string/tools';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import axios from 'axios';
|
||||
@@ -39,11 +39,13 @@ export const dispatchLafRequest = async (props: LafRequestProps): Promise<LafRes
|
||||
}
|
||||
|
||||
const concatVariables = {
|
||||
...variables,
|
||||
...body,
|
||||
...dynamicInput,
|
||||
appId,
|
||||
chatId,
|
||||
responseChatItemId,
|
||||
...variables,
|
||||
...body
|
||||
histories: histories?.slice(-10) || []
|
||||
};
|
||||
|
||||
httpReqUrl = replaceVariable(httpReqUrl, concatVariables);
|
||||
|
@@ -6,7 +6,7 @@ import {
|
||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { TUpdateListItem } from '@fastgpt/global/core/workflow/template/system/variableUpdate/type';
|
||||
import { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { removeSystemVariable, valueTypeFormat } from '../utils';
|
||||
import { responseWrite } from '../../../../common/response';
|
||||
|
||||
|
52
packages/service/core/workflow/dispatch/tools/textEditor.ts
Normal file
52
packages/service/core/workflow/dispatch/tools/textEditor.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import {
|
||||
DispatchNodeResponseKeyEnum,
|
||||
SseResponseEventEnum
|
||||
} from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { responseWrite } from '../../../../common/response';
|
||||
import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
|
||||
type Props = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.textareaInput]: string;
|
||||
[NodeInputKeyEnum.addInputParam]: Record<string, any>;
|
||||
}>;
|
||||
type Response = DispatchNodeResultType<{
|
||||
[NodeOutputKeyEnum.text]: string;
|
||||
}>;
|
||||
|
||||
export const dispatchTextEditor = (props: Record<string, any>): Response => {
|
||||
const {
|
||||
variables,
|
||||
params: { system_textareaInput: text = '', system_addInputParam: customVariables = {} }
|
||||
} = props as Props;
|
||||
|
||||
// format variable
|
||||
Object.keys(customVariables).forEach((key) => {
|
||||
let val = customVariables[key];
|
||||
|
||||
if (typeof val === 'object') {
|
||||
val = JSON.stringify(val, null, 2);
|
||||
} else if (typeof val === 'number') {
|
||||
val = String(val);
|
||||
} else if (typeof val === 'boolean') {
|
||||
val = val ? 'true' : 'false';
|
||||
}
|
||||
|
||||
customVariables[key] = val;
|
||||
});
|
||||
|
||||
const textResult = replaceVariable(text, {
|
||||
...customVariables,
|
||||
...variables
|
||||
});
|
||||
|
||||
return {
|
||||
[NodeOutputKeyEnum.text]: textResult,
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||
textOutput: textResult
|
||||
}
|
||||
};
|
||||
};
|
@@ -6,6 +6,7 @@ import {
|
||||
NodeOutputKeyEnum
|
||||
} from '@fastgpt/global/core/workflow/constants';
|
||||
import { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io';
|
||||
|
||||
export const filterToolNodeIdByEdges = ({
|
||||
nodeId,
|
||||
|
@@ -5,10 +5,10 @@ import { filterGPTMessageByMaxTokens } from '../../../chat/utils';
|
||||
import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
|
||||
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { getAIApi } from '../../../ai/config';
|
||||
import type { ClassifyQuestionAgentItemType } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ClassifyQuestionAgentItemType } from '@fastgpt/global/core/workflow/template/system/classifyQuestion/type';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import { Prompt_CQJson } from '@fastgpt/global/core/ai/prompt/agent';
|
||||
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||
|
@@ -9,10 +9,10 @@ import {
|
||||
|
||||
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { getAIApi } from '../../../ai/config';
|
||||
import type { ContextExtractAgentItemType } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ContextExtractAgentItemType } from '@fastgpt/global/core/workflow/template/system/contextExtract/type';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { Prompt_ExtractJson } from '@fastgpt/global/core/ai/prompt/agent';
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
|
||||
export type AnswerProps = ModuleDispatchProps<{}>;
|
||||
|
@@ -4,7 +4,7 @@ import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/node/type';
|
||||
import type {
|
||||
ModuleDispatchProps,
|
||||
DispatchNodeResponseType
|
||||
} from '@fastgpt/global/core/workflow/type.d';
|
||||
} from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||
import type { DispatchFlowResponse } from '../../type.d';
|
||||
|
@@ -19,7 +19,7 @@ import { formatModelChars2Points } from '../../../../support/wallet/usage/utils'
|
||||
import type { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||
import { postTextCensor } from '../../../../common/api/requestPlusApi';
|
||||
import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/global/core/ai/constants';
|
||||
import type { FlowNodeItemType } from '@fastgpt/global/core/workflow/type';
|
||||
import type { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||
import type { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import {
|
||||
countMessagesTokens,
|
||||
@@ -37,7 +37,7 @@ import {
|
||||
} from '@fastgpt/global/core/ai/prompt/AIChat';
|
||||
import type { AIChatNodeProps } from '@fastgpt/global/core/workflow/runtime/type.d';
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { responseWrite, responseWriteController } from '../../../../common/response';
|
||||
import { getLLMModel, ModelTypeEnum } from '../../../ai/model';
|
||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { datasetSearchResultConcat } from '@fastgpt/global/core/dataset/search/utils';
|
||||
import { filterSearchResultsByMaxChars } from '../../utils';
|
||||
|
@@ -6,7 +6,7 @@ import {
|
||||
import { formatModelChars2Points } from '../../../../support/wallet/usage/utils';
|
||||
import type { SelectedDatasetType } from '@fastgpt/global/core/workflow/api.d';
|
||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { ModelTypeEnum, getLLMModel, getVectorModel } from '../../../ai/model';
|
||||
import { searchDatasetData } from '../../../dataset/search/controller';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
|
@@ -3,24 +3,20 @@ import { NextApiResponse } from 'next';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import type { ChatDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ChatDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import type {
|
||||
AIChatItemValueItemType,
|
||||
ChatHistoryItemResType,
|
||||
ToolRunResponseItemType
|
||||
} from '@fastgpt/global/core/chat/type.d';
|
||||
import {
|
||||
FlowNodeInputTypeEnum,
|
||||
FlowNodeTypeEnum
|
||||
} from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import { responseWriteNodeStatus } from '../../../common/response';
|
||||
import { getSystemTime } from '@fastgpt/global/common/time/timezone';
|
||||
|
||||
import { dispatchHistory } from './init/history';
|
||||
import { dispatchChatInput } from './init/userChatInput';
|
||||
import { dispatchChatCompletion } from './chat/oneapi';
|
||||
import { dispatchDatasetSearch } from './dataset/search';
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { getHistories } from '../utils';
|
||||
export type HistoryProps = ModuleDispatchProps<{
|
||||
maxContext?: number;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
export type UserChatInputProps = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.userChatInput]: string;
|
||||
}>;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { dispatchWorkFlowV1 } from '../index';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import {
|
||||
@@ -42,7 +42,7 @@ const getPluginTemplateById = async (id: string): Promise<PluginTemplateType> =>
|
||||
showStatus: true,
|
||||
source: PluginSourceEnum.personal,
|
||||
modules: item.modules,
|
||||
templateType: FlowNodeTemplateTypeEnum.personalPlugin
|
||||
templateType: FlowNodeTemplateTypeEnum.teamApp
|
||||
};
|
||||
}
|
||||
return Promise.reject('plugin not found');
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
|
||||
export type PluginInputProps = ModuleDispatchProps<{
|
||||
[key: string]: any;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type.d';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { responseWrite } from '../../../../common/response';
|
||||
import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
export type AnswerProps = ModuleDispatchProps<{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import axios from 'axios';
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import axios from 'axios';
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// @ts-nocheck
|
||||
import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { ModelTypeEnum, getLLMModel } from '../../../../core/ai/model';
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// @ts-nocheck
|
||||
import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import { SelectAppItemType } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { SelectAppItemType } from '@fastgpt/global/core/workflow/template/system/runApp/type';
|
||||
import { dispatchWorkFlowV1 } from '../index';
|
||||
import { MongoApp } from '../../../../core/app/schema';
|
||||
import { responseWrite } from '../../../../common/response';
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import axios from 'axios';
|
||||
|
@@ -5,7 +5,7 @@ import {
|
||||
NodeOutputKeyEnum
|
||||
} from '@fastgpt/global/core/workflow/constants';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { FlowNodeItemType, StoreNodeItemType } from '@fastgpt/global/core/workflow/type/index';
|
||||
import { FlowNodeItemType, StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||
export const DYNAMIC_INPUT_KEY = 'DYNAMIC_INPUT_KEY';
|
||||
|
||||
export const setEntryEntries = (modules: StoreNodeItemType[]) => {
|
||||
|
@@ -3,6 +3,7 @@
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@fastgpt/global": "workspace:*",
|
||||
"@fastgpt/plugins": "workspace:*",
|
||||
"@node-rs/jieba": "1.10.0",
|
||||
"@xmldom/xmldom": "^0.8.10",
|
||||
"@zilliz/milvus2-sdk-node": "2.4.2",
|
||||
|
@@ -10,6 +10,8 @@ import { getResourcePermission } from '../controller';
|
||||
import { AppPermission } from '@fastgpt/global/support/permission/app/controller';
|
||||
import { AuthResponseType } from '../type/auth.d';
|
||||
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
import { AppFolderTypeList } from '@fastgpt/global/core/app/constants';
|
||||
import { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
|
||||
|
||||
export const authAppByTmbId = async ({
|
||||
tmbId,
|
||||
@@ -19,27 +21,57 @@ export const authAppByTmbId = async ({
|
||||
tmbId: string;
|
||||
appId: string;
|
||||
per: PermissionValueType;
|
||||
}) => {
|
||||
}): Promise<{
|
||||
app: AppDetailType;
|
||||
}> => {
|
||||
const { teamId, permission: tmbPer } = await getTmbInfoByTmbId({ tmbId });
|
||||
|
||||
const app = await (async () => {
|
||||
// get app and per
|
||||
const [app, rp] = await Promise.all([
|
||||
MongoApp.findOne({ _id: appId, teamId }).lean(),
|
||||
getResourcePermission({
|
||||
teamId,
|
||||
tmbId,
|
||||
resourceId: appId,
|
||||
resourceType: PerResourceTypeEnum.app
|
||||
}) // this could be null
|
||||
]);
|
||||
const app = await MongoApp.findOne({ _id: appId }).lean();
|
||||
|
||||
if (!app) {
|
||||
return Promise.reject(AppErrEnum.unExist);
|
||||
}
|
||||
|
||||
const isOwner = tmbPer.isOwner || String(app.tmbId) === String(tmbId);
|
||||
const Per = new AppPermission({ per: rp?.permission ?? app.defaultPermission, isOwner });
|
||||
|
||||
const { Per, defaultPermission } = await (async () => {
|
||||
if (
|
||||
AppFolderTypeList.includes(app.type) ||
|
||||
app.inheritPermission === false ||
|
||||
!app.parentId
|
||||
) {
|
||||
// 1. is a folder. (Folders have compeletely permission)
|
||||
// 2. inheritPermission is false.
|
||||
// 3. is root folder/app.
|
||||
const rp = await getResourcePermission({
|
||||
teamId,
|
||||
tmbId,
|
||||
resourceId: appId,
|
||||
resourceType: PerResourceTypeEnum.app
|
||||
});
|
||||
const Per = new AppPermission({ per: rp?.permission ?? app.defaultPermission, isOwner });
|
||||
return {
|
||||
Per,
|
||||
defaultPermission: app.defaultPermission
|
||||
};
|
||||
} else {
|
||||
// is not folder and inheritPermission is true and is not root folder.
|
||||
const { app: parent } = await authAppByTmbId({
|
||||
tmbId,
|
||||
appId: app.parentId,
|
||||
per
|
||||
});
|
||||
|
||||
const Per = new AppPermission({
|
||||
per: parent.permission.value,
|
||||
isOwner
|
||||
});
|
||||
return {
|
||||
Per,
|
||||
defaultPermission: parent.defaultPermission
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
if (!Per.checkPer(per)) {
|
||||
return Promise.reject(AppErrEnum.unAuthApp);
|
||||
@@ -47,6 +79,7 @@ export const authAppByTmbId = async ({
|
||||
|
||||
return {
|
||||
...app,
|
||||
defaultPermission,
|
||||
permission: Per
|
||||
};
|
||||
})();
|
||||
@@ -59,7 +92,7 @@ export const authApp = async ({
|
||||
per,
|
||||
...props
|
||||
}: AuthPropsType & {
|
||||
appId: string;
|
||||
appId: ParentIdType;
|
||||
}): Promise<
|
||||
AuthResponseType & {
|
||||
app: AppDetailType;
|
||||
@@ -68,6 +101,10 @@ export const authApp = async ({
|
||||
const result = await parseHeaderCert(props);
|
||||
const { tmbId } = result;
|
||||
|
||||
if (!appId) {
|
||||
return Promise.reject(AppErrEnum.unExist);
|
||||
}
|
||||
|
||||
const { app } = await authAppByTmbId({
|
||||
tmbId,
|
||||
appId,
|
||||
|
@@ -7,6 +7,9 @@ import { AuthUserTypeEnum, PerResourceTypeEnum } from '@fastgpt/global/support/p
|
||||
import { authOpenApiKey } from '../openapi/auth';
|
||||
import { FileTokenQuery } from '@fastgpt/global/common/file/type';
|
||||
import { MongoResourcePermission } from './schema';
|
||||
import { ClientSession } from 'mongoose';
|
||||
import { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
|
||||
import { ResourcePermissionType } from '@fastgpt/global/support/permission/type';
|
||||
|
||||
export const getResourcePermission = async ({
|
||||
resourceType,
|
||||
@@ -31,9 +34,45 @@ export const getResourcePermission = async ({
|
||||
}
|
||||
return per;
|
||||
};
|
||||
export async function getResourceAllClbs({
|
||||
resourceId,
|
||||
teamId,
|
||||
resourceType,
|
||||
session
|
||||
}: {
|
||||
resourceId: ParentIdType;
|
||||
teamId: string;
|
||||
resourceType: PerResourceTypeEnum;
|
||||
session?: ClientSession;
|
||||
}): Promise<ResourcePermissionType[]> {
|
||||
if (!resourceId) return [];
|
||||
return MongoResourcePermission.find(
|
||||
{
|
||||
resourceId,
|
||||
resourceType: resourceType,
|
||||
teamId: teamId
|
||||
},
|
||||
null,
|
||||
{
|
||||
session
|
||||
}
|
||||
).lean();
|
||||
}
|
||||
export const delResourcePermissionById = (id: string) => {
|
||||
return MongoResourcePermission.findByIdAndRemove(id);
|
||||
};
|
||||
export const delResourcePermission = ({
|
||||
session,
|
||||
...props
|
||||
}: {
|
||||
resourceType: PerResourceTypeEnum;
|
||||
resourceId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
session?: ClientSession;
|
||||
}) => {
|
||||
return MongoResourcePermission.deleteOne(props, { session });
|
||||
};
|
||||
|
||||
/* 下面代码等迁移 */
|
||||
/* create token */
|
||||
|
221
packages/service/support/permission/inheritPermission.ts
Normal file
221
packages/service/support/permission/inheritPermission.ts
Normal file
@@ -0,0 +1,221 @@
|
||||
import { mongoSessionRun } from '../../common/mongo/sessionRun';
|
||||
import { MongoResourcePermission } from './schema';
|
||||
import { ClientSession, Model } from 'mongoose';
|
||||
import { NullPermission, PerResourceTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
|
||||
import { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
|
||||
import { getResourceAllClbs } from './controller';
|
||||
|
||||
export type SyncChildrenPermissionResourceType = {
|
||||
_id: string;
|
||||
type: string;
|
||||
teamId: string;
|
||||
parentId?: ParentIdType;
|
||||
};
|
||||
export type UpdateCollaboratorItem = {
|
||||
permission: PermissionValueType;
|
||||
tmbId: string;
|
||||
};
|
||||
|
||||
// sync the permission to all children folders.
|
||||
export async function syncChildrenPermission({
|
||||
resource,
|
||||
folderTypeList,
|
||||
resourceType,
|
||||
resourceModel,
|
||||
session,
|
||||
|
||||
defaultPermission,
|
||||
collaborators
|
||||
}: {
|
||||
resource: SyncChildrenPermissionResourceType;
|
||||
|
||||
// when the resource is a folder
|
||||
folderTypeList: string[];
|
||||
|
||||
resourceModel: typeof Model;
|
||||
resourceType: PerResourceTypeEnum;
|
||||
|
||||
// should be provided when inheritPermission is true
|
||||
session: ClientSession;
|
||||
|
||||
defaultPermission?: PermissionValueType;
|
||||
collaborators?: UpdateCollaboratorItem[];
|
||||
}) {
|
||||
// only folder has permission
|
||||
const isFolder = folderTypeList.includes(resource.type);
|
||||
|
||||
if (!isFolder) return;
|
||||
|
||||
// get all folders and the resource permission of the app
|
||||
const allFolders = await resourceModel
|
||||
.find(
|
||||
{
|
||||
teamId: resource.teamId,
|
||||
type: { $in: folderTypeList },
|
||||
inheritPermission: true
|
||||
},
|
||||
'_id parentId'
|
||||
)
|
||||
.lean<SyncChildrenPermissionResourceType[]>()
|
||||
.session(session);
|
||||
|
||||
// bfs to get all children
|
||||
const queue = [String(resource._id)];
|
||||
const children: string[] = [];
|
||||
while (queue.length) {
|
||||
const parentId = queue.shift();
|
||||
const folderChildren = allFolders.filter(
|
||||
(folder) => String(folder.parentId) === String(parentId)
|
||||
);
|
||||
children.push(...folderChildren.map((folder) => folder._id));
|
||||
queue.push(...folderChildren.map((folder) => folder._id));
|
||||
}
|
||||
if (!children.length) return;
|
||||
|
||||
// Sync default permission
|
||||
if (defaultPermission !== undefined) {
|
||||
await resourceModel.updateMany(
|
||||
{
|
||||
_id: { $in: children }
|
||||
},
|
||||
{
|
||||
defaultPermission
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
}
|
||||
|
||||
// sync the resource permission
|
||||
if (collaborators) {
|
||||
// Update the collaborators of all children
|
||||
for await (const childId of children) {
|
||||
await syncCollaborators({
|
||||
resourceType,
|
||||
session,
|
||||
collaborators,
|
||||
teamId: resource.teamId,
|
||||
resourceId: childId
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Resume the inherit permission of the resource.
|
||||
1. Folder: Sync parent's defaultPermission and clbs, and sync its children.
|
||||
2. Resource: Sync parent's defaultPermission, and delete all its clbs.
|
||||
*/
|
||||
export async function resumeInheritPermission({
|
||||
resource,
|
||||
folderTypeList,
|
||||
resourceType,
|
||||
resourceModel,
|
||||
session
|
||||
}: {
|
||||
resource: SyncChildrenPermissionResourceType;
|
||||
folderTypeList: string[];
|
||||
resourceType: PerResourceTypeEnum;
|
||||
resourceModel: typeof Model;
|
||||
session?: ClientSession;
|
||||
}) {
|
||||
const isFolder = folderTypeList.includes(resource.type);
|
||||
|
||||
const fn = async (session: ClientSession) => {
|
||||
const parentResource = await resourceModel
|
||||
.findById(resource.parentId, 'defaultPermission')
|
||||
.lean<SyncChildrenPermissionResourceType & { defaultPermission: PermissionValueType }>()
|
||||
.session(session);
|
||||
|
||||
const parentDefaultPermissionVal = parentResource?.defaultPermission ?? NullPermission;
|
||||
|
||||
// update the resource permission
|
||||
await resourceModel.updateOne(
|
||||
{
|
||||
_id: resource._id
|
||||
},
|
||||
{
|
||||
inheritPermission: true,
|
||||
defaultPermission: parentDefaultPermissionVal
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
|
||||
// Folder resource, need to sync children
|
||||
if (isFolder) {
|
||||
const parentClbs = await getResourceAllClbs({
|
||||
resourceId: resource.parentId,
|
||||
teamId: resource.teamId,
|
||||
resourceType,
|
||||
session
|
||||
});
|
||||
|
||||
// sync self
|
||||
await syncCollaborators({
|
||||
resourceType,
|
||||
collaborators: parentClbs,
|
||||
teamId: resource.teamId,
|
||||
resourceId: resource._id,
|
||||
session
|
||||
});
|
||||
// sync children
|
||||
await syncChildrenPermission({
|
||||
resource: {
|
||||
...resource
|
||||
},
|
||||
resourceModel,
|
||||
folderTypeList,
|
||||
resourceType,
|
||||
session,
|
||||
defaultPermission: parentDefaultPermissionVal,
|
||||
collaborators: parentClbs
|
||||
});
|
||||
} else {
|
||||
// Not folder, delete all clb
|
||||
await MongoResourcePermission.deleteMany({ resourceId: resource._id }, { session });
|
||||
}
|
||||
};
|
||||
|
||||
if (session) {
|
||||
return fn(session);
|
||||
} else {
|
||||
return mongoSessionRun(fn);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Delete all the collaborators and then insert the new collaborators.
|
||||
*/
|
||||
export async function syncCollaborators({
|
||||
resourceType,
|
||||
teamId,
|
||||
resourceId,
|
||||
collaborators,
|
||||
session
|
||||
}: {
|
||||
resourceType: PerResourceTypeEnum;
|
||||
teamId: string;
|
||||
resourceId: string;
|
||||
collaborators: UpdateCollaboratorItem[];
|
||||
session: ClientSession;
|
||||
}) {
|
||||
await MongoResourcePermission.deleteMany(
|
||||
{
|
||||
resourceType,
|
||||
teamId,
|
||||
resourceId
|
||||
},
|
||||
{ session }
|
||||
);
|
||||
await MongoResourcePermission.insertMany(
|
||||
collaborators.map((item) => ({
|
||||
teamId: teamId,
|
||||
resourceId,
|
||||
resourceType: resourceType,
|
||||
tmbId: item.tmbId,
|
||||
permission: item.permission
|
||||
})),
|
||||
{
|
||||
session
|
||||
}
|
||||
);
|
||||
}
|
@@ -14,7 +14,7 @@ export const createTrainingUsage = async ({
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
appName: string;
|
||||
billSource: `${UsageSourceEnum}`;
|
||||
billSource: UsageSourceEnum;
|
||||
vectorModel: string;
|
||||
agentModel: string;
|
||||
session?: ClientSession;
|
||||
|
Reference in New Issue
Block a user