vnai 2.0.7__py3-none-any.whl → 2.0.9__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/beam/quota.py CHANGED
@@ -1,487 +1,105 @@
1
- # vnai/beam/quota.py
2
- # Resource allocation and management (formerly rate_limiter)
3
-
4
- import time
5
- import functools
6
- import threading
1
+ _G='resource_type'
2
+ _F=False
3
+ _E=True
4
+ _D=None
5
+ _C='default'
6
+ _B='hour'
7
+ _A='min'
8
+ import time,functools,threading
7
9
  from collections import defaultdict
8
10
  from datetime import datetime
9
-
10
11
  class RateLimitExceeded(Exception):
11
- """Custom exception for rate limit violations."""
12
- def __init__(self, resource_type, limit_type="min", current_usage=None, limit_value=None, retry_after=None):
13
- self.resource_type = resource_type
14
- self.limit_type = limit_type
15
- self.current_usage = current_usage
16
- self.limit_value = limit_value
17
- self.retry_after = retry_after
18
-
19
- # Create a user-friendly message
20
- message = f"Bạn đã gửi quá nhiều request tới {resource_type}. "
21
- if retry_after:
22
- message += f"Vui lòng thử lại sau {round(retry_after)} giây."
23
- else:
24
- message += "Vui lòng thêm thời gian chờ giữa các lần gửi request."
25
-
26
- super().__init__(message)
27
-
12
+ def __init__(self,resource_type,limit_type=_A,current_usage=_D,limit_value=_D,retry_after=_D):
13
+ self.resource_type=resource_type;self.limit_type=limit_type;self.current_usage=current_usage;self.limit_value=limit_value;self.retry_after=retry_after;message=f"Bạn đã gửi quá nhiều request tới {resource_type}. "
14
+ if retry_after:message+=f"Vui lòng thử lại sau {round(retry_after)} giây."
15
+ else:message+='Vui lòng thêm thời gian chờ giữa các lần gửi request.'
16
+ super().__init__(message)
28
17
  class Guardian:
29
- """Ensures optimal resource allocation"""
30
-
31
- _instance = None
32
- _lock = threading.Lock()
33
-
34
- def __new__(cls):
35
- with cls._lock:
36
- if cls._instance is None:
37
- cls._instance = super(Guardian, cls).__new__(cls)
38
- cls._instance._initialize()
39
- return cls._instance
40
-
41
- def _initialize(self):
42
- """Initialize guardian"""
43
- self.resource_limits = defaultdict(lambda: defaultdict(int))
44
- self.usage_counters = defaultdict(lambda: defaultdict(list))
45
-
46
- # Define resource limits
47
- self.resource_limits["default"] = {"min": 60, "hour": 3000}
48
- self.resource_limits["TCBS"] = {"min": 60, "hour": 3000}
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}
52
- self.resource_limits["VCI.ext"] = {"min": 600, "hour": 36000}
53
- self.resource_limits["FMK.ext"] = {"min": 600, "hour": 36000}
54
- self.resource_limits["VND.ext"] = {"min": 600, "hour": 36000}
55
- self.resource_limits["CAF.ext"] = {"min": 600, "hour": 36000}
56
- self.resource_limits["SPL.ext"] = {"min": 600, "hour": 36000}
57
- self.resource_limits["VDS.ext"] = {"min": 600, "hour": 36000}
58
- self.resource_limits["FAD.ext"] = {"min": 600, "hour": 36000}
59
-
60
- def verify(self, operation_id, resource_type="default"):
61
- """Verify resource availability before operation"""
62
- current_time = time.time()
63
-
64
- # Get limits for this resource type (or use default)
65
- limits = self.resource_limits.get(resource_type, self.resource_limits["default"])
66
-
67
- # Check minute limit
68
- minute_cutoff = current_time - 60
69
- self.usage_counters[resource_type]["min"] = [
70
- t for t in self.usage_counters[resource_type]["min"]
71
- if t > minute_cutoff
72
- ]
73
-
74
- minute_usage = len(self.usage_counters[resource_type]["min"])
75
- minute_exceeded = minute_usage >= limits["min"]
76
-
77
- if minute_exceeded:
78
- # Track limit check through metrics module
79
- from vnai.beam.metrics import collector
80
- collector.record(
81
- "rate_limit",
82
- {
83
- "resource_type": resource_type,
84
- "limit_type": "min",
85
- "limit_value": limits["min"],
86
- "current_usage": minute_usage,
87
- "is_exceeded": True
88
- },
89
- priority="high"
90
- )
91
- # Raise custom exception with retry information
92
- raise RateLimitExceeded(
93
- resource_type=resource_type,
94
- limit_type="min",
95
- current_usage=minute_usage,
96
- limit_value=limits["min"],
97
- retry_after=60 - (current_time % 60) # Seconds until the minute rolls over
98
- )
99
-
100
- # Check hour limit
101
- hour_cutoff = current_time - 3600
102
- self.usage_counters[resource_type]["hour"] = [
103
- t for t in self.usage_counters[resource_type]["hour"]
104
- if t > hour_cutoff
105
- ]
106
-
107
- hour_usage = len(self.usage_counters[resource_type]["hour"])
108
- hour_exceeded = hour_usage >= limits["hour"]
109
-
110
- # Track rate limit check
111
- from vnai.beam.metrics import collector
112
- collector.record(
113
- "rate_limit",
114
- {
115
- "resource_type": resource_type,
116
- "limit_type": "hour" if hour_exceeded else "min",
117
- "limit_value": limits["hour"] if hour_exceeded else limits["min"],
118
- "current_usage": hour_usage if hour_exceeded else minute_usage,
119
- "is_exceeded": hour_exceeded
120
- }
121
- )
122
-
123
- if hour_exceeded:
124
- # Raise custom exception with retry information
125
- raise RateLimitExceeded(
126
- resource_type=resource_type,
127
- limit_type="hour",
128
- current_usage=hour_usage,
129
- limit_value=limits["hour"],
130
- retry_after=3600 - (current_time % 3600) # Seconds until the hour rolls over
131
- )
132
-
133
- # Record this request
134
- self.usage_counters[resource_type]["min"].append(current_time)
135
- self.usage_counters[resource_type]["hour"].append(current_time)
136
- return True
137
-
138
- def usage(self, resource_type="default"):
139
- """Get current usage percentage for resource limits"""
140
- current_time = time.time()
141
- limits = self.resource_limits.get(resource_type, self.resource_limits["default"])
142
-
143
- # Clean old timestamps
144
- minute_cutoff = current_time - 60
145
- hour_cutoff = current_time - 3600
146
-
147
- self.usage_counters[resource_type]["min"] = [
148
- t for t in self.usage_counters[resource_type]["min"]
149
- if t > minute_cutoff
150
- ]
151
-
152
- self.usage_counters[resource_type]["hour"] = [
153
- t for t in self.usage_counters[resource_type]["hour"]
154
- if t > hour_cutoff
155
- ]
156
-
157
- # Calculate percentages
158
- minute_usage = len(self.usage_counters[resource_type]["min"])
159
- hour_usage = len(self.usage_counters[resource_type]["hour"])
160
-
161
- minute_percentage = (minute_usage / limits["min"]) * 100 if limits["min"] > 0 else 0
162
- hour_percentage = (hour_usage / limits["hour"]) * 100 if limits["hour"] > 0 else 0
163
-
164
- # Return the higher percentage
165
- return max(minute_percentage, hour_percentage)
166
-
167
- def get_limit_status(self, resource_type="default"):
168
- """Get detailed information about current limit status"""
169
- current_time = time.time()
170
- limits = self.resource_limits.get(resource_type, self.resource_limits["default"])
171
-
172
- # Clean old timestamps
173
- minute_cutoff = current_time - 60
174
- hour_cutoff = current_time - 3600
175
-
176
- minute_usage = len([t for t in self.usage_counters[resource_type]["min"] if t > minute_cutoff])
177
- hour_usage = len([t for t in self.usage_counters[resource_type]["hour"] if t > hour_cutoff])
178
-
179
- return {
180
- "resource_type": resource_type,
181
- "minute_limit": {
182
- "usage": minute_usage,
183
- "limit": limits["min"],
184
- "percentage": (minute_usage / limits["min"]) * 100 if limits["min"] > 0 else 0,
185
- "remaining": max(0, limits["min"] - minute_usage),
186
- "reset_in_seconds": 60 - (current_time % 60)
187
- },
188
- "hour_limit": {
189
- "usage": hour_usage,
190
- "limit": limits["hour"],
191
- "percentage": (hour_usage / limits["hour"]) * 100 if limits["hour"] > 0 else 0,
192
- "remaining": max(0, limits["hour"] - hour_usage),
193
- "reset_in_seconds": 3600 - (current_time % 3600)
194
- }
195
- }
196
-
197
- # Create singleton instance
198
- guardian = Guardian()
199
-
18
+ _instance=_D;_lock=threading.Lock()
19
+ def __new__(cls):
20
+ with cls._lock:
21
+ if cls._instance is _D:cls._instance=super(Guardian,cls).__new__(cls);cls._instance._initialize()
22
+ return cls._instance
23
+ def _initialize(self):self.resource_limits=defaultdict(lambda:defaultdict(int));self.usage_counters=defaultdict(lambda:defaultdict(list));self.resource_limits[_C]={_A:60,_B:3000};self.resource_limits['TCBS']={_A:60,_B:3000};self.resource_limits['VCI']={_A:60,_B:3000};self.resource_limits['MBK']={_A:600,_B:36000};self.resource_limits['MAS.ext']={_A:600,_B:36000};self.resource_limits['VCI.ext']={_A:600,_B:36000};self.resource_limits['FMK.ext']={_A:600,_B:36000};self.resource_limits['VND.ext']={_A:600,_B:36000};self.resource_limits['CAF.ext']={_A:600,_B:36000};self.resource_limits['SPL.ext']={_A:600,_B:36000};self.resource_limits['VDS.ext']={_A:600,_B:36000};self.resource_limits['FAD.ext']={_A:600,_B:36000}
24
+ def verify(self,operation_id,resource_type=_C):
25
+ E='is_exceeded';D='current_usage';C='limit_value';B='limit_type';A='rate_limit';current_time=time.time();limits=self.resource_limits.get(resource_type,self.resource_limits[_C]);minute_cutoff=current_time-60;self.usage_counters[resource_type][_A]=[t for t in self.usage_counters[resource_type][_A]if t>minute_cutoff];minute_usage=len(self.usage_counters[resource_type][_A]);minute_exceeded=minute_usage>=limits[_A]
26
+ if minute_exceeded:from vnai.beam.metrics import collector;collector.record(A,{_G:resource_type,B:_A,C:limits[_A],D:minute_usage,E:_E},priority='high');raise RateLimitExceeded(resource_type=resource_type,limit_type=_A,current_usage=minute_usage,limit_value=limits[_A],retry_after=60-current_time%60)
27
+ hour_cutoff=current_time-3600;self.usage_counters[resource_type][_B]=[t for t in self.usage_counters[resource_type][_B]if t>hour_cutoff];hour_usage=len(self.usage_counters[resource_type][_B]);hour_exceeded=hour_usage>=limits[_B];from vnai.beam.metrics import collector;collector.record(A,{_G:resource_type,B:_B if hour_exceeded else _A,C:limits[_B]if hour_exceeded else limits[_A],D:hour_usage if hour_exceeded else minute_usage,E:hour_exceeded})
28
+ if hour_exceeded:raise RateLimitExceeded(resource_type=resource_type,limit_type=_B,current_usage=hour_usage,limit_value=limits[_B],retry_after=3600-current_time%3600)
29
+ self.usage_counters[resource_type][_A].append(current_time);self.usage_counters[resource_type][_B].append(current_time);return _E
30
+ def usage(self,resource_type=_C):current_time=time.time();limits=self.resource_limits.get(resource_type,self.resource_limits[_C]);minute_cutoff=current_time-60;hour_cutoff=current_time-3600;self.usage_counters[resource_type][_A]=[t for t in self.usage_counters[resource_type][_A]if t>minute_cutoff];self.usage_counters[resource_type][_B]=[t for t in self.usage_counters[resource_type][_B]if t>hour_cutoff];minute_usage=len(self.usage_counters[resource_type][_A]);hour_usage=len(self.usage_counters[resource_type][_B]);minute_percentage=minute_usage/limits[_A]*100 if limits[_A]>0 else 0;hour_percentage=hour_usage/limits[_B]*100 if limits[_B]>0 else 0;return max(minute_percentage,hour_percentage)
31
+ def get_limit_status(self,resource_type=_C):E='reset_in_seconds';D='remaining';C='percentage';B='limit';A='usage';current_time=time.time();limits=self.resource_limits.get(resource_type,self.resource_limits[_C]);minute_cutoff=current_time-60;hour_cutoff=current_time-3600;minute_usage=len([t for t in self.usage_counters[resource_type][_A]if t>minute_cutoff]);hour_usage=len([t for t in self.usage_counters[resource_type][_B]if t>hour_cutoff]);return{_G:resource_type,'minute_limit':{A:minute_usage,B:limits[_A],C:minute_usage/limits[_A]*100 if limits[_A]>0 else 0,D:max(0,limits[_A]-minute_usage),E:60-current_time%60},'hour_limit':{A:hour_usage,B:limits[_B],C:hour_usage/limits[_B]*100 if limits[_B]>0 else 0,D:max(0,limits[_B]-hour_usage),E:3600-current_time%3600}}
32
+ guardian=Guardian()
200
33
  class CleanErrorContext:
201
- """Context manager to clean up tracebacks for rate limits"""
202
- # Class variable to track if a message has been displayed recently
203
- _last_message_time = 0
204
- _message_cooldown = 5 # Only show a message every 5 seconds
205
-
206
- def __enter__(self):
207
- return self
208
-
209
- def __exit__(self, exc_type, exc_val, exc_tb):
210
- if exc_type is RateLimitExceeded:
211
- current_time = time.time()
212
-
213
- # Only print the message if enough time has passed since the last one
214
- if current_time - CleanErrorContext._last_message_time >= CleanErrorContext._message_cooldown:
215
- print(f"\n⚠️ {str(exc_val)}\n")
216
- CleanErrorContext._last_message_time = current_time
217
-
218
- # Re-raise the exception more forcefully to ensure it propagates
219
- # This will bypass any try/except blocks that might be catching RateLimitExceeded
220
- import sys
221
- sys.exit(f"Rate limit exceeded. {str(exc_val)} Process terminated.")
222
-
223
- # The line below won't be reached, but we keep it for clarity
224
- return False
225
- return False
226
-
227
-
228
- def optimize(resource_type='default', loop_threshold=10, time_window=5, ad_cooldown=150, content_trigger_threshold=3,
229
- max_retries=2, backoff_factor=2, debug=False):
230
- """
231
- Decorator that optimizes function execution, tracks metrics, and detects loop patterns for ad opportunities.
232
-
233
- Features:
234
- - Resource verification
235
- - Performance metrics collection
236
- - Loop detection for ad/content opportunities
237
- - Automatic retry with exponential backoff for rate limit errors
238
-
239
- Args:
240
- resource_type: Type of resource used by function ("network", "database", "cpu", "memory", "io", "default")
241
- loop_threshold: Number of calls within time_window to consider as a loop (min: 2)
242
- time_window: Time period in seconds to consider for loop detection
243
- ad_cooldown: Minimum seconds between showing ads for the same function
244
- content_trigger_threshold: Number of consecutive loop detections before triggering content (min: 1)
245
- max_retries: Maximum number of times to retry when rate limits are hit
246
- backoff_factor: Base factor for exponential backoff (wait time = backoff_factor^retry_count)
247
- debug: When True, prints diagnostic information about loop detection
248
-
249
- Examples:
250
- @optimize
251
- def simple_function():
252
- return "result"
253
-
254
- @optimize("network")
255
- def fetch_stock_data(symbol):
256
- # Makes network calls
257
- return data
258
-
259
- @optimize("database", loop_threshold=4, time_window=10)
260
- def query_financial_data(params):
261
- # Database queries
262
- return results
263
- """
264
- # Handle case where decorator is used without arguments: @optimize
265
- if callable(resource_type):
266
- func = resource_type
267
- return _create_wrapper(func, 'default', loop_threshold, time_window, ad_cooldown, content_trigger_threshold,
268
- max_retries, backoff_factor, debug)
269
-
270
- # Basic validation
271
- if loop_threshold < 2:
272
- raise ValueError(f"loop_threshold must be at least 2, got {loop_threshold}")
273
- if time_window <= 0:
274
- raise ValueError(f"time_window must be positive, got {time_window}")
275
- if content_trigger_threshold < 1:
276
- raise ValueError(f"content_trigger_threshold must be at least 1, got {content_trigger_threshold}")
277
- if max_retries < 0:
278
- raise ValueError(f"max_retries must be non-negative, got {max_retries}")
279
- if backoff_factor <= 0:
280
- raise ValueError(f"backoff_factor must be positive, got {backoff_factor}")
281
-
282
- # Return the actual decorator
283
- def decorator(func):
284
- return _create_wrapper(func, resource_type, loop_threshold, time_window, ad_cooldown, content_trigger_threshold,
285
- max_retries, backoff_factor, debug)
286
- return decorator
287
-
288
- def _create_wrapper(func, resource_type, loop_threshold, time_window, ad_cooldown, content_trigger_threshold,
289
- max_retries, backoff_factor, debug):
290
- """Creates the function wrapper with call tracking for loop detection"""
291
- # Static storage for each decorated function instance
292
- call_history = []
293
- last_ad_time = 0
294
- consecutive_loop_detections = 0
295
- session_displayed = False # Track if we've displayed an ad in this session
296
- session_start_time = time.time()
297
- session_timeout = 1800 # 30 minutes for session expiration
298
-
299
- @functools.wraps(func)
300
- def wrapper(*args, **kwargs):
301
- nonlocal last_ad_time, consecutive_loop_detections, session_displayed, session_start_time
302
- current_time = time.time()
303
- content_triggered = False
304
-
305
- # Reset session if it has expired
306
- if current_time - session_start_time > session_timeout:
307
- session_displayed = False
308
- session_start_time = current_time
309
-
310
- # For automatic retries with rate limits
311
- retries = 0
312
- while True:
313
- # ===== LOOP DETECTION LOGIC =====
314
- # Add current call to history
315
- call_history.append(current_time)
316
-
317
- # Prune old calls outside the time window
318
- while call_history and current_time - call_history[0] > time_window:
319
- call_history.pop(0)
320
-
321
- # Check if we're in a loop pattern
322
- loop_detected = len(call_history) >= loop_threshold
323
-
324
- if debug and loop_detected:
325
- print(f"[OPTIMIZE] Đã phát hiện vòng lặp cho {func.__name__}: {len(call_history)} lần gọi trong {time_window}s")
326
-
327
- # Handle loop detection
328
- if loop_detected:
329
- consecutive_loop_detections += 1
330
- if debug:
331
- print(f"[OPTIMIZE] Số lần phát hiện vòng lặp liên tiếp: {consecutive_loop_detections}/{content_trigger_threshold}")
332
- else:
333
- consecutive_loop_detections = 0
334
-
335
- # Determine if we should show content - add session_displayed check
336
- should_show_content = (consecutive_loop_detections >= content_trigger_threshold) and \
337
- (current_time - last_ad_time >= ad_cooldown) and \
338
- not session_displayed
339
-
340
- # Handle content opportunity
341
- if should_show_content:
342
- last_ad_time = current_time
343
- consecutive_loop_detections = 0
344
- content_triggered = True
345
- session_displayed = True # Mark that we've displayed in this session
346
-
347
- if debug:
348
- print(f"[OPTIMIZE] Đã kích hoạt nội dung cho {func.__name__}")
349
-
350
- # Trigger content display using promo manager with "loop" context
351
- try:
352
- from vnai.scope.promo import manager
353
-
354
- # Get environment if available
355
- try:
356
- from vnai.scope.profile import inspector
357
- environment = inspector.examine().get("environment", None)
358
- manager.present_content(environment=environment, context="loop")
359
- except ImportError:
360
- manager.present_content(context="loop")
361
-
362
- except ImportError:
363
- # Fallback if content manager is not available
364
- print(f"Phát hiện vòng lặp: Hàm '{func.__name__}' đang được gọi trong một vòng lặp")
365
- except Exception as e:
366
- # Don't let content errors affect the main function
367
- if debug:
368
- print(f"[OPTIMIZE] Lỗi khi hiển thị nội dung: {str(e)}")
369
-
370
- # ===== RESOURCE VERIFICATION =====
371
- try:
372
- # Use a context manager to clean up the traceback
373
- with CleanErrorContext():
374
- guardian.verify(func.__name__, resource_type)
375
-
376
- except RateLimitExceeded as e:
377
- # Record the rate limit error
378
- from vnai.beam.metrics import collector
379
- collector.record(
380
- "error",
381
- {
382
- "function": func.__name__,
383
- "error": str(e),
384
- "context": "resource_verification",
385
- "resource_type": resource_type,
386
- "retry_attempt": retries
387
- },
388
- priority="high"
389
- )
390
-
391
- # Display rate limit content ONLY if we haven't shown any content this session
392
- if not session_displayed:
393
- try:
394
- from vnai.scope.promo import manager
395
- try:
396
- from vnai.scope.profile import inspector
397
- environment = inspector.examine().get("environment", None)
398
- manager.present_content(environment=environment, context="loop")
399
- session_displayed = True # Mark that we've displayed
400
- last_ad_time = current_time
401
- except ImportError:
402
- manager.present_content(context="loop")
403
- session_displayed = True
404
- last_ad_time = current_time
405
- except Exception:
406
- pass # Don't let content errors affect the retry logic
407
-
408
- # Continue with retry logic
409
- if retries < max_retries:
410
- wait_time = backoff_factor ** retries
411
- retries += 1
412
-
413
- # If the exception has a retry_after value, use that instead
414
- if hasattr(e, "retry_after") and e.retry_after:
415
- wait_time = min(wait_time, e.retry_after)
416
-
417
- if debug:
418
- print(f"[OPTIMIZE] Đã đạt giới hạn tốc độ cho {func.__name__}, thử lại sau {wait_time} giây (lần thử {retries}/{max_retries})")
419
-
420
- time.sleep(wait_time)
421
- continue # Retry the call
422
- else:
423
- # No more retries, re-raise the exception
424
- raise
425
-
426
- # ===== FUNCTION EXECUTION & METRICS =====
427
- start_time = time.time()
428
- success = False
429
- error = None
430
-
431
- try:
432
- # Execute the original function
433
- result = func(*args, **kwargs)
434
- success = True
435
- return result
436
- except Exception as e:
437
- error = str(e)
438
- raise
439
- finally:
440
- # Calculate execution metrics
441
- execution_time = time.time() - start_time
442
-
443
- # Record metrics
444
- try:
445
- from vnai.beam.metrics import collector
446
- collector.record(
447
- "function",
448
- {
449
- "function": func.__name__,
450
- "resource_type": resource_type,
451
- "execution_time": execution_time,
452
- "success": success,
453
- "error": error,
454
- "in_loop": loop_detected,
455
- "loop_depth": len(call_history),
456
- "content_triggered": content_triggered,
457
- "timestamp": datetime.now().isoformat(),
458
- "retry_count": retries if retries > 0 else None
459
- }
460
- )
461
-
462
- # Record content opportunity metrics if detected
463
- if content_triggered:
464
- collector.record(
465
- "ad_opportunity",
466
- {
467
- "function": func.__name__,
468
- "resource_type": resource_type,
469
- "call_frequency": len(call_history) / time_window,
470
- "consecutive_loops": consecutive_loop_detections,
471
- "timestamp": datetime.now().isoformat()
472
- }
473
- )
474
- except ImportError:
475
- # Metrics module not available, just continue
476
- pass
477
-
478
- # If we got here, the function executed successfully, so break the retry loop
479
- break
480
-
481
- return wrapper
482
-
483
-
484
- # Helper function for getting the current rate limit status
485
- def rate_limit_status(resource_type="default"):
486
- """Get the current rate limit status for a resource type"""
487
- return guardian.get_limit_status(resource_type)
34
+ _last_message_time=0;_message_cooldown=5
35
+ def __enter__(self):return self
36
+ def __exit__(self,exc_type,exc_val,exc_tb):
37
+ if exc_type is RateLimitExceeded:
38
+ current_time=time.time()
39
+ if current_time-CleanErrorContext._last_message_time>=CleanErrorContext._message_cooldown:print(f"\n⚠️ {str(exc_val)}\n");CleanErrorContext._last_message_time=current_time
40
+ import sys;sys.exit(f"Rate limit exceeded. {str(exc_val)} Process terminated.");return _F
41
+ return _F
42
+ def optimize(resource_type=_C,loop_threshold=10,time_window=5,ad_cooldown=150,content_trigger_threshold=3,max_retries=2,backoff_factor=2,debug=_F):
43
+ if callable(resource_type):func=resource_type;return _create_wrapper(func,_C,loop_threshold,time_window,ad_cooldown,content_trigger_threshold,max_retries,backoff_factor,debug)
44
+ if loop_threshold<2:raise ValueError(f"loop_threshold must be at least 2, got {loop_threshold}")
45
+ if time_window<=0:raise ValueError(f"time_window must be positive, got {time_window}")
46
+ if content_trigger_threshold<1:raise ValueError(f"content_trigger_threshold must be at least 1, got {content_trigger_threshold}")
47
+ if max_retries<0:raise ValueError(f"max_retries must be non-negative, got {max_retries}")
48
+ if backoff_factor<=0:raise ValueError(f"backoff_factor must be positive, got {backoff_factor}")
49
+ def decorator(func):return _create_wrapper(func,resource_type,loop_threshold,time_window,ad_cooldown,content_trigger_threshold,max_retries,backoff_factor,debug)
50
+ return decorator
51
+ def _create_wrapper(func,resource_type,loop_threshold,time_window,ad_cooldown,content_trigger_threshold,max_retries,backoff_factor,debug):
52
+ call_history=[];last_ad_time=0;consecutive_loop_detections=0;session_displayed=_F;session_start_time=time.time();session_timeout=1800
53
+ @functools.wraps(func)
54
+ def wrapper(*args,**kwargs):
55
+ E='timestamp';D='environment';C='error';B='function';A='loop';nonlocal last_ad_time,consecutive_loop_detections,session_displayed,session_start_time;current_time=time.time();content_triggered=_F
56
+ if current_time-session_start_time>session_timeout:session_displayed=_F;session_start_time=current_time
57
+ retries=0
58
+ while _E:
59
+ call_history.append(current_time)
60
+ while call_history and current_time-call_history[0]>time_window:call_history.pop(0)
61
+ loop_detected=len(call_history)>=loop_threshold
62
+ if debug and loop_detected:print(f"[OPTIMIZE] Đã phát hiện vòng lặp cho {func.__name__}: {len(call_history)} lần gọi trong {time_window}s")
63
+ if loop_detected:
64
+ consecutive_loop_detections+=1
65
+ if debug:print(f"[OPTIMIZE] Số lần phát hiện vòng lặp liên tiếp: {consecutive_loop_detections}/{content_trigger_threshold}")
66
+ else:consecutive_loop_detections=0
67
+ should_show_content=consecutive_loop_detections>=content_trigger_threshold and current_time-last_ad_time>=ad_cooldown and not session_displayed
68
+ if should_show_content:
69
+ last_ad_time=current_time;consecutive_loop_detections=0;content_triggered=_E;session_displayed=_E
70
+ if debug:print(f"[OPTIMIZE] Đã kích hoạt nội dung cho {func.__name__}")
71
+ try:
72
+ from vnai.scope.promo import manager
73
+ try:from vnai.scope.profile import inspector;environment=inspector.examine().get(D,_D);manager.present_content(environment=environment,context=A)
74
+ except ImportError:manager.present_content(context=A)
75
+ except ImportError:print(f"Phát hiện vòng lặp: Hàm '{func.__name__}' đang được gọi trong một vòng lặp")
76
+ except Exception as e:
77
+ if debug:print(f"[OPTIMIZE] Lỗi khi hiển thị nội dung: {str(e)}")
78
+ try:
79
+ with CleanErrorContext():guardian.verify(func.__name__,resource_type)
80
+ except RateLimitExceeded as e:
81
+ from vnai.beam.metrics import collector;collector.record(C,{B:func.__name__,C:str(e),'context':'resource_verification',_G:resource_type,'retry_attempt':retries},priority='high')
82
+ if not session_displayed:
83
+ try:
84
+ from vnai.scope.promo import manager
85
+ try:from vnai.scope.profile import inspector;environment=inspector.examine().get(D,_D);manager.present_content(environment=environment,context=A);session_displayed=_E;last_ad_time=current_time
86
+ except ImportError:manager.present_content(context=A);session_displayed=_E;last_ad_time=current_time
87
+ except Exception:pass
88
+ if retries<max_retries:
89
+ wait_time=backoff_factor**retries;retries+=1
90
+ if hasattr(e,'retry_after')and e.retry_after:wait_time=min(wait_time,e.retry_after)
91
+ if debug:print(f"[OPTIMIZE] Đã đạt giới hạn tốc độ cho {func.__name__}, thử lại sau {wait_time} giây (lần thử {retries}/{max_retries})")
92
+ time.sleep(wait_time);continue
93
+ else:raise
94
+ start_time=time.time();success=_F;error=_D
95
+ try:result=func(*args,**kwargs);success=_E;return result
96
+ except Exception as e:error=str(e);raise
97
+ finally:
98
+ execution_time=time.time()-start_time
99
+ try:
100
+ from vnai.beam.metrics import collector;collector.record(B,{B:func.__name__,_G:resource_type,'execution_time':execution_time,'success':success,C:error,'in_loop':loop_detected,'loop_depth':len(call_history),'content_triggered':content_triggered,E:datetime.now().isoformat(),'retry_count':retries if retries>0 else _D})
101
+ if content_triggered:collector.record('ad_opportunity',{B:func.__name__,_G:resource_type,'call_frequency':len(call_history)/time_window,'consecutive_loops':consecutive_loop_detections,E:datetime.now().isoformat()})
102
+ except ImportError:pass
103
+ break
104
+ return wrapper
105
+ def rate_limit_status(resource_type=_C):return guardian.get_limit_status(resource_type)
vnai/flow/__init__.py CHANGED
@@ -1,5 +1,2 @@
1
- # vnai/flow/__init__.py
2
- # Data flow and transmission management
3
-
4
- from vnai.flow.relay import conduit, configure
5
- from vnai.flow.queue import buffer
1
+ from vnai.flow.relay import conduit,configure
2
+ from vnai.flow.queue import buffer