4.8.10 fix (#2572)
* fix: circle workflow response modal * perf: workflow runtime check
This commit is contained in:
parent
322ca757af
commit
813eaacfd0
1
packages/global/core/chat/type.d.ts
vendored
1
packages/global/core/chat/type.d.ts
vendored
@ -151,6 +151,7 @@ export type ChatHistoryItemType = HistoryItemType & {
|
|||||||
/* ------- response data ------------ */
|
/* ------- response data ------------ */
|
||||||
export type ChatHistoryItemResType = DispatchNodeResponseType & {
|
export type ChatHistoryItemResType = DispatchNodeResponseType & {
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
|
id: string;
|
||||||
moduleType: FlowNodeTypeEnum;
|
moduleType: FlowNodeTypeEnum;
|
||||||
moduleName: string;
|
moduleName: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -159,6 +159,9 @@ export type DispatchNodeResponseType = {
|
|||||||
|
|
||||||
// user select
|
// user select
|
||||||
userSelectResult?: string;
|
userSelectResult?: string;
|
||||||
|
|
||||||
|
// update var
|
||||||
|
updateVarResult?: any[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DispatchNodeResultType<T> = {
|
export type DispatchNodeResultType<T> = {
|
||||||
|
|||||||
@ -117,39 +117,6 @@ export const filterWorkflowEdges = (edges: RuntimeEdgeItemType[]) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
区分普通连线和递归连线
|
|
||||||
递归连线:可以通过往上查询 nodes,最终追溯到自身
|
|
||||||
*/
|
|
||||||
export const splitEdges2WorkflowEdges = ({
|
|
||||||
edges,
|
|
||||||
allEdges,
|
|
||||||
currentNode
|
|
||||||
}: {
|
|
||||||
edges: RuntimeEdgeItemType[];
|
|
||||||
allEdges: RuntimeEdgeItemType[];
|
|
||||||
currentNode: RuntimeNodeItemType;
|
|
||||||
}) => {
|
|
||||||
const commonEdges: RuntimeEdgeItemType[] = [];
|
|
||||||
const recursiveEdges: RuntimeEdgeItemType[] = [];
|
|
||||||
|
|
||||||
edges.forEach((edge) => {
|
|
||||||
const checkIsCurrentNode = (edge: RuntimeEdgeItemType): boolean => {
|
|
||||||
const sourceEdge = allEdges.find((item) => item.target === edge.source);
|
|
||||||
if (!sourceEdge) return false;
|
|
||||||
if (sourceEdge.source === currentNode.nodeId) return true;
|
|
||||||
return checkIsCurrentNode(sourceEdge);
|
|
||||||
};
|
|
||||||
if (checkIsCurrentNode(edge)) {
|
|
||||||
recursiveEdges.push(edge);
|
|
||||||
} else {
|
|
||||||
commonEdges.push(edge);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return { commonEdges, recursiveEdges };
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
1. 输入线分类:普通线和递归线(可以追溯到自身)
|
1. 输入线分类:普通线和递归线(可以追溯到自身)
|
||||||
2. 起始线全部非 waiting 执行,或递归线全部非 waiting 执行
|
2. 起始线全部非 waiting 执行,或递归线全部非 waiting 执行
|
||||||
@ -161,31 +128,72 @@ export const checkNodeRunStatus = ({
|
|||||||
node: RuntimeNodeItemType;
|
node: RuntimeNodeItemType;
|
||||||
runtimeEdges: RuntimeEdgeItemType[];
|
runtimeEdges: RuntimeEdgeItemType[];
|
||||||
}) => {
|
}) => {
|
||||||
const workflowEdges = filterWorkflowEdges(runtimeEdges).filter(
|
/*
|
||||||
|
区分普通连线和递归连线
|
||||||
|
递归连线:可以通过往上查询 nodes,最终追溯到自身
|
||||||
|
*/
|
||||||
|
const splitEdges2WorkflowEdges = ({
|
||||||
|
sourceEdges,
|
||||||
|
allEdges,
|
||||||
|
currentNode
|
||||||
|
}: {
|
||||||
|
sourceEdges: RuntimeEdgeItemType[];
|
||||||
|
allEdges: RuntimeEdgeItemType[];
|
||||||
|
currentNode: RuntimeNodeItemType;
|
||||||
|
}) => {
|
||||||
|
const commonEdges: RuntimeEdgeItemType[] = [];
|
||||||
|
const recursiveEdges: RuntimeEdgeItemType[] = [];
|
||||||
|
|
||||||
|
const checkIsCircular = (edge: RuntimeEdgeItemType, visited: Set<string>): boolean => {
|
||||||
|
if (edge.source === currentNode.nodeId) {
|
||||||
|
return true; // 检测到环,并且环中包含当前节点
|
||||||
|
}
|
||||||
|
if (visited.has(edge.source)) {
|
||||||
|
return false; // 检测到环,但不包含当前节点(子节点成环)
|
||||||
|
}
|
||||||
|
visited.add(edge.source);
|
||||||
|
|
||||||
|
const nextEdges = allEdges.filter((item) => item.target === edge.source);
|
||||||
|
return nextEdges.some((nextEdge) => checkIsCircular(nextEdge, new Set(visited)));
|
||||||
|
};
|
||||||
|
|
||||||
|
sourceEdges.forEach((edge) => {
|
||||||
|
if (checkIsCircular(edge, new Set([currentNode.nodeId]))) {
|
||||||
|
recursiveEdges.push(edge);
|
||||||
|
} else {
|
||||||
|
commonEdges.push(edge);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { commonEdges, recursiveEdges };
|
||||||
|
};
|
||||||
|
|
||||||
|
const runtimeNodeSourceEdge = filterWorkflowEdges(runtimeEdges).filter(
|
||||||
(item) => item.target === node.nodeId
|
(item) => item.target === node.nodeId
|
||||||
);
|
);
|
||||||
|
|
||||||
// Entry
|
// Entry
|
||||||
if (workflowEdges.length === 0) {
|
if (runtimeNodeSourceEdge.length === 0) {
|
||||||
return 'run';
|
return 'run';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Classify edges
|
||||||
const { commonEdges, recursiveEdges } = splitEdges2WorkflowEdges({
|
const { commonEdges, recursiveEdges } = splitEdges2WorkflowEdges({
|
||||||
edges: workflowEdges,
|
sourceEdges: runtimeNodeSourceEdge,
|
||||||
allEdges: runtimeEdges,
|
allEdges: runtimeEdges,
|
||||||
currentNode: node
|
currentNode: node
|
||||||
});
|
});
|
||||||
|
|
||||||
// check skip
|
// check skip(其中一组边,全 skip)
|
||||||
if (commonEdges.every((item) => item.status === 'skipped')) {
|
if (commonEdges.length > 0 && commonEdges.every((item) => item.status === 'skipped')) {
|
||||||
return 'skip';
|
return 'skip';
|
||||||
}
|
}
|
||||||
if (recursiveEdges.length > 0 && recursiveEdges.every((item) => item.status === 'skipped')) {
|
if (recursiveEdges.length > 0 && recursiveEdges.every((item) => item.status === 'skipped')) {
|
||||||
return 'skip';
|
return 'skip';
|
||||||
}
|
}
|
||||||
|
|
||||||
// check active
|
// check active(有一类边,不全是 wait 即可运行)
|
||||||
if (commonEdges.every((item) => item.status !== 'waiting')) {
|
if (commonEdges.length > 0 && commonEdges.every((item) => item.status !== 'waiting')) {
|
||||||
return 'run';
|
return 'run';
|
||||||
}
|
}
|
||||||
if (recursiveEdges.length > 0 && recursiveEdges.every((item) => item.status !== 'waiting')) {
|
if (recursiveEdges.length > 0 && recursiveEdges.every((item) => item.status !== 'waiting')) {
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import {
|
|||||||
FlowNodeInputTypeEnum,
|
FlowNodeInputTypeEnum,
|
||||||
FlowNodeTypeEnum
|
FlowNodeTypeEnum
|
||||||
} from '@fastgpt/global/core/workflow/node/constant';
|
} from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
import { getNanoid, replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||||
import { getSystemTime } from '@fastgpt/global/common/time/timezone';
|
import { getSystemTime } from '@fastgpt/global/common/time/timezone';
|
||||||
import { replaceEditorVariable } from '@fastgpt/global/core/workflow/utils';
|
import { replaceEditorVariable } from '@fastgpt/global/core/workflow/utils';
|
||||||
|
|
||||||
@ -434,6 +434,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
const formatResponseData: ChatHistoryItemResType = (() => {
|
const formatResponseData: ChatHistoryItemResType = (() => {
|
||||||
if (!dispatchRes[DispatchNodeResponseKeyEnum.nodeResponse]) return undefined;
|
if (!dispatchRes[DispatchNodeResponseKeyEnum.nodeResponse]) return undefined;
|
||||||
return {
|
return {
|
||||||
|
id: getNanoid(),
|
||||||
nodeId: node.nodeId,
|
nodeId: node.nodeId,
|
||||||
moduleName: node.name,
|
moduleName: node.name,
|
||||||
moduleType: node.flowNodeType,
|
moduleType: node.flowNodeType,
|
||||||
|
|||||||
@ -19,12 +19,12 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
|
|||||||
const { params, variables, runtimeNodes, workflowStreamResponse, node } = props;
|
const { params, variables, runtimeNodes, workflowStreamResponse, node } = props;
|
||||||
|
|
||||||
const { updateList } = params;
|
const { updateList } = params;
|
||||||
updateList.forEach((item) => {
|
const result = updateList.map((item) => {
|
||||||
const varNodeId = item.variable?.[0];
|
const varNodeId = item.variable?.[0];
|
||||||
const varKey = item.variable?.[1];
|
const varKey = item.variable?.[1];
|
||||||
|
|
||||||
if (!varNodeId || !varKey) {
|
if (!varNodeId || !varKey) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = (() => {
|
const value = (() => {
|
||||||
@ -48,10 +48,11 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// Global variable
|
||||||
if (varNodeId === VARIABLE_NODE_ID) {
|
if (varNodeId === VARIABLE_NODE_ID) {
|
||||||
// update global variable
|
|
||||||
variables[varKey] = value;
|
variables[varKey] = value;
|
||||||
} else {
|
} else {
|
||||||
|
// Other nodes
|
||||||
runtimeNodes
|
runtimeNodes
|
||||||
.find((node) => node.nodeId === varNodeId)
|
.find((node) => node.nodeId === varNodeId)
|
||||||
?.outputs?.find((output) => {
|
?.outputs?.find((output) => {
|
||||||
@ -61,6 +62,8 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
});
|
});
|
||||||
|
|
||||||
workflowStreamResponse?.({
|
workflowStreamResponse?.({
|
||||||
@ -70,7 +73,7 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
totalPoints: 0
|
updateVarResult: result
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -565,6 +565,7 @@
|
|||||||
"plugin output": "Plugin output value",
|
"plugin output": "Plugin output value",
|
||||||
"search using reRank": "Result rearrangement",
|
"search using reRank": "Result rearrangement",
|
||||||
"text output": "text output",
|
"text output": "text output",
|
||||||
|
"update_var_result": "Variable update results (display multiple variable update results in order)",
|
||||||
"user_select_result": "User select result"
|
"user_select_result": "User select result"
|
||||||
},
|
},
|
||||||
"retry": "Regenerate",
|
"retry": "Regenerate",
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
"auto_renew_q": "订阅套餐会自动续费么?",
|
"auto_renew_q": "订阅套餐会自动续费么?",
|
||||||
"change_package_a": "当前套餐价格大于新套餐时,无法立即切换,将会在当前套餐过期后以“续费”形式进行切换。\n当前套餐价格小于新套餐时,系统会自动计算当前套餐剩余余额,您可支付差价进行套餐切换。",
|
"change_package_a": "当前套餐价格大于新套餐时,无法立即切换,将会在当前套餐过期后以“续费”形式进行切换。\n当前套餐价格小于新套餐时,系统会自动计算当前套餐剩余余额,您可支付差价进行套餐切换。",
|
||||||
"change_package_q": "能否切换订阅套餐?",
|
"change_package_q": "能否切换订阅套餐?",
|
||||||
|
"check_subscription_a": "账号-个人信息-套餐详情-使用情况。您可以查看所拥有套餐的生效和到期时间。当付费套餐到期后将自动切换免费版。",
|
||||||
|
"check_subscription_q": "在哪里查看已订阅的套餐?",
|
||||||
"dataset_compute_a": "1条知识库存储等于1条知识库索引。一条知识库数据可以包含1条或多条知识库索引。增强训练中,1条数据会生成5条索引。",
|
"dataset_compute_a": "1条知识库存储等于1条知识库索引。一条知识库数据可以包含1条或多条知识库索引。增强训练中,1条数据会生成5条索引。",
|
||||||
"dataset_compute_q": "知识库存储怎么计算?",
|
"dataset_compute_q": "知识库存储怎么计算?",
|
||||||
"dataset_index_a": "不会。但知识库索引超出时,无法插入和更新知识库内容。",
|
"dataset_index_a": "不会。但知识库索引超出时,无法插入和更新知识库内容。",
|
||||||
@ -18,19 +20,15 @@
|
|||||||
"free_user_clean_q": "免费版数据会清除么?",
|
"free_user_clean_q": "免费版数据会清除么?",
|
||||||
"package_overlay_a": "可以的。每次购买的资源包都是独立的,在其有效期内将会叠加使用。AI积分会优先扣除最先过期的资源包。",
|
"package_overlay_a": "可以的。每次购买的资源包都是独立的,在其有效期内将会叠加使用。AI积分会优先扣除最先过期的资源包。",
|
||||||
"package_overlay_q": "额外资源包可以叠加么?",
|
"package_overlay_q": "额外资源包可以叠加么?",
|
||||||
"switch_package_q": "是否切换订阅套餐?",
|
|
||||||
"switch_package_a": "套餐使用规则为优先使用更高级的套餐,因此,购买的新套餐若比当前套餐更高级,则新套餐立即生效:否则将继续使用当前套餐。",
|
"switch_package_a": "套餐使用规则为优先使用更高级的套餐,因此,购买的新套餐若比当前套餐更高级,则新套餐立即生效:否则将继续使用当前套餐。",
|
||||||
"check_subscription_q": "在哪里查看已订阅的套餐?",
|
"switch_package_q": "是否切换订阅套餐?"
|
||||||
"check_subscription_a": "账号-个人信息-套餐详情-使用情况。您可以查看所拥有套餐的生效和到期时间。当付费套餐到期后将自动切换免费版。"
|
|
||||||
},
|
},
|
||||||
"Folder": "文件夹",
|
"Folder": "文件夹",
|
||||||
"Login": "登录",
|
"Login": "登录",
|
||||||
"is_using": "正在使用",
|
|
||||||
"Move": "移动",
|
"Move": "移动",
|
||||||
"Name": "名称",
|
"Name": "名称",
|
||||||
"Rename": "重命名",
|
"Rename": "重命名",
|
||||||
"Resume": "恢复",
|
"Resume": "恢复",
|
||||||
"free": "免费",
|
|
||||||
"Running": "运行中",
|
"Running": "运行中",
|
||||||
"UnKnow": "未知",
|
"UnKnow": "未知",
|
||||||
"Warning": "提示",
|
"Warning": "提示",
|
||||||
@ -119,7 +117,6 @@
|
|||||||
"Cancel": "取消",
|
"Cancel": "取消",
|
||||||
"Choose": "选择",
|
"Choose": "选择",
|
||||||
"Close": "关闭",
|
"Close": "关闭",
|
||||||
"base_config": "基础配置",
|
|
||||||
"Config": "配置",
|
"Config": "配置",
|
||||||
"Confirm": "确认",
|
"Confirm": "确认",
|
||||||
"Confirm Create": "确认创建",
|
"Confirm Create": "确认创建",
|
||||||
@ -224,6 +221,7 @@
|
|||||||
"Select Avatar": "点击选择头像",
|
"Select Avatar": "点击选择头像",
|
||||||
"Select Failed": "选择头像异常"
|
"Select Failed": "选择头像异常"
|
||||||
},
|
},
|
||||||
|
"base_config": "基础配置",
|
||||||
"choosable": "可选",
|
"choosable": "可选",
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"Common Tip": "操作确认"
|
"Common Tip": "操作确认"
|
||||||
@ -567,6 +565,7 @@
|
|||||||
"plugin output": "插件输出值",
|
"plugin output": "插件输出值",
|
||||||
"search using reRank": "结果重排",
|
"search using reRank": "结果重排",
|
||||||
"text output": "文本输出",
|
"text output": "文本输出",
|
||||||
|
"update_var_result": "变量更新结果(按顺序展示多个变量更新结果)",
|
||||||
"user_select_result": "用户选择结果"
|
"user_select_result": "用户选择结果"
|
||||||
},
|
},
|
||||||
"retry": "重新生成",
|
"retry": "重新生成",
|
||||||
@ -639,7 +638,8 @@
|
|||||||
"success": "开始同步"
|
"success": "开始同步"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"training": {}
|
"training": {
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"Auxiliary Data": "辅助数据",
|
"Auxiliary Data": "辅助数据",
|
||||||
@ -775,7 +775,6 @@
|
|||||||
"test result tip": "根据知识库内容与测试文本的相似度进行排序,你可以根据测试结果调整对应的文本。\n注意:测试记录中的数据可能已经被修改过,点击某条测试数据后将展示最新的数据。"
|
"test result tip": "根据知识库内容与测试文本的相似度进行排序,你可以根据测试结果调整对应的文本。\n注意:测试记录中的数据可能已经被修改过,点击某条测试数据后将展示最新的数据。"
|
||||||
},
|
},
|
||||||
"training": {
|
"training": {
|
||||||
"tag": "排队情况",
|
|
||||||
"Agent queue": "QA 训练排队",
|
"Agent queue": "QA 训练排队",
|
||||||
"Auto mode": "增强处理(实验)",
|
"Auto mode": "增强处理(实验)",
|
||||||
"Auto mode Tip": "通过子索引以及调用模型生成相关问题与摘要,来增加数据块的语义丰富度,更利于检索。需要消耗更多的存储空间和增加 AI 调用次数。",
|
"Auto mode Tip": "通过子索引以及调用模型生成相关问题与摘要,来增加数据块的语义丰富度,更利于检索。需要消耗更多的存储空间和增加 AI 调用次数。",
|
||||||
@ -785,7 +784,8 @@
|
|||||||
"QA mode": "问答拆分",
|
"QA mode": "问答拆分",
|
||||||
"Vector queue": "索引排队",
|
"Vector queue": "索引排队",
|
||||||
"Waiting": "预计 5 分钟",
|
"Waiting": "预计 5 分钟",
|
||||||
"Website Sync": "Web 站点同步"
|
"Website Sync": "Web 站点同步",
|
||||||
|
"tag": "排队情况"
|
||||||
},
|
},
|
||||||
"website": {
|
"website": {
|
||||||
"Base Url": "根地址",
|
"Base Url": "根地址",
|
||||||
@ -1078,6 +1078,7 @@
|
|||||||
},
|
},
|
||||||
"extraction_results": "提取结果",
|
"extraction_results": "提取结果",
|
||||||
"field_name": "字段名",
|
"field_name": "字段名",
|
||||||
|
"free": "免费",
|
||||||
"get_QR_failed": "获取二维码失败",
|
"get_QR_failed": "获取二维码失败",
|
||||||
"get_app_failed": "获取应用失败",
|
"get_app_failed": "获取应用失败",
|
||||||
"get_laf_failed": "获取Laf函数列表失败",
|
"get_laf_failed": "获取Laf函数列表失败",
|
||||||
@ -1097,6 +1098,7 @@
|
|||||||
},
|
},
|
||||||
"invalid_variable": "无效变量",
|
"invalid_variable": "无效变量",
|
||||||
"is_open": "是否开启",
|
"is_open": "是否开启",
|
||||||
|
"is_using": "正在使用",
|
||||||
"item_description": "字段描述",
|
"item_description": "字段描述",
|
||||||
"item_name": "字段名",
|
"item_name": "字段名",
|
||||||
"key_repetition": "key 重复",
|
"key_repetition": "key 重复",
|
||||||
@ -1125,14 +1127,14 @@
|
|||||||
"notice": "请勿关闭页面",
|
"notice": "请勿关闭页面",
|
||||||
"old_package_price": "旧套餐余额",
|
"old_package_price": "旧套餐余额",
|
||||||
"other": "其他金额,请取整数",
|
"other": "其他金额,请取整数",
|
||||||
"to_recharge": "余额不足,去充值",
|
|
||||||
"wechat": "请微信扫码支付: {{price}}元\n请勿关闭页面",
|
|
||||||
"yuan": "{{amount}}元",
|
|
||||||
"package_tip": {
|
"package_tip": {
|
||||||
"buy": "您购买的套餐等级低于当前套餐,该套餐将在当前套餐过期后生效。您可在账号—个人信息—套餐详情里,查看套餐使用情况。",
|
"buy": "您购买的套餐等级低于当前套餐,该套餐将在当前套餐过期后生效。您可在账号—个人信息—套餐详情里,查看套餐使用情况。",
|
||||||
"renewal": "您正在续费套餐。您可在账号—个人信息—套餐详情里,查看套餐使用情况。",
|
"renewal": "您正在续费套餐。您可在账号—个人信息—套餐详情里,查看套餐使用情况。",
|
||||||
"upgrade": "您购买的套餐等级高于当前套餐,该套餐将即刻生效,当前套餐将延后生效。您可在账号—个人信息—套餐详情里,查看套餐使用情况。"
|
"upgrade": "您购买的套餐等级高于当前套餐,该套餐将即刻生效,当前套餐将延后生效。您可在账号—个人信息—套餐详情里,查看套餐使用情况。"
|
||||||
}
|
},
|
||||||
|
"to_recharge": "余额不足,去充值",
|
||||||
|
"wechat": "请微信扫码支付: {{price}}元\n请勿关闭页面",
|
||||||
|
"yuan": "{{amount}}元"
|
||||||
},
|
},
|
||||||
"permission": {
|
"permission": {
|
||||||
"Collaborator": "协作者",
|
"Collaborator": "协作者",
|
||||||
@ -1217,8 +1219,8 @@
|
|||||||
"standard": {
|
"standard": {
|
||||||
"AI Bonus Points": "AI 积分",
|
"AI Bonus Points": "AI 积分",
|
||||||
"Expired Time": "结束时间",
|
"Expired Time": "结束时间",
|
||||||
"due_date": "到期时间",
|
|
||||||
"Start Time": "开始时间",
|
"Start Time": "开始时间",
|
||||||
|
"due_date": "到期时间",
|
||||||
"storage": "存储量",
|
"storage": "存储量",
|
||||||
"type": "类型"
|
"type": "类型"
|
||||||
},
|
},
|
||||||
@ -1334,11 +1336,6 @@
|
|||||||
"noBill": "无账单记录~",
|
"noBill": "无账单记录~",
|
||||||
"no_invoice": "暂无开票记录",
|
"no_invoice": "暂无开票记录",
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"status": {
|
|
||||||
"expired": "已过期",
|
|
||||||
"active": "生效中",
|
|
||||||
"inactive": "待使用"
|
|
||||||
},
|
|
||||||
"AI points": "AI 积分",
|
"AI points": "AI 积分",
|
||||||
"AI points click to read tip": "每次调用 AI 模型时,都会消耗一定的 AI 积分(类似于 token)。点击可查看详细计算规则。",
|
"AI points click to read tip": "每次调用 AI 模型时,都会消耗一定的 AI 积分(类似于 token)。点击可查看详细计算规则。",
|
||||||
"AI points usage": "AI 积分使用量",
|
"AI points usage": "AI 积分使用量",
|
||||||
@ -1384,13 +1381,18 @@
|
|||||||
"standardSubLevel": {
|
"standardSubLevel": {
|
||||||
"custom": "自定义版",
|
"custom": "自定义版",
|
||||||
"enterprise": "企业版",
|
"enterprise": "企业版",
|
||||||
|
"enterprise_desc": "适合中小企业在生产环境构建知识库应用",
|
||||||
"experience": "体验版",
|
"experience": "体验版",
|
||||||
|
"experience_desc": "可解锁 FastGPT 完整功能",
|
||||||
"free": "免费版",
|
"free": "免费版",
|
||||||
"free desc": "每月均可免费使用基础功能,连续 30 天未登录系统,将会自动清除知识库",
|
"free desc": "每月均可免费使用基础功能,连续 30 天未登录系统,将会自动清除知识库",
|
||||||
"team": "团队版",
|
"team": "团队版",
|
||||||
"experience_desc": "可解锁 FastGPT 完整功能",
|
"team_desc": "适合小团队构建知识库应用并提供对外服务"
|
||||||
"team_desc": "适合小团队构建知识库应用并提供对外服务",
|
},
|
||||||
"enterprise_desc": "适合中小企业在生产环境构建知识库应用"
|
"status": {
|
||||||
|
"active": "生效中",
|
||||||
|
"expired": "已过期",
|
||||||
|
"inactive": "待使用"
|
||||||
},
|
},
|
||||||
"token_compute": "点击查看在线 Tokens 计算器",
|
"token_compute": "点击查看在线 Tokens 计算器",
|
||||||
"type": {
|
"type": {
|
||||||
|
|||||||
@ -24,7 +24,8 @@ type sideTabItemType = {
|
|||||||
moduleName: string;
|
moduleName: string;
|
||||||
runningTime?: number;
|
runningTime?: number;
|
||||||
moduleType: string;
|
moduleType: string;
|
||||||
nodeId: string;
|
// nodeId:string; // abandon
|
||||||
|
id: string;
|
||||||
children: sideTabItemType[];
|
children: sideTabItemType[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -149,18 +150,28 @@ export const ResponseBox = React.memo(function ResponseBox({
|
|||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isPc } = useSystem();
|
const { isPc } = useSystem();
|
||||||
const flattedResponse = useMemo(() => flattenArray(response), [response]);
|
|
||||||
|
const flattedResponse = useMemo(
|
||||||
|
() =>
|
||||||
|
flattenArray(response).map((item) => ({
|
||||||
|
...item,
|
||||||
|
id: item.id ?? item.nodeId
|
||||||
|
})),
|
||||||
|
[response]
|
||||||
|
);
|
||||||
const [currentNodeId, setCurrentNodeId] = useState(
|
const [currentNodeId, setCurrentNodeId] = useState(
|
||||||
flattedResponse[0]?.nodeId ? flattedResponse[0].nodeId : ''
|
flattedResponse[0]?.id ?? flattedResponse[0]?.nodeId ?? ''
|
||||||
);
|
);
|
||||||
|
|
||||||
const activeModule = useMemo(
|
const activeModule = useMemo(
|
||||||
() => flattedResponse.find((item) => item.nodeId === currentNodeId) as ChatHistoryItemResType,
|
() => flattedResponse.find((item) => item.id === currentNodeId) as ChatHistoryItemResType,
|
||||||
[currentNodeId, flattedResponse]
|
[currentNodeId, flattedResponse]
|
||||||
);
|
);
|
||||||
const sideResponse: sideTabItemType[] = useMemo(() => {
|
|
||||||
|
const sliderResponseList: sideTabItemType[] = useMemo(() => {
|
||||||
return pretreatmentResponse(response);
|
return pretreatmentResponse(response);
|
||||||
}, [response]);
|
}, [response]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isOpen: isOpenMobileModal,
|
isOpen: isOpenMobileModal,
|
||||||
onOpen: onOpenMobileModal,
|
onOpen: onOpenMobileModal,
|
||||||
@ -174,7 +185,7 @@ export const ResponseBox = React.memo(function ResponseBox({
|
|||||||
<Box flex={'2 0 0'} borderRight={'sm'} p={3}>
|
<Box flex={'2 0 0'} borderRight={'sm'} p={3}>
|
||||||
<Box overflow={'auto'} height={'100%'}>
|
<Box overflow={'auto'} height={'100%'}>
|
||||||
<WholeResponseSideTab
|
<WholeResponseSideTab
|
||||||
response={sideResponse}
|
response={sliderResponseList}
|
||||||
value={currentNodeId}
|
value={currentNodeId}
|
||||||
onChange={setCurrentNodeId}
|
onChange={setCurrentNodeId}
|
||||||
/>
|
/>
|
||||||
@ -192,7 +203,7 @@ export const ResponseBox = React.memo(function ResponseBox({
|
|||||||
<Box h={'100%'} overflow={'auto'}>
|
<Box h={'100%'} overflow={'auto'}>
|
||||||
{!isOpenMobileModal && (
|
{!isOpenMobileModal && (
|
||||||
<WholeResponseSideTab
|
<WholeResponseSideTab
|
||||||
response={sideResponse}
|
response={sliderResponseList}
|
||||||
value={currentNodeId}
|
value={currentNodeId}
|
||||||
onChange={(item: string) => {
|
onChange={(item: string) => {
|
||||||
setCurrentNodeId(item);
|
setCurrentNodeId(item);
|
||||||
@ -442,11 +453,11 @@ export const WholeResponseContent = ({
|
|||||||
/>
|
/>
|
||||||
{/* code */}
|
{/* code */}
|
||||||
<>
|
<>
|
||||||
|
<Row label={t('workflow:response.Custom inputs')} value={activeModule?.customInputs} />
|
||||||
<Row
|
<Row
|
||||||
label={t('workflow:response.Custom outputs')}
|
label={t('workflow:response.Custom outputs')}
|
||||||
value={activeModule?.customOutputs}
|
value={activeModule?.customOutputs}
|
||||||
/>
|
/>
|
||||||
<Row label={t('workflow:response.Custom inputs')} value={activeModule?.customInputs} />
|
|
||||||
<Row label={t('workflow:response.Code log')} value={activeModule?.codeLog} />
|
<Row label={t('workflow:response.Code log')} value={activeModule?.codeLog} />
|
||||||
</>
|
</>
|
||||||
|
|
||||||
@ -491,6 +502,12 @@ export const WholeResponseContent = ({
|
|||||||
label={t('common:core.chat.response.user_select_result')}
|
label={t('common:core.chat.response.user_select_result')}
|
||||||
value={activeModule?.userSelectResult}
|
value={activeModule?.userSelectResult}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* update var */}
|
||||||
|
<Row
|
||||||
|
label={t('common:core.chat.response.update_var_result')}
|
||||||
|
value={activeModule?.updateVarResult}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
@ -512,7 +529,7 @@ const WholeResponseSideTab = ({
|
|||||||
<>
|
<>
|
||||||
{response.map((item) => (
|
{response.map((item) => (
|
||||||
<Box
|
<Box
|
||||||
key={item.nodeId}
|
key={item.id}
|
||||||
bg={isMobile ? 'myGray.100' : ''}
|
bg={isMobile ? 'myGray.100' : ''}
|
||||||
m={isMobile ? 3 : 0}
|
m={isMobile ? 3 : 0}
|
||||||
borderRadius={'md'}
|
borderRadius={'md'}
|
||||||
@ -532,7 +549,7 @@ const AccordionSideTabItem = ({
|
|||||||
index
|
index
|
||||||
}: {
|
}: {
|
||||||
sideBarItem: sideTabItemType;
|
sideBarItem: sideTabItemType;
|
||||||
onChange: (nodeId: string) => void;
|
onChange: (id: string) => void;
|
||||||
value: string;
|
value: string;
|
||||||
index: number;
|
index: number;
|
||||||
}) => {
|
}) => {
|
||||||
@ -565,7 +582,7 @@ const AccordionSideTabItem = ({
|
|||||||
{sideBarItem.children.map((item) => (
|
{sideBarItem.children.map((item) => (
|
||||||
<SideTabItem
|
<SideTabItem
|
||||||
value={value}
|
value={value}
|
||||||
key={item.nodeId}
|
key={item.id}
|
||||||
sideBarItem={item}
|
sideBarItem={item}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
index={index + 1}
|
index={index + 1}
|
||||||
@ -585,7 +602,7 @@ const NormalSideTabItem = ({
|
|||||||
children
|
children
|
||||||
}: {
|
}: {
|
||||||
sideBarItem: sideTabItemType;
|
sideBarItem: sideTabItemType;
|
||||||
onChange: (nodeId: string) => void;
|
onChange: (id: string) => void;
|
||||||
value: string;
|
value: string;
|
||||||
index: number;
|
index: number;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
@ -596,9 +613,9 @@ const NormalSideTabItem = ({
|
|||||||
<Flex
|
<Flex
|
||||||
alignItems={'center'}
|
alignItems={'center'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onChange(sideBarItem.nodeId);
|
onChange(sideBarItem.id);
|
||||||
}}
|
}}
|
||||||
background={value === sideBarItem.nodeId ? 'myGray.100' : ''}
|
background={value === sideBarItem.id ? 'myGray.100' : ''}
|
||||||
_hover={{ background: 'myGray.100' }}
|
_hover={{ background: 'myGray.100' }}
|
||||||
p={2}
|
p={2}
|
||||||
width={'100%'}
|
width={'100%'}
|
||||||
@ -647,7 +664,7 @@ const SideTabItem = ({
|
|||||||
index
|
index
|
||||||
}: {
|
}: {
|
||||||
sideBarItem: sideTabItemType;
|
sideBarItem: sideTabItemType;
|
||||||
onChange: (nodeId: string) => void;
|
onChange: (id: string) => void;
|
||||||
value: string;
|
value: string;
|
||||||
index: number;
|
index: number;
|
||||||
}) => {
|
}) => {
|
||||||
@ -668,6 +685,7 @@ const SideTabItem = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Format response data to slider data */
|
||||||
function pretreatmentResponse(res: ChatHistoryItemResType[]): sideTabItemType[] {
|
function pretreatmentResponse(res: ChatHistoryItemResType[]): sideTabItemType[] {
|
||||||
return res.map((item) => {
|
return res.map((item) => {
|
||||||
let children: sideTabItemType[] = [];
|
let children: sideTabItemType[] = [];
|
||||||
@ -681,12 +699,13 @@ function pretreatmentResponse(res: ChatHistoryItemResType[]): sideTabItemType[]
|
|||||||
moduleName: item.moduleName,
|
moduleName: item.moduleName,
|
||||||
runningTime: item.runningTime,
|
runningTime: item.runningTime,
|
||||||
moduleType: item.moduleType,
|
moduleType: item.moduleType,
|
||||||
nodeId: item.nodeId,
|
id: item.id ?? item.nodeId,
|
||||||
children
|
children
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Flat response */
|
||||||
function flattenArray(arr: ChatHistoryItemResType[]) {
|
function flattenArray(arr: ChatHistoryItemResType[]) {
|
||||||
const result: ChatHistoryItemResType[] = [];
|
const result: ChatHistoryItemResType[] = [];
|
||||||
|
|
||||||
|
|||||||
@ -56,9 +56,9 @@ const FlowController = React.memo(function FlowController() {
|
|||||||
<>
|
<>
|
||||||
<MiniMap
|
<MiniMap
|
||||||
style={{
|
style={{
|
||||||
height: 98,
|
height: 92,
|
||||||
width: 184,
|
width: 150,
|
||||||
marginBottom: 72,
|
marginBottom: 62,
|
||||||
borderRadius: '10px',
|
borderRadius: '10px',
|
||||||
boxShadow: '0px 0px 1px rgba(19, 51, 107, 0.10), 0px 4px 10px rgba(19, 51, 107, 0.10)'
|
boxShadow: '0px 0px 1px rgba(19, 51, 107, 0.10), 0px 4px 10px rgba(19, 51, 107, 0.10)'
|
||||||
}}
|
}}
|
||||||
@ -68,7 +68,7 @@ const FlowController = React.memo(function FlowController() {
|
|||||||
position={'bottom-right'}
|
position={'bottom-right'}
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
marginBottom: 24,
|
marginBottom: 16,
|
||||||
padding: '5px 8px',
|
padding: '5px 8px',
|
||||||
background: 'white',
|
background: 'white',
|
||||||
borderRadius: '6px',
|
borderRadius: '6px',
|
||||||
|
|||||||
@ -375,15 +375,21 @@ const ConditionSelect = ({
|
|||||||
return [];
|
return [];
|
||||||
}, [valueType]);
|
}, [valueType]);
|
||||||
const filterQuiredConditionList = useMemo(() => {
|
const filterQuiredConditionList = useMemo(() => {
|
||||||
if (required) {
|
const list = (() => {
|
||||||
return conditionList.filter(
|
if (required) {
|
||||||
(item) =>
|
return conditionList.filter(
|
||||||
item.value !== VariableConditionEnum.isEmpty &&
|
(item) =>
|
||||||
item.value !== VariableConditionEnum.isNotEmpty
|
item.value !== VariableConditionEnum.isEmpty &&
|
||||||
);
|
item.value !== VariableConditionEnum.isNotEmpty
|
||||||
}
|
);
|
||||||
return conditionList;
|
}
|
||||||
}, [conditionList, required]);
|
return conditionList;
|
||||||
|
})();
|
||||||
|
return list.map((item) => ({
|
||||||
|
...item,
|
||||||
|
label: t(item.label)
|
||||||
|
}));
|
||||||
|
}, [conditionList, required, t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MySelect
|
<MySelect
|
||||||
|
|||||||
@ -87,7 +87,9 @@ export const getEditorVariables = ({
|
|||||||
appDetail: AppDetailType;
|
appDetail: AppDetailType;
|
||||||
t: TFunction;
|
t: TFunction;
|
||||||
}) => {
|
}) => {
|
||||||
const currentNode = nodeList.find((node) => node.nodeId === nodeId)!;
|
const currentNode = nodeList.find((node) => node.nodeId === nodeId);
|
||||||
|
if (!currentNode) return [];
|
||||||
|
|
||||||
const nodeVariables = currentNode.inputs
|
const nodeVariables = currentNode.inputs
|
||||||
.filter((input) => input.canEdit)
|
.filter((input) => input.canEdit)
|
||||||
.map((item) => ({
|
.map((item) => ({
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user