mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-22 20:37:48 +00:00
Feat: Workflow loop node;feat: support openai o1;perf: query extension prompt;fix: intro was not delivered when the datase was created (#2719)
* feat: loop node (#2675) * loop node frontend * loop-node * fix-code * fix version * fix * fix * fix * perf: loop array code * perf: get histories error tip * feat: support openai o1 * perf: query extension prompt * feat: 4811 doc * remove log * fix: loop node zindex & variable picker type (#2710) * perf: performance * perf: workflow performance * remove uninvalid code * perf:code * fix: invoice table refresh * perf: loop node data type * fix: loop node store assistants * perf: target connection * feat: loop node support help line * perf: add default icon --------- Co-authored-by: heheer <heheer@sealos.io>
This commit is contained in:
@@ -344,7 +344,7 @@ export const runtimePrompt2ChatsValue = (
|
||||
return value;
|
||||
};
|
||||
|
||||
export const getSystemPrompt = (prompt?: string): ChatItemType[] => {
|
||||
export const getSystemPrompt_ChatItemType = (prompt?: string): ChatItemType[] => {
|
||||
if (!prompt) return [];
|
||||
return [
|
||||
{
|
||||
|
@@ -24,6 +24,7 @@ export enum WorkflowIOValueTypeEnum {
|
||||
arrayNumber = 'arrayNumber',
|
||||
arrayBoolean = 'arrayBoolean',
|
||||
arrayObject = 'arrayObject',
|
||||
arrayAny = 'arrayAny',
|
||||
any = 'any',
|
||||
|
||||
chatHistory = 'chatHistory',
|
||||
@@ -135,7 +136,17 @@ export enum NodeInputKeyEnum {
|
||||
fileUrlList = 'fileUrlList',
|
||||
|
||||
// user select
|
||||
userSelectOptions = 'userSelectOptions'
|
||||
userSelectOptions = 'userSelectOptions',
|
||||
|
||||
// loop
|
||||
loopInputArray = 'loopInputArray',
|
||||
childrenNodeIdList = 'childrenNodeIdList',
|
||||
nodeWidth = 'nodeWidth',
|
||||
nodeHeight = 'nodeHeight',
|
||||
// loop start
|
||||
loopStartInput = 'loopStartInput',
|
||||
// loop end
|
||||
loopEndInput = 'loopEndInput'
|
||||
}
|
||||
|
||||
export enum NodeOutputKeyEnum {
|
||||
@@ -178,7 +189,13 @@ export enum NodeOutputKeyEnum {
|
||||
ifElseResult = 'ifElseResult',
|
||||
|
||||
//user select
|
||||
selectResult = 'selectResult'
|
||||
selectResult = 'selectResult',
|
||||
|
||||
// loop
|
||||
loopArray = 'loopArray',
|
||||
|
||||
// loop start
|
||||
loopStartInput = 'loopStartInput'
|
||||
}
|
||||
|
||||
export enum VariableInputEnum {
|
||||
|
@@ -125,7 +125,10 @@ export enum FlowNodeTypeEnum {
|
||||
textEditor = 'textEditor',
|
||||
customFeedback = 'customFeedback',
|
||||
readFiles = 'readFiles',
|
||||
userSelect = 'userSelect'
|
||||
userSelect = 'userSelect',
|
||||
loop = 'loop',
|
||||
loopStart = 'loopStart',
|
||||
loopEnd = 'loopEnd'
|
||||
}
|
||||
|
||||
// node IO value type
|
||||
@@ -162,6 +165,10 @@ export const FlowValueTypeMap = {
|
||||
label: 'array<object>',
|
||||
value: WorkflowIOValueTypeEnum.arrayObject
|
||||
},
|
||||
[WorkflowIOValueTypeEnum.arrayAny]: {
|
||||
label: 'array',
|
||||
value: WorkflowIOValueTypeEnum.arrayAny
|
||||
},
|
||||
[WorkflowIOValueTypeEnum.any]: {
|
||||
label: 'any',
|
||||
value: WorkflowIOValueTypeEnum.any
|
||||
|
@@ -172,6 +172,15 @@ export type DispatchNodeResponseType = {
|
||||
|
||||
// update var
|
||||
updateVarResult?: any[];
|
||||
|
||||
// loop
|
||||
loopResult?: any[];
|
||||
loopInput?: any[];
|
||||
loopDetail?: ChatHistoryItemResType[];
|
||||
// loop start
|
||||
loopInputValue?: any;
|
||||
// loop end
|
||||
loopOutputValue?: any;
|
||||
};
|
||||
|
||||
export type DispatchNodeResultType<T = {}> = {
|
||||
|
@@ -29,6 +29,9 @@ import { TextEditorNode } from './system/textEditor';
|
||||
import { CustomFeedbackNode } from './system/customFeedback';
|
||||
import { ReadFilesNodes } from './system/readFiles';
|
||||
import { UserSelectNode } from './system/userSelect/index';
|
||||
import { LoopNode } from './system/loop/loop';
|
||||
import { LoopStartNode } from './system/loop/loopStart';
|
||||
import { LoopEndNode } from './system/loop/loopEnd';
|
||||
|
||||
const systemNodes: FlowNodeTemplateType[] = [
|
||||
AiChatModule,
|
||||
@@ -46,7 +49,8 @@ const systemNodes: FlowNodeTemplateType[] = [
|
||||
LafModule,
|
||||
IfElseNode,
|
||||
VariableUpdateNode,
|
||||
CodeNode
|
||||
CodeNode,
|
||||
LoopNode
|
||||
];
|
||||
/* app flow module templates */
|
||||
export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
|
||||
@@ -74,5 +78,7 @@ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [
|
||||
EmptyNode,
|
||||
RunPluginModule,
|
||||
RunAppNode,
|
||||
RunAppModule
|
||||
RunAppModule,
|
||||
LoopStartNode,
|
||||
LoopEndNode
|
||||
];
|
||||
|
@@ -83,3 +83,25 @@ export const Input_Template_File_Link: FlowNodeInputItemType = {
|
||||
description: i18nT('app:workflow.user_file_input_desc'),
|
||||
valueType: WorkflowIOValueTypeEnum.arrayString
|
||||
};
|
||||
|
||||
export const Input_Template_Children_Node_List: FlowNodeInputItemType = {
|
||||
key: NodeInputKeyEnum.childrenNodeIdList,
|
||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||
valueType: WorkflowIOValueTypeEnum.arrayString,
|
||||
label: '',
|
||||
value: []
|
||||
};
|
||||
export const Input_Template_Node_Width: FlowNodeInputItemType = {
|
||||
key: NodeInputKeyEnum.nodeWidth,
|
||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||
valueType: WorkflowIOValueTypeEnum.number,
|
||||
label: '',
|
||||
value: 900
|
||||
};
|
||||
export const Input_Template_Node_Height: FlowNodeInputItemType = {
|
||||
key: NodeInputKeyEnum.nodeHeight,
|
||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||
valueType: WorkflowIOValueTypeEnum.number,
|
||||
label: '',
|
||||
value: 900
|
||||
};
|
||||
|
54
packages/global/core/workflow/template/system/loop/loop.ts
Normal file
54
packages/global/core/workflow/template/system/loop/loop.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import {
|
||||
FlowNodeInputTypeEnum,
|
||||
FlowNodeOutputTypeEnum,
|
||||
FlowNodeTypeEnum
|
||||
} from '../../../node/constant';
|
||||
import { FlowNodeTemplateType } from '../../../type/node';
|
||||
import {
|
||||
FlowNodeTemplateTypeEnum,
|
||||
NodeInputKeyEnum,
|
||||
NodeOutputKeyEnum,
|
||||
WorkflowIOValueTypeEnum
|
||||
} from '../../../constants';
|
||||
import { getHandleConfig } from '../../utils';
|
||||
import { i18nT } from '../../../../../../web/i18n/utils';
|
||||
import {
|
||||
Input_Template_Children_Node_List,
|
||||
Input_Template_Node_Height,
|
||||
Input_Template_Node_Width
|
||||
} from '../../input';
|
||||
|
||||
export const LoopNode: FlowNodeTemplateType = {
|
||||
id: FlowNodeTypeEnum.loop,
|
||||
templateType: FlowNodeTemplateTypeEnum.tools,
|
||||
flowNodeType: FlowNodeTypeEnum.loop,
|
||||
sourceHandle: getHandleConfig(true, true, true, true),
|
||||
targetHandle: getHandleConfig(true, true, true, true),
|
||||
avatar: 'core/workflow/template/loop',
|
||||
name: i18nT('workflow:loop'),
|
||||
intro: i18nT('workflow:intro_loop'),
|
||||
showStatus: true,
|
||||
version: '4811',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.loopInputArray,
|
||||
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
||||
valueType: WorkflowIOValueTypeEnum.arrayAny,
|
||||
required: true,
|
||||
label: i18nT('workflow:loop_input_array'),
|
||||
value: []
|
||||
},
|
||||
Input_Template_Children_Node_List,
|
||||
Input_Template_Node_Width,
|
||||
Input_Template_Node_Height
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
id: NodeOutputKeyEnum.loopArray,
|
||||
key: NodeOutputKeyEnum.loopArray,
|
||||
label: i18nT('workflow:loop_result'),
|
||||
type: FlowNodeOutputTypeEnum.static,
|
||||
valueType: WorkflowIOValueTypeEnum.arrayAny
|
||||
}
|
||||
]
|
||||
};
|
@@ -0,0 +1,34 @@
|
||||
import { i18nT } from '../../../../../../web/i18n/utils';
|
||||
import {
|
||||
FlowNodeTemplateTypeEnum,
|
||||
NodeInputKeyEnum,
|
||||
WorkflowIOValueTypeEnum
|
||||
} from '../../../constants';
|
||||
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../../node/constant';
|
||||
import { FlowNodeTemplateType } from '../../../type/node';
|
||||
import { getHandleConfig } from '../../utils';
|
||||
|
||||
export const LoopEndNode: FlowNodeTemplateType = {
|
||||
id: FlowNodeTypeEnum.loopEnd,
|
||||
templateType: FlowNodeTemplateTypeEnum.systemInput,
|
||||
flowNodeType: FlowNodeTypeEnum.loopEnd,
|
||||
sourceHandle: getHandleConfig(false, false, false, false),
|
||||
targetHandle: getHandleConfig(false, false, false, true),
|
||||
unique: true,
|
||||
forbidDelete: true,
|
||||
avatar: 'core/workflow/template/loopEnd',
|
||||
name: i18nT('workflow:loop_end'),
|
||||
showStatus: false,
|
||||
version: '4811',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.loopEndInput,
|
||||
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
||||
valueType: WorkflowIOValueTypeEnum.any,
|
||||
label: '',
|
||||
required: true,
|
||||
value: []
|
||||
}
|
||||
],
|
||||
outputs: []
|
||||
};
|
@@ -0,0 +1,34 @@
|
||||
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../../node/constant';
|
||||
import { FlowNodeTemplateType } from '../../../type/node.d';
|
||||
import {
|
||||
FlowNodeTemplateTypeEnum,
|
||||
NodeInputKeyEnum,
|
||||
WorkflowIOValueTypeEnum
|
||||
} from '../../../constants';
|
||||
import { getHandleConfig } from '../../utils';
|
||||
import { i18nT } from '../../../../../../web/i18n/utils';
|
||||
|
||||
export const LoopStartNode: FlowNodeTemplateType = {
|
||||
id: FlowNodeTypeEnum.loopStart,
|
||||
templateType: FlowNodeTemplateTypeEnum.systemInput,
|
||||
flowNodeType: FlowNodeTypeEnum.loopStart,
|
||||
sourceHandle: getHandleConfig(false, true, false, false),
|
||||
targetHandle: getHandleConfig(false, false, false, false),
|
||||
avatar: 'core/workflow/template/loopStart',
|
||||
name: i18nT('workflow:loop_start'),
|
||||
unique: true,
|
||||
forbidDelete: true,
|
||||
showStatus: false,
|
||||
version: '4811',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.loopStartInput,
|
||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||
valueType: WorkflowIOValueTypeEnum.any,
|
||||
label: '',
|
||||
required: true,
|
||||
value: ''
|
||||
}
|
||||
],
|
||||
outputs: []
|
||||
};
|
1
packages/global/core/workflow/type/node.d.ts
vendored
1
packages/global/core/workflow/type/node.d.ts
vendored
@@ -95,6 +95,7 @@ export type NodeTemplateListType = {
|
||||
// react flow node type
|
||||
export type FlowNodeItemType = FlowNodeTemplateType & {
|
||||
nodeId: string;
|
||||
parentNodeId?: string;
|
||||
isError?: boolean;
|
||||
debugResult?: {
|
||||
status: 'running' | 'success' | 'skipped' | 'failed';
|
||||
|
@@ -11,7 +11,7 @@
|
||||
"jschardet": "3.1.1",
|
||||
"nanoid": "^4.0.1",
|
||||
"next": "14.2.5",
|
||||
"openai": "4.57.0",
|
||||
"openai": "4.61.0",
|
||||
"openapi-types": "^12.1.3",
|
||||
"timezones-list": "^3.0.2"
|
||||
},
|
||||
|
@@ -4,13 +4,17 @@ import { ChatItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { countGptMessagesTokens } from '../../../common/string/tiktoken/index';
|
||||
import { ChatCompletionMessageParam } from '@fastgpt/global/core/ai/type';
|
||||
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
||||
import { getLLMModel } from '../model';
|
||||
|
||||
/*
|
||||
query extension - 问题扩展
|
||||
可以根据上下文,消除指代性问题以及扩展问题,利于检索。
|
||||
*/
|
||||
|
||||
const defaultPrompt = `作为一个向量检索助手,你的任务是结合历史记录,从不同角度,为“原问题”生成个不同版本的“检索词”,从而提高向量检索的语义丰富度,提高向量检索的精度。生成的问题要求指向对象清晰明确,并与“原问题语言相同”。
|
||||
const title = global.feConfigs?.systemTitle || 'FastAI';
|
||||
const defaultPrompt = `作为一个向量检索助手,你的任务是结合历史记录,从不同角度,为“原问题”生成个不同版本的“检索词”,从而提高向量检索的语义丰富度,提高向量检索的精度。
|
||||
生成的问题要求指向对象清晰明确,并与“原问题语言相同”。
|
||||
|
||||
参考 <Example></Example> 标中的示例来完成任务。
|
||||
|
||||
<Example>
|
||||
@@ -49,49 +53,50 @@ A: 护产假的天数根据员工所在的城市而定。请提供您所在的
|
||||
历史记录:
|
||||
"""
|
||||
Q: 作者是谁?
|
||||
A: FastGPT 的作者是 labring。
|
||||
A: ${title} 的作者是 labring。
|
||||
"""
|
||||
原问题: Tell me about him
|
||||
检索词: ["Introduce labring, the author of FastGPT." ," Background information on author labring." "," Why does labring do FastGPT?"]
|
||||
检索词: ["Introduce labring, the author of ${title}." ," Background information on author labring." "," Why does labring do ${title}?"]
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: 对话背景。
|
||||
A: 关于 FatGPT 的介绍和使用等问题。
|
||||
A: 关于 ${title} 的介绍和使用等问题。
|
||||
"""
|
||||
原问题: 你好。
|
||||
检索词: ["你好"]
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: FastGPT 如何收费?
|
||||
A: FastGPT 收费可以参考……
|
||||
Q: ${title} 如何收费?
|
||||
A: ${title} 收费可以参考……
|
||||
"""
|
||||
原问题: 你知道 laf 么?
|
||||
检索词: ["laf 的官网地址是多少?","laf 的使用教程。","laf 有什么特点和优势。"]
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: FastGPT 的优势
|
||||
Q: ${title} 的优势
|
||||
A: 1. 开源
|
||||
2. 简便
|
||||
3. 扩展性强
|
||||
"""
|
||||
原问题: 介绍下第2点。
|
||||
检索词: ["介绍下 FastGPT 简便的优势", "从哪些方面,可以体现出 FastGPT 的简便"]。
|
||||
检索词: ["介绍下 ${title} 简便的优势", "从哪些方面,可以体现出 ${title} 的简便"]。
|
||||
----------------
|
||||
历史记录:
|
||||
"""
|
||||
Q: 什么是 FastGPT?
|
||||
A: FastGPT 是一个 RAG 平台。
|
||||
Q: 什么是 ${title}?
|
||||
A: ${title} 是一个 RAG 平台。
|
||||
Q: 什么是 Laf?
|
||||
A: Laf 是一个云函数开发平台。
|
||||
"""
|
||||
原问题: 它们有什么关系?
|
||||
检索词: ["FastGPT和Laf有什么关系?","介绍下FastGPT","介绍下Laf"]
|
||||
检索词: ["${title}和Laf有什么关系?","介绍下${title}","介绍下Laf"]
|
||||
</Example>
|
||||
|
||||
----------------
|
||||
-----
|
||||
|
||||
下面是正式的任务:
|
||||
|
||||
历史记录:
|
||||
@@ -130,6 +135,8 @@ A: ${chatBg}
|
||||
.join('\n');
|
||||
const concatFewShot = `${systemFewShot}${historyFewShot}`.trim();
|
||||
|
||||
const modelData = getLLMModel(model);
|
||||
|
||||
const ai = getAIApi({
|
||||
timeout: 480000
|
||||
});
|
||||
@@ -144,11 +151,12 @@ A: ${chatBg}
|
||||
}
|
||||
] as ChatCompletionMessageParam[];
|
||||
const result = await ai.chat.completions.create({
|
||||
model: model,
|
||||
model: modelData.model,
|
||||
temperature: 0.01,
|
||||
// @ts-ignore
|
||||
messages,
|
||||
stream: false
|
||||
stream: false,
|
||||
...modelData.defaultConfig
|
||||
});
|
||||
|
||||
let answer = result.choices?.[0]?.message?.content || '';
|
||||
@@ -161,6 +169,8 @@ A: ${chatBg}
|
||||
};
|
||||
}
|
||||
|
||||
// Intercept the content of [] and retain []
|
||||
answer = answer.match(/\[.*?\]/)?.[0] || '';
|
||||
answer = answer.replace(/\\"/g, '"');
|
||||
|
||||
try {
|
||||
|
@@ -93,6 +93,7 @@ export const dispatchAppRequest = async (props: Props): Promise<Response> => {
|
||||
const { text } = chatValue2RuntimePrompt(assistantResponses);
|
||||
|
||||
return {
|
||||
assistantResponses,
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||
moduleLogo: appData.avatar,
|
||||
query: userChatInput,
|
||||
|
@@ -128,7 +128,8 @@ const completions = async ({
|
||||
model: cqModel.model,
|
||||
temperature: 0.01,
|
||||
messages: requestMessages,
|
||||
stream: false
|
||||
stream: false,
|
||||
...cqModel.defaultConfig
|
||||
});
|
||||
const answer = data.choices?.[0].message?.content || '';
|
||||
|
||||
|
@@ -355,7 +355,8 @@ Human: ${content}`
|
||||
model: extractModel.model,
|
||||
temperature: 0.01,
|
||||
messages: requestMessages,
|
||||
stream: false
|
||||
stream: false,
|
||||
...extractModel.defaultConfig
|
||||
});
|
||||
const answer = data.choices?.[0].message?.content || '';
|
||||
|
||||
|
@@ -14,7 +14,7 @@ import {
|
||||
GPTMessages2Chats,
|
||||
chatValue2RuntimePrompt,
|
||||
chats2GPTMessages,
|
||||
getSystemPrompt,
|
||||
getSystemPrompt_ChatItemType,
|
||||
runtimePrompt2ChatsValue
|
||||
} from '@fastgpt/global/core/chat/adapt';
|
||||
import { formatModelChars2Points } from '../../../../../support/wallet/usage/utils';
|
||||
@@ -95,7 +95,8 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
||||
});
|
||||
|
||||
const messages: ChatItemType[] = [
|
||||
...getSystemPrompt(systemPrompt),
|
||||
...getSystemPrompt_ChatItemType(toolModel.defaultSystemChatPrompt),
|
||||
...getSystemPrompt_ChatItemType(systemPrompt),
|
||||
// Add file input prompt to histories
|
||||
...chatHistories.map((item) => {
|
||||
if (item.obj === ChatRoleEnum.Human) {
|
||||
|
@@ -114,15 +114,16 @@ export const runToolWithPromptCall = async (
|
||||
})
|
||||
]);
|
||||
const requestBody = {
|
||||
...toolModel?.defaultConfig,
|
||||
model: toolModel.model,
|
||||
temperature: computedTemperature({
|
||||
model: toolModel,
|
||||
temperature
|
||||
}),
|
||||
max_completion_tokens: max_tokens,
|
||||
max_tokens,
|
||||
stream,
|
||||
messages: requestMessages
|
||||
messages: requestMessages,
|
||||
...toolModel?.defaultConfig
|
||||
};
|
||||
|
||||
// console.log(JSON.stringify(requestBody, null, 2));
|
||||
@@ -135,9 +136,13 @@ export const runToolWithPromptCall = async (
|
||||
Accept: 'application/json, text/plain, */*'
|
||||
}
|
||||
});
|
||||
const isStreamResponse =
|
||||
typeof aiResponse === 'object' &&
|
||||
aiResponse !== null &&
|
||||
('iterator' in aiResponse || 'controller' in aiResponse);
|
||||
|
||||
const answer = await (async () => {
|
||||
if (res && stream) {
|
||||
if (res && isStreamResponse) {
|
||||
const { answer } = await streamResponse({
|
||||
res,
|
||||
toolNodes,
|
||||
@@ -164,6 +169,17 @@ export const runToolWithPromptCall = async (
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 不支持 stream 模式的模型的流失响应
|
||||
if (stream && !isStreamResponse) {
|
||||
workflowStreamResponse?.({
|
||||
event: SseResponseEventEnum.fastAnswer,
|
||||
data: textAdaptGptResponse({
|
||||
text: replaceAnswer
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// No tool is invoked, indicating that the process is over
|
||||
const gptAssistantResponse: ChatCompletionAssistantMessageParam = {
|
||||
role: ChatCompletionRequestMessageRoleEnum.Assistant,
|
||||
|
@@ -128,17 +128,18 @@ export const runToolWithToolChoice = async (
|
||||
})
|
||||
]);
|
||||
const requestBody: any = {
|
||||
...toolModel?.defaultConfig,
|
||||
model: toolModel.model,
|
||||
temperature: computedTemperature({
|
||||
model: toolModel,
|
||||
temperature
|
||||
}),
|
||||
max_completion_tokens: max_tokens,
|
||||
max_tokens,
|
||||
stream,
|
||||
messages: requestMessages,
|
||||
tools,
|
||||
tool_choice: 'auto'
|
||||
tool_choice: 'auto',
|
||||
...toolModel?.defaultConfig
|
||||
};
|
||||
|
||||
// console.log(JSON.stringify(requestBody, null, 2));
|
||||
@@ -153,9 +154,13 @@ export const runToolWithToolChoice = async (
|
||||
Accept: 'application/json, text/plain, */*'
|
||||
}
|
||||
});
|
||||
const isStreamResponse =
|
||||
typeof aiResponse === 'object' &&
|
||||
aiResponse !== null &&
|
||||
('iterator' in aiResponse || 'controller' in aiResponse);
|
||||
|
||||
const { answer, toolCalls } = await (async () => {
|
||||
if (res && stream) {
|
||||
if (res && isStreamResponse) {
|
||||
return streamResponse({
|
||||
res,
|
||||
workflowStreamResponse,
|
||||
@@ -165,6 +170,7 @@ export const runToolWithToolChoice = async (
|
||||
} else {
|
||||
const result = aiResponse as ChatCompletion;
|
||||
const calls = result.choices?.[0]?.message?.tool_calls || [];
|
||||
const answer = result.choices?.[0]?.message?.content || '';
|
||||
|
||||
// 加上name和avatar
|
||||
const toolCalls = calls.map((tool) => {
|
||||
@@ -176,8 +182,33 @@ export const runToolWithToolChoice = async (
|
||||
};
|
||||
});
|
||||
|
||||
// 不支持 stream 模式的模型的流失响应
|
||||
toolCalls.forEach((tool) => {
|
||||
workflowStreamResponse?.({
|
||||
event: SseResponseEventEnum.toolCall,
|
||||
data: {
|
||||
tool: {
|
||||
id: tool.id,
|
||||
toolName: tool.toolName,
|
||||
toolAvatar: tool.toolAvatar,
|
||||
functionName: tool.function.name,
|
||||
params: tool.function?.arguments ?? '',
|
||||
response: ''
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
if (answer) {
|
||||
workflowStreamResponse?.({
|
||||
event: SseResponseEventEnum.fastAnswer,
|
||||
data: textAdaptGptResponse({
|
||||
text: answer
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
answer: result.choices?.[0]?.message?.content || '',
|
||||
answer,
|
||||
toolCalls: toolCalls
|
||||
};
|
||||
}
|
||||
@@ -239,7 +270,7 @@ export const runToolWithToolChoice = async (
|
||||
toolName: '',
|
||||
toolAvatar: '',
|
||||
params: '',
|
||||
response: sliceStrStartEnd(stringToolResponse, 500, 500)
|
||||
response: sliceStrStartEnd(stringToolResponse, 2000, 2000)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@@ -19,7 +19,7 @@ import { countMessagesTokens } from '../../../../common/string/tiktoken/index';
|
||||
import {
|
||||
chats2GPTMessages,
|
||||
chatValue2RuntimePrompt,
|
||||
getSystemPrompt,
|
||||
getSystemPrompt_ChatItemType,
|
||||
GPTMessages2Chats,
|
||||
runtimePrompt2ChatsValue
|
||||
} from '@fastgpt/global/core/chat/adapt';
|
||||
@@ -153,15 +153,16 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
||||
]);
|
||||
|
||||
const requestBody = {
|
||||
...modelConstantsData?.defaultConfig,
|
||||
model: modelConstantsData.model,
|
||||
temperature: computedTemperature({
|
||||
model: modelConstantsData,
|
||||
temperature
|
||||
}),
|
||||
max_completion_tokens: max_tokens,
|
||||
max_tokens,
|
||||
stream,
|
||||
messages: requestMessages
|
||||
messages: requestMessages,
|
||||
...modelConstantsData?.defaultConfig
|
||||
};
|
||||
// console.log(JSON.stringify(requestBody, null, 2), '===');
|
||||
try {
|
||||
@@ -175,8 +176,13 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
||||
}
|
||||
});
|
||||
|
||||
const isStreamResponse =
|
||||
typeof response === 'object' &&
|
||||
response !== null &&
|
||||
('iterator' in response || 'controller' in response);
|
||||
|
||||
const { answerText } = await (async () => {
|
||||
if (res && stream) {
|
||||
if (res && isStreamResponse) {
|
||||
// sse response
|
||||
const { answer } = await streamResponse({
|
||||
res,
|
||||
@@ -195,6 +201,14 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
||||
const unStreamResponse = response as ChatCompletion;
|
||||
const answer = unStreamResponse.choices?.[0]?.message?.content || '';
|
||||
|
||||
// Some models do not support streaming
|
||||
workflowStreamResponse?.({
|
||||
event: SseResponseEventEnum.fastAnswer,
|
||||
data: textAdaptGptResponse({
|
||||
text: answer
|
||||
})
|
||||
});
|
||||
|
||||
return {
|
||||
answerText: answer
|
||||
};
|
||||
@@ -310,9 +324,9 @@ async function getChatMessages({
|
||||
: userChatInput;
|
||||
|
||||
const messages: ChatItemType[] = [
|
||||
...getSystemPrompt(systemPrompt),
|
||||
...getSystemPrompt_ChatItemType(systemPrompt),
|
||||
...(stringQuoteText
|
||||
? getSystemPrompt(
|
||||
? getSystemPrompt_ChatItemType(
|
||||
replaceVariable(Prompt_DocumentQuote, {
|
||||
quote: stringQuoteText
|
||||
})
|
||||
|
@@ -66,6 +66,9 @@ import {
|
||||
UserSelectInteractive
|
||||
} from '@fastgpt/global/core/workflow/template/system/userSelect/type';
|
||||
import { dispatchRunAppNode } from './plugin/runApp';
|
||||
import { dispatchLoop } from './loop/runLoop';
|
||||
import { dispatchLoopEnd } from './loop/runLoopEnd';
|
||||
import { dispatchLoopStart } from './loop/runLoopStart';
|
||||
|
||||
const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
||||
@@ -91,6 +94,9 @@ const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||
[FlowNodeTypeEnum.customFeedback]: dispatchCustomFeedback,
|
||||
[FlowNodeTypeEnum.readFiles]: dispatchReadFiles,
|
||||
[FlowNodeTypeEnum.userSelect]: dispatchUserSelect,
|
||||
[FlowNodeTypeEnum.loop]: dispatchLoop,
|
||||
[FlowNodeTypeEnum.loopStart]: dispatchLoopStart,
|
||||
[FlowNodeTypeEnum.loopEnd]: dispatchLoopEnd,
|
||||
|
||||
// none
|
||||
[FlowNodeTypeEnum.systemConfig]: dispatchSystemConfig,
|
||||
@@ -160,7 +166,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
let chatResponses: ChatHistoryItemResType[] = []; // response request and save to database
|
||||
let chatAssistantResponse: AIChatItemValueItemType[] = []; // The value will be returned to the user
|
||||
let chatNodeUsages: ChatNodeUsageType[] = [];
|
||||
let toolRunResponse: ToolRunResponseItemType;
|
||||
let toolRunResponse: ToolRunResponseItemType; // Run with tool mode. Result will response to tool node.
|
||||
let debugNextStepRunNodes: RuntimeNodeItemType[] = [];
|
||||
// 记录交互节点,交互节点需要在工作流完全结束后再进行计算
|
||||
let workflowInteractiveResponse:
|
||||
@@ -196,9 +202,11 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
if (responseData) {
|
||||
chatResponses.push(responseData);
|
||||
}
|
||||
|
||||
if (nodeDispatchUsages) {
|
||||
chatNodeUsages = chatNodeUsages.concat(nodeDispatchUsages);
|
||||
}
|
||||
|
||||
if (toolResponses !== undefined) {
|
||||
if (Array.isArray(toolResponses) && toolResponses.length === 0) return;
|
||||
if (typeof toolResponses === 'object' && Object.keys(toolResponses).length === 0) {
|
||||
@@ -206,6 +214,8 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
}
|
||||
toolRunResponse = toolResponses;
|
||||
}
|
||||
|
||||
// Histories store
|
||||
if (assistantResponses) {
|
||||
chatAssistantResponse = chatAssistantResponse.concat(assistantResponses);
|
||||
} else if (answerText) {
|
||||
|
93
packages/service/core/workflow/dispatch/loop/runLoop.ts
Normal file
93
packages/service/core/workflow/dispatch/loop/runLoop.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import {
|
||||
DispatchNodeResultType,
|
||||
ModuleDispatchProps
|
||||
} from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { dispatchWorkFlow } from '..';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { AIChatItemValueItemType, ChatHistoryItemResType } from '@fastgpt/global/core/chat/type';
|
||||
|
||||
type Props = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.loopInputArray]: Array<any>;
|
||||
[NodeInputKeyEnum.childrenNodeIdList]: string[];
|
||||
}>;
|
||||
type Response = DispatchNodeResultType<{
|
||||
[NodeOutputKeyEnum.loopArray]: Array<any>;
|
||||
}>;
|
||||
|
||||
export const dispatchLoop = async (props: Props): Promise<Response> => {
|
||||
const {
|
||||
params,
|
||||
runtimeNodes,
|
||||
user,
|
||||
node: { name }
|
||||
} = props;
|
||||
const { loopInputArray = [], childrenNodeIdList } = params;
|
||||
|
||||
if (!Array.isArray(loopInputArray)) {
|
||||
return Promise.reject('Input value is not an array');
|
||||
}
|
||||
if (loopInputArray.length > 50) {
|
||||
return Promise.reject('Input array length cannot be greater than 50');
|
||||
}
|
||||
|
||||
const runNodes = runtimeNodes.filter((node) => childrenNodeIdList.includes(node.nodeId));
|
||||
|
||||
const outputValueArr = [];
|
||||
const loopDetail: ChatHistoryItemResType[] = [];
|
||||
let assistantResponses: AIChatItemValueItemType[] = [];
|
||||
let totalPoints = 0;
|
||||
|
||||
for await (const item of loopInputArray) {
|
||||
const response = await dispatchWorkFlow({
|
||||
...props,
|
||||
runtimeNodes: runNodes.map((node) =>
|
||||
node.flowNodeType === FlowNodeTypeEnum.loopStart
|
||||
? {
|
||||
...node,
|
||||
isEntry: true,
|
||||
inputs: node.inputs.map((input) =>
|
||||
input.key === NodeInputKeyEnum.loopStartInput
|
||||
? {
|
||||
...input,
|
||||
value: item
|
||||
}
|
||||
: input
|
||||
)
|
||||
}
|
||||
: {
|
||||
...node,
|
||||
isEntry: false
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
const loopOutputValue = response.flowResponses.find(
|
||||
(res) => res.moduleType === FlowNodeTypeEnum.loopEnd
|
||||
)?.loopOutputValue;
|
||||
|
||||
outputValueArr.push(loopOutputValue);
|
||||
loopDetail.push(...response.flowResponses);
|
||||
assistantResponses.push(...response.assistantResponses);
|
||||
|
||||
totalPoints = response.flowUsages.reduce((acc, usage) => acc + usage.totalPoints, 0);
|
||||
}
|
||||
|
||||
return {
|
||||
[DispatchNodeResponseKeyEnum.assistantResponses]: assistantResponses,
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||
totalPoints: totalPoints,
|
||||
loopInput: loopInputArray,
|
||||
loopResult: outputValueArr,
|
||||
loopDetail: loopDetail
|
||||
},
|
||||
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [
|
||||
{
|
||||
totalPoints: user.openaiAccount?.key ? 0 : totalPoints,
|
||||
moduleName: name
|
||||
}
|
||||
],
|
||||
[NodeOutputKeyEnum.loopArray]: outputValueArr
|
||||
};
|
||||
};
|
21
packages/service/core/workflow/dispatch/loop/runLoopEnd.ts
Normal file
21
packages/service/core/workflow/dispatch/loop/runLoopEnd.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import {
|
||||
DispatchNodeResultType,
|
||||
ModuleDispatchProps
|
||||
} from '@fastgpt/global/core/workflow/runtime/type';
|
||||
|
||||
type Props = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.loopEndInput]: any;
|
||||
}>;
|
||||
type Response = DispatchNodeResultType<{}>;
|
||||
|
||||
export const dispatchLoopEnd = async (props: Props): Promise<Response> => {
|
||||
const { params } = props;
|
||||
|
||||
return {
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||
loopOutputValue: params.loopEndInput
|
||||
}
|
||||
};
|
||||
};
|
23
packages/service/core/workflow/dispatch/loop/runLoopStart.ts
Normal file
23
packages/service/core/workflow/dispatch/loop/runLoopStart.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import {
|
||||
DispatchNodeResultType,
|
||||
ModuleDispatchProps
|
||||
} from '@fastgpt/global/core/workflow/runtime/type';
|
||||
|
||||
type Props = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.loopStartInput]: any;
|
||||
}>;
|
||||
type Response = DispatchNodeResultType<{
|
||||
[NodeOutputKeyEnum.loopStartInput]: any;
|
||||
}>;
|
||||
|
||||
export const dispatchLoopStart = async (props: Props): Promise<Response> => {
|
||||
const { params } = props;
|
||||
return {
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||
loopInputValue: params.loopStartInput
|
||||
},
|
||||
[NodeOutputKeyEnum.loopStartInput]: params.loopStartInput
|
||||
};
|
||||
};
|
@@ -107,6 +107,7 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
|
||||
const { text } = chatValue2RuntimePrompt(assistantResponses);
|
||||
|
||||
return {
|
||||
assistantResponses,
|
||||
[DispatchNodeResponseKeyEnum.runTimes]: runTimes,
|
||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||
moduleLogo: appData.avatar,
|
||||
|
@@ -20,7 +20,7 @@ export const dispatchAnswer = (props: Record<string, any>): AnswerResponse => {
|
||||
} = props as AnswerProps;
|
||||
|
||||
const formatText = typeof text === 'string' ? text : JSON.stringify(text, null, 2);
|
||||
const responseText = `\n${formatText}`;
|
||||
const responseText = `\n${formatText}`.replaceAll('\\n', '\n');
|
||||
|
||||
workflowStreamResponse?.({
|
||||
event: SseResponseEventEnum.fastAnswer,
|
||||
|
@@ -5,13 +5,14 @@ import { useTranslation } from 'next-i18next';
|
||||
|
||||
type Props = FlexProps & {
|
||||
text?: string | React.ReactNode;
|
||||
iconSize?: string | number;
|
||||
};
|
||||
|
||||
const EmptyTip = ({ text, ...props }: Props) => {
|
||||
const EmptyTip = ({ text, iconSize = '48px', ...props }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Flex mt={5} flexDirection={'column'} alignItems={'center'} py={'10vh'} {...props}>
|
||||
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
|
||||
<MyIcon name="empty" w={iconSize} h={iconSize} color={'transparent'} />
|
||||
<Box mt={2} color={'myGray.500'} fontSize={'sm'}>
|
||||
{text || t('common:common.empty.Common Tip')}
|
||||
</Box>
|
||||
|
@@ -177,6 +177,7 @@ export const iconPaths = {
|
||||
'core/workflow/debugResult': () => import('./icons/core/workflow/debugResult.svg'),
|
||||
'core/workflow/edgeArrow': () => import('./icons/core/workflow/edgeArrow.svg'),
|
||||
'core/workflow/grout': () => import('./icons/core/workflow/grout.svg'),
|
||||
'core/workflow/inputType/array': () => import('./icons/core/workflow/inputType/array.svg'),
|
||||
'core/workflow/inputType/customVariable': () =>
|
||||
import('./icons/core/workflow/inputType/customVariable.svg'),
|
||||
'core/workflow/inputType/dynamic': () => import('./icons/core/workflow/inputType/dynamic.svg'),
|
||||
@@ -226,6 +227,9 @@ export const iconPaths = {
|
||||
'core/workflow/template/ifelse': () => import('./icons/core/workflow/template/ifelse.svg'),
|
||||
'core/workflow/template/lafDispatch': () =>
|
||||
import('./icons/core/workflow/template/lafDispatch.svg'),
|
||||
'core/workflow/template/loop': () => import('./icons/core/workflow/template/loop.svg'),
|
||||
'core/workflow/template/loopEnd': () => import('./icons/core/workflow/template/loopEnd.svg'),
|
||||
'core/workflow/template/loopStart': () => import('./icons/core/workflow/template/loopStart.svg'),
|
||||
'core/workflow/template/mathCall': () => import('./icons/core/workflow/template/mathCall.svg'),
|
||||
'core/workflow/template/pluginOutput': () =>
|
||||
import('./icons/core/workflow/template/pluginOutput.svg'),
|
||||
|
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 11" fill="none">
|
||||
<path d="M0.331787 1.04757C0.331787 0.725401 0.592954 0.464233 0.91512 0.464233H2.3005C2.62267 0.464233 2.88383 0.725401 2.88383 1.04757V1.44423C2.88383 1.7664 2.62267 2.02757 2.3005 2.02757H1.89513L1.89512 9.36302H2.3005C2.62267 9.36302 2.88383 9.62419 2.88383 9.94635V10.343C2.88383 10.6652 2.62267 10.9264 2.3005 10.9264H0.91512C0.592954 10.9264 0.331787 10.6652 0.331787 10.343V9.94635L0.331791 9.94412L0.331792 1.44656L0.331787 1.44423V1.04757Z" fill="#3370FF"/>
|
||||
<path d="M12.6676 1.04757C12.6676 0.725401 12.4065 0.464233 12.0843 0.464233H10.6989C10.3768 0.464233 10.1156 0.725401 10.1156 1.04757V1.44423C10.1156 1.7664 10.3768 2.02757 10.6989 2.02757H11.1043V9.36302H10.6989C10.3768 9.36302 10.1156 9.62419 10.1156 9.94635V10.343C10.1156 10.6652 10.3768 10.9264 10.6989 10.9264H12.0843C12.4065 10.9264 12.6676 10.6652 12.6676 10.343V9.94635L12.6676 9.94412V1.44656L12.6676 1.44423V1.04757Z" fill="#3370FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.34759 8.72133C4.60023 8.72133 4.82416 8.5587 4.90231 8.31846L5.27478 7.17351H7.72561L8.09725 8.31814C8.17531 8.55855 8.39931 8.72133 8.65207 8.72133H8.94793C9.3486 8.72133 9.63 8.32668 9.49942 7.94789L7.56163 2.32667C7.48052 2.09137 7.25904 1.93345 7.01015 1.93345H5.99239C5.74359 1.93345 5.52217 2.09125 5.44099 2.32643L3.50046 7.94765C3.36968 8.32648 3.65109 8.72133 4.05186 8.72133H4.34759ZM7.36188 6.05324L6.53607 3.50982C6.53119 3.49477 6.51717 3.48459 6.50136 3.48459C6.48555 3.48459 6.47154 3.49476 6.46665 3.5098L5.63922 6.05324H7.36188Z" fill="#3370FF"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,11 @@
|
||||
<svg viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="36" height="36" fill="url(#paint0_linear_10814_19474)"/>
|
||||
<path d="M12.9578 11.1092C12.9578 9.34187 14.3905 7.90918 16.1578 7.90918H24.9728C26.7401 7.90918 28.1728 9.34187 28.1728 11.1092V19.3092C28.1728 21.0765 26.7401 22.5092 24.9728 22.5092H24.9678V14.3092C24.9678 12.5419 23.5351 11.1092 21.7678 11.1092L12.9578 11.1092Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.82697 16.2425C7.82697 14.4752 9.25965 13.0425 11.027 13.0425H19.842C21.6093 13.0425 23.042 14.4752 23.042 16.2425V24.4425C23.042 26.2098 21.6093 27.6425 19.842 27.6425H11.027C9.25966 27.6425 7.82697 26.2098 7.82697 24.4425V16.2425ZM19.1012 19.1173C19.4917 18.7268 19.4917 18.0936 19.1012 17.7031C18.7107 17.3126 18.0775 17.3126 17.687 17.7031L14.5304 20.8597L13.1819 19.5113C12.7914 19.1208 12.1582 19.1208 11.7677 19.5113C11.3772 19.9018 11.3772 20.535 11.7677 20.9255L13.7874 22.9452C13.7987 22.9576 13.8103 22.9699 13.8224 22.9819C14.0171 23.1767 14.2722 23.2743 14.5274 23.2748C14.7846 23.2758 15.0421 23.1782 15.2384 22.9819C15.2504 22.9699 15.2621 22.9576 15.2734 22.9451L19.1012 19.1173Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_10814_19474" x1="18" y1="0" x2="5.5" y2="33" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#EB78FE"/>
|
||||
<stop offset="1" stop-color="#C071FF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,11 @@
|
||||
<svg viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="36" height="36" fill="url(#paint0_linear_10832_16007)"/>
|
||||
<path d="M13.9673 10.3122C13.1868 10.8479 13.1935 11.9491 13.863 12.6185C14.3986 13.1541 15.2613 13.1384 15.9008 12.7325C16.5477 12.3219 17.268 12.0318 18.0272 11.8808C19.2374 11.6401 20.4919 11.7636 21.6319 12.2358C22.7719 12.708 23.7463 13.5077 24.4318 14.5337C25.1174 15.5597 25.4833 16.7659 25.4833 17.9999C25.4833 19.2338 25.1174 20.4401 24.4318 21.4661C23.7463 22.4921 22.7719 23.2917 21.6319 23.7639C20.4919 24.2361 19.2374 24.3597 18.0272 24.119C17.268 23.968 16.5477 23.6779 15.9008 23.2673C15.2613 22.8614 14.3986 22.8457 13.863 23.3812C13.1935 24.0507 13.1868 25.1518 13.9673 25.6876C15.0044 26.3995 16.1799 26.8976 17.4252 27.1453C19.234 27.5051 21.1088 27.3204 22.8127 26.6147C24.5165 25.9089 25.9728 24.7138 26.9974 23.1803C28.022 21.6469 28.5689 19.8441 28.5689 17.9999C28.5689 16.1557 28.022 14.3528 26.9974 12.8194C25.9728 11.286 24.5165 10.0908 22.8127 9.38509C21.1088 8.67933 19.234 8.49468 17.4252 8.85447C16.1799 9.10217 15.0044 9.60029 13.9673 10.3122Z" fill="white"/>
|
||||
<path d="M19.2443 22.5497C17.3579 22.5497 15.7397 21.4017 15.0501 19.7663H9.19726C8.22171 19.7663 7.43087 18.9754 7.43087 17.9999C7.43087 17.0243 8.22171 16.2335 9.19726 16.2335H15.0501C15.7397 14.598 17.3579 13.45 19.2443 13.45C21.7571 13.45 23.7942 15.4871 23.7942 17.9999C23.7942 20.5127 21.7571 22.5497 19.2443 22.5497Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_10832_16007" x1="18" y1="0" x2="5.5" y2="33" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#68C0FF"/>
|
||||
<stop offset="1" stop-color="#52A2FF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,11 @@
|
||||
<svg viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="36" height="36" fill="url(#paint0_linear_10829_15860)"/>
|
||||
<path d="M22.0325 10.3122C22.813 10.8479 22.8062 11.9491 22.1368 12.6185C21.6012 13.1541 20.7384 13.1384 20.099 12.7325C19.4521 12.3219 18.7317 12.0318 17.9726 11.8808C16.7623 11.6401 15.5079 11.7636 14.3679 12.2358C13.2279 12.708 12.2535 13.5077 11.5679 14.5337C10.8824 15.5597 10.5165 16.7659 10.5165 17.9999C10.5165 19.2338 10.8824 20.4401 11.5679 21.4661C12.2535 22.4921 13.2279 23.2917 14.3679 23.7639C15.5079 24.2361 16.7624 24.3597 17.9726 24.119C18.7317 23.968 19.4521 23.6779 20.099 23.2673C20.7384 22.8614 21.6012 22.8457 22.1368 23.3812C22.8062 24.0507 22.813 25.1518 22.0325 25.6876C20.9954 26.3995 19.8199 26.8976 18.5746 27.1453C16.7658 27.5051 14.8909 27.3204 13.1871 26.6147C11.4832 25.9089 10.0269 24.7138 9.00232 23.1803C7.97772 21.6469 7.43085 19.8441 7.43085 17.9999C7.43085 16.1557 7.97772 14.3528 9.00232 12.8194C10.0269 11.286 11.4832 10.0908 13.1871 9.38509C14.8909 8.67933 16.7658 8.49468 18.5746 8.85447C19.8199 9.10217 20.9954 9.60029 22.0325 10.3122Z" fill="white"/>
|
||||
<path d="M16.7554 22.5497C18.6418 22.5497 20.2601 21.4017 20.9497 19.7663H26.8025C27.778 19.7663 28.5689 18.9754 28.5689 17.9999C28.5689 17.0243 27.778 16.2335 26.8025 16.2335H20.9497C20.2601 14.598 18.6418 13.45 16.7554 13.45C14.2426 13.45 12.2056 15.4871 12.2056 17.9999C12.2056 20.5127 14.2426 22.5497 16.7554 22.5497Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_10829_15860" x1="18" y1="0" x2="5.5" y2="33" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#68C0FF"/>
|
||||
<stop offset="1" stop-color="#52A2FF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
@@ -13,6 +13,7 @@ const MultipleRowSelect = ({
|
||||
emptyTip,
|
||||
maxH = 300,
|
||||
onSelect,
|
||||
popDirection = 'bottom',
|
||||
styles
|
||||
}: MultipleSelectProps) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -124,7 +125,13 @@ const MultipleRowSelect = ({
|
||||
{isOpen && (
|
||||
<Box
|
||||
position={'absolute'}
|
||||
top={'45px'}
|
||||
{...(popDirection === 'top'
|
||||
? {
|
||||
bottom: '45px'
|
||||
}
|
||||
: {
|
||||
top: '45px'
|
||||
})}
|
||||
py={2}
|
||||
bg={'white'}
|
||||
border={'1px solid #fff'}
|
||||
|
@@ -13,4 +13,5 @@ export type MultipleSelectProps<T = any> = {
|
||||
maxH?: number;
|
||||
onSelect: (val: any[]) => void;
|
||||
styles?: ButtonProps;
|
||||
popDirection?: 'top' | 'bottom';
|
||||
};
|
||||
|
@@ -101,7 +101,7 @@ export default function VariablePickerPlugin({
|
||||
<MyIcon name={(item.icon as any) || 'core/modules/variable'} w={'14px'} />
|
||||
<Box ml={2} fontSize={'sm'} whiteSpace={'nowrap'}>
|
||||
{item.key}
|
||||
{item.key !== item.label && `(${item.label})`}
|
||||
{item.key !== item.label && `(${t(item.label as any)})`}
|
||||
</Box>
|
||||
</Flex>
|
||||
))}
|
||||
|
@@ -552,7 +552,11 @@
|
||||
"search using reRank": "Result Re-Rank",
|
||||
"text output": "Text Output",
|
||||
"update_var_result": "Variable Update Result (Displays Multiple Variable Update Results in Order)",
|
||||
"user_select_result": "User Selection Result"
|
||||
"user_select_result": "User Selection Result",
|
||||
"loop_input": "Loop Input Array",
|
||||
"loop_output": "Loop Output Array",
|
||||
"loop_input_element": "Loop Input Element",
|
||||
"loop_output_element": "Loop Output Element"
|
||||
},
|
||||
"retry": "Regenerate",
|
||||
"tts": {
|
||||
|
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"Array_element": "Array element",
|
||||
"Code": "Code",
|
||||
"about_xxx_question": "Question regarding xxx",
|
||||
"add_new_input": "Add New Input",
|
||||
"append_application_reply_to_history_as_new_context": "Append the application's reply to the history as new context",
|
||||
"application_call": "Application Call",
|
||||
"assigned_reply": "Assigned Reply",
|
||||
"can_not_loop": "This node can't loop.",
|
||||
"choose_another_application_to_call": "Select another application to call",
|
||||
"classification_result": "Classification Result",
|
||||
"code": {
|
||||
@@ -88,6 +90,8 @@
|
||||
"length_not_equal_to": "Length Not Equal To",
|
||||
"less_than": "Less Than",
|
||||
"less_than_or_equal_to": "Less Than or Equal To",
|
||||
"loop": "Batch execution",
|
||||
"loop_start_tip": "Not input array",
|
||||
"max_dialog_rounds": "Maximum Number of Dialog Rounds",
|
||||
"max_tokens": "Maximum Tokens",
|
||||
"mouse_priority": "Mouse first",
|
||||
|
@@ -552,7 +552,11 @@
|
||||
"search using reRank": "结果重排",
|
||||
"text output": "文本输出",
|
||||
"update_var_result": "变量更新结果(按顺序展示多个变量更新结果)",
|
||||
"user_select_result": "用户选择结果"
|
||||
"user_select_result": "用户选择结果",
|
||||
"loop_input": "输入数组",
|
||||
"loop_output": "输出数组",
|
||||
"loop_input_element": "输入数组元素",
|
||||
"loop_output_element": "输出数组元素"
|
||||
},
|
||||
"retry": "重新生成",
|
||||
"tts": {
|
||||
|
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"Array_element": "数组元素",
|
||||
"Code": "代码",
|
||||
"about_xxx_question": "关于 xxx 的问题",
|
||||
"add_new_input": "新增输入",
|
||||
"append_application_reply_to_history_as_new_context": "将该应用回复内容拼接到历史记录中,作为新的上下文返回",
|
||||
"application_call": "应用调用",
|
||||
"assigned_reply": "指定回复",
|
||||
"can_not_loop": "该节点不支持循环嵌套",
|
||||
"choose_another_application_to_call": "选择一个其他应用进行调用",
|
||||
"classification_result": "分类结果",
|
||||
"code": {
|
||||
@@ -66,6 +68,7 @@
|
||||
"intro_http_request": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
|
||||
"intro_knowledge_base_search_merge": "可以将多个知识库搜索结果进行合并输出。使用 RRF 的合并方式进行最终排序输出。",
|
||||
"intro_laf_function_call": "可以调用Laf账号下的云函数。",
|
||||
"intro_loop": "可以输入一个数组,数组内元素将独立执行循环体,并将所有结果作为数组输出。",
|
||||
"intro_plugin_input": "可以配置插件需要哪些输入,利用这些输入来运行插件",
|
||||
"intro_question_classification": "根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于商品“使用”问题\n类型3: 关于商品“购买”问题\n类型4: 其他问题",
|
||||
"intro_question_optimization": "使用问题优化功能,可以提高知识库连续对话时搜索的精度。使用该功能后,会先利用 AI 根据上下文构建一个或多个新的检索词,这些检索词更利于进行知识库搜索。该模块已内置在知识库搜索模块中,如果您仅进行一次知识库搜索,可直接使用知识库内置的补全功能。",
|
||||
@@ -88,6 +91,13 @@
|
||||
"length_not_equal_to": "长度不等于",
|
||||
"less_than": "小于",
|
||||
"less_than_or_equal_to": "小于等于",
|
||||
"loop": "批量执行(测试)",
|
||||
"loop_body": "循环体",
|
||||
"loop_end": "循环体结束",
|
||||
"loop_input_array": "数组",
|
||||
"loop_result": "数组执行结果",
|
||||
"loop_start": "循环体开始",
|
||||
"loop_start_tip": "未输入数组",
|
||||
"max_dialog_rounds": "最多携带多少轮对话记录",
|
||||
"max_tokens": "最大 Tokens",
|
||||
"mouse_priority": "鼠标优先",
|
||||
|
Reference in New Issue
Block a user