mm_os 4.2.6 → 4.2.7
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.
- package/README.md +1 -1
- package/README_EN.md +2 -2
- package/adapter/adapter.js +105 -52
- package/adapter/custom_persistence.js +32 -31
- package/adapter/mqtt.js +59 -79
- package/adapter/socket.js +188 -58
- package/adapter/web.js +92 -68
- package/adapter/websocket.js +43 -146
- package/com/api/drive.js +732 -708
- package/com/api/index.js +196 -198
- package/com/cmd/config.tpl.json +48 -122
- package/com/cmd/drive.js +176 -1548
- package/com/cmd/index.js +287 -1066
- package/com/cmd/job/config.json +66 -0
- package/com/cmd/job/index.js +241 -0
- package/com/cmd/job/test.js +188 -0
- package/com/cmd/script.tpl.js +12 -33
- package/com/db/drive.js +2206 -2019
- package/com/db/index.js +241 -242
- package/com/event/config.tpl.json +3 -1
- package/com/event/drive.js +3 -1
- package/com/event/index.js +73 -49
- package/com/event/script.tpl.js +1 -1
- package/com/mqtt/config.tpl.json +16 -8
- package/com/mqtt/drive.js +696 -676
- package/com/mqtt/index.js +1012 -822
- package/com/mqtt/index.test.js +503 -0
- package/com/mqtt/mm_mqtt.js +446 -420
- package/com/mqtt/script.tpl.js +3 -7
- package/com/nav/drive.js +7 -7
- package/com/nav/index.js +228 -231
- package/com/param/index.js +19 -17
- package/com/pendant/index.js +467 -441
- package/com/socket/drive.js +679 -616
- package/com/socket/index.js +94 -48
- package/com/sql/drive.js +1283 -1259
- package/com/sql/index.js +152 -150
- package/com/static/drive.js +1 -1
- package/com/static/index.js +232 -226
- package/com/task/drive.js +428 -405
- package/com/task/index.js +154 -148
- package/com/template/drive.js +1 -1
- package/com/template/index.js +141 -138
- package/com.js +87 -6
- package/common/middleware/web_after/index.js +4 -10
- package/common/middleware/web_base/index.js +1 -1
- package/common/middleware/web_cors/index.js +1 -1
- package/common/middleware/web_error/index.js +131 -119
- package/common/middleware/web_error/middleware.json +2 -1
- package/common/middleware/web_logger/index.js +1 -1
- package/common/middleware/web_main/index.js +2 -0
- package/common/middleware/web_static/index.js +2 -2
- package/common/middleware/web_waf/index.js +1 -1
- package/core/app/config.tpl.json +4 -4
- package/core/app/index.js +710 -534
- package/core/middleware/index.js +1 -9
- package/core/mod/config.tpl.json +1 -1
- package/core/model/config.tpl.json +1 -1
- package/core/plugin/config.tpl.json +15 -3
- package/core/plugin/index.js +31 -0
- package/core/pusher/index.js +158 -161
- package/core/scene/loop.js +1306 -1255
- package/core/store/index.js +1794 -1755
- package/core/store/sql.js +1488 -1464
- package/core/zone/bat/index.js +744 -728
- package/core/zone/config.tpl.json +3 -3
- package/core/zone/index.js +655 -616
- package/os.js +0 -4
- package/package.json +16 -16
- package/server.js +583 -427
- package/com/cmd/nlp.js +0 -525
- package/core/app/index copy.js +0 -611
- package/software.js +0 -194
- package/tcp.js +0 -279
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "job",
|
|
3
|
+
"title": "找工作",
|
|
4
|
+
"description": "用户输入求职意向, 登记信息并搜索匹配岗位",
|
|
5
|
+
"main": "./index.js",
|
|
6
|
+
"state": 1,
|
|
7
|
+
"tense": "main",
|
|
8
|
+
"match": ["找工作", "求职", "应聘", "找工作"],
|
|
9
|
+
"not": [],
|
|
10
|
+
"sort": 100,
|
|
11
|
+
"end": 1,
|
|
12
|
+
"params": {
|
|
13
|
+
"properties": {
|
|
14
|
+
"position": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "意向岗位",
|
|
17
|
+
"example": "前端开发",
|
|
18
|
+
"question": "你想找什么岗位的工作?比如: 前端开发、后端开发、UI设计",
|
|
19
|
+
"match": "{中文}",
|
|
20
|
+
"default": null
|
|
21
|
+
},
|
|
22
|
+
"name": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "姓名",
|
|
25
|
+
"example": "张三",
|
|
26
|
+
"match": "{中文}",
|
|
27
|
+
"default": null
|
|
28
|
+
},
|
|
29
|
+
"phone": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "手机号码",
|
|
32
|
+
"example": "13800138000",
|
|
33
|
+
"match": "{手机号码}",
|
|
34
|
+
"default": null
|
|
35
|
+
},
|
|
36
|
+
"location": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "工作地点",
|
|
39
|
+
"example": "深圳",
|
|
40
|
+
"question": "想在哪个城市工作?",
|
|
41
|
+
"match": "{中文}",
|
|
42
|
+
"enum": [
|
|
43
|
+
"北京",
|
|
44
|
+
"上海",
|
|
45
|
+
"广州",
|
|
46
|
+
"深圳",
|
|
47
|
+
"杭州",
|
|
48
|
+
"成都",
|
|
49
|
+
"武汉",
|
|
50
|
+
"南京"
|
|
51
|
+
],
|
|
52
|
+
"default": null
|
|
53
|
+
},
|
|
54
|
+
"salary": {
|
|
55
|
+
"type": "string",
|
|
56
|
+
"description": "期望薪资",
|
|
57
|
+
"example": "15k",
|
|
58
|
+
"question": "期望薪资多少?比如: 10k-15k",
|
|
59
|
+
"match": "{数字}k",
|
|
60
|
+
"remove": ["k"],
|
|
61
|
+
"default": null
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"required": ["position"]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模拟岗位库
|
|
3
|
+
*/
|
|
4
|
+
var jobPool = [
|
|
5
|
+
{
|
|
6
|
+
title: '前端开发工程师',
|
|
7
|
+
company: '科技公司A',
|
|
8
|
+
location: '深圳',
|
|
9
|
+
salary: '12k-18k',
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
title: '高级前端开发',
|
|
13
|
+
company: '互联网公司B',
|
|
14
|
+
location: '北京',
|
|
15
|
+
salary: '18k-25k',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
title: '前端架构师',
|
|
19
|
+
company: '金融科技C',
|
|
20
|
+
location: '上海',
|
|
21
|
+
salary: '25k-35k',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
title: 'Web前端开发',
|
|
25
|
+
company: '电商平台D',
|
|
26
|
+
location: '广州',
|
|
27
|
+
salary: '10k-15k',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
title: 'React前端工程师',
|
|
31
|
+
company: '游戏公司E',
|
|
32
|
+
location: '杭州',
|
|
33
|
+
salary: '15k-22k',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
title: 'Vue前端开发',
|
|
37
|
+
company: '教育科技F',
|
|
38
|
+
location: '成都',
|
|
39
|
+
salary: '10k-16k',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
title: '前端负责人',
|
|
43
|
+
company: 'AI公司G',
|
|
44
|
+
location: '深圳',
|
|
45
|
+
salary: '20k-30k',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
title: '全栈开发',
|
|
49
|
+
company: '创业公司H',
|
|
50
|
+
location: '北京',
|
|
51
|
+
salary: '15k-25k',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
title: '后端开发工程师',
|
|
55
|
+
company: '云计算I',
|
|
56
|
+
location: '深圳',
|
|
57
|
+
salary: '15k-22k',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
title: 'Java开发',
|
|
61
|
+
company: '银行J',
|
|
62
|
+
location: '上海',
|
|
63
|
+
salary: '14k-20k',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
title: 'Go开发工程师',
|
|
67
|
+
company: '区块链K',
|
|
68
|
+
location: '杭州',
|
|
69
|
+
salary: '20k-30k',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
title: 'Python开发',
|
|
73
|
+
company: 'AI公司L',
|
|
74
|
+
location: '北京',
|
|
75
|
+
salary: '18k-28k',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
title: 'UI设计师',
|
|
79
|
+
company: '设计公司M',
|
|
80
|
+
location: '上海',
|
|
81
|
+
salary: '12k-18k',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
title: '产品经理',
|
|
85
|
+
company: '互联网公司N',
|
|
86
|
+
location: '深圳',
|
|
87
|
+
salary: '15k-25k',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
title: '测试工程师',
|
|
91
|
+
company: '软件公司O',
|
|
92
|
+
location: '武汉',
|
|
93
|
+
salary: '10k-15k',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
title: '运维工程师',
|
|
97
|
+
company: '数据中心P',
|
|
98
|
+
location: '南京',
|
|
99
|
+
salary: '12k-18k',
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 解析薪资范围取中间值
|
|
105
|
+
* @param {string} range 薪资范围字符串, 如 "12k-18k"
|
|
106
|
+
* @returns {number} 中间值
|
|
107
|
+
*/
|
|
108
|
+
function getAvg(range) {
|
|
109
|
+
var parts = range.replace(/k/g, '').split('-');
|
|
110
|
+
return (parseInt(parts[0], 10) + parseInt(parts[1], 10)) / 2;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 按关键词过滤岗位
|
|
115
|
+
* @param {Array} lt 岗位列表
|
|
116
|
+
* @param {string} kw 关键词
|
|
117
|
+
* @returns {Array} 过滤结果
|
|
118
|
+
*/
|
|
119
|
+
function filterByKw(lt, kw) {
|
|
120
|
+
var ret = lt.filter((j) => {
|
|
121
|
+
return j.title.indexOf(kw) !== -1 || j.title.indexOf(kw.replace('开发', '')) !== -1;
|
|
122
|
+
});
|
|
123
|
+
return ret.length > 0 ? ret : jobPool.slice(0, 5);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 按城市排序
|
|
128
|
+
* @param {Array} lt 岗位列表
|
|
129
|
+
* @param {string} loc 目标城市
|
|
130
|
+
*/
|
|
131
|
+
function sortByLocation(lt, loc) {
|
|
132
|
+
lt.sort((a, b) => {
|
|
133
|
+
if (a.location === loc && b.location !== loc) return -1;
|
|
134
|
+
if (b.location === loc && a.location !== loc) return 1;
|
|
135
|
+
return 0;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* 按薪资接近度排序
|
|
141
|
+
* @param {Array} lt 岗位列表
|
|
142
|
+
* @param {string} salary 期望薪资
|
|
143
|
+
*/
|
|
144
|
+
function sortBySalary(lt, salary) {
|
|
145
|
+
var target = parseInt(salary, 10) || 15;
|
|
146
|
+
lt.sort((a, b) => {
|
|
147
|
+
return Math.abs(getAvg(a.salary) - target) - Math.abs(getAvg(b.salary) - target);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 格式化岗位列表为文本
|
|
153
|
+
* @param {Array} lt 岗位列表
|
|
154
|
+
* @returns {string} 格式化文本
|
|
155
|
+
*/
|
|
156
|
+
function formatList(lt) {
|
|
157
|
+
var list = lt.slice(0, 4).map((j, i) => {
|
|
158
|
+
return (i + 1) + '. ' + j.title + ' | ' + j.company + ' | ' + j.location + ' | ' + j.salary;
|
|
159
|
+
});
|
|
160
|
+
return '为你找到以下岗位:\n\n' + list.join('\n') + '\n\n已登记求职信息, 有合适岗位将推送通知';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* 搜索岗位
|
|
165
|
+
* @param {object} form 用户表单
|
|
166
|
+
* @returns {string} 搜索结果文本
|
|
167
|
+
*/
|
|
168
|
+
function search(form) {
|
|
169
|
+
var results = jobPool.slice();
|
|
170
|
+
if (form.position) {
|
|
171
|
+
results = filterByKw(results, form.position);
|
|
172
|
+
}
|
|
173
|
+
if (form.location) {
|
|
174
|
+
sortByLocation(results, form.location);
|
|
175
|
+
}
|
|
176
|
+
if (form.salary) {
|
|
177
|
+
sortBySalary(results, form.salary);
|
|
178
|
+
}
|
|
179
|
+
return formatList(results);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 收集缺失的可选信息
|
|
184
|
+
* @param {object} form 用户表单
|
|
185
|
+
* @returns {Array} 缺失信息列表
|
|
186
|
+
*/
|
|
187
|
+
function getMissing(form) {
|
|
188
|
+
var missing = [];
|
|
189
|
+
if (!form.name) missing.push('姓名');
|
|
190
|
+
if (!form.phone) missing.push('手机号');
|
|
191
|
+
if (!form.location) missing.push('工作城市');
|
|
192
|
+
if (!form.salary) missing.push('期望薪资(如: 15k)');
|
|
193
|
+
return missing;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* 构建已收集信息摘要
|
|
198
|
+
* @param {object} form 用户表单
|
|
199
|
+
* @returns {Array} 摘要行
|
|
200
|
+
*/
|
|
201
|
+
function buildSummary(form) {
|
|
202
|
+
var has = ['岗位: ' + form.position];
|
|
203
|
+
if (form.location) has.push('城市: ' + form.location);
|
|
204
|
+
if (form.salary) has.push('薪资: ' + form.salary + 'k');
|
|
205
|
+
if (form.name) has.push('姓名: ' + form.name);
|
|
206
|
+
return has;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
module.exports = {
|
|
210
|
+
/**
|
|
211
|
+
* 执行指令主函数
|
|
212
|
+
* @param {object} msg 消息对象
|
|
213
|
+
* @param {object} db 数据管理器
|
|
214
|
+
* @returns {object|string} 执行结果
|
|
215
|
+
*/
|
|
216
|
+
async main(msg, db) {
|
|
217
|
+
var form = msg.form || {};
|
|
218
|
+
if (msg.content === '搜索' || msg.content === '好了' || msg.content === '跳过') {
|
|
219
|
+
return search(form);
|
|
220
|
+
}
|
|
221
|
+
var missing = getMissing(form);
|
|
222
|
+
if (missing.length > 0) {
|
|
223
|
+
msg.end = 0;
|
|
224
|
+
return (
|
|
225
|
+
'已收集:\n' +
|
|
226
|
+
buildSummary(form).join('\n') +
|
|
227
|
+
'\n\n还需要: ' +
|
|
228
|
+
missing.join('、') +
|
|
229
|
+
'\n请回复补充, 或回复"搜索"直接查找'
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
if (db && db.table) {
|
|
233
|
+
try {
|
|
234
|
+
await db.table('job_candidate').addObj(form);
|
|
235
|
+
} catch {
|
|
236
|
+
// 登记失败不影响搜索
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return search(form);
|
|
240
|
+
},
|
|
241
|
+
};
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模拟"找工作"完整对话流程测试
|
|
3
|
+
*
|
|
4
|
+
* 测试 Drive 核心管线: 关键字匹配 → 槽位填充 → 会话恢复 → 结果返回
|
|
5
|
+
* 手动管理会话状态模拟多轮 NPC 式对话
|
|
6
|
+
*/
|
|
7
|
+
require('mm_expand');
|
|
8
|
+
require('mm_matchs');
|
|
9
|
+
|
|
10
|
+
var Drive = require('../drive');
|
|
11
|
+
var job_config = require('./config.json');
|
|
12
|
+
var job_script = require('./index');
|
|
13
|
+
|
|
14
|
+
// 创建模拟 mod: 绑定 Drive 原型方法 + job 配置 + job 脚本
|
|
15
|
+
var mod = {
|
|
16
|
+
name: 'job',
|
|
17
|
+
config: Object.assign({}, Drive.config, job_config),
|
|
18
|
+
call: function (name, msg, db) {
|
|
19
|
+
return job_script.main(msg, db);
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
mod.match = Drive.prototype.match.bind(mod);
|
|
24
|
+
mod.run = Drive.prototype.run.bind(mod);
|
|
25
|
+
mod._fillParams = Drive.prototype._fillParams.bind(mod);
|
|
26
|
+
mod._tryExtractParam = Drive.prototype._tryExtractParam.bind(mod);
|
|
27
|
+
mod._cleanVal = Drive.prototype._cleanVal.bind(mod);
|
|
28
|
+
mod.log = function () {};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 发送消息并获取回复
|
|
32
|
+
* @param {object} msg 消息对象(会被修改)
|
|
33
|
+
* @param {string} content 用户输入
|
|
34
|
+
* @param {boolean} is_session 是否为会话继续(跳过match)
|
|
35
|
+
* @returns {object|null} AI回复
|
|
36
|
+
*/
|
|
37
|
+
async function send(msg, content, is_session) {
|
|
38
|
+
if (!is_session) {
|
|
39
|
+
delete msg.cmd;
|
|
40
|
+
delete msg.form;
|
|
41
|
+
delete msg.stage;
|
|
42
|
+
}
|
|
43
|
+
delete msg.end;
|
|
44
|
+
msg.content = content;
|
|
45
|
+
return await mod.run(msg, {});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 打印分隔线
|
|
50
|
+
*/
|
|
51
|
+
function hr(title) {
|
|
52
|
+
console.log('\n' + '─'.repeat(55));
|
|
53
|
+
console.log(' ' + title);
|
|
54
|
+
console.log('─'.repeat(55));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 打印对话
|
|
59
|
+
*/
|
|
60
|
+
function chat(role, text) {
|
|
61
|
+
if (role === '用户') {
|
|
62
|
+
console.log('\n 👤 用户: ' + text);
|
|
63
|
+
} else {
|
|
64
|
+
console.log(' 🤖 系统: ' + text);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 打印内部状态
|
|
70
|
+
*/
|
|
71
|
+
function debug(msg) {
|
|
72
|
+
console.log('\n [调试]');
|
|
73
|
+
console.log(' msg.cmd : ' + (msg.cmd || '(无)'));
|
|
74
|
+
console.log(' msg.end : ' + (msg.end === 0 ? '0 (待续)' : msg.end || '(无)'));
|
|
75
|
+
console.log(' msg.form: ' + JSON.stringify(msg.form || {}));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ===== 执行完整对话测试 =====
|
|
79
|
+
async function main() {
|
|
80
|
+
var pass = 0;
|
|
81
|
+
var fail = 0;
|
|
82
|
+
|
|
83
|
+
function check(name, actual, expected) {
|
|
84
|
+
if (actual === expected) {
|
|
85
|
+
pass++;
|
|
86
|
+
} else {
|
|
87
|
+
fail++;
|
|
88
|
+
console.log(' ❌ ' + name + ' 期望: "' + expected + '", 实际: "' + actual + '"');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
var msg = { from_user: 'user_001', to_user: 'bot', chatid: 'chat_001' };
|
|
93
|
+
|
|
94
|
+
// ===== Round 1: 触发指令 =====
|
|
95
|
+
hr('第1轮: 关键词触发');
|
|
96
|
+
chat('用户', '找工作');
|
|
97
|
+
|
|
98
|
+
var ret = await send(msg, '找工作');
|
|
99
|
+
chat('系统', ret.content);
|
|
100
|
+
debug(msg);
|
|
101
|
+
|
|
102
|
+
console.log('\n [验证]');
|
|
103
|
+
check('cmd匹配', msg.cmd, 'job');
|
|
104
|
+
check('end状态', msg.end, 0);
|
|
105
|
+
check('position被过滤', msg.form.position, undefined);
|
|
106
|
+
check('返回追问', ret.content.indexOf('什么岗位') > -1, true);
|
|
107
|
+
|
|
108
|
+
// ===== Round 2: 填写岗位 =====
|
|
109
|
+
hr('第2轮: 填写意向岗位');
|
|
110
|
+
chat('用户', '前端开发');
|
|
111
|
+
|
|
112
|
+
ret = await send(msg, '前端开发', true);
|
|
113
|
+
chat('系统', ret.content);
|
|
114
|
+
debug(msg);
|
|
115
|
+
|
|
116
|
+
console.log('\n [验证]');
|
|
117
|
+
check('position填充', msg.form.position, '前端开发');
|
|
118
|
+
check('end状态', msg.end, 0);
|
|
119
|
+
check('返回追问', ret.content.indexOf('还需要') > -1, true);
|
|
120
|
+
|
|
121
|
+
// ===== Round 3: 填写城市和薪资 =====
|
|
122
|
+
hr('第3轮: 补充城市和薪资');
|
|
123
|
+
chat('用户', '深圳 15k');
|
|
124
|
+
|
|
125
|
+
ret = await send(msg, '深圳 15k', true);
|
|
126
|
+
chat('系统', ret.content);
|
|
127
|
+
debug(msg);
|
|
128
|
+
|
|
129
|
+
console.log('\n [验证]');
|
|
130
|
+
check('location填充', msg.form.location, '深圳');
|
|
131
|
+
check('salary填充', msg.form.salary, '15');
|
|
132
|
+
check('end状态', msg.end, 0);
|
|
133
|
+
check('追问手机号', ret.content.indexOf('手机号') > -1, true);
|
|
134
|
+
|
|
135
|
+
// ===== Round 4: 填写手机号 =====
|
|
136
|
+
hr('第4轮: 填写手机号');
|
|
137
|
+
chat('用户', '13800138000');
|
|
138
|
+
|
|
139
|
+
ret = await send(msg, '13800138000', true);
|
|
140
|
+
chat('系统', ret.content);
|
|
141
|
+
debug(msg);
|
|
142
|
+
|
|
143
|
+
console.log('\n [验证]');
|
|
144
|
+
check('phone填充', msg.form.phone, '13800138000');
|
|
145
|
+
check('end状态', msg.end, undefined);
|
|
146
|
+
check('返回岗位结果', ret.content.indexOf('为你找到以下岗位') > -1, true);
|
|
147
|
+
|
|
148
|
+
// ===== Round 5: 搜索岗位(覆盖全部信息) =====
|
|
149
|
+
hr('第5轮: 搜索岗位(补充姓名后)');
|
|
150
|
+
msg.form.name = '张三';
|
|
151
|
+
chat('用户', '张三');
|
|
152
|
+
|
|
153
|
+
ret = await send(msg, '张三', true);
|
|
154
|
+
chat('系统', ret.content);
|
|
155
|
+
debug(msg);
|
|
156
|
+
|
|
157
|
+
console.log('\n [验证]');
|
|
158
|
+
check('name填充', msg.form.name, '张三');
|
|
159
|
+
check('end完成', msg.end, undefined);
|
|
160
|
+
check('返回岗位', ret.content.indexOf('为你找到以下岗位') > -1, true);
|
|
161
|
+
check('无追问', ret.content.indexOf('还需要') > -1, false);
|
|
162
|
+
|
|
163
|
+
// ===== Round 6: 新会话重新找工作 =====
|
|
164
|
+
hr('第6轮: 新会话触发(验证状态隔离)');
|
|
165
|
+
var msg2 = { from_user: 'user_002', to_user: 'bot', chatid: 'chat_002' };
|
|
166
|
+
chat('用户', '应聘');
|
|
167
|
+
ret = await send(msg2, '应聘');
|
|
168
|
+
chat('系统', ret.content);
|
|
169
|
+
debug(msg2);
|
|
170
|
+
|
|
171
|
+
console.log('\n [验证]');
|
|
172
|
+
check('新会话cmd', msg2.cmd, 'job');
|
|
173
|
+
check('form为空', JSON.stringify(msg2.form), '{}');
|
|
174
|
+
|
|
175
|
+
// ===== 打印结果汇总 =====
|
|
176
|
+
hr('测试结果汇总');
|
|
177
|
+
var total = pass + fail;
|
|
178
|
+
console.log('\n 总计: ' + total + ' 项');
|
|
179
|
+
console.log(' 通过: ' + pass + ' 项 ✅');
|
|
180
|
+
if (fail > 0) {
|
|
181
|
+
console.log(' 失败: ' + fail + ' 项 ❌');
|
|
182
|
+
}
|
|
183
|
+
console.log('\n ' + (fail === 0 ? '全部通过! 🎉' : '存在失败项, 请检查'));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
main().catch(function (err) {
|
|
187
|
+
console.error('测试异常:', err);
|
|
188
|
+
});
|
package/com/cmd/script.tpl.js
CHANGED
|
@@ -1,33 +1,12 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
* @param {object} msg
|
|
5
|
-
* @param {object} db
|
|
6
|
-
* @returns {object} 执行结果
|
|
7
|
-
*/
|
|
8
|
-
async
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
},
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* 执行指令主函数
|
|
17
|
-
* @param {object} msg 消息
|
|
18
|
-
* @param {object} db 数据管理器,如: { next: async function{}, ret: {} }
|
|
19
|
-
* @returns {object} 执行结果
|
|
20
|
-
*/
|
|
21
|
-
async main(msg, db) {
|
|
22
|
-
let form = msg.form;
|
|
23
|
-
return {
|
|
24
|
-
location: '梅州',
|
|
25
|
-
datetime: '2023-08-25 12:00',
|
|
26
|
-
weather: '晴朗',
|
|
27
|
-
temperature: '25',
|
|
28
|
-
humidity: '60%',
|
|
29
|
-
wind: '3级',
|
|
30
|
-
...form
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
};
|
|
1
|
+
module.exports = {
|
|
2
|
+
/**
|
|
3
|
+
* 执行指令主函数
|
|
4
|
+
* @param {object} msg 消息对象 (含 content 字段)
|
|
5
|
+
* @param {object} db 数据管理器
|
|
6
|
+
* @returns {object|string} 执行结果
|
|
7
|
+
*/
|
|
8
|
+
async main(msg, db) {
|
|
9
|
+
// 在此编写指令业务逻辑
|
|
10
|
+
return '指令执行成功';
|
|
11
|
+
},
|
|
12
|
+
};
|