gomyck-tools 1.3.4__py3-none-any.whl → 1.3.6__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/ai/__init__.py +4 -0
- ctools/ai/env_config.py +33 -0
- ctools/ai/llm_chat.py +168 -0
- ctools/ai/llm_client.py +133 -0
- ctools/ai/mcp/__init__.py +4 -0
- ctools/ai/mcp/mcp_client.py +305 -0
- ctools/ai/tools/__init__.py +4 -0
- ctools/ai/tools/json_extract.py +201 -0
- ctools/ai/tools/think_process.py +11 -0
- ctools/ai/tools/tool_use_xml_parse.py +32 -0
- ctools/ai/tools/xml_extract.py +13 -0
- ctools/aio_web_server.py +145 -0
- ctools/bottle_web_base.py +1 -1
- ctools/bottle_webserver.py +3 -2
- ctools/cdebug.py +8 -5
- ctools/ckafka.py +1 -2
- ctools/credis.py +1 -0
- ctools/ctoken.py +1 -0
- ctools/czip.py +1 -0
- ctools/database.py +1 -1
- ctools/douglas_rarefy.py +0 -1
- ctools/http_utils.py +1 -1
- ctools/imgDialog.py +1 -0
- ctools/metrics.py +1 -0
- ctools/mqtt_utils.py +2 -1
- ctools/pty_tools.py +3 -2
- ctools/rsa.py +1 -1
- {gomyck_tools-1.3.4.dist-info → gomyck_tools-1.3.6.dist-info}/METADATA +8 -12
- {gomyck_tools-1.3.4.dist-info → gomyck_tools-1.3.6.dist-info}/RECORD +32 -20
- {gomyck_tools-1.3.4.dist-info → gomyck_tools-1.3.6.dist-info}/WHEEL +1 -1
- {gomyck_tools-1.3.4.dist-info → gomyck_tools-1.3.6.dist-info}/licenses/LICENSE +0 -0
- {gomyck_tools-1.3.4.dist-info → gomyck_tools-1.3.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,201 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: UTF-8 -*-
|
3
|
+
__author__ = 'haoyang'
|
4
|
+
__date__ = '2025/5/19 16:45'
|
5
|
+
|
6
|
+
import re
|
7
|
+
|
8
|
+
from ctools import cjson
|
9
|
+
|
10
|
+
|
11
|
+
def extract_json_from_text(text):
|
12
|
+
"""
|
13
|
+
从混杂文本中提取第一个完整的 JSON 对象
|
14
|
+
"""
|
15
|
+
import json
|
16
|
+
|
17
|
+
# 方法1:尝试直接解析
|
18
|
+
try:
|
19
|
+
return json.loads(text)
|
20
|
+
except json.JSONDecodeError:
|
21
|
+
pass
|
22
|
+
|
23
|
+
# 方法2:字符级括号匹配提取 JSON
|
24
|
+
start = None
|
25
|
+
brace_count = 0
|
26
|
+
for i, char in enumerate(text):
|
27
|
+
if char == '{':
|
28
|
+
if start is None:
|
29
|
+
start = i
|
30
|
+
brace_count += 1
|
31
|
+
elif char == '}':
|
32
|
+
brace_count -= 1
|
33
|
+
if brace_count == 0 and start is not None:
|
34
|
+
json_candidate = text[start:i + 1]
|
35
|
+
try:
|
36
|
+
return json.loads(json_candidate)
|
37
|
+
except json.JSONDecodeError:
|
38
|
+
start = None # 重置继续寻找下一个可能的 JSON
|
39
|
+
|
40
|
+
# 方法3:尝试 JSONP 格式
|
41
|
+
match = re.search(r'\((\{[\s\S]*\})\)', text)
|
42
|
+
if match:
|
43
|
+
try:
|
44
|
+
return json.loads(match.group(1))
|
45
|
+
except json.JSONDecodeError:
|
46
|
+
pass
|
47
|
+
|
48
|
+
return None
|
49
|
+
|
50
|
+
if __name__ == '__main__':
|
51
|
+
xx = """
|
52
|
+
<think>
|
53
|
+
|
54
|
+
</think>
|
55
|
+
|
56
|
+
{
|
57
|
+
"sjbs": {
|
58
|
+
"xsbt": "东都公园业主集体信访事件",
|
59
|
+
"sjbh": "202406031234",
|
60
|
+
"jjcd": ["黄"]
|
61
|
+
},
|
62
|
+
"skys": {
|
63
|
+
"zxsj": [
|
64
|
+
{
|
65
|
+
"jqsj": "2024-06-03 09:00",
|
66
|
+
"sjms": "6月3日",
|
67
|
+
"sjlx": ["计划时间"]
|
68
|
+
}
|
69
|
+
],
|
70
|
+
"zxdd": [
|
71
|
+
{
|
72
|
+
"bzdz": "黑龙江省哈尔滨市信访局",
|
73
|
+
"cslx": ["政府机关"]
|
74
|
+
}
|
75
|
+
]
|
76
|
+
},
|
77
|
+
"ssqt": {
|
78
|
+
"qtms": ["哈尔滨市道外区东都公园业主"],
|
79
|
+
"qtgm": ["约5人以上,可能发展至群体性事件"],
|
80
|
+
"qtbq": ["房地产纠纷", "历史遗留问题"],
|
81
|
+
"zztz": ["有核心组织"]
|
82
|
+
},
|
83
|
+
"ryqd": [
|
84
|
+
{
|
85
|
+
"xm": ["杨开亮"],
|
86
|
+
"sfzh": ["2301251968101335**"],
|
87
|
+
"js": ["组织者"],
|
88
|
+
"hjd": ["哈尔滨市宾县满井镇永宁村崔海屯"],
|
89
|
+
"jzd": ["团结镇东都公元一区五栋二单元603"],
|
90
|
+
"lxdh": ["139366789**"],
|
91
|
+
"rybq": ["重点人"],
|
92
|
+
"wlzh": {
|
93
|
+
"wx": [],
|
94
|
+
"qq": []
|
95
|
+
},
|
96
|
+
"gjxx": [
|
97
|
+
{
|
98
|
+
"sj": ["2024-05-28 20:26"],
|
99
|
+
"dd": ["网络群聊"],
|
100
|
+
"xw": ["组织动员"]
|
101
|
+
}
|
102
|
+
]
|
103
|
+
},
|
104
|
+
{
|
105
|
+
"xm": ["孙凤玲"],
|
106
|
+
"sfzh": ["2301041955121712**"],
|
107
|
+
"js": ["积极参与者"],
|
108
|
+
"hjd": ["哈尔滨市道外区迎新街好民居滨港水岸D15栋1单元14层4号"],
|
109
|
+
"jzd": ["道外区陶瓷小区D15-1-1404"],
|
110
|
+
"lxdh": ["17758887348"],
|
111
|
+
"rybq": [],
|
112
|
+
"wlzh": {
|
113
|
+
"wx": [],
|
114
|
+
"qq": []
|
115
|
+
},
|
116
|
+
"gjxx": [
|
117
|
+
{
|
118
|
+
"sj": ["2024-05-28 19:00"],
|
119
|
+
"dd": ["网络群聊"],
|
120
|
+
"xw": ["响应组织"]
|
121
|
+
}
|
122
|
+
]
|
123
|
+
},
|
124
|
+
{
|
125
|
+
"xm": ["高秀艳"],
|
126
|
+
"sfzh": ["2323261982060762**"],
|
127
|
+
"js": ["积极参与者"],
|
128
|
+
"hjd": ["绥化市青冈县劳动乡北斗村丛喜云屯"],
|
129
|
+
"jzd": ["哈尔滨市道外区团结镇森桐木业"],
|
130
|
+
"lxdh": ["15846349146"],
|
131
|
+
"rybq": [],
|
132
|
+
"wlzh": {
|
133
|
+
"wx": [],
|
134
|
+
"qq": []
|
135
|
+
},
|
136
|
+
"gjxx": [
|
137
|
+
{
|
138
|
+
"sj": ["2024-05-28 20:00"],
|
139
|
+
"dd": ["网络群聊"],
|
140
|
+
"xw": ["响应组织"]
|
141
|
+
}
|
142
|
+
]
|
143
|
+
},
|
144
|
+
{
|
145
|
+
"xm": ["高振凤"],
|
146
|
+
"sfzh": ["2323031974103046**"],
|
147
|
+
"js": ["一般参与者"],
|
148
|
+
"hjd": ["绥化市肇东市东发乡夕阳村郭家屯"],
|
149
|
+
"jzd": ["团结镇团结镇东都公园一区七栋一单元101"],
|
150
|
+
"lxdh": ["18004659805"],
|
151
|
+
"rybq": [],
|
152
|
+
"wlzh": {
|
153
|
+
"wx": [],
|
154
|
+
"qq": []
|
155
|
+
},
|
156
|
+
"gjxx": [
|
157
|
+
{
|
158
|
+
"sj": ["2024-05-28 19:30"],
|
159
|
+
"dd": ["网络群聊"],
|
160
|
+
"xw": ["响应组织"]
|
161
|
+
}
|
162
|
+
]
|
163
|
+
},
|
164
|
+
{
|
165
|
+
"xm": ["陈立军"],
|
166
|
+
"sfzh": ["2301251980031907**"],
|
167
|
+
"js": ["组织者", "群主"],
|
168
|
+
"hjd": ["哈尔滨市宾县宾西镇一委六组"],
|
169
|
+
"jzd": [],
|
170
|
+
"lxdh": ["15776806667"],
|
171
|
+
"rybq": ["重点人"],
|
172
|
+
"wlzh": {
|
173
|
+
"wx": [],
|
174
|
+
"qq": []
|
175
|
+
},
|
176
|
+
"gjxx": [
|
177
|
+
{
|
178
|
+
"sj": ["2024-05-28 19:00"],
|
179
|
+
"dd": ["网络群聊"],
|
180
|
+
"xw": ["组织动员"]
|
181
|
+
}
|
182
|
+
]
|
183
|
+
}
|
184
|
+
],
|
185
|
+
"sjtz": {
|
186
|
+
"xwlx": ["集体信访", "网络串联"],
|
187
|
+
"sqnr": ["要求政府解决房产证办理问题,明确责任主体并推动政策落实"],
|
188
|
+
"dktz": [],
|
189
|
+
"zjly": ["自筹"]
|
190
|
+
},
|
191
|
+
"czjy": {
|
192
|
+
"zrdw": ["哈尔滨市公安局道外分局", "信访维稳专班"],
|
193
|
+
"yjcs": ["提前约谈重点人员", "加强网络群组监控", "部署现场警力"]
|
194
|
+
}
|
195
|
+
}
|
196
|
+
20250603142141-INFO-8399134464-web_log(log:214) 127.0.0.1 [03/Jun/2025:14:18:39 +0800] "POST /chat/completion HTTP/1.1" 200 3670 "-" "python-requests/2.32.3"
|
197
|
+
|
198
|
+
|
199
|
+
"""
|
200
|
+
|
201
|
+
print((cjson.dumps(extract_json_from_text(xx))))
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: UTF-8 -*-
|
3
|
+
__author__ = 'haoyang'
|
4
|
+
__date__ = '2025/6/3 14:30'
|
5
|
+
|
6
|
+
import re
|
7
|
+
|
8
|
+
|
9
|
+
def remove_think_blocks(text: str) -> str:
|
10
|
+
cleaned_text = re.sub(r"<think>.*?</think>", "", text, flags=re.DOTALL)
|
11
|
+
return cleaned_text.strip()
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import json
|
2
|
+
import xml.etree.ElementTree as ET
|
3
|
+
import html
|
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
|
+
arguments_text = root.find("arguments").text.strip()
|
13
|
+
arguments_text = html.unescape(arguments_text)
|
14
|
+
arguments = json.loads(arguments_text)
|
15
|
+
return {
|
16
|
+
"tool": tool_name,
|
17
|
+
"arguments": arguments
|
18
|
+
}
|
19
|
+
except Exception as e:
|
20
|
+
raise ValueError(f"tool_use_{tool_name} 解析失败: {e}")
|
21
|
+
|
22
|
+
# 测试
|
23
|
+
if __name__ == '__main__':
|
24
|
+
xml_input = """
|
25
|
+
<tool_use>
|
26
|
+
<name>set</name>
|
27
|
+
<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>
|
28
|
+
</tool_use>
|
29
|
+
"""
|
30
|
+
result = parse_tool_use(xml_input)
|
31
|
+
print("\n【结果】")
|
32
|
+
print(json.dumps(result, ensure_ascii=False, indent=2))
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import re
|
2
|
+
|
3
|
+
def extract_all_xml_blocks(text):
|
4
|
+
return re.findall(r"<tool_use>.*?</tool_use>", text, re.DOTALL)
|
5
|
+
text = """
|
6
|
+
一些内容...
|
7
|
+
123
|
8
|
+
"""
|
9
|
+
|
10
|
+
results = extract_all_xml_blocks(text)
|
11
|
+
print(results)
|
12
|
+
for xml_block in results:
|
13
|
+
print(xml_block)
|
ctools/aio_web_server.py
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: UTF-8 -*-
|
3
|
+
"""A lightweight async HTTP server based on aiohttp."""
|
4
|
+
|
5
|
+
__author__ = 'haoyang'
|
6
|
+
__date__ = '2025/5/30 09:54'
|
7
|
+
|
8
|
+
import asyncio
|
9
|
+
import sys
|
10
|
+
from pathlib import Path
|
11
|
+
from typing import Optional, Dict, Any
|
12
|
+
|
13
|
+
from aiohttp import web
|
14
|
+
|
15
|
+
from ctools import sys_info
|
16
|
+
|
17
|
+
DEFAULT_PORT = 8888
|
18
|
+
|
19
|
+
class AioHttpServer:
|
20
|
+
def __init__(self, port: int = DEFAULT_PORT, app: Optional[web.Application] = None, routes: Optional[web.RouteTableDef] = None, async_func = None):
|
21
|
+
"""
|
22
|
+
Initialize the HTTP server.
|
23
|
+
|
24
|
+
Args:
|
25
|
+
port: Port number to listen on
|
26
|
+
app: Optional existing aiohttp Application instance
|
27
|
+
"""
|
28
|
+
self.app = app or web.Application()
|
29
|
+
self.port = port
|
30
|
+
self.index_root = Path('./')
|
31
|
+
self.index_filename = 'index.html'
|
32
|
+
self.is_tpl = False
|
33
|
+
self.template_args: Dict[str, Any] = {}
|
34
|
+
self.redirect_url: Optional[str] = None
|
35
|
+
self.static_root = Path('./static')
|
36
|
+
self.download_root = Path('./download')
|
37
|
+
self.routes = routes
|
38
|
+
self.async_func = async_func
|
39
|
+
|
40
|
+
# Register routes
|
41
|
+
self.app.add_routes([
|
42
|
+
web.get('/', self.handle_index),
|
43
|
+
web.get('/index', self.handle_index),
|
44
|
+
web.get('/static/{filepath:.*}', self.handle_static),
|
45
|
+
web.get('/download/{filepath:.*}', self.handle_download)
|
46
|
+
])
|
47
|
+
if self.routes:
|
48
|
+
self.app.add_routes(self.routes)
|
49
|
+
|
50
|
+
async def handle_index(self, request: web.Request) -> web.StreamResponse:
|
51
|
+
"""Handle requests to the index page."""
|
52
|
+
if self.redirect_url:
|
53
|
+
return web.HTTPFound(self.redirect_url)
|
54
|
+
|
55
|
+
index_path = self.index_root / self.index_filename
|
56
|
+
|
57
|
+
if not index_path.exists():
|
58
|
+
return web.HTTPNotFound()
|
59
|
+
|
60
|
+
if self.is_tpl:
|
61
|
+
# If using templates, you might want to use a template engine here
|
62
|
+
return web.FileResponse(
|
63
|
+
index_path,
|
64
|
+
headers={'Content-Type': 'text/html'}
|
65
|
+
)
|
66
|
+
return web.FileResponse(index_path)
|
67
|
+
|
68
|
+
async def handle_static(self, request: web.Request) -> web.StreamResponse:
|
69
|
+
"""Handle static file requests."""
|
70
|
+
filepath = Path(request.match_info['filepath'])
|
71
|
+
full_path = self.static_root / filepath
|
72
|
+
|
73
|
+
if not full_path.exists():
|
74
|
+
return web.HTTPNotFound()
|
75
|
+
|
76
|
+
return web.FileResponse(full_path)
|
77
|
+
|
78
|
+
async def handle_download(self, request: web.Request) -> web.StreamResponse:
|
79
|
+
"""Handle file download requests."""
|
80
|
+
filepath = Path(request.match_info['filepath'])
|
81
|
+
full_path = self.download_root / filepath
|
82
|
+
|
83
|
+
if not full_path.exists():
|
84
|
+
return web.HTTPNotFound()
|
85
|
+
|
86
|
+
return web.FileResponse(
|
87
|
+
full_path,
|
88
|
+
headers={'Content-Disposition': f'attachment; filename="{filepath.name}"'}
|
89
|
+
)
|
90
|
+
|
91
|
+
def set_index(
|
92
|
+
self,
|
93
|
+
filename: str = 'index.html',
|
94
|
+
root: str = './',
|
95
|
+
is_tpl: bool = False,
|
96
|
+
redirect_url: Optional[str] = None,
|
97
|
+
**kwargs: Any
|
98
|
+
) -> None:
|
99
|
+
"""
|
100
|
+
Configure index page settings.
|
101
|
+
|
102
|
+
Args:
|
103
|
+
filename: Name of the index file
|
104
|
+
root: Root directory for index file
|
105
|
+
is_tpl: Whether the file is a template
|
106
|
+
redirect_url: URL to redirect to instead of serving index
|
107
|
+
kwargs: Additional template arguments
|
108
|
+
"""
|
109
|
+
self.index_root = Path(root)
|
110
|
+
self.index_filename = filename
|
111
|
+
self.is_tpl = is_tpl
|
112
|
+
self.redirect_url = redirect_url
|
113
|
+
self.template_args = kwargs
|
114
|
+
|
115
|
+
def set_static(self, root: str = './static') -> None:
|
116
|
+
"""Set the root directory for static files."""
|
117
|
+
self.static_root = Path(root)
|
118
|
+
|
119
|
+
def set_download(self, root: str = './download') -> None:
|
120
|
+
"""Set the root directory for downloadable files."""
|
121
|
+
self.download_root = Path(root)
|
122
|
+
|
123
|
+
async def run(self) -> None:
|
124
|
+
"""Run the server."""
|
125
|
+
if self.async_func:
|
126
|
+
await self.async_func()
|
127
|
+
print(
|
128
|
+
'Server running at:\n'
|
129
|
+
f'\tLocal: http://localhost:{self.port}\n'
|
130
|
+
f'\tNetwork: http://{sys_info.get_local_ipv4()}:{self.port}',
|
131
|
+
file=sys.stderr
|
132
|
+
)
|
133
|
+
await web._run_app(
|
134
|
+
self.app,
|
135
|
+
port=self.port,
|
136
|
+
host='0.0.0.0'
|
137
|
+
)
|
138
|
+
|
139
|
+
|
140
|
+
def init_routes() -> web.RouteTableDef:
|
141
|
+
return web.RouteTableDef()
|
142
|
+
|
143
|
+
def init_server(routes: Optional[web.RouteTableDef] = None, app: Optional[web.Application] = None, port: int = DEFAULT_PORT, async_func = None) -> AioHttpServer:
|
144
|
+
"""Initialize and return a new AioHttpServer instance."""
|
145
|
+
return AioHttpServer(port=port, app=app, routes=routes, async_func=async_func)
|
ctools/bottle_web_base.py
CHANGED
@@ -6,8 +6,8 @@ import bottle
|
|
6
6
|
from bottle import response, Bottle, request
|
7
7
|
|
8
8
|
from ctools import ctoken
|
9
|
-
from ctools.dict_wrapper import DictWrapper
|
10
9
|
from ctools.api_result import R
|
10
|
+
from ctools.dict_wrapper import DictWrapper
|
11
11
|
from ctools.sys_log import flog as log
|
12
12
|
|
13
13
|
bottle.BaseRequest.MEMFILE_MAX = 1024 * 1024 * 50
|
ctools/bottle_webserver.py
CHANGED
@@ -22,7 +22,7 @@ def get_ws_modules():
|
|
22
22
|
"""
|
23
23
|
|
24
24
|
"""
|
25
|
-
from ctools import bottle_web_base,
|
25
|
+
from ctools import bottle_web_base, ctoken, bottle_webserver
|
26
26
|
from ctools.api_result import R
|
27
27
|
|
28
28
|
secret_key = "xxx"
|
@@ -35,7 +35,7 @@ def token_check():
|
|
35
35
|
|
36
36
|
@app.post('/login')
|
37
37
|
def login(params):
|
38
|
-
return R.ok(
|
38
|
+
return R.ok(ctoken.gen_token({'username': 'xxx'}, secret_key, 3600))
|
39
39
|
|
40
40
|
@app.get('/demo')
|
41
41
|
@bottle_web_base.rule('DOC:DOWNLOAD')
|
@@ -115,6 +115,7 @@ class CBottle:
|
|
115
115
|
self.download_root = root
|
116
116
|
|
117
117
|
def mount(self, context_path, app, **kwargs):
|
118
|
+
if not context_path: return
|
118
119
|
self.bottle.mount(context_path, app, **kwargs)
|
119
120
|
|
120
121
|
def init_bottle(app:Bottle=None, port=_default_port, quiet=False) -> CBottle:
|
ctools/cdebug.py
CHANGED
@@ -14,6 +14,11 @@ class ProgramInterceptor:
|
|
14
14
|
self.log_queue = Queue()
|
15
15
|
|
16
16
|
def start(self):
|
17
|
+
if self.command[0] == "--log":
|
18
|
+
# 启动日志写入线程
|
19
|
+
log_thread = threading.Thread(target=self._write_log_thread, daemon=True)
|
20
|
+
log_thread.start()
|
21
|
+
self.command = self.command[1:]
|
17
22
|
# 启动子进程
|
18
23
|
self.process = subprocess.Popen(
|
19
24
|
self.command,
|
@@ -24,10 +29,6 @@ class ProgramInterceptor:
|
|
24
29
|
universal_newlines=True
|
25
30
|
)
|
26
31
|
|
27
|
-
# 启动日志写入线程
|
28
|
-
log_thread = threading.Thread(target=self._write_log_thread, daemon=True)
|
29
|
-
log_thread.start()
|
30
|
-
|
31
32
|
# 记录初始信息
|
32
33
|
self._enqueue_log("header", f"Command: {' '.join(self.command)}")
|
33
34
|
self._enqueue_log("header", f"Start time: {datetime.now()}")
|
@@ -88,7 +89,9 @@ class ProgramInterceptor:
|
|
88
89
|
|
89
90
|
# 等待日志写入完成
|
90
91
|
self.log_queue.put(None) # 结束信号
|
91
|
-
log_thread.
|
92
|
+
if hasattr(self, "log_thread") and isinstance(self.log_thread, threading.Thread):
|
93
|
+
if self.log_thread.is_alive():
|
94
|
+
self.log_thread.join(timeout=2)
|
92
95
|
|
93
96
|
def _forward_stream(self, source, target, stream_name):
|
94
97
|
"""转发数据流并记录"""
|
ctools/ckafka.py
CHANGED
@@ -4,12 +4,11 @@ __author__ = 'haoyang'
|
|
4
4
|
__date__ = '2024/9/5 10:39'
|
5
5
|
|
6
6
|
import time
|
7
|
-
from threading import Thread
|
7
|
+
from threading import Thread
|
8
8
|
|
9
9
|
from kafka import KafkaProducer, errors, KafkaConsumer
|
10
10
|
from kafka.producer.future import FutureRecordMetadata
|
11
11
|
|
12
|
-
from ctools import thread_pool
|
13
12
|
from ctools.cjson import dumps
|
14
13
|
|
15
14
|
"""
|
ctools/credis.py
CHANGED
@@ -8,6 +8,7 @@ from redis import Redis
|
|
8
8
|
|
9
9
|
from ctools import date_utils, thread_pool, string_tools
|
10
10
|
|
11
|
+
|
11
12
|
def init_pool(host: str = 'localhost', port: int = 6379, db: int = 0, password: str = None,
|
12
13
|
username: str = None, decode_responses: bool = True, max_connections: int = 75,
|
13
14
|
health_check_interval: int = 30, retry_count: int = 3) -> Redis:
|
ctools/ctoken.py
CHANGED
ctools/czip.py
CHANGED
ctools/database.py
CHANGED
ctools/douglas_rarefy.py
CHANGED
ctools/http_utils.py
CHANGED
@@ -16,7 +16,7 @@ def get(url, params=None, headers=None):
|
|
16
16
|
|
17
17
|
def post(url, data=None, json=None, headers=None, files=None):
|
18
18
|
result = ""
|
19
|
-
response = requests.post(url, data=data, json=json, files=files, headers=headers, timeout=
|
19
|
+
response = requests.post(url, data=data, json=json, files=files, headers=headers, timeout=600, verify=False)
|
20
20
|
response.raise_for_status()
|
21
21
|
if response.status_code == 200:
|
22
22
|
result = response.content
|
ctools/imgDialog.py
CHANGED
ctools/metrics.py
CHANGED
ctools/mqtt_utils.py
CHANGED
@@ -2,11 +2,12 @@ import time
|
|
2
2
|
from enum import Enum
|
3
3
|
from typing import Dict
|
4
4
|
|
5
|
-
from ctools.dict_wrapper import DictWrapper as DictToObj
|
6
5
|
from paho.mqtt import client as mqtt
|
7
6
|
from paho.mqtt.enums import CallbackAPIVersion
|
8
7
|
|
9
8
|
from ctools import sys_log, cjson, string_tools, sys_info, date_utils, sm_tools, thread_pool
|
9
|
+
from ctools.dict_wrapper import DictWrapper as DictToObj
|
10
|
+
|
10
11
|
|
11
12
|
class MQTTEvent(Enum):
|
12
13
|
|
ctools/pty_tools.py
CHANGED
ctools/rsa.py
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: gomyck-tools
|
3
|
-
Version: 1.3.
|
3
|
+
Version: 1.3.6
|
4
4
|
Summary: A tools collection for python development by hao474798383
|
5
5
|
Author-email: gomyck <hao474798383@163.com>
|
6
6
|
License-Expression: Apache-2.0
|
7
|
-
Requires-Python: >=3.
|
7
|
+
Requires-Python: >=3.11
|
8
8
|
Description-Content-Type: text/markdown
|
9
9
|
License-File: LICENSE
|
10
10
|
Requires-Dist: jsonpickle~=3.4.2
|
@@ -32,16 +32,12 @@ Requires-Dist: redis==5.2.1
|
|
32
32
|
Provides-Extra: db
|
33
33
|
Requires-Dist: sqlalchemy>=2.0; extra == "db"
|
34
34
|
Requires-Dist: asyncpg>=0.28; extra == "db"
|
35
|
-
Provides-Extra:
|
36
|
-
Requires-Dist:
|
37
|
-
Requires-Dist:
|
38
|
-
Requires-Dist:
|
39
|
-
Provides-Extra:
|
40
|
-
Requires-Dist:
|
41
|
-
Requires-Dist: asyncpg>=0.28; extra == "full"
|
42
|
-
Requires-Dist: pytest>=7.0; extra == "full"
|
43
|
-
Requires-Dist: black>=24.0; extra == "full"
|
44
|
-
Requires-Dist: mypy>=1.0; extra == "full"
|
35
|
+
Provides-Extra: office
|
36
|
+
Requires-Dist: pandas>=2.2.3; extra == "office"
|
37
|
+
Requires-Dist: xlrd>=2.0.1; extra == "office"
|
38
|
+
Requires-Dist: python-docx>=1.1.2; extra == "office"
|
39
|
+
Provides-Extra: auto-ui
|
40
|
+
Requires-Dist: pynput==1.7.7; extra == "auto-ui"
|
45
41
|
Dynamic: license-file
|
46
42
|
|
47
43
|
# Gomyck-Tools
|