vnai 2.0.3__py3-none-any.whl → 2.0.4__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 +55 -81
- vnai/beam/__init__.py +3 -0
- vnai/beam/metrics.py +32 -57
- vnai/beam/pulse.py +21 -36
- vnai/beam/quota.py +109 -137
- vnai/flow/__init__.py +2 -4
- vnai/flow/queue.py +20 -31
- vnai/flow/relay.py +64 -101
- vnai/scope/__init__.py +2 -4
- vnai/scope/profile.py +110 -206
- vnai/scope/promo.py +80 -28
- vnai/scope/state.py +38 -64
- {vnai-2.0.3.dist-info → vnai-2.0.4.dist-info}/METADATA +4 -5
- vnai-2.0.4.dist-info/RECORD +16 -0
- vnai-2.0.3.dist-info/RECORD +0 -16
- {vnai-2.0.3.dist-info → vnai-2.0.4.dist-info}/WHEEL +0 -0
- {vnai-2.0.3.dist-info → vnai-2.0.4.dist-info}/top_level.txt +0 -0
vnai/scope/promo.py
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
"""
|
2
|
+
Promo module for vnai: fetches and presents promotional content periodically or on demand,
|
3
|
+
using logging instead of printing to avoid polluting stdout for AI tools.
|
4
|
+
"""
|
1
5
|
import logging
|
2
6
|
import requests
|
3
7
|
from datetime import datetime
|
@@ -6,18 +10,29 @@ import threading
|
|
6
10
|
import time
|
7
11
|
import urllib.parse
|
8
12
|
|
13
|
+
# Module-level logger setup
|
9
14
|
logger = logging.getLogger(__name__)
|
10
15
|
if not logger.hasHandlers():
|
16
|
+
# Add a simple stream handler that only outputs the message text
|
11
17
|
handler = logging.StreamHandler()
|
12
18
|
handler.setFormatter(logging.Formatter('%(message)s'))
|
13
19
|
logger.addHandler(handler)
|
14
20
|
logger.setLevel(logging.INFO)
|
15
21
|
|
16
22
|
class ContentManager:
|
23
|
+
"""
|
24
|
+
Singleton manager to fetch remote or fallback promotional content and
|
25
|
+
present it in different environments (Jupyter, terminal, other).
|
26
|
+
|
27
|
+
Displays content automatically at randomized intervals via a background thread.
|
28
|
+
"""
|
17
29
|
_instance = None
|
18
30
|
_lock = threading.Lock()
|
19
31
|
|
20
32
|
def __new__(cls):
|
33
|
+
"""
|
34
|
+
Ensure only one instance of ContentManager is created (thread-safe).
|
35
|
+
"""
|
21
36
|
with cls._lock:
|
22
37
|
if cls._instance is None:
|
23
38
|
cls._instance = super(ContentManager, cls).__new__(cls)
|
@@ -25,27 +40,36 @@ class ContentManager:
|
|
25
40
|
return cls._instance
|
26
41
|
|
27
42
|
def _initialize(self):
|
43
|
+
"""
|
44
|
+
Internal initializer: sets up display timing, URLs, and starts the periodic display thread.
|
45
|
+
"""
|
46
|
+
# Timestamp of last content display (epoch seconds)
|
28
47
|
self.last_display = 0
|
48
|
+
# Minimum interval between displays (24 hours)
|
29
49
|
self.display_interval = 24 * 3600
|
30
50
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
self.target_url = (
|
35
|
-
"https://vnstocks.com/lp-khoa-hoc-python-chung-khoan"
|
36
|
-
)
|
51
|
+
# Base endpoints for fetching remote content and linking
|
52
|
+
self.content_base_url = "https://vnstock-beam.hf.space/content-delivery"
|
53
|
+
self.target_url = "https://vnstocks.com/lp-khoa-hoc-python-chung-khoan"
|
37
54
|
self.image_url = (
|
38
55
|
"https://vnstocks.com/img/trang-chu-vnstock-python-api-phan-tich-giao-dich-chung-khoan.jpg"
|
39
56
|
)
|
40
57
|
|
58
|
+
# Launch the background thread to periodically present content
|
41
59
|
self._start_periodic_display()
|
42
60
|
|
43
61
|
def _start_periodic_display(self):
|
62
|
+
"""
|
63
|
+
Launch a daemon thread that sleeps a random duration between 2–6 hours,
|
64
|
+
then checks if the display interval has elapsed and calls present_content.
|
65
|
+
"""
|
44
66
|
def periodic_display():
|
45
67
|
while True:
|
68
|
+
# Randomize sleep to avoid synchronized requests across instances
|
46
69
|
sleep_time = random.randint(2 * 3600, 6 * 3600)
|
47
70
|
time.sleep(sleep_time)
|
48
71
|
|
72
|
+
# Present content if enough time has passed since last_display
|
49
73
|
current_time = time.time()
|
50
74
|
if current_time - self.last_display >= self.display_interval:
|
51
75
|
self.present_content(context="periodic")
|
@@ -53,66 +77,87 @@ class ContentManager:
|
|
53
77
|
thread = threading.Thread(target=periodic_display, daemon=True)
|
54
78
|
thread.start()
|
55
79
|
|
56
|
-
def fetch_remote_content(self, context="init", html=True):
|
80
|
+
def fetch_remote_content(self, context: str = "init", html: bool = True) -> str:
|
81
|
+
"""
|
82
|
+
Fetch promotional content from remote service with context and format flag.
|
83
|
+
|
84
|
+
Args:
|
85
|
+
context: usage context (e.g., "init", "periodic", "loop").
|
86
|
+
html: if True, request HTML; otherwise plain text.
|
87
|
+
|
88
|
+
Returns:
|
89
|
+
The content string on HTTP 200, or None on failure.
|
90
|
+
"""
|
57
91
|
try:
|
92
|
+
# Build query params and URL
|
58
93
|
params = {"context": context, "html": "true" if html else "false"}
|
59
94
|
url = f"{self.content_base_url}?{urllib.parse.urlencode(params)}"
|
60
95
|
|
61
96
|
response = requests.get(url, timeout=3)
|
62
97
|
if response.status_code == 200:
|
63
98
|
return response.text
|
99
|
+
# Log non-200 responses at debug level
|
64
100
|
logger.debug(f"Non-200 response fetching content: {response.status_code}")
|
65
101
|
return None
|
66
102
|
except Exception as e:
|
103
|
+
# Log exceptions without interrupting user code
|
67
104
|
logger.debug(f"Failed to fetch remote content: {e}")
|
68
105
|
return None
|
69
106
|
|
70
|
-
def present_content(self, environment=None, context="init"):
|
107
|
+
def present_content(self, environment: str = None, context: str = "init") -> None:
|
108
|
+
"""
|
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.
|
116
|
+
"""
|
117
|
+
# Update last display timestamp
|
71
118
|
self.last_display = time.time()
|
72
119
|
|
120
|
+
# Auto-detect environment if not provided
|
73
121
|
if environment is None:
|
74
122
|
try:
|
75
123
|
from vnai.scope.profile import inspector
|
76
|
-
|
77
|
-
environment = (
|
78
|
-
inspector.examine().get("environment", "unknown")
|
79
|
-
)
|
124
|
+
environment = inspector.examine().get("environment", "unknown")
|
80
125
|
except Exception:
|
81
126
|
environment = "unknown"
|
82
127
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
context=context, html=False
|
90
|
-
)
|
91
|
-
|
92
|
-
fallback_content = self._generate_fallback_content(context)
|
128
|
+
# Retrieve remote or HTML/text content based on environment
|
129
|
+
remote_content = self.fetch_remote_content(
|
130
|
+
context=context, html=(environment == "jupyter")
|
131
|
+
)
|
132
|
+
# Generate fallback messages if remote fetch fails
|
133
|
+
fallback = self._generate_fallback_content(context)
|
93
134
|
|
94
135
|
if environment == "jupyter":
|
136
|
+
# Rich display in Jupyter notebooks
|
95
137
|
try:
|
96
138
|
from IPython.display import display, HTML, Markdown
|
97
139
|
|
98
140
|
if remote_content:
|
99
141
|
display(HTML(remote_content))
|
100
142
|
else:
|
143
|
+
# Try Markdown, fallback to HTML
|
101
144
|
try:
|
102
|
-
display(Markdown(
|
145
|
+
display(Markdown(fallback["markdown"]))
|
103
146
|
except Exception:
|
104
|
-
display(HTML(
|
147
|
+
display(HTML(fallback["html"]))
|
105
148
|
except Exception as e:
|
106
149
|
logger.debug(f"Jupyter display failed: {e}")
|
107
150
|
|
108
151
|
elif environment == "terminal":
|
152
|
+
# Log terminal-friendly or raw content via logger
|
109
153
|
if remote_content:
|
110
154
|
logger.info(remote_content)
|
111
155
|
else:
|
112
|
-
logger.info(
|
156
|
+
logger.info(fallback["terminal"])
|
113
157
|
|
114
158
|
else:
|
115
|
-
|
159
|
+
# Generic simple message for other environments
|
160
|
+
logger.info(fallback["simple"])
|
116
161
|
|
117
162
|
def _generate_fallback_content(self, context):
|
118
163
|
fallback = {"html": "", "markdown": "", "terminal": "", "simple": ""}
|
@@ -211,8 +256,15 @@ Khám phá các tính năng mới nhất và tham gia cộng đồng để nhậ
|
|
211
256
|
)
|
212
257
|
return fallback
|
213
258
|
|
214
|
-
# Singleton instance
|
259
|
+
# Singleton instance for module-level use
|
215
260
|
manager = ContentManager()
|
216
261
|
|
217
|
-
|
262
|
+
|
263
|
+
def present(context: str = "init") -> None:
|
264
|
+
"""
|
265
|
+
Shortcut to ContentManager.present_content for external callers.
|
266
|
+
|
267
|
+
Args:
|
268
|
+
context: propagate context string to ContentManager.
|
269
|
+
"""
|
218
270
|
return manager.present_content(context=context)
|
vnai/scope/state.py
CHANGED
@@ -1,7 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
##
|
4
|
-
|
1
|
+
# vnai/scope/state.py
|
2
|
+
# System state tracking
|
5
3
|
|
6
4
|
import time
|
7
5
|
import threading
|
@@ -11,7 +9,7 @@ from datetime import datetime
|
|
11
9
|
from pathlib import Path
|
12
10
|
|
13
11
|
class Tracker:
|
14
|
-
|
12
|
+
"""Tracks system state and performance metrics"""
|
15
13
|
|
16
14
|
_instance = None
|
17
15
|
_lock = threading.Lock()
|
@@ -24,7 +22,7 @@ class Tracker:
|
|
24
22
|
return cls._instance
|
25
23
|
|
26
24
|
def _initialize(self):
|
27
|
-
|
25
|
+
"""Initialize tracker"""
|
28
26
|
self.metrics = {
|
29
27
|
"startup_time": datetime.now().isoformat(),
|
30
28
|
"function_calls": 0,
|
@@ -41,8 +39,7 @@ class Tracker:
|
|
41
39
|
|
42
40
|
self.privacy_level = "standard"
|
43
41
|
|
44
|
-
|
45
|
-
|
42
|
+
# Setup data directory
|
46
43
|
self.home_dir = Path.home()
|
47
44
|
self.project_dir = self.home_dir / ".vnstock"
|
48
45
|
self.project_dir.mkdir(exist_ok=True)
|
@@ -51,31 +48,26 @@ class Tracker:
|
|
51
48
|
self.metrics_path = self.data_dir / "usage_metrics.json"
|
52
49
|
self.privacy_config_path = self.project_dir / 'config' / "privacy.json"
|
53
50
|
|
54
|
-
|
55
|
-
|
51
|
+
# Create config directory if it doesn't exist
|
56
52
|
os.makedirs(os.path.dirname(self.privacy_config_path), exist_ok=True)
|
57
53
|
|
58
|
-
|
59
|
-
|
54
|
+
# Load existing metrics
|
60
55
|
self._load_metrics()
|
61
56
|
|
62
|
-
|
63
|
-
|
57
|
+
# Load privacy settings
|
64
58
|
self._load_privacy_settings()
|
65
59
|
|
66
|
-
|
67
|
-
|
60
|
+
# Start background metrics collector
|
68
61
|
self._start_background_collector()
|
69
62
|
|
70
63
|
def _load_metrics(self):
|
71
|
-
|
64
|
+
"""Load metrics from file"""
|
72
65
|
if self.metrics_path.exists():
|
73
66
|
try:
|
74
67
|
with open(self.metrics_path, 'r') as f:
|
75
68
|
stored_metrics = json.load(f)
|
76
69
|
|
77
|
-
|
78
|
-
|
70
|
+
# Update metrics with stored values
|
79
71
|
for key, value in stored_metrics.items():
|
80
72
|
if key in self.metrics:
|
81
73
|
self.metrics[key] = value
|
@@ -83,7 +75,7 @@ class Tracker:
|
|
83
75
|
pass
|
84
76
|
|
85
77
|
def _save_metrics(self):
|
86
|
-
|
78
|
+
"""Save metrics to file"""
|
87
79
|
try:
|
88
80
|
with open(self.metrics_path, 'w') as f:
|
89
81
|
json.dump(self.metrics, f)
|
@@ -91,7 +83,7 @@ class Tracker:
|
|
91
83
|
pass
|
92
84
|
|
93
85
|
def _load_privacy_settings(self):
|
94
|
-
|
86
|
+
"""Load privacy settings"""
|
95
87
|
if self.privacy_config_path.exists():
|
96
88
|
try:
|
97
89
|
with open(self.privacy_config_path, 'r') as f:
|
@@ -101,7 +93,7 @@ class Tracker:
|
|
101
93
|
pass
|
102
94
|
|
103
95
|
def setup_privacy(self, level=None):
|
104
|
-
|
96
|
+
"""Configure privacy level for data collection"""
|
105
97
|
privacy_levels = {
|
106
98
|
"minimal": "Essential system data only",
|
107
99
|
"standard": "Performance metrics and errors",
|
@@ -109,107 +101,90 @@ class Tracker:
|
|
109
101
|
}
|
110
102
|
|
111
103
|
if level is None:
|
112
|
-
|
113
|
-
|
104
|
+
# Default level
|
114
105
|
level = "standard"
|
115
106
|
|
116
107
|
if level not in privacy_levels:
|
117
108
|
raise ValueError(f"Invalid privacy level: {level}. Choose from {', '.join(privacy_levels.keys())}")
|
118
109
|
|
119
|
-
|
120
|
-
|
110
|
+
# Store preference
|
121
111
|
self.privacy_level = level
|
122
112
|
|
123
|
-
|
124
|
-
|
113
|
+
# Store in configuration file
|
125
114
|
with open(self.privacy_config_path, "w") as f:
|
126
115
|
json.dump({"level": level}, f)
|
127
116
|
|
128
117
|
return level
|
129
118
|
|
130
119
|
def get_privacy_level(self):
|
131
|
-
|
120
|
+
"""Get current privacy level"""
|
132
121
|
return self.privacy_level
|
133
122
|
|
134
123
|
def _start_background_collector(self):
|
135
|
-
|
124
|
+
"""Start background metrics collection"""
|
136
125
|
def collect_metrics():
|
137
126
|
while True:
|
138
127
|
try:
|
139
128
|
import psutil
|
140
129
|
|
141
|
-
|
142
|
-
|
130
|
+
# Update peak memory
|
143
131
|
current_process = psutil.Process()
|
144
132
|
memory_info = current_process.memory_info()
|
145
|
-
memory_usage = memory_info.rss / (1024 * 1024)
|
146
|
-
|
133
|
+
memory_usage = memory_info.rss / (1024 * 1024) # MB
|
147
134
|
|
148
135
|
if memory_usage > self.performance_metrics["peak_memory"]:
|
149
136
|
self.performance_metrics["peak_memory"] = memory_usage
|
150
137
|
|
151
|
-
|
152
|
-
|
138
|
+
# Save metrics periodically
|
153
139
|
self._save_metrics()
|
154
140
|
|
155
141
|
except:
|
156
142
|
pass
|
157
143
|
|
158
|
-
time.sleep(300)
|
159
|
-
|
144
|
+
time.sleep(300) # Run every 5 minutes
|
160
145
|
|
161
|
-
|
162
|
-
|
146
|
+
# Start thread
|
163
147
|
thread = threading.Thread(target=collect_metrics, daemon=True)
|
164
148
|
thread.start()
|
165
149
|
|
166
150
|
def record(self, event_type, data=None):
|
167
|
-
|
168
|
-
|
169
|
-
|
151
|
+
"""Record an event"""
|
152
|
+
# Check privacy level
|
170
153
|
if self.privacy_level == "minimal" and event_type != "errors":
|
171
|
-
|
172
|
-
|
154
|
+
# In minimal mode, only track errors
|
173
155
|
return True
|
174
156
|
|
175
|
-
|
176
|
-
|
157
|
+
# Update counts
|
177
158
|
if event_type in self.metrics:
|
178
159
|
self.metrics[event_type] += 1
|
179
160
|
else:
|
180
161
|
self.metrics[event_type] = 1
|
181
162
|
|
182
|
-
|
183
|
-
|
163
|
+
# Special handling for errors
|
184
164
|
if event_type == "errors":
|
185
165
|
self.performance_metrics["last_error_time"] = datetime.now().isoformat()
|
186
166
|
|
187
|
-
|
188
|
-
|
167
|
+
# Special handling for function calls with timing data
|
189
168
|
if event_type == "function_calls" and data and "execution_time" in data:
|
190
|
-
|
191
|
-
|
169
|
+
# Keep up to 100 latest execution times
|
192
170
|
self.performance_metrics["execution_times"].append(data["execution_time"])
|
193
171
|
if len(self.performance_metrics["execution_times"]) > 100:
|
194
172
|
self.performance_metrics["execution_times"] = self.performance_metrics["execution_times"][-100:]
|
195
173
|
|
196
|
-
|
197
|
-
|
174
|
+
# Save if metrics change significantly
|
198
175
|
if self.metrics["function_calls"] % 100 == 0 or event_type == "errors":
|
199
176
|
self._save_metrics()
|
200
177
|
|
201
178
|
return True
|
202
179
|
|
203
180
|
def get_metrics(self):
|
204
|
-
|
205
|
-
|
206
|
-
|
181
|
+
"""Get current metrics"""
|
182
|
+
# Calculate derived metrics
|
207
183
|
avg_execution_time = 0
|
208
184
|
if self.performance_metrics["execution_times"]:
|
209
185
|
avg_execution_time = sum(self.performance_metrics["execution_times"]) / len(self.performance_metrics["execution_times"])
|
210
186
|
|
211
|
-
|
212
|
-
|
187
|
+
# Add derived metrics to output
|
213
188
|
output = self.metrics.copy()
|
214
189
|
output.update({
|
215
190
|
"avg_execution_time": avg_execution_time,
|
@@ -221,7 +196,7 @@ class Tracker:
|
|
221
196
|
return output
|
222
197
|
|
223
198
|
def reset(self):
|
224
|
-
|
199
|
+
"""Reset metrics"""
|
225
200
|
self.metrics = {
|
226
201
|
"startup_time": datetime.now().isoformat(),
|
227
202
|
"function_calls": 0,
|
@@ -239,11 +214,10 @@ class Tracker:
|
|
239
214
|
self._save_metrics()
|
240
215
|
return True
|
241
216
|
|
242
|
-
|
243
|
-
|
217
|
+
# Create singleton instance
|
244
218
|
tracker = Tracker()
|
245
219
|
|
246
220
|
|
247
221
|
def record(event_type, data=None):
|
248
|
-
|
222
|
+
"""Record an event"""
|
249
223
|
return tracker.record(event_type, data)
|
@@ -1,10 +1,10 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: vnai
|
3
|
-
Version: 2.0.
|
3
|
+
Version: 2.0.4
|
4
4
|
Summary: System optimization and resource management toolkit
|
5
|
-
Home-page: https://github.com/
|
6
|
-
Author:
|
7
|
-
Author-email:
|
5
|
+
Home-page: https://github.com/vnstock-hq/initialization/new/main
|
6
|
+
Author: Vnstock HQ
|
7
|
+
Author-email: support@vnstocks.com
|
8
8
|
License: MIT
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
10
10
|
Classifier: Operating System :: OS Independent
|
@@ -17,7 +17,6 @@ Requires-Dist: requests>=2.25.0
|
|
17
17
|
Requires-Dist: psutil>=5.8.0
|
18
18
|
Provides-Extra: dev
|
19
19
|
Requires-Dist: pytest>=6.0.0; extra == "dev"
|
20
|
-
Requires-Dist: black>=21.5b2; extra == "dev"
|
21
20
|
Dynamic: author
|
22
21
|
Dynamic: author-email
|
23
22
|
Dynamic: classifier
|
@@ -0,0 +1,16 @@
|
|
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,,
|
vnai-2.0.3.dist-info/RECORD
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
vnai/__init__.py,sha256=SF3HcEadrvSmtotBCy8a6637UwTFiSAaAN0Azi0X4qg,7219
|
2
|
-
vnai/beam/__init__.py,sha256=h19ZEQFnWTvqed0mpTcuQf-sT9XifWhfVbaobTEs91Q,131
|
3
|
-
vnai/beam/metrics.py,sha256=lNYEeav5kMm8SGnlsxwz6aD3fRzOytopHhUPkUx9Avs,5950
|
4
|
-
vnai/beam/pulse.py,sha256=-rN4tbcgNKmA74P2ThVkQqxabG0-UlhfRbFCyYPvKFw,2920
|
5
|
-
vnai/beam/quota.py,sha256=DRlqZpztppdFDJymuJS6VCKLHZrkI_PX8cUtStHDSFM,16934
|
6
|
-
vnai/flow/__init__.py,sha256=VW6R7c30M4q8PhOUqXyHwWlmk1BwPrYvcxtLFI0fWJo,91
|
7
|
-
vnai/flow/queue.py,sha256=0R6LjF6PSUz37JV2SnsOQMBHps3bG5c0BGfEOUIPhcA,3650
|
8
|
-
vnai/flow/relay.py,sha256=wIRojuZKQ5Jk1N-p2PkA9fkx-F7kwgVu0JIc0Iya5aw,13783
|
9
|
-
vnai/scope/__init__.py,sha256=yB0qWMlKd2ix5tFlBcRPX6SYR1O8Di0mwgQC15u8l2o,207
|
10
|
-
vnai/scope/profile.py,sha256=tIy39_FpcNKZCg3Dy5mgy0jdLQCH2FK2nfvUlTM72wM,26781
|
11
|
-
vnai/scope/promo.py,sha256=NlKcyadl6BlOr2TMlKkdri4dkm8xIoI_3Z05ErcVnGo,9930
|
12
|
-
vnai/scope/state.py,sha256=XUhuXNx1W6pce5vRY3IkSrR__MGetRo8lQt1bQIAOLM,6550
|
13
|
-
vnai-2.0.3.dist-info/METADATA,sha256=IlnWkYA8m9Rxjyfu7JCgpwJw0C7ldherJqhQnAdRrug,1017
|
14
|
-
vnai-2.0.3.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
|
15
|
-
vnai-2.0.3.dist-info/top_level.txt,sha256=4zI0qZHePCwvgSqXl4420sBcd0VzZn4MEcRsAIFae3k,5
|
16
|
-
vnai-2.0.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|