diff --git a/packages/global/core/workflow/runtime/type.d.ts b/packages/global/core/workflow/runtime/type.d.ts index 1f32e34547c9..ca76cfbb5981 100644 --- a/packages/global/core/workflow/runtime/type.d.ts +++ b/packages/global/core/workflow/runtime/type.d.ts @@ -21,20 +21,11 @@ import { ReadFileNodeResponse } from '../template/system/readFiles/type'; import { UserSelectOptionType } from '../template/system/userSelect/type'; import { WorkflowResponseType } from '../../../../service/core/workflow/dispatch/type'; import { AiChatQuoteRoleType } from '../template/system/aiChat/type'; -import { - ExternalWorkflowVariableType, - LafAccountType, - OpenaiAccountType -} from '../../../support/user/team/type'; +import { LafAccountType, OpenaiAccountType } from '../../../support/user/team/type'; -export type UserExternalProviderConfigType = { - timezone: string; -}; - -export type TeamExternalProviderConfigType = { - lafAccount?: LafAccountType; +export type ExternalProviderType = { openaiAccount?: OpenaiAccountType; - externalWorkflowVariables?: ExternalWorkflowVariableType[]; + externalWorkflowVariables?: Record; }; /* workflow props */ @@ -42,8 +33,8 @@ export type ChatDispatchProps = { res?: NextApiResponse; requestOrigin?: string; mode: 'test' | 'chat' | 'debug'; - user: UserExternalProviderConfigType; - team: TeamExternalProviderConfigType; + timezone: string; + externalProvider: ExternalProviderType; runningAppInfo: { id: string; // May be the id of the system plug-in (cannot be used directly to look up the table) diff --git a/packages/global/support/user/team/controller.d.ts b/packages/global/support/user/team/controller.d.ts index 4e3eac20ebd1..c19b226c0ed1 100644 --- a/packages/global/support/user/team/controller.d.ts +++ b/packages/global/support/user/team/controller.d.ts @@ -1,11 +1,6 @@ import { PermissionValueType } from '../../permission/type'; import { TeamMemberRoleEnum } from './constant'; -import { - ExternalWorkflowVariableType, - LafAccountType, - TeamMemberSchema, - WorkflowVariableType -} from './type'; +import { LafAccountType, TeamMemberSchema } from './type'; export type AuthTeamRoleProps = { teamId: string; @@ -25,7 +20,7 @@ export type UpdateTeamProps = { teamDomain?: string; lafAccount?: LafAccountType; openaiAccount?: OpenaiAccountType; - externalWorkflowVariables?: ExternalWorkflowVariableType[]; + externalWorkflowVariable?: Record; }; /* ------------- member ----------- */ diff --git a/packages/global/support/user/team/type.d.ts b/packages/global/support/user/team/type.d.ts index c7f6450b6a6b..21972c1132b3 100644 --- a/packages/global/support/user/team/type.d.ts +++ b/packages/global/support/user/team/type.d.ts @@ -18,7 +18,7 @@ export type TeamSchema = { }; lafAccount?: LafAccountType; openaiAccount?: OpenaiAccountType; - externalWorkflowVariables?: ExternalWorkflowVariableType[]; + externalWorkflowVariables?: Record; notificationAccount?: string; }; @@ -70,7 +70,7 @@ export type TeamTmbItemType = { status: `${TeamMemberStatusEnum}`; lafAccount?: LafAccountType; openaiAccount?: OpenaiAccountType; - externalWorkflowVariables?: ExternalWorkflowVariableType[]; + externalWorkflowVariables?: Record; notificationAccount?: string; permission: TeamPermission; }; @@ -102,11 +102,6 @@ export type OpenaiAccountType = { baseUrl: string; }; -export type ExternalWorkflowVariableType = { - key: string; - value: string; -}; - export type TeamInvoiceHeaderType = { teamName: string; unifiedCreditCode: string; diff --git a/packages/service/core/workflow/dispatch/agent/classifyQuestion.ts b/packages/service/core/workflow/dispatch/agent/classifyQuestion.ts index 4eb120a0553a..a3196e02b5be 100644 --- a/packages/service/core/workflow/dispatch/agent/classifyQuestion.ts +++ b/packages/service/core/workflow/dispatch/agent/classifyQuestion.ts @@ -35,7 +35,7 @@ type ActionProps = Props & { cqModel: LLMModelItemType }; /* request openai chat */ export const dispatchClassifyQuestion = async (props: Props): Promise => { const { - team, + externalProvider, node: { nodeId, name }, histories, params: { model, history = 6, agents, userChatInput } @@ -69,7 +69,7 @@ export const dispatchClassifyQuestion = async (props: Props): Promise item.key !== result.key) .map((item) => getHandleId(nodeId, 'source', item.key)), [DispatchNodeResponseKeyEnum.nodeResponse]: { - totalPoints: team.openaiAccount?.key ? 0 : totalPoints, + totalPoints: externalProvider.openaiAccount?.key ? 0 : totalPoints, model: modelName, query: userChatInput, tokens, @@ -80,7 +80,7 @@ export const dispatchClassifyQuestion = async (props: Props): Promise { @@ -131,7 +131,7 @@ const completions = async ({ }, cqModel ), - userKey: team.openaiAccount + userKey: externalProvider.openaiAccount }); const answer = data.choices?.[0].message?.content || ''; diff --git a/packages/service/core/workflow/dispatch/agent/extract.ts b/packages/service/core/workflow/dispatch/agent/extract.ts index 1972fbd7ad7e..ca59d1b425c4 100644 --- a/packages/service/core/workflow/dispatch/agent/extract.ts +++ b/packages/service/core/workflow/dispatch/agent/extract.ts @@ -46,7 +46,7 @@ const agentFunName = 'request_function'; export async function dispatchContentExtract(props: Props): Promise { const { - team, + externalProvider, node: { name }, histories, params: { content, history = 6, model, description, extractKeys } @@ -123,7 +123,7 @@ export async function dispatchContentExtract(props: Props): Promise { [NodeOutputKeyEnum.contextExtractFields]: JSON.stringify(arg), ...arg, [DispatchNodeResponseKeyEnum.nodeResponse]: { - totalPoints: team.openaiAccount?.key ? 0 : totalPoints, + totalPoints: externalProvider.openaiAccount?.key ? 0 : totalPoints, model: modelName, query: content, tokens, @@ -134,7 +134,7 @@ export async function dispatchContentExtract(props: Props): Promise { [DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [ { moduleName: name, - totalPoints: team.openaiAccount?.key ? 0 : totalPoints, + totalPoints: externalProvider.openaiAccount?.key ? 0 : totalPoints, model: modelName, tokens } @@ -211,7 +211,7 @@ ${description ? `- ${description}` : ''} }; const toolChoice = async (props: ActionProps) => { - const { team, extractModel } = props; + const { externalProvider, extractModel } = props; const { filterMessages, agentFunction } = await getFunctionCallSchema(props); @@ -233,7 +233,7 @@ const toolChoice = async (props: ActionProps) => { }, extractModel ), - userKey: team.openaiAccount + userKey: externalProvider.openaiAccount }); const arg: Record = (() => { @@ -263,7 +263,7 @@ const toolChoice = async (props: ActionProps) => { }; const functionCall = async (props: ActionProps) => { - const { team, extractModel } = props; + const { externalProvider, extractModel } = props; const { agentFunction, filterMessages } = await getFunctionCallSchema(props); const functions: ChatCompletionCreateParams.Function[] = [agentFunction]; @@ -281,7 +281,7 @@ const functionCall = async (props: ActionProps) => { }, extractModel ), - userKey: team.openaiAccount + userKey: externalProvider.openaiAccount }); try { @@ -312,7 +312,7 @@ const functionCall = async (props: ActionProps) => { const completions = async ({ extractModel, - team, + externalProvider, histories, params: { content, extractKeys, description = 'No special requirements' } }: ActionProps) => { @@ -360,7 +360,7 @@ Human: ${content}` }, extractModel ), - userKey: team.openaiAccount + userKey: externalProvider.openaiAccount }); const answer = data.choices?.[0].message?.content || ''; diff --git a/packages/service/core/workflow/dispatch/agent/runTool/functionCall.ts b/packages/service/core/workflow/dispatch/agent/runTool/functionCall.ts index 8a51b75bf7b8..0e8ad7ae3f17 100644 --- a/packages/service/core/workflow/dispatch/agent/runTool/functionCall.ts +++ b/packages/service/core/workflow/dispatch/agent/runTool/functionCall.ts @@ -43,7 +43,7 @@ export const runToolWithFunctionCall = async ( requestOrigin, runtimeNodes, runtimeEdges, - team, + externalProvider, stream, workflowStreamResponse, params: { temperature = 0, maxToken = 4000, aiChatVision } @@ -221,7 +221,7 @@ export const runToolWithFunctionCall = async ( getEmptyResponseTip } = await createChatCompletion({ body: requestBody, - userKey: team.openaiAccount, + userKey: externalProvider.openaiAccount, options: { headers: { Accept: 'application/json, text/plain, */*' diff --git a/packages/service/core/workflow/dispatch/agent/runTool/index.ts b/packages/service/core/workflow/dispatch/agent/runTool/index.ts index 3aeb4681eeaa..0677a3b4f238 100644 --- a/packages/service/core/workflow/dispatch/agent/runTool/index.ts +++ b/packages/service/core/workflow/dispatch/agent/runTool/index.ts @@ -46,7 +46,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise< requestOrigin, chatConfig, runningAppInfo: { teamId }, - team, + externalProvider, params: { model, systemPrompt, @@ -153,7 +153,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise< })(); // censor model and system key - if (toolModel.censor && !team.openaiAccount?.key) { + if (toolModel.censor && !externalProvider.openaiAccount?.key) { await postTextCensor({ text: `${systemPrompt} ${userChatInput} @@ -228,7 +228,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise< tokens: toolNodeTokens, modelType: ModelTypeEnum.llm }); - const toolAIUsage = team.openaiAccount?.key ? 0 : totalPoints; + const toolAIUsage = externalProvider.openaiAccount?.key ? 0 : totalPoints; // flat child tool response const childToolResponse = dispatchFlowResponse.map((item) => item.flowResponses).flat(); diff --git a/packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts b/packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts index 07753903f78a..21d8bf569416 100644 --- a/packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts +++ b/packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts @@ -51,7 +51,7 @@ export const runToolWithPromptCall = async ( requestOrigin, runtimeNodes, runtimeEdges, - team, + externalProvider, stream, workflowStreamResponse, params: { temperature = 0, maxToken = 4000, aiChatVision } @@ -230,7 +230,7 @@ export const runToolWithPromptCall = async ( getEmptyResponseTip } = await createChatCompletion({ body: requestBody, - userKey: team.openaiAccount, + userKey: externalProvider.openaiAccount, options: { headers: { Accept: 'application/json, text/plain, */*' diff --git a/packages/service/core/workflow/dispatch/agent/runTool/toolChoice.ts b/packages/service/core/workflow/dispatch/agent/runTool/toolChoice.ts index 5ba1d548b340..e27bdb626e6f 100644 --- a/packages/service/core/workflow/dispatch/agent/runTool/toolChoice.ts +++ b/packages/service/core/workflow/dispatch/agent/runTool/toolChoice.ts @@ -24,11 +24,9 @@ import { AIChatItemType } from '@fastgpt/global/core/chat/type'; import { formatToolResponse, initToolCallEdges, initToolNodes } from './utils'; import { computedMaxToken, llmCompletionsBodyFormat } from '../../../../ai/utils'; import { getNanoid, sliceStrStartEnd } from '@fastgpt/global/common/string/tools'; -import { addLog } from '../../../../../common/system/log'; import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants'; import { WorkflowInteractiveResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type'; import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants'; -import { i18nT } from '../../../../../../web/i18n/utils'; type ToolRunResponseType = { toolRunResponse: DispatchFlowResponse; @@ -92,7 +90,7 @@ export const runToolWithToolChoice = async ( runtimeNodes, runtimeEdges, stream, - team, + externalProvider, workflowStreamResponse, params: { temperature = 0, maxToken = 4000, aiChatVision } } = workflowProps; @@ -278,7 +276,7 @@ export const runToolWithToolChoice = async ( getEmptyResponseTip } = await createChatCompletion({ body: requestBody, - userKey: team.openaiAccount, + userKey: externalProvider.openaiAccount, options: { headers: { Accept: 'application/json, text/plain, */*' diff --git a/packages/service/core/workflow/dispatch/chat/oneapi.ts b/packages/service/core/workflow/dispatch/chat/oneapi.ts index e57b8e09c355..4132101a76c2 100644 --- a/packages/service/core/workflow/dispatch/chat/oneapi.ts +++ b/packages/service/core/workflow/dispatch/chat/oneapi.ts @@ -62,7 +62,7 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise { // censor model and system key - if (modelConstantsData.censor && !team.openaiAccount?.key) { + if (modelConstantsData.censor && !externalProvider.openaiAccount?.key) { return postTextCensor({ text: `${systemPrompt} ${userChatInput} @@ -170,7 +170,7 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise - >((acc: Record, item: { key: string; value: string }) => { - if (!item?.key || !item?.value) return acc; - - const key = item.key.replace(/^\{\{(.*)\}\}$/, '$1'); - acc[key] = String(item.value); + const externalWorkflowVariables = Object.entries( + externalProvider.externalWorkflowVariables || {} + ).reduce>((acc, [key, value]) => { + if (!key || !value) return acc; + const cleanKey = key.replace(/^\{\{(.*)\}\}$/, '$1'); + acc[cleanKey] = String(value); return acc; }, {}); @@ -505,7 +504,7 @@ export async function dispatchWorkFlow(data: Props): Promise => { params, runtimeEdges, runtimeNodes, - team, + externalProvider, node: { name } } = props; const { loopInputArray = [], childrenNodeIdList = [] } = params; @@ -93,7 +93,7 @@ export const dispatchLoop = async (props: Props): Promise => { }, [DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [ { - totalPoints: team.openaiAccount?.key ? 0 : totalPoints, + totalPoints: externalProvider.openaiAccount?.key ? 0 : totalPoints, moduleName: name } ], diff --git a/packages/service/core/workflow/dispatch/tools/runUpdateVar.ts b/packages/service/core/workflow/dispatch/tools/runUpdateVar.ts index 9c70c754278b..e16df10cb843 100644 --- a/packages/service/core/workflow/dispatch/tools/runUpdateVar.ts +++ b/packages/service/core/workflow/dispatch/tools/runUpdateVar.ts @@ -19,7 +19,7 @@ type Props = ModuleDispatchProps<{ type Response = DispatchNodeResultType<{}>; export const dispatchUpdateVariable = async (props: Props): Promise => { - const { params, variables, runtimeNodes, workflowStreamResponse, team } = props; + const { params, variables, runtimeNodes, workflowStreamResponse, externalProvider } = props; const { updateList } = params; const nodeIds = runtimeNodes.map((node) => node.nodeId); @@ -80,7 +80,7 @@ export const dispatchUpdateVariable = async (props: Props): Promise => workflowStreamResponse?.({ event: SseResponseEventEnum.updateVariables, - data: removeSystemVariable(variables, team.externalWorkflowVariables) + data: removeSystemVariable(variables, externalProvider.externalWorkflowVariables) }); return { diff --git a/packages/service/core/workflow/dispatch/utils.ts b/packages/service/core/workflow/dispatch/utils.ts index 985f5607727b..b0874833b198 100644 --- a/packages/service/core/workflow/dispatch/utils.ts +++ b/packages/service/core/workflow/dispatch/utils.ts @@ -14,8 +14,6 @@ import { NextApiResponse } from 'next'; import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/constants'; import { getNanoid } from '@fastgpt/global/common/string/tools'; import { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type'; -import { ExternalProviderWorkflowVarType } from '@fastgpt/global/common/system/types'; -import { ExternalWorkflowVariableType } from '@fastgpt/global/support/user/team/type'; export const getWorkflowResponseWrite = ({ res, @@ -145,7 +143,7 @@ export const checkQuoteQAValue = (quoteQA?: SearchDataResponseItemType[]) => { /* remove system variable */ export const removeSystemVariable = ( variables: Record, - externalProviderWorkflowVariables?: ExternalWorkflowVariableType[] + externalProviderWorkflowVariables?: Record ) => { const copyVariables = { ...variables }; delete copyVariables.userId; @@ -157,8 +155,7 @@ export const removeSystemVariable = ( // delete external provider workflow variables if (externalProviderWorkflowVariables) { - externalProviderWorkflowVariables.forEach((item) => { - const key = item.key.replace(/^\{\{(.*)\}\}$/, '$1'); + Object.keys(externalProviderWorkflowVariables).forEach((key) => { delete copyVariables[key]; }); } diff --git a/packages/service/support/permission/auth/team.ts b/packages/service/support/permission/auth/team.ts index d29e1de5646d..3f134b24d686 100644 --- a/packages/service/support/permission/auth/team.ts +++ b/packages/service/support/permission/auth/team.ts @@ -1,14 +1,13 @@ -import { - TeamExternalProviderConfigType, - UserExternalProviderConfigType -} from '@fastgpt/global/core/workflow/runtime/type'; +import { ExternalProviderType } from '@fastgpt/global/core/workflow/runtime/type'; import { MongoTeamMember } from '../../user/team/teamMemberSchema'; import { checkTeamAIPoints } from '../teamLimit'; import { UserErrEnum } from '@fastgpt/global/common/error/code/user'; type tmbType = { - teamId: TeamExternalProviderConfigType & { _id: string }; - userId: UserExternalProviderConfigType; + teamId: ExternalProviderType & { _id: string }; + userId: { + timezone: string; + }; }; export async function getUserChatInfoAndAuthTeamPoints(tmbId: string) { @@ -21,7 +20,7 @@ export async function getUserChatInfoAndAuthTeamPoints(tmbId: string) { await checkTeamAIPoints(tmb.teamId._id); return { - user: tmb.userId, - team: tmb.teamId + timezone: tmb.userId.timezone, + externalProvider: tmb.teamId }; } diff --git a/packages/service/support/user/team/controller.ts b/packages/service/support/user/team/controller.ts index 4f4e234c7242..af02812650d7 100644 --- a/packages/service/support/user/team/controller.ts +++ b/packages/service/support/user/team/controller.ts @@ -150,7 +150,7 @@ export async function updateTeam({ teamDomain, lafAccount, openaiAccount, - externalWorkflowVariables + externalWorkflowVariable }: UpdateTeamProps & { teamId: string }) { // auth key if (openaiAccount?.key) { @@ -180,8 +180,12 @@ export async function updateTeam({ if (teamDomain !== undefined) updateObj.teamDomain = teamDomain; if (lafAccount !== undefined) updateObj.lafAccount = lafAccount; if (openaiAccount !== undefined) updateObj.openaiAccount = openaiAccount; - if (externalWorkflowVariables !== undefined) - updateObj.externalWorkflowVariables = externalWorkflowVariables; + if (externalWorkflowVariable !== undefined) { + updateObj.$set = { + [`externalWorkflowVariables.${externalWorkflowVariable.key}`]: + externalWorkflowVariable.value + }; + } await MongoTeam.findByIdAndUpdate(teamId, updateObj, { session }); diff --git a/packages/service/support/user/team/teamSchema.ts b/packages/service/support/user/team/teamSchema.ts index 3b7863cee3e3..a418d0c342ce 100644 --- a/packages/service/support/user/team/teamSchema.ts +++ b/packages/service/support/user/team/teamSchema.ts @@ -54,13 +54,8 @@ const TeamSchema = new Schema({ } }, externalWorkflowVariables: { - type: [ - { - key: String, - value: String - } - ], - default: [] + type: Object, + default: {} }, notificationAccount: { type: String, diff --git a/packages/web/components/common/Textarea/PromptEditor/Editor.tsx b/packages/web/components/common/Textarea/PromptEditor/Editor.tsx index b639b13e97cb..a76cc136e006 100644 --- a/packages/web/components/common/Textarea/PromptEditor/Editor.tsx +++ b/packages/web/components/common/Textarea/PromptEditor/Editor.tsx @@ -21,11 +21,7 @@ import { VariableNode } from './plugins/VariablePlugin/node'; import { EditorState, LexicalEditor } from 'lexical'; import OnBlurPlugin from './plugins/OnBlurPlugin'; import MyIcon from '../../Icon'; -import { - EditorVariableLabelPickerType, - EditorVariablePickerType, - EditorWorkflowVariableType -} from './type.d'; +import { EditorVariableLabelPickerType, EditorVariablePickerType } from './type.d'; import { getNanoid } from '@fastgpt/global/common/string/tools'; import FocusPlugin from './plugins/FocusPlugin'; import { textToEditorState } from './utils'; @@ -34,8 +30,6 @@ import { VariableLabelNode } from './plugins/VariableLabelPlugin/node'; import VariableLabelPlugin from './plugins/VariableLabelPlugin'; import { useDeepCompareEffect } from 'ahooks'; import VariablePickerPlugin from './plugins/VariablePickerPlugin'; -import WorkflowVariablePlugin from './plugins/WorkflowVariablePlugin'; -import { WorkflowVariableNode } from './plugins/WorkflowVariablePlugin/node'; export default function Editor({ minH = 200, @@ -45,7 +39,6 @@ export default function Editor({ onOpenModal, variables, variableLabels, - externalProviderWorkflowVariables, onChange, onBlur, value, @@ -59,7 +52,6 @@ export default function Editor({ onOpenModal?: () => void; variables: EditorVariablePickerType[]; variableLabels: EditorVariableLabelPickerType[]; - externalProviderWorkflowVariables: EditorWorkflowVariableType[]; onChange?: (editorState: EditorState, editor: LexicalEditor) => void; onBlur?: (editor: LexicalEditor) => void; value?: string; @@ -73,7 +65,7 @@ export default function Editor({ const initialConfig = { namespace: 'promptEditor', - nodes: [VariableNode, VariableLabelNode, WorkflowVariableNode], + nodes: [VariableNode, VariableLabelNode], editorState: textToEditorState(value), onError: (error: Error) => { throw error; @@ -146,7 +138,6 @@ export default function Editor({ /> - 0 ? [] : variables} /> diff --git a/packages/web/components/common/Textarea/PromptEditor/index.tsx b/packages/web/components/common/Textarea/PromptEditor/index.tsx index 10e06b375f81..cf8d0cb2f002 100644 --- a/packages/web/components/common/Textarea/PromptEditor/index.tsx +++ b/packages/web/components/common/Textarea/PromptEditor/index.tsx @@ -5,18 +5,13 @@ import Editor from './Editor'; import MyModal from '../../MyModal'; import { useTranslation } from 'next-i18next'; import { EditorState, type LexicalEditor } from 'lexical'; -import { - EditorVariableLabelPickerType, - EditorVariablePickerType, - EditorWorkflowVariableType -} from './type.d'; +import { EditorVariableLabelPickerType, EditorVariablePickerType } from './type.d'; import { useCallback } from 'react'; const PromptEditor = ({ showOpenModal = true, variables = [], variableLabels = [], - externalProviderWorkflowVariables = [], value, onChange, onBlur, @@ -30,7 +25,6 @@ const PromptEditor = ({ showOpenModal?: boolean; variables?: EditorVariablePickerType[]; variableLabels?: EditorVariableLabelPickerType[]; - externalProviderWorkflowVariables?: EditorWorkflowVariableType[]; value?: string; onChange?: (text: string) => void; onBlur?: (text: string) => void; @@ -66,7 +60,6 @@ const PromptEditor = ({ onOpenModal={onOpen} variables={variables} variableLabels={variableLabels} - externalProviderWorkflowVariables={externalProviderWorkflowVariables} minH={minH} maxH={maxH} maxLength={maxLength} @@ -85,7 +78,6 @@ const PromptEditor = ({ showOpenModal={false} variables={variables} variableLabels={variableLabels} - externalProviderWorkflowVariables={externalProviderWorkflowVariables} value={value} onChange={onChangeInput} onBlur={onBlurInput} diff --git a/packages/web/components/common/Textarea/PromptEditor/plugins/WorkflowVariablePlugin/components/WorkflowVariable.tsx b/packages/web/components/common/Textarea/PromptEditor/plugins/VariablePlugin/components/Variable.tsx similarity index 88% rename from packages/web/components/common/Textarea/PromptEditor/plugins/WorkflowVariablePlugin/components/WorkflowVariable.tsx rename to packages/web/components/common/Textarea/PromptEditor/plugins/VariablePlugin/components/Variable.tsx index 4f4b0654259c..1f0039d07707 100644 --- a/packages/web/components/common/Textarea/PromptEditor/plugins/WorkflowVariablePlugin/components/WorkflowVariable.tsx +++ b/packages/web/components/common/Textarea/PromptEditor/plugins/VariablePlugin/components/Variable.tsx @@ -1,7 +1,7 @@ import { Box, Flex } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; -export default function WorkflowVariable({ variableLabel }: { variableLabel: string }) { +export default function Variable({ variableLabel }: { variableLabel: string }) { const { t } = useTranslation(); return ( diff --git a/packages/web/components/common/Textarea/PromptEditor/plugins/VariablePlugin/index.tsx b/packages/web/components/common/Textarea/PromptEditor/plugins/VariablePlugin/index.tsx index bab875b0a227..7d6911ede56c 100644 --- a/packages/web/components/common/Textarea/PromptEditor/plugins/VariablePlugin/index.tsx +++ b/packages/web/components/common/Textarea/PromptEditor/plugins/VariablePlugin/index.tsx @@ -5,8 +5,8 @@ import { useCallback, useEffect, useMemo } from 'react'; import { getHashtagRegexString } from './utils'; import { registerLexicalTextEntity } from '../../utils'; -import { $createVariableNode, VariableNode } from './node'; import { EditorVariablePickerType } from '../../type'; +import { $createVariableNode, VariableNode } from './node'; const REGEX = new RegExp(getHashtagRegexString(), 'i'); @@ -22,7 +22,11 @@ export default function VariablePlugin({ variables }: { variables: EditorVariabl }, [variables]); const createVariableNode = useCallback((textNode: TextNode): VariableNode => { - return $createVariableNode(textNode.getTextContent()); + const currentVariable = variables.find( + (item) => item.key === textNode.getTextContent().replace(/[{}]/g, '') + ); + const variableLabel = currentVariable?.label; + return $createVariableNode(textNode.getTextContent(), variableLabel || ''); }, []); const getVariableMatch = useCallback((text: string) => { diff --git a/packages/web/components/common/Textarea/PromptEditor/plugins/VariablePlugin/node.ts b/packages/web/components/common/Textarea/PromptEditor/plugins/VariablePlugin/node.ts deleted file mode 100644 index 536f25b9043e..000000000000 --- a/packages/web/components/common/Textarea/PromptEditor/plugins/VariablePlugin/node.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { NodeKey, EditorConfig, LexicalNode, SerializedTextNode } from 'lexical'; - -import { TextNode, $applyNodeReplacement } from 'lexical'; -import { addClassNamesToElement } from '@lexical/utils'; -import styles from '../../index.module.scss'; - -export class VariableNode extends TextNode { - static getType(): string { - return 'variable'; - } - - static clone(node: VariableNode): VariableNode { - return new VariableNode(node.__text, node.__key); - } - - constructor(text: string, key?: NodeKey) { - super(text, key); - } - - createDOM(config: EditorConfig): HTMLElement { - const element = super.createDOM(config); - addClassNamesToElement(element, styles.variable); - return element; - } - - static importJSON(serializedNode: SerializedTextNode): TextNode { - const node = $createVariableNode(serializedNode.text); - node.setFormat(serializedNode.format); - node.setDetail(serializedNode.detail); - node.setMode(serializedNode.mode); - node.setStyle(serializedNode.style); - return node; - } - - exportJSON(): SerializedTextNode { - return { - ...super.exportJSON(), - type: 'variable' - }; - } -} - -export function $createVariableNode(text: string): VariableNode { - return $applyNodeReplacement(new VariableNode(text)); -} - -export function $isVariableNode(node: LexicalNode | null | undefined): node is VariableNode { - return node instanceof VariableNode; -} diff --git a/packages/web/components/common/Textarea/PromptEditor/plugins/WorkflowVariablePlugin/node.tsx b/packages/web/components/common/Textarea/PromptEditor/plugins/VariablePlugin/node.tsx similarity index 60% rename from packages/web/components/common/Textarea/PromptEditor/plugins/WorkflowVariablePlugin/node.tsx rename to packages/web/components/common/Textarea/PromptEditor/plugins/VariablePlugin/node.tsx index 24f610396e93..49bcfee8d764 100644 --- a/packages/web/components/common/Textarea/PromptEditor/plugins/WorkflowVariablePlugin/node.tsx +++ b/packages/web/components/common/Textarea/PromptEditor/plugins/VariablePlugin/node.tsx @@ -10,9 +10,9 @@ import { Spread, TextFormatType } from 'lexical'; -import WorkflowVariable from './components/WorkflowVariable'; +import Variable from './components/Variable'; -export type SerializedWorkflowVariableNode = Spread< +export type SerializedVariableNode = Spread< { variableKey: string; variableLabel: string; @@ -21,20 +21,15 @@ export type SerializedWorkflowVariableNode = Spread< SerializedLexicalNode >; -export class WorkflowVariableNode extends DecoratorNode { +export class VariableNode extends DecoratorNode { __format: number | TextFormatType; __variableKey: string; __variableLabel: string; static getType(): string { - return 'workflowVariable'; + return 'Variable'; } - static clone(node: WorkflowVariableNode): WorkflowVariableNode { - return new WorkflowVariableNode( - node.__variableKey, - node.__variableLabel, - node.__format, - node.__key - ); + static clone(node: VariableNode): VariableNode { + return new VariableNode(node.__variableKey, node.__variableLabel, node.__format, node.__key); } constructor( variableKey: string, @@ -48,11 +43,8 @@ export class WorkflowVariableNode extends DecoratorNode { this.__variableLabel = variableLabel; } - static importJSON(serializedNode: SerializedWorkflowVariableNode): WorkflowVariableNode { - const node = $createWorkflowVariableNode( - serializedNode.variableKey, - serializedNode.variableLabel - ); + static importJSON(serializedNode: SerializedVariableNode): VariableNode { + const node = $createVariableNode(serializedNode.variableKey, serializedNode.variableLabel); node.setFormat(serializedNode.format); return node; } @@ -65,10 +57,10 @@ export class WorkflowVariableNode extends DecoratorNode { return this.__format; } - exportJSON(): SerializedWorkflowVariableNode { + exportJSON(): SerializedVariableNode { return { format: this.__format || 0, - type: 'workflowVariable', + type: 'Variable', version: 1, variableKey: this.getVariableKey(), variableLabel: this.__variableLabel @@ -98,19 +90,16 @@ export class WorkflowVariableNode extends DecoratorNode { return `${this.__variableKey}`; } decorate(_editor: LexicalEditor, config: EditorConfig): JSX.Element { - return ; + return ; } } -export function $createWorkflowVariableNode( - variableKey: string, - variableLabel: string -): WorkflowVariableNode { - return new WorkflowVariableNode(variableKey, variableLabel); +export function $createVariableNode(variableKey: string, variableLabel: string): VariableNode { + return new VariableNode(variableKey, variableLabel); } -export function $isWorkflowVariableNode( - node: WorkflowVariableNode | LexicalNode | null | undefined -): node is WorkflowVariableNode { - return node instanceof WorkflowVariableNode; +export function $isVariableNode( + node: VariableNode | LexicalNode | null | undefined +): node is VariableNode { + return node instanceof VariableNode; } diff --git a/packages/web/components/common/Textarea/PromptEditor/plugins/WorkflowVariablePlugin/index.tsx b/packages/web/components/common/Textarea/PromptEditor/plugins/WorkflowVariablePlugin/index.tsx deleted file mode 100644 index b6d43f84a5ff..000000000000 --- a/packages/web/components/common/Textarea/PromptEditor/plugins/WorkflowVariablePlugin/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; -import { EditorWorkflowVariableType } from '../../type'; -import { useCallback, useEffect } from 'react'; -import { $createWorkflowVariableNode, WorkflowVariableNode } from './node'; -import { TextNode } from 'lexical'; -import { mergeRegister } from '@lexical/utils'; -import { registerLexicalTextEntity } from '../../utils'; -import { getHashtagRegexString } from './utils'; - -const REGEX = new RegExp(getHashtagRegexString(), 'i'); - -export default function WorkflowVariablePlugin({ - variables -}: { - variables: EditorWorkflowVariableType[]; -}) { - const [editor] = useLexicalComposerContext(); - useEffect(() => { - if (!editor.hasNodes([WorkflowVariableNode])) - throw new Error('WorkflowVariablePlugin: WorkflowVariablePlugin not registered on editor'); - }, [editor]); - - const createWorkflowVariablePlugin = useCallback((textNode: TextNode): WorkflowVariableNode => { - const currentVariable = variables.find((item) => item.key === textNode.getTextContent()); - const variableLabel = currentVariable?.name; - return $createWorkflowVariableNode(textNode.getTextContent(), variableLabel || ''); - }, []); - - const getVariableMatch = useCallback((text: string) => { - const matches = REGEX.exec(text); - if (!matches) return null; - const hashtagLength = matches[0].length; - const startOffset = matches.index; - const endOffset = startOffset + hashtagLength; - return { - end: endOffset, - start: startOffset - }; - }, []); - - useEffect(() => { - mergeRegister( - ...registerLexicalTextEntity( - editor, - getVariableMatch, - WorkflowVariableNode, - createWorkflowVariablePlugin - ) - ); - }, [createWorkflowVariablePlugin, editor, getVariableMatch]); - - return null; -} diff --git a/packages/web/components/common/Textarea/PromptEditor/plugins/WorkflowVariablePlugin/utils.ts b/packages/web/components/common/Textarea/PromptEditor/plugins/WorkflowVariablePlugin/utils.ts deleted file mode 100644 index be71818347a1..000000000000 --- a/packages/web/components/common/Textarea/PromptEditor/plugins/WorkflowVariablePlugin/utils.ts +++ /dev/null @@ -1,30 +0,0 @@ -function getHashtagRegexVariableLabels(): Readonly<{ - leftBrace: string; - prefix: string; - rightBrace: string; -}> { - const leftBrace = '[\\{]'; - const prefix = 'system\\.'; - const rightBrace = '[\\}]'; - - return { - leftBrace, - prefix, - rightBrace - }; -} - -export function getHashtagRegexString(): string { - const { leftBrace, prefix, rightBrace } = getHashtagRegexVariableLabels(); - - // 构建递归匹配的正则表达式 - const hashtag = - `(${leftBrace})` + // 第一个左花括号 - `(${leftBrace})` + // 第二个左花括号 - `${prefix}` + // system. - `([a-zA-Z0-9_]{6})` + // 变量名 - `(${rightBrace})` + // 第一个右花括号 - `(${rightBrace})`; // 第二个右花括号 - - return hashtag; -} diff --git a/packages/web/components/common/Textarea/PromptEditor/type.d.ts b/packages/web/components/common/Textarea/PromptEditor/type.d.ts index a2aceb356f5c..939c4d45e801 100644 --- a/packages/web/components/common/Textarea/PromptEditor/type.d.ts +++ b/packages/web/components/common/Textarea/PromptEditor/type.d.ts @@ -21,8 +21,3 @@ export type EditorVariableLabelPickerType = { avatar?: string; }; }; - -export type EditorWorkflowVariableType = { - key: string; - name: string; -}; diff --git a/packages/web/components/common/Textarea/PromptEditor/utils.ts b/packages/web/components/common/Textarea/PromptEditor/utils.ts index 06419c914f61..15ff217f0aee 100644 --- a/packages/web/components/common/Textarea/PromptEditor/utils.ts +++ b/packages/web/components/common/Textarea/PromptEditor/utils.ts @@ -11,11 +11,9 @@ import type { EntityMatch } from '@lexical/text'; import { $createTextNode, $getRoot, $isTextNode, TextNode } from 'lexical'; import { useCallback } from 'react'; import { VariableLabelNode } from './plugins/VariableLabelPlugin/node'; -import { WorkflowVariableNode } from './plugins/WorkflowVariablePlugin/node'; +import { VariableNode } from './plugins/VariablePlugin/node'; -export function registerLexicalTextEntity< - T extends TextNode | VariableLabelNode | WorkflowVariableNode ->( +export function registerLexicalTextEntity( editor: LexicalEditor, getMatch: (text: string) => null | EntityMatch, targetNode: Klass, @@ -25,9 +23,7 @@ export function registerLexicalTextEntity< return node instanceof targetNode; }; - const replaceWithSimpleText = ( - node: TextNode | VariableLabelNode | WorkflowVariableNode - ): void => { + const replaceWithSimpleText = (node: TextNode | VariableLabelNode | VariableNode): void => { const textNode = $createTextNode(node.getTextContent()); textNode.setFormat(node.getFormat()); node.replace(textNode); @@ -233,7 +229,7 @@ export function editorStateToText(editor: LexicalEditor) { paragraphText.push(child.text); } else if (child.type === 'variableLabel') { paragraphText.push(child.variableKey); - } else if (child.type === 'workflowVariable') { + } else if (child.type === 'Variable') { paragraphText.push(child.variableKey); } }); diff --git a/projects/app/src/pages/account/thirdParty/components/WorkflowVariableModal.tsx b/projects/app/src/pages/account/thirdParty/components/WorkflowVariableModal.tsx index a64d8e9d93e4..4ff45fdfce35 100644 --- a/projects/app/src/pages/account/thirdParty/components/WorkflowVariableModal.tsx +++ b/projects/app/src/pages/account/thirdParty/components/WorkflowVariableModal.tsx @@ -7,7 +7,6 @@ import { useForm } from 'react-hook-form'; import { useUserStore } from '@/web/support/user/useUserStore'; import { putUpdateTeam } from '@/web/support/user/team/api'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; -import { ExternalWorkflowVariableType } from '@fastgpt/global/support/user/team/type'; const WorkflowVariableModal = ({ defaultData, @@ -19,8 +18,6 @@ const WorkflowVariableModal = ({ const { t } = useTranslation(); const { userInfo, initUserInfo } = useUserStore(); - const externalWorkflowVariables = userInfo?.team.externalWorkflowVariables || []; - const { register, handleSubmit } = useForm({ defaultValues: { value: defaultData.value || '', @@ -29,18 +26,11 @@ const WorkflowVariableModal = ({ }); const { runAsync: onSubmit, loading } = useRequest2( - async (data: ExternalWorkflowVariableType) => { - console.log('data', data); + async (data: { key: string; value: string }) => { if (!userInfo?.team.teamId) return; - if (externalWorkflowVariables.find((item) => item.key === data.key)) { - return putUpdateTeam({ - externalWorkflowVariables: externalWorkflowVariables.map((item) => - item.key === data.key ? data : item - ) - }); - } - return putUpdateTeam({ - externalWorkflowVariables: [...externalWorkflowVariables, data] + + await putUpdateTeam({ + externalWorkflowVariable: data }); }, { diff --git a/projects/app/src/pages/account/thirdParty/index.tsx b/projects/app/src/pages/account/thirdParty/index.tsx index fc1dbdac436b..55b6d04021ba 100644 --- a/projects/app/src/pages/account/thirdParty/index.tsx +++ b/projects/app/src/pages/account/thirdParty/index.tsx @@ -1,4 +1,3 @@ -import { serviceSideProps } from '@/web/common/utils/i18n'; import AccountContainer from '../components/AccountContainer'; import { Box, Flex, Grid, Progress, useDisclosure } from '@chakra-ui/react'; import MyIcon from '@fastgpt/web/components/common/Icon'; @@ -11,6 +10,7 @@ import { useState, useEffect, useCallback } from 'react'; import WorkflowVariableModal from './components/WorkflowVariableModal'; import axios from 'axios'; import { useToast } from '@fastgpt/web/hooks/useToast'; +import { serviceSideProps } from '@fastgpt/web/common/system/nextjs'; const LafAccountModal = dynamic(() => import('@/components/support/laf/LafAccountModal')); const OpenAIAccountModal = dynamic(() => import('./components/OpenAIAccountModal')); @@ -62,16 +62,16 @@ const ThirdParty = () => { const getWorkflowVariables = useCallback(async (): Promise => { return Promise.all( (feConfigs?.externalProviderWorkflowVariables || []).map(async (item) => { - const workflowVariable = userInfo?.team.externalWorkflowVariables?.find( - (variable) => variable.key === item.key - ); + const teamExternalWorkflowVariables = userInfo?.team.externalWorkflowVariables || {}; + + const workflowVariable = teamExternalWorkflowVariables[item.key]; const usage = await (async () => { - if (!workflowVariable?.value || !item.url) return [0, -1]; + if (!workflowVariable || !item.url) return [0, -1]; try { const response = await axios.get(item.url, { headers: { - Authorization: workflowVariable.value + Authorization: workflowVariable } }); return response.data.usage; @@ -84,7 +84,7 @@ const ThirdParty = () => { const account = { key: item.key, name: item.name, - value: workflowVariable?.value, + value: workflowVariable, icon: 'common/variable', iconColor: 'primary.600', intro: item.intro || t('account_thirdParty:no_intro') diff --git a/projects/app/src/pages/api/core/chat/chatTest.ts b/projects/app/src/pages/api/core/chat/chatTest.ts index de619a78a447..3c0d64ddd5ef 100644 --- a/projects/app/src/pages/api/core/chat/chatTest.ts +++ b/projects/app/src/pages/api/core/chat/chatTest.ts @@ -115,7 +115,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { })(); const limit = getMaxHistoryLimitFromNodes(nodes); - const [{ histories }, chatDetail, { user, team }] = await Promise.all([ + const [{ histories }, chatDetail, { timezone, externalProvider }] = await Promise.all([ getChatItems({ appId, chatId, @@ -158,8 +158,8 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { res, requestOrigin: req.headers.origin, mode: 'test', - user, - team, + timezone, + externalProvider, uid: tmbId, runningAppInfo: { @@ -205,7 +205,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { const { text: userInteractiveVal } = chatValue2RuntimePrompt(userQuestion.value); const newTitle = isPlugin - ? variables.cTime ?? getSystemTime(user.timezone) + ? variables.cTime ?? getSystemTime(timezone) : getChatTitleFromChatMessage(userQuestion); const aiResponse: AIChatItemType & { dataId?: string } = { diff --git a/projects/app/src/pages/api/v1/chat/completions.ts b/projects/app/src/pages/api/v1/chat/completions.ts index 1bdd371aa307..23c245df36cf 100644 --- a/projects/app/src/pages/api/v1/chat/completions.ts +++ b/projects/app/src/pages/api/v1/chat/completions.ts @@ -59,11 +59,7 @@ import { rewriteNodeOutputByHistories } from '@fastgpt/global/core/workflow/runt import { getWorkflowResponseWrite } from '@fastgpt/service/core/workflow/dispatch/utils'; import { WORKFLOW_MAX_RUN_TIMES } from '@fastgpt/service/core/workflow/constants'; import { getPluginInputsFromStoreNodes } from '@fastgpt/global/core/app/plugin/utils'; -import { TeamSchema } from '@fastgpt/global/support/user/team/type'; -import { - TeamExternalProviderConfigType, - UserExternalProviderConfigType -} from '@fastgpt/global/core/workflow/runtime/type'; +import { ExternalProviderType } from '@fastgpt/global/core/workflow/runtime/type'; type FastGptWebChatProps = { chatId?: string; // undefined: get histories from messages, '': new chat, 'xxxxx': get histories from db @@ -85,8 +81,8 @@ export type Props = ChatCompletionCreateParams & type AuthResponseType = { teamId: string; tmbId: string; - user: UserExternalProviderConfigType; - team: TeamExternalProviderConfigType; + timezone: string; + externalProvider: ExternalProviderType; app: AppSchema; responseDetail?: boolean; showNodeStatus?: boolean; @@ -160,8 +156,8 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { const { teamId, tmbId, - user, - team, + timezone, + externalProvider, app, responseDetail, authType, @@ -276,8 +272,8 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { res, requestOrigin: req.headers.origin, mode: 'chat', - user, - team, + timezone, + externalProvider, runningAppInfo: { id: String(app._id), @@ -322,7 +318,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { const { text: userInteractiveVal } = chatValue2RuntimePrompt(userQuestion.value); const newTitle = isPlugin - ? variables.cTime ?? getSystemTime(user.timezone) + ? variables.cTime ?? getSystemTime(timezone) : getChatTitleFromChatMessage(userQuestion); const aiResponse: AIChatItemType & { dataId?: string } = { @@ -470,8 +466,8 @@ const authShareChat = async ({ const { teamId, tmbId, - user, - team, + timezone, + externalProvider, appId, authType, responseDetail, @@ -495,9 +491,9 @@ const authShareChat = async ({ sourceName, teamId, tmbId, - user, app, - team, + timezone, + externalProvider, apikey: '', authType, responseAllData: false, @@ -527,7 +523,7 @@ const authTeamSpaceChat = async ({ return Promise.reject('app is empty'); } - const [chat, { user, team }] = await Promise.all([ + const [chat, { timezone, externalProvider }] = await Promise.all([ MongoChat.findOne({ appId, chatId }).lean(), getUserChatInfoAndAuthTeamPoints(app.tmbId) ]); @@ -539,9 +535,9 @@ const authTeamSpaceChat = async ({ return { teamId, tmbId: app.tmbId, - user, - team, app, + timezone, + externalProvider, authType: AuthUserTypeEnum.outLink, apikey: '', responseAllData: false, @@ -608,7 +604,7 @@ const authHeaderRequest = async ({ } })(); - const [{ user, team }, chat] = await Promise.all([ + const [{ timezone, externalProvider }, chat] = await Promise.all([ getUserChatInfoAndAuthTeamPoints(tmbId), MongoChat.findOne({ appId, chatId }).lean() ]); @@ -625,8 +621,8 @@ const authHeaderRequest = async ({ return { teamId, tmbId, - user, - team, + timezone, + externalProvider, app, apikey, authType, diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/Textarea.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/Textarea.tsx index b363a6a78f6d..ed2d3fa11e8d 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/Textarea.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/RenderInput/templates/Textarea.tsx @@ -32,10 +32,12 @@ const TextareaRender = ({ inputs = [], item, nodeId }: RenderInputProps) => { }, [nodeId, nodeList, edges, appDetail, t]); const externalProviderWorkflowVariables = useMemo(() => { - return feConfigs?.externalProviderWorkflowVariables?.map((item) => ({ - key: item.key, - name: item.name - })); + return ( + feConfigs?.externalProviderWorkflowVariables?.map((item) => ({ + key: item.key.replace(/[{}]/g, ''), + label: item.name + })) || [] + ); }, [feConfigs?.externalProviderWorkflowVariables]); const onChange = useCallback( @@ -57,8 +59,7 @@ const TextareaRender = ({ inputs = [], item, nodeId }: RenderInputProps) => { return (