gomyck-tools 1.0.0__py3-none-any.whl → 1.4.7__py3-none-any.whl
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.
- ctools/__init__.py +21 -0
- ctools/ai/__init__.py +4 -0
- ctools/ai/llm_chat.py +184 -0
- ctools/ai/llm_client.py +163 -0
- ctools/ai/llm_exception.py +17 -0
- ctools/ai/mcp/__init__.py +4 -0
- ctools/ai/mcp/mcp_client.py +326 -0
- ctools/ai/tools/__init__.py +4 -0
- ctools/ai/tools/json_extract.py +202 -0
- ctools/ai/tools/quick_tools.py +149 -0
- ctools/ai/tools/think_process.py +11 -0
- ctools/ai/tools/tool_use_xml_parse.py +40 -0
- ctools/ai/tools/xml_extract.py +15 -0
- ctools/application.py +50 -47
- ctools/aspect.py +65 -0
- ctools/auto/__init__.py +4 -0
- ctools/{browser_element_tools.py → auto/browser_element.py} +18 -8
- ctools/{plan_area_tools.py → auto/plan_area.py} +5 -7
- ctools/{pty_tools.py → auto/pty_process.py} +6 -3
- ctools/{resource_bundle_tools.py → auto/resource_bundle.py} +4 -4
- ctools/{screenshot_tools.py → auto/screenshot.py} +7 -6
- ctools/{win_canvas.py → auto/win_canvas.py} +10 -4
- ctools/{win_control.py → auto/win_control.py} +14 -5
- ctools/call.py +34 -49
- ctools/cdate.py +84 -0
- ctools/cdebug.py +146 -0
- ctools/cid.py +20 -0
- ctools/cipher/__init__.py +4 -0
- ctools/{aes_tools.py → cipher/aes_util.py} +10 -0
- ctools/{b64.py → cipher/b64.py} +2 -0
- ctools/cipher/czip.py +133 -0
- ctools/cipher/rsa.py +75 -0
- ctools/{sign.py → cipher/sign.py} +2 -1
- ctools/{sm_tools.py → cipher/sm_util.py} +20 -4
- ctools/cjson.py +10 -10
- ctools/cron_lite.py +109 -97
- ctools/database/__init__.py +4 -0
- ctools/{database.py → database/database.py} +93 -26
- ctools/dict_wrapper.py +21 -0
- ctools/ex.py +4 -0
- ctools/geo/__init__.py +4 -0
- ctools/geo/coord_trans.py +127 -0
- ctools/geo/douglas_rarefy.py +139 -0
- ctools/metrics.py +56 -63
- ctools/office/__init__.py +4 -0
- ctools/office/cword.py +30 -0
- ctools/{word_fill.py → office/word_fill.py} +3 -6
- ctools/patch.py +88 -0
- ctools/{work_path.py → path_info.py} +34 -2
- ctools/pkg/__init__.py +4 -0
- ctools/pkg/dynamic_imp.py +38 -0
- ctools/pools/__init__.py +4 -0
- ctools/pools/process_pool.py +41 -0
- ctools/{thread_pool.py → pools/thread_pool.py} +13 -4
- ctools/similar.py +25 -0
- ctools/stream/__init__.py +4 -0
- ctools/stream/ckafka.py +164 -0
- ctools/stream/credis.py +127 -0
- ctools/{mqtt_utils.py → stream/mqtt_utils.py} +20 -12
- ctools/sys_info.py +36 -13
- ctools/sys_log.py +46 -27
- ctools/util/__init__.py +4 -0
- ctools/util/cftp.py +76 -0
- ctools/util/cklock.py +118 -0
- ctools/util/config_util.py +52 -0
- ctools/util/env_config.py +63 -0
- ctools/{html_soup.py → util/html_soup.py} +0 -7
- ctools/{http_utils.py → util/http_util.py} +4 -2
- ctools/{images_tools.py → util/image_process.py} +10 -1
- ctools/util/jb_cut.py +54 -0
- ctools/{id_worker_tools.py → util/snow_id.py} +8 -23
- ctools/web/__init__.py +4 -0
- ctools/web/aio_web_server.py +186 -0
- ctools/web/api_result.py +56 -0
- ctools/web/bottle_web_base.py +239 -0
- ctools/web/bottle_webserver.py +191 -0
- ctools/web/bottle_websocket.py +79 -0
- ctools/web/ctoken.py +103 -0
- ctools/{download_tools.py → web/download_util.py} +14 -12
- ctools/web/params_util.py +46 -0
- ctools/{upload_tools.py → web/upload_util.py} +3 -2
- gomyck_tools-1.4.7.dist-info/METADATA +70 -0
- gomyck_tools-1.4.7.dist-info/RECORD +88 -0
- {gomyck_tools-1.0.0.dist-info → gomyck_tools-1.4.7.dist-info}/WHEEL +1 -1
- gomyck_tools-1.4.7.dist-info/licenses/LICENSE +13 -0
- ctools/bashPath.py +0 -13
- ctools/bottle_server.py +0 -49
- ctools/console.py +0 -55
- ctools/date_utils.py +0 -44
- ctools/enums.py +0 -4
- ctools/excelOpt.py +0 -36
- ctools/imgDialog.py +0 -44
- ctools/license.py +0 -37
- ctools/log.py +0 -28
- ctools/mvc.py +0 -56
- ctools/obj.py +0 -20
- ctools/pacth.py +0 -73
- ctools/ssh.py +0 -9
- ctools/strDiff.py +0 -20
- ctools/string_tools.py +0 -101
- ctools/token_tools.py +0 -13
- ctools/wordFill.py +0 -24
- gomyck_tools-1.0.0.dist-info/METADATA +0 -20
- gomyck_tools-1.0.0.dist-info/RECORD +0 -54
- /ctools/{word_fill_entity.py → office/word_fill_entity.py} +0 -0
- /ctools/{compile_tools.py → util/compile_util.py} +0 -0
- {gomyck_tools-1.0.0.dist-info → gomyck_tools-1.4.7.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import html
|
|
2
|
+
import json
|
|
3
|
+
import xml.etree.ElementTree as ET
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def parse_tool_use(xml_string):
|
|
7
|
+
tool_name = ''
|
|
8
|
+
try:
|
|
9
|
+
root = ET.fromstring(xml_string.strip())
|
|
10
|
+
if root.tag != "tool_use": raise ValueError("根标签必须是 <tool_use>")
|
|
11
|
+
tool_name = root.find("name").text.strip()
|
|
12
|
+
args = root.find("arguments").text
|
|
13
|
+
if args:
|
|
14
|
+
arguments_text = args.strip()
|
|
15
|
+
arguments_text = html.unescape(arguments_text)
|
|
16
|
+
arguments = json.loads(arguments_text)
|
|
17
|
+
return {
|
|
18
|
+
"tool": tool_name,
|
|
19
|
+
"arguments": arguments
|
|
20
|
+
}
|
|
21
|
+
else:
|
|
22
|
+
return {
|
|
23
|
+
"tool": tool_name,
|
|
24
|
+
"arguments": {}
|
|
25
|
+
}
|
|
26
|
+
except Exception as e:
|
|
27
|
+
raise ValueError(f"tool_use_{tool_name} 解析失败: {e}")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# 测试
|
|
31
|
+
if __name__ == '__main__':
|
|
32
|
+
xml_input = """
|
|
33
|
+
<tool_use>
|
|
34
|
+
<name>set</name>
|
|
35
|
+
<arguments>{"key": "weather_harbin", "value": "{\\"city\\":\\"哈尔滨市\\",\\"forecasts\\":[{\\"date\\":\\"2025-05-27\\",\\"week\\":\\"2\\",\\"dayweather\\":\\"晴\\",\\"nightweather\\":\\"晴\\",\\"daytemp\\":29,\\"nighttemp\\":15,\\"daywind\\":\\"南\\",\\"nightwind\\":\\"南\\",\\"daypower\\":1,\\"nightpower\\":3},{\\"date\\":\\"2025-05-28\\",\\"week\\":"3", \\"dayweather\\":"晴", \\"nightweather\\":"晴", \\"daytemp\\":"30", \\"nighttemp\\":"17"}]}"}</arguments>
|
|
36
|
+
</tool_use>
|
|
37
|
+
"""
|
|
38
|
+
result = parse_tool_use(xml_input)
|
|
39
|
+
print("\n【结果】")
|
|
40
|
+
print(json.dumps(result, ensure_ascii=False, indent=2))
|
ctools/application.py
CHANGED
|
@@ -8,7 +8,9 @@ from configparser import ConfigParser
|
|
|
8
8
|
|
|
9
9
|
from PIL import Image
|
|
10
10
|
|
|
11
|
-
from ctools import
|
|
11
|
+
from ctools import path_info, call
|
|
12
|
+
from ctools.cipher import sign
|
|
13
|
+
from ctools.pools import thread_pool
|
|
12
14
|
from ctools.sys_info import get_os_architecture, get_os_architecture4x
|
|
13
15
|
|
|
14
16
|
"""
|
|
@@ -23,10 +25,9 @@ class Server:
|
|
|
23
25
|
metricsPort = 8011 # 获取指标信息端口
|
|
24
26
|
wsPort = 8012 # websocket服务端口
|
|
25
27
|
startTime = time.time() # 系统启动时间
|
|
26
|
-
baseWorkPath =
|
|
28
|
+
baseWorkPath = path_info.get_user_path_info('rpa') # 基础的工作目录
|
|
27
29
|
sysLogPath = os.path.join(baseWorkPath, ".logs") # 系统日志存储目录
|
|
28
|
-
pythonHome = os.path.join(
|
|
29
|
-
hylinkFunctionPath = os.path.join(pythonHome, "Lib", "site-packages", "hylink")
|
|
30
|
+
pythonHome = os.path.join(path_info.get_Users_path(), 'Public/python-3.8.9') # python根目录
|
|
30
31
|
indicatorsPath = os.path.join(baseWorkPath, "indicators") # 指标信息存储目录
|
|
31
32
|
screenshotPath = os.path.join(baseWorkPath, "screenshot") # 截图存储目录
|
|
32
33
|
controlServerAddr = None
|
|
@@ -38,9 +39,9 @@ class Authorization:
|
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
class Database:
|
|
41
|
-
url_biz = os.path.join(
|
|
42
|
-
url_func = os.path.join(
|
|
43
|
-
url_auth = os.path.join(
|
|
42
|
+
url_biz = os.path.join(path_info.get_user_temp_path(), "AppData/Local/SystemWin32Core", 'systemRDB') # 数据库文件地址
|
|
43
|
+
url_func = os.path.join(path_info.get_user_temp_path(), "AppData/Local/SystemWin32Core", 'explorerSearch') # 函数库地址
|
|
44
|
+
url_auth = os.path.join(path_info.get_user_temp_path(), "AppData/Local/SystemWin32Core", 'tmp') # 授权库地址
|
|
44
45
|
pool_size = 5
|
|
45
46
|
max_overflow = 25
|
|
46
47
|
|
|
@@ -53,14 +54,14 @@ class Upload:
|
|
|
53
54
|
|
|
54
55
|
|
|
55
56
|
class Schedule:
|
|
56
|
-
rpa_script_path = os.path.join(
|
|
57
|
+
rpa_script_path = os.path.join(path_info.get_user_temp_path(), ".cache/.tmp") # 执行流程存储目录
|
|
57
58
|
template_output_path = os.path.join(Server.baseWorkPath, 'document') # 使用模板生成的文档存储目录
|
|
58
59
|
play_wright_slow_mo = 0 # play wright每一步执行延时时间, 单位毫秒
|
|
59
60
|
|
|
60
61
|
|
|
61
62
|
@call.once
|
|
62
63
|
def sync_config():
|
|
63
|
-
path = os.path.join(
|
|
64
|
+
path = os.path.join(path_info.get_app_path(), "application.ini")
|
|
64
65
|
conf = ConfigParser()
|
|
65
66
|
if os.path.exists(path):
|
|
66
67
|
conf.read(path)
|
|
@@ -70,7 +71,7 @@ def sync_config():
|
|
|
70
71
|
server_conf = conf['Server']
|
|
71
72
|
Server.version = server_conf['version']
|
|
72
73
|
Server.port = int(server_conf['port'])
|
|
73
|
-
Server.baseWorkPath =
|
|
74
|
+
Server.baseWorkPath = path_info.get_user_work_path(server_conf['baseWorkPath'])
|
|
74
75
|
Server.sysLogPath = os.path.join(Server.baseWorkPath, ".logs")
|
|
75
76
|
######### Server 必须放在第一个初始化的位置 ########
|
|
76
77
|
if "Database" in sections:
|
|
@@ -107,29 +108,30 @@ def sync_config():
|
|
|
107
108
|
|
|
108
109
|
|
|
109
110
|
def check_database():
|
|
110
|
-
db_file = os.path.join(
|
|
111
|
+
db_file = os.path.join(path_info.get_user_temp_path(), "AppData/Local/SystemWin32Core", 'systemRDB')
|
|
111
112
|
if os.path.exists(db_file):
|
|
112
113
|
db_size = os.path.getsize(db_file)
|
|
113
114
|
if db_size < 2000 * 1024: os.remove(db_file)
|
|
114
|
-
db_file = os.path.join(
|
|
115
|
+
db_file = os.path.join(path_info.get_user_temp_path(), "AppData/Local/SystemWin32Core", 'tmp')
|
|
115
116
|
if os.path.exists(db_file):
|
|
116
117
|
db_size = os.path.getsize(db_file)
|
|
117
118
|
if db_size < 2000 * 1024: os.remove(db_file)
|
|
118
119
|
|
|
120
|
+
|
|
119
121
|
def validate_sign():
|
|
120
|
-
sign_app_val = sign.generate_signature(
|
|
121
|
-
with open(
|
|
122
|
+
sign_app_val = sign.generate_signature(path_info.get_install_path('rpa-server.exe'))
|
|
123
|
+
with open(path_info.get_install_path('rpa-server.sign')) as sign_file:
|
|
122
124
|
sign_file_val = sign_file.readline()
|
|
123
|
-
if '
|
|
125
|
+
if 'rpa-dev-sign' == sign_file_val.strip(): return
|
|
124
126
|
if sign_app_val != sign_file_val: raise Exception('程序签名验证失败!!!')
|
|
125
127
|
|
|
126
128
|
|
|
127
129
|
def path_config():
|
|
128
130
|
print('start config path')
|
|
129
131
|
driverPath = Upload.driver_path
|
|
130
|
-
pythonPath = os.path.join(
|
|
131
|
-
hplPath = os.path.join(
|
|
132
|
-
taguiPath = os.path.join(
|
|
132
|
+
pythonPath = os.path.join(path_info.get_Users_path(), 'Public/python-3.8.9')
|
|
133
|
+
hplPath = os.path.join(path_info.get_user_temp_path(), 'AppData/Local/ms-playwright')
|
|
134
|
+
taguiPath = os.path.join(path_info.get_user_temp_path(), 'AppData/Roaming/tagui')
|
|
133
135
|
os.environ['PATH'] = os.pathsep.join([pythonPath, os.path.join(pythonPath, 'Scripts'), driverPath, os.path.join(hplPath, 'chromium-920619\chrome-win'), taguiPath, os.environ['PATH']])
|
|
134
136
|
print('end config path')
|
|
135
137
|
|
|
@@ -137,9 +139,9 @@ def path_config():
|
|
|
137
139
|
def sync_version(callFunc):
|
|
138
140
|
destFilePath = os.path.join(Server.baseWorkPath, "version")
|
|
139
141
|
driverPath = Upload.driver_path
|
|
140
|
-
pythonPath = os.path.join(
|
|
141
|
-
msPlayPath = os.path.join(
|
|
142
|
-
taguiPath = os.path.join(
|
|
142
|
+
pythonPath = os.path.join(path_info.get_Users_path(), 'Public/python-3.8.9')
|
|
143
|
+
msPlayPath = os.path.join(path_info.get_user_temp_path(), 'AppData/Local/ms-playwright')
|
|
144
|
+
taguiPath = os.path.join(path_info.get_user_temp_path(), 'AppData/Roaming/tagui')
|
|
143
145
|
if not os.path.exists(destFilePath):
|
|
144
146
|
try:
|
|
145
147
|
shutil.rmtree(pythonPath)
|
|
@@ -157,7 +159,7 @@ def sync_version(callFunc):
|
|
|
157
159
|
shutil.rmtree(taguiPath)
|
|
158
160
|
except Exception:
|
|
159
161
|
pass
|
|
160
|
-
|
|
162
|
+
import Patch
|
|
161
163
|
patch = Patch(oldVersion='V1.0.0', newVersion=Server.version, pythonPath=pythonPath, playwrightPath=msPlayPath, driverPath=driverPath)
|
|
162
164
|
patch.apply_patch()
|
|
163
165
|
if callFunc: callFunc()
|
|
@@ -172,7 +174,7 @@ def sync_version(callFunc):
|
|
|
172
174
|
oldVersion.close()
|
|
173
175
|
if oldV == Server.version and '-snapshot' not in oldV: return
|
|
174
176
|
print('开始升级本地程序..')
|
|
175
|
-
|
|
177
|
+
import Patch
|
|
176
178
|
patch = Patch(oldVersion=oldV, newVersion=Server.version, pythonPath=pythonPath, playwrightPath=msPlayPath, driverPath=driverPath)
|
|
177
179
|
patch.apply_patch()
|
|
178
180
|
if callFunc: callFunc()
|
|
@@ -184,8 +186,8 @@ def sync_version(callFunc):
|
|
|
184
186
|
|
|
185
187
|
def sync_database():
|
|
186
188
|
for db in [['simpleYWI', 'systemRDB', False], ['simpleHSI', 'explorerSearch', True], ['simpleSQI', 'tmp', False]]:
|
|
187
|
-
dbPath = os.path.join(
|
|
188
|
-
destDBPath = os.path.join(
|
|
189
|
+
dbPath = os.path.join(path_info.get_app_path(), "extension", db[0])
|
|
190
|
+
destDBPath = os.path.join(path_info.get_user_temp_path(), "AppData/Local/SystemWin32Core")
|
|
189
191
|
os.makedirs(destDBPath, exist_ok=True)
|
|
190
192
|
destFilePath = os.path.join(destDBPath, db[1])
|
|
191
193
|
try:
|
|
@@ -200,9 +202,9 @@ def sync_database():
|
|
|
200
202
|
|
|
201
203
|
def sync_python_env():
|
|
202
204
|
print('SDK 开始安装...')
|
|
203
|
-
sourcePath = os.path.join(
|
|
204
|
-
destPLPath = os.path.join(
|
|
205
|
-
unzipPLPath = os.path.join(
|
|
205
|
+
sourcePath = os.path.join(path_info.get_install_path(), "sources", 'python-3.8.9-{}.zip'.format(get_os_architecture()))
|
|
206
|
+
destPLPath = os.path.join(path_info.get_Users_path(), 'Public/python-3.8.9')
|
|
207
|
+
unzipPLPath = os.path.join(path_info.get_Users_path(), 'Public')
|
|
206
208
|
if not os.path.exists(destPLPath):
|
|
207
209
|
with zipfile.ZipFile(sourcePath, 'r') as zip_ref:
|
|
208
210
|
zip_ref.extractall(unzipPLPath)
|
|
@@ -221,7 +223,7 @@ def sync_python_module():
|
|
|
221
223
|
m_path = os.path.join(Upload.module_path, file_name)
|
|
222
224
|
module_list.append(m_path)
|
|
223
225
|
|
|
224
|
-
upgrade_module_path = os.path.join(
|
|
226
|
+
upgrade_module_path = os.path.join(path_info.get_install_path(), "sources/UpgradeModule")
|
|
225
227
|
init_flag = os.path.join(upgrade_module_path, "init")
|
|
226
228
|
upgrade_module_path = os.path.join(upgrade_module_path, get_os_architecture4x())
|
|
227
229
|
if not os.path.exists(init_flag) and os.path.exists(upgrade_module_path):
|
|
@@ -268,12 +270,12 @@ def sync_python_module():
|
|
|
268
270
|
|
|
269
271
|
|
|
270
272
|
def sync_python_interpreter():
|
|
271
|
-
destPLPath = os.path.join(
|
|
272
|
-
enhancePath = os.path.join(
|
|
273
|
-
originPath = os.path.join(
|
|
274
|
-
initFlag = os.path.join(
|
|
273
|
+
destPLPath = os.path.join(path_info.get_Users_path(), 'Public/python-3.8.9')
|
|
274
|
+
enhancePath = os.path.join(path_info.get_Users_path(), "Public/enhance", 'enhance-{}.zip'.format(get_os_architecture()))
|
|
275
|
+
originPath = os.path.join(path_info.get_Users_path(), "Public/enhance", 'origin-{}.zip'.format(get_os_architecture()))
|
|
276
|
+
initFlag = os.path.join(path_info.get_Users_path(), "Public/enhance", 'init')
|
|
275
277
|
flagValue = 'can not find dest dir'
|
|
276
|
-
os.makedirs(os.path.join(
|
|
278
|
+
os.makedirs(os.path.join(path_info.get_Users_path(), "Public/enhance"), exist_ok=True)
|
|
277
279
|
if not os.path.exists(initFlag):
|
|
278
280
|
try:
|
|
279
281
|
if os.path.exists(enhancePath):
|
|
@@ -301,7 +303,7 @@ def sync_python_interpreter():
|
|
|
301
303
|
|
|
302
304
|
def sync_driver():
|
|
303
305
|
print('DRIVER 开始安装...')
|
|
304
|
-
sourcePath = os.path.join(
|
|
306
|
+
sourcePath = os.path.join(path_info.get_install_path(), "sources", 'uploadDriver.zip')
|
|
305
307
|
destPLPath = Upload.driver_path
|
|
306
308
|
unzipPLPath = Upload.driver_path
|
|
307
309
|
if not os.path.exists(os.path.join(destPLPath)):
|
|
@@ -316,9 +318,9 @@ def sync_driver():
|
|
|
316
318
|
|
|
317
319
|
def sync_tagui():
|
|
318
320
|
print('HTG ENGINE 开始安装...')
|
|
319
|
-
plPath = os.path.join(
|
|
320
|
-
destPLPath = os.path.join(
|
|
321
|
-
unzipPLPath = os.path.join(
|
|
321
|
+
plPath = os.path.join(path_info.get_install_path(), "sources", 'htg-source.zip')
|
|
322
|
+
destPLPath = os.path.join(path_info.get_user_temp_path(), 'AppData/Roaming/tagui')
|
|
323
|
+
unzipPLPath = os.path.join(path_info.get_user_temp_path(), 'AppData/Roaming/')
|
|
322
324
|
if not os.path.exists(os.path.join(destPLPath)):
|
|
323
325
|
with zipfile.ZipFile(plPath, 'r') as zip_ref:
|
|
324
326
|
zip_ref.extractall(unzipPLPath)
|
|
@@ -329,9 +331,9 @@ def sync_tagui():
|
|
|
329
331
|
|
|
330
332
|
def sync_playwright():
|
|
331
333
|
print('HPL ENGINE 开始安装...')
|
|
332
|
-
plPath = os.path.join(
|
|
333
|
-
destPLPath = os.path.join(
|
|
334
|
-
unzipPLPath = os.path.join(
|
|
334
|
+
plPath = os.path.join(path_info.get_install_path(), "sources", 'ms-playwright.zip')
|
|
335
|
+
destPLPath = os.path.join(path_info.get_user_temp_path(), 'AppData/Local/ms-playwright')
|
|
336
|
+
unzipPLPath = os.path.join(path_info.get_user_temp_path(), 'AppData/Local/')
|
|
335
337
|
if not os.path.exists(os.path.join(destPLPath)):
|
|
336
338
|
with zipfile.ZipFile(plPath, 'r') as zip_ref:
|
|
337
339
|
zip_ref.extractall(unzipPLPath)
|
|
@@ -339,9 +341,10 @@ def sync_playwright():
|
|
|
339
341
|
else:
|
|
340
342
|
print('HPL ENGINE 依赖安装成功(1)')
|
|
341
343
|
|
|
344
|
+
|
|
342
345
|
def sync_paddleocr_model():
|
|
343
|
-
model_path = os.path.join(
|
|
344
|
-
paddleocr_path =
|
|
346
|
+
model_path = os.path.join(path_info.get_install_path(), "sources", 'paddleocr-model.zip')
|
|
347
|
+
paddleocr_path = path_info.get_user_temp_path(".paddleocr")
|
|
345
348
|
if not os.path.exists(paddleocr_path) and os.path.exists(model_path) and get_os_architecture() == "64":
|
|
346
349
|
print('安装paddleocr模型文件开始')
|
|
347
350
|
with zipfile.ZipFile(model_path, 'r') as zip_ref:
|
|
@@ -349,14 +352,14 @@ def sync_paddleocr_model():
|
|
|
349
352
|
print('安装paddleocr模型文件结束')
|
|
350
353
|
|
|
351
354
|
|
|
352
|
-
def clean_temp_dir(target_file='
|
|
353
|
-
root_folder =
|
|
355
|
+
def clean_temp_dir(target_file='rpa_ident'):
|
|
356
|
+
root_folder = path_info.get_user_temp_path()
|
|
354
357
|
print("Start clear cache...")
|
|
355
358
|
for folder_name in os.listdir(root_folder):
|
|
356
359
|
folder_path = os.path.join(root_folder, folder_name)
|
|
357
360
|
if os.path.isdir(folder_path):
|
|
358
361
|
file_path = os.path.join(folder_path, target_file)
|
|
359
|
-
if os.path.exists(file_path) and os.path.normpath(folder_path) != os.path.normpath(
|
|
362
|
+
if os.path.exists(file_path) and os.path.normpath(folder_path) != os.path.normpath(path_info.get_app_path()):
|
|
360
363
|
try:
|
|
361
364
|
shutil.rmtree(folder_path)
|
|
362
365
|
except Exception:
|
|
@@ -377,7 +380,7 @@ def system_tray(app_server):
|
|
|
377
380
|
thread_pool.submit(app_server.stop)
|
|
378
381
|
app_icon.stop()
|
|
379
382
|
|
|
380
|
-
image = Image.open(os.path.join(
|
|
383
|
+
image = Image.open(os.path.join(path_info.get_app_path(), "images/ico.png"))
|
|
381
384
|
menu = (
|
|
382
385
|
pystray.MenuItem(text='退出', action=on_quit_clicked),
|
|
383
386
|
)
|
ctools/aspect.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: UTF-8 -*-
|
|
3
|
+
__author__ = 'haoyang'
|
|
4
|
+
__date__ = '2025/7/23 08:33'
|
|
5
|
+
|
|
6
|
+
import functools
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from ctools.pools import thread_pool
|
|
10
|
+
|
|
11
|
+
def _ensure_list(funcs):
|
|
12
|
+
if callable(funcs):
|
|
13
|
+
return [funcs]
|
|
14
|
+
if isinstance(funcs, (list, tuple, set)):
|
|
15
|
+
return list(funcs)
|
|
16
|
+
raise TypeError("必须是可调用对象或可迭代对象")
|
|
17
|
+
|
|
18
|
+
def before(before_funcs):
|
|
19
|
+
"""
|
|
20
|
+
用于将无参函数注入目标函数的调用前
|
|
21
|
+
支持多个函数
|
|
22
|
+
"""
|
|
23
|
+
before_funcs = _ensure_list(before_funcs)
|
|
24
|
+
def decorator(func, sync=True):
|
|
25
|
+
@functools.wraps(func)
|
|
26
|
+
def wrapper(*args, **kwargs):
|
|
27
|
+
for bf in before_funcs:
|
|
28
|
+
if callable(bf):
|
|
29
|
+
if sync:
|
|
30
|
+
bf()
|
|
31
|
+
else:
|
|
32
|
+
thread_pool.submit(bf)
|
|
33
|
+
return func(*args, **kwargs)
|
|
34
|
+
_replace_func_binding(func, wrapper)
|
|
35
|
+
return wrapper
|
|
36
|
+
return decorator
|
|
37
|
+
|
|
38
|
+
def after(after_funcs, sync=True):
|
|
39
|
+
"""
|
|
40
|
+
用于将无参函数注入目标函数的调用后
|
|
41
|
+
支持多个函数
|
|
42
|
+
"""
|
|
43
|
+
after_funcs = _ensure_list(after_funcs)
|
|
44
|
+
def decorator(func):
|
|
45
|
+
@functools.wraps(func)
|
|
46
|
+
def wrapper(*args, **kwargs):
|
|
47
|
+
result = func(*args, **kwargs)
|
|
48
|
+
for af in after_funcs:
|
|
49
|
+
if callable(af):
|
|
50
|
+
if sync:
|
|
51
|
+
af()
|
|
52
|
+
else:
|
|
53
|
+
thread_pool.submit(af)
|
|
54
|
+
return result
|
|
55
|
+
_replace_func_binding(func, wrapper)
|
|
56
|
+
return wrapper
|
|
57
|
+
return decorator
|
|
58
|
+
|
|
59
|
+
def _replace_func_binding(old_func, new_func):
|
|
60
|
+
"""
|
|
61
|
+
替换函数在其模块中的绑定,确保所有使用点都生效
|
|
62
|
+
"""
|
|
63
|
+
mod = sys.modules.get(old_func.__module__)
|
|
64
|
+
if mod and hasattr(mod, old_func.__name__):
|
|
65
|
+
setattr(mod, old_func.__name__, new_func)
|
ctools/auto/__init__.py
ADDED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import time
|
|
3
|
+
|
|
4
|
+
from business.common.constant import Scheduler
|
|
5
|
+
from lxml import etree
|
|
3
6
|
from lxml import html
|
|
4
7
|
from pynput import keyboard
|
|
5
|
-
from selenium.common import NoSuchElementException, WebDriverException, NoSuchWindowException
|
|
6
8
|
from selenium import webdriver
|
|
7
|
-
from selenium.
|
|
9
|
+
from selenium.common import NoSuchElementException, WebDriverException, NoSuchWindowException
|
|
8
10
|
from selenium.webdriver.chrome.options import Options
|
|
9
11
|
from selenium.webdriver.chrome.service import Service
|
|
12
|
+
from selenium.webdriver.common.by import By
|
|
10
13
|
from urllib3.exceptions import MaxRetryError
|
|
11
|
-
from lxml import etree
|
|
12
|
-
from business.common.constant import Scheduler
|
|
13
|
-
from ctools import application, string_tools
|
|
14
14
|
|
|
15
|
+
from ctools import application
|
|
16
|
+
from ctools.util import cid
|
|
15
17
|
|
|
16
18
|
keyboard_listener = None
|
|
17
19
|
ctrl_pressed = None
|
|
@@ -21,6 +23,7 @@ g_result = []
|
|
|
21
23
|
g_quite_flag = False
|
|
22
24
|
picture_path = ""
|
|
23
25
|
|
|
26
|
+
|
|
24
27
|
def get_hovered_element_html(url, explore, callback):
|
|
25
28
|
global g_driver, g_callback, g_result
|
|
26
29
|
g_callback = callback
|
|
@@ -71,10 +74,10 @@ def get_hovered_element_html(url, explore, callback):
|
|
|
71
74
|
match_dom = page_dom_tree.xpath('//*[@ck-flag="ck"]')
|
|
72
75
|
for ck_element in match_dom:
|
|
73
76
|
ck_xpath = page_dom_tree.getpath(ck_element)
|
|
74
|
-
#print('XPATH IS {}'.format(ck_xpath))
|
|
77
|
+
# print('XPATH IS {}'.format(ck_xpath))
|
|
75
78
|
try:
|
|
76
79
|
ele = driver.find_element(By.XPATH, ck_xpath)
|
|
77
|
-
#print('XPATH_HTML: {}'.format(ele.get_attribute('outerHTML')))
|
|
80
|
+
# print('XPATH_HTML: {}'.format(ele.get_attribute('outerHTML')))
|
|
78
81
|
except Exception:
|
|
79
82
|
pass
|
|
80
83
|
g_result.append(ck_xpath)
|
|
@@ -97,10 +100,12 @@ def get_hovered_element_html(url, explore, callback):
|
|
|
97
100
|
except Exception as e:
|
|
98
101
|
pass
|
|
99
102
|
|
|
103
|
+
|
|
100
104
|
def break_func():
|
|
101
105
|
keyboard_listener.stop()
|
|
102
106
|
g_callback(None)
|
|
103
107
|
|
|
108
|
+
|
|
104
109
|
def on_press(key):
|
|
105
110
|
global keyboard_listener, ctrl_pressed, g_driver, g_quite_flag, picture_path
|
|
106
111
|
if key == keyboard.Key.ctrl_l and not ctrl_pressed:
|
|
@@ -115,7 +120,7 @@ def on_press(key):
|
|
|
115
120
|
if g_result:
|
|
116
121
|
try:
|
|
117
122
|
select_element = g_driver.find_element(By.XPATH, g_result[0])
|
|
118
|
-
picture_path = "%s.png" % os.path.join(application.Server.screenshotPath, "element-"+
|
|
123
|
+
picture_path = "%s.png" % os.path.join(application.Server.screenshotPath, "element-" + cid.get_uuid())
|
|
119
124
|
select_element.screenshot(picture_path)
|
|
120
125
|
except Exception:
|
|
121
126
|
pass
|
|
@@ -124,11 +129,13 @@ def on_press(key):
|
|
|
124
129
|
g_quite_flag = True
|
|
125
130
|
g_callback(g_result)
|
|
126
131
|
|
|
132
|
+
|
|
127
133
|
def on_release(key):
|
|
128
134
|
global ctrl_pressed
|
|
129
135
|
if key == keyboard.Key.ctrl_l:
|
|
130
136
|
ctrl_pressed = False
|
|
131
137
|
|
|
138
|
+
|
|
132
139
|
def start_keyboard_listener():
|
|
133
140
|
global keyboard_listener
|
|
134
141
|
keyboard_listener = keyboard.Listener(on_press=on_press, on_release=on_release)
|
|
@@ -181,6 +188,7 @@ if (shade) {
|
|
|
181
188
|
}
|
|
182
189
|
"""
|
|
183
190
|
|
|
191
|
+
|
|
184
192
|
class IE:
|
|
185
193
|
|
|
186
194
|
@staticmethod
|
|
@@ -285,6 +293,7 @@ class Chrome:
|
|
|
285
293
|
def callback(xpath):
|
|
286
294
|
print("Hovered Element XPATH IS :", xpath)
|
|
287
295
|
|
|
296
|
+
|
|
288
297
|
def get_element(url: str = None, explore: str = "chrome"):
|
|
289
298
|
global keyboard_listener, ctrl_pressed, g_driver, g_callback, g_result, g_quite_flag, picture_path
|
|
290
299
|
keyboard_listener = None
|
|
@@ -307,6 +316,7 @@ def get_element(url: str = None, explore: str = "chrome"):
|
|
|
307
316
|
|
|
308
317
|
return g_result, picture_path
|
|
309
318
|
|
|
319
|
+
|
|
310
320
|
if __name__ == "__main__":
|
|
311
321
|
# from explore_record_core import get_hovered_element_html, Chrome
|
|
312
322
|
g_result, picture_path = get_element("weibo.com")
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import time
|
|
3
1
|
import tkinter as tk
|
|
4
|
-
import pyautogui
|
|
5
|
-
|
|
6
|
-
from ctools import application, string_tools
|
|
7
2
|
|
|
8
3
|
"""
|
|
9
4
|
规划区域工具类, 按回车获取区域坐标
|
|
@@ -68,8 +63,8 @@ class PlanAreaTools:
|
|
|
68
63
|
|
|
69
64
|
def mouse_left_move(self, event):
|
|
70
65
|
self.x, self.y = event.x, event.y
|
|
71
|
-
self.xcenter = self.xstart + int((self.x-self.xstart)/2)-2
|
|
72
|
-
self.ycenter = self.ystart + int((self.y-self.ystart)/2)-2
|
|
66
|
+
self.xcenter = self.xstart + int((self.x - self.xstart) / 2) - 2
|
|
67
|
+
self.ycenter = self.ystart + int((self.y - self.ystart) / 2) - 2
|
|
73
68
|
|
|
74
69
|
self.pos_label.config(text=self.pos_div_text % (self.x, self.y))
|
|
75
70
|
self.pos_div.geometry(f"+{self.x + 10}+{self.y + 10}")
|
|
@@ -100,3 +95,6 @@ def get_area():
|
|
|
100
95
|
pat = PlanAreaTools()
|
|
101
96
|
pat.start()
|
|
102
97
|
return tuple(pat.area)
|
|
98
|
+
|
|
99
|
+
# if __name__ == '__main__':
|
|
100
|
+
# get_area()
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import time
|
|
2
|
-
import queue
|
|
3
1
|
import _thread
|
|
2
|
+
import queue
|
|
3
|
+
import time
|
|
4
|
+
|
|
4
5
|
from winpty import PtyProcess
|
|
5
6
|
|
|
6
7
|
|
|
8
|
+
# 伪终端交互
|
|
9
|
+
|
|
10
|
+
|
|
7
11
|
class Code:
|
|
8
12
|
SUCCESS = 200
|
|
9
13
|
FAIL = 201
|
|
@@ -66,4 +70,3 @@ class PtyTools:
|
|
|
66
70
|
|
|
67
71
|
def close(self):
|
|
68
72
|
self._process.close(force=True)
|
|
69
|
-
|
|
@@ -11,7 +11,7 @@ from Crypto.Hash import MD5
|
|
|
11
11
|
from Crypto.PublicKey import RSA
|
|
12
12
|
from Crypto.Signature import pkcs1_15
|
|
13
13
|
|
|
14
|
-
from ctools import sys_log,
|
|
14
|
+
from ctools import sys_log, application, path_info
|
|
15
15
|
|
|
16
16
|
log = sys_log.flog
|
|
17
17
|
|
|
@@ -30,7 +30,7 @@ def data_layout(manifest: dict):
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def get_md5_sum(data):
|
|
33
|
-
return hashlib.md5(data + "
|
|
33
|
+
return hashlib.md5(data + "gomyck-daning".encode()).hexdigest()
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
def signature(manifest: dict):
|
|
@@ -39,7 +39,7 @@ def signature(manifest: dict):
|
|
|
39
39
|
:param manifest: 元数据字典
|
|
40
40
|
:return:
|
|
41
41
|
"""
|
|
42
|
-
with open(
|
|
42
|
+
with open(path_info.get_app_path() + '/keys/resource_private_key.pem', 'r') as pri:
|
|
43
43
|
private_key = RSA.import_key(pri.read())
|
|
44
44
|
digest = MD5.new(data_layout(manifest).encode('utf-8'))
|
|
45
45
|
return b64encode(pkcs1_15.new(private_key).sign(digest)).decode()
|
|
@@ -52,7 +52,7 @@ def sign_verify(manifest: dict, sign_val: str):
|
|
|
52
52
|
:param sign_val: 对比的签名值
|
|
53
53
|
:return:
|
|
54
54
|
"""
|
|
55
|
-
with open(
|
|
55
|
+
with open(path_info.get_app_path() + '/keys/resource_public_key.pem', 'r') as pub:
|
|
56
56
|
public_key = RSA.import_key(pub.read())
|
|
57
57
|
digest = MD5.new(data_layout(manifest).encode('utf-8'))
|
|
58
58
|
try:
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import time
|
|
3
3
|
import tkinter as tk
|
|
4
|
+
|
|
4
5
|
import pyautogui
|
|
5
6
|
|
|
6
|
-
from ctools import application
|
|
7
|
+
from ctools import application
|
|
8
|
+
from ctools import cid
|
|
7
9
|
|
|
8
10
|
"""
|
|
9
11
|
截屏工具类, 按回车截图
|
|
@@ -63,7 +65,7 @@ class ScreenshotTools:
|
|
|
63
65
|
def change_center_point(self, event):
|
|
64
66
|
offset_x = event.x + self.xstart - self.xcenter - 2
|
|
65
67
|
offset_y = event.y + self.ystart - self.ycenter - 2
|
|
66
|
-
self.center_div.geometry(f"+{self.xstart+event.x-2}+{self.ystart+event.y-2}")
|
|
68
|
+
self.center_div.geometry(f"+{self.xstart + event.x - 2}+{self.ystart + event.y - 2}")
|
|
67
69
|
self.center_offset = (offset_x, offset_y)
|
|
68
70
|
|
|
69
71
|
def mouse_left_down(self, event):
|
|
@@ -84,8 +86,8 @@ class ScreenshotTools:
|
|
|
84
86
|
|
|
85
87
|
def mouse_left_move(self, event):
|
|
86
88
|
self.x, self.y = event.x, event.y
|
|
87
|
-
self.xcenter = self.xstart + int((self.x-self.xstart)/2)-2
|
|
88
|
-
self.ycenter = self.ystart + int((self.y-self.ystart)/2)-2
|
|
89
|
+
self.xcenter = self.xstart + int((self.x - self.xstart) / 2) - 2
|
|
90
|
+
self.ycenter = self.ystart + int((self.y - self.ystart) / 2) - 2
|
|
89
91
|
|
|
90
92
|
self.pos_label.config(text=self.pos_div_text % (self.x, self.y))
|
|
91
93
|
self.pos_div.geometry(f"+{self.x + 10}+{self.y + 10}")
|
|
@@ -107,7 +109,7 @@ class ScreenshotTools:
|
|
|
107
109
|
time.sleep(0.3)
|
|
108
110
|
img = pyautogui.screenshot(region=[self.xstart, self.ystart, self.xend - self.xstart, self.yend - self.ystart])
|
|
109
111
|
self.screenshot_path = os.path.join(application.Server.screenshotPath,
|
|
110
|
-
"screenshot-%s.png" %
|
|
112
|
+
"screenshot-%s.png" % cid.get_snowflake_id())
|
|
111
113
|
img.save(self.screenshot_path)
|
|
112
114
|
except Exception:
|
|
113
115
|
pass
|
|
@@ -123,4 +125,3 @@ def screenshot():
|
|
|
123
125
|
st = ScreenshotTools()
|
|
124
126
|
st.start()
|
|
125
127
|
return st.screenshot_path, st.center_offset
|
|
126
|
-
|
|
@@ -4,12 +4,14 @@ from multiprocessing import Process, Queue
|
|
|
4
4
|
data_queue: Queue = None
|
|
5
5
|
canvas_process: Process = None
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
class MSGType:
|
|
8
|
-
BOTTOM = 'bottom'
|
|
9
|
-
DRAW = 'draw'
|
|
9
|
+
BOTTOM = 'bottom' # 置于底部
|
|
10
|
+
DRAW = 'draw' # 绘制矩形
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
class CanvasInfo:
|
|
12
|
-
def __init__(self,title: str='', points: list=None, msg_type: MSGType=MSGType.DRAW):
|
|
14
|
+
def __init__(self, title: str = '', points: list = None, msg_type: MSGType = MSGType.DRAW):
|
|
13
15
|
self.msg_type = msg_type
|
|
14
16
|
# 标题
|
|
15
17
|
self.title = title
|
|
@@ -17,9 +19,11 @@ class CanvasInfo:
|
|
|
17
19
|
# [(100, 100), (200, 100), (200, 150), (100, 150)]
|
|
18
20
|
self.points = points
|
|
19
21
|
|
|
22
|
+
|
|
20
23
|
def on_ctrl_click(event):
|
|
21
24
|
print("Ctrl+Left Click detected")
|
|
22
25
|
|
|
26
|
+
|
|
23
27
|
class RecorderTool(tk.Tk):
|
|
24
28
|
def __init__(self, data: Queue):
|
|
25
29
|
super().__init__()
|
|
@@ -65,10 +69,12 @@ class RecorderTool(tk.Tk):
|
|
|
65
69
|
self.draw_red_border(canvas_info)
|
|
66
70
|
self.after(10, self.check_queue)
|
|
67
71
|
|
|
72
|
+
|
|
68
73
|
def _init_recorder(data):
|
|
69
74
|
canvas_app = RecorderTool(data)
|
|
70
75
|
canvas_app.mainloop()
|
|
71
76
|
|
|
77
|
+
|
|
72
78
|
def start():
|
|
73
79
|
global data_queue, canvas_process
|
|
74
80
|
data_queue = Queue()
|
|
@@ -76,8 +82,8 @@ def start():
|
|
|
76
82
|
canvas_process.start()
|
|
77
83
|
return canvas_process
|
|
78
84
|
|
|
85
|
+
|
|
79
86
|
def stop():
|
|
80
87
|
canvas_process.terminate()
|
|
81
88
|
canvas_process.join()
|
|
82
89
|
data_queue.close()
|
|
83
|
-
|