feat: knowledge pipeline (#25360)

Signed-off-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: twwu <twwu@dify.ai>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
Co-authored-by: jyong <718720800@qq.com>
Co-authored-by: Wu Tianwei <30284043+WTW0313@users.noreply.github.com>
Co-authored-by: QuantumGhost <obelisk.reg+git@gmail.com>
Co-authored-by: lyzno1 <yuanyouhuilyz@gmail.com>
Co-authored-by: quicksand <quicksandzn@gmail.com>
Co-authored-by: Jyong <76649700+JohnJyong@users.noreply.github.com>
Co-authored-by: lyzno1 <92089059+lyzno1@users.noreply.github.com>
Co-authored-by: zxhlyh <jasonapring2015@outlook.com>
Co-authored-by: Yongtao Huang <yongtaoh2022@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: nite-knite <nkCoding@gmail.com>
Co-authored-by: Hanqing Zhao <sherry9277@gmail.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Harry <xh001x@hotmail.com>
This commit is contained in:
-LAN-
2025-09-18 12:49:10 +08:00
committed by GitHub
parent 7dadb33003
commit 85cda47c70
1772 changed files with 102407 additions and 31710 deletions

View File

@@ -0,0 +1,222 @@
import React from 'react'
import { type InputFieldConfiguration, InputFieldType } from './types'
import { withForm } from '../..'
import { useStore } from '@tanstack/react-form'
type InputFieldProps = {
initialData?: Record<string, any>
config: InputFieldConfiguration
}
const InputField = ({
initialData,
config,
}: InputFieldProps) => withForm({
defaultValues: initialData,
render: function Render({
form,
}) {
const {
type,
label,
placeholder,
variable,
tooltip,
showConditions,
max,
min,
required,
showOptional,
supportFile,
description,
options,
listeners,
popupProps,
} = config
const isAllConditionsMet = useStore(form.store, (state) => {
const fieldValues = state.values
return showConditions.every((condition) => {
const { variable, value } = condition
const fieldValue = fieldValues[variable as keyof typeof fieldValues]
return fieldValue === value
})
})
if (!isAllConditionsMet)
return <></>
if (type === InputFieldType.textInput) {
return (
<form.AppField
name={variable}
listeners={listeners}
children={field => (
<field.TextField
label={label}
labelOptions={{
tooltip,
isRequired: required,
showOptional,
}}
placeholder={placeholder}
/>
)}
/>
)
}
if (type === InputFieldType.numberInput) {
return (
<form.AppField
name={variable}
children={field => (
<field.NumberInputField
label={label}
labelOptions={{
tooltip,
isRequired: required,
showOptional,
}}
placeholder={placeholder}
max={max}
min={min}
/>
)}
/>
)
}
if (type === InputFieldType.numberSlider) {
return (
<form.AppField
name={variable}
children={field => (
<field.NumberSliderField
label={label}
labelOptions={{
tooltip,
isRequired: required,
showOptional,
}}
description={description}
max={max}
min={min}
/>
)}
/>
)
}
if (type === InputFieldType.checkbox) {
return (
<form.AppField
name={variable}
children={field => (
<field.CheckboxField
label={label}
/>
)}
/>
)
}
if (type === InputFieldType.select) {
return (
<form.AppField
name={variable}
children={field => (
<field.SelectField
label={label}
labelOptions={{
tooltip,
isRequired: required,
showOptional,
}}
options={options!}
popupProps={popupProps}
/>
)}
/>
)
}
if (type === InputFieldType.inputTypeSelect) {
return (
<form.AppField
name={variable}
listeners={listeners}
children={field => (
<field.InputTypeSelectField
label={label}
labelOptions={{
tooltip,
isRequired: required,
showOptional,
}}
supportFile={!!supportFile}
/>
)}
/>
)
}
if (type === InputFieldType.uploadMethod) {
return (
<form.AppField
name={variable}
children={field => (
<field.UploadMethodField
label={label}
labelOptions={{
tooltip,
isRequired: required,
showOptional,
}}
/>
)}
/>
)
}
if (type === InputFieldType.fileTypes) {
return (
<form.AppField
name={variable}
children={field => (
<field.FileTypesField
label={label}
labelOptions={{
tooltip,
isRequired: required,
showOptional,
}}
/>
)}
/>
)
}
if (type === InputFieldType.options) {
return (
<form.AppField
name={variable}
children={field => (
<field.OptionsField
label={label}
labelOptions={{
tooltip,
isRequired: required,
showOptional,
}}
/>
)}
/>
)
}
return <></>
},
})
export default InputField

View File

@@ -0,0 +1,39 @@
import type { DeepKeys, FieldListeners } from '@tanstack/react-form'
import type { NumberConfiguration, SelectConfiguration, ShowCondition } from '../base/types'
export enum InputFieldType {
textInput = 'textInput',
numberInput = 'numberInput',
numberSlider = 'numberSlider',
checkbox = 'checkbox',
options = 'options',
select = 'select',
inputTypeSelect = 'inputTypeSelect',
uploadMethod = 'uploadMethod',
fileTypes = 'fileTypes',
}
export type InputTypeSelectConfiguration = {
supportFile: boolean
}
export type NumberSliderConfiguration = {
description: string
max?: number
min?: number
}
export type InputFieldConfiguration = {
label: string
variable: string // Variable name
maxLength?: number // Max length for text input
placeholder?: string
required: boolean
showOptional?: boolean // show optional label
showConditions: ShowCondition[] // Show this field only when all conditions are met
type: InputFieldType
tooltip?: string // Tooltip for this field
listeners?: FieldListeners<Record<string, any>, DeepKeys<Record<string, any>>> // Listener for this field
} & NumberConfiguration & Partial<InputTypeSelectConfiguration>
& Partial<NumberSliderConfiguration>
& Partial<SelectConfiguration>

View File

@@ -0,0 +1,75 @@
import type { ZodSchema, ZodString } from 'zod'
import { z } from 'zod'
import { type InputFieldConfiguration, InputFieldType } from './types'
import { SupportedFileTypes, TransferMethod } from '@/app/components/rag-pipeline/components/panel/input-field/editor/form/schema'
export const generateZodSchema = (fields: InputFieldConfiguration[]) => {
const shape: Record<string, ZodSchema> = {}
fields.forEach((field) => {
let zodType
switch (field.type) {
case InputFieldType.textInput:
zodType = z.string()
break
case InputFieldType.numberInput:
zodType = z.number()
break
case InputFieldType.numberSlider:
zodType = z.number()
break
case InputFieldType.checkbox:
zodType = z.boolean()
break
case InputFieldType.options:
zodType = z.array(z.string())
break
case InputFieldType.select:
zodType = z.string()
break
case InputFieldType.fileTypes:
zodType = z.object({
allowedFileExtensions: z.string().optional(),
allowedFileTypes: z.array(SupportedFileTypes),
})
break
case InputFieldType.inputTypeSelect:
zodType = z.string()
break
case InputFieldType.uploadMethod:
zodType = z.array(TransferMethod)
break
default:
zodType = z.any()
break
}
if (field.maxLength) {
if ([InputFieldType.textInput].includes(field.type))
zodType = (zodType as ZodString).max(field.maxLength, `${field.label} exceeds max length of ${field.maxLength}`)
}
if (field.min) {
if ([InputFieldType.numberInput].includes(field.type))
zodType = (zodType as ZodString).min(field.min, `${field.label} must be at least ${field.min}`)
}
if (field.max) {
if ([InputFieldType.numberInput].includes(field.type))
zodType = (zodType as ZodString).max(field.max, `${field.label} exceeds max value of ${field.max}`)
}
if (field.required) {
if ([InputFieldType.textInput].includes(field.type))
zodType = (zodType as ZodString).nonempty(`${field.label} is required`)
}
else {
zodType = zodType.optional()
}
shape[field.variable] = zodType
})
return z.object(shape)
}