vnai 2.0.2__py3-none-any.whl → 2.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
vnai/beam/quota.py CHANGED
@@ -1,107 +1,512 @@
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
1
+ ##
2
+
3
+ ##
4
+
5
+
6
+ import time
7
+ import functools
8
+ import threading
9
9
  from collections import defaultdict
10
10
  from datetime import datetime
11
+
11
12
  class RateLimitExceeded(Exception):
12
- def __init__(A,resource_type,limit_type=_A,current_usage=_D,limit_value=_D,retry_after=_D):
13
- D=resource_type;B=retry_after;A.resource_type=D;A.limit_type=limit_type;A.current_usage=current_usage;A.limit_value=limit_value;A.retry_after=B;C=f"Bạn đã gửi quá nhiều request tới {D}. "
14
- if B:C+=f"Vui lòng thử lại sau {round(B)} giây."
15
- else:C+='Vui lòng thêm thời gian chờ giữa các lần gửi request.'
16
- super().__init__(C)
13
+ #--
14
+ def __init__(self, resource_type, limit_type="min", current_usage=None, limit_value=None, retry_after=None):
15
+ self.resource_type = resource_type
16
+ self.limit_type = limit_type
17
+ self.current_usage = current_usage
18
+ self.limit_value = limit_value
19
+ self.retry_after = retry_after
20
+
21
+ ##
22
+
23
+ message = f"Bạn đã gửi quá nhiều request tới {resource_type}. "
24
+ if retry_after:
25
+ message += f"Vui lòng thử lại sau {round(retry_after)} giây."
26
+ else:
27
+ message += "Vui lòng thêm thời gian chờ giữa các lần gửi request."
28
+
29
+ super().__init__(message)
30
+
17
31
  class Guardian:
