vnai 2.0.4__py3-none-any.whl → 2.0.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.
vnai/__init__.py CHANGED
@@ -17,6 +17,7 @@ from vnai.flow.relay import conduit, configure
17
17
  from vnai.flow.queue import buffer
18
18
  from vnai.scope.profile import inspector
19
19
  from vnai.scope.state import tracker, record
20
+ import vnai.scope.promo
20
21
  from vnai.scope.promo import present
21
22
 
22
23
  # Constants for terms and conditions
vnai/beam/metrics.py CHANGED
@@ -34,53 +34,58 @@ class Collector:
34
34
  }
35
35
  self.function_count = 0
36
36
  self.colab_auth_triggered = False
37
+ self.max_metric_length = 200 # Keep only the latest 200 entries
37
38
 
38
39
  def record(self, metric_type, data, priority=None):
39
- """Record operation metrics"""
40
+ """Record operation metrics with deduplication and throttling"""
41
+
40
42
  # Ensure data is a dictionary
41
43
  if not isinstance(data, dict):
42
44
  data = {"value": str(data)}
43
-
45
+
44
46
  # Add timestamp if not present
45
47
  if "timestamp" not in data:
46
48
  data["timestamp"] = datetime.now().isoformat()
47
-
48
- # For system_info type, keep full data
49
- # For other types, only include machine_id reference
50
- if metric_type != "system_info" and isinstance(data, dict):
51
- # Remove any system info and just reference machine_id
52
- if "system" in data:
53
- del data["system"]
54
-
55
- # Get machine_id for reference
49
+
50
+ # For non-system info, simplify and tag machine
51
+ if metric_type != "system_info":
52
+ data.pop("system", None)
56
53
  from vnai.scope.profile import inspector
57
54
  data["machine_id"] = inspector.fingerprint()
58
-
59
- # Add to appropriate metrics collection
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 ====
60
70
  if metric_type in self.metrics:
61
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:]
62
75
  else:
63
76
  self.metrics["function"].append(data)
64
-
65
- # Keep track of function call count for Colab auth trigger
77
+
78
+ # Function metric tracking (Colab trigger)
66
79
  if metric_type == "function":
67
80
  self.function_count += 1
68
-
69
- # Check if we should trigger Colab authentication
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
- # Trigger in a separate thread to avoid blocking
73
- threading.Thread(
74
- target=self._trigger_colab_auth,
75
- daemon=True
76
- ).start()
77
-
78
- # Check buffer size and send if threshold reached
83
+ threading.Thread(target=self._trigger_colab_auth, daemon=True).start()
84
+
85
+ # Auto-send triggers
79
86
  if sum(len(metric_list) for metric_list in self.metrics.values()) >= self.thresholds["buffer_size"]:
80
87
  self._send_metrics()
81
-
82
- # Send immediately for high priority metrics
83
- if priority == "high" or (metric_type == "error"):
88
+ if priority == "high" or metric_type == "error":
84
89
  self._send_metrics()
85
90
 
86
91
  def _trigger_colab_auth(self):
vnai/beam/quota.py CHANGED
@@ -47,7 +47,10 @@ class Guardian:
47
47
  self.resource_limits["default"] = {"min": 60, "hour": 3000}
48
48
  self.resource_limits["TCBS"] = {"min": 60, "hour": 3000}
49
49
  self.resource_limits["VCI"] = {"min": 60, "hour": 3000}
50
+ self.resource_limits["MBK"] = {"min": 600, "hour": 36000}
51
+ self.resource_limits["MAS.ext"] = {"min": 600, "hour": 36000}
50
52
  self.resource_limits["VCI.ext"] = {"min": 600, "hour": 36000}
53
+ self.resource_limits["FMK.ext"] = {"min": 600, "hour": 36000}
51
54
  self.resource_limits["VND.ext"] = {"min": 600, "hour": 36000}
52
55
  self.resource_limits["CAF.ext"] = {"min": 600, "hour": 36000}
53
56
  self.resource_limits["SPL.ext"] = {"min": 600, "hour": 36000}
vnai/flow/relay.py CHANGED
@@ -191,13 +191,37 @@ class Conduit:
191
191
  ).start()
192
192
 
193
193
  def queue(self, package, priority=None):
