vnai 2.1.8__py3-none-any.whl → 2.1.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/__init__.py CHANGED
@@ -1,6 +1,3 @@
1
- # vnai/__init__.py
2
- # Main entry point for vnai package
3
-
4
1
  import os
5
2
  import pathlib
6
3
  import json
@@ -8,8 +5,6 @@ import time
8
5
  import threading
9
6
  import functools
10
7
  from datetime import datetime
11
-
12
- # Import core functionality
13
8
  from vnai.beam.quota import guardian, optimize
14
9
  from vnai.beam.metrics import collector, capture
15
10
  from vnai.beam.pulse import monitor
@@ -19,204 +14,139 @@ from vnai.scope.profile import inspector
19
14
  from vnai.scope.state import tracker, record
20
15
  import vnai.scope.promo
21
16
  from vnai.scope.promo import present
22
-
23
- # Constants for terms and conditions
24
- TC_VAR = "ACCEPT_TC"
25
- TC_VAL = "tôi đồng ý"
26
- TC_PATH = pathlib.Path.home() / ".vnstock" / "id" / "terms_agreement.txt"
27
-
28
- TERMS_AND_CONDITIONS = """
17
+ TC_VAR ="ACCEPT_TC"
18
+ TC_VAL ="tôi đồng ý"
19
+ TC_PATH = pathlib.Path.home() /".vnstock" /"id" /"terms_agreement.txt"
20
+ TERMS_AND_CONDITIONS ="""
29
21
  Khi tiếp tục sử dụng Vnstock, bạn xác nhận rằng bạn đã đọc, hiểu và đồng ý với Chính sách quyền riêng tư và Điều khoản, điều kiện về giấy phép sử dụng Vnstock.
30
-
31
22
  Chi tiết:
32
23
  - Giấy phép sử dụng phần mềm: https://vnstocks.com/docs/tai-lieu/giay-phep-su-dung
33
24
  - Chính sách quyền riêng tư: https://vnstocks.com/docs/tai-lieu/chinh-sach-quyen-rieng-tu
