mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-20 12:39:14 +08:00
feat: doc extract struct
This commit is contained in:
parent
1668df104f
commit
6fafd410d2
@ -69,6 +69,11 @@ export const BLOCKS: Block[] = [
|
|||||||
type: BlockEnum.HttpRequest,
|
type: BlockEnum.HttpRequest,
|
||||||
title: 'HTTP Request',
|
title: 'HTTP Request',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
classification: BlockClassificationEnum.Utilities,
|
||||||
|
type: BlockEnum.DocExtractor,
|
||||||
|
title: 'Doc Extractor',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const BLOCK_CLASSIFICATIONS: string[] = [
|
export const BLOCK_CLASSIFICATIONS: string[] = [
|
||||||
|
@ -14,6 +14,7 @@ import ToolDefault from './nodes/tool/default'
|
|||||||
import VariableAssignerDefault from './nodes/variable-assigner/default'
|
import VariableAssignerDefault from './nodes/variable-assigner/default'
|
||||||
import EndNodeDefault from './nodes/end/default'
|
import EndNodeDefault from './nodes/end/default'
|
||||||
import IterationDefault from './nodes/iteration/default'
|
import IterationDefault from './nodes/iteration/default'
|
||||||
|
import DocExtractorDefault from './nodes/doc-extractor/default'
|
||||||
|
|
||||||
type NodesExtraData = {
|
type NodesExtraData = {
|
||||||
author: string
|
author: string
|
||||||
@ -160,6 +161,16 @@ export const NODES_EXTRA_DATA: Record<BlockEnum, NodesExtraData> = {
|
|||||||
getAvailableNextNodes: ToolDefault.getAvailableNextNodes,
|
getAvailableNextNodes: ToolDefault.getAvailableNextNodes,
|
||||||
checkValid: ToolDefault.checkValid,
|
checkValid: ToolDefault.checkValid,
|
||||||
},
|
},
|
||||||
|
[BlockEnum.DocExtractor]: {
|
||||||
|
author: 'Dify',
|
||||||
|
about: '',
|
||||||
|
availablePrevNodes: [],
|
||||||
|
availableNextNodes: [],
|
||||||
|
getAvailablePrevNodes: DocExtractorDefault.getAvailablePrevNodes,
|
||||||
|
getAvailableNextNodes: DocExtractorDefault.getAvailableNextNodes,
|
||||||
|
checkValid: DocExtractorDefault.checkValid,
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ALL_CHAT_AVAILABLE_BLOCKS = Object.keys(NODES_EXTRA_DATA).filter(key => key !== BlockEnum.End && key !== BlockEnum.Start) as BlockEnum[]
|
export const ALL_CHAT_AVAILABLE_BLOCKS = Object.keys(NODES_EXTRA_DATA).filter(key => key !== BlockEnum.End && key !== BlockEnum.Start) as BlockEnum[]
|
||||||
@ -274,6 +285,12 @@ export const NODES_INITIAL_DATA = {
|
|||||||
desc: '',
|
desc: '',
|
||||||
...ToolDefault.defaultValue,
|
...ToolDefault.defaultValue,
|
||||||
},
|
},
|
||||||
|
[BlockEnum.DocExtractor]: {
|
||||||
|
type: BlockEnum.DocExtractor,
|
||||||
|
title: '',
|
||||||
|
desc: '',
|
||||||
|
...DocExtractorDefault.defaultValue,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NODE_WIDTH = 240
|
export const NODE_WIDTH = 240
|
||||||
|
@ -235,6 +235,16 @@ const formatItem = (
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BlockEnum.DocExtractor: {
|
||||||
|
res.vars = [
|
||||||
|
{
|
||||||
|
variable: 'text',
|
||||||
|
type: VarType.string,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
case 'env': {
|
case 'env': {
|
||||||
res.vars = data.envList.map((env: EnvironmentVariable) => {
|
res.vars = data.envList.map((env: EnvironmentVariable) => {
|
||||||
return {
|
return {
|
||||||
|
@ -28,6 +28,8 @@ import ParameterExtractorNode from './parameter-extractor/node'
|
|||||||
import ParameterExtractorPanel from './parameter-extractor/panel'
|
import ParameterExtractorPanel from './parameter-extractor/panel'
|
||||||
import IterationNode from './iteration/node'
|
import IterationNode from './iteration/node'
|
||||||
import IterationPanel from './iteration/panel'
|
import IterationPanel from './iteration/panel'
|
||||||
|
import DocExtractorNode from './doc-extractor/node'
|
||||||
|
import DocExtractorPanel from './doc-extractor/panel'
|
||||||
|
|
||||||
export const NodeComponentMap: Record<string, ComponentType<any>> = {
|
export const NodeComponentMap: Record<string, ComponentType<any>> = {
|
||||||
[BlockEnum.Start]: StartNode,
|
[BlockEnum.Start]: StartNode,
|
||||||
@ -45,6 +47,7 @@ export const NodeComponentMap: Record<string, ComponentType<any>> = {
|
|||||||
[BlockEnum.VariableAggregator]: VariableAssignerNode,
|
[BlockEnum.VariableAggregator]: VariableAssignerNode,
|
||||||
[BlockEnum.ParameterExtractor]: ParameterExtractorNode,
|
[BlockEnum.ParameterExtractor]: ParameterExtractorNode,
|
||||||
[BlockEnum.Iteration]: IterationNode,
|
[BlockEnum.Iteration]: IterationNode,
|
||||||
|
[BlockEnum.DocExtractor]: DocExtractorNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PanelComponentMap: Record<string, ComponentType<any>> = {
|
export const PanelComponentMap: Record<string, ComponentType<any>> = {
|
||||||
@ -63,6 +66,7 @@ export const PanelComponentMap: Record<string, ComponentType<any>> = {
|
|||||||
[BlockEnum.VariableAggregator]: VariableAssignerPanel,
|
[BlockEnum.VariableAggregator]: VariableAssignerPanel,
|
||||||
[BlockEnum.ParameterExtractor]: ParameterExtractorPanel,
|
[BlockEnum.ParameterExtractor]: ParameterExtractorPanel,
|
||||||
[BlockEnum.Iteration]: IterationPanel,
|
[BlockEnum.Iteration]: IterationPanel,
|
||||||
|
[BlockEnum.DocExtractor]: DocExtractorPanel,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CUSTOM_NODE_TYPE = 'custom'
|
export const CUSTOM_NODE_TYPE = 'custom'
|
||||||
|
35
web/app/components/workflow/nodes/doc-extractor/default.ts
Normal file
35
web/app/components/workflow/nodes/doc-extractor/default.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { BlockEnum } from '../../types'
|
||||||
|
import type { NodeDefault } from '../../types'
|
||||||
|
import { type DocExtractorNodeType } from './types'
|
||||||
|
import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/constants'
|
||||||
|
const i18nPrefix = 'workflow.errorMsg'
|
||||||
|
|
||||||
|
const nodeDefault: NodeDefault<DocExtractorNodeType> = {
|
||||||
|
defaultValue: {
|
||||||
|
variable: [],
|
||||||
|
},
|
||||||
|
getAvailablePrevNodes(isChatMode: boolean) {
|
||||||
|
const nodes = isChatMode
|
||||||
|
? ALL_CHAT_AVAILABLE_BLOCKS
|
||||||
|
: ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
|
||||||
|
return nodes
|
||||||
|
},
|
||||||
|
getAvailableNextNodes(isChatMode: boolean) {
|
||||||
|
const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
|
||||||
|
return nodes
|
||||||
|
},
|
||||||
|
checkValid(payload: DocExtractorNodeType, t: any) {
|
||||||
|
let errorMessages = ''
|
||||||
|
const { variable } = payload
|
||||||
|
|
||||||
|
if (!errorMessages && !variable?.length)
|
||||||
|
errorMessages = t(`${i18nPrefix}.fieldRequired`, { field: t('workflow.nodes.assigner.assignedVariable') })
|
||||||
|
|
||||||
|
return {
|
||||||
|
isValid: !errorMessages,
|
||||||
|
errorMessage: errorMessages,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default nodeDefault
|
40
web/app/components/workflow/nodes/doc-extractor/node.tsx
Normal file
40
web/app/components/workflow/nodes/doc-extractor/node.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import type { FC } from 'react'
|
||||||
|
import React from 'react'
|
||||||
|
import { useNodes } from 'reactflow'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import NodeVariableItem from '../variable-assigner/components/node-variable-item'
|
||||||
|
import { type DocExtractorNodeType } from './types'
|
||||||
|
import { isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
|
||||||
|
import { BlockEnum, type Node, type NodeProps } from '@/app/components/workflow/types'
|
||||||
|
|
||||||
|
const i18nPrefix = 'workflow.nodes.assigner'
|
||||||
|
|
||||||
|
const NodeComponent: FC<NodeProps<DocExtractorNodeType>> = ({
|
||||||
|
data,
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const nodes: Node[] = useNodes()
|
||||||
|
const { variable } = data
|
||||||
|
|
||||||
|
if (!variable || variable.length === 0)
|
||||||
|
return null
|
||||||
|
|
||||||
|
const isSystem = isSystemVar(variable)
|
||||||
|
const isEnv = isENV(variable)
|
||||||
|
const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0])
|
||||||
|
const varName = isSystem ? `sys.${variable[variable.length - 1]}` : variable.slice(1).join('.')
|
||||||
|
return (
|
||||||
|
<div className='relative px-3'>
|
||||||
|
<div className='mb-1 system-2xs-medium-uppercase text-text-tertiary'>{t(`${i18nPrefix}.assignedVariable`)}</div>
|
||||||
|
<NodeVariableItem
|
||||||
|
node={node as Node}
|
||||||
|
isEnv={isEnv}
|
||||||
|
varName={varName}
|
||||||
|
className='bg-workflow-block-parma-bg'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(NodeComponent)
|
45
web/app/components/workflow/nodes/doc-extractor/panel.tsx
Normal file
45
web/app/components/workflow/nodes/doc-extractor/panel.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import type { FC } from 'react'
|
||||||
|
import React from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import VarReferencePicker from '../_base/components/variable/var-reference-picker'
|
||||||
|
import useConfig from './use-config'
|
||||||
|
import type { DocExtractorNodeType } from './types'
|
||||||
|
import Field from '@/app/components/workflow/nodes/_base/components/field'
|
||||||
|
import { type NodePanelProps } from '@/app/components/workflow/types'
|
||||||
|
|
||||||
|
const i18nPrefix = 'workflow.nodes.docExtractor'
|
||||||
|
|
||||||
|
const Panel: FC<NodePanelProps<DocExtractorNodeType>> = ({
|
||||||
|
id,
|
||||||
|
data,
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const {
|
||||||
|
readOnly,
|
||||||
|
inputs,
|
||||||
|
handleVarChanges,
|
||||||
|
filterVar,
|
||||||
|
} = useConfig(id, data)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='mt-2'>
|
||||||
|
<div className='px-4 pb-4 space-y-4'>
|
||||||
|
<Field
|
||||||
|
title={t(`${i18nPrefix}.assignedVariable`)}
|
||||||
|
>
|
||||||
|
<VarReferencePicker
|
||||||
|
readonly={readOnly}
|
||||||
|
nodeId={id}
|
||||||
|
isShowNodeName
|
||||||
|
value={inputs.variable || []}
|
||||||
|
onChange={handleVarChanges}
|
||||||
|
filterVar={filterVar}
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(Panel)
|
5
web/app/components/workflow/nodes/doc-extractor/types.ts
Normal file
5
web/app/components/workflow/nodes/doc-extractor/types.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import type { CommonNodeType, ValueSelector } from '@/app/components/workflow/types'
|
||||||
|
|
||||||
|
export type DocExtractorNodeType = CommonNodeType & {
|
||||||
|
variable: ValueSelector
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
|
import produce from 'immer'
|
||||||
|
import type { ValueSelector, Var } from '../../types'
|
||||||
|
import { VarType } from '../../types'
|
||||||
|
import { type DocExtractorNodeType } from './types'
|
||||||
|
import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
|
||||||
|
import {
|
||||||
|
useNodesReadOnly,
|
||||||
|
} from '@/app/components/workflow/hooks'
|
||||||
|
|
||||||
|
const useConfig = (id: string, payload: DocExtractorNodeType) => {
|
||||||
|
const { nodesReadOnly: readOnly } = useNodesReadOnly()
|
||||||
|
|
||||||
|
const { inputs, setInputs } = useNodeCrud<DocExtractorNodeType>(id, payload)
|
||||||
|
|
||||||
|
const handleVarChanges = useCallback((variable: ValueSelector | string) => {
|
||||||
|
const newInputs = produce(inputs, (draft) => {
|
||||||
|
draft.variable = variable as ValueSelector
|
||||||
|
})
|
||||||
|
setInputs(newInputs)
|
||||||
|
}, [inputs, setInputs])
|
||||||
|
|
||||||
|
const filterVar = useCallback((varPayload: Var) => {
|
||||||
|
return varPayload.type !== VarType.file
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return {
|
||||||
|
readOnly,
|
||||||
|
inputs,
|
||||||
|
filterVar,
|
||||||
|
handleVarChanges,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useConfig
|
@ -8,12 +8,14 @@ import type { Node } from '@/app/components/workflow/types'
|
|||||||
import { BlockEnum } from '@/app/components/workflow/types'
|
import { BlockEnum } from '@/app/components/workflow/types'
|
||||||
|
|
||||||
type NodeVariableItemProps = {
|
type NodeVariableItemProps = {
|
||||||
|
className?: string
|
||||||
isEnv: boolean
|
isEnv: boolean
|
||||||
node: Node
|
node: Node
|
||||||
varName: string
|
varName: string
|
||||||
showBorder?: boolean
|
showBorder?: boolean
|
||||||
}
|
}
|
||||||
const NodeVariableItem = ({
|
const NodeVariableItem = ({
|
||||||
|
className,
|
||||||
isEnv,
|
isEnv,
|
||||||
node,
|
node,
|
||||||
varName,
|
varName,
|
||||||
@ -22,7 +24,7 @@ const NodeVariableItem = ({
|
|||||||
return (
|
return (
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
'relative flex items-center mt-0.5 h-6 bg-gray-100 rounded-md px-1 text-xs font-normal text-gray-700',
|
'relative flex items-center mt-0.5 h-6 bg-gray-100 rounded-md px-1 text-xs font-normal text-gray-700',
|
||||||
showBorder && '!bg-black/[0.02]',
|
showBorder && '!bg-black/[0.02]', className,
|
||||||
)}>
|
)}>
|
||||||
{!isEnv && (
|
{!isEnv && (
|
||||||
<div className='flex items-center'>
|
<div className='flex items-center'>
|
||||||
|
@ -25,6 +25,8 @@ export enum BlockEnum {
|
|||||||
Tool = 'tool',
|
Tool = 'tool',
|
||||||
ParameterExtractor = 'parameter-extractor',
|
ParameterExtractor = 'parameter-extractor',
|
||||||
Iteration = 'iteration',
|
Iteration = 'iteration',
|
||||||
|
DocExtractor = 'doc-extractor',
|
||||||
|
ListFilter = 'list-filter',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Branch = {
|
export type Branch = {
|
||||||
@ -193,6 +195,7 @@ export enum VarType {
|
|||||||
secret = 'secret',
|
secret = 'secret',
|
||||||
boolean = 'boolean',
|
boolean = 'boolean',
|
||||||
object = 'object',
|
object = 'object',
|
||||||
|
file = 'file',
|
||||||
array = 'array',
|
array = 'array',
|
||||||
arrayString = 'array[string]',
|
arrayString = 'array[string]',
|
||||||
arrayNumber = 'array[number]',
|
arrayNumber = 'array[number]',
|
||||||
|
@ -176,6 +176,7 @@ const translation = {
|
|||||||
'iteration-start': 'Iteration Start',
|
'iteration-start': 'Iteration Start',
|
||||||
'iteration': 'Iteration',
|
'iteration': 'Iteration',
|
||||||
'parameter-extractor': 'Parameter Extractor',
|
'parameter-extractor': 'Parameter Extractor',
|
||||||
|
'doc-extractor': 'Doc Extractor',
|
||||||
},
|
},
|
||||||
blocksAbout: {
|
blocksAbout: {
|
||||||
'start': 'Define the initial parameters for launching a workflow',
|
'start': 'Define the initial parameters for launching a workflow',
|
||||||
@ -192,6 +193,7 @@ const translation = {
|
|||||||
'variable-aggregator': 'Aggregate multi-branch variables into a single variable for unified configuration of downstream nodes.',
|
'variable-aggregator': 'Aggregate multi-branch variables into a single variable for unified configuration of downstream nodes.',
|
||||||
'iteration': 'Perform multiple steps on a list object until all results are outputted.',
|
'iteration': 'Perform multiple steps on a list object until all results are outputted.',
|
||||||
'parameter-extractor': 'Use LLM to extract structured parameters from natural language for tool invocations or HTTP requests.',
|
'parameter-extractor': 'Use LLM to extract structured parameters from natural language for tool invocations or HTTP requests.',
|
||||||
|
'doc-extractor': 'TODO',
|
||||||
},
|
},
|
||||||
operator: {
|
operator: {
|
||||||
zoomIn: 'Zoom In',
|
zoomIn: 'Zoom In',
|
||||||
@ -489,6 +491,8 @@ const translation = {
|
|||||||
showAuthor: 'Show Author',
|
showAuthor: 'Show Author',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
docExtractor: {
|
||||||
|
},
|
||||||
},
|
},
|
||||||
tracing: {
|
tracing: {
|
||||||
stopBy: 'Stop by {{user}}',
|
stopBy: 'Stop by {{user}}',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user