194
+ # --- Auto add 'segment' field to every payload ---
195
+ try:
196
+ from vnai.scope.promo import ContentManager
197
+ is_paid = ContentManager().is_paid_user
198
+ segment_val = "paid" if is_paid else "free"
199
+ except Exception:
200
+ segment_val = "free"
201
+
202
+ def ensure_segment(d):
203
+ if not isinstance(d, dict):
204
+ return d
205
+ d = dict(d) # tạo bản sao để không ảnh hưởng dict gốc
206
+ if "segment" not in d:
207
+ d["segment"] = segment_val
208
+ return d
209
+ # Add segment to package if not present
210
+ if isinstance(package, dict) and "segment" not in package:
211
+ package["segment"] = segment_val
212
+ # Add segment to data if exists and is dict
213
+ if isinstance(package, dict) and isinstance(package.get("data"), dict):
214
+ if "segment" not in package["data"]:
215
+ package["data"]["segment"] = segment_val
216
+ # --- End auto segment ---
217
+
194
218
  """Queue data package"""
195
219
  if not package:
196
220
  return False
197
221
 
198
222
  # Handle non-dictionary packages
199
223
  if not isinstance(package, dict):
200
- self.add_function_call({"message": str(package)})
224
+ self.add_function_call(ensure_segment({"message": str(package)}))
201
225
  return True
202
226
 
203
227
  # Add timestamp if not present
@@ -216,13 +240,12 @@ class Conduit:
216
240
  data.pop("system")
217
241
  if machine_id:
218
242
  data["machine_id"] = machine_id
219
-
220
243
  if package_type == "function":
221
- self.add_function_call(data)
244
+ self.add_function_call(ensure_segment(data))
222
245
  elif package_type == "api_request":
223
- self.add_api_request(data)
246
+ self.add_api_request(ensure_segment(data))
224
247
  elif package_type == "rate_limit":
225
- self.add_rate_limit(data)
248
+ self.add_rate_limit(ensure_segment(data))
226
249
  elif package_type == "system_info":
227
250
  # For system info, we'll add it as a special function call
228
251
  # but remove duplicated data
@@ -239,19 +262,22 @@ class Conduit:
239
262
  if isinstance(metrics_list, list):
240
263
  if metric_type == "function":
241
264
  for item in metrics_list:
242
- self.add_function_call(item)
265
+ self.add_function_call(ensure_segment(item))
243
266
  elif metric_type == "rate_limit":
244
267
  for item in metrics_list:
245
- self.add_rate_limit(item)
268
+ self.add_rate_limit(ensure_segment(item))
246
269
  elif metric_type == "request":
247
270
  for item in metrics_list:
248
- self.add_api_request(item)
271
+ self.add_api_request(ensure_segment(item))
249
272
  else:
250
273
  # Default to function calls
251
- self.add_function_call(data)
274
+ if isinstance(data, dict) and data is not package:
275
+ self.add_function_call(ensure_segment(data))
276
+ else:
277
+ self.add_function_call(ensure_segment(package))
252
278
  else:
253
279
  # No type specified, default to function call
254
- self.add_function_call(package)
280
+ self.add_function_call(ensure_segment(package))
255
281
 
256
282
  # Handle high priority items
257
283
  if priority == "high":
vnai/scope/promo.py CHANGED
@@ -10,6 +10,28 @@ import threading
10
10
  import time
11
11
  import urllib.parse
12
12
 
13
+ _vnii_check_attempted = False
14
+
15
+ # Enum AdCategory (tương thích với vnii)
16
+ class AdCategory:
17
+ FREE = 0
18
+ MANDATORY = 1
19
+ ANNOUNCEMENT = 2
20
+ REFERRAL = 3
21
+ FEATURE = 4
22
+ GUIDE = 5
23
+ SURVEY = 6
24
+ PROMOTION = 7
25
+ SECURITY = 8
26
+ MAINTENANCE = 9
27
+ WARNING = 10
28
+
29
+ # Thêm import kiểm tra license từ vnii
30
+ try:
31
+ from vnii import lc_init
32
+ except ImportError:
33
+ lc_init = None # Nếu không có vnii, luôn coi là free user
34
+
13
35
  # Module-level logger setup
14
36
  logger = logging.getLogger(__name__)
