mm_os 3.3.1 → 4.0.1
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/LICENSE +21 -201
- package/README.md +498 -99
- package/README_EN.md +505 -0
- package/adapter/adapter.js +431 -0
- package/adapter/custom_persistence.js +660 -0
- package/adapter/mqtt.js +273 -0
- package/adapter/socket.js +113 -0
- package/adapter/web.js +67 -0
- package/adapter/websocket.js +146 -0
- package/com/api/com.json +5 -0
- package/{core/com → com}/api/config.tpl.json +8 -8
- package/com/api/drive.js +708 -0
- package/com/api/index.js +198 -0
- package/com/api/oauth.js +200 -0
- package/com/api/script.tpl.js +32 -0
- package/com/cmd/README.md +11 -0
- package/com/cmd/com.json +5 -0
- package/com/cmd/config.tpl.json +122 -0
- package/com/cmd/drive.js +1548 -0
- package/com/cmd/index.js +1066 -0
- package/com/cmd/msg.json +48 -0
- package/com/cmd/nlp.js +525 -0
- package/com/cmd/script.tpl.js +32 -0
- package/com/db/com.json +5 -0
- package/com/db/drive.js +1999 -0
- package/com/db/index.js +242 -0
- package/{core/com → com}/event/README.md +4 -4
- package/com/event/com.json +5 -0
- package/{core/com → com}/event/config.tpl.json +18 -18
- package/com/event/drive.js +59 -0
- package/com/event/index.js +409 -0
- package/com/event/script.tpl.js +23 -0
- package/com/mqtt/com.json +5 -0
- package/{core/com → com}/mqtt/config.tpl.json +3 -5
- package/com/mqtt/drive.js +676 -0
- package/com/mqtt/index.js +822 -0
- package/com/mqtt/mm_mqtt.js +425 -0
- package/com/mqtt/script.tpl.js +723 -0
- package/com/nav/com.json +5 -0
- package/com/nav/config.tpl.json +84 -0
- package/com/nav/drive.js +702 -0
- package/com/nav/index.js +231 -0
- package/{core/com → com}/nav/tpl/admin_pc/page_config.vue +280 -280
- package/{core/com → com}/nav/tpl/admin_pc/page_config_form.vue +194 -194
- package/com/nav/tpl/admin_pc/page_form.vue +180 -0
- package/com/nav/tpl/admin_pc/page_view.vue +124 -0
- package/com/nav/tpl/dev_pc/page_default.vue +247 -0
- package/com/nav/tpl/dev_pc/page_type.vue +313 -0
- package/com/nav/tpl/home_pc/page_default.vue +234 -0
- package/com/nav/tpl/home_pc/page_form.vue +137 -0
- package/com/nav/tpl/home_pc/page_list.vue +234 -0
- package/com/nav/tpl/home_pc/page_nav.vue +221 -0
- package/com/nav/tpl/home_pc/page_type.vue +234 -0
- package/com/nav/tpl/home_pc/page_view.vue +125 -0
- package/com/nav/tpl/home_phone/page_channel.vue +234 -0
- package/com/nav/tpl/home_phone/page_default.vue +234 -0
- package/com/nav/tpl/home_phone/page_form.vue +137 -0
- package/com/nav/tpl/home_phone/page_nav.vue +237 -0
- package/com/nav/tpl/home_phone/page_type.vue +234 -0
- package/com/nav/tpl/home_phone/page_view.vue +125 -0
- package/com/nav/viewmodel.js +446 -0
- package/com/param/com.json +5 -0
- package/{core/com → com}/param/config.tpl.json +7 -1
- package/com/param/drive.js +502 -0
- package/com/param/index.js +155 -0
- package/com/param/script.tpl.js +12 -0
- package/com/pendant/com.json +5 -0
- package/{core/com/component → com/pendant}/config.tpl.json +15 -13
- package/com/pendant/drive.js +204 -0
- package/com/pendant/index.js +441 -0
- package/com/pendant/pendant.html +16 -0
- package/com/pendant/script.tpl.js +18 -0
- package/com/socket/com.json +5 -0
- package/com/socket/config.tpl.json +12 -0
- package/com/socket/drive.js +651 -0
- package/com/socket/index.js +351 -0
- package/com/socket/script.tpl.js +41 -0
- package/com/sql/com.json +5 -0
- package/{core/com → com}/sql/config.tpl.json +13 -9
- package/com/sql/drive.js +1259 -0
- package/com/sql/index.js +150 -0
- package/com/sql/script.tpl.js +47 -0
- package/com/static/com.json +5 -0
- package/{core/com → com}/static/config.tpl.json +10 -6
- package/com/static/drive.js +194 -0
- package/com/static/index.js +226 -0
- package/com/static/script.tpl.js +28 -0
- package/com/task/com.json +5 -0
- package/{core/com → com}/task/config.tpl.json +4 -6
- package/com/task/drive.js +405 -0
- package/com/task/index.js +148 -0
- package/com/task/script.tpl.js +37 -0
- package/com/template/com.json +5 -0
- package/com/template/config.tpl.json +16 -0
- package/com/template/drive.js +80 -0
- package/com/template/index.js +141 -0
- package/com.js +156 -0
- package/common/README.md +2 -0
- package/common/handler/msg/handler.json +22 -0
- package/common/handler/msg/index.js +23 -0
- package/common/handler/player/handler.json +22 -0
- package/common/handler/player/index.js +287 -0
- package/common/handler/user/handler.json +22 -0
- package/common/handler/user/index.js +23 -0
- package/common/middleware/web_after/index.js +29 -0
- package/common/middleware/web_after/middleware.json +9 -0
- package/common/middleware/web_base/index.js +113 -0
- package/common/middleware/web_base/middleware.json +19 -0
- package/common/middleware/web_before/index.js +33 -0
- package/common/middleware/web_before/middleware.json +9 -0
- package/common/middleware/web_cors/index.js +87 -0
- package/common/middleware/web_cors/middleware.json +24 -0
- package/common/middleware/web_error/index.js +119 -0
- package/common/middleware/web_error/middleware.json +18 -0
- package/common/middleware/web_ip/index.js +15 -0
- package/common/middleware/web_ip/middleware.json +14 -0
- package/common/middleware/web_logger/index.js +156 -0
- package/common/middleware/web_logger/middleware.json +14 -0
- package/common/middleware/web_main/index.js +24 -0
- package/common/middleware/web_main/middleware.json +9 -0
- package/common/middleware/web_static/index.js +73 -0
- package/common/middleware/web_static/middleware.json +54 -0
- package/common/middleware/web_waf/index.js +385 -0
- package/common/middleware/web_waf/middleware.json +13 -0
- package/common/model/msg/index.js +88 -0
- package/common/model/msg/model.json +401 -0
- package/common/model/player/index.js +63 -0
- package/common/model/player/model.json +185 -0
- package/common/model/user/index.js +11 -0
- package/common/model/user/model.json +219 -0
- package/core/app/config.tpl.json +67 -0
- package/core/app/index.js +632 -0
- package/core/app/script.tpl.js +52 -0
- package/core/channel/index.js +899 -0
- package/core/channel/matcher.js +585 -0
- package/core/com/config.tpl.json +16 -0
- package/core/com/index.js +74 -0
- package/core/com/script.tpl.js +5 -0
- package/core/component/component.js +42 -0
- package/core/component/config.tpl.json +63 -0
- package/core/component/index.js +273 -0
- package/core/component/script.tpl.js +19 -0
- package/core/controller/config.tpl.json +14 -0
- package/core/controller/index.js +373 -0
- package/core/controller/script.tpl.js +27 -0
- package/core/factory/config.tpl.json +14 -0
- package/core/factory/entity.js +275 -0
- package/core/factory/index.js +241 -0
- package/core/factory/script.tpl.js +16 -0
- package/core/game/bat/index.js +137 -0
- package/core/game/bat/world.js +622 -0
- package/core/game/config.tpl.json +16 -0
- package/core/game/entity_admin.js +230 -0
- package/core/game/index.js +186 -0
- package/core/handler/config.tpl.json +22 -0
- package/core/handler/index.js +181 -0
- package/core/handler/script.tpl.js +23 -0
- package/core/logic/config.tpl.json +14 -0
- package/core/logic/index.js +59 -0
- package/core/logic/script.tpl.js +19 -0
- package/core/middleware/config.tpl.json +16 -0
- package/core/middleware/index.js +125 -0
- package/core/middleware/script.tpl.js +37 -0
- package/core/mod/config.tpl.json +22 -0
- package/core/mod/index.js +130 -0
- package/core/mod/script.tpl.js +34 -0
- package/core/model/config.tpl.json +219 -0
- package/core/model/index.js +272 -0
- package/core/model/model.js +27 -0
- package/core/model/script.tpl.js +20 -0
- package/core/notifier/config.tpl.json +14 -0
- package/core/notifier/index.js +77 -0
- package/core/notifier/script.tpl.js +20 -0
- package/core/plugin/config.tpl.json +24 -0
- package/core/plugin/index.js +232 -0
- package/core/plugin/script.tpl.js +51 -0
- package/core/pusher/config.tpl.json +14 -0
- package/core/pusher/index.js +161 -0
- package/core/pusher/script.tpl.js +20 -0
- package/core/room/bat/index.js +170 -0
- package/core/room/bat/room.js +524 -0
- package/core/room/config.tpl.json +20 -0
- package/core/room/index.js +249 -0
- package/core/room/room.js +61 -0
- package/core/scene/config.tpl.json +14 -0
- package/core/scene/index.js +466 -0
- package/core/scene/loop.js +1255 -0
- package/core/scene/map.js +28 -0
- package/core/scene/script.tpl.js +22 -0
- package/core/sender/config.tpl.json +14 -0
- package/core/sender/index.js +79 -0
- package/core/sender/script.tpl.js +20 -0
- package/core/service/config.tpl.json +14 -0
- package/core/service/index.js +100 -0
- package/core/service/script.tpl.js +25 -0
- package/core/store/config.tpl.json +26 -0
- package/core/store/index.js +1755 -0
- package/core/store/script.tpl.js +22 -0
- package/core/store/sql.js +1464 -0
- package/core/system/config.tpl.json +18 -0
- package/core/system/index.js +312 -0
- package/core/system/script.tpl.js +77 -0
- package/core/view/config.tpl.json +14 -0
- package/core/view/index.js +91 -0
- package/core/view/script.tpl.js +20 -0
- package/core/zone/bat/index.js +725 -0
- package/core/zone/config.tpl.json +54 -0
- package/core/zone/index.js +614 -0
- package/core/zone/script.tpl.js +10 -0
- package/core/zone/zone_bat.js +136 -0
- package/core//345/237/272/347/261/273/346/250/241/345/235/227/346/270/205/345/215/225.md +24 -0
- package/index.js +17 -333
- package/os.js +57 -0
- package/package.json +65 -55
- package/server.js +598 -0
- package/README.en.md +0 -36
- package/conf.json +0 -3
- package/core/base/mqtt/index.js +0 -1110
- package/core/base/mqtt/lib.js +0 -40
- package/core/base/web/index.js +0 -245
- package/core/com/api/com.json +0 -4
- package/core/com/api/drive.js +0 -668
- package/core/com/api/index.js +0 -108
- package/core/com/api/oauth.js +0 -158
- package/core/com/api/script.js +0 -32
- package/core/com/app/README.md +0 -3
- package/core/com/app/com.json +0 -4
- package/core/com/app/config.tpl.json +0 -16
- package/core/com/app/drive.js +0 -309
- package/core/com/app/index.js +0 -211
- package/core/com/app/script.js +0 -155
- package/core/com/cmd/com.json +0 -4
- package/core/com/cmd/config.tpl.json +0 -66
- package/core/com/cmd/drive.js +0 -513
- package/core/com/cmd/index.js +0 -354
- package/core/com/cmd/old/5w2h.js +0 -54
- package/core/com/cmd/old/drive.js +0 -423
- package/core/com/cmd/script.js +0 -11
- package/core/com/component/README.md +0 -3
- package/core/com/component/com.json +0 -4
- package/core/com/component/component.html +0 -16
- package/core/com/component/drive.js +0 -197
- package/core/com/component/index.js +0 -312
- package/core/com/component/script.js +0 -18
- package/core/com/db/com.json +0 -4
- package/core/com/db/drive.js +0 -1160
- package/core/com/db/index.js +0 -176
- package/core/com/event/com.json +0 -4
- package/core/com/event/drive.js +0 -133
- package/core/com/event/index.js +0 -345
- package/core/com/event/script.js +0 -26
- package/core/com/eventer/com.js +0 -477
- package/core/com/eventer/com.json +0 -4
- package/core/com/middleware/com.js +0 -154
- package/core/com/middleware/com.json +0 -4
- package/core/com/middleware/config.tpl.json +0 -8
- package/core/com/middleware/script.js +0 -9
- package/core/com/mqtt/com.json +0 -4
- package/core/com/mqtt/drive.js +0 -600
- package/core/com/mqtt/index.js +0 -572
- package/core/com/mqtt/mm_mqtt.js +0 -330
- package/core/com/mqtt/script.js +0 -604
- package/core/com/msg/com.js +0 -296
- package/core/com/msg/com.json +0 -4
- package/core/com/nav/com.json +0 -4
- package/core/com/nav/config.tpl.json +0 -75
- package/core/com/nav/drive.js +0 -549
- package/core/com/nav/index.js +0 -182
- package/core/com/nav/tpl/admin_pc/page_form.vue +0 -180
- package/core/com/nav/tpl/admin_pc/page_view.vue +0 -124
- package/core/com/nav/tpl/dev_pc/page_default.vue +0 -247
- package/core/com/nav/tpl/dev_pc/page_type.vue +0 -313
- package/core/com/nav/tpl/home_pc/page_default.vue +0 -234
- package/core/com/nav/tpl/home_pc/page_form.vue +0 -137
- package/core/com/nav/tpl/home_pc/page_list.vue +0 -234
- package/core/com/nav/tpl/home_pc/page_nav.vue +0 -221
- package/core/com/nav/tpl/home_pc/page_type.vue +0 -234
- package/core/com/nav/tpl/home_pc/page_view.vue +0 -125
- package/core/com/nav/tpl/home_phone/page_channel.vue +0 -234
- package/core/com/nav/tpl/home_phone/page_default.vue +0 -234
- package/core/com/nav/tpl/home_phone/page_form.vue +0 -137
- package/core/com/nav/tpl/home_phone/page_nav.vue +0 -237
- package/core/com/nav/tpl/home_phone/page_type.vue +0 -234
- package/core/com/nav/tpl/home_phone/page_view.vue +0 -125
- package/core/com/nav/viewmodel.js +0 -296
- package/core/com/param/drive.js +0 -366
- package/core/com/param/index.js +0 -80
- package/core/com/param/script.js +0 -12
- package/core/com/param/test.js +0 -98
- package/core/com/plugin/README.md +0 -3
- package/core/com/plugin/com.json +0 -4
- package/core/com/plugin/config.tpl.json +0 -26
- package/core/com/plugin/drive.js +0 -536
- package/core/com/plugin/index.js +0 -259
- package/core/com/plugin/script.js +0 -213
- package/core/com/rpc/com.json +0 -4
- package/core/com/rpc/drive.js +0 -160
- package/core/com/rpc/index.js +0 -87
- package/core/com/rpc/rpc.js +0 -118
- package/core/com/socket/com.json +0 -4
- package/core/com/socket/config.tpl.json +0 -14
- package/core/com/socket/drive.js +0 -403
- package/core/com/socket/index.js +0 -62
- package/core/com/socket/script.js +0 -42
- package/core/com/sql/drive.js +0 -1087
- package/core/com/sql/index.js +0 -83
- package/core/com/sql/script.js +0 -48
- package/core/com/static/com.json +0 -4
- package/core/com/static/drive.js +0 -220
- package/core/com/static/index.js +0 -149
- package/core/com/static/script.js +0 -28
- package/core/com/task/com.json +0 -4
- package/core/com/task/drive.js +0 -403
- package/core/com/task/index.js +0 -110
- package/core/com/task/script.js +0 -37
- package/core/com/timer/com.js +0 -217
- package/core/com/timer/com.json +0 -4
- package/core/com/tpl/com.js +0 -19
- package/core/com/tpl/com.json +0 -4
- package/lib/actions.js +0 -50
- package/lib/base.js +0 -361
- package/lib/com.js +0 -29
- package/lib/ref.js +0 -121
- package/middleware/cors/index.js +0 -119
- package/middleware/cors/middleware.json +0 -20
- package/middleware/csrf/index.js +0 -202
- package/middleware/csrf/middleware.json +0 -24
- package/middleware/ip_firewall/index.js +0 -476
- package/middleware/ip_firewall/middleware.json +0 -109
- package/middleware/mqtt_base/index.js +0 -10
- package/middleware/mqtt_base/middleware.json +0 -11
- package/middleware/security_audit/index.js +0 -543
- package/middleware/security_audit/middleware.json +0 -48
- package/middleware/waf/index.js +0 -343
- package/middleware/waf/middleware.json +0 -10
- package/middleware/waf_ddos/index.js +0 -520
- package/middleware/waf_ddos/middleware.json +0 -38
- package/middleware/waf_xss/index.js +0 -269
- package/middleware/waf_xss/middleware.json +0 -18
- package/middleware/web_after/index.js +0 -33
- package/middleware/web_after/middleware.json +0 -10
- package/middleware/web_base/index.js +0 -90
- package/middleware/web_base/middleware.json +0 -10
- package/middleware/web_before/index.js +0 -27
- package/middleware/web_before/middleware.json +0 -10
- package/middleware/web_check/index.js +0 -28
- package/middleware/web_check/middleware.json +0 -10
- package/middleware/web_main/index.js +0 -28
- package/middleware/web_main/middleware.json +0 -10
- package/middleware/web_proxy/index.js +0 -37
- package/middleware/web_proxy/middleware.json +0 -10
- package/middleware/web_render/index.js +0 -87
- package/middleware/web_render/middleware.json +0 -10
- package/middleware/web_socket/index.js +0 -34
- package/middleware/web_socket/middleware.json +0 -10
- package/middleware/web_static/index.js +0 -115
- package/middleware/web_static/middleware.json +0 -10
- /package/{core/com → com}/api/README.md +0 -0
- /package/{core/com → com}/db/README.md +0 -0
- /package/{core/com → com}/mqtt/README.md +0 -0
- /package/{core/com → com}/nav/README.md +0 -0
- /package/{core/com → com}/nav/tpl/admin_pc/page_channel.vue +0 -0
- /package/{core/com → com}/nav/tpl/admin_pc/page_default.vue +0 -0
- /package/{core/com → com}/nav/tpl/admin_pc/page_lang.vue +0 -0
- /package/{core/com → com}/nav/tpl/admin_pc/page_nav.vue +0 -0
- /package/{core/com → com}/nav/tpl/admin_pc/page_table.vue +0 -0
- /package/{core/com → com}/nav/tpl/admin_pc/page_type.vue +0 -0
- /package/{core/com → com}/nav/tpl/dev_pc/page_channel.vue +0 -0
- /package/{core/com → com}/nav/tpl/dev_pc/page_config.vue +0 -0
- /package/{core/com → com}/nav/tpl/dev_pc/page_form.vue +0 -0
- /package/{core/com → com}/nav/tpl/dev_pc/page_nav.vue +0 -0
- /package/{core/com → com}/nav/tpl/dev_pc/page_table.vue +0 -0
- /package/{core/com → com}/nav/tpl/home_pc/page_channel.vue +0 -0
- /package/{core/com → com}/nav/tpl/home_phone/page_list.vue +0 -0
- /package/{core/com → com}/param/README.md +0 -0
- /package/{core/com/cmd → com/pendant}/README.md +0 -0
- /package/{core/com → com}/socket/README.md +0 -0
- /package/{core/com → com}/sql/README.md +0 -0
- /package/{core/com → com}/static/README.md +0 -0
- /package/{core/com → com}/task/README.md +0 -0
package/com/cmd/drive.js
ADDED
|
@@ -0,0 +1,1548 @@
|
|
|
1
|
+
require('mm_matchs');
|
|
2
|
+
const Item = require('mm_machine').Drive;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 指令驱动类
|
|
6
|
+
* @augments {Item}
|
|
7
|
+
* @class
|
|
8
|
+
*/
|
|
9
|
+
class Drive extends Item {
|
|
10
|
+
static config = {
|
|
11
|
+
// 应用名称 例如:demo_app
|
|
12
|
+
'app': 'server',
|
|
13
|
+
// 插件名称 例如:demo_plugin
|
|
14
|
+
'plugin': 'sys',
|
|
15
|
+
// 时态, 分before之前、main主要、after之后三个时态,
|
|
16
|
+
'tense': 'main',
|
|
17
|
+
// 分组
|
|
18
|
+
'group': 'default',
|
|
19
|
+
// 类型: query便民查询,action执行,game游戏,orther其他,为空表示未分类
|
|
20
|
+
'type': '',
|
|
21
|
+
// 匹配关键词
|
|
22
|
+
'match': [],
|
|
23
|
+
// 不含关键词
|
|
24
|
+
'not_match': [],
|
|
25
|
+
// 去除关键词
|
|
26
|
+
'remove': [],
|
|
27
|
+
// 摘取
|
|
28
|
+
'extract': [],
|
|
29
|
+
// 阶段
|
|
30
|
+
'stage': [
|
|
31
|
+
// 第一阶段
|
|
32
|
+
{
|
|
33
|
+
// 方式
|
|
34
|
+
'mode': 'fill',
|
|
35
|
+
// 验证参数集
|
|
36
|
+
'param': [
|
|
37
|
+
// {
|
|
38
|
+
// 参数名
|
|
39
|
+
// "name": "name",
|
|
40
|
+
// 参数介绍名
|
|
41
|
+
// "title": "名称",
|
|
42
|
+
// 是否必填, 1为必填, 0为选填
|
|
43
|
+
// "required": 1,
|
|
44
|
+
// 参数描述, 用于提示AI该参数的作用
|
|
45
|
+
// "desc": "请输入快递单号",
|
|
46
|
+
// 示例, 用于提示用户该参数的格式
|
|
47
|
+
// "example": "123456789012345678",
|
|
48
|
+
// // 参数格式
|
|
49
|
+
// "format": "",
|
|
50
|
+
// // 缺少参数提示语,传键值对,例如:{ number: "快递单号多少?" }
|
|
51
|
+
// "not_tip": "",
|
|
52
|
+
// // 错误提示
|
|
53
|
+
// "error_tip": "",
|
|
54
|
+
// // 监听语法
|
|
55
|
+
// "listen": "",
|
|
56
|
+
// // 校验函数明
|
|
57
|
+
// "func_name": ""
|
|
58
|
+
// },
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
// 第二阶段
|
|
62
|
+
{
|
|
63
|
+
// 方式
|
|
64
|
+
'mode': 'update',
|
|
65
|
+
// 验证参数集
|
|
66
|
+
'param': []
|
|
67
|
+
},
|
|
68
|
+
// 第三阶段
|
|
69
|
+
{
|
|
70
|
+
// 方式
|
|
71
|
+
'mode': 'fill',
|
|
72
|
+
// 验证参数集
|
|
73
|
+
'param': []
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 构造函数
|
|
80
|
+
* @param {object} config 配置参数
|
|
81
|
+
* @param {object} parent 父对象
|
|
82
|
+
* @class
|
|
83
|
+
*/
|
|
84
|
+
constructor(config, parent) {
|
|
85
|
+
super({ ...Drive.config, ...config }, parent);
|
|
86
|
+
// 默认启用热更新
|
|
87
|
+
this.mode = 3;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 创建一个参数模型
|
|
94
|
+
* @returns {object} 参数模型
|
|
95
|
+
*/
|
|
96
|
+
Drive.prototype.model = function () {
|
|
97
|
+
return {
|
|
98
|
+
// 参数名
|
|
99
|
+
'name': 'default',
|
|
100
|
+
// 参数介绍名
|
|
101
|
+
'title': '参数显示名称',
|
|
102
|
+
// 应用名称 例如:demo_app
|
|
103
|
+
'app': '',
|
|
104
|
+
// 插件名称 例如:demo_plugin
|
|
105
|
+
'plugin': '',
|
|
106
|
+
// 是否必填, 1为必填, 0为选填
|
|
107
|
+
'required': 1,
|
|
108
|
+
// 参数描述, 用于提示AI该参数的作用
|
|
109
|
+
'desc': '',
|
|
110
|
+
// 示例, 用于提示用户该参数的格式
|
|
111
|
+
'example': '',
|
|
112
|
+
// 排序
|
|
113
|
+
'sort': 10,
|
|
114
|
+
// 监听语法
|
|
115
|
+
'listen': '',
|
|
116
|
+
// 参数格式
|
|
117
|
+
'format': '',
|
|
118
|
+
// 缺少参数提示语
|
|
119
|
+
'not_tip': '',
|
|
120
|
+
// 更新提示
|
|
121
|
+
'update_tip': '',
|
|
122
|
+
// 错误提示
|
|
123
|
+
'error_tip': ''
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 校验是否匹配指令
|
|
129
|
+
* @param {object} content 请求的正文
|
|
130
|
+
* @param {object} db 数据管理器
|
|
131
|
+
* @returns {boolean} 匹配返回true,不匹配返回false
|
|
132
|
+
*/
|
|
133
|
+
Drive.prototype.match = function (content, db) {
|
|
134
|
+
var word;
|
|
135
|
+
var arr = this.config.match;
|
|
136
|
+
|
|
137
|
+
// 如果匹配规则为空,使用智能匹配
|
|
138
|
+
if (!arr || arr.length === 0) {
|
|
139
|
+
return this._smartMatch(content, db);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
for (var i = 0; i < arr.length; i++) {
|
|
143
|
+
var format = arr[i];
|
|
144
|
+
var str = content.match(format);
|
|
145
|
+
if (str) {
|
|
146
|
+
word = str;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return word;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* 增强的指令匹配方法,支持上下文匹配
|
|
155
|
+
* @param {object} msg 消息对象
|
|
156
|
+
* @param {object} db 数据管理器
|
|
157
|
+
* @returns {boolean} 匹配返回true,不匹配返回false
|
|
158
|
+
*/
|
|
159
|
+
Drive.prototype.enhancedMatch = function (msg, db) {
|
|
160
|
+
// 首先检查标准匹配
|
|
161
|
+
var standard_match = this.match(msg.content, db);
|
|
162
|
+
if (standard_match) {
|
|
163
|
+
return standard_match;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 使用上下文信息进行增强匹配
|
|
167
|
+
return this._contextAwareMatch(msg, db);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* 基于上下文的智能匹配
|
|
172
|
+
* @param {object} msg 消息对象
|
|
173
|
+
* @param {object} db 数据管理器
|
|
174
|
+
* @returns {boolean} 匹配返回true,不匹配返回false
|
|
175
|
+
* @private
|
|
176
|
+
*/
|
|
177
|
+
Drive.prototype._contextAwareMatch = function (msg, db) {
|
|
178
|
+
var name = this.config.name.toLowerCase();
|
|
179
|
+
var title = this.config.title.toLowerCase();
|
|
180
|
+
var description = this.config.description.toLowerCase();
|
|
181
|
+
var content = (msg.content || '').toLowerCase();
|
|
182
|
+
|
|
183
|
+
// 1. 基于消息类型的匹配
|
|
184
|
+
if (this._matchByMsgType(msg, name, title)) {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 2. 基于会话上下文的匹配
|
|
189
|
+
if (this._matchBySessionContext(msg, name, title)) {
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// 3. 基于历史状态的匹配
|
|
194
|
+
if (this._matchByHistoryState(msg, name, title, db)) {
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 4. 基于关键词和表单数据的匹配
|
|
199
|
+
if (this._matchByKeywordsAndForm(msg, name, title)) {
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return false;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 基于消息类型的匹配
|
|
208
|
+
* @param {object} msg 消息对象
|
|
209
|
+
* @param {string} name 指令名称
|
|
210
|
+
* @param {string} title 指令标题
|
|
211
|
+
* @returns {boolean} 匹配返回true
|
|
212
|
+
* @private
|
|
213
|
+
*/
|
|
214
|
+
Drive.prototype._matchByMsgType = function (msg, name, title) {
|
|
215
|
+
var msg_type = msg.msg_type || 'text';
|
|
216
|
+
|
|
217
|
+
// 根据指令类型推断支持的消息类型
|
|
218
|
+
var supported_types = this._getSupportedMsgTypes(name);
|
|
219
|
+
|
|
220
|
+
// 如果指令支持当前消息类型,增加匹配权重
|
|
221
|
+
if (supported_types.includes(msg_type)) {
|
|
222
|
+
return this._checkContentRelevance(msg.content, title);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return false;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* 获取指令支持的消息类型
|
|
230
|
+
* @param {string} name 指令名称
|
|
231
|
+
* @returns {Array} 返回支持的消息类型数组
|
|
232
|
+
* @private
|
|
233
|
+
*/
|
|
234
|
+
Drive.prototype._getSupportedMsgTypes = function (name) {
|
|
235
|
+
var name_lower = name.toLowerCase();
|
|
236
|
+
|
|
237
|
+
if (name_lower.includes('image') || name_lower.includes('pic') || name_lower.includes('photo')) {
|
|
238
|
+
return ['image'];
|
|
239
|
+
} else if (name_lower.includes('voice') || name_lower.includes('audio')) {
|
|
240
|
+
return ['voice'];
|
|
241
|
+
} else if (name_lower.includes('video')) {
|
|
242
|
+
return ['video'];
|
|
243
|
+
} else if (name_lower.includes('file') || name_lower.includes('document')) {
|
|
244
|
+
return ['file'];
|
|
245
|
+
} else if (name_lower.includes('location') || name_lower.includes('map')) {
|
|
246
|
+
return ['location'];
|
|
247
|
+
} else if (name_lower.includes('link') || name_lower.includes('url')) {
|
|
248
|
+
return ['link'];
|
|
249
|
+
} else if (name_lower.includes('event')) {
|
|
250
|
+
return ['event'];
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// 默认支持文本类型
|
|
254
|
+
return ['text'];
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* 检查内容相关性
|
|
259
|
+
* @param {string} content 消息内容
|
|
260
|
+
* @param {string} title 指令标题
|
|
261
|
+
* @returns {boolean} 相关返回true
|
|
262
|
+
* @private
|
|
263
|
+
*/
|
|
264
|
+
Drive.prototype._checkContentRelevance = function (content, title) {
|
|
265
|
+
if (!content) return false;
|
|
266
|
+
|
|
267
|
+
var content = content.toLowerCase();
|
|
268
|
+
var title_lower = title.toLowerCase();
|
|
269
|
+
|
|
270
|
+
// 简单的关键词匹配
|
|
271
|
+
var keywords = title_lower.split(/[\s_\-]+/).filter(function (word) {
|
|
272
|
+
return word.length > 1;
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
for (var i = 0; i < keywords.length; i++) {
|
|
276
|
+
if (content.includes(keywords[i])) {
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return false;
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* 基于会话上下文的匹配
|
|
286
|
+
* @param {object} msg 消息对象
|
|
287
|
+
* @param {string} name 指令名称
|
|
288
|
+
* @param {string} title 指令标题
|
|
289
|
+
* @returns {boolean} 匹配返回true
|
|
290
|
+
* @private
|
|
291
|
+
*/
|
|
292
|
+
Drive.prototype._matchBySessionContext = function (msg, name, title) {
|
|
293
|
+
// 检查群组匹配
|
|
294
|
+
if (msg.group && this._isGroupSpecificCmd(name)) {
|
|
295
|
+
return this._checkContentRelevance(msg.content, title);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// 检查会话类型匹配
|
|
299
|
+
var session_type = msg.type === 1 ? 'permanent' : 'temporary';
|
|
300
|
+
if (this._isSessionTypeSpecificCmd(name, session_type)) {
|
|
301
|
+
return this._checkContentRelevance(msg.content, title);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return false;
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* 判断是否为群组特定指令
|
|
309
|
+
* @param {string} name 指令名称
|
|
310
|
+
* @returns {boolean} 是群组特定指令返回true
|
|
311
|
+
* @private
|
|
312
|
+
*/
|
|
313
|
+
Drive.prototype._isGroupSpecificCmd = function (name) {
|
|
314
|
+
var name_lower = name.toLowerCase();
|
|
315
|
+
return name_lower.includes('group') || name_lower.includes('群') ||
|
|
316
|
+
name_lower.includes('broadcast') || name_lower.includes('广播');
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* 判断是否为会话类型特定指令
|
|
321
|
+
* @param {string} name 指令名称
|
|
322
|
+
* @param {string} session_type 会话类型
|
|
323
|
+
* @returns {boolean} 是会话类型特定指令返回true
|
|
324
|
+
* @private
|
|
325
|
+
*/
|
|
326
|
+
Drive.prototype._isSessionTypeSpecificCmd = function (name, session_type) {
|
|
327
|
+
var name_lower = name.toLowerCase();
|
|
328
|
+
|
|
329
|
+
if (session_type === 'permanent') {
|
|
330
|
+
return name_lower.includes('permanent') || name_lower.includes('永久') ||
|
|
331
|
+
name_lower.includes('persistent') || name_lower.includes('持久');
|
|
332
|
+
} else {
|
|
333
|
+
return name_lower.includes('temporary') || name_lower.includes('临时') ||
|
|
334
|
+
name_lower.includes('temp') || name_lower.includes('暂时');
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* 基于历史状态的匹配
|
|
340
|
+
* @param {object} msg 消息对象
|
|
341
|
+
* @param {string} name 指令名称
|
|
342
|
+
* @param {string} title 指令标题
|
|
343
|
+
* @param {object} db 数据管理器
|
|
344
|
+
* @returns {boolean} 匹配返回true
|
|
345
|
+
* @private
|
|
346
|
+
*/
|
|
347
|
+
Drive.prototype._matchByHistoryState = function (msg, name, title, db) {
|
|
348
|
+
// 检查阶段匹配
|
|
349
|
+
if (msg.stage && this._isStageSpecificCmd(name, msg.stage)) {
|
|
350
|
+
return this._checkContentRelevance(msg.content, title);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// 检查结束状态匹配
|
|
354
|
+
if (msg.end !== undefined && this._isEndStateSpecificCmd(name, msg.end)) {
|
|
355
|
+
return this._checkContentRelevance(msg.content, title);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return false;
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* 判断是否为阶段特定指令
|
|
363
|
+
* @param {string} name 指令名称
|
|
364
|
+
* @param {number} stage 当前阶段
|
|
365
|
+
* @returns {boolean} 是阶段特定指令返回true
|
|
366
|
+
* @private
|
|
367
|
+
*/
|
|
368
|
+
Drive.prototype._isStageSpecificCmd = function (name, stage) {
|
|
369
|
+
var name_lower = name.toLowerCase();
|
|
370
|
+
|
|
371
|
+
// 根据阶段推断指令类型
|
|
372
|
+
if (stage === 1) {
|
|
373
|
+
return name_lower.includes('init') || name_lower.includes('开始') ||
|
|
374
|
+
name_lower.includes('start') || name_lower.includes('启动');
|
|
375
|
+
} else if (stage >= 2 && stage <= 8) {
|
|
376
|
+
return name_lower.includes('process') || name_lower.includes('处理') ||
|
|
377
|
+
name_lower.includes('execute') || name_lower.includes('执行');
|
|
378
|
+
} else if (stage === 9) {
|
|
379
|
+
return name_lower.includes('final') || name_lower.includes('结束') ||
|
|
380
|
+
name_lower.includes('complete') || name_lower.includes('完成');
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return false;
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* 判断是否为结束状态特定指令
|
|
388
|
+
* @param {string} name 指令名称
|
|
389
|
+
* @param {number} end_state 结束状态
|
|
390
|
+
* @returns {boolean} 是结束状态特定指令返回true
|
|
391
|
+
* @private
|
|
392
|
+
*/
|
|
393
|
+
Drive.prototype._isEndStateSpecificCmd = function (name, end_state) {
|
|
394
|
+
var name_lower = name.toLowerCase();
|
|
395
|
+
|
|
396
|
+
if (end_state === 0) {
|
|
397
|
+
return name_lower.includes('continue') || name_lower.includes('继续') ||
|
|
398
|
+
name_lower.includes('resume') || name_lower.includes('恢复');
|
|
399
|
+
} else {
|
|
400
|
+
return name_lower.includes('end') || name_lower.includes('结束') ||
|
|
401
|
+
name_lower.includes('stop') || name_lower.includes('停止');
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* 基于关键词和表单数据的匹配
|
|
407
|
+
* @param {object} msg 消息对象
|
|
408
|
+
* @param {string} name 指令名称
|
|
409
|
+
* @param {string} title 指令标题
|
|
410
|
+
* @returns {boolean} 匹配返回true
|
|
411
|
+
* @private
|
|
412
|
+
*/
|
|
413
|
+
Drive.prototype._matchByKeywordsAndForm = function (msg, name, title) {
|
|
414
|
+
// 检查关键词匹配
|
|
415
|
+
if (msg.keyword && this._matchByKeywords(msg.keyword, title)) {
|
|
416
|
+
return true;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// 检查表单数据匹配
|
|
420
|
+
if (msg.form && this._matchByFormData(msg.form, name)) {
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return false;
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* 基于关键词的匹配
|
|
429
|
+
* @param {string} keyword 关键词
|
|
430
|
+
* @param {string} title 指令标题
|
|
431
|
+
* @returns {boolean} 匹配返回true
|
|
432
|
+
* @private
|
|
433
|
+
*/
|
|
434
|
+
Drive.prototype._matchByKeywords = function (keyword, title) {
|
|
435
|
+
if (!keyword) return false;
|
|
436
|
+
|
|
437
|
+
var keyword_lower = keyword.toLowerCase();
|
|
438
|
+
var title_lower = title.toLowerCase();
|
|
439
|
+
|
|
440
|
+
var keywords = keyword_lower.split(/\s+/);
|
|
441
|
+
var title_words = title_lower.split(/[\s_\-]+/);
|
|
442
|
+
|
|
443
|
+
// 检查关键词与指令标题的匹配度
|
|
444
|
+
for (var i = 0; i < keywords.length; i++) {
|
|
445
|
+
for (var j = 0; j < title_words.length; j++) {
|
|
446
|
+
if (keywords[i] === title_words[j] && keywords[i].length > 1) {
|
|
447
|
+
return true;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return false;
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* 基于表单数据的匹配
|
|
457
|
+
* @param {string|object} form 表单数据
|
|
458
|
+
* @param {string} name 指令名称
|
|
459
|
+
* @returns {boolean} 匹配返回true
|
|
460
|
+
* @private
|
|
461
|
+
*/
|
|
462
|
+
Drive.prototype._matchByFormData = function (form, name) {
|
|
463
|
+
try {
|
|
464
|
+
var form_data = typeof form === 'string' ? JSON.parse(form) : form;
|
|
465
|
+
|
|
466
|
+
// 检查表单数据是否包含与指令相关的字段
|
|
467
|
+
var cmd_fields = this._getCmdSpecificFields(name);
|
|
468
|
+
|
|
469
|
+
for (var field in form_data) {
|
|
470
|
+
if (form_data.hasOwnProperty(field) && cmd_fields.includes(field)) {
|
|
471
|
+
return true;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
} catch (e) {
|
|
475
|
+
// 表单数据解析失败
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return false;
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* 获取指令特定的字段
|
|
483
|
+
* @param {string} name 指令名称
|
|
484
|
+
* @returns {Array} 返回字段数组
|
|
485
|
+
* @private
|
|
486
|
+
*/
|
|
487
|
+
Drive.prototype._getCmdSpecificFields = function (name) {
|
|
488
|
+
var name_lower = name.toLowerCase();
|
|
489
|
+
var fields = [];
|
|
490
|
+
|
|
491
|
+
// 根据指令名称推断相关字段
|
|
492
|
+
if (name_lower.includes('user')) {
|
|
493
|
+
fields.push('user_id', 'user_name', 'from_user', 'to_user');
|
|
494
|
+
}
|
|
495
|
+
if (name_lower.includes('group')) {
|
|
496
|
+
fields.push('group', 'chatid');
|
|
497
|
+
}
|
|
498
|
+
if (name_lower.includes('time') || name_lower.includes('date')) {
|
|
499
|
+
fields.push('create_time', 'update_time');
|
|
500
|
+
}
|
|
501
|
+
if (name_lower.includes('media')) {
|
|
502
|
+
fields.push('media_id', 'msg_type');
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
return fields;
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* 智能匹配指令
|
|
510
|
+
* @param {string} content 请求正文
|
|
511
|
+
* @param {object} db 数据管理器
|
|
512
|
+
* @returns {string|boolean} 匹配返回关键词,不匹配返回false
|
|
513
|
+
* @private
|
|
514
|
+
*/
|
|
515
|
+
Drive.prototype._smartMatch = function (content, db) {
|
|
516
|
+
// 基于指令名称和描述的智能匹配
|
|
517
|
+
var name = this.config.name.toLowerCase();
|
|
518
|
+
var title = this.config.title.toLowerCase();
|
|
519
|
+
var description = this.config.description.toLowerCase();
|
|
520
|
+
var content = content.toLowerCase();
|
|
521
|
+
|
|
522
|
+
// 检查是否包含指令关键词
|
|
523
|
+
var keywords = this._extractKeywords(name, title, description);
|
|
524
|
+
|
|
525
|
+
for (var i = 0; i < keywords.length; i++) {
|
|
526
|
+
var keyword = keywords[i];
|
|
527
|
+
if (content.includes(keyword)) {
|
|
528
|
+
return keyword;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// 增强的自然语言理解匹配
|
|
533
|
+
return this._enhancedNLPMatch(content, name, title);
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* 增强的自然语言理解匹配
|
|
538
|
+
* @param {string} content 请求正文
|
|
539
|
+
* @param {string} name 指令名称
|
|
540
|
+
* @param {string} title 指令标题
|
|
541
|
+
* @returns {string|boolean} 匹配返回关键词,不匹配返回false
|
|
542
|
+
* @private
|
|
543
|
+
*/
|
|
544
|
+
Drive.prototype._enhancedNLPMatch = function (content, name, title) {
|
|
545
|
+
var content = content.toLowerCase();
|
|
546
|
+
|
|
547
|
+
// 根据指令类型进行语义匹配
|
|
548
|
+
var patterns = this._getPatternsByCmdType(name, title);
|
|
549
|
+
var keyword = this._getKeywordByCmdType(name, title);
|
|
550
|
+
|
|
551
|
+
return this._matchPatterns(content, patterns, keyword);
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* 根据指令类型获取匹配模式
|
|
556
|
+
* @param {string} name 指令名称
|
|
557
|
+
* @param {string} title 指令标题
|
|
558
|
+
* @returns {Array} 返回正则表达式模式数组
|
|
559
|
+
* @private
|
|
560
|
+
*/
|
|
561
|
+
Drive.prototype._getPatternsByCmdType = function (name, title) {
|
|
562
|
+
// 根据指令名称推断指令类型
|
|
563
|
+
var cmd_type = this._inferCmdType(name);
|
|
564
|
+
|
|
565
|
+
switch (cmd_type) {
|
|
566
|
+
case 'open':
|
|
567
|
+
// 打开类指令的语义匹配
|
|
568
|
+
return [
|
|
569
|
+
new RegExp('(?:打开|开启|启动|点亮)(?:.*?)' + this._escapeRegex(title)),
|
|
570
|
+
new RegExp('(?:把|将)(?:.*?)' + this._escapeRegex(title) + '(?:打开|开启|启动)'),
|
|
571
|
+
new RegExp('(?:需要|想要)(?:.*?)' + this._escapeRegex(title) + '(?:打开|开启|启动)')
|
|
572
|
+
];
|
|
573
|
+
|
|
574
|
+
case 'close':
|
|
575
|
+
// 关闭类指令的语义匹配
|
|
576
|
+
return [
|
|
577
|
+
new RegExp('(?:关闭|关掉|熄灭|停止)(?:.*?)' + this._escapeRegex(title)),
|
|
578
|
+
new RegExp('(?:把|将)(?:.*?)' + this._escapeRegex(title) + '(?:关闭|关掉|熄灭|停止)'),
|
|
579
|
+
new RegExp('(?:需要|想要)(?:.*?)' + this._escapeRegex(title) + '(?:关闭|关掉|熄灭|停止)')
|
|
580
|
+
];
|
|
581
|
+
|
|
582
|
+
case 'set':
|
|
583
|
+
// 设置类指令的语义匹配
|
|
584
|
+
return [
|
|
585
|
+
new RegExp('(?:把|将)(?:.*?)' + this._escapeRegex(title) + '(?:调到|设置为|设为)(\\d+)'),
|
|
586
|
+
new RegExp('(?:设置|调整)(?:.*?)' + this._escapeRegex(title) + '(?:为|到)(\\d+)'),
|
|
587
|
+
new RegExp('(?:需要|想要)(?:.*?)' + this._escapeRegex(title) + '(?:为|到)(\\d+)')
|
|
588
|
+
];
|
|
589
|
+
|
|
590
|
+
case 'play':
|
|
591
|
+
// 播放类指令的语义匹配
|
|
592
|
+
return [
|
|
593
|
+
new RegExp('(?:播放|放|听)(?:.*?)' + this._escapeRegex(title)),
|
|
594
|
+
new RegExp('(?:想听|要听|需要)(?:.*?)' + this._escapeRegex(title)),
|
|
595
|
+
new RegExp('(?:播放|放)(?:.*?)(?:的)' + this._escapeRegex(title))
|
|
596
|
+
];
|
|
597
|
+
|
|
598
|
+
case 'query':
|
|
599
|
+
// 查询类指令的语义匹配
|
|
600
|
+
return [
|
|
601
|
+
new RegExp('(?:查询|查一下|看看)(?:.*?)' + this._escapeRegex(title)),
|
|
602
|
+
new RegExp('(?:今天|明天|后天)(?:.*?)' + this._escapeRegex(title) + '(?:怎么样|如何)'),
|
|
603
|
+
new RegExp('(?:需要|想要)(?:.*?)' + this._escapeRegex(title) + '(?:信息|情况)')
|
|
604
|
+
];
|
|
605
|
+
|
|
606
|
+
default:
|
|
607
|
+
// 通用语义匹配
|
|
608
|
+
return [
|
|
609
|
+
new RegExp('(?:执行|运行|启动|使用)' + this._escapeRegex(title)),
|
|
610
|
+
new RegExp('(?:需要|想要)' + this._escapeRegex(title)),
|
|
611
|
+
new RegExp('(?:帮我|请帮我)' + this._escapeRegex(title))
|
|
612
|
+
];
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* 根据指令类型获取关键词
|
|
618
|
+
* @param {string} name 指令名称
|
|
619
|
+
* @param {string} title 指令标题
|
|
620
|
+
* @returns {string} 返回关键词
|
|
621
|
+
* @private
|
|
622
|
+
*/
|
|
623
|
+
Drive.prototype._getKeywordByCmdType = function (name, title) {
|
|
624
|
+
var cmd_type = this._inferCmdType(name);
|
|
625
|
+
|
|
626
|
+
switch (cmd_type) {
|
|
627
|
+
case 'open':
|
|
628
|
+
return '打开' + title;
|
|
629
|
+
case 'close':
|
|
630
|
+
return '关闭' + title;
|
|
631
|
+
case 'set':
|
|
632
|
+
return '设置' + title;
|
|
633
|
+
case 'play':
|
|
634
|
+
return '播放' + title;
|
|
635
|
+
case 'query':
|
|
636
|
+
return '查询' + title;
|
|
637
|
+
default:
|
|
638
|
+
return title;
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* 推断指令类型
|
|
644
|
+
* @param {string} name 指令名称
|
|
645
|
+
* @returns {string} 返回指令类型
|
|
646
|
+
* @private
|
|
647
|
+
*/
|
|
648
|
+
Drive.prototype._inferCmdType = function (name) {
|
|
649
|
+
var name_lower = name.toLowerCase();
|
|
650
|
+
|
|
651
|
+
if (name_lower.includes('open') || name_lower.includes('start') || name_lower.includes('begin')) {
|
|
652
|
+
return 'open';
|
|
653
|
+
} else if (name_lower.includes('close') || name_lower.includes('stop') || name_lower.includes('end')) {
|
|
654
|
+
return 'close';
|
|
655
|
+
} else if (name_lower.includes('set') || name_lower.includes('adjust') || name_lower.includes('config')) {
|
|
656
|
+
return 'set';
|
|
657
|
+
} else if (name_lower.includes('play') || name_lower.includes('show') || name_lower.includes('display')) {
|
|
658
|
+
return 'play';
|
|
659
|
+
} else if (name_lower.includes('get') || name_lower.includes('query') || name_lower.includes('search')) {
|
|
660
|
+
return 'query';
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
return 'general';
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* 转义正则表达式特殊字符
|
|
668
|
+
* @param {string} str 原始字符串
|
|
669
|
+
* @returns {string} 返回转义后的字符串
|
|
670
|
+
* @private
|
|
671
|
+
*/
|
|
672
|
+
Drive.prototype._escapeRegex = function (str) {
|
|
673
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* 匹配模式列表
|
|
678
|
+
* @param {string} content 请求正文
|
|
679
|
+
* @param {Array} patterns 正则表达式模式数组
|
|
680
|
+
* @param {string} keyword 关键词
|
|
681
|
+
* @returns {string|boolean} 匹配返回关键词,不匹配返回false
|
|
682
|
+
* @private
|
|
683
|
+
*/
|
|
684
|
+
Drive.prototype._matchPatterns = function (content, patterns, keyword) {
|
|
685
|
+
for (var i = 0; i < patterns.length; i++) {
|
|
686
|
+
if (patterns[i].test(content)) {
|
|
687
|
+
return keyword;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
return false;
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* 提取关键词
|
|
695
|
+
* @param {string} name 指令名称
|
|
696
|
+
* @param {string} title 指令标题
|
|
697
|
+
* @param {string} desc 指令描述
|
|
698
|
+
* @returns {Array} 返回关键词数组
|
|
699
|
+
* @private
|
|
700
|
+
*/
|
|
701
|
+
Drive.prototype._extractKeywords = function (name, title, desc) {
|
|
702
|
+
var keywords = [];
|
|
703
|
+
|
|
704
|
+
// 从名称中提取关键词
|
|
705
|
+
var name_words = name.split(/[\s_\-]+/).filter(function (word) {
|
|
706
|
+
return word.length > 1 && !['的', '和', '与', '或', '在', '从', '到', '为'].includes(word);
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
// 从标题中提取关键词
|
|
710
|
+
var title_words = title.split(/[\s_\-]+/).filter(function (word) {
|
|
711
|
+
return word.length > 1 && !['的', '和', '与', '或', '在', '从', '到', '为'].includes(word);
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
// 合并关键词
|
|
715
|
+
keywords = keywords.concat(name_words);
|
|
716
|
+
keywords = keywords.concat(title_words);
|
|
717
|
+
|
|
718
|
+
// 去重
|
|
719
|
+
keywords = keywords.filter(function (item, index, self) {
|
|
720
|
+
return self.indexOf(item) === index;
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
return keywords;
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* 校验是否不含关键词
|
|
728
|
+
* @param {object} content 请求的正文
|
|
729
|
+
* @param {object} db 数据管理器
|
|
730
|
+
* @returns {boolean} 不含返回true,含有返回false
|
|
731
|
+
*/
|
|
732
|
+
Drive.prototype.notMatch = function (content, db) {
|
|
733
|
+
var bl = true;
|
|
734
|
+
var arr = this.config.not_match;
|
|
735
|
+
if (!arr || arr.length === 0) {
|
|
736
|
+
return bl;
|
|
737
|
+
}
|
|
738
|
+
for (var i = 0; i < arr.length; i++) {
|
|
739
|
+
var format = arr[i];
|
|
740
|
+
if (content.match(format)) {
|
|
741
|
+
bl = false;
|
|
742
|
+
break;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
return bl;
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* 抽取主要内容
|
|
751
|
+
* @param {string} content 正文
|
|
752
|
+
* @param {object} db 数据管理器
|
|
753
|
+
* @returns {object} 返回过滤后的参数
|
|
754
|
+
*/
|
|
755
|
+
Drive.prototype.extract = async function (content, db) {
|
|
756
|
+
var list = this.config.extract;
|
|
757
|
+
if (!list || !list.length) {
|
|
758
|
+
return content;
|
|
759
|
+
}
|
|
760
|
+
var result = content;
|
|
761
|
+
for (var i = 0; i < list.length; i++) {
|
|
762
|
+
var format = list[i];
|
|
763
|
+
var ret = content.match(format);
|
|
764
|
+
if (ret) {
|
|
765
|
+
result = ret;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return result;
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* 移除关键词
|
|
773
|
+
* @param {Array} content 内容
|
|
774
|
+
* @returns {object} 返回过滤后的参数
|
|
775
|
+
*/
|
|
776
|
+
Drive.prototype.remove = async function (content) {
|
|
777
|
+
var ct = content;
|
|
778
|
+
var list = this.config.remove;
|
|
779
|
+
if (!list || !list.length) {
|
|
780
|
+
return ct;
|
|
781
|
+
}
|
|
782
|
+
for (var i = 0; i < list.length; i++) {
|
|
783
|
+
var format = list[i];
|
|
784
|
+
if (format.indexOf('/') === 0) {
|
|
785
|
+
var fmt = format.replace(/\//g, '\\/').replace(/\r/g, '\\r').replace(/\n/g, '\\n')
|
|
786
|
+
.replace(/\*/g, '.*').replace(
|
|
787
|
+
/\{[a-zA-Z\u4e00-\u9fa5_]+\}/g, '[\s\S]*');
|
|
788
|
+
var rx = eval(fmt);
|
|
789
|
+
ct = ct.replace(rx, '').trim();
|
|
790
|
+
} else {
|
|
791
|
+
ct = ct.replace(format, '').trim();
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
return ct;
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* 修改提示
|
|
799
|
+
* @param {object} msg 消息上下文
|
|
800
|
+
* @param {object} db 数据管理器
|
|
801
|
+
* @param {string} tip 提示模板
|
|
802
|
+
* @returns {object|string} 返回过滤后的参数
|
|
803
|
+
*/
|
|
804
|
+
Drive.prototype.viewTip = async function (msg, db, tip) {
|
|
805
|
+
var form = this.view(msg, db);
|
|
806
|
+
return tip.replace('{form}', form);
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* 1. 检验阶段, 判断条件是否满足
|
|
811
|
+
* @param {object} msg 消息上下文
|
|
812
|
+
* @param {object} db 数据管理器
|
|
813
|
+
* @returns {string} 验证失败返回错误提示
|
|
814
|
+
*/
|
|
815
|
+
Drive.prototype.check = async function (msg, db) {
|
|
816
|
+
// 校验是否匹配指令
|
|
817
|
+
var word = await this.match(msg.content, db);
|
|
818
|
+
if (word) {
|
|
819
|
+
var bl = await this.notMatch(msg.content, db);
|
|
820
|
+
if (!bl) {
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
return word;
|
|
825
|
+
};
|
|
826
|
+
|
|
827
|
+
/**
|
|
828
|
+
* 2. 过滤阶段, 抽出主要的内容
|
|
829
|
+
* @param {object} msg 消息上下文
|
|
830
|
+
* @param {object} db 数据管理器
|
|
831
|
+
* @returns {object} 返回过滤后的参数
|
|
832
|
+
*/
|
|
833
|
+
Drive.prototype.filter = async function (msg, db) {
|
|
834
|
+
var content = await this.extract(msg.content);
|
|
835
|
+
content = await this.remove(content);
|
|
836
|
+
if (content) {
|
|
837
|
+
msg.keyword = content;
|
|
838
|
+
}
|
|
839
|
+
return content;
|
|
840
|
+
};
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* 3.1 信息补全阶段 用于通知用户补全执行的必要条件
|
|
844
|
+
* @param {object} msg 消息上下文
|
|
845
|
+
* @param {object} db 数据管理器
|
|
846
|
+
* @param {object} stage 阶段参数
|
|
847
|
+
* @returns {object} 返回参数表单
|
|
848
|
+
*/
|
|
849
|
+
Drive.prototype.fill = async function (msg, db, stage) {
|
|
850
|
+
if (!stage || !stage.param || stage.param.length === 0) {
|
|
851
|
+
return '';
|
|
852
|
+
}
|
|
853
|
+
var form = this._getForm(msg);
|
|
854
|
+
var ct = msg.content_last || '';
|
|
855
|
+
var result = await this._processFillParams(stage.param, form, ct, msg, db);
|
|
856
|
+
this._updateMsgForm(msg, db, result.form, result.keyword);
|
|
857
|
+
return result.tip;
|
|
858
|
+
};
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* 获取表单
|
|
862
|
+
* @param {object} msg 消息上下文
|
|
863
|
+
* @returns {object} 表单数据
|
|
864
|
+
* @private
|
|
865
|
+
*/
|
|
866
|
+
Drive.prototype._getForm = function (msg) {
|
|
867
|
+
if (msg.form) {
|
|
868
|
+
return msg.form.toJson();
|
|
869
|
+
}
|
|
870
|
+
return {};
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* 处理填充参数
|
|
875
|
+
* @param {Array} paramList 参数列表
|
|
876
|
+
* @param {object} form 表单数据
|
|
877
|
+
* @param {string} ct 内容
|
|
878
|
+
* @param {object} msg 消息上下文
|
|
879
|
+
* @param {object} db 数据管理器
|
|
880
|
+
* @returns {object} 处理结果
|
|
881
|
+
* @private
|
|
882
|
+
*/
|
|
883
|
+
Drive.prototype._processFillParams = async function (paramList, form, ct, msg, db) {
|
|
884
|
+
var keyword = '';
|
|
885
|
+
var tip = '';
|
|
886
|
+
var new_ct = ct;
|
|
887
|
+
var new_form = { ...form };
|
|
888
|
+
for (var i = 0; i < paramList.length; i++) {
|
|
889
|
+
var o = paramList[i];
|
|
890
|
+
var k = o.name;
|
|
891
|
+
if (!new_form[k]) {
|
|
892
|
+
var result = await this._processParam(o, new_ct, msg, db);
|
|
893
|
+
if (result.value) {
|
|
894
|
+
new_form[k] = result.value;
|
|
895
|
+
new_ct = '';
|
|
896
|
+
} else {
|
|
897
|
+
tip = result.tip;
|
|
898
|
+
if (new_ct) {
|
|
899
|
+
break;
|
|
900
|
+
} else {
|
|
901
|
+
keyword = k;
|
|
902
|
+
break;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
return { keyword, tip, form: new_form };
|
|
908
|
+
};
|
|
909
|
+
|
|
910
|
+
/**
|
|
911
|
+
* 处理单个参数
|
|
912
|
+
* @param {object} param 参数对象
|
|
913
|
+
* @param {string} ct 内容
|
|
914
|
+
* @param {object} msg 消息上下文
|
|
915
|
+
* @param {object} db 数据管理器
|
|
916
|
+
* @returns {object} 处理结果
|
|
917
|
+
* @private
|
|
918
|
+
*/
|
|
919
|
+
Drive.prototype._processParam = async function (param, ct, msg, db) {
|
|
920
|
+
if (ct) {
|
|
921
|
+
var value = ct;
|
|
922
|
+
if (param.format) {
|
|
923
|
+
value = value.matchs(param.format);
|
|
924
|
+
}
|
|
925
|
+
if (value) {
|
|
926
|
+
return { value, tip: '' };
|
|
927
|
+
} else if (param.error_tip) {
|
|
928
|
+
var tip = await this.viewTip(msg, db, param.error_tip);
|
|
929
|
+
return { value: null, tip };
|
|
930
|
+
} else if (param.not_tip) {
|
|
931
|
+
var tip = await this.viewTip(msg, db, param.not_tip);
|
|
932
|
+
return { value: null, tip };
|
|
933
|
+
}
|
|
934
|
+
} else if (param.not_tip) {
|
|
935
|
+
var tip = await this.viewTip(msg, db, param.not_tip);
|
|
936
|
+
return { value: null, tip };
|
|
937
|
+
}
|
|
938
|
+
return { value: null, tip: '' };
|
|
939
|
+
};
|
|
940
|
+
|
|
941
|
+
/**
|
|
942
|
+
* 更新消息表单
|
|
943
|
+
* @param {object} msg 消息上下文
|
|
944
|
+
* @param {object} db 数据管理器
|
|
945
|
+
* @param {object} form 表单数据
|
|
946
|
+
* @param {string} keyword 关键词
|
|
947
|
+
* @private
|
|
948
|
+
*/
|
|
949
|
+
Drive.prototype._updateMsgForm = function (msg, db, form, keyword) {
|
|
950
|
+
msg.form = JSON.stringify(form);
|
|
951
|
+
db.form = form;
|
|
952
|
+
msg.keyword = keyword;
|
|
953
|
+
};
|
|
954
|
+
|
|
955
|
+
/**
|
|
956
|
+
* 3.2 更新信息 用于用户更改完善
|
|
957
|
+
* @param {object} msg 消息上下文
|
|
958
|
+
* @param {object} db 数据管理器
|
|
959
|
+
* @param {object} stage 阶段参数
|
|
960
|
+
* @returns {object} 返回参数表单
|
|
961
|
+
*/
|
|
962
|
+
Drive.prototype.set = async function (msg, db, stage) {
|
|
963
|
+
if (!stage || !stage.param || stage.param.length === 0) {
|
|
964
|
+
return '';
|
|
965
|
+
}
|
|
966
|
+
var form = this._getForm(msg);
|
|
967
|
+
var ct = msg.content_last || '';
|
|
968
|
+
var result = await this._processSetParams(stage.param, form, ct, msg);
|
|
969
|
+
this._updateMsgFormOnly(msg, db, result.form);
|
|
970
|
+
return result.tip;
|
|
971
|
+
};
|
|
972
|
+
|
|
973
|
+
/**
|
|
974
|
+
* 处理设置参数
|
|
975
|
+
* @param {Array} paramList 参数列表
|
|
976
|
+
* @param {object} form 表单数据
|
|
977
|
+
* @param {string} ct 内容
|
|
978
|
+
* @param {object} msg 消息上下文
|
|
979
|
+
* @returns {object} 处理结果
|
|
980
|
+
* @private
|
|
981
|
+
*/
|
|
982
|
+
Drive.prototype._processSetParams = async function (paramList, form, ct = '', msg = {}) {
|
|
983
|
+
var new_form = { ...form };
|
|
984
|
+
for (var i = 0; i < paramList.length; i++) {
|
|
985
|
+
var o = paramList[i];
|
|
986
|
+
var k = o.name;
|
|
987
|
+
if (new_form[k]) {
|
|
988
|
+
var value = ct.matchs(o.listen);
|
|
989
|
+
if (value) {
|
|
990
|
+
var tip = this._generateUpdateTip(o, value);
|
|
991
|
+
msg.note = k;
|
|
992
|
+
return { tip, form: new_form };
|
|
993
|
+
} else if (msg.note == k && o.format) {
|
|
994
|
+
value = ct.matchs(o.format);
|
|
995
|
+
if (value) {
|
|
996
|
+
new_form[k] = value;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
return { tip: '', form: new_form };
|
|
1002
|
+
};
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* 生成更新提示
|
|
1006
|
+
* @param {object} param 参数对象
|
|
1007
|
+
* @param {string} value 值
|
|
1008
|
+
* @returns {string} 提示信息
|
|
1009
|
+
* @private
|
|
1010
|
+
*/
|
|
1011
|
+
Drive.prototype._generateUpdateTip = function (param, value) {
|
|
1012
|
+
if (param.update_tip) {
|
|
1013
|
+
return param.update_tip;
|
|
1014
|
+
}
|
|
1015
|
+
return '那' + value.replace(value.matchs('{不对}'), '是?');
|
|
1016
|
+
};
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* 仅更新消息表单
|
|
1020
|
+
* @param {object} msg 消息上下文
|
|
1021
|
+
* @param {object} db 数据管理器
|
|
1022
|
+
* @param {object} form 表单数据
|
|
1023
|
+
* @private
|
|
1024
|
+
*/
|
|
1025
|
+
Drive.prototype._updateMsgFormOnly = function (msg, db, form) {
|
|
1026
|
+
msg.form = JSON.stringify(form);
|
|
1027
|
+
db.form = form;
|
|
1028
|
+
};
|
|
1029
|
+
|
|
1030
|
+
/**
|
|
1031
|
+
* 4. 执行阶段
|
|
1032
|
+
* @param {object} msg 消息上下文
|
|
1033
|
+
* @param {object} db 数据管理器
|
|
1034
|
+
* @returns {object} 返回执行结果
|
|
1035
|
+
*/
|
|
1036
|
+
Drive.prototype.chat = async function (msg, db) {
|
|
1037
|
+
// 如果有表单数据,使用表单执行
|
|
1038
|
+
if (msg.form) {
|
|
1039
|
+
return await this._execForm(msg, db);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
// 否则使用自然语言理解执行
|
|
1043
|
+
return await this._execNLP(msg, db);
|
|
1044
|
+
};
|
|
1045
|
+
|
|
1046
|
+
/**
|
|
1047
|
+
* 执行指令主函数
|
|
1048
|
+
* @param {object} msg 消息上下文
|
|
1049
|
+
* @param {object} db 数据管理器
|
|
1050
|
+
* @returns {object} 执行结果
|
|
1051
|
+
*/
|
|
1052
|
+
Drive.prototype.main = async function (msg, db) {
|
|
1053
|
+
console.log('执行指令主函数', msg.content, db.ret);
|
|
1054
|
+
};
|
|
1055
|
+
|
|
1056
|
+
/**
|
|
1057
|
+
* 使用表单数据执行指令
|
|
1058
|
+
* @param {object} msg 消息上下文
|
|
1059
|
+
* @param {object} db 数据管理器
|
|
1060
|
+
* @returns {object} 返回执行结果
|
|
1061
|
+
* @private
|
|
1062
|
+
*/
|
|
1063
|
+
Drive.prototype._execForm = async function (msg, db) {
|
|
1064
|
+
var form_data = msg.form.toJson();
|
|
1065
|
+
|
|
1066
|
+
// 这里可以根据具体的指令逻辑进行处理
|
|
1067
|
+
// 示例:返回表单数据确认
|
|
1068
|
+
var result = '指令执行完成,参数如下:\\n';
|
|
1069
|
+
|
|
1070
|
+
for (var key in form_data) {
|
|
1071
|
+
if (form_data.hasOwnProperty(key)) {
|
|
1072
|
+
result += `${key}: ${form_data[key]}\\n`;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
return result;
|
|
1077
|
+
};
|
|
1078
|
+
|
|
1079
|
+
/**
|
|
1080
|
+
* 使用自然语言理解执行指令
|
|
1081
|
+
* @param {object} msg 消息上下文
|
|
1082
|
+
* @param {object} db 数据管理器
|
|
1083
|
+
* @returns {object} 返回执行结果
|
|
1084
|
+
* @private
|
|
1085
|
+
*/
|
|
1086
|
+
Drive.prototype._execNLP = async function (msg, db) {
|
|
1087
|
+
// 分析用户意图
|
|
1088
|
+
var intent = this._analyzeIntent(msg.content);
|
|
1089
|
+
|
|
1090
|
+
// 根据意图执行相应的逻辑
|
|
1091
|
+
switch (intent.type) {
|
|
1092
|
+
case 'query':
|
|
1093
|
+
return await this._handleQueryIntent(intent, msg, db);
|
|
1094
|
+
case 'action':
|
|
1095
|
+
return await this._handleActionIntent(intent, msg, db);
|
|
1096
|
+
case 'help':
|
|
1097
|
+
return await this._handleHelpIntent(intent, msg, db);
|
|
1098
|
+
default:
|
|
1099
|
+
return await this._handleDefaultIntent(intent, msg, db);
|
|
1100
|
+
}
|
|
1101
|
+
};
|
|
1102
|
+
|
|
1103
|
+
/**
|
|
1104
|
+
* 分析用户意图
|
|
1105
|
+
* @param {string} content 消息内容
|
|
1106
|
+
* @returns {object} 返回意图分析结果
|
|
1107
|
+
* @private
|
|
1108
|
+
*/
|
|
1109
|
+
Drive.prototype._analyzeIntent = function (content) {
|
|
1110
|
+
var intent = {
|
|
1111
|
+
type: 'unknown',
|
|
1112
|
+
confidence: 0.5,
|
|
1113
|
+
entities: [],
|
|
1114
|
+
keywords: []
|
|
1115
|
+
};
|
|
1116
|
+
|
|
1117
|
+
var content = content.toLowerCase();
|
|
1118
|
+
|
|
1119
|
+
// 查询类意图
|
|
1120
|
+
var query_keywords = ['查询', '查找', '搜索', '查一下', '找一下', '什么是', '哪里', '什么时候'];
|
|
1121
|
+
// 操作类意图
|
|
1122
|
+
var action_keywords = ['执行', '运行', '启动', '打开', '关闭', '设置', '配置'];
|
|
1123
|
+
// 帮助类意图
|
|
1124
|
+
var help_keywords = ['帮助', '怎么用', '如何使用', '说明', '介绍'];
|
|
1125
|
+
|
|
1126
|
+
// 检查意图类型
|
|
1127
|
+
for (var i = 0; i < query_keywords.length; i++) {
|
|
1128
|
+
if (content.includes(query_keywords[i])) {
|
|
1129
|
+
intent.type = 'query';
|
|
1130
|
+
intent.confidence = 0.8;
|
|
1131
|
+
break;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
for (var i = 0; i < action_keywords.length; i++) {
|
|
1136
|
+
if (content.includes(action_keywords[i])) {
|
|
1137
|
+
intent.type = 'action';
|
|
1138
|
+
intent.confidence = 0.8;
|
|
1139
|
+
break;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
for (var i = 0; i < help_keywords.length; i++) {
|
|
1144
|
+
if (content.includes(help_keywords[i])) {
|
|
1145
|
+
intent.type = 'help';
|
|
1146
|
+
intent.confidence = 0.9;
|
|
1147
|
+
break;
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
// 提取实体和关键词
|
|
1152
|
+
intent.entities = this._extractEntities(content);
|
|
1153
|
+
intent.keywords = this._extractKeywords(content);
|
|
1154
|
+
|
|
1155
|
+
return intent;
|
|
1156
|
+
};
|
|
1157
|
+
|
|
1158
|
+
/**
|
|
1159
|
+
* 提取实体
|
|
1160
|
+
* @param {string} content 消息内容
|
|
1161
|
+
* @returns {Array} 返回实体数组
|
|
1162
|
+
* @private
|
|
1163
|
+
*/
|
|
1164
|
+
Drive.prototype._extractEntities = function (content) {
|
|
1165
|
+
var entities = [];
|
|
1166
|
+
|
|
1167
|
+
// 提取时间实体
|
|
1168
|
+
var time_patterns = [/\d{4}-\d{2}-\d{2}/, /\d{2}:\d{2}/, /今天|明天|昨天|本周|本月|今年/];
|
|
1169
|
+
// 提取数字实体
|
|
1170
|
+
var number_patterns = [/\d+/];
|
|
1171
|
+
// 提取地点实体
|
|
1172
|
+
var location_patterns = [/在.+?(?:市|区|县|街道|路|号)/];
|
|
1173
|
+
|
|
1174
|
+
// 这里可以添加更复杂的实体提取逻辑
|
|
1175
|
+
|
|
1176
|
+
return entities;
|
|
1177
|
+
};
|
|
1178
|
+
|
|
1179
|
+
/**
|
|
1180
|
+
* 从内容中提取关键词
|
|
1181
|
+
* @param {string} content 消息内容
|
|
1182
|
+
* @returns {Array} 返回关键词数组
|
|
1183
|
+
* @private
|
|
1184
|
+
*/
|
|
1185
|
+
Drive.prototype._extractKeywords = function (content) {
|
|
1186
|
+
var words = content.split(/[\s\p{P}]/u).filter(function (word) {
|
|
1187
|
+
return word.length > 1 && !['的', '了', '在', '是', '有', '和', '与', '或'].includes(word);
|
|
1188
|
+
});
|
|
1189
|
+
|
|
1190
|
+
return words;
|
|
1191
|
+
};
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* 处理查询意图
|
|
1195
|
+
* @param {object} intent 意图对象
|
|
1196
|
+
* @param {object} msg 消息上下文
|
|
1197
|
+
* @param {object} db 数据管理器
|
|
1198
|
+
* @returns {string} 返回查询结果
|
|
1199
|
+
* @private
|
|
1200
|
+
*/
|
|
1201
|
+
Drive.prototype._handleQueryIntent = async function (intent, msg, db) {
|
|
1202
|
+
return `正在为您查询关于"${msg.content}"的信息...`;
|
|
1203
|
+
};
|
|
1204
|
+
|
|
1205
|
+
/**
|
|
1206
|
+
* 处理操作意图
|
|
1207
|
+
* @param {object} intent 意图对象
|
|
1208
|
+
* @param {object} msg 消息上下文
|
|
1209
|
+
* @param {object} db 数据管理器
|
|
1210
|
+
* @returns {string} 返回操作结果
|
|
1211
|
+
* @private
|
|
1212
|
+
*/
|
|
1213
|
+
Drive.prototype._handleActionIntent = async function (intent, msg, db) {
|
|
1214
|
+
return `正在执行"${msg.content}"操作...`;
|
|
1215
|
+
};
|
|
1216
|
+
|
|
1217
|
+
/**
|
|
1218
|
+
* 处理帮助意图
|
|
1219
|
+
* @param {object} intent 意图对象
|
|
1220
|
+
* @param {object} msg 消息上下文
|
|
1221
|
+
* @param {object} db 数据管理器
|
|
1222
|
+
* @returns {string} 返回帮助信息
|
|
1223
|
+
* @private
|
|
1224
|
+
*/
|
|
1225
|
+
Drive.prototype._handleHelpIntent = async function (intent, msg, db) {
|
|
1226
|
+
var help_text = `指令帮助:${this.config.title}\\n`;
|
|
1227
|
+
help_text += `描述:${this.config.description}\\n`;
|
|
1228
|
+
help_text += `使用方法:${this._generateUsageExamples()}`;
|
|
1229
|
+
|
|
1230
|
+
return help_text;
|
|
1231
|
+
};
|
|
1232
|
+
|
|
1233
|
+
/**
|
|
1234
|
+
* 处理默认意图
|
|
1235
|
+
* @param {object} intent 意图对象
|
|
1236
|
+
* @param {object} msg 消息上下文
|
|
1237
|
+
* @param {object} db 数据管理器
|
|
1238
|
+
* @returns {string} 返回默认回复
|
|
1239
|
+
* @private
|
|
1240
|
+
*/
|
|
1241
|
+
Drive.prototype._handleDefaultIntent = async function (intent, msg, db) {
|
|
1242
|
+
return `已收到您的指令:${msg.content}`;
|
|
1243
|
+
};
|
|
1244
|
+
|
|
1245
|
+
/**
|
|
1246
|
+
* 生成使用示例
|
|
1247
|
+
* @returns {string} 返回使用示例
|
|
1248
|
+
* @private
|
|
1249
|
+
*/
|
|
1250
|
+
Drive.prototype._generateUsageExamples = function () {
|
|
1251
|
+
var examples = [];
|
|
1252
|
+
|
|
1253
|
+
// 根据指令类型生成不同的示例
|
|
1254
|
+
switch (this.config.type) {
|
|
1255
|
+
case 'query':
|
|
1256
|
+
examples.push('• 查询信息:"查询天气"');
|
|
1257
|
+
examples.push('• 搜索内容:"搜索新闻"');
|
|
1258
|
+
break;
|
|
1259
|
+
case 'action':
|
|
1260
|
+
examples.push('• 执行操作:"执行任务"');
|
|
1261
|
+
examples.push('• 启动功能:"启动服务"');
|
|
1262
|
+
break;
|
|
1263
|
+
case 'game':
|
|
1264
|
+
examples.push('• 开始游戏:"开始游戏"');
|
|
1265
|
+
examples.push('• 游戏操作:"移动角色"');
|
|
1266
|
+
break;
|
|
1267
|
+
default:
|
|
1268
|
+
examples.push('• 使用指令:直接说出您的需求');
|
|
1269
|
+
examples.push('• 获取帮助:"帮助"或"怎么用"');
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
return examples.join('\\n');
|
|
1273
|
+
};
|
|
1274
|
+
|
|
1275
|
+
/**
|
|
1276
|
+
* 5. 结束阶段 用来判断是否结束会话
|
|
1277
|
+
* @param {object} msg 消息上下文
|
|
1278
|
+
* @param {object} db 数据管理器
|
|
1279
|
+
* @param {object} ret 执行结果
|
|
1280
|
+
* @returns {boolean} 返回会话结果
|
|
1281
|
+
*/
|
|
1282
|
+
Drive.prototype.end = async function (msg, db, ret) {
|
|
1283
|
+
if (ret) {
|
|
1284
|
+
var txt = '';
|
|
1285
|
+
if (typeof (ret) == 'object') {
|
|
1286
|
+
txt = JSON.stringify(ret);
|
|
1287
|
+
} else {
|
|
1288
|
+
txt = ret;
|
|
1289
|
+
}
|
|
1290
|
+
if (this.config.tense == 'main') {
|
|
1291
|
+
if (txt.indexOf('?') === -1 && txt.indexOf('?') === -1) {
|
|
1292
|
+
msg.end = 0;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
return ret;
|
|
1297
|
+
};
|
|
1298
|
+
|
|
1299
|
+
/**
|
|
1300
|
+
* 执行前 用于有历史信息时,直接获取,不重复询问
|
|
1301
|
+
* @param {object} msg 消息上下文
|
|
1302
|
+
* @param {object} db 数据管理器
|
|
1303
|
+
* @returns {object} 执行结果, 如果有结果则直接跳过其他步骤,并返回
|
|
1304
|
+
*/
|
|
1305
|
+
Drive.prototype.runBefore = async function (msg, db) {
|
|
1306
|
+
return null;
|
|
1307
|
+
};
|
|
1308
|
+
|
|
1309
|
+
/**
|
|
1310
|
+
* 执行后, 用于特殊情况下的不结束会话
|
|
1311
|
+
* @param {object} msg 消息上下文
|
|
1312
|
+
* @param {object} db 数据管理器
|
|
1313
|
+
* @param {object} ret 执行结果
|
|
1314
|
+
* @returns {object|string} 返回执行结果
|
|
1315
|
+
*/
|
|
1316
|
+
Drive.prototype.runAfter = async function (msg, db, ret) {
|
|
1317
|
+
return ret;
|
|
1318
|
+
};
|
|
1319
|
+
|
|
1320
|
+
/**
|
|
1321
|
+
* 执行
|
|
1322
|
+
* @param {object} msg 消息上下文
|
|
1323
|
+
* @param {object} db 数据管理器
|
|
1324
|
+
* @returns {object} 返回执行结果
|
|
1325
|
+
*/
|
|
1326
|
+
Drive.prototype.run = async function (msg, db) {
|
|
1327
|
+
var ret;
|
|
1328
|
+
try {
|
|
1329
|
+
// 第一步, 验证阶段
|
|
1330
|
+
var match = await this.check(msg, db);
|
|
1331
|
+
if (!match) {
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
msg.match = typeof match === 'string' ? match.substring(0, 255) : JSON.stringify(match).substring(0, 255);
|
|
1335
|
+
// 第二步, 过滤阶段
|
|
1336
|
+
await this.filter(msg, db);
|
|
1337
|
+
|
|
1338
|
+
// 执行前
|
|
1339
|
+
ret = await this.runBefore(msg, db);
|
|
1340
|
+
if (!ret) {
|
|
1341
|
+
// 第三步, 信息补全或更新阶段
|
|
1342
|
+
var stages = this.config.stage;
|
|
1343
|
+
if (stages.length >= msg.stage) {
|
|
1344
|
+
var stage = stages[msg.stage - 1];
|
|
1345
|
+
if (stage) {
|
|
1346
|
+
var mode = stage.mode ? stage.mode : 'fill';
|
|
1347
|
+
if (this[mode]) {
|
|
1348
|
+
ret = await this[mode](msg, db, stage);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
if (!ret) {
|
|
1354
|
+
// 第四步, 执行阶段
|
|
1355
|
+
ret = await this.main(msg, db);
|
|
1356
|
+
|
|
1357
|
+
// 第五步, 结束会话阶段
|
|
1358
|
+
ret = this.end(msg, db, ret);
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
// 执行后
|
|
1362
|
+
ret = await this.runAfter(msg, db, ret);
|
|
1363
|
+
} catch (error) {
|
|
1364
|
+
this.log('error', '指令执行失败!', this.config.name, error);
|
|
1365
|
+
|
|
1366
|
+
// 错误处理:如果指令执行失败,可以回退到AI处理
|
|
1367
|
+
if (this._shouldFallbackToAI(error)) {
|
|
1368
|
+
ret = await this._fallbackToAI(msg, db);
|
|
1369
|
+
} else {
|
|
1370
|
+
ret = '指令执行失败,请稍后重试';
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
return ret;
|
|
1374
|
+
};
|
|
1375
|
+
|
|
1376
|
+
/**
|
|
1377
|
+
* 判断是否应该回退到AI处理
|
|
1378
|
+
* @param {Error} error 错误对象
|
|
1379
|
+
* @returns {boolean} 返回是否应该回退
|
|
1380
|
+
* @private
|
|
1381
|
+
*/
|
|
1382
|
+
Drive.prototype._shouldFallbackToAI = function (error) {
|
|
1383
|
+
// 检查是否配置了AI回退
|
|
1384
|
+
var cmd = this.getCmdManager();
|
|
1385
|
+
if (!cmd || !cmd.config.deepseek.enable) {
|
|
1386
|
+
return false;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
// 检查错误类型,如果是可恢复的错误,允许回退
|
|
1390
|
+
var recoverable_errors = [
|
|
1391
|
+
'参数缺失',
|
|
1392
|
+
'格式错误',
|
|
1393
|
+
'无法理解',
|
|
1394
|
+
'未找到'
|
|
1395
|
+
];
|
|
1396
|
+
|
|
1397
|
+
var error_message = error.message.toLowerCase();
|
|
1398
|
+
for (var i = 0; i < recoverable_errors.length; i++) {
|
|
1399
|
+
if (error_message.includes(recoverable_errors[i].toLowerCase())) {
|
|
1400
|
+
return true;
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
return false;
|
|
1405
|
+
};
|
|
1406
|
+
|
|
1407
|
+
/**
|
|
1408
|
+
* 回退到AI处理
|
|
1409
|
+
* @param {object} msg 消息上下文
|
|
1410
|
+
* @param {object} db 数据管理器
|
|
1411
|
+
* @returns {string} 返回AI的回复
|
|
1412
|
+
* @private
|
|
1413
|
+
*/
|
|
1414
|
+
Drive.prototype._fallbackToAI = async function (msg, db) {
|
|
1415
|
+
var cmd = this.getCmdManager();
|
|
1416
|
+
if (!cmd) {
|
|
1417
|
+
return '指令执行失败,无法回退到AI处理';
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
// 构建包含指令信息的上下文
|
|
1421
|
+
var enhanced_msg = {
|
|
1422
|
+
...msg,
|
|
1423
|
+
content: `指令"${this.config.title}"执行失败,用户原话:${msg.content}`
|
|
1424
|
+
};
|
|
1425
|
+
|
|
1426
|
+
return await cmd._runAI(enhanced_msg, db);
|
|
1427
|
+
};
|
|
1428
|
+
|
|
1429
|
+
/**
|
|
1430
|
+
* 获取Cmd管理器
|
|
1431
|
+
* @returns {object} 返回Cmd管理器实例
|
|
1432
|
+
* @private
|
|
1433
|
+
*/
|
|
1434
|
+
Drive.prototype.getCmdManager = function () {
|
|
1435
|
+
// 这里需要根据实际的项目结构来获取Cmd管理器
|
|
1436
|
+
// 假设可以通过全局对象或父级引用获取
|
|
1437
|
+
if (typeof $ !== 'undefined' && $.admin && $.admin.cmd) {
|
|
1438
|
+
return $.admin.cmd();
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
return null;
|
|
1442
|
+
};
|
|
1443
|
+
|
|
1444
|
+
/**
|
|
1445
|
+
* 增强的过滤方法,支持自然语言理解
|
|
1446
|
+
* @param {object} msg 消息上下文
|
|
1447
|
+
* @param {object} db 数据管理器
|
|
1448
|
+
* @returns {object} 返回过滤后的参数
|
|
1449
|
+
*/
|
|
1450
|
+
Drive.prototype.enhancedFilter = async function (msg, db) {
|
|
1451
|
+
// 先执行原有的过滤逻辑
|
|
1452
|
+
var result = await this.filter(msg, db);
|
|
1453
|
+
|
|
1454
|
+
// 如果过滤后没有结果,尝试使用NLP提取关键信息
|
|
1455
|
+
if (!result || result === msg.content) {
|
|
1456
|
+
var nlp_result = await this._extractNLP(msg.content);
|
|
1457
|
+
if (nlp_result) {
|
|
1458
|
+
msg.keyword = nlp_result;
|
|
1459
|
+
return nlp_result;
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
return result;
|
|
1464
|
+
};
|
|
1465
|
+
|
|
1466
|
+
/**
|
|
1467
|
+
* 使用NLP提取关键信息
|
|
1468
|
+
* @param {string} content 消息内容
|
|
1469
|
+
* @returns {string} 返回提取的关键信息
|
|
1470
|
+
* @private
|
|
1471
|
+
*/
|
|
1472
|
+
Drive.prototype._extractNLP = async function (content) {
|
|
1473
|
+
// 这里可以集成更复杂的NLP处理
|
|
1474
|
+
// 目前使用简单的关键词提取
|
|
1475
|
+
|
|
1476
|
+
// 移除常见的语气词和连接词
|
|
1477
|
+
var stop_words = ['请', '帮', '我', '想要', '需要', '可以', '吗', '呢', '吧', '啊'];
|
|
1478
|
+
var words = content.split(/[\s\p{P}]/u).filter(function (word) {
|
|
1479
|
+
return word.length > 0 && !stop_words.includes(word);
|
|
1480
|
+
});
|
|
1481
|
+
|
|
1482
|
+
return words.join(' ');
|
|
1483
|
+
};
|
|
1484
|
+
|
|
1485
|
+
/**
|
|
1486
|
+
* 查看参数
|
|
1487
|
+
* @param {object} msg 消息上下文
|
|
1488
|
+
* @param {object} db 数据管理器
|
|
1489
|
+
* @returns {object} 返回结构化参数
|
|
1490
|
+
*/
|
|
1491
|
+
Drive.prototype.view = function (msg, db) {
|
|
1492
|
+
var ret = '';
|
|
1493
|
+
if (msg.form) {
|
|
1494
|
+
var json = msg.form.toJson();
|
|
1495
|
+
var stage = this.config.stage;
|
|
1496
|
+
if (stage && stage.length >= msg.stage) {
|
|
1497
|
+
var list = stage[msg.stage - 1].param;
|
|
1498
|
+
if (list) {
|
|
1499
|
+
for (var i = 0; i < list.length; i++) {
|
|
1500
|
+
var o = list[i];
|
|
1501
|
+
var value = json[o.name];
|
|
1502
|
+
if (value) {
|
|
1503
|
+
ret += o.title + ': ' + value + '\r\n';
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
return ret.trim();
|
|
1510
|
+
};
|
|
1511
|
+
|
|
1512
|
+
/**
|
|
1513
|
+
* 获取插件
|
|
1514
|
+
* @param {string} app 应用名称
|
|
1515
|
+
* @param {string} name 插件名称
|
|
1516
|
+
* @returns {object} 返回获取到的插件
|
|
1517
|
+
*/
|
|
1518
|
+
Drive.prototype.plugin = function (app, name) {
|
|
1519
|
+
var l = $.slash;
|
|
1520
|
+
var app_name = app || this.config_file.between('app' + l, l);
|
|
1521
|
+
var plugin_name = name || this.config_file.between('plugin' + l, l);
|
|
1522
|
+
var plus;
|
|
1523
|
+
var plugins = $.pool.plugin[app_name];
|
|
1524
|
+
if (plugins) {
|
|
1525
|
+
plus = plugins.get(plugin_name);
|
|
1526
|
+
}
|
|
1527
|
+
return plus;
|
|
1528
|
+
};
|
|
1529
|
+
|
|
1530
|
+
/**
|
|
1531
|
+
* 获取模型
|
|
1532
|
+
* @param {string} type 模型类型
|
|
1533
|
+
* @returns {object} 返回获取到的模型
|
|
1534
|
+
*/
|
|
1535
|
+
Drive.prototype.getModel = function (type) {
|
|
1536
|
+
let model = { ...this.config };
|
|
1537
|
+
let dir = this._getDir();
|
|
1538
|
+
let l = $.slash;
|
|
1539
|
+
let app_name = dir.between('app' + l, l);
|
|
1540
|
+
let plugin_name = dir.between('plugin' + l, l);
|
|
1541
|
+
let name = dir.basename();
|
|
1542
|
+
model.app = app_name;
|
|
1543
|
+
model.plugin = plugin_name;
|
|
1544
|
+
model.name = model.name || name;
|
|
1545
|
+
return model;
|
|
1546
|
+
};
|
|
1547
|
+
|
|
1548
|
+
module.exports = Drive;
|