Skip to content

Commit a9d20d4

Browse files
feat: Display more execution process information of the condition-node in the execution details
1 parent 487ea43 commit a9d20d4

6 files changed

Lines changed: 131 additions & 11 deletions

File tree

apps/application/flow/compare/__init__.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,37 @@ def _compare(source_value, compare, target_value):
6262
return compare_handler.compare(source_value, compare, target_value)
6363

6464

65-
def _assertion(workflow_manage, field_list: List[str], compare: str, value):
65+
def _assertion(workflow_manage, field_list: List[str], compare: str, target_value, condition_details: list = None):
6666
try:
67-
value = workflow_manage.generate_prompt(value)
67+
target_value = workflow_manage.generate_prompt(target_value)
6868
except Exception:
6969
pass
7070
field_value = None
7171
try:
7272
field_value = workflow_manage.get_reference_field(field_list[0], field_list[1:])
7373
except Exception:
7474
pass
75-
return _compare(field_value, compare, value)
7675

76+
result = _compare(field_value, compare, target_value)
7777

78-
def do_assertion(workflow_manage, condition, condition_list):
78+
# condition_details不为None,说明调用端需要分支执行详情,拼接到列表中
79+
if condition_details is not None:
80+
condition_details.append({
81+
'field': field_list,
82+
'field_type': type(field_value).__name__ if field_value is not None else None,
83+
'field_value': field_value,
84+
'compare': compare,
85+
'target_type': type(target_value).__name__ if target_value is not None else None,
86+
'target_value': target_value,
87+
'result': result
88+
})
89+
90+
return result
91+
92+
93+
def do_assertion(workflow_manage, condition, condition_list, condition_details: list = None):
7994
b = False if condition == 'and' else True
8095
for row in condition_list:
81-
if _assertion(workflow_manage, row.get('field'), row.get('compare'), row.get('value')) is b:
96+
if _assertion(workflow_manage, row.get('field'), row.get('compare'), row.get('value'), condition_details) is b:
8297
return b
8398
return not b

apps/application/flow/step_node/condition_node/impl/base_condition_node.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,38 @@ class BaseConditionNode(IConditionNode):
1717
def save_context(self, details, workflow_manage):
1818
self.context['branch_id'] = details.get('branch_id')
1919
self.context['branch_name'] = details.get('branch_name')
20+
self.context['branch_details'] = details.get('branch_details')
2021
self.context['exception_message'] = details.get('err_message')
2122

2223
def execute(self, **kwargs) -> NodeResult:
2324
branch_list = self.node_params_serializer.data['branch']
24-
branch = self._execute(branch_list)
25-
r = NodeResult({'branch_id': branch.get('id'), 'branch_name': branch.get('type')}, {})
25+
branch, branch_details = self._execute(branch_list)
26+
r = NodeResult({
27+
'branch_id': branch.get('id') if branch else None,
28+
'branch_name': branch.get('type') if branch else None,
29+
'branch_details': branch_details
30+
}, {})
2631
return r
2732

2833
def _execute(self, branch_list: List):
34+
branch_details = []
2935
for branch in branch_list:
30-
if self.branch_assertion(branch):
31-
return branch
36+
is_matched, condition_details = self.branch_assertion(branch)
37+
branch_details.append({
38+
'id': branch.get('id'),
39+
'type': branch.get('type'),
40+
'condition_logic': branch.get('condition'),
41+
'is_matched': is_matched,
42+
'conditions': condition_details
43+
})
44+
if is_matched:
45+
return branch, branch_details
46+
return None, branch_details
3247

3348
def branch_assertion(self, branch):
34-
return do_assertion(self.workflow_manage, branch.get('condition'), branch.get('conditions'))
49+
condition_details = []
50+
is_matched = do_assertion(self.workflow_manage, branch.get('condition'), branch.get('conditions'), condition_details)
51+
return is_matched, condition_details
3552