15
37
  if not logger.hasHandlers():
@@ -43,19 +65,83 @@ class ContentManager:
43
65
  """
44
66
  Internal initializer: sets up display timing, URLs, and starts the periodic display thread.
45
67
  """
68
+ global _vnii_check_attempted
69
+ if _vnii_check_attempted:
70
+ # Đã kiểm tra/cài đặt vnii trước đó, không làm lại nữa
71
+ return
72
+ _vnii_check_attempted = True
73
+ # Nếu máy đã từng cài vnii, luôn cài lại bản mới nhất; nếu chưa từng cài thì coi là free user
74
+ import sys
75
+ import importlib
76
+ try:
77
+ import importlib.metadata
78
+ try:
79
+ old_version = importlib.metadata.version("vnii")
80
+ # Nếu đã từng cài, luôn force cài bản mới nhất
81
+ VNII_LATEST_VERSION = "0.0.9"
82
+ VNII_URL = f"https://github.com/vnstock-hq/licensing/releases/download/vnii-{VNII_LATEST_VERSION}/vnii-{VNII_LATEST_VERSION}.tar.gz"
83
+ logger.debug(f"Đã phát hiện vnii version {old_version}. Đang cập nhật lên bản mới nhất...")
84
+ import subprocess
85
+ subprocess.check_call([sys.executable, "-m", "pip", "install", f"vnii@{VNII_URL}"])
86
+ importlib.invalidate_caches()
87
+ if "vnii" in sys.modules:
88
+ importlib.reload(sys.modules["vnii"])
89
+ else:
90
+ import vnii
91
+ new_version = importlib.metadata.version("vnii")
92
+ logger.debug(f"Đã cập nhật vnii lên version {new_version}")
93
+ except importlib.metadata.PackageNotFoundError:
94
+ # Nếu chưa từng cài, không cài, luôn coi là free user
95
+ logger.debug("Không phát hiện vnii trên hệ thống. Luôn coi là free user, không kiểm tra license.")
96
+ self.is_paid_user = False
97
+ return
98
+ except Exception as e:
99
+ logger.warning(f"Lỗi khi kiểm tra/cài đặt vnii: {e}")
100
+ user_msg = (
101
+ "Không thể tự động cài đặt/cập nhật vnii. "
102
+ "Vui lòng liên hệ admin hoặc hỗ trợ kỹ thuật của Vnstock để được trợ giúp. "
103
+ f"Chi tiết lỗi: {e}"
104
+ )
105
+ logger.error(user_msg)
106
+ try:
107
+ print(user_msg)
108
+ except Exception:
109
+ pass
110
+ self.is_paid_user = False
111
+ return
112
+
113
+ # Kiểm tra trạng thái paid user (sponsor) và cache lại
114
+ self.is_paid_user = False
115
+ logger.debug("[promo] Bắt đầu kiểm tra trạng thái paid user với vnii...")
116
+ if lc_init is not None:
117
+ try:
118
+ license_info = lc_init(repo_name='vnstock')
119
+ logger.debug(f"[promo] license_info trả về: {license_info}")
120
+ status = license_info.get('status', '').lower()
121
+ if 'recognized and verified' in status:
122
+ self.is_paid_user = True
123
+ logger.debug("[promo] Đã xác nhận paid user từ vnii. Sẽ không hiện quảng cáo.")
124
+ else:
125
+ logger.debug(f"[promo] Không xác nhận được paid user từ vnii. Status: {status}")
126
+ except Exception as e:
127
+ logger.warning(f"[promo] Không thể kiểm tra trạng thái sponsor: {e}. Sẽ coi là free user và hiện quảng cáo.")
128
+ else:
129
+ logger.debug("[promo] Không tìm thấy module vnii. Luôn coi là free user và hiện quảng cáo.")
130
+
46
131
  # Timestamp of last content display (epoch seconds)
47
132
  self.last_display = 0
48
133
  # Minimum interval between displays (24 hours)
49
134
  self.display_interval = 24 * 3600
50
135
 
51
136
  # Base endpoints for fetching remote content and linking
52
- self.content_base_url = "https://vnstock-beam.hf.space/content-delivery"
137
+ self.content_base_url = "https://hq.vnstocks.com/static"
53
138
  self.target_url = "https://vnstocks.com/lp-khoa-hoc-python-chung-khoan"
