From a6350daa0297df5eb3ff7bc9be191d7a50bc6fb2 Mon Sep 17 00:00:00 2001 From: Joel Date: Mon, 22 Jul 2024 11:44:12 +0800 Subject: [PATCH] chore: improve prompt auto generator (#6514) --- .../app/configuration/config-prompt/index.tsx | 9 + .../config-prompt/simple-prompt-input.tsx | 63 +++-- .../config/automatic/automatic-btn.tsx | 14 +- .../config/automatic/get-automatic-res.tsx | 262 +++++++++++------- .../config/automatic/style.module.css | 7 + .../icons/assets/vender/other/generator.svg | 4 + .../icons/src/vender/other/Generator.json | 37 +++ .../base/icons/src/vender/other/Generator.tsx | 16 ++ .../base/icons/src/vender/other/index.ts | 1 + .../solid/general/QuestionTriangle.json | 2 +- .../nodes/_base/components/prompt/editor.tsx | 9 + .../llm/components/config-prompt-item.tsx | 14 +- .../nodes/llm/components/config-prompt.tsx | 14 +- .../llm/components/prompt-generator-btn.tsx | 42 +++ web/i18n/de-DE/app-debug.ts | 19 +- web/i18n/en-US/app-debug.ts | 64 ++++- web/i18n/fr-FR/app-debug.ts | 19 +- web/i18n/ja-JP/app-debug.ts | 17 -- web/i18n/zh-Hans/app-debug.ts | 61 +++- web/i18n/zh-Hant/app-debug.ts | 19 +- 20 files changed, 455 insertions(+), 238 deletions(-) create mode 100644 web/app/components/app/configuration/config/automatic/style.module.css create mode 100644 web/app/components/base/icons/assets/vender/other/generator.svg create mode 100644 web/app/components/base/icons/src/vender/other/Generator.json create mode 100644 web/app/components/base/icons/src/vender/other/Generator.tsx create mode 100644 web/app/components/base/icons/src/vender/other/index.ts create mode 100644 web/app/components/workflow/nodes/llm/components/prompt-generator-btn.tsx diff --git a/web/app/components/app/configuration/config-prompt/index.tsx b/web/app/components/app/configuration/config-prompt/index.tsx index bea4a9e455ed81..7e40fdc84e5c97 100644 --- a/web/app/components/app/configuration/config-prompt/index.tsx +++ b/web/app/components/app/configuration/config-prompt/index.tsx @@ -19,6 +19,9 @@ export type IPromptProps = { promptTemplate: string promptVariables: PromptVariable[] readonly?: boolean + noTitle?: boolean + gradientBorder?: boolean + editorHeight?: number onChange?: (prompt: string, promptVariables: PromptVariable[]) => void } @@ -26,7 +29,10 @@ const Prompt: FC = ({ mode, promptTemplate, promptVariables, + noTitle, + gradientBorder, readonly = false, + editorHeight, onChange, }) => { const { t } = useTranslation() @@ -99,6 +105,9 @@ const Prompt: FC = ({ promptVariables={promptVariables} readonly={readonly} onChange={onChange} + noTitle={noTitle} + gradientBorder={gradientBorder} + editorHeight={editorHeight} /> ) } diff --git a/web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx b/web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx index a15f538227e0d8..b0a140fc975fc6 100644 --- a/web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx +++ b/web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx @@ -28,6 +28,7 @@ import { useEventEmitterContextContext } from '@/context/event-emitter' import { ADD_EXTERNAL_DATA_TOOL } from '@/app/components/app/configuration/config-var' import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '@/app/components/base/prompt-editor/plugins/variable-block' import { PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER } from '@/app/components/base/prompt-editor/plugins/update-block' +import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' export type ISimplePromptInput = { mode: AppType @@ -35,6 +36,9 @@ export type ISimplePromptInput = { promptVariables: PromptVariable[] readonly?: boolean onChange?: (promp: string, promptVariables: PromptVariable[]) => void + noTitle?: boolean + gradientBorder?: boolean + editorHeight?: number } const Prompt: FC = ({ @@ -43,8 +47,14 @@ const Prompt: FC = ({ promptVariables, readonly = false, onChange, + noTitle, + gradientBorder, + editorHeight: initEditorHeight, }) => { const { t } = useTranslation() + const media = useBreakpoints() + const isMobile = media === MediaType.mobile + const { eventEmitter } = useEventEmitterContextContext() const { modelConfig, @@ -116,6 +126,11 @@ const Prompt: FC = ({ const [showAutomatic, { setTrue: showAutomaticTrue, setFalse: showAutomaticFalse }] = useBoolean(false) const handleAutomaticRes = (res: AutomaticRes) => { + // put eventEmitter in first place to prevent overwrite the configs.prompt_variables.But another problem is that prompt won't hight the prompt_variables. + eventEmitter?.emit({ + type: PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER, + payload: res.prompt, + } as any) const newModelConfig = produce(modelConfig, (draft) => { draft.configs.prompt_template = res.prompt draft.configs.prompt_variables = res.variables.map(key => ({ key, name: key, type: 'string', required: true })) @@ -125,36 +140,35 @@ const Prompt: FC = ({ if (mode !== AppType.completion) setIntroduction(res.opening_statement) showAutomaticFalse() - eventEmitter?.emit({ - type: PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER, - payload: res.prompt, - } as any) } - const minHeight = 228 + const minHeight = initEditorHeight || 228 const [editorHeight, setEditorHeight] = useState(minHeight) return ( -
+
-
-
-
{mode !== AppType.completion ? t('appDebug.chatSubTitle') : t('appDebug.completionSubTitle')}
- {!readonly && ( - - {t('appDebug.promptTip')} -
} - selector='config-prompt-tooltip'> - - - )} -
-
- {!isAgent && !readonly && ( - - )} + {!noTitle && ( +
+
+
{mode !== AppType.completion ? t('appDebug.chatSubTitle') : t('appDebug.completionSubTitle')}
+ {!readonly && ( + + {t('appDebug.promptTip')} +
} + selector='config-prompt-tooltip'> + + + )} +
+
+ {!isAgent && !readonly && !isMobile && ( + + )} +
-
+ )} + = ({ onBlur={() => { handleChange(promptTemplate, getVars(promptTemplate)) }} + editable={!readonly} />
diff --git a/web/app/components/app/configuration/config/automatic/automatic-btn.tsx b/web/app/components/app/configuration/config/automatic/automatic-btn.tsx index 40a9b9d79944c0..f70976082d92b9 100644 --- a/web/app/components/app/configuration/config/automatic/automatic-btn.tsx +++ b/web/app/components/app/configuration/config/automatic/automatic-btn.tsx @@ -2,29 +2,21 @@ import type { FC } from 'react' import React from 'react' import { useTranslation } from 'react-i18next' +import { Generator } from '@/app/components/base/icons/src/vender/other' export type IAutomaticBtnProps = { onClick: () => void } - -const leftIcon = ( - - - - - - -) const AutomaticBtn: FC = ({ onClick, }) => { const { t } = useTranslation() return ( -
- {leftIcon} + {t('appDebug.operation.automatic')}
) diff --git a/web/app/components/app/configuration/config/automatic/get-automatic-res.tsx b/web/app/components/app/configuration/config/automatic/get-automatic-res.tsx index fa58253cac7291..13cf857edf4824 100644 --- a/web/app/components/app/configuration/config/automatic/get-automatic-res.tsx +++ b/web/app/components/app/configuration/config/automatic/get-automatic-res.tsx @@ -1,8 +1,20 @@ 'use client' import type { FC } from 'react' -import React from 'react' +import React, { useCallback } from 'react' import { useTranslation } from 'react-i18next' import { useBoolean } from 'ahooks' +import { + RiDatabase2Line, + RiFileExcel2Line, + RiGitCommitLine, + RiNewspaperLine, + RiPresentationLine, + RiRoadMapLine, + RiTerminalBoxLine, + RiTranslate, + RiUser2Line, +} from '@remixicon/react' +import s from './style.module.css' import Modal from '@/app/components/base/modal' import Button from '@/app/components/base/button' import Toast from '@/app/components/base/toast' @@ -14,57 +26,97 @@ import OpeningStatement from '@/app/components/app/configuration/features/chat-g import GroupName from '@/app/components/app/configuration/base/group-name' import Loading from '@/app/components/base/loading' import Confirm from '@/app/components/base/confirm' + // type import type { AutomaticRes } from '@/service/debug' -import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' - -const noDataIcon = ( - - - -) +import { Generator } from '@/app/components/base/icons/src/vender/other' export type IGetAutomaticResProps = { mode: AppType isShow: boolean onClose: () => void onFinished: (res: AutomaticRes) => void + isInLLMNode?: boolean } -const genIcon = ( - - - - - -) +const TryLabel: FC<{ + Icon: any + text: string + onClick: () => void +}> = ({ Icon, text, onClick }) => { + return ( +
+ +
{text}
+
+ ) +} const GetAutomaticRes: FC = ({ mode, isShow, onClose, - // appId, + isInLLMNode, onFinished, }) => { const { t } = useTranslation() - const media = useBreakpoints() - const isMobile = media === MediaType.mobile + const tryList = [ + { + icon: RiTerminalBoxLine, + key: 'pythonDebugger', + }, + { + icon: RiTranslate, + key: 'translation', + }, + { + icon: RiPresentationLine, + key: 'meetingTakeaways', + }, + { + icon: RiNewspaperLine, + key: 'writingsPolisher', + }, + { + icon: RiUser2Line, + key: 'professionalAnalyst', + }, + { + icon: RiFileExcel2Line, + key: 'excelFormulaExpert', + }, + { + icon: RiRoadMapLine, + key: 'travelPlanning', + }, + { + icon: RiDatabase2Line, + key: 'SQLSorcerer', + }, + { + icon: RiGitCommitLine, + key: 'GitGud', + }, + ] - const [audiences, setAudiences] = React.useState('') - const [hopingToSolve, setHopingToSolve] = React.useState('') - const isValid = () => { - if (audiences.trim() === '') { - Toast.notify({ - type: 'error', - message: t('appDebug.automatic.audiencesRequired'), - }) - return false + const [instruction, setInstruction] = React.useState('') + const handleChooseTemplate = useCallback((key: string) => { + return () => { + const template = t(`appDebug.generate.template.${key}.instruction`) + setInstruction(template) } - if (hopingToSolve.trim() === '') { + }, [t]) + const isValid = () => { + if (instruction.trim() === '') { Toast.notify({ type: 'error', - message: t('appDebug.automatic.problemRequired'), + message: t('common.errorMsg.fieldRequired', { + field: t('appDebug.generate.instruction'), + }), }) return false } @@ -76,14 +128,17 @@ const GetAutomaticRes: FC = ({ const renderLoading = (
-
{t('appDebug.automatic.loading')}
+
{t('appDebug.generate.loading')}
) const renderNoData = (
- {noDataIcon} -
{t('appDebug.automatic.noData')}
+ +
+
{t('appDebug.generate.noDataLine1')}
+
{t('appDebug.generate.noDataLine2')}
+
) @@ -95,8 +150,7 @@ const GetAutomaticRes: FC = ({ setLoadingTrue() try { const res = await generateRule({ - audiences, - hoping_to_solve: hopingToSolve, + instruction, }) setRes(res) } @@ -107,24 +161,7 @@ const GetAutomaticRes: FC = ({ const [showConfirmOverwrite, setShowConfirmOverwrite] = React.useState(false) - const isShowAutoPromptInput = () => { - if (isMobile) { - // hide prompt panel on mobile if it is loading or has had result - if (isLoading || res) - return false - return true - } - - // always display prompt panel on desktop mode - return true - } - const isShowAutoPromptResPlaceholder = () => { - if (isMobile) { - // hide placeholder panel on mobile - return false - } - return !isLoading && !res } @@ -132,75 +169,96 @@ const GetAutomaticRes: FC = ({ -
- {isShowAutoPromptInput() &&
-
-
{t('appDebug.automatic.title')}
-
{t('appDebug.automatic.description')}
+
+
+
+
{t('appDebug.generate.title')}
+
{t('appDebug.generate.description')}
- {/* inputs */} -
-
-
{t('appDebug.automatic.intendedAudience')}
- setAudiences(e.target.value)} /> +
+
+
{t('appDebug.generate.tryIt')}
+
-
-
{t('appDebug.automatic.solveProblem')}
-