KarlQuant commited on
Commit
6578cff
Β·
verified Β·
1 Parent(s): a41e1f5

Upload 2 files

Browse files
Files changed (2) hide show
  1. http_diagnostic.py +250 -0
  2. test_websocket.py +165 -0
http_diagnostic.py ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ QUASAR Hub HTTP Diagnostic β€” Check metrics without WebSocket
4
+
5
+ This is the FASTEST way to diagnose what's happening.
6
+ No wscat, no WebSocket needed β€” just HTTP polling.
7
+
8
+ Usage:
9
+ python3 http_diagnostic.py [--watch]
10
+ """
11
+
12
+ import json
13
+ import sys
14
+ import time
15
+ import requests
16
+ from datetime import datetime
17
+
18
+ def get_hub_state(hub_url: str = "http://127.0.0.1:7860"):
19
+ """Fetch current hub state."""
20
+ try:
21
+ resp = requests.get(f"{hub_url}/api/state", timeout=2)
22
+ resp.raise_for_status()
23
+ return resp.json()
24
+ except requests.exceptions.ConnectionError:
25
+ return None
26
+ except Exception as e:
27
+ print(f"[!] Error: {e}")
28
+ return None
29
+
30
+
31
+ def get_hub_health(hub_url: str = "http://127.0.0.1:7860"):
32
+ """Fetch hub health."""
33
+ try:
34
+ resp = requests.get(f"{hub_url}/api/health", timeout=2)
35
+ resp.raise_for_status()
36
+ return resp.json()
37
+ except Exception:
38
+ return None
39
+
40
+
41
+ def format_value(key: str, value):
42
+ """Format metric value with color coding."""
43
+ if "loss" in key.lower():
44
+ # Green if decreasing (< 0.5), red if high (> 0.7), yellow otherwise
45
+ if isinstance(value, (int, float)):
46
+ if value < 0.3:
47
+ return f"🟒 {value:.4f}"
48
+ elif value > 0.7:
49
+ return f"πŸ”΄ {value:.4f}"
50
+ else:
51
+ return f"🟑 {value:.4f}"
52
+ elif "accuracy" in key.lower():
53
+ if isinstance(value, (int, float)):
54
+ if value > 0.7:
55
+ return f"🟒 {value:.4f}"
56
+ elif value < 0.3:
57
+ return f"πŸ”΄ {value:.4f}"
58
+ else:
59
+ return f"🟑 {value:.4f}"
60
+ elif isinstance(value, float):
61
+ return f"{value:.6f}"
62
+
63
+ return str(value)
64
+
65
+
66
+ def print_diagnostic(hub_url: str = "http://127.0.0.1:7860"):
67
+ """Print a complete diagnostic report."""
68
+ print("\n" + "=" * 70)
69
+ print(f"QUASAR Hub Diagnostic β€” {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
70
+ print("=" * 70)
71
+
72
+ # Check health
73
+ print("\n[1] HUB HEALTH")
74
+ print("-" * 70)
75
+ health = get_hub_health(hub_url)
76
+ if not health:
77
+ print(f"βœ— Hub not responding at {hub_url}")
78
+ print(" Try: curl http://127.0.0.1:7860/api/health")
79
+ return False
80
+
81
+ print(f"βœ“ Hub is online")
82
+ print(f" Status: {health.get('status', '?')}")
83
+ print(f" Service: {health.get('service', '?')}")
84
+ print(f" Spaces connected: {health.get('spaces_connected', 0)}")
85
+ print(f" Messages RX: {health.get('messages_rx', 0)}")
86
+ print(f" Uptime: {health.get('uptime_seconds', 0):.0f}s")
87
+
88
+ # Get state
89
+ print("\n[2] ASSET RANKINGS")
90
+ print("-" * 70)
91
+ state = get_hub_state(hub_url)
92
+ if not state:
93
+ print("βœ— Could not fetch state")
94
+ return False
95
+
96
+ rankings = state.get("rankings", [])
97
+ if not rankings:
98
+ print("⚠ NO ASSETS CONNECTED YET")
99
+ print(" β†’ Asset spaces need to connect and send metrics")
100
+ print(" β†’ Check if asset spaces are running")
101
+ return False
102
+
103
+ print(f"βœ“ {len(rankings)} assets connected\n")
104
+
105
+ # Show each asset
106
+ for i, asset in enumerate(rankings[:8], 1):
107
+ name = asset.get("space_name", "?")
108
+ print(f"{i}. {name}")
109
+
110
+ training = asset.get("training", {})
111
+ voting = asset.get("voting", {})
112
+
113
+ # Training metrics
114
+ actor_loss = training.get("actor_loss", 0)
115
+ avn_acc = training.get("avn_accuracy", 0)
116
+ training_steps = training.get("training_steps", 0)
117
+
118
+ print(f" Training: {training_steps:5d} steps")
119
+ print(f" Actor Loss: {format_value('actor_loss', actor_loss)} (expect < 0.3)")
120
+ print(f" AVN Acc: {format_value('avn_accuracy', avn_acc)} (expect > 0.7)")
121
+
122
+ # Voting metrics
123
+ buy = voting.get("buy_count", 0)
124
+ sell = voting.get("sell_count", 0)
125
+ signal = voting.get("dominant_signal", "?")
126
+
127
+ print(f" Signal: {signal} ({buy}B / {sell}S)")
128
+
129
+ # Check if metrics are being updated
130
+ last_updated = asset.get("last_updated", 0)
131
+ if last_updated:
132
+ age = time.time() - last_updated
133
+ if age < 10:
134
+ print(f" βœ“ Updated {age:.0f}s ago")
135
+ else:
136
+ print(f" ⚠ Stale ({age:.0f}s old) β€” space may have disconnected")
137
+
138
+ print()
139
+
140
+ # Metric history
141
+ print("[3] METRIC HISTORY")
142
+ print("-" * 70)
143
+ history = state.get("metric_history", {})
144
+ if history:
145
+ print(f"βœ“ Collecting metric history for {len(history)} assets")
146
+ for name, points in list(history.items())[:3]:
147
+ if points:
148
+ latest = points[-1]
149
+ print(f" {name}: {len(points)} data points (latest: {latest})")
150
+ else:
151
+ print("⚠ No metric history yet")
152
+ print(" β†’ Metrics will be recorded once spaces send non-zero values")
153
+
154
+ print("\n" + "=" * 70)
155
+ print("DIAGNOSIS")
156
+ print("=" * 70)
157
+
158
+ if not rankings:
159
+ print("""
160
+ ❌ PROBLEM: No assets connected to hub
161
+ β†’ Asset spaces need to connect to ws://hub:7860/ws/publish/{name}
162
+ β†’ Check if asset spaces are running and have correct hub URL
163
+ β†’ Check firewall/network rules allow port 7860
164
+ """)
165
+ return False
166
+
167
+ # Check for zero metrics
168
+ has_nonzero_metrics = False
169
+ for asset in rankings:
170
+ training = asset.get("training", {})
171
+ if training.get("actor_loss", 0) != 0 or training.get("avn_accuracy", 0) != 0:
172
+ has_nonzero_metrics = True
173
+ break
174
+
175
+ if not has_nonzero_metrics:
176
+ print("""
177
+ ⚠ WARNING: Assets connected but no training metrics being sent
178
+ β†’ Asset spaces are sending voting data but NOT training metrics
179
+ β†’ They need to include "training" field with loss/accuracy
180
+ β†’ Expected format:
181
+ {
182
+ "training": {
183
+ "actor_loss": 0.234,
184
+ "critic_loss": 0.567,
185
+ "avn_loss": 0.123,
186
+ "avn_accuracy": 0.87
187
+ }
188
+ }
189
+ """)
190
+ return False
191
+
192
+ print("""
193
+ βœ… EVERYTHING LOOKS GOOD!
194
+ β†’ Assets are connected
195
+ β†’ Training metrics are flowing
196
+ β†’ Dashboard should display metrics in real-time
197
+ """)
198
+ return True
199
+
200
+
201
+ def watch_mode(hub_url: str = "http://127.0.0.1:7860", interval: int = 5):
202
+ """Continuously monitor hub state."""
203
+ print(f"[*] Watching hub at {hub_url} (update every {interval}s)")
204
+ print(" Press Ctrl+C to stop\n")
205
+
206
+ iteration = 0
207
+ try:
208
+ while True:
209
+ iteration += 1
210
+ print(f"\n{'='*70}")
211
+ print(f"Update #{iteration} β€” {datetime.now().strftime('%H:%M:%S')}")
212
+ print(f"{'='*70}\n")
213
+
214
+ state = get_hub_state(hub_url)
215
+ if not state:
216
+ print("βœ— Hub not responding")
217
+ break
218
+
219
+ rankings = state.get("rankings", [])
220
+ print(f"Connected: {len(rankings)} assets\n")
221
+
222
+ for asset in rankings[:5]:
223
+ name = asset.get("space_name", "?")
224
+ training = asset.get("training", {})
225
+ voting = asset.get("voting", {})
226
+
227
+ actor_loss = training.get("actor_loss", 0)
228
+ avn_acc = training.get("avn_accuracy", 0)
229
+
230
+ # Simple bar graph
231
+ loss_bar = "β–ˆ" * int(actor_loss * 10) + "β–‘" * (10 - int(actor_loss * 10))
232
+ acc_bar = "β–ˆ" * int(avn_acc * 10) + "β–‘" * (10 - int(avn_acc * 10))
233
+
234
+ print(f"{name:15} | Loss: [{loss_bar}] {actor_loss:.3f}")
235
+ print(f"{'':15} | Acc: [{acc_bar}] {avn_acc:.3f}\n")
236
+
237
+ time.sleep(interval)
238
+
239
+ except KeyboardInterrupt:
240
+ print("\n[*] Stopped.")
241
+
242
+
243
+ if __name__ == "__main__":
244
+ watch = "--watch" in sys.argv
245
+
246
+ if watch:
247
+ watch_mode()
248
+ else:
249
+ success = print_diagnostic()
250
+ sys.exit(0 if success else 1)
test_websocket.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ WebSocket Test Client β€” Monitor what the hub is broadcasting
4
+ No external dependencies beyond websockets (already installed)
5
+
6
+ Usage:
7
+ python3 test_websocket.py [--subscribe|--publish] [--space ASSET_NAME]
8
+ """
9
+
10
+ import asyncio
11
+ import json
12
+ import sys
13
+ import websockets
14
+ from datetime import datetime
15
+
16
+ async def test_subscribe(hub_url: str):
17
+ """Listen to what the hub is broadcasting."""
18
+ print(f"[*] Connecting to hub subscriber at {hub_url}/ws/subscribe")
19
+
20
+ try:
21
+ async with websockets.connect(f"{hub_url}/ws/subscribe") as ws:
22
+ print(f"[βœ“] Connected! Listening for metrics updates...\n")
23
+
24
+ count = 0
25
+ while True:
26
+ try:
27
+ msg = await asyncio.wait_for(ws.recv(), timeout=10.0)
28
+ count += 1
29
+ data = json.loads(msg)
30
+
31
+ ts = datetime.now().strftime("%H:%M:%S")
32
+ print(f"[{ts}] Message #{count}:")
33
+ print(f" {json.dumps(data, indent=2)}\n")
34
+
35
+ except asyncio.TimeoutError:
36
+ print("[!] No messages received for 10 seconds...")
37
+ print(" β†’ Asset spaces may not be connected yet")
38
+ sys.exit(1)
39
+
40
+ except Exception as e:
41
+ print(f"[βœ—] Connection failed: {e}")
42
+ print(f" Make sure hub is running and accessible at {hub_url}")
43
+ sys.exit(1)
44
+
45
+
46
+ async def test_publish(hub_url: str, space_name: str):
47
+ """Send a test metric to the hub."""
48
+ print(f"[*] Connecting to hub publisher for space: {space_name}")
49
+
50
+ test_message = {
51
+ "training": {
52
+ "training_steps": 9999,
53
+ "actor_loss": 0.123,
54
+ "critic_loss": 0.456,
55
+ "avn_loss": 0.789,
56
+ "avn_accuracy": 0.95,
57
+ },
58
+ "voting": {
59
+ "dominant_signal": "BUY",
60
+ "buy_count": 42,
61
+ "sell_count": 18,
62
+ }
63
+ }
64
+
65
+ try:
66
+ uri = f"{hub_url}/ws/publish/{space_name}"
67
+ print(f"[*] Connecting to {uri}")
68
+
69
+ async with websockets.connect(uri) as ws:
70
+ print(f"[βœ“] Connected! Sending test message...")
71
+ await ws.send(json.dumps(test_message))
72
+ print(f"[βœ“] Sent:\n{json.dumps(test_message, indent=2)}")
73
+
74
+ # Keep connection open for 5 seconds
75
+ print(f"[*] Keeping connection open for 5 seconds...")
76
+ await asyncio.sleep(5)
77
+ print(f"[βœ“] Done!")
78
+
79
+ except Exception as e:
80
+ print(f"[βœ—] Error: {e}")
81
+ sys.exit(1)
82
+
83
+
84
+ async def main():
85
+ # Default hub URL (adjust if needed)
86
+ hub_url = "ws://127.0.0.1:7860"
87
+
88
+ if len(sys.argv) > 1:
89
+ if "--subscribe" in sys.argv:
90
+ print("=" * 60)
91
+ print("QUASAR Hub WebSocket Monitor (Subscribe Mode)")
92
+ print("=" * 60)
93
+ await test_subscribe(hub_url)
94
+
95
+ elif "--publish" in sys.argv:
96
+ space_name = "TEST_ASSET"
97
+ if "--space" in sys.argv:
98
+ idx = sys.argv.index("--space")
99
+ if idx + 1 < len(sys.argv):
100
+ space_name = sys.argv[idx + 1]
101
+
102
+ print("=" * 60)
103
+ print(f"QUASAR Hub WebSocket Test (Publish Mode)")
104
+ print("=" * 60)
105
+ await test_publish(hub_url, space_name)
106
+ else:
107
+ print_usage()
108
+ else:
109
+ print_usage()
110
+
111
+
112
+ def print_usage():
113
+ print("""
114
+ ╔════════════════════════════════════════════════════════════════╗
115
+ β•‘ QUASAR WebSocket Test Tool v1.0 β•‘
116
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
117
+
118
+ USAGE:
119
+ # Monitor what hub is broadcasting (metrics from all spaces)
120
+ python3 test_websocket.py --subscribe
121
+
122
+ # Send a test metric to hub (publish as a space)
123
+ python3 test_websocket.py --publish --space TEST_ASSET
124
+
125
+ # Send test metrics with a different space name
126
+ python3 test_websocket.py --publish --space V100_1h
127
+
128
+ EXAMPLE WORKFLOW:
129
+
130
+ Terminal 1 (Monitor hub):
131
+ $ python3 test_websocket.py --subscribe
132
+ [βœ“] Connected! Listening for metrics updates...
133
+
134
+ Terminal 2 (Send test data):
135
+ $ python3 test_websocket.py --publish --space V100_1h
136
+ [βœ“] Connected! Sending test message...
137
+ [βœ“] Sent:
138
+ {
139
+ "training": {...},
140
+ "voting": {...}
141
+ }
142
+
143
+ Terminal 1 (should see the message):
144
+ [12:34:56] Message #1:
145
+ {
146
+ "space_name": "V100_1h",
147
+ "training": {...},
148
+ "voting": {...}
149
+ }
150
+
151
+ TROUBLESHOOTING:
152
+
153
+ "Connection refused" β†’ Hub not running on port 7860
154
+ $ curl http://127.0.0.1:7860/api/health
155
+
156
+ No messages on subscribe β†’ Asset spaces not connected
157
+ Check if asset spaces are running and sending data
158
+
159
+ "Module not found: websockets" β†’ Install it
160
+ $ pip install websockets
161
+ """)
162
+
163
+
164
+ if __name__ == "__main__":
165
+ asyncio.run(main())