Feat/attachments (#9526)

Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: JzoNg <jzongcode@gmail.com>
This commit is contained in:
zxhlyh
2024-10-21 10:32:37 +08:00
committed by GitHub
parent 4fd2743efa
commit 7a1d6fe509
445 changed files with 11759 additions and 6922 deletions

View File

@@ -79,6 +79,8 @@ const nodeDefault: NodeDefault<LLMNodeType> = {
})
}
}
if (!errorMessages && payload.vision?.enabled && !payload.vision.configs?.variable_selector?.length)
errorMessages = t(`${i18nPrefix}.fieldRequired`, { field: t(`${i18nPrefix}.fields.visionVariable`) })
return {
isValid: !errorMessages,
errorMessage: errorMessages,

View File

@@ -3,8 +3,8 @@ import React from 'react'
import { useTranslation } from 'react-i18next'
import MemoryConfig from '../_base/components/memory-config'
import VarReferencePicker from '../_base/components/variable/var-reference-picker'
import ConfigVision from '../_base/components/config-vision'
import useConfig from './use-config'
import ResolutionPicker from './components/resolution-picker'
import type { LLMNodeType } from './types'
import ConfigPrompt from './components/config-prompt'
import VarList from '@/app/components/workflow/nodes/_base/components/variable/var-list'
@@ -13,14 +13,13 @@ 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 Tooltip from '@/app/components/base/tooltip'
import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor'
import Switch from '@/app/components/base/switch'
const i18nPrefix = 'workflow.nodes.llm'
const Panel: FC<NodePanelProps<LLMNodeType>> = ({
@@ -36,7 +35,7 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
isChatMode,
isCompletionModel,
shouldShowContextTip,
isShowVisionConfig,
isVisionModel,
handleModelChanged,
hasSetBlockStatus,
handleCompletionParamsChange,
@@ -102,12 +101,13 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
)
}
if (isShowVisionConfig) {
if (isVisionModel) {
const variableName = data.vision.configs?.variable_selector?.[1] || t(`${i18nPrefix}.files`)!
forms.push(
{
label: t(`${i18nPrefix}.vision`)!,
inputs: [{
label: t(`${i18nPrefix}.files`)!,
label: variableName!,
variable: '#files#',
type: InputVarType.files,
required: false,
@@ -256,28 +256,15 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
)}
{/* Vision: GPT4-vision and so on */}
{isShowVisionConfig && (
<>
<Split />
<Field
title={t(`${i18nPrefix}.vision`)}
tooltip={t('appDebug.vision.description')!}
operations={
<Switch size='md' defaultValue={inputs.vision.enabled} onChange={handleVisionResolutionEnabledChange} />
}
>
{inputs.vision.enabled
? (
<ResolutionPicker
value={inputs.vision.configs?.detail || Resolution.high}
onChange={handleVisionResolutionChange}
/>
)
: null}
</Field>
</>
)}
<ConfigVision
nodeId={id}
readOnly={readOnly}
isVisionModel={isVisionModel}
enabled={inputs.vision?.enabled}
onEnabledChange={handleVisionResolutionEnabledChange}
config={inputs.vision?.configs}
onConfigChange={handleVisionResolutionChange}
/>
</div>
<Split />
<div className='px-4 pt-4 pb-2'>

View File

@@ -1,5 +1,4 @@
import type { Resolution } from '@/types/app'
import type { CommonNodeType, Memory, ModelConfig, PromptItem, ValueSelector, Variable } from '@/app/components/workflow/types'
import type { CommonNodeType, Memory, ModelConfig, PromptItem, ValueSelector, Variable, VisionSetting } from '@/app/components/workflow/types'
export type LLMNodeType = CommonNodeType & {
model: ModelConfig
@@ -14,8 +13,6 @@ export type LLMNodeType = CommonNodeType & {
}
vision: {
enabled: boolean
configs?: {
detail: Resolution
}
configs?: VisionSetting
}
}

View File

@@ -8,11 +8,10 @@ import {
useNodesReadOnly,
} from '../../hooks'
import useAvailableVarList from '../_base/hooks/use-available-var-list'
import useConfigVision from '../../hooks/use-config-vision'
import type { LLMNodeType } from './types'
import { Resolution } from '@/types/app'
import { useModelListAndDefaultModelAndCurrentProviderAndModel, useTextGenerationCurrentProviderAndModelAndModelList } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import {
ModelFeatureEnum,
ModelTypeEnum,
} from '@/app/components/header/account-setting/model-provider-page/declarations'
import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
@@ -100,7 +99,7 @@ const useConfig = (id: string, payload: LLMNodeType) => {
})
setInputs(newInputs)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [defaultConfig, isChatModel])
const [modelChanged, setModelChanged] = useState(false)
@@ -109,6 +108,21 @@ const useConfig = (id: string, payload: LLMNodeType) => {
currentModel,
} = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.textGeneration)
const {
isVisionModel,
handleVisionResolutionEnabledChange,
handleVisionResolutionChange,
handleModelChanged: handleVisionConfigAfterModelChanged,
} = useConfigVision(model, {
payload: inputs.vision,
onChange: (newPayload) => {
const newInputs = produce(inputs, (draft) => {
draft.vision = newPayload
})
setInputs(newInputs)
},
})
const handleModelChanged = useCallback((model: { provider: string; modelId: string; mode?: string }) => {
const newInputs = produce(inputRef.current, (draft) => {
draft.model.provider = model.provider
@@ -139,44 +153,14 @@ const useConfig = (id: string, payload: LLMNodeType) => {
setInputs(newInputs)
}, [inputs, setInputs])
const {
currentModel: currModel,
} = useTextGenerationCurrentProviderAndModelAndModelList(
{
provider: model.provider,
model: model.name,
},
)
const isShowVisionConfig = !!currModel?.features?.includes(ModelFeatureEnum.vision)
// change to vision model to set vision enabled, else disabled
useEffect(() => {
if (!modelChanged)
return
setModelChanged(false)
if (!isShowVisionConfig) {
const newInputs = produce(inputs, (draft) => {
draft.vision = {
enabled: false,
}
})
setInputs(newInputs)
return
}
if (!inputs.vision?.enabled) {
const newInputs = produce(inputs, (draft) => {
if (!draft.vision?.enabled) {
draft.vision = {
enabled: true,
configs: {
detail: Resolution.high,
},
}
}
})
setInputs(newInputs)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isShowVisionConfig, modelChanged])
handleVisionConfigAfterModelChanged()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isVisionModel, modelChanged])
// variables
const isShowVars = (() => {
@@ -293,46 +277,12 @@ const useConfig = (id: string, payload: LLMNodeType) => {
setInputs(newInputs)
}, [inputs, setInputs])
const handleVisionResolutionEnabledChange = useCallback((enabled: boolean) => {
const newInputs = produce(inputs, (draft) => {
if (!draft.vision) {
draft.vision = {
enabled,
configs: {
detail: Resolution.high,
},
}
}
else {
draft.vision.enabled = enabled
if (!draft.vision.configs) {
draft.vision.configs = {
detail: Resolution.high,
}
}
}
})
setInputs(newInputs)
}, [inputs, setInputs])
const handleVisionResolutionChange = useCallback((newResolution: Resolution) => {
const newInputs = produce(inputs, (draft) => {
if (!draft.vision.configs) {
draft.vision.configs = {
detail: Resolution.high,
}
}
draft.vision.configs.detail = newResolution
})
setInputs(newInputs)
}, [inputs, setInputs])
const filterInputVar = useCallback((varPayload: Var) => {
return [VarType.number, VarType.string, VarType.secret].includes(varPayload.type)
return [VarType.number, VarType.string, VarType.secret, VarType.arrayString, VarType.arrayNumber].includes(varPayload.type)
}, [])
const filterVar = useCallback((varPayload: Var) => {
return [VarType.arrayObject, VarType.array, VarType.number, VarType.string, VarType.secret].includes(varPayload.type)
const filterMemoryPromptVar = useCallback((varPayload: Var) => {
return [VarType.arrayObject, VarType.array, VarType.number, VarType.string, VarType.secret, VarType.arrayString, VarType.arrayNumber].includes(varPayload.type)
}, [])
const {
@@ -340,7 +290,7 @@ const useConfig = (id: string, payload: LLMNodeType) => {
availableNodesWithParent,
} = useAvailableVarList(id, {
onlyLeafNodeVar: false,
filterVar,
filterVar: filterMemoryPromptVar,
})
// single run
@@ -425,7 +375,7 @@ const useConfig = (id: string, payload: LLMNodeType) => {
isCompletionModel,
hasSetBlockStatus,
shouldShowContextTip,
isShowVisionConfig,
isVisionModel,
handleModelChanged,
handleCompletionParamsChange,
isShowVars,
@@ -435,7 +385,7 @@ const useConfig = (id: string, payload: LLMNodeType) => {
handleAddEmptyVariable,
handleContextVarChange,
filterInputVar,
filterVar,
filterVar: filterMemoryPromptVar,
availableVars,
availableNodesWithParent,
handlePromptChange,