-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathpbottleRPA.js
1758 lines (1547 loc) · 53.8 KB
/
pbottleRPA.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* 小瓶 RPA 标准库API NodeJS版本
* 官网:https://rpa.pbottle.com/
* 作者:[email protected]
*
* 欢迎各路高手将本代码转换成 python、lua、C# 等其他语言封装
*
*/
const request = require('sync-request'); //默认同步请求
const keycode = require('keycode');
const path = require("node:path");
const fs = require("node:fs");
const childProcess = require('node:child_process');
/**
* 当前脚本的路径,结尾无/ 如 'D:/pbottleRPAdemo'
*/
const jsPath = path.resolve('./');
const CppUrl = `http://127.0.0.1:49888/`
let basePath = ''; //基座路径
console.log("基座服务地址:(NodeJS)",CppUrl);
exports.jsPath = jsPath
exports.basePath = basePath
exports.__dirname = jsPath
exports.目录路径 = jsPath
let defaultDelay = 1000; //默认值一秒
/**
* 设置RPA模拟操作的延时 包含鼠标、键盘、粘贴、打开网页操作
* 设置为 0 可以用 sleep() 手动管理操作延时
* @param {number} millisecond 毫秒单位的数字,系统默认 1000 毫秒 即1秒
*/
let setDefaultDelay = (millisecond)=>{
defaultDelay = millisecond
}
exports.setDefaultDelay = setDefaultDelay
exports.设置默认操作延时 = setDefaultDelay
/**
* 获取并设置基座平台的根目录路径 | V2025.0 以上版本启用
* @returns {string}
*/
function getBasePath() {
if (basePath) {
return basePath;
}
let url = `${CppUrl}?action=basePath`
let res = request('GET', url);
basePath = res.getBody('utf8')
return basePath;
}
exports.getBasePath = getBasePath
/**
* 发出系统警告声音
* @returns
*/
let beep = ()=>{
let url = `${CppUrl}?action=beep`
// console.log(url)
let res = request('GET', url);
return res;
}
exports.beep = beep
exports.蜂鸣声 = beep
/**
* 日志输出,同时生成文件日志
*/
exports.log = console.log
exports.日志输出 = console.log
/**
* 系统原生消息提示
* @param {string} title 标题
* @param {string} content 内容
* @returns
*/
let showMsg = (title,content)=>{
title = encodeURIComponent(title)
content = encodeURIComponent(content)
let url = `${CppUrl}?action=showMsg&title=${title}&content=${content}`
// console.log(url)
let res = request('GET', url);
return res;
}
exports.showMsg = showMsg
exports.显示系统消息 = showMsg
/**
* (强行)关闭指定软件
* @param {string} processName 进程名称,如:'WINWORD.EXE' 任务管理器 ‘进程名称’ 栏目 。注意不是 名称,如不显示,右键勾选显示这一栏目即可
* @param {boolean} force 是否强制,相当于模拟任务管理器的结束任务操作。默认普通关闭,可能跟随保存确认框
*/
let kill = (processName,force=false)=>{
let forceCMD = ''
if (force) {
forceCMD = '/F'
}
try {
childProcess.execSync(`taskkill ${forceCMD} /IM ${processName}`,{ stdio: 'ignore',encoding: 'utf8' })
} catch (error) {
console.error(`关闭进程(${processName})失败,可能软件未运行`);
return;
}
console.log('关闭进程成功:' + processName);
}
exports.kill = kill
exports.关闭软件 = kill
/**
* 有效屏幕内显示一个彩色方框,直观提示流程操作范围和目标的当前的定位
* V2024.6以上版本有效
* @param {number} fromX 起始位置xy坐标,屏幕左上角为零点
* @param {number} fromY
* @param {number} width 宽度
* @param {number} height 高度
* @param {string} color 颜色 红绿蓝黄4色可选:red|green|blue|yellow
* @param {number} msec 显示持续时间 单位毫秒
* @returns
*/
let showRect = (fromX=0,fromY=0,width=500,height=500,color='red',msec=500)=>{
color = encodeURIComponent(color)
let url = `${CppUrl}?action=showRect&fromX=${fromX}&fromY=${fromY}&width=${width}&height=${height}&color=${color}&msec=${msec}`
// console.log(url)
let res = request('GET', url);
return res;
}
exports.showRect = showRect
exports.显示标记框 = showRect
/**
* 强制退出当前脚本
* @param {string} msg 退出时候输出的信息
*/
let exit = (msg='')=>{
if (msg) {
console.log(msg)
}
beep()
process.exit(1)
}
exports.exit = exit
exports.退出流程 = exit
/**
* 脚本暂停等待操作响应 (毫秒)
* 注意:一次等待上限时长两分钟内
* @param {number} milliseconds 毫秒
* @returns
*/
let sleep = (milliseconds)=>{
if(milliseconds<1){
// console.log('milliseconds input error');
return;
}
if (milliseconds>=120000) {
console.log('警告:一次等待上限时长两分钟内');
}
let url = `${CppUrl}?action=httpSleep&milliseconds=${milliseconds}`
// console.log(url)
let res = request('GET', url);
return res;
}
exports.sleep = sleep
exports.睡眠毫秒 = sleep
/**
* 脚本暂停等待操作响应 (秒)
* 注意:一次等待上限时长两分钟内
* @param {number} seconds 秒, 缺省值为 1 秒
* @returns
*/
let wait = (seconds = 1)=>{
if(seconds<=0 || !isNumeric(seconds)){
console.log('pbottle.wait:seconds input error');
return;
}
sleep(seconds*1000)
}
exports.wait = wait
exports.等待 = wait
/**
* 移动鼠标到指定位置并点击 起点为屏幕左上角
* @param {number} x 横坐标
* @param {number} y 纵坐标
* @param {number} interval 像素间隔时间,越大移动越慢 毫秒单位,默认:0
* @returns
*/
let moveMouseSmooth = (x,y,interval=0)=>{
x=Math.round(x)
y=Math.round(y)
let url = `${CppUrl}?action=moveMouse&x=${x}&y=${y}&interval=${interval}`
// console.log(url)
let res = request('GET', url);
sleep(defaultDelay);
return res;
}
exports.moveMouseSmooth = moveMouseSmooth
exports.moveMouse = moveMouseSmooth //增加别名
exports.鼠标移动 = moveMouseSmooth
/**
* 移动鼠标到指定位置并点击
* @param {number} x 横坐标
* @param {number} y 纵坐标
*/
let moveAndClick = (x,y)=>{
this.moveMouse(x,y)
this.mouseClick()
}
exports.moveAndClick = moveAndClick
exports.鼠标移动并点击 = moveAndClick
/**
* 当前位置点击鼠标 默认左键 可选 'right'
* @param {string} leftRight 可选
* @param {number} time 点按时间 单位毫秒 可选
* @returns
*/
let mouseClick = (leftRight = 'left',time=30)=>{
let url = `${CppUrl}?action=mouseLeftClick&time=${time}`
if (leftRight == 'right') {
url = `${CppUrl}?action=mouseRightClick&time=${time}`
}
// console.log(url)
let res = request('GET', url);
sleep(defaultDelay);
return res;
}
exports.mouseClick = mouseClick
exports.鼠标点击 = mouseClick
/**
* 双击鼠标 默认左键
* @returns
*/
let mouseDoubleClick = ()=>{
let url = `${CppUrl}?action=mouseDoubleClick`
// console.log(url)
let res = request('GET', url);
sleep(defaultDelay);
return res;
}
exports.mouseDoubleClick = mouseDoubleClick
exports.鼠标双击 = mouseDoubleClick
/**
* 鼠标滚轮
* @param {number} data 滚动的量 默认为-720 向下滚动720度
* @returns
*/
let mouseWheel = (data = -720)=>{
let url = `${CppUrl}?action=mouseWheel&data=${data}`
// console.log(url)
let res = request('GET', url);
sleep(defaultDelay);
return res;
}
exports.mouseWheel = mouseWheel
exports.鼠标滚轮 = mouseWheel
/**
* 鼠标左键拖到指定位置
* @param {number} x
* @param {number} y
* @returns
*/
let mouseLeftDragTo = (x,y)=>{
x=Math.round(x)
y=Math.round(y)
let url = `${CppUrl}?action=mouseLeftDragTo&x=${x}&y=${y}`
// console.log(url)
let res = request('GET', url);
sleep(defaultDelay);
return res;
}
exports.mouseLeftDragTo = mouseLeftDragTo
exports.鼠标左键拖动 = mouseLeftDragTo
/**
* 鼠标右键拖到指定位置
* @param {number} x
* @param {number} y
* @returns
*/
let mouseRightDragTo = (x,y)=>{
x=Math.round(x)
y=Math.round(y)
let url = `${CppUrl}?action=mouseRightDragTo&x=${x}&y=${y}`
// console.log(url)
let res = request('GET', url);
sleep(defaultDelay);
return res;
}
exports.mouseRightDragTo = mouseRightDragTo
exports.鼠标右键拖动 = mouseRightDragTo
/**
* 屏幕一个点取色
* @param {number} x
* @param {number} y
* @returns 返回颜色值
*/
let getScreenColor = (x,y)=>{
let url = `${CppUrl}?action=getScreenColor&x=${x}&y=${y}`
// console.log(url)
let res = request('GET', url);
let jsonRes = JSON.parse(res.getBody('utf8'))
return jsonRes.rs;
}
exports.getScreenColor = getScreenColor
exports.获取屏幕颜色 = getScreenColor
/**
* 屏幕截图
* @param {string} savePath 保存路径默认 我的图片,图片格式为PNG;如果使用自定义路径请以 '.png' 结尾;
* @param {number} x 截图开始位置
* @param {number} y
* @param {number} w 可选 截图宽度
* @param {number} h 可选 截图长度
* @returns
*/
let screenShot = (savePath='',x=0,y=0,w=-1,h=-1)=>{
savePath = encodeURIComponent(savePath)
x=parseInt(x)
y=parseInt(y)
w=parseInt(w)
h=parseInt(h)
if (x!=0 || y!=0 || w!=-1 || h!=-1) {
showRect(x,y,w,h);
}
let url = `${CppUrl}?action=screenShot&savePath=${savePath}&x=${x}&y=${y}&w=${w}&h=${h}`
// console.log(url)
let res = request('GET', url);
res = res.getBody('utf8')
return res;
}
exports.screenShot = screenShot
exports.屏幕截图 = screenShot
/**
* 模拟键盘按键触发基础事件
* @param {string} key 按键名称参考:https://www.pbottle.com/a-13862.html
* @param {string} "up" 或 "down" 默认按下down。up松开按键
* @returns
*/
let keyToggle = (key,upDown='down')=>{
let upDown_n = 0;
if (upDown == 'up') {
upDown_n = 2;
}
let key_n = keycode(key)
if (key_n === undefined) {
console.log(`⚠ 按键 ${key} 不存在!~`);
return
}
let url = `${CppUrl}?action=keyToggle&key_n=${key_n}&upDown_n=${upDown_n}`
// console.log(url)
let res = request('GET', url);
return res;
}
exports.keyToggle = keyToggle
exports.键盘基础触发 = keyToggle
/**
* 模拟鼠标按键触发基础事件
* @param {string} key 鼠标 left | right | middle
* @param {string} "up" 或 "down" 默认按下down。up松开按键
* @returns
*/
let mouseKeyToggle = (key='left',upDown='down')=>{
let upDown_n = 0;
if (upDown == 'up') {
upDown_n = 2;
}
let key_n = 0
switch (key) {
case 'right':
key_n = 1
break;
case 'middle':
key_n = 2
break;
default:
key_n = 0
break;
}
let url = `${CppUrl}?action=mouseKeyToggle&key_n=${key_n}&upDown_n=${upDown_n}`
// console.log(url)
let res = request('GET', url);
return res;
}
exports.mouseKeyToggle = mouseKeyToggle
exports.鼠标基础触发 = mouseKeyToggle
/**
* 按一下键盘 支持组合按键 加号连接 如: keyTap('ctrl + a')
* @param {string} key 按键名称参考:https://www.pbottle.com/a-13862.html
*/
let keyTap = (key)=>{
if (key.includes('+')) {
let subkeys = new Array();
subkeys = key.split('+')
subkeys = subkeys.map((value)=>{
return value.trim()
})
for (let index = 0; index < subkeys.length; index++) {
const element = subkeys[index];
keyToggle(element,"up") //净化复位
keyToggle(element,"down")
}
subkeys = subkeys.reverse()
for (let index = 0; index < subkeys.length; index++) {
const element = subkeys[index];
keyToggle(element,"up")
}
}else{
keyToggle(key,"up") //净化复位
keyToggle(key,"down")
keyToggle(key,"up")
}
sleep(defaultDelay);
}
exports.keyTap = keyTap
exports.键盘按键 = keyTap
/**
*
* @typedef {Object} position - 位置坐标
* @property {number} x - 横坐标-从左边开始
* @property {number} y - 纵坐标-从上边开始
*
*/
/**
* 屏幕查找图象定位
* @param {string} tpPath 搜索的小图片,建议png格式 相对路径:./image/123.png
* @param {number} miniSimilarity 可选,指定最低相似度,默认0.85。取值0-1,1为找到完全相同的。
* @param {number} fromX=0 可选,查找开始的开始横坐标
* @param {number} fromY=0 可选,查找开始的开始纵坐标
* @param {number} width=-1 可选,搜索宽度
* @param {number} height=-1 可选,搜索高度
* @returns {position|boolean} 返回找到的结果json 格式:{x,y} 相对于左上角原点
*/
var findScreen = (tpPath,miniSimilarity=0.85,fromX=0,fromY=0,width=-1,height=-1) =>{
if (fromX<0 || fromY<0) {
exit(`错误:找图起始点不能为负,x:${fromX} y:${fromY} `);
}
if (fromX!=0 || fromY!=0 || width!=-1 || height!=-1) {
showRect(fromX,fromY,width,height);
}
tpPath = path.join(jsPath+tpPath)
tpPath = encodeURIComponent(tpPath)
let url = `${CppUrl}?action=findScreen&imgPath=${tpPath}&fromX=${fromX}&fromY=${fromY}&width=${width}&height=${height}`
// console.log(url)
let res = request('GET', url);
// console.log(res.getBody('utf8'));
jsonRes = JSON.parse(res.getBody('utf8'));
// console.log(jsonRes);
if (jsonRes.error) {
console.log(jsonRes.error);
return false;
}
if (jsonRes.value<miniSimilarity) {
return false;
}
showRect(jsonRes.x-25,jsonRes.y-25,50,50,'green');
return jsonRes;
}
exports.findScreen = findScreen
exports.寻找图像 = findScreen
/**
* @typedef {Object} textposition - 查找文字结果
* @property {number} x - 横坐标-从左边开始
* @property {number} y - 纵坐标-从上边开始
* @property {string} text - 文本结果
*/
/**
* 查找文字,注:此功能受电脑性能影响,低配电脑可能速度较慢。 需要小瓶RPA客户端版本 > V2024.5
* @param {string} inputTxt
* @param {number} fromX=0 可选,查找开始的开始横坐标
* @param {number} fromY=0 可选,查找开始的开始纵坐标
* @param {number} width=-1 可选,搜索宽度
* @param {number} height=-1 可选,搜索高度
* @returns {textposition} 返回json结果:{x,y,text} x,y坐标相对于左上角的原点
*/
var findText = (inputTxt,fromX=0,fromY=0,width=-1,height=-1) =>{
let jsonDatas = aiOcr('screen',fromX,fromY,width,height);
let result = false;
jsonDatas.forEach(element => {
// console.log(element.text);
if (element.text.includes(inputTxt)) {
result = element
return;
}
});
if(result!==false){
showRect(result.x-25,result.y-25,50,50,'green');
}
return result;
}
exports.findText = findText
exports.寻找文字 = findText
/**
* 屏幕查找物体或者窗口轮廓
* 调试:软件根目录会生成 debug/findContours.png
*
* @param {number} minimumArea 轮廓最小面积 默认过滤掉 10x10 以下的元素
* @param {number} fromX 查找起点
* @param {number} fromY
* @param {number} width 查找范围
* @param {number} height
* @returns {[]} 所有查找到的轮廓信息,包含闭合区域的起始坐标,中点坐标,面积,id。 格式:[{ x: 250, y: 10, cx: 265.5, cy: 30.5, area: 2401, id: 42 },...] xy相对于原点
*/
var findContours = (minimumArea=1000,fromX=0,fromY=0,width=-1,height=-1) =>{
if (fromX<0 || fromY<0) {
exit(`错误:轮廓查找起始点不能为负,x:${fromX} y:${fromY} `);
}
if (fromX!=0 || fromY!=0 || width!=-1 || height!=-1) {
showRect(fromX,fromY,width,height);
}
let url = `${CppUrl}?action=findContours&minimumArea=${minimumArea}&fromX=${fromX}&fromY=${fromY}&width=${width}&height=${height}`
// console.log(url)
let res = request('GET', url);
// console.log(res.getBody('utf8'));
jsonRes = JSON.parse(res.getBody('utf8'));
for (const json of jsonRes) {
json.x += fromX
json.y += fromY
}
// console.log(jsonRes);
return jsonRes;
}
exports.findContours = findContours
exports.寻找轮廓 = findContours
/**
* 当前位置 粘贴(输入)文字
* @param {string} text 复制到电脑剪切板的文本
*/
var paste = (txt)=>{
copyText(txt)
sleep(200)
keyTap('ctrl+v')
// txt = encodeURIComponent(txt)
// url = `${CppUrl}?action=paste&txt=${txt}`
// console.log(url)
// request('GET', url);
sleep(defaultDelay);
}
exports.paste = paste
exports.粘贴输入 = paste
/**
* 模拟复制文字,相当于选择并复制文本内容 v2025.0以上生效
* @param {string} txt 复制的文本内容
*/
var copyText=(txt)=>{
txt = encodeURIComponent(txt)
url = `${CppUrl}?action=copyText&txt=${txt}`
// console.log(url)
request('GET', url);
}
exports.copyText = copyText
exports.复制文字 = copyText
/**
* 模拟复制操作,支持文件路径和文件夹路径,复制后在目标文件夹ctrl+V 即可粘贴 V2024.7开始生效
* 复制文件后,在微信发送窗口粘贴,即可发送文件
* @param {string} filepath 绝对路径
*/
var copyFile = (filepath)=>{
filepath = path.join(filepath)
if (!fs.existsSync(filepath)) {
console.log('copyFile警告:文件路径不存在',filepath);
}
filepath = filepath.replace(/\\/g,'/')
filepath = encodeURIComponent(filepath)
url = `${CppUrl}?action=copyFile&path=${filepath}`
// console.log(url)
request('GET', url);
}
exports.copyFile = copyFile
exports.复制文件 = copyFile
/**
* 获取当前电脑的剪切板内容,系统剪切板支持多种格式 版本 V2024.2 开始生效
* ①纯文本格式:普通复制 如'小瓶RPA'
* ②图片格式 base64形式:浏览器复制图片 'data:image/png;base64,' 开头
* ③html格式:浏览器或者钉钉复制富文本综合内容 '<html>'开头
* @returns 结果文本
*/
var getClipboard= ()=>{
let url = `${CppUrl}?action=getClipboard`
// console.log(url)
let res = request('GET', url);
return res.getBody('utf8');
}
exports.getClipboard = getClipboard
exports.获取剪切板内容 = getClipboard
/**
* 通知到手机
* 通过小瓶云发送微信通知 (微信到达率高,并且免费)
* @param {string} title 消息标题
* @param {string} content 消息详细内容
* @param {string} key 获取key详情方法:https://www.pbottle.com/a-12586.html
*/
var wxMessage= (title,content,key)=>{
let url = `https://yun.pbottle.com/manage/yun/?msg=${encodeURIComponent(content)}&name=${encodeURIComponent(title)}&key=${key}`;
let res = request('GET', url);
console.log('发送微信消息:',res.getBody('utf8') );
}
exports.wxMessage = wxMessage
exports.微信消息发送 = wxMessage
/**
* 向指定API网址post一个json,最常用网络接口方式
* @param {string} url API网络地址
* @param {object} msgJson Json对象
* @returns
*/
var postJson= (url,msgJson)=>{
let res = request('POST',url,{json:msgJson});
// console.log('Post反馈:',res.getBody('utf8') );
return res.getBody('utf8')
}
exports.postJson = postJson
/**
* 从文本到语音(TextToSpeech) 语音播报
* 非阻塞
* @param {string} text 朗读内容
*/
var tts= (text)=>{
text = encodeURIComponent(text)
let url = `${CppUrl}?action=tts&txt=${text}`
// console.log(url)
let res = request('GET', url);
sleep(defaultDelay);
}
exports.tts = tts
exports.文字转语音 = tts
/**
* 用电脑默认浏览器打开网址
* @param {string} myurl 网址
*/
var openURL= (myurl)=>{
myurl = encodeURIComponent(myurl)
let url = `${CppUrl}?action=openURL&url=${myurl}`
// console.log(url)
let res = request('GET', url);
sleep(defaultDelay+1000);
}
exports.openURL = openURL
exports.打开网址 = openURL
/**
* 打开文件(用默认软件)或者 用资源管理器打开展示文件夹,
* @param {string} path 文件夹绝对路径 如:'c:/input/RPAlogo128.png' Windows磁盘路径分隔符要双 '\\'
*/
var openDir= (path)=>{
path = encodeURIComponent(path)
let url = `${CppUrl}?action=openDir&path=${path}`
// console.log(url)
let res = request('GET', url);
sleep(defaultDelay);
}
exports.openDir = openDir
exports.openfile = openDir
exports.打开目录 = openDir
exports.打开文件 = openDir
/**
* @typedef {Object} ResolutionInfo
* @property {number} w - 宽度
* @property {number} h - 高度
* @property {number} ratio - 缩放比例
*/
/**
* 获取当前屏幕分辨率和缩放
* @returns {ResolutionInfo} JSON内容格式 {w:1920,h:1080,ratio:1.5} ratio 为桌面缩放比例
*/
var getResolution= ()=>{
let url = `${CppUrl}?action=getResolution`
// console.log(url)
let res = request('GET', url);
return JSON.parse(res.getBody('utf8'));
}
exports.getResolution = getResolution
exports.获取屏幕分辨率 = getResolution
/**
* 文字识别 OCR已经从经典算法升级为AI模型预测,永久免费可脱网使用
*
* @param {string} imagePath 空或者screen 为电脑屏幕; 或者本地图片的绝对路径;
* @param {number} x 可选 查找起始点
* @param {number} y 可选 查找起始点
* @param {number} width 可选 宽度范围
* @param {number} height 可选 高度范围
* @returns {array} AI OCR识别的json结果 包含准确率的评分和中点位置 格式: [{text:'A',score:'0.319415',x:100,y:200},...] xy相对于原点
*/
var aiOcr= (imagePath="screen", x=0, y=0, width=-1, height=-1)=>{
if (!imagePath) {
imagePath="screen"
}
if (x<0 || y<0) {
exit(`错误:OCR 起始点不能为负,x:${x} y:${y} `);
}
if (x!=0 || y!=0 || width!=-1 || height!=-1) {
showRect(x,y,width,height);
}
imagePath = encodeURIComponent(imagePath);
let url = `${CppUrl}?action=aiOcr&path=${imagePath}&x=${x}&y=${y}&width=${width}&height=${height}&onlyEn=0`
// console.log(url)
let res = request('GET', url);
res = res.getBody('utf8');
if (res == '文字识别引擎未启动') {
console.log('⚠',res,'请在软件设置中开启');
exit()
}
let jsons = JSON.parse(res);
for (const json of jsons) {
json.x += x
json.y += y
}
return jsons;
}
exports.aiOcr = aiOcr
exports.文字识别 = aiOcr
/**
* AI 物体识别 已经从经典算法升级为AI模型预测,企业版可脱网使用 V2024.8 以上版本有效
* 调试:软件根目录会生成 debug/Ai_ObjectDetect.png 文件
*
* @param {number} imagePath 空或者screen 为电脑屏幕; 或者本地图片的绝对路径;
* @param {number} x 可选 查找范围
* @param {number} y 可选 查找范围
* @param {number} width 可选 查找宽度
* @param {number} height 可选 查找高度
* @returns {array} AI 物体识别的 json 结果 包含准确率的评分 格式: [{x:100,y:100,width:150,height:150,score:0.86,class:'分类名'},...] xy相对于原点
*/
var aiObject= (minimumScore=0.5, x=0, y=0, width=-1, height=-1)=>{
if (x<0 || y<0) {
exit(`错误:OCR 起始点不能为负,x:${x} y:${y} `);
}
if (x!=0 || y!=0 || width!=-1 || height!=-1) {
showRect(x,y,width,height);
}
minimumScore = encodeURIComponent(minimumScore);
let url = `${CppUrl}?action=aiObject&minimumScore=${minimumScore}&x=${x}&y=${y}&width=${width}&height=${height}&onlyEn=0`
// console.log(url)
let res = request('GET', url);
res = res.getBody('utf8');
if (res == '物体识别引擎未启动') {
console.log('⚠',res,'请在软件设置中开启');
exit()
}
let jsons = JSON.parse(res);
for (const json of jsons) {
json.x += x
json.y += y
showRect(json.x,json.y,json.width,json.height,'green');
}
return jsons;
}
exports.aiObject = aiObject
exports.物体识别 = aiObject
/**
* 压缩文件夹内容成一个zip文件包 v2025.0 以后版本生效
* @param {string} directory 文件夹路径,输入绝对路径
* @param {string} zipFilePath zip文件包
*/
function zipDir(directory,zipFilePath="") {
let basePath = getBasePath()
if (!zipFilePath) {
zipFilePath = path.join(directory,'RPA生成的压缩包.zip')
}
try {
zipFilePath = path.join(zipFilePath)
directory = path.join(directory)
let exe = path.join(`${basePath}/bin/7za`)
const os = process.platform;
if (os === 'linux') {
exe = '7za'
}
childProcess.execSync(`"${exe}" a "${zipFilePath}" "${directory}"`, { stdio: ['ignore', 'ignore', 'pipe'], encoding: 'utf8' })
} catch (error) {
if (!error.stderr.includes('Headers Error')) { //warning
console.error(`压缩失败`, error);
}
}
}
exports.zipDir = zipDir
exports.压缩 = zipDir
/**
* 解压缩zip文件内容到指定文件夹内 v2025.0 以后版本生效
* @param {string} zipFilePath zip文件包
* @param {string} directory 文件夹路径,输入绝对路径 默认解压到zip文件当前目录
*/
function unZip(zipFilePath,directory="") {
let basePath = getBasePath()
if (!directory) {
directory = path.dirname(zipFilePath)
}
try {
filePath = path.join(zipFilePath)
directory = path.join(directory)
let exe = path.join(`${basePath}/bin/7za`)
const os = process.platform;
if (os === 'linux') {
exe = '7za'
}
childProcess.execSync(`"${exe}" x "${filePath}" -o"${directory}" -aoa`, { stdio: ['ignore', 'ignore', 'pipe'], encoding: 'utf8' })
} catch (error) {
console.error(`解压缩失败`, error);
}
}
exports.unZip = unZip
exports.解压缩 = unZip
/**
* 获取buffer存储内容
* 此buffer可以跨脚本存取,RPA重启时才重置,存取多线程下安全
* http外部获取方式:http://ip:49888/action=bufferGet&n=0
* @param {number} n buffer编号,从0-9共10个 默认:0 第一个buffer
* @returns {string} 返回字符串
*/
var bufferGet = (n=0)=>{
let url = `${CppUrl}?action=bufferGet&n=${n}`
let res = request('GET', url);
return res.getBody('utf8');
}
exports.bufferGet = bufferGet
/**
* 设置buffer存储内容
* 此buffer可以跨脚本存取,RPA重启时才重置,存取多线程下安全
* http外部设置方式(POST方法):http://ip:49888/action=bufferSet&n=0 ,content设置到Post的body中
* @param {string} content 存储的内容,通常为一个json,也可以字符串
* @param {number} n buffer编号,从0-9共10个 默认:0 第一个buffer
* @returns {string} ok 表示成功
*/
var bufferSet = (content,n=0)=>{
let url = `${CppUrl}?action=bufferSet&n=${n}`
let res = postJson(url,content);
return res;
}
exports.bufferSet = bufferSet
/**
* 设置接力执行的脚本
* 当前脚本结束后(无论正常结束还是错误退出),立刻启动的自动脚本。
* http外部设置方式(GET方法):http://ip:49888/action=pbottleRPA_delay&path=MyPATH
* @param {string} scriptPath 接力脚本的路径 如:'D:/test.mjs' 如果路径为空,默认清除当前已经设置的接力任务。
* @returns {string} ok 表示成功
*/
var delaySet = (scriptPath='')=>{
scriptPath = encodeURIComponent(scriptPath)
let url = `${CppUrl}?action=pbottleRPA_delay&path=${scriptPath}`
let res = request('GET', url);
return res.getBody('utf8');
}
exports.delaySet = delaySet
/**
* 获取当前的设备唯一号
* @returns {string} 返回字符串
*/
function deviceID(){
let url = `${CppUrl}?action=pbottleRPA_deviceID`
let res = request('GET', url);
return res.getBody('utf8');
}
exports.deviceID = deviceID
/**
* 小瓶RPA 云端模块,AI在线大模型
* 注意:
* ①此模块不是必须模块 ,云端模块不影响本地模块的独立运行
* ②此模块功能需要登录并激活云端模块。碍于成本因素,部分功能需要充值计费才能使用
*/
exports.cloud={}
/**
* @typedef {Object} Answerinfo AI回答结果
* @property {string} content - 回答结果
* @property {number} usage - 消耗token数量
*/
/**
* 小瓶RPA整合的云端大语言答案生成模型
* @param {string} question 提问问题,如:'今天是xx日,你能给我写首诗吗?'
* @param {number} modelLevel 模型等级,不同参数大小不同定价,默认 0 为标准模型。0为低价模型;1为性价比模型;2为旗舰高智能模型;
* @returns {Answerinfo} JSON内容格式 {content:'结果',tokens:消耗token的数量}
*/
function cloud_GPT(question,modelLevel=0) {
let deviceToken = deviceID()
let rs = postJson('https://rpa.pbottle.com/API/',{question,deviceToken,modelLevel})
return JSON.parse(rs)
}
exports.cloud_GPT = cloud_GPT
exports.cloud.GPT = cloud_GPT
/**
* 小瓶RPA整合的云端图像分析大模型
* @param {string} question 提问问题,如:'分析这个图片的内容'
* @param {string} imagePath 上传图片的路径,如:'c:/test.jpg'
* @param {number} modelLevel 模型等级,不同参数大小不同定价,默认 0 为标准模型。
* @returns {Answerinfo} JSON内容格式 {content:'结果',tokens:消耗token的数量}
*/
function cloud_GPTV(question,imagePath,modelLevel=0) {
let deviceToken = deviceID()
imagePath = path.join(imagePath)