vnai 2.0.3__tar.gz → 2.0.5__tar.gz
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-2.0.3 → vnai-2.0.5}/PKG-INFO +4 -17
- vnai-2.0.5/README.md +1 -0
- vnai-2.0.5/pyproject.toml +34 -0
- {vnai-2.0.3 → vnai-2.0.5}/vnai/__init__.py +56 -81
- vnai-2.0.5/vnai/beam/__init__.py +6 -0
- {vnai-2.0.3 → vnai-2.0.5}/vnai/beam/metrics.py +47 -67
- {vnai-2.0.3 → vnai-2.0.5}/vnai/beam/pulse.py +21 -36
- {vnai-2.0.3 → vnai-2.0.5}/vnai/beam/quota.py +112 -137
- {vnai-2.0.3 → vnai-2.0.5}/vnai/flow/__init__.py +2 -4
- {vnai-2.0.3 → vnai-2.0.5}/vnai/flow/queue.py +20 -31
- {vnai-2.0.3 → vnai-2.0.5}/vnai/flow/relay.py +100 -111
- {vnai-2.0.3 → vnai-2.0.5}/vnai/scope/__init__.py +2 -4
- {vnai-2.0.3 → vnai-2.0.5}/vnai/scope/profile.py +110 -206
- vnai-2.0.5/vnai/scope/promo.py +389 -0
- {vnai-2.0.3 → vnai-2.0.5}/vnai/scope/state.py +38 -64
- {vnai-2.0.3 → vnai-2.0.5}/vnai.egg-info/PKG-INFO +4 -17
- {vnai-2.0.3 → vnai-2.0.5}/vnai.egg-info/SOURCES.txt +1 -1
- {vnai-2.0.3 → vnai-2.0.5}/vnai.egg-info/requires.txt +0 -1
- {vnai-2.0.3 → vnai-2.0.5}/vnai.egg-info/top_level.txt +1 -0
- vnai-2.0.3/README.md +0 -17
- vnai-2.0.3/setup.py +0 -37
- vnai-2.0.3/vnai/beam/__init__.py +0 -3
- vnai-2.0.3/vnai/scope/promo.py +0 -218
- {vnai-2.0.3 → vnai-2.0.5}/setup.cfg +0 -0
- {vnai-2.0.3 → vnai-2.0.5}/vnai.egg-info/dependency_links.txt +0 -0
@@ -1,11 +1,10 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: vnai
|
3
|
-
Version: 2.0.
|
3
|
+
Version: 2.0.5
|
4
4
|
Summary: System optimization and resource management toolkit
|
5
|
-
|
6
|
-
Author: Your Name
|
7
|
-
Author-email: your.email@example.com
|
5
|
+
Author-email: Vnstock HQ <support@vnstocks.com>
|
8
6
|
License: MIT
|
7
|
+
Project-URL: Homepage, https://vnstocks.com
|
9
8
|
Classifier: Programming Language :: Python :: 3
|
10
9
|
Classifier: Operating System :: OS Independent
|
11
10
|
Classifier: Development Status :: 4 - Beta
|
@@ -17,17 +16,5 @@ Requires-Dist: requests>=2.25.0
|
|
17
16
|
Requires-Dist: psutil>=5.8.0
|
18
17
|
Provides-Extra: dev
|
19
18
|
Requires-Dist: pytest>=6.0.0; extra == "dev"
|
20
|
-
Requires-Dist: black>=21.5b2; extra == "dev"
|
21
|
-
Dynamic: author
|
22
|
-
Dynamic: author-email
|
23
|
-
Dynamic: classifier
|
24
|
-
Dynamic: description
|
25
|
-
Dynamic: description-content-type
|
26
|
-
Dynamic: home-page
|
27
|
-
Dynamic: license
|
28
|
-
Dynamic: provides-extra
|
29
|
-
Dynamic: requires-dist
|
30
|
-
Dynamic: requires-python
|
31
|
-
Dynamic: summary
|
32
19
|
|
33
|
-
|
20
|
+
# VnAI
|
vnai-2.0.5/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# VnAI
|
@@ -0,0 +1,34 @@
|
|
1
|
+
[build-system]
|
2
|
+
requires = ["setuptools>=61.0"]
|
3
|
+
build-backend = "setuptools.build_meta"
|
4
|
+
|
5
|
+
[project]
|
6
|
+
name = "vnai"
|
7
|
+
version = "2.0.5"
|
8
|
+
description = "System optimization and resource management toolkit"
|
9
|
+
readme = "README.md"
|
10
|
+
requires-python = ">=3.7"
|
11
|
+
authors = [
|
12
|
+
{ name = "Vnstock HQ", email = "support@vnstocks.com" },
|
13
|
+
]
|
14
|
+
license = {text = "MIT"}
|
15
|
+
urls = {"Homepage" = "https://vnstocks.com"}
|
16
|
+
dependencies = [
|
17
|
+
"requests>=2.25.0",
|
18
|
+
"psutil>=5.8.0"
|
19
|
+
]
|
20
|
+
classifiers = [
|
21
|
+
"Programming Language :: Python :: 3",
|
22
|
+
"Operating System :: OS Independent",
|
23
|
+
"Development Status :: 4 - Beta",
|
24
|
+
"Intended Audience :: Developers",
|
25
|
+
"Topic :: Software Development :: Libraries :: Python Modules"
|
26
|
+
]
|
27
|
+
|
28
|
+
[project.optional-dependencies]
|
29
|
+
dev = [
|
30
|
+
"pytest>=6.0.0"
|
31
|
+
]
|
32
|
+
|
33
|
+
[tool.setuptools.packages.find]
|
34
|
+
where = ["."]
|
@@ -1,7 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
##
|
4
|
-
|
1
|
+
# vnai/__init__.py
|
2
|
+
# Main entry point for vnai package
|
5
3
|
|
6
4
|
import os
|
7
5
|
import pathlib
|
@@ -11,8 +9,7 @@ import threading
|
|
11
9
|
import functools
|
12
10
|
from datetime import datetime
|
13
11
|
|
14
|
-
|
15
|
-
|
12
|
+
# Import core functionality
|
16
13
|
from vnai.beam.quota import guardian, optimize
|
17
14
|
from vnai.beam.metrics import collector, capture
|
18
15
|
from vnai.beam.pulse import monitor
|
@@ -20,10 +17,10 @@ from vnai.flow.relay import conduit, configure
|
|
20
17
|
from vnai.flow.queue import buffer
|
21
18
|
from vnai.scope.profile import inspector
|
22
19
|
from vnai.scope.state import tracker, record
|
20
|
+
import vnai.scope.promo
|
23
21
|
from vnai.scope.promo import present
|
24
22
|
|
25
|
-
|
26
|
-
|
23
|
+
# Constants for terms and conditions
|
27
24
|
TC_VAR = "ACCEPT_TC"
|
28
25
|
TC_VAL = "tôi đồng ý"
|
29
26
|
TC_PATH = pathlib.Path.home() / ".vnstock" / "id" / "terms_agreement.txt"
|
@@ -37,10 +34,10 @@ Chi tiết:
|
|
37
34
|
"""
|
38
35
|
|
39
36
|
class Core:
|
40
|
-
|
37
|
+
"""Core functionality for system optimization"""
|
41
38
|
|
42
39
|
def __init__(self):
|
43
|
-
|
40
|
+
"""Initialize core"""
|
44
41
|
self.initialized = False
|
45
42
|
self.webhook_url = None
|
46
43
|
self.init_time = datetime.now().isoformat()
|
@@ -50,50 +47,41 @@ class Core:
|
|
50
47
|
self.terms_file_path = TC_PATH
|
51
48
|
self.system_info = None
|
52
49
|
|
53
|
-
|
54
|
-
|
50
|
+
# Create necessary directories
|
55
51
|
self.project_dir.mkdir(exist_ok=True)
|
56
52
|
self.id_dir.mkdir(exist_ok=True)
|
57
53
|
|
58
|
-
|
59
|
-
|
54
|
+
# Auto-initialize
|
60
55
|
self.initialize()
|
61
56
|
|
62
57
|
def initialize(self, webhook_url=None):
|
63
|
-
|
58
|
+
"""Initialize the system"""
|
64
59
|
if self.initialized:
|
65
60
|
return True
|
66
61
|
|
67
|
-
|
68
|
-
|
62
|
+
# Check terms acceptance
|
69
63
|
if not self._check_terms():
|
70
64
|
self._accept_terms()
|
71
65
|
|
72
|
-
|
73
|
-
|
66
|
+
# Set up vnstock environment
|
74
67
|
from vnai.scope.profile import inspector
|
75
68
|
inspector.setup_vnstock_environment()
|
76
69
|
|
77
|
-
|
78
|
-
|
70
|
+
# Display content during initialization
|
79
71
|
present()
|
80
72
|
|
81
|
-
|
82
|
-
|
73
|
+
# Configure webhook if provided
|
83
74
|
if webhook_url:
|
84
75
|
self.webhook_url = webhook_url
|
85
76
|
configure(webhook_url)
|
86
77
|
|
87
|
-
|
88
|
-
|
78
|
+
# Record initialization
|
89
79
|
record("initialization", {"timestamp": datetime.now().isoformat()})
|
90
80
|
|
91
|
-
|
92
|
-
|
81
|
+
# Get system information ONCE and store it in the class
|
93
82
|
self.system_info = inspector.examine()
|
94
83
|
|
95
|
-
|
96
|
-
|
84
|
+
# Queue system data with optimal structure
|
97
85
|
conduit.queue({
|
98
86
|
"type": "system_info",
|
99
87
|
"data": {
|
@@ -106,27 +94,23 @@ class Core:
|
|
106
94
|
return True
|
107
95
|
|
108
96
|
def _check_terms(self):
|
109
|
-
|
97
|
+
"""Check if terms have been accepted"""
|
110
98
|
return os.path.exists(self.terms_file_path)
|
111
99
|
|
112
100
|
def _accept_terms(self):
|
113
|
-
|
114
|
-
|
115
|
-
|
101
|
+
"""Record terms acceptance"""
|
102
|
+
# Get system information
|
116
103
|
system_info = inspector.examine()
|
117
104
|
|
118
|
-
|
119
|
-
|
105
|
+
# Auto-accept terms
|
120
106
|
if TC_VAR in os.environ and os.environ[TC_VAR] == TC_VAL:
|
121
107
|
response = TC_VAL
|
122
108
|
else:
|
123
|
-
|
124
|
-
|
109
|
+
# For non-interactive environments, accept by default
|
125
110
|
response = TC_VAL
|
126
111
|
os.environ[TC_VAR] = TC_VAL
|
127
112
|
|
128
|
-
|
129
|
-
|
113
|
+
# Store the acceptance with hardware info
|
130
114
|
now = datetime.now()
|
131
115
|
signed_agreement = (
|
132
116
|
f"Người dùng có mã nhận dạng {system_info['machine_id']} đã chấp nhận "
|
@@ -137,13 +121,11 @@ class Core:
|
|
137
121
|
f"{TERMS_AND_CONDITIONS}"
|
138
122
|
)
|
139
123
|
|
140
|
-
|
141
|
-
|
124
|
+
# Store the acceptance
|
142
125
|
with open(self.terms_file_path, "w", encoding="utf-8") as f:
|
143
126
|
f.write(signed_agreement)
|
144
127
|
|
145
|
-
|
146
|
-
|
128
|
+
# Create the environment.json file that vnstock expects
|
147
129
|
env_file = self.id_dir / "environment.json"
|
148
130
|
env_data = {
|
149
131
|
"accepted_agreement": True,
|
@@ -157,59 +139,53 @@ class Core:
|
|
157
139
|
return True
|
158
140
|
|
159
141
|
def status(self):
|
160
|
-
|
142
|
+
"""Get system status"""
|
161
143
|
return {
|
162
144
|
"initialized": self.initialized,
|
163
145
|
"health": monitor.report(),
|
164
146
|
"metrics": tracker.get_metrics()
|
165
|
-
|
166
|
-
|
147
|
+
# Environment information available via self.system_info
|
167
148
|
}
|
168
149
|
|
169
150
|
def configure_privacy(self, level="standard"):
|
170
|
-
|
151
|
+
"""Configure privacy settings"""
|
171
152
|
from vnai.scope.state import tracker
|
172
153
|
return tracker.setup_privacy(level)
|
173
154
|
|
174
155
|
|
175
|
-
|
176
|
-
|
156
|
+
# Create singleton instance
|
177
157
|
core = Core()
|
178
158
|
|
179
|
-
|
180
|
-
|
159
|
+
# Backward support
|
181
160
|
def tc_init(webhook_url=None):
|
182
161
|
return core.initialize(webhook_url)
|
183
162
|
|
184
|
-
|
185
|
-
|
163
|
+
# Public API
|
186
164
|
def setup(webhook_url=None):
|
187
|
-
|
165
|
+
"""Setup vnai with optional webhook URL"""
|
188
166
|
return core.initialize(webhook_url)
|
189
167
|
|
190
168
|
def optimize_execution(resource_type="default"):
|
191
|
-
|
169
|
+
"""Decorator for optimizing function execution"""
|
192
170
|
return optimize(resource_type)
|
193
171
|
|
194
172
|
def agg_execution(resource_type="default"):
|
195
|
-
|
173
|
+
"""Decorator for aggregating function execution"""
|
196
174
|
return optimize(resource_type, ad_cooldown=1500, content_trigger_threshold=100000)
|
197
175
|
|
198
176
|
def measure_performance(module_type="function"):
|
199
|
-
|
177
|
+
"""Decorator for measuring function performance"""
|
200
178
|
return capture(module_type)
|
201
179
|
|
202
180
|
def accept_license_terms(terms_text=None):
|
203
|
-
|
181
|
+
"""Accept license terms and conditions"""
|
204
182
|
if terms_text is None:
|
205
183
|
terms_text = TERMS_AND_CONDITIONS
|
206
184
|
|
207
|
-
|
208
|
-
|
185
|
+
# Get system information
|
209
186
|
system_info = inspector.examine()
|
210
187
|
|
211
|
-
|
212
|
-
|
188
|
+
# Record acceptance
|
213
189
|
terms_file = pathlib.Path.home() / ".vnstock" / "id" / "terms_agreement.txt"
|
214
190
|
os.makedirs(os.path.dirname(terms_file), exist_ok=True)
|
215
191
|
|
@@ -221,22 +197,19 @@ def accept_license_terms(terms_text=None):
|
|
221
197
|
return True
|
222
198
|
|
223
199
|
def accept_vnstock_terms():
|
224
|
-
|
225
|
-
|
226
|
-
|
200
|
+
"""Accept vnstock terms and create necessary files"""
|
201
|
+
# Get system information
|
227
202
|
from vnai.scope.profile import inspector
|
228
203
|
system_info = inspector.examine()
|
229
204
|
|
230
|
-
|
231
|
-
|
205
|
+
# Create necessary directories
|
232
206
|
home_dir = pathlib.Path.home()
|
233
207
|
project_dir = home_dir / ".vnstock"
|
234
208
|
project_dir.mkdir(exist_ok=True)
|
235
209
|
id_dir = project_dir / 'id'
|
236
210
|
id_dir.mkdir(exist_ok=True)
|
237
211
|
|
238
|
-
|
239
|
-
|
212
|
+
# Create environment.json file that vnstock looks for
|
240
213
|
env_file = id_dir / "environment.json"
|
241
214
|
env_data = {
|
242
215
|
"accepted_agreement": True,
|
@@ -254,40 +227,43 @@ def accept_vnstock_terms():
|
|
254
227
|
return False
|
255
228
|
|
256
229
|
def setup_for_colab():
|
257
|
-
|
230
|
+
"""Special setup for Google Colab environments"""
|
258
231
|
from vnai.scope.profile import inspector
|
259
232
|
|
260
|
-
|
261
|
-
|
233
|
+
# Immediate authentication for Colab
|
262
234
|
inspector.detect_colab_with_delayed_auth(immediate=True)
|
263
235
|
|
264
|
-
|
265
|
-
|
236
|
+
# Setup vnstock environment
|
266
237
|
inspector.setup_vnstock_environment()
|
267
238
|
|
268
239
|
return "Environment set up for Google Colab"
|
269
240
|
|
270
241
|
def display_content():
|
271
|
-
|
242
|
+
"""Display promotional content appropriate for the current environment"""
|
272
243
|
return present()
|
273
244
|
|
274
245
|
def configure_privacy(level="standard"):
|
275
|
-
|
246
|
+
"""Configure privacy level for analytics data"""
|
276
247
|
from vnai.scope.state import tracker
|
277
248
|
return tracker.setup_privacy(level)
|
278
249
|
|
279
250
|
def check_commercial_usage():
|
280
|
-
|
251
|
+
"""Check if running in commercial environment"""
|
281
252
|
from vnai.scope.profile import inspector
|
282
253
|
return inspector.detect_commercial_usage()
|
283
254
|
|
284
255
|
def authenticate_for_persistence():
|
285
|
-
|
256
|
+
"""Authenticate to Google Drive for persistent settings (Colab only)"""
|
286
257
|
from vnai.scope.profile import inspector
|
287
258
|
return inspector.get_or_create_user_id()
|
288
259
|
|
289
260
|
def configure_webhook(webhook_id='80b8832b694a75c8ddc811ac7882a3de'):
|
290
|
-
|
261
|
+
"""Configure webhook URL for analytics data transmission
|
262
|
+
|
263
|
+
This method should be called once during application initialization
|
264
|
+
to set up the analytics endpoint. For security reasons, the URL should
|
265
|
+
not be hardcoded in user-facing code.
|
266
|
+
"""
|
291
267
|
if not webhook_id:
|
292
268
|
return False
|
293
269
|
|
@@ -295,6 +271,5 @@ def configure_webhook(webhook_id='80b8832b694a75c8ddc811ac7882a3de'):
|
|
295
271
|
webhook_url = f'https://botbuilder.larksuite.com/api/trigger-webhook/{webhook_id}'
|
296
272
|
return configure(webhook_url)
|
297
273
|
|
298
|
-
|
299
|
-
|
274
|
+
# Set the webhook
|
300
275
|
configure_webhook()
|
@@ -1,7 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
##
|
4
|
-
|
1
|
+
# vnai/beam/metrics.py
|
2
|
+
# System performance metrics collection (formerly analytics)
|
5
3
|
|
6
4
|
import sys
|
7
5
|
import time
|
@@ -9,7 +7,7 @@ import threading
|
|
9
7
|
from datetime import datetime
|
10
8
|
|
11
9
|
class Collector:
|
12
|
-
|
10
|
+
"""Collects operation metrics for system optimization"""
|
13
11
|
|
14
12
|
_instance = None
|
15
13
|
_lock = threading.Lock()
|
@@ -22,7 +20,7 @@ class Collector:
|
|
22
20
|
return cls._instance
|
23
21
|
|
24
22
|
def _initialize(self):
|
25
|
-
|
23
|
+
"""Initialize collector"""
|
26
24
|
self.metrics = {
|
27
25
|
"function": [],
|
28
26
|
"rate_limit": [],
|
@@ -36,95 +34,83 @@ class Collector:
|
|
36
34
|
}
|
37
35
|
self.function_count = 0
|
38
36
|
self.colab_auth_triggered = False
|
37
|
+
self.max_metric_length = 200 # Keep only the latest 200 entries
|
39
38
|
|
40
39
|
def record(self, metric_type, data, priority=None):
|
41
|
-
|
42
|
-
##
|
40
|
+
"""Record operation metrics with deduplication and throttling"""
|
43
41
|
|
42
|
+
# Ensure data is a dictionary
|
44
43
|
if not isinstance(data, dict):
|
45
44
|
data = {"value": str(data)}
|
46
|
-
|
47
|
-
##
|
48
45
|
|
46
|
+
# Add timestamp if not present
|
49
47
|
if "timestamp" not in data:
|
50
48
|
data["timestamp"] = datetime.now().isoformat()
|
51
|
-
|
52
|
-
##
|
53
|
-
|
54
|
-
##
|
55
|
-
|
56
|
-
if metric_type != "system_info" and isinstance(data, dict):
|
57
|
-
##
|
58
|
-
|
59
|
-
if "system" in data:
|
60
|
-
del data["system"]
|
61
|
-
|
62
|
-
##
|
63
49
|
|
50
|
+
# For non-system info, simplify and tag machine
|
51
|
+
if metric_type != "system_info":
|
52
|
+
data.pop("system", None)
|
64
53
|
from vnai.scope.profile import inspector
|
65
54
|
data["machine_id"] = inspector.fingerprint()
|
66
|
-
|
67
|
-
##
|
68
55
|
|
56
|
+
# ==== THROTTLING ====
|
57
|
+
now = time.time()
|
58
|
+
last_time = self._last_record_time.get(metric_type, 0)
|
59
|
+
if now - last_time < self.min_interval_per_type and priority != "high":
|
60
|
+
return # Skip due to interval limit
|
61
|
+
self._last_record_time[metric_type] = now
|
62
|
+
|
63
|
+
# ==== DEDUPLICATION ====
|
64
|
+
data_hash = hashlib.md5(json.dumps(data, sort_keys=True).encode()).hexdigest()
|
65
|
+
if data_hash in self._recent_hashes and priority != "high":
|
66
|
+
return # Skip duplicate
|
67
|
+
self._recent_hashes.append(data_hash)
|
68
|
+
|
69
|
+
# ==== RECORD LOGIC ====
|
69
70
|
if metric_type in self.metrics:
|
70
71
|
self.metrics[metric_type].append(data)
|
72
|
+
# Prune oldest if too long
|
73
|
+
if len(self.metrics[metric_type]) > self.max_metric_length:
|
74
|
+
self.metrics[metric_type] = self.metrics[metric_type][-self.max_metric_length:]
|
71
75
|
else:
|
72
76
|
self.metrics["function"].append(data)
|
73
|
-
|
74
|
-
##
|
75
77
|
|
78
|
+
# Function metric tracking (Colab trigger)
|
76
79
|
if metric_type == "function":
|
77
80
|
self.function_count += 1
|
78
|
-
|
79
|
-
##
|
80
|
-
|
81
81
|
if self.function_count > 10 and not self.colab_auth_triggered and 'google.colab' in sys.modules:
|
82
82
|
self.colab_auth_triggered = True
|
83
|
-
|
84
|
-
|
85
|
-
threading.Thread(
|
86
|
-
target=self._trigger_colab_auth,
|
87
|
-
daemon=True
|
88
|
-
).start()
|
89
|
-
|
90
|
-
##
|
83
|
+
threading.Thread(target=self._trigger_colab_auth, daemon=True).start()
|
91
84
|
|
85
|
+
# Auto-send triggers
|
92
86
|
if sum(len(metric_list) for metric_list in self.metrics.values()) >= self.thresholds["buffer_size"]:
|
93
87
|
self._send_metrics()
|
94
|
-
|
95
|
-
##
|
96
|
-
|
97
|
-
if priority == "high" or (metric_type == "error"):
|
88
|
+
if priority == "high" or metric_type == "error":
|
98
89
|
self._send_metrics()
|
99
90
|
|
100
91
|
def _trigger_colab_auth(self):
|
101
|
-
|
92
|
+
"""Trigger Google Colab authentication in a background thread"""
|
102
93
|
try:
|
103
94
|
from vnai.scope.profile import inspector
|
104
95
|
inspector.get_or_create_user_id()
|
105
96
|
except:
|
106
|
-
pass
|
107
|
-
|
97
|
+
pass # Silently fail if there's an issue
|
108
98
|
|
109
99
|
def _send_metrics(self):
|
110
|
-
|
111
|
-
|
112
|
-
|
100
|
+
"""Send collected metrics to data relay"""
|
101
|
+
# Import here to avoid circular imports
|
113
102
|
from vnai.flow.relay import track_function_call, track_rate_limit, track_api_request
|
114
103
|
|
115
|
-
|
116
|
-
|
104
|
+
# Process and send each type of metric using the appropriate tracking function
|
117
105
|
for metric_type, data_list in self.metrics.items():
|
118
106
|
if not data_list:
|
119
107
|
continue
|
120
108
|
|
121
|
-
|
122
|
-
|
109
|
+
# Process each metric by type
|
123
110
|
for data in data_list:
|
124
111
|
try:
|
125
112
|
if metric_type == "function":
|
126
|
-
|
127
|
-
|
113
|
+
# Use the track_function_call interface
|
128
114
|
track_function_call(
|
129
115
|
function_name=data.get("function", "unknown"),
|
130
116
|
source=data.get("source", "vnai"),
|
@@ -134,8 +120,7 @@ class Collector:
|
|
134
120
|
args=data.get("args")
|
135
121
|
)
|
136
122
|
elif metric_type == "rate_limit":
|
137
|
-
|
138
|
-
|
123
|
+
# Use the track_rate_limit interface
|
139
124
|
track_rate_limit(
|
140
125
|
source=data.get("source", "vnai"),
|
141
126
|
limit_type=data.get("limit_type", "unknown"),
|
@@ -144,8 +129,7 @@ class Collector:
|
|
144
129
|
is_exceeded=data.get("is_exceeded", False)
|
145
130
|
)
|
146
131
|
elif metric_type == "request":
|
147
|
-
|
148
|
-
|
132
|
+
# Use the track_api_request interface
|
149
133
|
track_api_request(
|
150
134
|
endpoint=data.get("endpoint", "unknown"),
|
151
135
|
source=data.get("source", "vnai"),
|
@@ -156,27 +140,24 @@ class Collector:
|
|
156
140
|
response_size=data.get("response_size", 0)
|
157
141
|
)
|
158
142
|
except Exception as e:
|
159
|
-
|
160
|
-
|
143
|
+
# If tracking fails, just continue with the next item
|
161
144
|
continue
|
162
145
|
|
163
|
-
|
164
|
-
|
146
|
+
# Clear the processed metrics
|
165
147
|
self.metrics[metric_type] = []
|
166
148
|
|
167
149
|
def get_metrics_summary(self):
|
168
|
-
|
150
|
+
"""Get summary of collected metrics"""
|
169
151
|
return {
|
170
152
|
metric_type: len(data_list)
|
171
153
|
for metric_type, data_list in self.metrics.items()
|
172
154
|
}
|
173
155
|
|
174
|
-
|
175
|
-
|
156
|
+
# Create singleton instance
|
176
157
|
collector = Collector()
|
177
158
|
|
178
159
|
def capture(module_type="function"):
|
179
|
-
|
160
|
+
"""Decorator to capture metrics for any function"""
|
180
161
|
def decorator(func):
|
181
162
|
def wrapper(*args, **kwargs):
|
182
163
|
start_time = time.time()
|
@@ -201,8 +182,7 @@ def capture(module_type="function"):
|
|
201
182
|
"success": success,
|
202
183
|
"error": error,
|
203
184
|
"timestamp": datetime.now().isoformat(),
|
204
|
-
"args": str(args)[:100] if args else None
|
205
|
-
|
185
|
+
"args": str(args)[:100] if args else None # Truncate for privacy
|
206
186
|
}
|
207
187
|
)
|
208
188
|
return wrapper
|