54
139
  self.image_url = (
55
140
  "https://vnstocks.com/img/trang-chu-vnstock-python-api-phan-tich-giao-dich-chung-khoan.jpg"
56
141
  )
57
142
 
58
143
  # Launch the background thread to periodically present content
144
+ logger.debug(f"[promo] is_paid_user = {self.is_paid_user}")
59
145
  self._start_periodic_display()
60
146
 
61
147
  def _start_periodic_display(self):
@@ -63,21 +149,36 @@ class ContentManager:
63
149
  Launch a daemon thread that sleeps a random duration between 2–6 hours,
64
150
  then checks if the display interval has elapsed and calls present_content.
65
151
  """
152
+ logger.debug("[promo] Khởi tạo thread hiển thị quảng cáo định kỳ...")
66
153
  def periodic_display():
154
+ logger.debug("[promo] Thread quảng cáo bắt đầu chạy.")
67
155
  while True:
156
+ # Nếu là paid user thì không bao giờ hiện ads
157
+ if self.is_paid_user:
158
+ logger.debug("[promo] Đang là paid user trong thread. Không hiện quảng cáo, dừng thread.")
159
+ break
68
160
  # Randomize sleep to avoid synchronized requests across instances
69
161
  sleep_time = random.randint(2 * 3600, 6 * 3600)
162
+ logger.debug(f"[promo] Thread quảng cáo sẽ ngủ {sleep_time//3600} giờ...")
70
163
  time.sleep(sleep_time)
71
164
 
72
165
  # Present content if enough time has passed since last_display
73
166
  current_time = time.time()
167
+ logger.debug(f"[promo] Kiểm tra điều kiện hiện quảng cáo: time since last_display = {current_time - self.last_display}s")
74
168
  if current_time - self.last_display >= self.display_interval:
169
+ logger.debug("[promo] Đã đủ thời gian, sẽ gọi present_content(context='periodic')")
75
170
  self.present_content(context="periodic")
171
+ else:
172
+ logger.debug("[promo] Chưa đủ thời gian, chưa hiện quảng cáo.")
76
173
 
77
174
  thread = threading.Thread(target=periodic_display, daemon=True)
78
175
  thread.start()
79
176
 
80
177
  def fetch_remote_content(self, context: str = "init", html: bool = True) -> str:
178
+ if self.is_paid_user:
179
+ logger.debug("Paid user detected. Skip fetching remote content (ads).")
180
+ return ""
181
+
81
182
  """
82
183
  Fetch promotional content from remote service with context and format flag.
83
184
 
@@ -104,16 +205,21 @@ class ContentManager:
104
205
  logger.debug(f"Failed to fetch remote content: {e}")
105
206
  return None
106
207
 
107
- def present_content(self, environment: str = None, context: str = "init") -> None:
208
+ def present_content(self, context: str = "init", ad_category: int = AdCategory.FREE) -> None:
209
+ environment = None
210
+ logger.debug(f"[promo] Gọi present_content(context={context}, ad_category={ad_category}). is_paid_user = {getattr(self, 'is_paid_user', None)}")
108
211
  """
109
- Present content according to the detected environment:
110
- - In Jupyter: use display(HTML or Markdown).
111
- - In terminal or other: log via logger.info().
112
-
113
- Args:
114
- environment: override detected environment ("jupyter", "terminal", else).
115
- context: same context flag passed to fetch_remote_content and fallback logic.
212
+ Display promotional content in the appropriate environment.
213
+ ad_category: Loại quảng cáo (FREE, ANNOUNCEMENT, ...)
116
214
  """
215
+ # Nếu là paid user và ad_category là FREE thì skip, còn lại vẫn hiện
216
+ if getattr(self, 'is_paid_user', False) and ad_category == AdCategory.FREE:
217
+ logger.debug("[promo] Đang là paid user và ad_category là FREE. Không hiện quảng cáo.")
218
+ return
219
+
220
+ # Chỉ hiện log này nếu debug mode
221
+ if logger.level <= logging.DEBUG:
222
+ logger.debug(f"[promo] Sẽ hiển thị quảng cáo với context={context}, ad_category={ad_category}")
117
223
  # Update last display timestamp
