| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | import type { FC } from 'react' | 
					
						
							| 
									
										
										
										
											2024-04-26 14:23:13 +08:00
										 |  |  | import React from 'react' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | import { useTranslation } from 'react-i18next' | 
					
						
							| 
									
										
										
										
											2024-06-20 11:05:08 +08:00
										 |  |  | import { RiQuestionLine } from '@remixicon/react' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | import MemoryConfig from '../_base/components/memory-config' | 
					
						
							|  |  |  | import VarReferencePicker from '../_base/components/variable/var-reference-picker' | 
					
						
							|  |  |  | import useConfig from './use-config' | 
					
						
							|  |  |  | import ResolutionPicker from './components/resolution-picker' | 
					
						
							|  |  |  | import type { LLMNodeType } from './types' | 
					
						
							|  |  |  | import ConfigPrompt from './components/config-prompt' | 
					
						
							| 
									
										
										
										
											2024-05-10 18:14:05 +08:00
										 |  |  | import VarList from '@/app/components/workflow/nodes/_base/components/variable/var-list' | 
					
						
							|  |  |  | import AddButton2 from '@/app/components/base/button/add-button' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | import Field from '@/app/components/workflow/nodes/_base/components/field' | 
					
						
							|  |  |  | import Split from '@/app/components/workflow/nodes/_base/components/split' | 
					
						
							|  |  |  | import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal' | 
					
						
							|  |  |  | import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars' | 
					
						
							|  |  |  | import { Resolution } from '@/types/app' | 
					
						
							|  |  |  | import { InputVarType, type NodePanelProps } from '@/app/components/workflow/types' | 
					
						
							|  |  |  | import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form' | 
					
						
							|  |  |  | import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form' | 
					
						
							|  |  |  | import ResultPanel from '@/app/components/workflow/run/result-panel' | 
					
						
							|  |  |  | import TooltipPlus from '@/app/components/base/tooltip-plus' | 
					
						
							|  |  |  | import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor' | 
					
						
							| 
									
										
										
										
											2024-04-09 15:07:43 +08:00
										 |  |  | import Switch from '@/app/components/base/switch' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | const i18nPrefix = 'workflow.nodes.llm' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const Panel: FC<NodePanelProps<LLMNodeType>> = ({ | 
					
						
							|  |  |  |   id, | 
					
						
							|  |  |  |   data, | 
					
						
							|  |  |  | }) => { | 
					
						
							|  |  |  |   const { t } = useTranslation() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { | 
					
						
							|  |  |  |     readOnly, | 
					
						
							|  |  |  |     inputs, | 
					
						
							|  |  |  |     isChatModel, | 
					
						
							|  |  |  |     isChatMode, | 
					
						
							|  |  |  |     isCompletionModel, | 
					
						
							|  |  |  |     shouldShowContextTip, | 
					
						
							|  |  |  |     isShowVisionConfig, | 
					
						
							|  |  |  |     handleModelChanged, | 
					
						
							|  |  |  |     hasSetBlockStatus, | 
					
						
							|  |  |  |     handleCompletionParamsChange, | 
					
						
							|  |  |  |     handleContextVarChange, | 
					
						
							|  |  |  |     filterInputVar, | 
					
						
							|  |  |  |     filterVar, | 
					
						
							| 
									
										
										
										
											2024-04-25 18:01:53 +08:00
										 |  |  |     availableVars, | 
					
						
							| 
									
										
										
										
											2024-05-27 21:57:08 +08:00
										 |  |  |     availableNodesWithParent, | 
					
						
							| 
									
										
										
										
											2024-05-10 18:14:05 +08:00
										 |  |  |     isShowVars, | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |     handlePromptChange, | 
					
						
							| 
									
										
										
										
											2024-05-10 18:14:05 +08:00
										 |  |  |     handleAddEmptyVariable, | 
					
						
							|  |  |  |     handleAddVariable, | 
					
						
							|  |  |  |     handleVarListChange, | 
					
						
							|  |  |  |     handleVarNameChange, | 
					
						
							| 
									
										
										
										
											2024-04-25 18:01:53 +08:00
										 |  |  |     handleSyeQueryChange, | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |     handleMemoryChange, | 
					
						
							| 
									
										
										
										
											2024-04-09 15:07:43 +08:00
										 |  |  |     handleVisionResolutionEnabledChange, | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |     handleVisionResolutionChange, | 
					
						
							|  |  |  |     isShowSingleRun, | 
					
						
							|  |  |  |     hideSingleRun, | 
					
						
							|  |  |  |     inputVarValues, | 
					
						
							|  |  |  |     setInputVarValues, | 
					
						
							|  |  |  |     visionFiles, | 
					
						
							|  |  |  |     setVisionFiles, | 
					
						
							|  |  |  |     contexts, | 
					
						
							|  |  |  |     setContexts, | 
					
						
							|  |  |  |     runningStatus, | 
					
						
							|  |  |  |     handleRun, | 
					
						
							|  |  |  |     handleStop, | 
					
						
							|  |  |  |     varInputs, | 
					
						
							|  |  |  |     runResult, | 
					
						
							|  |  |  |   } = useConfig(id, data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const model = inputs.model | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const singleRunForms = (() => { | 
					
						
							|  |  |  |     const forms: FormProps[] = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (varInputs.length > 0) { | 
					
						
							|  |  |  |       forms.push( | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           label: t(`${i18nPrefix}.singleRun.variable`)!, | 
					
						
							|  |  |  |           inputs: varInputs, | 
					
						
							|  |  |  |           values: inputVarValues, | 
					
						
							|  |  |  |           onChange: setInputVarValues, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (inputs.context?.variable_selector && inputs.context?.variable_selector.length > 0) { | 
					
						
							|  |  |  |       forms.push( | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           label: t(`${i18nPrefix}.context`)!, | 
					
						
							|  |  |  |           inputs: [{ | 
					
						
							|  |  |  |             label: '', | 
					
						
							|  |  |  |             variable: '#context#', | 
					
						
							|  |  |  |             type: InputVarType.contexts, | 
					
						
							|  |  |  |             required: false, | 
					
						
							|  |  |  |           }], | 
					
						
							|  |  |  |           values: { '#context#': contexts }, | 
					
						
							|  |  |  |           onChange: keyValue => setContexts((keyValue as any)['#context#']), | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (isShowVisionConfig) { | 
					
						
							|  |  |  |       forms.push( | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           label: t(`${i18nPrefix}.vision`)!, | 
					
						
							|  |  |  |           inputs: [{ | 
					
						
							|  |  |  |             label: t(`${i18nPrefix}.files`)!, | 
					
						
							|  |  |  |             variable: '#files#', | 
					
						
							|  |  |  |             type: InputVarType.files, | 
					
						
							|  |  |  |             required: false, | 
					
						
							|  |  |  |           }], | 
					
						
							|  |  |  |           values: { '#files#': visionFiles }, | 
					
						
							|  |  |  |           onChange: keyValue => setVisionFiles((keyValue as any)['#files#']), | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return forms | 
					
						
							|  |  |  |   })() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ( | 
					
						
							|  |  |  |     <div className='mt-2'> | 
					
						
							|  |  |  |       <div className='px-4 pb-4 space-y-4'> | 
					
						
							|  |  |  |         <Field | 
					
						
							|  |  |  |           title={t(`${i18nPrefix}.model`)} | 
					
						
							|  |  |  |         > | 
					
						
							|  |  |  |           <ModelParameterModal | 
					
						
							|  |  |  |             popupClassName='!w-[387px]' | 
					
						
							|  |  |  |             isInWorkflow | 
					
						
							|  |  |  |             isAdvancedMode={true} | 
					
						
							|  |  |  |             mode={model?.mode} | 
					
						
							|  |  |  |             provider={model?.provider} | 
					
						
							|  |  |  |             completionParams={model?.completion_params} | 
					
						
							|  |  |  |             modelId={model?.name} | 
					
						
							|  |  |  |             setModel={handleModelChanged} | 
					
						
							|  |  |  |             onCompletionParamsChange={handleCompletionParamsChange} | 
					
						
							|  |  |  |             hideDebugWithMultipleModel | 
					
						
							|  |  |  |             debugWithMultipleModel={false} | 
					
						
							|  |  |  |             readonly={readOnly} | 
					
						
							|  |  |  |           /> | 
					
						
							|  |  |  |         </Field> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         {/* knowledge */} | 
					
						
							|  |  |  |         <Field | 
					
						
							|  |  |  |           title={t(`${i18nPrefix}.context`)} | 
					
						
							|  |  |  |           tooltip={t(`${i18nPrefix}.contextTooltip`)!} | 
					
						
							|  |  |  |         > | 
					
						
							|  |  |  |           <> | 
					
						
							|  |  |  |             <VarReferencePicker | 
					
						
							|  |  |  |               readonly={readOnly} | 
					
						
							|  |  |  |               nodeId={id} | 
					
						
							|  |  |  |               isShowNodeName | 
					
						
							|  |  |  |               value={inputs.context?.variable_selector || []} | 
					
						
							|  |  |  |               onChange={handleContextVarChange} | 
					
						
							|  |  |  |               filterVar={filterVar} | 
					
						
							|  |  |  |             /> | 
					
						
							|  |  |  |             {shouldShowContextTip && ( | 
					
						
							|  |  |  |               <div className='leading-[18px] text-xs font-normal text-[#DC6803]'>{t(`${i18nPrefix}.notSetContextInPromptTip`)}</div> | 
					
						
							|  |  |  |             )} | 
					
						
							|  |  |  |           </> | 
					
						
							|  |  |  |         </Field> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         {/* Prompt */} | 
					
						
							|  |  |  |         {model.name && ( | 
					
						
							|  |  |  |           <ConfigPrompt | 
					
						
							|  |  |  |             readOnly={readOnly} | 
					
						
							|  |  |  |             nodeId={id} | 
					
						
							|  |  |  |             filterVar={filterInputVar} | 
					
						
							|  |  |  |             isChatModel={isChatModel} | 
					
						
							|  |  |  |             isChatApp={isChatMode} | 
					
						
							|  |  |  |             isShowContext | 
					
						
							|  |  |  |             payload={inputs.prompt_template} | 
					
						
							|  |  |  |             onChange={handlePromptChange} | 
					
						
							|  |  |  |             hasSetBlockStatus={hasSetBlockStatus} | 
					
						
							| 
									
										
										
										
											2024-05-10 18:14:05 +08:00
										 |  |  |             varList={inputs.prompt_config?.jinja2_variables || []} | 
					
						
							|  |  |  |             handleAddVariable={handleAddVariable} | 
					
						
							| 
									
										
										
										
											2024-07-23 19:51:38 +08:00
										 |  |  |             modelConfig={model} | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |           /> | 
					
						
							|  |  |  |         )} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-10 18:14:05 +08:00
										 |  |  |         {isShowVars && ( | 
					
						
							|  |  |  |           <Field | 
					
						
							|  |  |  |             title={t('workflow.nodes.templateTransform.inputVars')} | 
					
						
							|  |  |  |             operations={ | 
					
						
							|  |  |  |               !readOnly ? <AddButton2 onClick={handleAddEmptyVariable} /> : undefined | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           > | 
					
						
							|  |  |  |             <VarList | 
					
						
							|  |  |  |               nodeId={id} | 
					
						
							|  |  |  |               readonly={readOnly} | 
					
						
							|  |  |  |               list={inputs.prompt_config?.jinja2_variables || []} | 
					
						
							|  |  |  |               onChange={handleVarListChange} | 
					
						
							|  |  |  |               onVarNameChange={handleVarNameChange} | 
					
						
							|  |  |  |               filterVar={filterVar} | 
					
						
							|  |  |  |             /> | 
					
						
							|  |  |  |           </Field> | 
					
						
							|  |  |  |         )} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |         {/* Memory put place examples. */} | 
					
						
							|  |  |  |         {isChatMode && isChatModel && !!inputs.memory && ( | 
					
						
							|  |  |  |           <div className='mt-4'> | 
					
						
							|  |  |  |             <div className='flex justify-between items-center h-8 pl-3 pr-2 rounded-lg bg-gray-100'> | 
					
						
							|  |  |  |               <div className='flex items-center space-x-1'> | 
					
						
							|  |  |  |                 <div className='text-xs font-semibold text-gray-700 uppercase'>{t('workflow.nodes.common.memories.title')}</div> | 
					
						
							|  |  |  |                 <TooltipPlus | 
					
						
							|  |  |  |                   popupContent={t('workflow.nodes.common.memories.tip')} | 
					
						
							|  |  |  |                 > | 
					
						
							| 
									
										
										
										
											2024-06-20 11:05:08 +08:00
										 |  |  |                   <RiQuestionLine className='w-3.5 h-3.5 text-gray-400' /> | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |                 </TooltipPlus> | 
					
						
							|  |  |  |               </div> | 
					
						
							|  |  |  |               <div className='flex items-center h-[18px] px-1 rounded-[5px] border border-black/8 text-xs font-semibold text-gray-500 uppercase'>{t('workflow.nodes.common.memories.builtIn')}</div> | 
					
						
							|  |  |  |             </div> | 
					
						
							|  |  |  |             {/* Readonly User Query */} | 
					
						
							|  |  |  |             <div className='mt-4'> | 
					
						
							|  |  |  |               <Editor | 
					
						
							|  |  |  |                 title={<div className='flex items-center space-x-1'> | 
					
						
							|  |  |  |                   <div className='text-xs font-semibold text-gray-700 uppercase'>user</div> | 
					
						
							|  |  |  |                   <TooltipPlus | 
					
						
							|  |  |  |                     popupContent={ | 
					
						
							|  |  |  |                       <div className='max-w-[180px]'>{t('workflow.nodes.llm.roleDescription.user')}</div> | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                   > | 
					
						
							| 
									
										
										
										
											2024-06-20 11:05:08 +08:00
										 |  |  |                     <RiQuestionLine className='w-3.5 h-3.5 text-gray-400' /> | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |                   </TooltipPlus> | 
					
						
							|  |  |  |                 </div>} | 
					
						
							| 
									
										
										
										
											2024-04-25 18:01:53 +08:00
										 |  |  |                 value={inputs.memory.query_prompt_template || '{{#sys.query#}}'} | 
					
						
							|  |  |  |                 onChange={handleSyeQueryChange} | 
					
						
							|  |  |  |                 readOnly={readOnly} | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |                 isShowContext={false} | 
					
						
							|  |  |  |                 isChatApp | 
					
						
							| 
									
										
										
										
											2024-04-25 18:01:53 +08:00
										 |  |  |                 isChatModel | 
					
						
							|  |  |  |                 hasSetBlockStatus={hasSetBlockStatus} | 
					
						
							|  |  |  |                 nodesOutputVars={availableVars} | 
					
						
							| 
									
										
										
										
											2024-05-27 21:57:08 +08:00
										 |  |  |                 availableNodes={availableNodesWithParent} | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |               /> | 
					
						
							| 
									
										
										
										
											2024-04-25 18:01:53 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |               {inputs.memory.query_prompt_template && !inputs.memory.query_prompt_template.includes('{{#sys.query#}}') && ( | 
					
						
							|  |  |  |                 <div className='leading-[18px] text-xs font-normal text-[#DC6803]'>{t(`${i18nPrefix}.sysQueryInUser`)}</div> | 
					
						
							|  |  |  |               )} | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |             </div> | 
					
						
							|  |  |  |           </div> | 
					
						
							|  |  |  |         )} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         {/* Memory */} | 
					
						
							|  |  |  |         {isChatMode && ( | 
					
						
							|  |  |  |           <> | 
					
						
							|  |  |  |             <Split /> | 
					
						
							|  |  |  |             <MemoryConfig | 
					
						
							|  |  |  |               readonly={readOnly} | 
					
						
							|  |  |  |               config={{ data: inputs.memory }} | 
					
						
							|  |  |  |               onChange={handleMemoryChange} | 
					
						
							|  |  |  |               canSetRoleName={isCompletionModel} | 
					
						
							|  |  |  |             /> | 
					
						
							|  |  |  |           </> | 
					
						
							|  |  |  |         )} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         {/* Vision: GPT4-vision and so on */} | 
					
						
							|  |  |  |         {isShowVisionConfig && ( | 
					
						
							|  |  |  |           <> | 
					
						
							|  |  |  |             <Split /> | 
					
						
							|  |  |  |             <Field | 
					
						
							|  |  |  |               title={t(`${i18nPrefix}.vision`)} | 
					
						
							|  |  |  |               tooltip={t('appDebug.vision.description')!} | 
					
						
							|  |  |  |               operations={ | 
					
						
							| 
									
										
										
										
											2024-04-09 15:07:43 +08:00
										 |  |  |                 <Switch size='md' defaultValue={inputs.vision.enabled} onChange={handleVisionResolutionEnabledChange} /> | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |               } | 
					
						
							| 
									
										
										
										
											2024-04-09 15:07:43 +08:00
										 |  |  |             > | 
					
						
							|  |  |  |               {inputs.vision.enabled | 
					
						
							|  |  |  |                 ? ( | 
					
						
							|  |  |  |                   <ResolutionPicker | 
					
						
							|  |  |  |                     value={inputs.vision.configs?.detail || Resolution.high} | 
					
						
							|  |  |  |                     onChange={handleVisionResolutionChange} | 
					
						
							|  |  |  |                   /> | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 : null} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             </Field> | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |           </> | 
					
						
							|  |  |  |         )} | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |       <Split /> | 
					
						
							|  |  |  |       <div className='px-4 pt-4 pb-2'> | 
					
						
							|  |  |  |         <OutputVars> | 
					
						
							|  |  |  |           <> | 
					
						
							|  |  |  |             <VarItem | 
					
						
							|  |  |  |               name='text' | 
					
						
							|  |  |  |               type='string' | 
					
						
							|  |  |  |               description={t(`${i18nPrefix}.outputVars.output`)} | 
					
						
							|  |  |  |             /> | 
					
						
							|  |  |  |           </> | 
					
						
							|  |  |  |         </OutputVars> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |       {isShowSingleRun && ( | 
					
						
							|  |  |  |         <BeforeRunForm | 
					
						
							|  |  |  |           nodeName={inputs.title} | 
					
						
							|  |  |  |           onHide={hideSingleRun} | 
					
						
							|  |  |  |           forms={singleRunForms} | 
					
						
							|  |  |  |           runningStatus={runningStatus} | 
					
						
							|  |  |  |           onRun={handleRun} | 
					
						
							|  |  |  |           onStop={handleStop} | 
					
						
							|  |  |  |           result={<ResultPanel {...runResult} showSteps={false} />} | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  |       )} | 
					
						
							|  |  |  |     </div> | 
					
						
							|  |  |  |   ) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default React.memo(Panel) |