markdown-flow 0.2.7__tar.gz → 0.2.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of markdown-flow might be problematic. Click here for more details.
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/PKG-INFO +1 -1
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/markdown_flow/__init__.py +1 -1
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/markdown_flow/core.py +85 -30
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/markdown_flow.egg-info/PKG-INFO +1 -1
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/tests/test_dynamic_interaction.py +304 -22
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/LICENSE +0 -0
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/README.md +0 -0
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/markdown_flow/constants.py +0 -0
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/markdown_flow/enums.py +0 -0
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/markdown_flow/exceptions.py +0 -0
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/markdown_flow/llm.py +0 -0
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/markdown_flow/models.py +0 -0
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/markdown_flow/utils.py +0 -0
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/markdown_flow.egg-info/SOURCES.txt +0 -0
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/markdown_flow.egg-info/dependency_links.txt +0 -0
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/markdown_flow.egg-info/top_level.txt +0 -0
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/pyproject.toml +0 -0
- {markdown_flow-0.2.7 → markdown_flow-0.2.8}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: markdown-flow
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: An agent library designed to parse and process MarkdownFlow documents
|
|
5
5
|
Project-URL: Homepage, https://github.com/ai-shifu/markdown-flow-agent-py
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/ai-shifu/markdown-flow-agent-py/issues
|
|
@@ -1066,47 +1066,102 @@ Analyze the content and provide the structured interaction data.""")
|
|
|
1066
1066
|
context: list[dict[str, str]] | None,
|
|
1067
1067
|
variables: dict[str, str | list[str]] | None,
|
|
1068
1068
|
) -> LLMResult:
|
|
1069
|
-
"""Validate user input for dynamically generated interaction blocks."""
|
|
1069
|
+
"""Validate user input for dynamically generated interaction blocks using same logic as normal interactions."""
|
|
1070
1070
|
_ = block_index # Mark as intentionally unused
|
|
1071
|
-
_ = mode # Mark as intentionally unused
|
|
1072
1071
|
_ = context # Mark as intentionally unused
|
|
1073
1072
|
|
|
1074
1073
|
from .utils import InteractionParser
|
|
1075
1074
|
|
|
1076
|
-
# Parse the interaction format
|
|
1075
|
+
# Parse the interaction format using the same parser as normal interactions
|
|
1077
1076
|
parser = InteractionParser()
|
|
1078
|
-
|
|
1077
|
+
parse_result = parser.parse(interaction_format)
|
|
1079
1078
|
|
|
1080
|
-
if
|
|
1081
|
-
|
|
1079
|
+
if "error" in parse_result:
|
|
1080
|
+
error_msg = f"Invalid interaction format: {parse_result['error']}"
|
|
1081
|
+
return self._render_error(error_msg, mode)
|
|
1082
1082
|
|
|
1083
|
-
# Extract variable name
|
|
1084
|
-
|
|
1085
|
-
|
|
1083
|
+
# Extract variable name and interaction type
|
|
1084
|
+
variable_name = parse_result.get("variable")
|
|
1085
|
+
interaction_type = parse_result.get("type")
|
|
1086
1086
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1087
|
+
if not variable_name:
|
|
1088
|
+
error_msg = f"No variable found in interaction format: {interaction_format}"
|
|
1089
|
+
return self._render_error(error_msg, mode)
|
|
1090
1090
|
|
|
1091
|
-
|
|
1091
|
+
# Get user input for the target variable
|
|
1092
|
+
target_values = user_input.get(variable_name, [])
|
|
1092
1093
|
|
|
1093
|
-
#
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1094
|
+
# Basic validation - check if input is provided when required
|
|
1095
|
+
if not target_values:
|
|
1096
|
+
# Check if this is a text input or allows empty input
|
|
1097
|
+
allow_text_input = interaction_type in [
|
|
1098
|
+
InteractionType.BUTTONS_WITH_TEXT,
|
|
1099
|
+
InteractionType.BUTTONS_MULTI_WITH_TEXT,
|
|
1100
|
+
]
|
|
1097
1101
|
|
|
1098
|
-
|
|
1099
|
-
|
|
1102
|
+
if allow_text_input:
|
|
1103
|
+
# Allow empty input for buttons+text mode - merge with existing variables
|
|
1104
|
+
merged_variables = dict(variables or {})
|
|
1105
|
+
merged_variables[variable_name] = []
|
|
1106
|
+
return LLMResult(
|
|
1107
|
+
content="",
|
|
1108
|
+
variables=merged_variables,
|
|
1109
|
+
metadata={
|
|
1110
|
+
"interaction_type": "dynamic_interaction",
|
|
1111
|
+
"empty_input": True,
|
|
1112
|
+
},
|
|
1113
|
+
)
|
|
1114
|
+
else:
|
|
1115
|
+
error_msg = f"No input provided for variable '{variable_name}'"
|
|
1116
|
+
return self._render_error(error_msg, mode)
|
|
1100
1117
|
|
|
1101
|
-
#
|
|
1102
|
-
if
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1118
|
+
# Use the same validation logic as normal interactions
|
|
1119
|
+
if interaction_type in [
|
|
1120
|
+
InteractionType.BUTTONS_ONLY,
|
|
1121
|
+
InteractionType.BUTTONS_WITH_TEXT,
|
|
1122
|
+
InteractionType.BUTTONS_MULTI_SELECT,
|
|
1123
|
+
InteractionType.BUTTONS_MULTI_WITH_TEXT,
|
|
1124
|
+
]:
|
|
1125
|
+
# Button validation - reuse the existing button validation logic
|
|
1126
|
+
button_result = self._process_button_validation(
|
|
1127
|
+
parse_result,
|
|
1128
|
+
target_values,
|
|
1129
|
+
variable_name,
|
|
1130
|
+
mode,
|
|
1131
|
+
interaction_type,
|
|
1132
|
+
)
|
|
1106
1133
|
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1134
|
+
# Merge with existing variables for dynamic interactions
|
|
1135
|
+
if hasattr(button_result, 'variables') and variables:
|
|
1136
|
+
merged_variables = dict(variables)
|
|
1137
|
+
merged_variables.update(button_result.variables)
|
|
1138
|
+
return LLMResult(
|
|
1139
|
+
content=button_result.content,
|
|
1140
|
+
variables=merged_variables,
|
|
1141
|
+
metadata=button_result.metadata,
|
|
1142
|
+
)
|
|
1143
|
+
return button_result
|
|
1144
|
+
|
|
1145
|
+
elif interaction_type == InteractionType.NON_ASSIGNMENT_BUTTON:
|
|
1146
|
+
# Non-assignment buttons: don't set variables, keep existing ones
|
|
1147
|
+
return LLMResult(
|
|
1148
|
+
content="",
|
|
1149
|
+
variables=dict(variables or {}),
|
|
1150
|
+
metadata={
|
|
1151
|
+
"interaction_type": "non_assignment_button",
|
|
1152
|
+
"user_input": user_input,
|
|
1153
|
+
},
|
|
1154
|
+
)
|
|
1155
|
+
else:
|
|
1156
|
+
# Text-only input type - merge with existing variables
|
|
1157
|
+
merged_variables = dict(variables or {})
|
|
1158
|
+
merged_variables[variable_name] = target_values
|
|
1159
|
+
return LLMResult(
|
|
1160
|
+
content="",
|
|
1161
|
+
variables=merged_variables,
|
|
1162
|
+
metadata={
|
|
1163
|
+
"interaction_type": "text_only",
|
|
1164
|
+
"target_variable": variable_name,
|
|
1165
|
+
"values": target_values,
|
|
1166
|
+
},
|
|
1167
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: markdown-flow
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: An agent library designed to parse and process MarkdownFlow documents
|
|
5
5
|
Project-URL: Homepage, https://github.com/ai-shifu/markdown-flow-agent-py
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/ai-shifu/markdown-flow-agent-py/issues
|
|
@@ -49,20 +49,66 @@ def test_chinese_restaurant_scenario():
|
|
|
49
49
|
print(f"生成的交互格式: {result1.content}")
|
|
50
50
|
|
|
51
51
|
if result1.transformed_to_interaction:
|
|
52
|
-
#
|
|
53
|
-
print("\n---
|
|
52
|
+
# 验证交互格式正确性
|
|
53
|
+
print("\n--- 验证交互格式 ---")
|
|
54
|
+
assert "?[" in result1.content, "交互格式应该包含 ?["
|
|
55
|
+
assert "%{{菜品选择}}" in result1.content, "应该包含变量名"
|
|
56
|
+
print("✅ 交互格式验证通过")
|
|
57
|
+
|
|
58
|
+
# 验证是否为多选格式
|
|
59
|
+
is_multi_select = "||" in result1.content
|
|
60
|
+
print(f"多选格式: {is_multi_select}")
|
|
61
|
+
if is_multi_select:
|
|
62
|
+
print("✅ 正确识别为多选场景")
|
|
63
|
+
|
|
64
|
+
# 第二步:测试有效选择
|
|
65
|
+
print("\n--- 测试有效选择 ---")
|
|
54
66
|
user_choices = ["宫保鸡丁", "麻婆豆腐"] # 模拟用户多选
|
|
55
|
-
|
|
56
67
|
result2 = mf.process(
|
|
57
68
|
block_index=0,
|
|
58
69
|
mode=ProcessMode.COMPLETE,
|
|
59
70
|
user_input={"菜品选择": user_choices},
|
|
60
71
|
dynamic_interaction_format=result1.content
|
|
61
72
|
)
|
|
62
|
-
|
|
63
73
|
print(f"用户选择: {user_choices}")
|
|
64
74
|
print(f"验证后的变量: {result2.variables}")
|
|
65
|
-
|
|
75
|
+
assert result2.variables.get("菜品选择") == user_choices, "变量应该正确存储用户选择"
|
|
76
|
+
print("✅ 有效选择验证通过")
|
|
77
|
+
|
|
78
|
+
# 第三步:测试无效选择
|
|
79
|
+
print("\n--- 测试无效选择 ---")
|
|
80
|
+
try:
|
|
81
|
+
invalid_choices = ["意大利面", "汉堡包"] # 不在选项中的选择
|
|
82
|
+
result3 = mf.process(
|
|
83
|
+
block_index=0,
|
|
84
|
+
mode=ProcessMode.COMPLETE,
|
|
85
|
+
user_input={"菜品选择": invalid_choices},
|
|
86
|
+
dynamic_interaction_format=result1.content
|
|
87
|
+
)
|
|
88
|
+
if hasattr(result3, 'content') and result3.content and "Invalid" in result3.content:
|
|
89
|
+
print("✅ 正确处理无效选择")
|
|
90
|
+
else:
|
|
91
|
+
print("⚠️ 可能允许了无效选择")
|
|
92
|
+
except Exception as e:
|
|
93
|
+
print(f"✅ 正确拒绝无效选择: {str(e)[:50]}...")
|
|
94
|
+
|
|
95
|
+
# 第四步:测试空输入
|
|
96
|
+
print("\n--- 测试空输入 ---")
|
|
97
|
+
try:
|
|
98
|
+
result4 = mf.process(
|
|
99
|
+
block_index=0,
|
|
100
|
+
mode=ProcessMode.COMPLETE,
|
|
101
|
+
user_input={"菜品选择": []},
|
|
102
|
+
dynamic_interaction_format=result1.content
|
|
103
|
+
)
|
|
104
|
+
if hasattr(result4, 'content') and result4.content:
|
|
105
|
+
print("⚠️ 空输入可能被接受(取决于交互类型)")
|
|
106
|
+
else:
|
|
107
|
+
print("✅ 正确处理空输入")
|
|
108
|
+
except Exception as e:
|
|
109
|
+
print(f"✅ 正确处理空输入错误: {str(e)[:50]}...")
|
|
110
|
+
|
|
111
|
+
print("✅ 中文餐厅场景完整验证通过")
|
|
66
112
|
|
|
67
113
|
except Exception as e:
|
|
68
114
|
print(f"❌ 测试失败: {e}")
|
|
@@ -101,19 +147,61 @@ Format: Provide specific educational options"""
|
|
|
101
147
|
print(f"Generated interaction format: {result1.content}")
|
|
102
148
|
|
|
103
149
|
if result1.transformed_to_interaction:
|
|
104
|
-
#
|
|
105
|
-
print("\n---
|
|
106
|
-
|
|
150
|
+
# 验证交互格式正确性
|
|
151
|
+
print("\n--- Validate Interaction Format ---")
|
|
152
|
+
assert "?[" in result1.content, "Should contain ?["
|
|
153
|
+
assert "%{{learning_choice}}" in result1.content, "Should contain variable name"
|
|
154
|
+
print("✅ Interaction format validated")
|
|
155
|
+
|
|
156
|
+
# 验证英文选项内容
|
|
157
|
+
has_english_content = any(word in result1.content for word in ["Computer", "Science", "Online", "Business"])
|
|
158
|
+
if has_english_content:
|
|
159
|
+
print("✅ Generated English content as requested")
|
|
160
|
+
else:
|
|
161
|
+
print("⚠️ May not contain expected English content")
|
|
107
162
|
|
|
163
|
+
# 第二步:测试有效选择
|
|
164
|
+
print("\n--- Test Valid Selection ---")
|
|
165
|
+
user_choices = ["Computer Science", "Online"] # 模拟用户选择
|
|
108
166
|
result2 = mf.process(
|
|
109
167
|
block_index=0,
|
|
110
168
|
mode=ProcessMode.COMPLETE,
|
|
111
169
|
user_input={"learning_choice": user_choices},
|
|
112
170
|
dynamic_interaction_format=result1.content
|
|
113
171
|
)
|
|
114
|
-
|
|
115
172
|
print(f"User choices: {user_choices}")
|
|
116
173
|
print(f"Validated variables: {result2.variables}")
|
|
174
|
+
assert result2.variables.get("learning_choice") == user_choices, "Variables should store user selection"
|
|
175
|
+
print("✅ Valid selection validated")
|
|
176
|
+
|
|
177
|
+
# 第三步:测试部分匹配选择
|
|
178
|
+
print("\n--- Test Partial Match ---")
|
|
179
|
+
try:
|
|
180
|
+
partial_choices = ["Computer"] # 只选择一个词
|
|
181
|
+
result3 = mf.process(
|
|
182
|
+
block_index=0,
|
|
183
|
+
mode=ProcessMode.COMPLETE,
|
|
184
|
+
user_input={"learning_choice": partial_choices},
|
|
185
|
+
dynamic_interaction_format=result1.content
|
|
186
|
+
)
|
|
187
|
+
print(f"Partial selection: {partial_choices}")
|
|
188
|
+
print(f"Result: {result3.variables}")
|
|
189
|
+
except Exception as e:
|
|
190
|
+
print(f"Partial selection handling: {str(e)[:50]}...")
|
|
191
|
+
|
|
192
|
+
# 第四步:测试单个选择
|
|
193
|
+
print("\n--- Test Single Selection ---")
|
|
194
|
+
single_choice = ["Business"]
|
|
195
|
+
result4 = mf.process(
|
|
196
|
+
block_index=0,
|
|
197
|
+
mode=ProcessMode.COMPLETE,
|
|
198
|
+
user_input={"learning_choice": single_choice},
|
|
199
|
+
dynamic_interaction_format=result1.content
|
|
200
|
+
)
|
|
201
|
+
expected_value = single_choice[0] if len(single_choice) == 1 else single_choice
|
|
202
|
+
actual_value = result4.variables.get("learning_choice")
|
|
203
|
+
print(f"Single choice: {single_choice}")
|
|
204
|
+
print(f"Stored as: {actual_value}")
|
|
117
205
|
print("✅ English education scenario completed")
|
|
118
206
|
|
|
119
207
|
except Exception as e:
|
|
@@ -153,6 +241,14 @@ def test_japanese_fitness_scenario():
|
|
|
153
241
|
print(f"生成されたインタラクション形式: {result1.content}")
|
|
154
242
|
|
|
155
243
|
if result1.transformed_to_interaction:
|
|
244
|
+
# 验证日文内容
|
|
245
|
+
japanese_exercises = ["ランニング", "水泳", "ヨガ", "ウェイト"]
|
|
246
|
+
has_japanese_content = any(exercise in result1.content for exercise in japanese_exercises)
|
|
247
|
+
if has_japanese_content:
|
|
248
|
+
print("✅ 生成了日文运动选项")
|
|
249
|
+
else:
|
|
250
|
+
print("⚠️ 可能未生成预期的日文内容")
|
|
251
|
+
|
|
156
252
|
# 第二步:用户选择运动
|
|
157
253
|
print("\n--- ユーザー選択 ---")
|
|
158
254
|
user_choices = ["ランニング", "ヨガ"] # 模拟用户选择
|
|
@@ -166,6 +262,7 @@ def test_japanese_fitness_scenario():
|
|
|
166
262
|
|
|
167
263
|
print(f"ユーザー選択: {user_choices}")
|
|
168
264
|
print(f"検証後の変数: {result2.variables}")
|
|
265
|
+
assert result2.variables.get("運動選択") == user_choices, "变量应该正确存储"
|
|
169
266
|
print("✅ 日本語フィットネスシナリオ完了")
|
|
170
267
|
|
|
171
268
|
except Exception as e:
|
|
@@ -205,6 +302,14 @@ def test_korean_travel_scenario():
|
|
|
205
302
|
print(f"생성된 인터랙션 형식: {result1.content}")
|
|
206
303
|
|
|
207
304
|
if result1.transformed_to_interaction:
|
|
305
|
+
# 验证韩文内容
|
|
306
|
+
korean_travel = ["휴양", "문화탐방", "호텔", "펜션"]
|
|
307
|
+
has_korean_content = any(option in result1.content for option in korean_travel)
|
|
308
|
+
if has_korean_content:
|
|
309
|
+
print("✅ 생성된 한국어 여행 옵션")
|
|
310
|
+
else:
|
|
311
|
+
print("⚠️ 예상된 한국어 콘텐츠가 생성되지 않았을 수 있음")
|
|
312
|
+
|
|
208
313
|
# 第二步:用户选择旅游选项
|
|
209
314
|
print("\n--- 사용자 선택 ---")
|
|
210
315
|
user_choices = ["문화탐방", "호텔"] # 模拟用户选择
|
|
@@ -218,6 +323,7 @@ def test_korean_travel_scenario():
|
|
|
218
323
|
|
|
219
324
|
print(f"사용자 선택: {user_choices}")
|
|
220
325
|
print(f"검증된 변수: {result2.variables}")
|
|
326
|
+
assert result2.variables.get("여행선택") == user_choices, "변수가 올바르게 저장되어야 함"
|
|
221
327
|
print("✅ 한국어 여행 시나리오 완료")
|
|
222
328
|
|
|
223
329
|
except Exception as e:
|
|
@@ -279,6 +385,15 @@ def test_complex_job_consultation_scenario():
|
|
|
279
385
|
print(f"职位选项: {result2.content}")
|
|
280
386
|
|
|
281
387
|
if result2.transformed_to_interaction:
|
|
388
|
+
# 验证职位选项是否基于行业生成
|
|
389
|
+
print("\n--- 验证职位选项上下文相关性 ---")
|
|
390
|
+
tech_jobs = ["软件工程师", "数据科学家", "产品经理", "工程师"]
|
|
391
|
+
has_tech_jobs = any(job in result2.content for job in tech_jobs)
|
|
392
|
+
if has_tech_jobs:
|
|
393
|
+
print("✅ 正确基于'科技'行业生成了相关职位")
|
|
394
|
+
else:
|
|
395
|
+
print("⚠️ 可能未正确基于行业上下文生成职位")
|
|
396
|
+
|
|
282
397
|
# 第三步:用户选择职位
|
|
283
398
|
print("\n--- 步骤3: 用户选择职位 ---")
|
|
284
399
|
job_choices = ["软件工程师", "数据科学家"]
|
|
@@ -292,6 +407,28 @@ def test_complex_job_consultation_scenario():
|
|
|
292
407
|
print(f"用户选择职位: {job_choices}")
|
|
293
408
|
print(f"第二步变量: {result3.variables}")
|
|
294
409
|
|
|
410
|
+
# 验证职位选择验证
|
|
411
|
+
assert result3.variables.get("职位选择") == job_choices, "职位变量应该正确存储"
|
|
412
|
+
assert result3.variables.get("行业") == ["科技"], "行业变量应该保持不变"
|
|
413
|
+
print("✅ 职位选择验证通过")
|
|
414
|
+
|
|
415
|
+
# 测试无效职位选择
|
|
416
|
+
print("\n--- 测试无效职位选择 ---")
|
|
417
|
+
try:
|
|
418
|
+
invalid_job = ["厨师", "司机"] # 不属于科技行业的职位
|
|
419
|
+
result_invalid = mf.process(
|
|
420
|
+
block_index=1,
|
|
421
|
+
mode=ProcessMode.COMPLETE,
|
|
422
|
+
variables=result1.variables,
|
|
423
|
+
user_input={"职位选择": invalid_job},
|
|
424
|
+
dynamic_interaction_format=result2.content
|
|
425
|
+
)
|
|
426
|
+
print("⚠️ 无效职位选择可能被接受")
|
|
427
|
+
# 避免未使用变量警告
|
|
428
|
+
_ = result_invalid
|
|
429
|
+
except Exception as e:
|
|
430
|
+
print(f"✅ 正确拒绝无效职位选择: {str(e)[:50]}...")
|
|
431
|
+
|
|
295
432
|
# 第四步:生成薪资选项
|
|
296
433
|
print("\n--- 步骤4: 生成薪资选项 ---")
|
|
297
434
|
result4 = mf.process(
|
|
@@ -303,6 +440,17 @@ def test_complex_job_consultation_scenario():
|
|
|
303
440
|
print(f"薪资选项: {result4.content}")
|
|
304
441
|
|
|
305
442
|
if result4.transformed_to_interaction:
|
|
443
|
+
# 验证薪资选项格式
|
|
444
|
+
salary_ranges = ["5-10万", "10-20万", "20-30万", "30万"]
|
|
445
|
+
has_salary_ranges = any(salary in result4.content for salary in salary_ranges)
|
|
446
|
+
if has_salary_ranges:
|
|
447
|
+
print("✅ 生成了预期的薪资范围选项")
|
|
448
|
+
|
|
449
|
+
# 验证是否为单选(薪资期望通常是单选)
|
|
450
|
+
is_single_select = "||" not in result4.content and "|" in result4.content
|
|
451
|
+
if is_single_select:
|
|
452
|
+
print("✅ 正确识别薪资选择为单选模式")
|
|
453
|
+
|
|
306
454
|
# 第五步:用户选择薪资期望
|
|
307
455
|
print("\n--- 步骤5: 用户选择薪资期望 ---")
|
|
308
456
|
salary_choice = ["20-30万"]
|
|
@@ -315,7 +463,15 @@ def test_complex_job_consultation_scenario():
|
|
|
315
463
|
)
|
|
316
464
|
print(f"用户选择薪资: {salary_choice}")
|
|
317
465
|
print(f"最终变量: {result5.variables}")
|
|
318
|
-
|
|
466
|
+
|
|
467
|
+
# 验证最终变量完整性
|
|
468
|
+
expected_vars = ["行业", "职位选择", "薪资期望"]
|
|
469
|
+
for var in expected_vars:
|
|
470
|
+
assert var in result5.variables, f"最终结果应该包含变量: {var}"
|
|
471
|
+
|
|
472
|
+
# 避免未使用变量警告
|
|
473
|
+
_ = result5
|
|
474
|
+
print("✅ 复杂职业咨询场景完整验证通过")
|
|
319
475
|
|
|
320
476
|
except Exception as e:
|
|
321
477
|
print(f"❌ 测试失败: {e}")
|
|
@@ -353,8 +509,22 @@ def test_text_input_scenario():
|
|
|
353
509
|
print(f"生成的选项: {result1.content}")
|
|
354
510
|
|
|
355
511
|
if result1.transformed_to_interaction:
|
|
512
|
+
# 验证混合输入格式(按钮+文本)
|
|
513
|
+
print("\n--- 验证混合输入格式 ---")
|
|
514
|
+
has_buttons = "|" in result1.content
|
|
515
|
+
has_text_input = "..." in result1.content
|
|
516
|
+
print(f"包含按钮: {has_buttons}")
|
|
517
|
+
print(f"包含文本输入: {has_text_input}")
|
|
518
|
+
|
|
519
|
+
if has_buttons and has_text_input:
|
|
520
|
+
print("✅ 正确生成混合输入格式(按钮+文本)")
|
|
521
|
+
elif has_buttons:
|
|
522
|
+
print("⚠️ 只有按钮选项,没有文本输入选项")
|
|
523
|
+
else:
|
|
524
|
+
print("⚠️ 格式可能不符合预期")
|
|
525
|
+
|
|
356
526
|
# 测试预设选项选择
|
|
357
|
-
print("\n---
|
|
527
|
+
print("\n--- 测试预设按钮选择 ---")
|
|
358
528
|
preset_choices = ["定制颜色", "个性化logo"]
|
|
359
529
|
result2 = mf.process(
|
|
360
530
|
block_index=0,
|
|
@@ -364,9 +534,11 @@ def test_text_input_scenario():
|
|
|
364
534
|
)
|
|
365
535
|
print(f"预设选项: {preset_choices}")
|
|
366
536
|
print(f"验证后的变量: {result2.variables}")
|
|
537
|
+
assert result2.variables.get("自定义需求") == preset_choices, "应该正确存储预设选项"
|
|
538
|
+
print("✅ 预设选项验证通过")
|
|
367
539
|
|
|
368
|
-
#
|
|
369
|
-
print("\n---
|
|
540
|
+
# 测试自定义文本输入
|
|
541
|
+
print("\n--- 测试自定义文本输入 ---")
|
|
370
542
|
custom_input = ["需要特殊的防水涂层处理"]
|
|
371
543
|
result3 = mf.process(
|
|
372
544
|
block_index=0,
|
|
@@ -376,7 +548,37 @@ def test_text_input_scenario():
|
|
|
376
548
|
)
|
|
377
549
|
print(f"自定义输入: {custom_input}")
|
|
378
550
|
print(f"验证后的变量: {result3.variables}")
|
|
379
|
-
|
|
551
|
+
assert result3.variables.get("自定义需求") == custom_input, "应该正确存储自定义文本"
|
|
552
|
+
print("✅ 自定义文本验证通过")
|
|
553
|
+
|
|
554
|
+
# 测试混合选择(按钮+自定义)
|
|
555
|
+
print("\n--- 测试混合选择 ---")
|
|
556
|
+
mixed_input = ["定制颜色", "需要增加夜光效果"] # 一个按钮选项+一个自定义
|
|
557
|
+
result4 = mf.process(
|
|
558
|
+
block_index=0,
|
|
559
|
+
mode=ProcessMode.COMPLETE,
|
|
560
|
+
user_input={"自定义需求": mixed_input},
|
|
561
|
+
dynamic_interaction_format=result1.content
|
|
562
|
+
)
|
|
563
|
+
print(f"混合输入: {mixed_input}")
|
|
564
|
+
print(f"验证后的变量: {result4.variables}")
|
|
565
|
+
assert result4.variables.get("自定义需求") == mixed_input, "应该正确存储混合输入"
|
|
566
|
+
print("✅ 混合选择验证通过")
|
|
567
|
+
|
|
568
|
+
# 测试空输入(对于支持文本输入的交互,可能允许空输入)
|
|
569
|
+
print("\n--- 测试空输入处理 ---")
|
|
570
|
+
try:
|
|
571
|
+
result5 = mf.process(
|
|
572
|
+
block_index=0,
|
|
573
|
+
mode=ProcessMode.COMPLETE,
|
|
574
|
+
user_input={"自定义需求": []},
|
|
575
|
+
dynamic_interaction_format=result1.content
|
|
576
|
+
)
|
|
577
|
+
print("✅ 空输入被接受(支持文本输入的交互可能允许空输入)")
|
|
578
|
+
except Exception as e:
|
|
579
|
+
print(f"空输入被拒绝: {str(e)[:50]}...")
|
|
580
|
+
|
|
581
|
+
print("✅ 文本输入场景完整验证通过")
|
|
380
582
|
|
|
381
583
|
except Exception as e:
|
|
382
584
|
print(f"❌ 测试失败: {e}")
|
|
@@ -433,6 +635,7 @@ def test_variable_context_cuisine_scenario():
|
|
|
433
635
|
|
|
434
636
|
# 验证是否生成了川菜相关的选项
|
|
435
637
|
if result2.transformed_to_interaction:
|
|
638
|
+
print("\n--- 验证上下文相关性 ---")
|
|
436
639
|
sichuan_dishes = ['宫保鸡丁', '麻婆豆腐', '水煮鱼', '回锅肉']
|
|
437
640
|
has_sichuan_dishes = any(dish in result2.content for dish in sichuan_dishes)
|
|
438
641
|
|
|
@@ -442,24 +645,78 @@ def test_variable_context_cuisine_scenario():
|
|
|
442
645
|
print("⚠️ 可能未正确基于菜系上下文生成选项")
|
|
443
646
|
|
|
444
647
|
# 验证是否使用了多选格式
|
|
445
|
-
|
|
446
|
-
|
|
648
|
+
is_multi_select = "||" in result2.content
|
|
649
|
+
if is_multi_select:
|
|
650
|
+
print("✅ 正确识别为多选场景(用户可以选多个菜品)")
|
|
447
651
|
else:
|
|
448
652
|
print("⚠️ 可能未正确识别为多选场景")
|
|
449
653
|
|
|
654
|
+
# 验证变量名正确性
|
|
655
|
+
assert "%{{菜品}}" in result2.content, "应该包含正确的变量名"
|
|
656
|
+
print("✅ 变量名验证通过")
|
|
657
|
+
|
|
450
658
|
# 第三步:用户选择菜品
|
|
451
659
|
print("\n--- 步骤3: 用户选择菜品 ---")
|
|
660
|
+
dish_choices = ["宫保鸡丁", "麻婆豆腐"]
|
|
452
661
|
result3 = mf.process(
|
|
453
662
|
block_index=1,
|
|
454
663
|
mode=ProcessMode.COMPLETE,
|
|
455
664
|
variables=result1.variables,
|
|
456
|
-
user_input={"菜品":
|
|
665
|
+
user_input={"菜品": dish_choices},
|
|
457
666
|
dynamic_interaction_format=result2.content
|
|
458
667
|
)
|
|
459
668
|
|
|
460
|
-
print(f"用户选择菜品:
|
|
669
|
+
print(f"用户选择菜品: {dish_choices}")
|
|
461
670
|
print(f"最终变量: {result3.variables}")
|
|
462
|
-
|
|
671
|
+
|
|
672
|
+
# 验证变量存储正确性
|
|
673
|
+
cuisine_var = result3.variables.get("菜系")
|
|
674
|
+
dish_var = result3.variables.get("菜品")
|
|
675
|
+
|
|
676
|
+
print(f"菜系变量: {cuisine_var}")
|
|
677
|
+
print(f"菜品变量: {dish_var}")
|
|
678
|
+
|
|
679
|
+
# 更宽松的验证 - 菜系可能是字符串或列表
|
|
680
|
+
if cuisine_var == ["川菜"] or cuisine_var == "川菜":
|
|
681
|
+
print("✅ 菜系变量正确保留")
|
|
682
|
+
else:
|
|
683
|
+
print(f"⚠️ 菜系变量格式不符合预期: {cuisine_var}")
|
|
684
|
+
|
|
685
|
+
assert dish_var == dish_choices, "菜品变量应该正确存储"
|
|
686
|
+
assert "菜系" in result3.variables, "应该包含菜系变量"
|
|
687
|
+
assert "菜品" in result3.variables, "应该包含菜品变量"
|
|
688
|
+
print("✅ 变量存储验证通过")
|
|
689
|
+
|
|
690
|
+
# 测试单个菜品选择
|
|
691
|
+
print("\n--- 测试单个菜品选择 ---")
|
|
692
|
+
single_dish = ["宫保鸡丁"]
|
|
693
|
+
result4 = mf.process(
|
|
694
|
+
block_index=1,
|
|
695
|
+
mode=ProcessMode.COMPLETE,
|
|
696
|
+
variables=result1.variables,
|
|
697
|
+
user_input={"菜品": single_dish},
|
|
698
|
+
dynamic_interaction_format=result2.content
|
|
699
|
+
)
|
|
700
|
+
print(f"单个选择结果: {result4.variables.get('菜品')}")
|
|
701
|
+
|
|
702
|
+
# 测试无效菜品选择
|
|
703
|
+
print("\n--- 测试无效菜品选择 ---")
|
|
704
|
+
try:
|
|
705
|
+
invalid_dishes = ["北京烤鸭", "小笼包"] # 非川菜选项
|
|
706
|
+
result_invalid = mf.process(
|
|
707
|
+
block_index=1,
|
|
708
|
+
mode=ProcessMode.COMPLETE,
|
|
709
|
+
variables=result1.variables,
|
|
710
|
+
user_input={"菜品": invalid_dishes},
|
|
711
|
+
dynamic_interaction_format=result2.content
|
|
712
|
+
)
|
|
713
|
+
print("⚠️ 无效菜品选择可能被接受")
|
|
714
|
+
# 避免未使用变量警告
|
|
715
|
+
_ = result_invalid
|
|
716
|
+
except Exception as e:
|
|
717
|
+
print(f"✅ 正确拒绝无效菜品选择: {str(e)[:50]}...")
|
|
718
|
+
|
|
719
|
+
print("✅ 变量上下文场景完整验证通过")
|
|
463
720
|
|
|
464
721
|
except Exception as e:
|
|
465
722
|
print(f"❌ 测试失败: {e}")
|
|
@@ -515,6 +772,7 @@ Format: Provide specific project options based on the selected programming langu
|
|
|
515
772
|
|
|
516
773
|
if result2.transformed_to_interaction:
|
|
517
774
|
# 验证是否生成了Python相关的项目
|
|
775
|
+
print("\n--- Validate Context-Based Project Options ---")
|
|
518
776
|
python_projects = ['scraping', 'analysis', 'learning', 'Django']
|
|
519
777
|
has_python_projects = any(project.lower() in result2.content.lower() for project in python_projects)
|
|
520
778
|
|
|
@@ -523,19 +781,43 @@ Format: Provide specific project options based on the selected programming langu
|
|
|
523
781
|
else:
|
|
524
782
|
print("⚠️ May not have correctly generated context-based options")
|
|
525
783
|
|
|
784
|
+
# 验证多选格式(项目通常可以多选)
|
|
785
|
+
is_multi_select = "||" in result2.content
|
|
786
|
+
if is_multi_select:
|
|
787
|
+
print("✅ Correctly identified as multi-select scenario")
|
|
788
|
+
|
|
526
789
|
# 第三步:用户选择项目
|
|
527
790
|
print("\n--- Step 3: User selects projects ---")
|
|
791
|
+
project_choices = ["Data analysis", "Machine learning"]
|
|
528
792
|
result3 = mf.process(
|
|
529
793
|
block_index=1,
|
|
530
794
|
mode=ProcessMode.COMPLETE,
|
|
531
795
|
variables=result1.variables,
|
|
532
|
-
user_input={"project_type":
|
|
796
|
+
user_input={"project_type": project_choices},
|
|
533
797
|
dynamic_interaction_format=result2.content
|
|
534
798
|
)
|
|
535
799
|
|
|
536
|
-
print(f"User project selection:
|
|
800
|
+
print(f"User project selection: {project_choices}")
|
|
537
801
|
print(f"Final variables: {result3.variables}")
|
|
538
|
-
|
|
802
|
+
|
|
803
|
+
# 验证变量存储
|
|
804
|
+
assert result3.variables.get("skill") == ["Python"], "Skill should remain unchanged"
|
|
805
|
+
assert result3.variables.get("project_type") == project_choices, "Projects should be stored correctly"
|
|
806
|
+
print("✅ Variable storage validated")
|
|
807
|
+
|
|
808
|
+
# 测试单个项目选择
|
|
809
|
+
print("\n--- Test Single Project Selection ---")
|
|
810
|
+
single_project = ["Web scraping"]
|
|
811
|
+
result4 = mf.process(
|
|
812
|
+
block_index=1,
|
|
813
|
+
mode=ProcessMode.COMPLETE,
|
|
814
|
+
variables=result1.variables,
|
|
815
|
+
user_input={"project_type": single_project},
|
|
816
|
+
dynamic_interaction_format=result2.content
|
|
817
|
+
)
|
|
818
|
+
print(f"Single project result: {result4.variables.get('project_type')}")
|
|
819
|
+
|
|
820
|
+
print("✅ Skill-project scenario validation completed")
|
|
539
821
|
|
|
540
822
|
except Exception as e:
|
|
541
823
|
print(f"❌ Test failed: {e}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|