118
224
  self.last_display = time.time()
119
225
 
@@ -122,42 +228,52 @@ class ContentManager:
122
228
  try:
123
229
  from vnai.scope.profile import inspector
124
230
  environment = inspector.examine().get("environment", "unknown")
125
- except Exception:
231
+ logger.debug(f"[promo] Đã detect environment: {environment}")
232
+ except Exception as e:
233
+ logger.debug(f"[promo] Không detect được environment: {e}")
126
234
  environment = "unknown"
127
235
 
128
236
  # Retrieve remote or HTML/text content based on environment
129
237
  remote_content = self.fetch_remote_content(
130
238
  context=context, html=(environment == "jupyter")
131
239
  )
240
+ logger.debug(f"[promo] remote_content = {bool(remote_content)} (None -> False, có nội dung -> True)")
132
241
  # Generate fallback messages if remote fetch fails
133
242
  fallback = self._generate_fallback_content(context)
243
+ logger.debug(f"[promo] fallback keys: {list(fallback.keys())}")
134
244
 
135
245
  if environment == "jupyter":
136
- # Rich display in Jupyter notebooks
246
+ logger.debug("[promo] Đang môi trường Jupyter, sẽ thử display HTML/Markdown.")
137
247
  try:
138
248
  from IPython.display import display, HTML, Markdown
139
249
 
140
250
  if remote_content:
251
+ logger.debug("[promo] Hiển thị quảng cáo bằng HTML từ remote_content.")
141
252
  display(HTML(remote_content))
142
253
  else:
143
- # Try Markdown, fallback to HTML
254
+ logger.debug("[promo] Không có remote_content, thử display fallback Markdown/HTML.")
144
255
  try:
145
256
  display(Markdown(fallback["markdown"]))
146
- except Exception:
257
+ except Exception as e:
258
+ logger.debug(f"[promo] Lỗi khi display Markdown: {e}, fallback HTML.")
147
259
  display(HTML(fallback["html"]))
148
260
  except Exception as e:
149
- logger.debug(f"Jupyter display failed: {e}")
261
+ logger.debug(f"[promo] Jupyter display failed: {e}")
150
262
 
151
263
  elif environment == "terminal":
264
+ logger.debug("[promo] Đang ở môi trường terminal, sẽ log quảng cáo ra logger.")
152
265
  # Log terminal-friendly or raw content via logger
153
266
  if remote_content:
154
- logger.info(remote_content)
267
+ logger.debug("[promo] Hiển thị quảng cáo bằng remote_content cho terminal.")
268
+ logger.debug(remote_content)
155
269
  else:
156
- logger.info(fallback["terminal"])
270
+ logger.debug("[promo] Không có remote_content, hiển thị fallback terminal.")
271
+ logger.debug(fallback["terminal"])
157
272
 
158
273
  else:
274
+ logger.debug(f"[promo] Môi trường khác ({environment}), hiển thị fallback simple.")
159
275
  # Generic simple message for other environments
160
- logger.info(fallback["simple"])
276
+ logger.debug(fallback["simple"])
161
277
 
162
278
  def _generate_fallback_content(self, context):
163
279
  fallback = {"html": "", "markdown": "", "terminal": "", "simple": ""}
@@ -225,46 +341,51 @@ class ContentManager:
225
341
 
226
342
  Cảm ơn bạn đã sử dụng package phân tích chứng khoán #1 tại Việt Nam
227
343
 
