remove debug log and add type check

Signed-off-by: kenwoodjw <blackxin55+@gmail.com>
pull/20589/head
kenwoodjw 12 months ago
parent 9b0bf4cedf
commit b6e63e8329

@ -1048,18 +1048,22 @@ class DatasetRetrieval:
filters.append(sqlalchemy_cast(DatasetDocument.doc_metadata[metadata_name].astext, Float) != value)
case "in":
if isinstance(value, list | tuple):
# For arrays: check if metadata field (single value) is in the input array
if not value:
return filters
or_conditions = []
for i, v in enumerate(value):
param_key = f"{key_value}_{i}"
if isinstance(v, str):
# For string type: exact match with quoted string
or_conditions.append(DatasetDocument.doc_metadata[metadata_name] == f'"{v}"')
else:
# For number type: exact match as numeric value
elif isinstance(v, int | float):
or_conditions.append(
sqlalchemy_cast(DatasetDocument.doc_metadata[metadata_name].astext, Float) == v
)
or_conditions.append(DatasetDocument.doc_metadata[metadata_name] == str(v))
else:
v_str = str(v)
or_conditions.append(DatasetDocument.doc_metadata[metadata_name] == f'"{v_str}"')
if or_conditions:
filters.append(or_(*or_conditions))
else:
@ -1072,18 +1076,23 @@ class DatasetRetrieval:
)
case "not in":
if isinstance(value, list | tuple):
# For arrays: check if metadata field (single value) is not in the input array
if not value:
return filters
and_conditions = []
for i, v in enumerate(value):
param_key = f"{key_value}_{i}"
if isinstance(v, str):
# For string type: not equal to quoted string
and_conditions.append(DatasetDocument.doc_metadata[metadata_name] != f'"{v}"')
else:
# For number type: not equal to numeric value
elif isinstance(v, int | float):
and_conditions.append(
sqlalchemy_cast(DatasetDocument.doc_metadata[metadata_name].astext, Float) != v
)
and_conditions.append(DatasetDocument.doc_metadata[metadata_name] != str(v))
else:
v_str = str(v)
and_conditions.append(DatasetDocument.doc_metadata[metadata_name] != f'"{v_str}"')
if and_conditions:
filters.append(and_(*and_conditions))
else:

@ -527,18 +527,24 @@ class KnowledgeRetrievalNode(LLMNode):
filters.append(sqlalchemy_cast(Document.doc_metadata[metadata_name].astext, Float) != value)
case "in":
if isinstance(value, list | tuple):
# For arrays: check if metadata field (single value) is in the input array
if not value:
return filters
# Generate matching conditions for each value, supporting both number and string matching
or_conditions = []
for i, v in enumerate(value):
param_key = f"{key_value}_{i}"
if isinstance(v, str):
# For string type: exact match with quoted string
or_conditions.append(Document.doc_metadata[metadata_name] == f'"{v}"')
else:
# For number type: exact match as numeric value
elif isinstance(v, int | float):
or_conditions.append(
sqlalchemy_cast(Document.doc_metadata[metadata_name].astext, Float) == v
)
or_conditions.append(Document.doc_metadata[metadata_name] == str(v))
else:
v_str = str(v)
or_conditions.append(Document.doc_metadata[metadata_name] == f'"{v_str}"')
if or_conditions:
filters.append(or_(*or_conditions))
else:
@ -549,18 +555,24 @@ class KnowledgeRetrievalNode(LLMNode):
filters.append(sqlalchemy_cast(Document.doc_metadata[metadata_name].astext, Float) == value)
case "not in":
if isinstance(value, list | tuple):
# For arrays: check if metadata field (single value) is not in the input array
if not value: # 空数组
return filters
# 为每个值生成不匹配条件
and_conditions = []
for i, v in enumerate(value):
param_key = f"{key_value}_{i}"
if isinstance(v, str):
# For string type: not equal to quoted string
and_conditions.append(Document.doc_metadata[metadata_name] != f'"{v}"')
else:
# For number type: not equal to numeric value
elif isinstance(v, int | float):
and_conditions.append(
sqlalchemy_cast(Document.doc_metadata[metadata_name].astext, Float) != v
)
and_conditions.append(Document.doc_metadata[metadata_name] != str(v))
else:
v_str = str(v)
and_conditions.append(Document.doc_metadata[metadata_name] != f'"{v_str}"')
if and_conditions:
filters.append(and_(*and_conditions))
else:

