4.8.11 perf (#2768)

* perf: watch local

* perf: dataset list ui

* perf: Check workflow invalid edges in saved

* remove log

* perf: Forbid touch scale

* perf: rename dataset process

* feat: support child app unstream mode

* feat: Dispatch child app will record detail

* feat: Save childApp run log

* fix: share page init error

* perf: chatId reset
This commit is contained in:
Archer
2024-09-23 10:17:49 +08:00
committed by GitHub
parent 4245ea4998
commit 3ab934771f
38 changed files with 252 additions and 143 deletions

View File

@@ -4,7 +4,11 @@ import { countGptMessagesTokens } from '../../../common/string/tiktoken/index';
import { loadRequestMessages } from '../../chat/utils';
import { llmCompletionsBodyFormat } from '../utils';
export const Prompt_QuestionGuide = `你是一个AI智能助手可以回答和解决我的问题。请结合前面的对话记录,帮我生成 3 个问题引导我继续提问生成问题的语言要与原问题相同。问题的长度应小于20个字符按 JSON 格式返回: ["问题1", "问题2", "问题3"]`;
export const Prompt_QuestionGuide = `你是一个AI智能助手你的任务是结合对话记录,推测我下一步的问题。
你需要生成 3 个可能的问题,引导我继续提问,生成的问题要求:
1. 生成问题的语言,与最后一个用户提问语言一致。
2. 问题的长度应小于20个字符。
3. 按 JSON 格式返回: ["question1", "question2", "question3"]。`;
export async function createQuestionGuide({
messages,

View File

@@ -34,7 +34,7 @@ export async function splitCombinePluginId(id: string) {
return { source, pluginId: id };
}
const getPluginTemplateById = async (
const getChildAppTemplateById = async (
id: string
): Promise<SystemPluginTemplateItemType & { teamId?: string }> => {
const { source, pluginId } = await splitCombinePluginId(id);
@@ -69,44 +69,48 @@ const getPluginTemplateById = async (
};
/* format plugin modules to plugin preview module */
export async function getPluginPreviewNode({ id }: { id: string }): Promise<FlowNodeTemplateType> {
const plugin = await getPluginTemplateById(id);
const isPlugin = !!plugin.workflow.nodes.find(
export async function getChildAppPreviewNode({
id
}: {
id: string;
}): Promise<FlowNodeTemplateType> {
const app = await getChildAppTemplateById(id);
const isPlugin = !!app.workflow.nodes.find(
(node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput
);
return {
id: getNanoid(),
pluginId: plugin.id,
templateType: plugin.templateType,
pluginId: app.id,
templateType: app.templateType,
flowNodeType: isPlugin ? FlowNodeTypeEnum.pluginModule : FlowNodeTypeEnum.appModule,
avatar: plugin.avatar,
name: plugin.name,
intro: plugin.intro,
inputExplanationUrl: plugin.inputExplanationUrl,
showStatus: plugin.showStatus,
avatar: app.avatar,
name: app.name,
intro: app.intro,
inputExplanationUrl: app.inputExplanationUrl,
showStatus: app.showStatus,
isTool: isPlugin,
version: plugin.version,
version: app.version,
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
...(isPlugin
? pluginData2FlowNodeIO({ nodes: plugin.workflow.nodes })
: appData2FlowNodeIO({ chatConfig: plugin.workflow.chatConfig }))
? pluginData2FlowNodeIO({ nodes: app.workflow.nodes })
: appData2FlowNodeIO({ chatConfig: app.workflow.chatConfig }))
};
}
/* run plugin time */
export async function getPluginRuntimeById(id: string): Promise<PluginRuntimeType> {
const plugin = await getPluginTemplateById(id);
export async function getChildAppRuntimeById(id: string): Promise<PluginRuntimeType> {
const app = await getChildAppTemplateById(id);
return {
id: plugin.id,
teamId: plugin.teamId,
name: plugin.name,
avatar: plugin.avatar,
showStatus: plugin.showStatus,
currentCost: plugin.currentCost,
nodes: plugin.workflow.nodes,
edges: plugin.workflow.edges
id: app.id,
teamId: app.teamId,
name: app.name,
avatar: app.avatar,
showStatus: app.showStatus,
currentCost: app.currentCost,
nodes: app.workflow.nodes,
edges: app.workflow.edges
};
}

View File

@@ -13,6 +13,7 @@ export const computedPluginUsage = async (
) => {
const { source } = await splitCombinePluginId(plugin.id);
// Commercial plugin: n points per times
if (source === PluginSourceEnum.commercial) {
return plugin.currentCost ?? 0;
}

View File

@@ -2,7 +2,7 @@ import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/
import { dispatchWorkFlow } from '../index';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import { getPluginRuntimeById } from '../../../app/plugin/controller';
import { getChildAppRuntimeById } from '../../../app/plugin/controller';
import {
getWorkflowEntryNodeIds,
initWorkflowEdgeStatus,
@@ -16,8 +16,10 @@ import { filterSystemVariables } from '../utils';
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
import { getPluginRunUserQuery } from '@fastgpt/global/core/workflow/utils';
import { getPluginInputsFromStoreNodes } from '@fastgpt/global/core/app/plugin/utils';
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
type RunPluginProps = ModuleDispatchProps<{
[NodeInputKeyEnum.forbidStream]?: boolean;
[key: string]: any;
}>;
type RunPluginResponse = DispatchNodeResultType<{}>;
@@ -26,9 +28,8 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
const {
node: { pluginId },
runningAppInfo,
mode,
query,
params: data // Plugin input
params: { system_forbid_stream = false, ...data } // Plugin input
} = props;
if (!pluginId) {
@@ -44,7 +45,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
per: ReadPermissionVal
});
const plugin = await getPluginRuntimeById(pluginId);
const plugin = await getChildAppRuntimeById(pluginId);
const runtimeNodes = storeNodes2RuntimeNodes(
plugin.nodes,
@@ -73,6 +74,13 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
const { flowResponses, flowUsages, assistantResponses, runTimes } = await dispatchWorkFlow({
...props,
// Rewrite stream mode
...(system_forbid_stream
? {
stream: false,
workflowStreamResponse: undefined
}
: {}),
runningAppInfo: {
id: String(plugin.id),
teamId: plugin.teamId || '',
@@ -95,11 +103,12 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
output.moduleLogo = plugin.avatar;
}
const isError = !!output?.pluginOutput?.error;
const usagePoints = isError ? 0 : await computedPluginUsage(plugin, flowUsages);
const usagePoints = await computedPluginUsage(plugin, flowUsages);
const childStreamResponse = system_forbid_stream ? false : props.stream;
return {
assistantResponses,
// 嵌套运行时,如果 childApp stream=false实际上不会有任何内容输出给用户所以不需要存储
assistantResponses: childStreamResponse ? assistantResponses : [],
// responseData, // debug
[DispatchNodeResponseKeyEnum.runTimes]: runTimes,
[DispatchNodeResponseKeyEnum.nodeResponse]: {
@@ -107,7 +116,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
totalPoints: usagePoints,
pluginOutput: output?.pluginOutput,
pluginDetail:
mode === 'test' && plugin.teamId === runningAppInfo.teamId
pluginData && pluginData.permission.hasWritePer // Not system plugin
? flowResponses.filter((item) => {
const filterArr = [FlowNodeTypeEnum.pluginOutput];
return !filterArr.includes(item.moduleType as any);

View File

@@ -22,6 +22,7 @@ type Props = ModuleDispatchProps<{
[NodeInputKeyEnum.userChatInput]: string;
[NodeInputKeyEnum.history]?: ChatItemType[] | number;
[NodeInputKeyEnum.fileUrlList]?: string[];
[NodeInputKeyEnum.forbidStream]?: boolean;
}>;
type Response = DispatchNodeResultType<{
[NodeOutputKeyEnum.answerText]: string;
@@ -33,13 +34,14 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
runningAppInfo,
histories,
query,
mode,
node: { pluginId },
workflowStreamResponse,
params,
variables
} = props;
const { userChatInput, history, ...childrenAppVariables } = params;
const { system_forbid_stream = false, userChatInput, history, ...childrenAppVariables } = params;
if (!userChatInput) {
return Promise.reject('Input is empty');
}
@@ -54,14 +56,17 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
per: ReadPermissionVal
});
const { nodes, edges, chatConfig } = await getAppLatestVersion(pluginId);
const childStreamResponse = system_forbid_stream ? false : props.stream;
// Auto line
workflowStreamResponse?.({
event: SseResponseEventEnum.answer,
data: textAdaptGptResponse({
text: '\n'
})
});
if (childStreamResponse) {
workflowStreamResponse?.({
event: SseResponseEventEnum.answer,
data: textAdaptGptResponse({
text: '\n'
})
});
}
const chatHistories = getHistories(history, histories);
const { files } = chatValue2RuntimePrompt(query);
@@ -77,6 +82,13 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
const { flowResponses, flowUsages, assistantResponses, runTimes } = await dispatchWorkFlow({
...props,
// Rewrite stream mode
...(system_forbid_stream
? {
stream: false,
workflowStreamResponse: undefined
}
: {}),
runningAppInfo: {
id: String(appData._id),
teamId: String(appData.teamId),
@@ -106,21 +118,26 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
const { text } = chatValue2RuntimePrompt(assistantResponses);
const usagePoints = flowUsages.reduce((sum, item) => sum + (item.totalPoints || 0), 0);
return {
assistantResponses,
assistantResponses: childStreamResponse ? assistantResponses : [],
[DispatchNodeResponseKeyEnum.runTimes]: runTimes,
[DispatchNodeResponseKeyEnum.nodeResponse]: {
moduleLogo: appData.avatar,
totalPoints: usagePoints,
query: userChatInput,
textOutput: text,
totalPoints: flowResponses.reduce((sum, item) => sum + (item.totalPoints || 0), 0)
pluginDetail: appData.permission.hasWritePer ? flowResponses : undefined
},
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [
{
moduleName: appData.name,
totalPoints: flowUsages.reduce((sum, item) => sum + (item.totalPoints || 0), 0)
totalPoints: usagePoints,
tokens: 0
}
],
[DispatchNodeResponseKeyEnum.toolResponses]: text,
answerText: text,
history: completeMessages
};

View File

@@ -12,17 +12,18 @@ import {
import { responseWrite } from '../../../common/response';
import { NextApiResponse } from 'next';
import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import { getNanoid } from '@fastgpt/global/common/string/tools';
export const getWorkflowResponseWrite = ({
res,
detail,
streamResponse,
id
id = getNanoid(24)
}: {
res?: NextApiResponse;
detail: boolean;
streamResponse: boolean;
id: string;
id?: string;
}) => {
return ({
write,