228
- * Tài liệu: [Sổ tay hướng dẫn](https://vnstocks.com/docs/category/s%E1%BB%95-tay-h%C6%B0%E1%BB%9Bng-d%E1%BA%ABn)
229
- * Cộng đồng: [Nhóm Facebook](https://www.facebook.com/groups/vnstock.official)
344
+ * Tài liệu: [Sổ tay hướng dẫn](https://vnstocks.com/docs)
345
+ * Cộng đồng: [Nhóm Facebook](https://facebook.com/groups/vnstock.official)
230
346
 
231
347
  Khám phá các tính năng mới nhất và tham gia cộng đồng để nhận hỗ trợ.
232
348
  """
233
349
  )
234
350
  fallback["terminal"] = (
235
351
  """
236
- ╔══════════════════════════════════════════════════════════╗
237
-
238
- ║ 👋 Chào mừng bạn đến với Vnstock!
239
-
240
- ║ Cảm ơn bạn đã sử dụng package phân tích
241
- ║ chứng khoán #1 tại Việt Nam
242
-
243
- ║ ✓ Tài liệu: https://vnstocks.com/docs/category/s%E1%BB%95-tay-h%C6%B0%E1%BB%9Bng-d%E1%BA%ABn
244
- ║ ✓ Cộng đồng: https://www.facebook.com/groups/vnstock.official
245
-
246
- ║ Khám phá các tính năng mới nhất và tham gia
247
- ║ cộng đồng để nhận hỗ trợ.
248
-
249
- ╚══════════════════════════════════════════════════════════╝
352
+ ╔════════════════════════════════════════════════════════════╗
353
+
354
+ ║ 👋 Chào mừng bạn đến với Vnstock!
355
+
356
+ ║ Cảm ơn bạn đã sử dụng package phân tích
357
+ ║ chứng khoán #1 tại Việt Nam
358
+
359
+ ║ ✓ Tài liệu: https://vnstocks.com/docs
360
+ ║ ✓ Cộng đồng: https://facebook.com/groups/vnstock.official
361
+
362
+ ║ Khám phá các tính năng mới nhất và tham gia
363
+ ║ cộng đồng để nhận hỗ trợ.
364
+
365
+ ╚════════════════════════════════════════════════════════════╝
250
366
  """
251
367
  )
252
368
  fallback["simple"] = (
253
369
  "👋 Chào mừng bạn đến với Vnstock! "
254
- "Tài liệu: https://vnstocks.com/docs/tai-lieu/huong-dan-nhanh | "
255
- "Cộng đồng: https://www.facebook.com/groups/vnstock.official"
370
+ "Tài liệu: https://vnstocks.com/onboard | "
371
+ "Cộng đồng: https://facebook.com/groups/vnstock.official"
256
372
  )
257
373
  return fallback
258
374
 
259
375
  # Singleton instance for module-level use
260
376
  manager = ContentManager()
261
377
 
378
+ # Ép buộc hiện quảng cáo ngay khi import nếu là free user
379
+ if not getattr(manager, 'is_paid_user', False):
380
+ manager.present_content(context="auto_import")
381
+
262
382
 
263
- def present(context: str = "init") -> None:
383
+ def present(context: str = "init", ad_category: int = AdCategory.FREE) -> None:
264
384
  """
265
385
  Shortcut to ContentManager.present_content for external callers.
266
386
 
267
387
  Args:
268
388
  context: propagate context string to ContentManager.
389
+ ad_category: loại quảng cáo (FREE, ANNOUNCEMENT, ...)
269
390
  """
270
- return manager.present_content(context=context)
391
+ manager.present_content(context=context, ad_category=ad_category)
@@ -1,11 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vnai
3
- Version: 2.0.4
3
+ Version: 2.0.6
4
4
  Summary: System optimization and resource management toolkit
5
- Home-page: https://github.com/vnstock-hq/initialization/new/main
6
- Author: Vnstock HQ
7
- Author-email: support@vnstocks.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,16 +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
- Dynamic: author
21
- Dynamic: author-email
22
- Dynamic: classifier
23
- Dynamic: description
24
- Dynamic: description-content-type
25
- Dynamic: home-page
26
- Dynamic: license
27
- Dynamic: provides-extra
28
- Dynamic: requires-dist
29
- Dynamic: requires-python
30
- Dynamic: summary
31
19
 
32
- System resource management and performance optimization toolkit
20
+ # VnAI
@@ -0,0 +1,16 @@
1
+ vnai/__init__.py,sha256=t27DlC7AGj-c4MrunqFne0bohTHE4NfZQL_nEsvWmlc,9106
2
+ vnai/beam/__init__.py,sha256=xKb_iu9aAPXCulI7dENrvqVIhelSD1mIqKE9Go3GAHw,200
3
+ vnai/beam/metrics.py,sha256=Yjht8nMLxm0JaRSVcHUwHyPkfWReIzgD5uuaXAFNjlE,7472
4
+ vnai/beam/pulse.py,sha256=jp1YwjLaMhne2nYhM5PofveDsdrSp2YtewQ2jjE78Is,3470
5
+ vnai/beam/quota.py,sha256=Ob_IoVpDKL6IdxxivkU1Z5x2nvIf-X1DQeQXdCiRUiU,21424
6
+ vnai/flow/__init__.py,sha256=K3OeabzAWGrdPgTAOlDqrJh2y9aQW2pgLZg8tblN3ho,147
7
+ vnai/flow/queue.py,sha256=b9YKUbiXDZRC3fVgEnA77EO0EMXAi8eCoBkHnAUI5Sc,4162
8
+ vnai/flow/relay.py,sha256=XA4dognPrZ7IQbrgckeEjFw80IgBoK7i8LRmd1A4vR8,17058
9
+ vnai/scope/__init__.py,sha256=overJZ_UiEfBRNcSieE1GPU_9X3oS4C5l6JeBaFFVxk,267
10
+ vnai/scope/profile.py,sha256=6LL7Djke9F1HVA9eEExud2jZ5yGUfy9_NYt68nIj2-8,30737
11
+ vnai/scope/promo.py,sha256=-1Rx-SFHXWQqkUs2jUPRB-VsaqcMmAwCANS54rD-7sc,19224
12
+ vnai/scope/state.py,sha256=LlcZNKBy2mcAnD765BO2Tlv3Zzbak2TOEz4RUPMCFZ8,7490
13
+ vnai-2.0.6.dist-info/METADATA,sha256=Qyi8jdrLMptRy09y0Ezm6bfNv2uH8JYuxlmxzOLbrBg,666
14
+ vnai-2.0.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ vnai-2.0.6.dist-info/top_level.txt,sha256=4zI0qZHePCwvgSqXl4420sBcd0VzZn4MEcRsAIFae3k,5
16
+ vnai-2.0.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,16 +0,0 @@
1
- vnai/__init__.py,sha256=ClnS_1T23BjbzejrIW4KTsAVBhXuq9bjDUcRP5AIcPo,9082
2
- vnai/beam/__init__.py,sha256=xKb_iu9aAPXCulI7dENrvqVIhelSD1mIqKE9Go3GAHw,200
3
- vnai/beam/metrics.py,sha256=xVmVw93yhKeWzRZJurmrD9mWur16HyLJl_p1XqMwW_w,7187
4
- vnai/beam/pulse.py,sha256=jp1YwjLaMhne2nYhM5PofveDsdrSp2YtewQ2jjE78Is,3470
5
- vnai/beam/quota.py,sha256=yP5_Z62QJwOoCEgqqWuNkzm1Dar70UiJsu6W27LNqiw,21218
6
- vnai/flow/__init__.py,sha256=K3OeabzAWGrdPgTAOlDqrJh2y9aQW2pgLZg8tblN3ho,147
7
- vnai/flow/queue.py,sha256=b9YKUbiXDZRC3fVgEnA77EO0EMXAi8eCoBkHnAUI5Sc,4162
8
- vnai/flow/relay.py,sha256=RtIPRZ3BlQd-XgTbisJg0iC1HqikAjHGyyo8aTj_fUw,15766
9
- vnai/scope/__init__.py,sha256=overJZ_UiEfBRNcSieE1GPU_9X3oS4C5l6JeBaFFVxk,267
10
- vnai/scope/profile.py,sha256=6LL7Djke9F1HVA9eEExud2jZ5yGUfy9_NYt68nIj2-8,30737
11
- vnai/scope/promo.py,sha256=N4aWZdh92rVNovjCwuUjv-QdhoRwloPAn4Hydx4IcRs,12515
12
- vnai/scope/state.py,sha256=LlcZNKBy2mcAnD765BO2Tlv3Zzbak2TOEz4RUPMCFZ8,7490
13
- vnai-2.0.4.dist-info/METADATA,sha256=rgGwwXBeevv4rjzJ-hLADRkGnPcuTaC3rMnSgd_WMRw,988
14
- vnai-2.0.4.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
15
- vnai-2.0.4.dist-info/top_level.txt,sha256=4zI0qZHePCwvgSqXl4420sBcd0VzZn4MEcRsAIFae3k,5
16
- vnai-2.0.4.dist-info/RECORD,,