34
25
  """
35
26
 
36
27
  class Core:
37
- """Core functionality for system optimization"""
38
-
39
28
  def __init__(self):
40
- """Initialize core"""
41
29
  self.initialized = False
42
30
  self.webhook_url = None
43
31
  self.init_time = datetime.now().isoformat()
44
32
  self.home_dir = pathlib.Path.home()
45
- self.project_dir = self.home_dir / ".vnstock"
46
- self.id_dir = self.project_dir / 'id'
33
+ self.project_dir = self.home_dir /".vnstock"
34
+ self.id_dir = self.project_dir /'id'
47
35
  self.terms_file_path = TC_PATH
48
36
  self.system_info = None
49
-
50
- # Create necessary directories
51
37
  self.project_dir.mkdir(exist_ok=True)
52
38
  self.id_dir.mkdir(exist_ok=True)
53
-
54
- # Auto-initialize
55
39
  self.initialize()
56
40
 
57
41
  def initialize(self):
58
- """Initialize the system"""
59
42
  if self.initialized:
60
43
  return True
61
-
62
- # Check terms acceptance
63
44
  if not self._check_terms():
64
45
  self._accept_terms()
65
-
66
- # Set up vnstock environment
67
46
  from vnai.scope.profile import inspector
68
47
  inspector.setup_vnstock_environment()
69
-
70
- # Display content during initialization
71
48
  from vnai.scope.promo import ContentManager
72
49
  manager = ContentManager()
73
- # Chỉ hiện ads nếu chắc chắn là free user
74
- if manager.is_paid_user is False and getattr(manager, 'license_checked', False):
50
+ if manager.is_paid_user is False and getattr(manager,'license_checked', False):
75
51
  present()
76
-
77
- # Record initialization
78
52
  record("initialization", {"timestamp": datetime.now().isoformat()})
79
-
80
- # Get system information ONCE and store it in the class
81
53
  self.system_info = inspector.examine()
82
-
83
- # Queue system data with optimal structure
84
54
  conduit.queue({
85
- "type": "system_info",
86
- "data": {
87
- "commercial": inspector.detect_commercial_usage(),
88
- "packages": inspector.scan_packages()
55
+ "type":"system_info",
56
+ "data": {
57
+ "commercial": inspector.detect_commercial_usage(),
58
+ "packages": inspector.scan_packages()
89
59
  }
90
60
  }, priority="high")
91
-
92
61
  self.initialized = True
93
62
  return True
94
63
 
95
64
  def _check_terms(self):
96
- """Check if terms have been accepted"""
97
65
  return os.path.exists(self.terms_file_path)
98
66
 
99
67
  def _accept_terms(self):
100
- """Record terms acceptance"""
101
- # Get system information
102
68
  system_info = inspector.examine()
103
-
104
- # Auto-accept terms
105
69
  if TC_VAR in os.environ and os.environ[TC_VAR] == TC_VAL:
106
70
  response = TC_VAL
107
71
  else:
108
- # For non-interactive environments, accept by default
109
72
  response = TC_VAL
110
73
  os.environ[TC_VAR] = TC_VAL
111
-
112
- # Store the acceptance with hardware info
113
74
  now = datetime.now()
114
75
  signed_agreement = (
115
- f"Người dùng có mã nhận dạng {system_info['machine_id']} đã chấp nhận "
116
- f"điều khoản & điều kiện sử dụng Vnstock lúc {now}\n"
117
- f"---\n\n"
118
- f"THÔNG TIN THIẾT BỊ: {json.dumps(system_info, indent=2)}\n\n"
119
- f"Đính kèm bản sao nội dung bạn đã đọc, hiểu rõ và đồng ý dưới đây:\n"
120
- f"{TERMS_AND_CONDITIONS}"
76
+ f"Người dùng có mã nhận dạng {system_info['machine_id']} đã chấp nhận "
77
+ f"điều khoản & điều kiện sử dụng Vnstock lúc {now}\n"
78
+ f"---\n\n"
79
+ f"THÔNG TIN THIẾT BỊ: {json.dumps(system_info, indent=2)}\n\n"
80
+ f"Đính kèm bản sao nội dung bạn đã đọc, hiểu rõ và đồng ý dưới đây:\n"
81
+ f"{TERMS_AND_CONDITIONS}"
121
82
  )
122
-
123
- # Store the acceptance
124
- with open(self.terms_file_path, "w", encoding="utf-8") as f:
83
+ with open(self.terms_file_path,"w", encoding="utf-8") as f:
125
84
  f.write(signed_agreement)
126
-
127
- # Create the environment.json file that vnstock expects
128
- env_file = self.id_dir / "environment.json"
85
+ env_file = self.id_dir /"environment.json"
129
86
  env_data = {
130
- "accepted_agreement": True,
131
- "timestamp": now.isoformat(),
132
- "machine_id": system_info['machine_id']
87
+ "accepted_agreement": True,
88
+ "timestamp": now.isoformat(),
89
+ "machine_id": system_info['machine_id']
133
90
  }
134
-
135
- with open(env_file, "w") as f:
91
+ with open(env_file,"w") as f:
136
92
  json.dump(env_data, f)
137
-
138
93
  return True
139
94
 
140
95
  def status(self):
141
- """Get system status"""
142
96
  return {
143
- "initialized": self.initialized,
144
- "health": monitor.report(),
145
- "metrics": tracker.get_metrics()
146
- # Environment information available via self.system_info
97
+ "initialized": self.initialized,
98
+ "health": monitor.report(),
99
+ "metrics": tracker.get_metrics()
147
100
  }
148
-
101
+
149
102
  def configure_privacy(self, level="standard"):
150
- """Configure privacy settings"""
151
103
  from vnai.scope.state import tracker
152
104
  return tracker.setup_privacy(level)
153
-
154
-
155
- # Create singleton instance
156
105
  core = Core()
157
106
 
158
- # Backward support
159
107
  def tc_init():
160
108
  return core.initialize()
161
109
 
162
110
  def setup():
163
- """Setup vnai"""
164
111
  return core.initialize()
165
112
 
166
113
  def optimize_execution(resource_type="default"):
167
- """Decorator for optimizing function execution"""
168
114
  return optimize(resource_type)
169
115
 
170
116
  def agg_execution(resource_type="default"):
171
- """Decorator for aggregating function execution"""
172
117
  return optimize(resource_type, ad_cooldown=1500, content_trigger_threshold=100000)
173
118
 
174
119
  def measure_performance(module_type="function"):
175
- """Decorator for measuring function performance"""
176
120
  return capture(module_type)
177
121
 
178
122
  def accept_license_terms(terms_text=None):
179
- """Accept license terms and conditions"""
180
123
  if terms_text is None:
181
124
  terms_text = TERMS_AND_CONDITIONS
182
-
183
- # Get system information
184
125
  system_info = inspector.examine()
185
-
186
- # Record acceptance
187
- terms_file = pathlib.Path.home() / ".vnstock" / "id" / "terms_agreement.txt"
126
+ terms_file = pathlib.Path.home() /".vnstock" /"id" /"terms_agreement.txt"
188
127
  os.makedirs(os.path.dirname(terms_file), exist_ok=True)
189
-
190
- with open(terms_file, "w", encoding="utf-8") as f:
128
+ with open(terms_file,"w", encoding="utf-8") as f:
191
129
  f.write(f"Terms accepted at {datetime.now().isoformat()}\n")
192
130
  f.write(f"System: {json.dumps(system_info)}\n\n")
193
131
  f.write(terms_text)
194
-
195
132
  return True
196
133
 
197
134
  def accept_vnstock_terms():
198
- """Accept vnstock terms and create necessary files"""
199
- # Get system information
200
135
  from vnai.scope.profile import inspector
201
136
  system_info = inspector.examine()
202
-
203
- # Create necessary directories
204
137
  home_dir = pathlib.Path.home()
205
- project_dir = home_dir / ".vnstock"
138
+ project_dir = home_dir /".vnstock"
206
139
  project_dir.mkdir(exist_ok=True)
207
- id_dir = project_dir / 'id'
140
+ id_dir = project_dir /'id'
208
141
  id_dir.mkdir(exist_ok=True)
209
-
210
- # Create environment.json file that vnstock looks for
211
- env_file = id_dir / "environment.json"
142
+ env_file = id_dir /"environment.json"
212
143
  env_data = {
213
- "accepted_agreement": True,
214
- "timestamp": datetime.now().isoformat(),
215
- "machine_id": system_info['machine_id']
144
+ "accepted_agreement": True,
145
+ "timestamp": datetime.now().isoformat(),
146
+ "machine_id": system_info['machine_id']
216
147
  }
217
-
218
148
  try:
219
- with open(env_file, "w") as f:
149
+ with open(env_file,"w") as f:
220
150
  json.dump(env_data, f)
221
151
  print("Vnstock terms accepted successfully.")
222
152
  return True
@@ -225,16 +155,13 @@ def accept_vnstock_terms():
225
155
  return False
226
156
 
227
157
  def configure_privacy(level="standard"):
228
- """Configure privacy level for analytics data"""
229
158
  from vnai.scope.state import tracker
230
159
  return tracker.setup_privacy(level)
231
160
 
232
161
  def check_commercial_usage():
233
- """Check if running in commercial environment"""
234
162
  from vnai.scope.profile import inspector
235
163
  return inspector.detect_commercial_usage()
236
164
 
237
165
  def authenticate_for_persistence():
238
- """Authenticate to Google Drive for persistent settings (Colab only)"""
239
166
  from vnai.scope.profile import inspector
240
- return inspector.get_or_create_user_id()
167
+ return inspector.get_or_create_user_id()
vnai/beam/__init__.py CHANGED
@@ -1,5 +1,3 @@
1
- # vnai/beam/__init__.py
2
-
3
1
  from vnai.beam.quota import guardian, optimize
4
2
  from vnai.beam.metrics import collector, capture
5
3
  from vnai.beam.pulse import monitor
vnai/beam/metrics.py CHANGED
@@ -1,5 +1,3 @@
1
- # vnai/beam/metrics.py
2
-
3
1
  import sys
4
2
  import time
5
3
  import threading
@@ -8,211 +6,162 @@ import hashlib
8
6
  import json
9
7
 
10
8
  class Collector:
11
- """Collects operation metrics for system optimization"""
12
-
13
9
  _instance = None
14
10
  _lock = threading.Lock()
15
-
11
+
16
12
  def __new__(cls):
17
13
  with cls._lock:
18
14
  if cls._instance is None:
19
15
  cls._instance = super(Collector, cls).__new__(cls)
20
16
  cls._instance._initialize()
21
17
  return cls._instance
22
-
18
+
23
19
  def _initialize(self):
24
- """Initialize collector"""
25
- # Initialize metrics storage
26
20
  self.metrics = {
27
- "function": [],
28
- "rate_limit": [],
29
- "request": [],
30
- "error": []
21
+ "function": [],
22
+ "rate_limit": [],
23
+ "request": [],
24
+ "error": []
31
25
  }
32
- # Configuration thresholds
33
26
  self.thresholds = {
34
- "buffer_size": 50,
35
- "error_threshold": 0.1,
36
- "performance_threshold": 5.0
27
+ "buffer_size": 50,
28
+ "error_threshold": 0.1,
29
+ "performance_threshold": 5.0
37
30
  }
38
- # Tracking variables
39
31
  self.function_count = 0
40
32
  self.colab_auth_triggered = False
41
- self.max_metric_length = 200 # Keep only the latest 200 entries
42
- self._last_record_time = {} # Track last record time for throttling
43
- self.min_interval_per_type = 0.5 # Min interval between same type records
44
- self._recent_hashes = [] # Track recent hashes for deduplication
45
- self._sending_metrics = False # Prevent reentrancy in _send_metrics
46
-
47
- def record(self, metric_type, data, priority=None):
48
- """Record operation metrics with deduplication and throttling"""
33
+ self.max_metric_length = 200
34
+ self._last_record_time = {}
35
+ self.min_interval_per_type = 0.5
36
+ self._recent_hashes = []
37
+ self._sending_metrics = False
49
38
 
50
- # Ensure data is a dictionary
39
+ def record(self, metric_type, data, priority=None):
51
40
  if not isinstance(data, dict):
52
41
  data = {"value": str(data)}
53
-
54
- # Add timestamp if not present
55
- if "timestamp" not in data:
42
+ if"timestamp" not in data:
56
43
  data["timestamp"] = datetime.now().isoformat()
57
-
58
- # For non-system info, simplify and tag machine
59
- if metric_type != "system_info":
44
+ if metric_type !="system_info":
60
45
  data.pop("system", None)
61
46
  from vnai.scope.profile import inspector
62
47
  data["machine_id"] = inspector.fingerprint()
63
-
64
- # ==== THROTTLING ====
65
48
  now = time.time()
66
49
  last_time = self._last_record_time.get(metric_type, 0)
67
- if now - last_time < self.min_interval_per_type and priority != "high":
68
- return # Skip due to interval limit
50
+ if now - last_time < self.min_interval_per_type and priority !="high":
51
+ return
69
52
  self._last_record_time[metric_type] = now
70
-
71
- # ==== DEDUPLICATION ====
72
53
  data_hash = hashlib.md5(json.dumps(data, sort_keys=True).encode()).hexdigest()
73
- if data_hash in self._recent_hashes and priority != "high":
74
- return # Skip duplicate
54
+ if data_hash in self._recent_hashes and priority !="high":
55
+ return
75
56
  self._recent_hashes.append(data_hash)
76
-
77
- # ==== RECORD LOGIC ====
78
57
  if metric_type in self.metrics:
79
58
  self.metrics[metric_type].append(data)
80
- # Prune oldest if too long
81
59
  if len(self.metrics[metric_type]) > self.max_metric_length:
82
60
  self.metrics[metric_type] = self.metrics[metric_type][-self.max_metric_length:]
83
61
  else:
84
62
  self.metrics["function"].append(data)
85
-
86
- # Function metric tracking (Colab trigger)
87
- if metric_type == "function":
63
+ if metric_type =="function":
88
64
  self.function_count += 1
89
- if self.function_count > 10 and not self.colab_auth_triggered and 'google.colab' in sys.modules:
65
+ if self.function_count > 10 and not self.colab_auth_triggered and'google.colab' in sys.modules:
90
66
  self.colab_auth_triggered = True
91
67
  threading.Thread(target=self._trigger_colab_auth, daemon=True).start()
92
-
93
- # Auto-send triggers
94
68
  if sum(len(metric_list) for metric_list in self.metrics.values()) >= self.thresholds["buffer_size"]:
95
69
  self._send_metrics()
96
- if priority == "high" or metric_type == "error":
70
+ if priority =="high" or metric_type =="error":
97
71
  self._send_metrics()
98
-
72
+
99
73
  def _trigger_colab_auth(self):
100
- """Trigger Google Colab authentication in a background thread"""
101
74
  try:
102
75
  from vnai.scope.profile import inspector
103
76
  inspector.get_or_create_user_id()
104
77
  except:
105
- pass # Silently fail if there's an issue
106
-
78
+ pass
79
+
107
80
  def _send_metrics(self):
108
- """Send collected metrics to data relay"""
109
- # Prevent reentrancy
110
81
  if self._sending_metrics:
111
82
  return
112
-
113
83
  self._sending_metrics = True
114
84
  try:
115
- # Import here to avoid circular imports
116
85
  from vnai.flow.relay import track_function_call, track_rate_limit, track_api_request
117
86
  except ImportError:
118
- # If relay module is not available, clear metrics and return
119
87
  for metric_type in self.metrics:
120
88
  self.metrics[metric_type] = []
121
89
  self._sending_metrics = False
122
90
  return
123
-
124
- # Process and send each type of metric using the appropriate tracking function
125
91
  for metric_type, data_list in self.metrics.items():
126
92
  if not data_list:
127
93
  continue
128
-
129
- # Process each metric by type
130
94
  for data in data_list:
131
95
  try:
132
- if metric_type == "function":
133
- # Use the track_function_call interface
96
+ if metric_type =="function":
134
97
  track_function_call(
135
- function_name=data.get("function", "unknown"),
136
- source=data.get("source", "vnai"),
98
+ function_name=data.get("function","unknown"),
99
+ source=data.get("source","vnai"),
137
100
  execution_time=data.get("execution_time", 0),
138
101
  success=data.get("success", True),
139
102
  error=data.get("error"),
140
103
  args=data.get("args")
141
104
  )
142
- elif metric_type == "rate_limit":
143
- # Use the track_rate_limit interface
105
+ elif metric_type =="rate_limit":
144
106
  track_rate_limit(
145
- source=data.get("source", "vnai"),
146
- limit_type=data.get("limit_type", "unknown"),
107
+ source=data.get("source","vnai"),
108
+ limit_type=data.get("limit_type","unknown"),
147
109
  limit_value=data.get("limit_value", 0),
148
110
  current_usage=data.get("current_usage", 0),
149
111
  is_exceeded=data.get("is_exceeded", False)
150
112
  )
151
- elif metric_type == "request":
152
- # Use the track_api_request interface
113
+ elif metric_type =="request":
153
114
  track_api_request(
154
- endpoint=data.get("endpoint", "unknown"),
155
- source=data.get("source", "vnai"),
156
- method=data.get("method", "GET"),
115
+ endpoint=data.get("endpoint","unknown"),
116
+ source=data.get("source","vnai"),
117
+ method=data.get("method","GET"),
157
118
  status_code=data.get("status_code", 200),
158
119
  execution_time=data.get("execution_time", 0),
159
120
  request_size=data.get("request_size", 0),
160
121
  response_size=data.get("response_size", 0)
161
122
  )
162
123
  except Exception as e:
163
- # If tracking fails, just continue with the next item
164
124
  continue
165
-
166
- # Clear the processed metrics
167
125
  self.metrics[metric_type] = []
168
-
169
- # Reset sending flag
170
126
  self._sending_metrics = False
171
-
127
+
172
128
  def get_metrics_summary(self):
173
- """Get summary of collected metrics"""
174
129
  return {
175
130
  metric_type: len(data_list)
176
131
  for metric_type, data_list in self.metrics.items()
177
132
  }
178
-
179
- # Create singleton instance
180
133
  collector = Collector()
181
134
 
182
135
  def capture(module_type="function"):
183
- """Decorator to capture metrics for any function"""
184
136
  def decorator(func):
185
137
  def wrapper(*args, **kwargs):
186
138
  start_time = time.time()
187
139
  success = False
188
140
  error = None
189
-
190
141
  try:
191
142
  result = func(*args, **kwargs)
192
143
  success = True
193
144
  return result
194
145
  except Exception as e:
195
146
  error = str(e)
196
- # Log the error to metrics before re-raising
197
147
  collector.record("error", {
198
- "function": func.__name__,
199
- "error": error,
200
- "args": str(args)[:100] if args else None
148
+ "function": func.__name__,
149
+ "error": error,
150
+ "args": str(args)[:100] if args else None
201
151
  })
202
152
  raise
203
153
  finally:
204
154
  execution_time = time.time() - start_time
205
-
206
155
  collector.record(
207
156
  module_type,
208
157
  {
209
- "function": func.__name__,
210
- "execution_time": execution_time,
211
- "success": success,
212
- "error": error,
213
- "timestamp": datetime.now().isoformat(),
214
- "args": str(args)[:100] if args else None # Truncate for privacy
158
+ "function": func.__name__,
159
+ "execution_time": execution_time,
160
+ "success": success,
161
+ "error": error,
162
+ "timestamp": datetime.now().isoformat(),
163
+ "args": str(args)[:100] if args else None
215
164
  }
216
165
  )
217
166
  return wrapper
218
- return decorator
167
+ return decorator
vnai/beam/pulse.py CHANGED
@@ -1,108 +1,79 @@
1
- # vnai/beam/pulse.py
2
-
3
1
  import threading
4
2
  import time
5
3
  from datetime import datetime
6
4
 
7
5
  class Monitor:
8
- """Monitors system health and performance"""
9
-
10
6
  _instance = None
11
7
  _lock = threading.Lock()
12
-
8
+
13
9
  def __new__(cls):
14
10
  with cls._lock:
15
11
  if cls._instance is None:
16
12
  cls._instance = super(Monitor, cls).__new__(cls)
17
13
  cls._instance._initialize()
18
14
  return cls._instance
19
-
15
+
20
16
  def _initialize(self):
21
- """Initialize monitor"""
22
- self.health_status = "healthy"
17
+ self.health_status ="healthy"
23
18
  self.last_check = time.time()
24
- self.check_interval = 300 # seconds
19
+ self.check_interval = 300
25
20
  self.error_count = 0
26
21
  self.warning_count = 0
27
22
  self.status_history = []
28
-
29
- # Start background health check thread
30
23
  self._start_background_check()
31
-
24
+
32
25
  def _start_background_check(self):
33
- """Start background health check thread"""
34
26
  def check_health():
35
27
  while True:
36
28
  try:
37
29
  self.check_health()
38
30
  except:
39
- pass # Don't let errors stop the monitor
31
+ pass
40
32
  time.sleep(self.check_interval)
41
-
42
33
  thread = threading.Thread(target=check_health, daemon=True)
43
34
  thread.start()
44
-
35
+
45
36
  def check_health(self):
46
- """Check system health status"""
47
37
  from vnai.beam.metrics import collector
48
38
  from vnai.beam.quota import guardian
49
-
50
- # Record check time
51
39
  self.last_check = time.time()
52
-
53
- # Check metrics collector health
54
40
  metrics_summary = collector.get_metrics_summary()
55
41
  has_errors = metrics_summary.get("error", 0) > 0
56
-
57
- # Check resource usage
58
42
  resource_usage = guardian.usage()
59
- high_usage = resource_usage > 80 # Over 80% of rate limits
60
-
61
- # Determine health status
43
+ high_usage = resource_usage > 80
62
44
  if has_errors and high_usage:
63
- self.health_status = "critical"
45
+ self.health_status ="critical"
64
46
  self.error_count += 1
65
47
  elif has_errors or high_usage:
66
- self.health_status = "warning"
48
+ self.health_status ="warning"
67
49
  self.warning_count += 1
68
50
  else:
69
- self.health_status = "healthy"
70
-
71
- # Record health status
51
+ self.health_status ="healthy"
72
52
  self.status_history.append({
73
- "timestamp": datetime.now().isoformat(),
74
- "status": self.health_status,
75
- "metrics": metrics_summary,
76
- "resource_usage": resource_usage
53
+ "timestamp": datetime.now().isoformat(),
54
+ "status": self.health_status,
55
+ "metrics": metrics_summary,
56
+ "resource_usage": resource_usage
77
57
  })
78
-
79
- # Keep history limited to last 10 entries
80
58
  if len(self.status_history) > 10:
81
59
  self.status_history = self.status_history[-10:]
82
-
83
60
  return self.health_status
84
-
61
+
85
62
  def report(self):
86
- """Get health report"""
87
- # Ensure we have a fresh check if last one is old
88
63
  if time.time() - self.last_check > self.check_interval:
89
64
  self.check_health()
90
-
91
65
  return {
92
- "status": self.health_status,
93
- "last_check": datetime.fromtimestamp(self.last_check).isoformat(),
94
- "error_count": self.error_count,
95
- "warning_count": self.warning_count,
96
- "history": self.status_history[-3:], # Last 3 entries
66
+ "status": self.health_status,
67
+ "last_check": datetime.fromtimestamp(self.last_check).isoformat(),
68
+ "error_count": self.error_count,
69
+ "warning_count": self.warning_count,
70
+ "history": self.status_history[-3:],
97
71
  }
98
-
72
+
99
73
  def reset(self):
100
- """Reset health monitor"""
101
- self.health_status = "healthy"
74
+ self.health_status ="healthy"
102
75
  self.error_count = 0
103
76
  self.warning_count = 0
104
77
  self.status_history = []
105
78
  self.last_check = time.time()
106
-
107
- # Create singleton instance
108
- monitor = Monitor()
79
+ monitor = Monitor()