18
- _instance=_D;_lock=threading.Lock()
19
- def __new__(A):
20
- with A._lock:
21
- if A._instance is _D:A._instance=super(Guardian,A).__new__(A);A._instance._initialize()
22
- return A._instance
23
- def _initialize(A):A.resource_limits=defaultdict(lambda:defaultdict(int));A.usage_counters=defaultdict(lambda:defaultdict(list));A.resource_limits[_C]={_A:60,_B:3000};A.resource_limits['TCBS']={_A:60,_B:3000};A.resource_limits['VCI']={_A:60,_B:3000};A.resource_limits['VCI.ext']={_A:600,_B:36000};A.resource_limits['VND.ext']={_A:600,_B:36000};A.resource_limits['CAF.ext']={_A:600,_B:36000};A.resource_limits['SPL.ext']={_A:600,_B:36000};A.resource_limits['VDS.ext']={_A:600,_B:36000};A.resource_limits['FAD.ext']={_A:600,_B:36000}
24
- def verify(B,operation_id,resource_type=_C):
25
- M='is_exceeded';L='current_usage';K='limit_value';J='limit_type';I='rate_limit';A=resource_type;D=time.time();C=B.resource_limits.get(A,B.resource_limits[_C]);N=D-60;B.usage_counters[A][_A]=[A for A in B.usage_counters[A][_A]if A>N];F=len(B.usage_counters[A][_A]);O=F>=C[_A]
26
- if O:from vnai.beam.metrics import collector as G;G.record(I,{_G:A,J:_A,K:C[_A],L:F,M:_E},priority='high');raise RateLimitExceeded(resource_type=A,limit_type=_A,current_usage=F,limit_value=C[_A],retry_after=60-D%60)
27
- P=D-3600;B.usage_counters[A][_B]=[A for A in B.usage_counters[A][_B]if A>P];H=len(B.usage_counters[A][_B]);E=H>=C[_B];from vnai.beam.metrics import collector as G;G.record(I,{_G:A,J:_B if E else _A,K:C[_B]if E else C[_A],L:H if E else F,M:E})
28
- if E:raise RateLimitExceeded(resource_type=A,limit_type=_B,current_usage=H,limit_value=C[_B],retry_after=3600-D%3600)
29
- B.usage_counters[A][_A].append(D);B.usage_counters[A][_B].append(D);return _E
30
- def usage(A,resource_type=_C):B=resource_type;D=time.time();C=A.resource_limits.get(B,A.resource_limits[_C]);E=D-60;F=D-3600;A.usage_counters[B][_A]=[A for A in A.usage_counters[B][_A]if A>E];A.usage_counters[B][_B]=[A for A in A.usage_counters[B][_B]if A>F];G=len(A.usage_counters[B][_A]);H=len(A.usage_counters[B][_B]);I=G/C[_A]*100 if C[_A]>0 else 0;J=H/C[_B]*100 if C[_B]>0 else 0;return max(I,J)
31
- def get_limit_status(B,resource_type=_C):K='reset_in_seconds';J='remaining';I='percentage';H='limit';G='usage';C=resource_type;D=time.time();A=B.resource_limits.get(C,B.resource_limits[_C]);L=D-60;M=D-3600;E=len([A for A in B.usage_counters[C][_A]if A>L]);F=len([A for A in B.usage_counters[C][_B]if A>M]);return{_G:C,'minute_limit':{G:E,H:A[_A],I:E/A[_A]*100 if A[_A]>0 else 0,J:max(0,A[_A]-E),K:60-D%60},'hour_limit':{G:F,H:A[_B],I:F/A[_B]*100 if A[_B]>0 else 0,J:max(0,A[_B]-F),K:3600-D%3600}}
32
- guardian=Guardian()
32
+ #--
33
+
34
+ _instance = None
35
+ _lock = threading.Lock()
36
+
37
+ def __new__(cls):
38
+ with cls._lock:
39
+ if cls._instance is None:
40
+ cls._instance = super(Guardian, cls).__new__(cls)
41
+ cls._instance._initialize()
42
+ return cls._instance
43
+
44
+ def _initialize(self):
45
+ #--
46
+ self.resource_limits = defaultdict(lambda: defaultdict(int))
47
+ self.usage_counters = defaultdict(lambda: defaultdict(list))
48
+
49
+ ##
50
+
51
+ self.resource_limits["default"] = {"min": 60, "hour": 3000}
52
+ self.resource_limits["TCBS"] = {"min": 60, "hour": 3000}
53
+ self.resource_limits["VCI"] = {"min": 60, "hour": 3000}
54
+ self.resource_limits["VCI.ext"] = {"min": 600, "hour": 36000}
55
+ self.resource_limits["VND.ext"] = {"min": 600, "hour": 36000}
56
+ self.resource_limits["CAF.ext"] = {"min": 600, "hour": 36000}
57
+ self.resource_limits["SPL.ext"] = {"min": 600, "hour": 36000}
58
+ self.resource_limits["VDS.ext"] = {"min": 600, "hour": 36000}
59
+ self.resource_limits["FAD.ext"] = {"min": 600, "hour": 36000}
60
+
61
+ def verify(self, operation_id, resource_type="default"):
62
+ #--
63
+ current_time = time.time()
64
+
65
+ ##
66
+
67
+ limits = self.resource_limits.get(resource_type, self.resource_limits["default"])
68
+
69
+ ##
70
+
71
+ minute_cutoff = current_time - 60
72
+ self.usage_counters[resource_type]["min"] = [
73
+ t for t in self.usage_counters[resource_type]["min"]
74
+ if t > minute_cutoff
75
+ ]
76
+
77
+ minute_usage = len(self.usage_counters[resource_type]["min"])
78
+ minute_exceeded = minute_usage >= limits["min"]
79
+
80
+ if minute_exceeded:
81
+ ##
82
+
83
+ from vnai.beam.metrics import collector
84
+ collector.record(
85
+ "rate_limit",
86
+ {
87
+ "resource_type": resource_type,
88
+ "limit_type": "min",
89
+ "limit_value": limits["min"],
90
+ "current_usage": minute_usage,
91
+ "is_exceeded": True
92
+ },
93
+ priority="high"
94
+ )
95
+ ##
96
+
97
+ raise RateLimitExceeded(
98
+ resource_type=resource_type,
99
+ limit_type="min",
100
+ current_usage=minute_usage,
101
+ limit_value=limits["min"],
102
+ retry_after=60 - (current_time % 60) ##
103
+
104
+ )
105
+
106
+ ##
107
+
108
+ hour_cutoff = current_time - 3600
109
+ self.usage_counters[resource_type]["hour"] = [
110
+ t for t in self.usage_counters[resource_type]["hour"]
111
+ if t > hour_cutoff
112
+ ]
113
+
114
+ hour_usage = len(self.usage_counters[resource_type]["hour"])
115
+ hour_exceeded = hour_usage >= limits["hour"]
116
+
117
+ ##
118
+
119
+ from vnai.beam.metrics import collector
120
+ collector.record(
121
+ "rate_limit",
122
+ {
123
+ "resource_type": resource_type,
124
+ "limit_type": "hour" if hour_exceeded else "min",
125
+ "limit_value": limits["hour"] if hour_exceeded else limits["min"],
126
+ "current_usage": hour_usage if hour_exceeded else minute_usage,
127
+ "is_exceeded": hour_exceeded
128
+ }
129
+ )
130
+
131
+ if hour_exceeded:
132
+ ##
133
+
134
+ raise RateLimitExceeded(
135
+ resource_type=resource_type,
136
+ limit_type="hour",
137
+ current_usage=hour_usage,
138
+ limit_value=limits["hour"],
139
+ retry_after=3600 - (current_time % 3600) ##
140
+
141
+ )
142
+
143
+ ##
144
+
145
+ self.usage_counters[resource_type]["min"].append(current_time)
146
+ self.usage_counters[resource_type]["hour"].append(current_time)
147
+ return True
148
+
149
+ def usage(self, resource_type="default"):
150
+ #--
151
+ current_time = time.time()
152
+ limits = self.resource_limits.get(resource_type, self.resource_limits["default"])
153
+
154
+ ##
155
+
156
+ minute_cutoff = current_time - 60
157
+ hour_cutoff = current_time - 3600
158
+
159
+ self.usage_counters[resource_type]["min"] = [
160
+ t for t in self.usage_counters[resource_type]["min"]
161
+ if t > minute_cutoff
162
+ ]
163
+
164
+ self.usage_counters[resource_type]["hour"] = [
165
+ t for t in self.usage_counters[resource_type]["hour"]
166
+ if t > hour_cutoff
167
+ ]
168
+
169
+ ##
170
+
171
+ minute_usage = len(self.usage_counters[resource_type]["min"])
172
+ hour_usage = len(self.usage_counters[resource_type]["hour"])
173
+
174
+ minute_percentage = (minute_usage / limits["min"]) * 100 if limits["min"] > 0 else 0
175
+ hour_percentage = (hour_usage / limits["hour"]) * 100 if limits["hour"] > 0 else 0
176
+
177
+ ##
178
+
179
+ return max(minute_percentage, hour_percentage)
180
+
181
+ def get_limit_status(self, resource_type="default"):
182
+ #--
183
+ current_time = time.time()
184
+ limits = self.resource_limits.get(resource_type, self.resource_limits["default"])
185
+
186
+ ##
187
+
188
+ minute_cutoff = current_time - 60
189
+ hour_cutoff = current_time - 3600
190
+
191
+ minute_usage = len([t for t in self.usage_counters[resource_type]["min"] if t > minute_cutoff])
192
+ hour_usage = len([t for t in self.usage_counters[resource_type]["hour"] if t > hour_cutoff])
193
+
194
+ return {
195
+ "resource_type": resource_type,
196
+ "minute_limit": {
197
+ "usage": minute_usage,
198
+ "limit": limits["min"],
199
+ "percentage": (minute_usage / limits["min"]) * 100 if limits["min"] > 0 else 0,
200
+ "remaining": max(0, limits["min"] - minute_usage),
201
+ "reset_in_seconds": 60 - (current_time % 60)
202
+ },
203
+ "hour_limit": {
204
+ "usage": hour_usage,
205
+ "limit": limits["hour"],
206
+ "percentage": (hour_usage / limits["hour"]) * 100 if limits["hour"] > 0 else 0,
207
+ "remaining": max(0, limits["hour"] - hour_usage),
208
+ "reset_in_seconds": 3600 - (current_time % 3600)
209
+ }
210
+ }
211
+
212
+ ##
213
+
214
+ guardian = Guardian()
215
+
33
216
  class CleanErrorContext:
34
- _last_message_time=0;_message_cooldown=5
35
- def __enter__(A):return A
36
- def __exit__(C,exc_type,exc_val,exc_tb):
37
- A=exc_val
38
- if exc_type is RateLimitExceeded:
39
- B=time.time()
40
- if B-CleanErrorContext._last_message_time>=CleanErrorContext._message_cooldown:print(f"\n⚠️ {str(A)}\n");CleanErrorContext._last_message_time=B
41
- import sys;sys.exit(f"Rate limit exceeded. {str(A)} Process terminated.");return _F
42
- return _F
43
- 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):
44
- H=debug;G=ad_cooldown;F=resource_type;E=backoff_factor;D=max_retries;C=content_trigger_threshold;B=time_window;A=loop_threshold
45
- if callable(F):I=F;return _create_wrapper(I,_C,A,B,G,C,D,E,H)
46
- if A<2:raise ValueError(f"loop_threshold must be at least 2, got {A}")
47
- if B<=0:raise ValueError(f"time_window must be positive, got {B}")
48
- if C<1:raise ValueError(f"content_trigger_threshold must be at least 1, got {C}")
49
- if D<0:raise ValueError(f"max_retries must be non-negative, got {D}")
50
- if E<=0:raise ValueError(f"backoff_factor must be positive, got {E}")
51
- def J(func):return _create_wrapper(func,F,A,B,G,C,D,E,H)
52
- return J
53
- def _create_wrapper(func,resource_type,loop_threshold,time_window,ad_cooldown,content_trigger_threshold,max_retries,backoff_factor,debug):
54
- X=max_retries;W=content_trigger_threshold;P=time_window;K=resource_type;H=debug;A=func;B=[];I=0;E=0;F=_F;Q=time.time();c=1800
55
- @functools.wraps(A)
56
- def C(*d,**e):
57
- b='timestamp';a='environment';V='error';O='function';N='loop';nonlocal I,E,F,Q;C=time.time();R=_F
58
- if C-Q>c:F=_F;Q=C
59
- G=0
60
- while _E:
61
- B.append(C)
62
- while B and C-B[0]>P:B.pop(0)
63
- S=len(B)>=loop_threshold
64
- if H and S:print(f"[OPTIMIZE] Đã phát hiện vòng lặp cho {A.__name__}: {len(B)} lần gọi trong {P}s")
65
- if S:
66
- E+=1
67
- if H:print(f"[OPTIMIZE] Số lần phát hiện vòng lặp liên tiếp: {E}/{W}")
68
- else:E=0
69
- f=E>=W and C-I>=ad_cooldown and not F
70
- if f:
71
- I=C;E=0;R=_E;F=_E
72
- if H:print(f"[OPTIMIZE] Đã kích hoạt nội dung cho {A.__name__}")
73
- try:
74
- from vnai.scope.promo import manager as J
75
- try:from vnai.scope.profile import inspector as T;U=T.examine().get(a,_D);J.present_content(environment=U,context=N)
76
- except ImportError:J.present_content(context=N)
77
- except ImportError:print(f"Phát hiện vòng lặp: Hàm '{A.__name__}' đang được gọi trong một vòng lặp")
78
- except Exception as D:
79
- if H:print(f"[OPTIMIZE] Lỗi khi hiển thị nội dung: {str(D)}")
80
- try:
81
- with CleanErrorContext():guardian.verify(A.__name__,K)
82
- except RateLimitExceeded as D:
83
- from vnai.beam.metrics import collector as L;L.record(V,{O:A.__name__,V:str(D),'context':'resource_verification',_G:K,'retry_attempt':G},priority='high')
84
- if not F:
85
- try:
86
- from vnai.scope.promo import manager as J
87
- try:from vnai.scope.profile import inspector as T;U=T.examine().get(a,_D);J.present_content(environment=U,context=N);F=_E;I=C
88
- except ImportError:J.present_content(context=N);F=_E;I=C
89
- except Exception:pass
90
- if G<X:
91
- M=backoff_factor**G;G+=1
92
- if hasattr(D,'retry_after')and D.retry_after:M=min(M,D.retry_after)
93
- if H:print(f"[OPTIMIZE] Đã đạt giới hạn tốc độ cho {A.__name__}, thử lại sau {M} giây (lần thử {G}/{X})")
94
- time.sleep(M);continue
95
- else:raise
96
- g=time.time();Y=_F;Z=_D
97
- try:h=A(*d,**e);Y=_E;return h
98
- except Exception as D:Z=str(D);raise
99
- finally:
100
- i=time.time()-g
101
- try:
102
- from vnai.beam.metrics import collector as L;L.record(O,{O:A.__name__,_G:K,'execution_time':i,'success':Y,V:Z,'in_loop':S,'loop_depth':len(B),'content_triggered':R,b:datetime.now().isoformat(),'retry_count':G if G>0 else _D})
103
- if R:L.record('ad_opportunity',{O:A.__name__,_G:K,'call_frequency':len(B)/P,'consecutive_loops':E,b:datetime.now().isoformat()})
104
- except ImportError:pass
105
- break
106
- return C
107
- def rate_limit_status(resource_type=_C):return guardian.get_limit_status(resource_type)
217
+ #--
218
+ ##
219
+
220
+ _last_message_time = 0
221
+ _message_cooldown = 5 ##
222
+
223
+
224
+ def __enter__(self):
225
+ return self
226
+
227
+ def __exit__(self, exc_type, exc_val, exc_tb):
228
+ if exc_type is RateLimitExceeded:
229
+ current_time = time.time()
230
+
231
+ ##
232
+
233
+ if current_time - CleanErrorContext._last_message_time >= CleanErrorContext._message_cooldown:
234
+ print(f"\n⚠️ {str(exc_val)}\n")
235
+ CleanErrorContext._last_message_time = current_time
236
+
237
+ ##
238
+
239
+ ##
240
+
241
+ import sys
242
+ sys.exit(f"Rate limit exceeded. {str(exc_val)} Process terminated.")
243
+
244
+ ##
245
+
246
+ return False
247
+ return False
248
+
249
+
250
+ def optimize(resource_type='default', loop_threshold=10, time_window=5, ad_cooldown=150, content_trigger_threshold=3,
251
+ max_retries=2, backoff_factor=2, debug=False):
252
+ #--
253
+ ##
254
+
255
+ if callable(resource_type):
256
+ func = resource_type
257
+ return _create_wrapper(func, 'default', loop_threshold, time_window, ad_cooldown, content_trigger_threshold,
258
+ max_retries, backoff_factor, debug)
259
+
260
+ ##
261
+
262
+ if loop_threshold < 2:
263
+ raise ValueError(f"loop_threshold must be at least 2, got {loop_threshold}")
264
+ if time_window <= 0:
265
+ raise ValueError(f"time_window must be positive, got {time_window}")
266
+ if content_trigger_threshold < 1:
267
+ raise ValueError(f"content_trigger_threshold must be at least 1, got {content_trigger_threshold}")
268
+ if max_retries < 0:
269
+ raise ValueError(f"max_retries must be non-negative, got {max_retries}")
270
+ if backoff_factor <= 0:
271
+ raise ValueError(f"backoff_factor must be positive, got {backoff_factor}")
272
+
273
+ ##
274
+
275
+ def decorator(func):
276
+ return _create_wrapper(func, resource_type, loop_threshold, time_window, ad_cooldown, content_trigger_threshold,
277
+ max_retries, backoff_factor, debug)
278
+ return decorator
279
+
280
+ def _create_wrapper(func, resource_type, loop_threshold, time_window, ad_cooldown, content_trigger_threshold,
281
+ max_retries, backoff_factor, debug):
282
+ #--
283
+ ##
284
+
285
+ call_history = []
286
+ last_ad_time = 0
287
+ consecutive_loop_detections = 0
288
+ session_displayed = False ##
289
+
290
+ session_start_time = time.time()
291
+ session_timeout = 1800 ##
292
+
293
+
294
+ @functools.wraps(func)
295
+ def wrapper(*args, **kwargs):
296
+ nonlocal last_ad_time, consecutive_loop_detections, session_displayed, session_start_time
297
+ current_time = time.time()
298
+ content_triggered = False
299
+
300
+ ##
301
+
302
+ if current_time - session_start_time > session_timeout:
303
+ session_displayed = False
304
+ session_start_time = current_time
305
+
306
+ ##
307
+
308
+ retries = 0
309
+ while True:
310
+ ##
311
+
312
+ ##
313
+
314
+ call_history.append(current_time)
315
+
316
+ ##
317
+
318
+ while call_history and current_time - call_history[0] > time_window:
319
+ call_history.pop(0)
320
+
321
+ ##
322
+
323
+ loop_detected = len(call_history) >= loop_threshold
324
+
325
+ if debug and loop_detected:
326
+ 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")
327
+
328
+ ##
329
+
330
+ if loop_detected:
331
+ consecutive_loop_detections += 1
332
+ if debug:
333
+ print(f"[OPTIMIZE] Số lần phát hiện vòng lặp liên tiếp: {consecutive_loop_detections}/{content_trigger_threshold}")
334
+ else:
335
+ consecutive_loop_detections = 0
336
+
337
+ ##
338
+
339
+ should_show_content = (consecutive_loop_detections >= content_trigger_threshold) and (current_time - last_ad_time >= ad_cooldown) and not session_displayed
340
+
341
+ ##
342
+
343
+ if should_show_content:
344
+ last_ad_time = current_time
345
+ consecutive_loop_detections = 0
346
+ content_triggered = True
347
+ session_displayed = True ##
348
+
349
+
350
+ if debug:
351
+ print(f"[OPTIMIZE] Đã kích hoạt nội dung cho {func.__name__}")
352
+
353
+ ##
354
+
355
+ try:
356
+ from vnai.scope.promo import manager
357
+
358
+ ##
359
+
360
+ try:
361
+ from vnai.scope.profile import inspector
362
+ environment = inspector.examine().get("environment", None)
363
+ manager.present_content(environment=environment, context="loop")
364
+ except ImportError:
365
+ manager.present_content(context="loop")
366
+
367
+ except ImportError:
368
+ ##
369
+
370
+ 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")
371
+ except Exception as e:
372
+ ##
373
+
374
+ if debug:
375
+ print(f"[OPTIMIZE] Lỗi khi hiển thị nội dung: {str(e)}")
376
+
377
+ ##
378
+
379
+ try:
380
+ ##
381
+
382
+ with CleanErrorContext():
383
+ guardian.verify(func.__name__, resource_type)
384
+
385
+ except RateLimitExceeded as e:
386
+ ##
387
+
388
+ from vnai.beam.metrics import collector
389
+ collector.record(
390
+ "error",
391
+ {
392
+ "function": func.__name__,
393
+ "error": str(e),
394
+ "context": "resource_verification",
395
+ "resource_type": resource_type,
396
+ "retry_attempt": retries
397
+ },
398
+ priority="high"
399
+ )
400
+
401
+ ##
402
+
403
+ if not session_displayed:
404
+ try:
405
+ from vnai.scope.promo import manager
406
+ try:
407
+ from vnai.scope.profile import inspector
408
+ environment = inspector.examine().get("environment", None)
409
+ manager.present_content(environment=environment, context="loop")
410
+ session_displayed = True ##
411
+
412
+ last_ad_time = current_time
413
+ except ImportError:
414
+ manager.present_content(context="loop")
415
+ session_displayed = True
416
+ last_ad_time = current_time
417
+ except Exception:
418
+ pass ##
419
+
420
+
421
+ ##
422
+
423
+ if retries < max_retries:
424
+ wait_time = backoff_factor ** retries
425
+ retries += 1
426
+
427
+ ##
428
+
429
+ if hasattr(e, "retry_after") and e.retry_after:
430
+ wait_time = min(wait_time, e.retry_after)
431
+
432
+ if debug:
433
+ 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})")
434
+
435
+ time.sleep(wait_time)
436
+ continue ##
437
+
438
+ else:
439
+ ##
440
+
441
+ raise
442
+
443
+ ##
444
+
445
+ start_time = time.time()
446
+ success = False
447
+ error = None
448
+
449
+ try:
450
+ ##
451
+
452
+ result = func(*args, **kwargs)
453
+ success = True
454
+ return result
455
+ except Exception as e:
456
+ error = str(e)
457
+ raise
458
+ finally:
459
+ ##
460
+
461
+ execution_time = time.time() - start_time
462
+
463
+ ##
464
+
465
+ try:
466
+ from vnai.beam.metrics import collector
467
+ collector.record(
468
+ "function",
469
+ {
470
+ "function": func.__name__,
471
+ "resource_type": resource_type,
472
+ "execution_time": execution_time,
473
+ "success": success,
474
+ "error": error,
475
+ "in_loop": loop_detected,
476
+ "loop_depth": len(call_history),
477
+ "content_triggered": content_triggered,
478
+ "timestamp": datetime.now().isoformat(),
479
+ "retry_count": retries if retries > 0 else None
480
+ }
481
+ )
482
+
483
+ ##
484
+
485
+ if content_triggered:
486
+ collector.record(
487
+ "ad_opportunity",
488
+ {
489
+ "function": func.__name__,
490
+ "resource_type": resource_type,
491
+ "call_frequency": len(call_history) / time_window,
492
+ "consecutive_loops": consecutive_loop_detections,
493
+ "timestamp": datetime.now().isoformat()
494
+ }
495
+ )
496
+ except ImportError:
497
+ ##
498
+
499
+ pass
500
+
501
+ ##
502
+
503
+ break
504
+
505
+ return wrapper
506
+
507
+
508
+ ##
509
+
510
+ def rate_limit_status(resource_type="default"):
511
+ #--
512
+ return guardian.get_limit_status(resource_type)
vnai/flow/__init__.py CHANGED
@@ -1,2 +1,7 @@
1
- from vnai.flow.relay import conduit,configure
2
- from vnai.flow.queue import buffer
1
+ ##
2
+
3
+ ##
4
+
5
+
6
+ from vnai.flow.relay import conduit, configure
7
+ from vnai.flow.queue import buffer