vnai 2.0.1__py3-none-any.whl → 2.0.3__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.
- vnai/__init__.py +84 -54
- vnai/beam/__init__.py +0 -3
- vnai/beam/metrics.py +57 -32
- vnai/beam/pulse.py +36 -21
- vnai/beam/quota.py +143 -109
- vnai/flow/__init__.py +4 -2
- vnai/flow/queue.py +31 -20
- vnai/flow/relay.py +101 -64
- vnai/scope/__init__.py +4 -2
- vnai/scope/profile.py +205 -110
- vnai/scope/promo.py +96 -114
- vnai/scope/state.py +64 -38
- {vnai-2.0.1.dist-info → vnai-2.0.3.dist-info}/METADATA +3 -2
- vnai-2.0.3.dist-info/RECORD +16 -0
- {vnai-2.0.1.dist-info → vnai-2.0.3.dist-info}/WHEEL +1 -1
- vnai-2.0.1.dist-info/RECORD +0 -16
- {vnai-2.0.1.dist-info → vnai-2.0.3.dist-info}/top_level.txt +0 -0
vnai/__init__.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
##
|
2
|
+
|
3
|
+
##
|
4
|
+
|
3
5
|
|
4
6
|
import os
|
5
7
|
import pathlib
|
@@ -9,7 +11,8 @@ import threading
|
|
9
11
|
import functools
|
10
12
|
from datetime import datetime
|
11
13
|
|
12
|
-
|
14
|
+
##
|
15
|
+
|
13
16
|
from vnai.beam.quota import guardian, optimize
|
14
17
|
from vnai.beam.metrics import collector, capture
|
15
18
|
from vnai.beam.pulse import monitor
|
@@ -19,7 +22,8 @@ from vnai.scope.profile import inspector
|
|
19
22
|
from vnai.scope.state import tracker, record
|
20
23
|
from vnai.scope.promo import present
|
21
24
|
|
22
|
-
|
25
|
+
##
|
26
|
+
|
23
27
|
TC_VAR = "ACCEPT_TC"
|
24
28
|
TC_VAL = "tôi đồng ý"
|
25
29
|
TC_PATH = pathlib.Path.home() / ".vnstock" / "id" / "terms_agreement.txt"
|
@@ -33,10 +37,10 @@ Chi tiết:
|
|
33
37
|
"""
|
34
38
|
|
35
39
|
class Core:
|
36
|
-
|
40
|
+
#--
|
37
41
|
|
38
42
|
def __init__(self):
|
39
|
-
|
43
|
+
#--
|
40
44
|
self.initialized = False
|
41
45
|
self.webhook_url = None
|
42
46
|
self.init_time = datetime.now().isoformat()
|
@@ -46,41 +50,50 @@ class Core:
|
|
46
50
|
self.terms_file_path = TC_PATH
|
47
51
|
self.system_info = None
|
48
52
|
|
49
|
-
|
53
|
+
##
|
54
|
+
|
50
55
|
self.project_dir.mkdir(exist_ok=True)
|
51
56
|
self.id_dir.mkdir(exist_ok=True)
|
52
57
|
|
53
|
-
|
58
|
+
##
|
59
|
+
|
54
60
|
self.initialize()
|
55
61
|
|
56
62
|
def initialize(self, webhook_url=None):
|
57
|
-
|
63
|
+
#--
|
58
64
|
if self.initialized:
|
59
65
|
return True
|
60
66
|
|
61
|
-
|
67
|
+
##
|
68
|
+
|
62
69
|
if not self._check_terms():
|
63
70
|
self._accept_terms()
|
64
71
|
|
65
|
-
|
72
|
+
##
|
73
|
+
|
66
74
|
from vnai.scope.profile import inspector
|
67
75
|
inspector.setup_vnstock_environment()
|
68
76
|
|
69
|
-
|
77
|
+
##
|
78
|
+
|
70
79
|
present()
|
71
80
|
|
72
|
-
|
81
|
+
##
|
82
|
+
|
73
83
|
if webhook_url:
|
74
84
|
self.webhook_url = webhook_url
|
75
85
|
configure(webhook_url)
|
76
86
|
|
77
|
-
|
87
|
+
##
|
88
|
+
|
78
89
|
record("initialization", {"timestamp": datetime.now().isoformat()})
|
79
90
|
|
80
|
-
|
91
|
+
##
|
92
|
+
|
81
93
|
self.system_info = inspector.examine()
|
82
94
|
|
83
|
-
|
95
|
+
##
|
96
|
+
|
84
97
|
conduit.queue({
|
85
98
|
"type": "system_info",
|
86
99
|
"data": {
|
@@ -93,23 +106,27 @@ class Core:
|
|
93
106
|
return True
|
94
107
|
|
95
108
|
def _check_terms(self):
|
96
|
-
|
109
|
+
#--
|
97
110
|
return os.path.exists(self.terms_file_path)
|
98
111
|
|
99
112
|
def _accept_terms(self):
|
100
|
-
|
101
|
-
|
113
|
+
#--
|
114
|
+
##
|
115
|
+
|
102
116
|
system_info = inspector.examine()
|
103
117
|
|
104
|
-
|
118
|
+
##
|
119
|
+
|
105
120
|
if TC_VAR in os.environ and os.environ[TC_VAR] == TC_VAL:
|
106
121
|
response = TC_VAL
|
107
122
|
else:
|
108
|
-
|
123
|
+
##
|
124
|
+
|
109
125
|
response = TC_VAL
|
110
126
|
os.environ[TC_VAR] = TC_VAL
|
111
127
|
|
112
|
-
|
128
|
+
##
|
129
|
+
|
113
130
|
now = datetime.now()
|
114
131
|
signed_agreement = (
|
115
132
|
f"Người dùng có mã nhận dạng {system_info['machine_id']} đã chấp nhận "
|
@@ -120,11 +137,13 @@ class Core:
|
|
120
137
|
f"{TERMS_AND_CONDITIONS}"
|
121
138
|
)
|
122
139
|
|
123
|
-
|
140
|
+
##
|
141
|
+
|
124
142
|
with open(self.terms_file_path, "w", encoding="utf-8") as f:
|
125
143
|
f.write(signed_agreement)
|
126
144
|
|
127
|
-
|
145
|
+
##
|
146
|
+
|
128
147
|
env_file = self.id_dir / "environment.json"
|
129
148
|
env_data = {
|
130
149
|
"accepted_agreement": True,
|
@@ -138,49 +157,59 @@ class Core:
|
|
138
157
|
return True
|
139
158
|
|
140
159
|
def status(self):
|
141
|
-
|
160
|
+
#--
|
142
161
|
return {
|
143
162
|
"initialized": self.initialized,
|
144
163
|
"health": monitor.report(),
|
145
164
|
"metrics": tracker.get_metrics()
|
146
|
-
|
165
|
+
##
|
166
|
+
|
147
167
|
}
|
148
168
|
|
149
169
|
def configure_privacy(self, level="standard"):
|
150
|
-
|
170
|
+
#--
|
151
171
|
from vnai.scope.state import tracker
|
152
172
|
return tracker.setup_privacy(level)
|
153
173
|
|
154
174
|
|
155
|
-
|
175
|
+
##
|
176
|
+
|
156
177
|
core = Core()
|
157
178
|
|
158
|
-
|
179
|
+
##
|
180
|
+
|
159
181
|
def tc_init(webhook_url=None):
|
160
182
|
return core.initialize(webhook_url)
|
161
183
|
|
162
|
-
|
184
|
+
##
|
185
|
+
|
163
186
|
def setup(webhook_url=None):
|
164
|
-
|
187
|
+
#--
|
165
188
|
return core.initialize(webhook_url)
|
166
189
|
|
167
190
|
def optimize_execution(resource_type="default"):
|
168
|
-
|
191
|
+
#--
|
169
192
|
return optimize(resource_type)
|
170
193
|
|
194
|
+
def agg_execution(resource_type="default"):
|
195
|
+
#--
|
196
|
+
return optimize(resource_type, ad_cooldown=1500, content_trigger_threshold=100000)
|
197
|
+
|
171
198
|
def measure_performance(module_type="function"):
|
172
|
-
|
199
|
+
#--
|
173
200
|
return capture(module_type)
|
174
201
|
|
175
202
|
def accept_license_terms(terms_text=None):
|
176
|
-
|
203
|
+
#--
|
177
204
|
if terms_text is None:
|
178
205
|
terms_text = TERMS_AND_CONDITIONS
|
179
206
|
|
180
|
-
|
207
|
+
##
|
208
|
+
|
181
209
|
system_info = inspector.examine()
|
182
210
|
|
183
|
-
|
211
|
+
##
|
212
|
+
|
184
213
|
terms_file = pathlib.Path.home() / ".vnstock" / "id" / "terms_agreement.txt"
|
185
214
|
os.makedirs(os.path.dirname(terms_file), exist_ok=True)
|
186
215
|
|
@@ -192,19 +221,22 @@ def accept_license_terms(terms_text=None):
|
|
192
221
|
return True
|
193
222
|
|
194
223
|
def accept_vnstock_terms():
|
195
|
-
|
196
|
-
|
224
|
+
#--
|
225
|
+
##
|
226
|
+
|
197
227
|
from vnai.scope.profile import inspector
|
198
228
|
system_info = inspector.examine()
|
199
229
|
|
200
|
-
|
230
|
+
##
|
231
|
+
|
201
232
|
home_dir = pathlib.Path.home()
|
202
233
|
project_dir = home_dir / ".vnstock"
|
203
234
|
project_dir.mkdir(exist_ok=True)
|
204
235
|
id_dir = project_dir / 'id'
|
205
236
|
id_dir.mkdir(exist_ok=True)
|
206
237
|
|
207
|
-
|
238
|
+
##
|
239
|
+
|
208
240
|
env_file = id_dir / "environment.json"
|
209
241
|
env_data = {
|
210
242
|
"accepted_agreement": True,
|
@@ -222,43 +254,40 @@ def accept_vnstock_terms():
|
|
222
254
|
return False
|
223
255
|
|
224
256
|
def setup_for_colab():
|
225
|
-
|
257
|
+
#--
|
226
258
|
from vnai.scope.profile import inspector
|
227
259
|
|
228
|
-
|
260
|
+
##
|
261
|
+
|
229
262
|
inspector.detect_colab_with_delayed_auth(immediate=True)
|
230
263
|
|
231
|
-
|
264
|
+
##
|
265
|
+
|
232
266
|
inspector.setup_vnstock_environment()
|
233
267
|
|
234
268
|
return "Environment set up for Google Colab"
|
235
269
|
|
236
270
|
def display_content():
|
237
|
-
|
271
|
+
#--
|
238
272
|
return present()
|
239
273
|
|
240
274
|
def configure_privacy(level="standard"):
|
241
|
-
|
275
|
+
#--
|
242
276
|
from vnai.scope.state import tracker
|
243
277
|
return tracker.setup_privacy(level)
|
244
278
|
|
245
279
|
def check_commercial_usage():
|
246
|
-
|
280
|
+
#--
|
247
281
|
from vnai.scope.profile import inspector
|
248
282
|
return inspector.detect_commercial_usage()
|
249
283
|
|
250
284
|
def authenticate_for_persistence():
|
251
|
-
|
285
|
+
#--
|
252
286
|
from vnai.scope.profile import inspector
|
253
287
|
return inspector.get_or_create_user_id()
|
254
288
|
|
255
289
|
def configure_webhook(webhook_id='80b8832b694a75c8ddc811ac7882a3de'):
|
256
|
-
|
257
|
-
|
258
|
-
This method should be called once during application initialization
|
259
|
-
to set up the analytics endpoint. For security reasons, the URL should
|
260
|
-
not be hardcoded in user-facing code.
|
261
|
-
"""
|
290
|
+
#--
|
262
291
|
if not webhook_id:
|
263
292
|
return False
|
264
293
|
|
@@ -266,5 +295,6 @@ def configure_webhook(webhook_id='80b8832b694a75c8ddc811ac7882a3de'):
|
|
266
295
|
webhook_url = f'https://botbuilder.larksuite.com/api/trigger-webhook/{webhook_id}'
|
267
296
|
return configure(webhook_url)
|
268
297
|
|
269
|
-
|
298
|
+
##
|
299
|
+
|
270
300
|
configure_webhook()
|
vnai/beam/__init__.py
CHANGED
vnai/beam/metrics.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
##
|
2
|
+
|
3
|
+
##
|
4
|
+
|
3
5
|
|
4
6
|
import sys
|
5
7
|
import time
|
@@ -7,7 +9,7 @@ import threading
|
|
7
9
|
from datetime import datetime
|
8
10
|
|
9
11
|
class Collector:
|
10
|
-
|
12
|
+
#--
|
11
13
|
|
12
14
|
_instance = None
|
13
15
|
_lock = threading.Lock()
|
@@ -20,7 +22,7 @@ class Collector:
|
|
20
22
|
return cls._instance
|
21
23
|
|
22
24
|
def _initialize(self):
|
23
|
-
|
25
|
+
#--
|
24
26
|
self.metrics = {
|
25
27
|
"function": [],
|
26
28
|
"rate_limit": [],
|
@@ -36,76 +38,93 @@ class Collector:
|
|
36
38
|
self.colab_auth_triggered = False
|
37
39
|
|
38
40
|
def record(self, metric_type, data, priority=None):
|
39
|
-
|
40
|
-
|
41
|
+
#--
|
42
|
+
##
|
43
|
+
|
41
44
|
if not isinstance(data, dict):
|
42
45
|
data = {"value": str(data)}
|
43
46
|
|
44
|
-
|
47
|
+
##
|
48
|
+
|
45
49
|
if "timestamp" not in data:
|
46
50
|
data["timestamp"] = datetime.now().isoformat()
|
47
51
|
|
48
|
-
|
49
|
-
|
52
|
+
##
|
53
|
+
|
54
|
+
##
|
55
|
+
|
50
56
|
if metric_type != "system_info" and isinstance(data, dict):
|
51
|
-
|
57
|
+
##
|
58
|
+
|
52
59
|
if "system" in data:
|
53
60
|
del data["system"]
|
54
61
|
|
55
|
-
|
62
|
+
##
|
63
|
+
|
56
64
|
from vnai.scope.profile import inspector
|
57
65
|
data["machine_id"] = inspector.fingerprint()
|
58
66
|
|
59
|
-
|
67
|
+
##
|
68
|
+
|
60
69
|
if metric_type in self.metrics:
|
61
70
|
self.metrics[metric_type].append(data)
|
62
71
|
else:
|
63
72
|
self.metrics["function"].append(data)
|
64
73
|
|
65
|
-
|
74
|
+
##
|
75
|
+
|
66
76
|
if metric_type == "function":
|
67
77
|
self.function_count += 1
|
68
78
|
|
69
|
-
|
79
|
+
##
|
80
|
+
|
70
81
|
if self.function_count > 10 and not self.colab_auth_triggered and 'google.colab' in sys.modules:
|
71
82
|
self.colab_auth_triggered = True
|
72
|
-
|
83
|
+
##
|
84
|
+
|
73
85
|
threading.Thread(
|
74
86
|
target=self._trigger_colab_auth,
|
75
87
|
daemon=True
|
76
88
|
).start()
|
77
89
|
|
78
|
-
|
90
|
+
##
|
91
|
+
|
79
92
|
if sum(len(metric_list) for metric_list in self.metrics.values()) >= self.thresholds["buffer_size"]:
|
80
93
|
self._send_metrics()
|
81
94
|
|
82
|
-
|
95
|
+
##
|
96
|
+
|
83
97
|
if priority == "high" or (metric_type == "error"):
|
84
98
|
self._send_metrics()
|
85
99
|
|
86
100
|
def _trigger_colab_auth(self):
|
87
|
-
|
101
|
+
#--
|
88
102
|
try:
|
89
103
|
from vnai.scope.profile import inspector
|
90
104
|
inspector.get_or_create_user_id()
|
91
105
|
except:
|
92
|
-
pass
|
106
|
+
pass ##
|
107
|
+
|
93
108
|
|
94
109
|
def _send_metrics(self):
|
95
|
-
|
96
|
-
|
110
|
+
#--
|
111
|
+
##
|
112
|
+
|
97
113
|
from vnai.flow.relay import track_function_call, track_rate_limit, track_api_request
|
98
114
|
|
99
|
-
|
115
|
+
##
|
116
|
+
|
100
117
|
for metric_type, data_list in self.metrics.items():
|
101
118
|
if not data_list:
|
102
119
|
continue
|
103
120
|
|
104
|
-
|
121
|
+
##
|
122
|
+
|
105
123
|
for data in data_list:
|
106
124
|
try:
|
107
125
|
if metric_type == "function":
|
108
|
-
|
126
|
+
##
|
127
|
+
|
109
128
|
track_function_call(
|
110
129
|
function_name=data.get("function", "unknown"),
|
111
130
|
source=data.get("source", "vnai"),
|
@@ -115,7 +134,8 @@ class Collector:
|
|
115
134
|
args=data.get("args")
|
116
135
|
)
|
117
136
|
elif metric_type == "rate_limit":
|
118
|
-
|
137
|
+
##
|
138
|
+
|
119
139
|
track_rate_limit(
|
120
140
|
source=data.get("source", "vnai"),
|
121
141
|
limit_type=data.get("limit_type", "unknown"),
|
@@ -124,7 +144,8 @@ class Collector:
|
|
124
144
|
is_exceeded=data.get("is_exceeded", False)
|
125
145
|
)
|
126
146
|
elif metric_type == "request":
|
127
|
-
|
147
|
+
##
|
148
|
+
|
128
149
|
track_api_request(
|
129
150
|
endpoint=data.get("endpoint", "unknown"),
|
130
151
|
source=data.get("source", "vnai"),
|
@@ -135,24 +156,27 @@ class Collector:
|
|
135
156
|
response_size=data.get("response_size", 0)
|
136
157
|
)
|
137
158
|
except Exception as e:
|
138
|
-
|
159
|
+
##
|
160
|
+
|
139
161
|
continue
|
140
162
|
|
141
|
-
|
163
|
+
##
|
164
|
+
|
142
165
|
self.metrics[metric_type] = []
|
143
166
|
|
144
167
|
def get_metrics_summary(self):
|
145
|
-
|
168
|
+
#--
|
146
169
|
return {
|
147
170
|
metric_type: len(data_list)
|
148
171
|
for metric_type, data_list in self.metrics.items()
|
149
172
|
}
|
150
173
|
|
151
|
-
|
174
|
+
##
|
175
|
+
|
152
176
|
collector = Collector()
|
153
177
|
|
154
178
|
def capture(module_type="function"):
|
155
|
-
|
179
|
+
#--
|
156
180
|
def decorator(func):
|
157
181
|
def wrapper(*args, **kwargs):
|
158
182
|
start_time = time.time()
|
@@ -177,7 +201,8 @@ def capture(module_type="function"):
|
|
177
201
|
"success": success,
|
178
202
|
"error": error,
|
179
203
|
"timestamp": datetime.now().isoformat(),
|
180
|
-
"args": str(args)[:100] if args else None
|
204
|
+
"args": str(args)[:100] if args else None ##
|
205
|
+
|
181
206
|
}
|
182
207
|
)
|
183
208
|
return wrapper
|
vnai/beam/pulse.py
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
##
|
2
|
+
|
3
|
+
##
|
4
|
+
|
3
5
|
|
4
6
|
import threading
|
5
7
|
import time
|
6
8
|
from datetime import datetime
|
7
9
|
|
8
10
|
class Monitor:
|
9
|
-
|
11
|
+
#--
|
10
12
|
|
11
13
|
_instance = None
|
12
14
|
_lock = threading.Lock()
|
@@ -19,47 +21,55 @@ class Monitor:
|
|
19
21
|
return cls._instance
|
20
22
|
|
21
23
|
def _initialize(self):
|
22
|
-
|
24
|
+
#--
|
23
25
|
self.health_status = "healthy"
|
24
26
|
self.last_check = time.time()
|
25
|
-
self.check_interval = 300
|
27
|
+
self.check_interval = 300 ##
|
28
|
+
|
26
29
|
self.error_count = 0
|
27
30
|
self.warning_count = 0
|
28
31
|
self.status_history = []
|
29
32
|
|
30
|
-
|
33
|
+
##
|
34
|
+
|
31
35
|
self._start_background_check()
|
32
36
|
|
33
37
|
def _start_background_check(self):
|
34
|
-
|
38
|
+
#--
|
35
39
|
def check_health():
|
36
40
|
while True:
|
37
41
|
try:
|
38
42
|
self.check_health()
|
39
43
|
except:
|
40
|
-
pass
|
44
|
+
pass ##
|
45
|
+
|
41
46
|
time.sleep(self.check_interval)
|
42
47
|
|
43
48
|
thread = threading.Thread(target=check_health, daemon=True)
|
44
49
|
thread.start()
|
45
50
|
|
46
51
|
def check_health(self):
|
47
|
-
|
52
|
+
#--
|
48
53
|
from vnai.beam.metrics import collector
|
49
54
|
from vnai.beam.quota import guardian
|
50
55
|
|
51
|
-
|
56
|
+
##
|
57
|
+
|
52
58
|
self.last_check = time.time()
|
53
59
|
|
54
|
-
|
60
|
+
##
|
61
|
+
|
55
62
|
metrics_summary = collector.get_metrics_summary()
|
56
63
|
has_errors = metrics_summary.get("error", 0) > 0
|
57
64
|
|
58
|
-
|
65
|
+
##
|
66
|
+
|
59
67
|
resource_usage = guardian.usage()
|
60
|
-
high_usage = resource_usage > 80
|
68
|
+
high_usage = resource_usage > 80 ##
|
69
|
+
|
61
70
|
|
62
|
-
|
71
|
+
##
|
72
|
+
|
63
73
|
if has_errors and high_usage:
|
64
74
|
self.health_status = "critical"
|
65
75
|
self.error_count += 1
|
@@ -69,7 +79,8 @@ class Monitor:
|
|
69
79
|
else:
|
70
80
|
self.health_status = "healthy"
|
71
81
|
|
72
|
-
|
82
|
+
##
|
83
|
+
|
73
84
|
self.status_history.append({
|
74
85
|
"timestamp": datetime.now().isoformat(),
|
75
86
|
"status": self.health_status,
|
@@ -77,15 +88,17 @@ class Monitor:
|
|
77
88
|
"resource_usage": resource_usage
|
78
89
|
})
|
79
90
|
|
80
|
-
|
91
|
+
##
|
92
|
+
|
81
93
|
if len(self.status_history) > 10:
|
82
94
|
self.status_history = self.status_history[-10:]
|
83
95
|
|
84
96
|
return self.health_status
|
85
97
|
|
86
98
|
def report(self):
|
87
|
-
|
88
|
-
|
99
|
+
#--
|
100
|
+
##
|
101
|
+
|
89
102
|
if time.time() - self.last_check > self.check_interval:
|
90
103
|
self.check_health()
|
91
104
|
|
@@ -94,16 +107,18 @@ class Monitor:
|
|
94
107
|
"last_check": datetime.fromtimestamp(self.last_check).isoformat(),
|
95
108
|
"error_count": self.error_count,
|
96
109
|
"warning_count": self.warning_count,
|
97
|
-
"history": self.status_history[-3:],
|
110
|
+
"history": self.status_history[-3:], ##
|
111
|
+
|
98
112
|
}
|
99
113
|
|
100
114
|
def reset(self):
|
101
|
-
|
115
|
+
#--
|
102
116
|
self.health_status = "healthy"
|
103
117
|
self.error_count = 0
|
104
118
|
self.warning_count = 0
|
105
119
|
self.status_history = []
|
106
120
|
self.last_check = time.time()
|
107
121
|
|
108
|
-
|
122
|
+
##
|
123
|
+
|
109
124
|
monitor = Monitor()
|