3653
def get_details(self, index: int, **kwargs):
3754
return {
@@ -40,6 +57,7 @@ def get_details(self, index: int, **kwargs):
4057
'run_time': self.context.get('run_time'),
4158
'branch_id': self.context.get('branch_id'),
4259
'branch_name': self.context.get('branch_name'),
60+
'branch_details': self.context.get('branch_details'),
4361
'type': self.node.type,
4462
'status': self.status,
4563
'err_message': self.err_message,

ui/src/components/execution-detail-card/index.vue

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,44 @@
182182
{{ $t('aiChat.executionDetails.conditionResult') }}
183183
</h5>
184184
<div class="p-8-12 border-t-dashed lighter">
185-
{{ data.branch_name || '-' }}
185+
<el-tag type="success" size="small">
186+
{{ data.branch_name || '-' }}
187+
</el-tag>
188+
</div>
189+
</div>
190+
<!-- 判断器执行细节 -->
191+
<div class="card-never border-r-6 mt-8" v-if="data.branch_details && data.branch_details.length > 0" v-for="(branch, bIndex) in data.branch_details" :key="bIndex">
192+
<h5 class="p-8-12">
193+
<span class="min-w-25">
194+
<el-tag :type="branch.is_matched ? 'success' : 'error'" size="small">
195+
{{ branch.type || '-' }}
196+
</el-tag>
197+
<span class="ml-4">{{ $t('aiChat.executionDetails.branchEvaluationDetails') }}</span>
198+
</span>
199+
<span v-if="branch.type !== 'ELSE'">
200+
<span class="color-secondary">{{ $t('workflow.nodes.conditionNode.conditions.info') }}</span>
201+
<el-tag type="warn" size="small" class="ml-4">
202+
{{ branch.condition_logic === 'and' ? $t('workflow.condition.AND') : $t('workflow.condition.OR') }}
203+
</el-tag>
204+
<span class="color-secondary">{{ $t('workflow.nodes.conditionNode.conditions.label') }}</span>
205+
</span>
206+
</h5>
207+
<div v-if="branch.conditions && branch.conditions.length > 0" class="border-t-dashed lighter clean" style="padding: 0 12px 8px 12px">
208+
<div v-for="(cond, cIndex) in branch.conditions" :key="cIndex" class="mt-8">
209+
<el-tag type="warn" size="small" class="f_val" :title="formatValue(cond.field_value, cond.field_type)">
210+
{{ formatValue(cond.field_value, cond.field_type) }}
211+
</el-tag>
212+
<el-tag type="primary" size="small" class="ml-8">{{ getCompareLabel(cond.compare) }}</el-tag>
213+
<el-tag type="warn" size="small" class="f_val"
214+
v-if="!['is_null', 'is_not_null', 'is_true', 'is_not_true', 'is_false', 'is_not_false'].includes(cond.compare)"
215+
>
216+
{{ formatValue(cond.target_value, cond.target_type) }}
217+
</el-tag>
218+
<span class="ml-8">=</span>
219+
<el-tag :type="cond.result ? 'success' : 'danger'" size="small" class="ml-8">
220+
{{ cond.result ? 'True' : 'False' }}
221+
</el-tag>
222+
</div>
186223
</div>
187224
</div>
188225
</template>
@@ -1400,6 +1437,7 @@
14001437
import { ref, computed, type PropType } from 'vue'
14011438
import ParagraphCard from '@/components/ai-chat/component/knowledge-source-component/ParagraphCard.vue'
14021439
import DynamicsForm from '@/components/dynamics-form/index.vue'
1440+
import { compareList } from '@/workflow/common/data'
14031441
import { iconComponent } from '@/workflow/icons/utils'
14041442
import { WorkflowType } from '@/enums/application'
14051443
import { getImgUrl } from '@/utils/common'
@@ -1422,11 +1460,57 @@ const isKnowLedge = computed(() => props.type === 'knowledge')
14221460
const currentLoopNode = ref(0)
14231461
const currentParagraph = ref(0)
14241462
const currentWriteContent = ref(0)
1463+
1464+
// 格式化值显示
1465+
const formatValue = (value: any, value_type: any): string => {
1466+
if (value === null || value === undefined) {
1467+
return 'null'
1468+
}
1469+
if (value === '') {
1470+
return `${value_type}: ""`
1471+
}
1472+
if (typeof value === 'string') {
1473+
return `${value_type}: "${value}"`
1474+
}
1475+
if (Array.isArray(value)) {
1476+
return `${value_type}: ${JSON.stringify(value)}`
1477+
}
1478+
if (typeof value === 'object') {
1479+
return `${value_type}: ${JSON.stringify(value)}`
1480+
}
1481+
return `${value_type}: ${value}`
1482+
}
1483+
1484+
const compareMap: Record<string, string> = compareList.reduce((acc, cur) => {
1485+
acc[cur.value] = cur.label
1486+
return acc
1487+
}, {} as Record<string, string>)
1488+
1489+
// 获取比较操作符标签
1490+
const getCompareLabel = (compare: string): string => {
1491+
return compareMap[compare] || compare
1492+
}
14251493
</script>
14261494
<style lang="scss" scoped>
14271495
.execution-detail-card {
14281496
:deep(.md-editor-previewOnly) {
14291497
background: none !important;
14301498
}
14311499
}
1500+
1501+
.min-w-25 {
1502+
min-width: 38%;
1503+
display: inline-block;
1504+
}
1505+
1506+
.f_val {
1507+
margin-left: 4px;
1508+
max-width: 30%;
1509+
1510+
* {
1511+
overflow: hidden;
1512+
text-overflow: ellipsis;
1513+
white-space: nowrap;
1514+
}
1515+
}
14321516
</style>

ui/src/locales/lang/en-US/ai-chat.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ export default {
109109
searchContent: 'Search Query',
110110
searchResult: 'Search Results',
111111
conditionResult: 'Condition Evaluation',
112+
branchEvaluationDetails: 'Branch Evaluation Details',
112113
currentChat: 'Current Chat',
113114
answer: 'AI Response',
114115
replyContent: 'Reply Content',

ui/src/locales/lang/zh-CN/ai-chat.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export default {
107107
searchContent: '检索内容',
108108
searchResult: '检索结果',
109109
conditionResult: '判断结果',
110+
branchEvaluationDetails: '分支判断详情',
110111
currentChat: '本次对话',
111112
answer: 'AI 回答',
112113
replyContent: '回复内容',

ui/src/locales/lang/zh-Hant/ai-chat.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export default {
107107
searchContent: '檢索內容',
108108
searchResult: '檢索結果',
109109
conditionResult: '判斷結果',
110+
branchEvaluationDetails: '分支判斷詳情',
110111
currentChat: '本次對話',
111112
answer: 'AI 回答',
112113
replyContent: '回覆內容',

0 commit comments

Comments
 (0)