@ -14,7 +14,7 @@ dependencies = [
"chardet~=5.1.0",
"flask~=3.1.0",
"flask-compress~=1.17",
"flask-cors~=5.0.0",
"flask-cors~=6.0.0",
"flask-login~=0.6.3",
"flask-migrate~=4.0.7",
"flask-restful~=0.3.10",

@ -1392,7 +1392,7 @@ requires-dist = [
{ name = "chardet", specifier = "~=5.1.0" },
{ name = "flask", specifier = "~=3.1.0" },
{ name = "flask-compress", specifier = "~=1.17" },
{ name = "flask-cors", specifier = "~=5.0.0" },
{ name = "flask-cors", specifier = "~=6.0.0" },
{ name = "flask-login", specifier = "~=0.6.3" },
{ name = "flask-migrate", specifier = "~=4.0.7" },
{ name = "flask-restful", specifier = "~=0.3.10" },
@ -1765,15 +1765,15 @@ wheels = [
[[package]]
name = "flask-cors"
version = "5.0.1"
version = "6.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "flask" },
{ name = "werkzeug" },
]
sdist = { url = "https://files.pythonhosted.org/packages/32/d8/667bd90d1ee41c96e938bafe81052494e70b7abd9498c4a0215c103b9667/flask_cors-5.0.1.tar.gz", hash = "sha256:6ccb38d16d6b72bbc156c1c3f192bc435bfcc3c2bc864b2df1eb9b2d97b2403c", size = 11643 }
sdist = { url = "https://files.pythonhosted.org/packages/20/e7/b3c6afdd984672b55dff07482699c688af6c01bd7fd5dd55f9c9d1a88d1c/flask_cors-6.0.0.tar.gz", hash = "sha256:4592c1570246bf7beee96b74bc0adbbfcb1b0318f6ba05c412e8909eceec3393", size = 11875 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/85/61/4aea5fb55be1b6f95e604627dc6c50c47d693e39cab2ac086ee0155a0abd/flask_cors-5.0.1-py3-none-any.whl", hash = "sha256:fa5cb364ead54bbf401a26dbf03030c6b18fb2fcaf70408096a572b409586b0c", size = 11296 },
{ url = "https://files.pythonhosted.org/packages/ba/f0/0ee29090016345938f016ee98aa8b5de1c500ee93491dc0c76495848fca1/flask_cors-6.0.0-py3-none-any.whl", hash = "sha256:6332073356452343a8ccddbfec7befdc3fdd040141fe776ec9b94c262f058657", size = 11549 },
]
[[package]]

@ -1,4 +1,4 @@
import { useCallback, useEffect } from 'react'
import { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import ConditionValueMethod from './condition-value-method'
import type { ConditionValueMethodProps } from './condition-value-method'
@ -11,14 +11,17 @@ import type {
} from '@/app/components/workflow/types'
import { VarType } from '@/app/components/workflow/types'
import Input from '@/app/components/base/input'
import type { MetadataFilteringVariableType } from '@/app/components/workflow/nodes/knowledge-retrieval/types'
type ConditionArrayProps = {
value?: string | string[] | (string | number)[]
value?: string | string[] | (string | number)[] | number
onChange: (value?: string | string[] | (string | number)[]) => void
nodesOutputVars: NodeOutPutVar[]
availableNodes: Node[]
isCommonVariable?: boolean
commonVariables: { name: string, type: string }[]
fieldType?: MetadataFilteringVariableType
strictTypeChecking?: boolean
} & ConditionValueMethodProps
const ConditionArray = ({
@ -30,22 +33,24 @@ const ConditionArray = ({
availableNodes,
isCommonVariable,
commonVariables,
fieldType,
strictTypeChecking = false,
}: ConditionArrayProps) => {
const { t } = useTranslation()
const parseValueSelector = useCallback((value?: string | string[] | (string | number)[]): string[] => {
const parseValueSelector = useCallback((value?: string | string[] | (string | number)[] | number): string[] => {
if (typeof value !== 'string')
return []
// 支持多种格式:
// 1. {{#nodeId.variable#}} 格式
// Support multiple formats:
// 1. {{#nodeId.variable#}} format
if (value.includes('#')) {
const match = value.match(/\{\{#([^#]+)#\}\}/)
if (match && match[1])
return match[1].split('.')
}
// 2. nodeId.variable 格式(直接格式)
// 2. nodeId.variable format (direct format)
if (value.includes('.'))
return value.split('.')
@ -54,27 +59,55 @@ const ConditionArray = ({
const currentValueSelector = parseValueSelector(value)
useEffect(() => {
console.log('🔍 ConditionArray Debug:')
console.log(' - valueMethod:', valueMethod)
console.log(' - isCommonVariable:', isCommonVariable)
console.log(' - value:', value)
console.log(' - currentValueSelector:', currentValueSelector)
console.log(' - nodesOutputVars (数组变量):', nodesOutputVars)
console.log(' - availableNodes:', availableNodes)
console.log(' - commonVariables (通用数组变量):', commonVariables)
}, [valueMethod, isCommonVariable, value, currentValueSelector, nodesOutputVars, availableNodes, commonVariables])
const handleVariableValueChange = useCallback((v: ValueSelector) => {
console.log('🔧 数组变量被选择:', v)
onChange(`{{#${v.join('.')}#}}`)
}, [onChange])
const handleCommonVariableValueChange = useCallback((v: string) => {
console.log('🔧 通用数组变量被选择:', v)
onChange(`{{${v}}}`)
}, [onChange])
// Type compatibility check
const checkTypeCompatibility = useCallback((selectedVariable: any) => {
if (!fieldType || !selectedVariable) return null
// Get variable type
const variableType = selectedVariable.type || selectedVariable.value_type
// Define compatibility rules
const compatibilityRules: Record<string, string[]> = {
string: ['array[string]', 'array', 'string'],
number: ['array[number]', 'array', 'number'],
select: ['array[string]', 'array', 'string'],
array: ['array[string]', 'array[number]', 'array[object]', 'array'],
time: ['array[string]', 'array', 'string'], // Time field compatibility
}
const compatibleTypes = compatibilityRules[fieldType as string] || []
if (!compatibleTypes.includes(variableType)) {
return {
warning: true,
message: `⚠️ Type mismatch: ${fieldType} field is not recommended to use ${variableType} type variables`,
}
}
return null
}, [fieldType])
// Check if currently selected variable is compatible
const typeCompatibilityCheck = useMemo(() => {
if (valueMethod === 'variable' && currentValueSelector.length > 0) {
// Find currently selected variable information
const selectedVar = nodesOutputVars.find(nodeVar =>
nodeVar.nodeId === currentValueSelector[0],
)?.vars.find(v => v.variable === currentValueSelector[1])
return checkTypeCompatibility(selectedVar)
}
return null
}, [valueMethod, currentValueSelector, nodesOutputVars, checkTypeCompatibility])
const handleConstantValueChange = useCallback((inputValue: string) => {
// Parse comma-separated values into array
if (inputValue.trim() === '') {
@ -87,26 +120,25 @@ const ConditionArray = ({
const trimmed = item.trim()
if (trimmed === '') return null
// Try to convert to number if it's a valid number (only if it looks like a pure numeric value)
// Keep natural type detection: pure numbers auto-convert to numbers, otherwise keep as strings
if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
const numericValue = Number(trimmed)
if (!isNaN(numericValue) && isFinite(numericValue))
return numericValue
}
// Otherwise keep as string (remove quotes if present)
// Remove quotes (if any) and keep as string
return trimmed.replace(/^["']|["']$/g, '')
}).filter(item => item !== null)
console.log('🔧 常量数组值被设置:', arrayValues)
console.log('🔧 数组类型检测:', arrayValues.map(v => typeof v))
onChange(arrayValues)
}, [onChange])
const displayValue = Array.isArray(value) ? value.map(v => String(v)).join(', ') : (value || '')
// Filter available variables to show only array types
const filteredNodesOutputVars = nodesOutputVars.filter(nodeVar =>
// Filter variables based on strict mode
const filteredNodesOutputVars = useMemo(() => {
const basicFilter = nodesOutputVars.filter(nodeVar =>
nodeVar.vars.some(v =>
v.type === VarType.arrayString
|| v.type === VarType.arrayNumber
@ -117,11 +149,35 @@ const ConditionArray = ({
),
)
const filteredCommonVariables = commonVariables.filter(v =>
if (!strictTypeChecking || !fieldType)
return basicFilter
// Strict mode: only show type-compatible variables
return basicFilter.map(nodeVar => ({
...nodeVar,
vars: nodeVar.vars.filter((v) => {
const typeCheck = checkTypeCompatibility(v)
return !typeCheck?.warning
}),
})).filter(nodeVar => nodeVar.vars.length > 0)
}, [nodesOutputVars, strictTypeChecking, fieldType, checkTypeCompatibility])
const filteredCommonVariables = useMemo(() => {
const basicFilter = commonVariables.filter(v =>
v.type === 'array'
|| v.type.startsWith('array'),
)
if (!strictTypeChecking || !fieldType)
return basicFilter
// Strict mode: only show type-compatible variables
return basicFilter.filter((v) => {
const typeCheck = checkTypeCompatibility(v)
return !typeCheck?.warning
})
}, [commonVariables, strictTypeChecking, fieldType, checkTypeCompatibility])
return (
<div className='flex h-8 items-center pl-1 pr-2'>
<ConditionValueMethod
@ -131,6 +187,7 @@ const ConditionArray = ({
<div className='ml-1 mr-1.5 h-4 w-[1px] bg-divider-regular'></div>
{
valueMethod === 'variable' && !isCommonVariable && (
<div className='flex-1'>
<ConditionVariableSelector
valueSelector={currentValueSelector}
onChange={handleVariableValueChange}
@ -138,16 +195,29 @@ const ConditionArray = ({
availableNodes={availableNodes}
varType='array'
/>
{typeCompatibilityCheck?.warning && (
<div className='mt-1 text-xs text-text-warning'>
{typeCompatibilityCheck.message}
</div>
)}
</div>
)
}
{
valueMethod === 'variable' && isCommonVariable && (
<div className='flex-1'>
<ConditionCommonVariableSelector
variables={filteredCommonVariables}
value={typeof value === 'string' ? value : ''}
onChange={handleCommonVariableValueChange}
varType={VarType.array}
/>
{typeCompatibilityCheck?.warning && (
<div className='mt-1 text-xs text-text-warning'>
{typeCompatibilityCheck.message}
</div>
)}
</div>
)
}
{

@ -218,6 +218,8 @@ const ConditionItem = ({
onChange={handleValueChange}
isCommonVariable={isCommonVariable}
commonVariables={availableCommonArrayVars}
fieldType={currentMetadata?.type}
strictTypeChecking={false}
/>
)
}

Loading…
Cancel
Save