alex n commited on
Commit
f909ba9
·
1 Parent(s): cbf3f1e

fixed website added better requirements file

Browse files
Files changed (2) hide show
  1. app.py +250 -244
  2. requirements.txt +117 -3
app.py CHANGED
@@ -1,270 +1,276 @@
1
  import gradio as gr
2
  import pandas as pd
3
- import bittensor as bt
4
- import requests
5
- from apscheduler.schedulers.background import BackgroundScheduler
 
6
 
7
- # 1. Define data functions first
8
- def get_validator_data() -> pd.DataFrame:
9
- if subtensor is None or metagraph is None:
10
- return pd.DataFrame(columns=['Name', 'UID', 'Axon', 'API', 'Step', 'Recent Bits', 'Updated', 'VTrust'])
11
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  try:
13
- validator_ids = list(set([i for i in range(len(metagraph.validator_permit))
14
- if metagraph.validator_permit[i] and
15
- metagraph.active[i] and
16
- str(metagraph.axons[i].ip) != "0.0.0.0"]))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  except Exception as e:
18
- print(f"Error getting validator IDs: {e}")
19
- validator_ids = []
 
 
 
 
 
 
20
 
21
- current_block = subtensor.block
22
  results = []
23
 
24
- for uid in validator_ids:
25
- validator_info = {
26
- 'Name': 'unavailable',
27
- 'UID': uid,
28
- 'Axon': 'unavailable',
29
- 'Step': 0,
30
- 'Recent Bits': 0,
31
- 'Updated': 0,
32
- 'VTrust': 0,
33
- 'API': '❌'
34
- }
35
-
36
- try:
37
- # Get validator name
38
- try:
39
- identity = subtensor.substrate.query('SubtensorModule', 'Identities', [metagraph.coldkeys[uid]])
40
- validator_info['Name'] = identity.value["name"] if identity != None else 'unnamed'
41
- except Exception as e:
42
- print(f"Error getting Name for UID {uid}: {str(e)}")
43
-
44
- validator_info['Axon'] = f"{metagraph.axons[uid].ip}:{metagraph.axons[uid].port}"
45
-
46
- # Get Step and Range from endpoints
47
- try:
48
- axon_endpoint = f"http://{validator_info['Axon']}"
49
- step_response = requests.get(f"{axon_endpoint}/step", timeout=(2, 3))
50
- step_response.raise_for_status()
51
- validator_info['Step'] = step_response.json()
52
-
53
- bits_response = requests.get(
54
- f"{axon_endpoint}/bits",
55
- headers={"range": "bytes=-1"},
56
- timeout=(2, 3)
57
- )
58
- bits_response.raise_for_status()
59
- binary_string = ''.join(format(byte, '08b') for byte in bits_response.content)
60
- validator_info['Recent Bits'] = binary_string[-8:]
61
- validator_info['API'] = '<span class="api-status api-up">✅</span>' if bits_response.ok else '<span class="api-status api-down">❌</span>'
62
-
63
- except requests.Timeout:
64
- validator_info['API'] = '<span class="api-status api-down">❌</span>'
65
- except Exception as e:
66
- if not isinstance(e, requests.Timeout):
67
- print(f"Error connecting to {axon_endpoint}: {str(e)}")
68
- validator_info['API'] = '<span class="api-status api-down">❌</span>'
69
-
70
- try:
71
- last_update = int(metagraph.last_update[uid])
72
- validator_info['Updated'] = current_block - last_update
73
- except Exception as e:
74
- print(f"Error getting Updated for UID {uid}: {str(e)}")
75
 
76
- try:
77
- validator_info['VTrust'] = float(metagraph.validator_trust[uid])
78
- except Exception as e:
79
- print(f"Error getting VTrust for UID {uid}: {str(e)}")
80
-
81
- except Exception as e:
82
- print(f"Error getting Axon for UID {uid}: {str(e)}")
83
 
 
 
 
 
 
 
 
 
 
 
84
  results.append(validator_info)
85
 
86
  df = pd.DataFrame(results)
87
  df['VTrust'] = df['VTrust'].round(4)
88
- return df.sort_values('Step', ascending=False)[['Name', 'UID', 'Axon', 'API', 'Step', 'Recent Bits', 'Updated', 'VTrust']]
89
 
90
- # 2. Initialize bittensor and load data
91
- try:
92
- subtensor = bt.subtensor()
93
- metagraph = bt.metagraph(netuid=36)
94
- initial_df = get_validator_data()
95
- initial_timestamp = pd.Timestamp.now().strftime("%Y-%m-%d %H:%M:%S UTC")
96
- print("✅ Data loaded successfully")
97
- except Exception as e:
98
- print(f"❌ Failed to initialize: {e}")
99
- initial_df = pd.DataFrame()
100
- initial_timestamp = "Failed to load initial data"
101
-
102
- # 3. Then CSS and UI components
103
- background_url = "https://cdn-lfs.hf.co/repos/a4/b4/a4b48e51a6a5ebd9414fc6798da9acf09a6a9425ea160334a1a81c4ad3fdb801/7f89926e2018d54403ac1dc8b0d6fe2401a6489d7da11df27259a07cde7acf87?response-content-disposition=inline%3B+filename*%3DUTF-8%27%27background2.png%3B+filename%3D%22background2.png%22%3B&response-content-type=image%2Fpng&Expires=1731722075&Policy=eyJTdGF0ZW1lbnQiOlt7IkNvbmRpdGlvbiI6eyJEYXRlTGVzc1RoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTczMTcyMjA3NX19LCJSZXNvdXJjZSI6Imh0dHBzOi8vY2RuLWxmcy5oZi5jby9yZXBvcy9hNC9iNC9hNGI0OGU1MWE2YTVlYmQ5NDE0ZmM2Nzk4ZGE5YWNmMDlhNmE5NDI1ZWExNjAzMzRhMWE4MWM0YWQzZmRiODAxLzdmODk5MjZlMjAxOGQ1NDQwM2FjMWRjOGIwZDZmZTI0MDFhNjQ4OWQ3ZGExMWRmMjcyNTlhMDdjZGU3YWNmODc%7EcmVzcG9uc2UtY29udGVudC1kaXNwb3NpdGlvbj0qJnJlc3BvbnNlLWNvbnRlbnQtdHlwZT0qIn1dfQ__&Signature=Y9KvhLMB7xHfQUnq2RC4rMDegTBzbqoMiHAIJzVKy%7E7ajPw2p-AQ19KCYCaXPNbElSV7PZowowMOS%7EtK98A7SM4ndHDePx3OcD%7EDNP8w150rLj58XeCZuVSZ32ayv%7Eb6nZEwYjUbrtrFboN5T9HG8xezW7BgmcXzV3iHppgSNu%7EnwKwJvorVr%7EyddXC6AMsAjsYKYOl1AxnkiMiIKeoD7Rd4ZaAlQsbqAC31BfnbSkBfPq4g0HlCiQYvYsxoofyLsGslnx9X5yIPaYRIRz3uJibPwDZg6GCEYViOfKWwiWV74iA1ptt2DeWLSxBRkjRfnv-HMAs25GmMjqyF85o8vA__&Key-Pair-Id=K3RPWS32NSSJCE"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  custom_css = """
105
- #component-0 {
106
- max-width: 100% !important;
107
- padding: 0 !important;
108
- margin: 0 !important;
109
- }
110
-
111
- .gradio-container {
112
- max-width: 100% !important;
113
- padding: 0 !important;
114
- margin: 0 !important;
115
- background-image: url('""" + background_url + """') !important;
116
- background-size: cover !important;
117
- background-position: center !important;
118
- background-repeat: no-repeat !important;
119
- min-height: 100vh !important;
120
- }
121
-
122
- .header-box {
123
- text-align: center;
124
- max-width: 100%;
125
- margin: 20px auto;
126
- padding: 1rem;
127
- background-color: rgba(17, 24, 39, 0.95); /* Darker, more opaque background */
128
- border-radius: 1rem;
129
- }
130
-
131
- .header-box h1 {
132
- color: white;
133
- margin: 0;
134
- font-size: 2rem;
135
- }
136
-
137
- .header-box p {
138
- color: white; /* Changed to white instead of gray */
139
- margin-top: 0.5rem;
140
- }
141
- """
142
 
143
- # Data functions first
144
- def fetch_data():
145
- # your data fetching logic
146
- pass
 
 
 
147
 
148
- def create_leaderboard():
149
- try:
150
- data = fetch_data()
151
- if not data:
152
- return pd.DataFrame()
153
- return data
154
- except Exception as e:
155
- print(f"Error creating leaderboard: {e}")
156
- return pd.DataFrame()
157
 
158
- def update_data():
159
- try:
160
- data = create_leaderboard()
161
- error_msg = ""
162
- success = True
163
- except Exception as e:
164
- data = pd.DataFrame()
165
- error_msg = f"Error loading data: {str(e)}"
166
- success = False
167
- return data, error_msg, not success
168
-
169
- # Add this before creating the app
170
- header_html = """
171
- <div class="header-box">
172
- <h1>SN36 Validator Leaderboard</h1>
173
- <p>Real-time validator status monitoring</p>
174
- </div>
175
- """
176
 
177
- # UI components last
178
- # Create the Gradio interface with custom theme
179
- app = gr.Blocks(
180
- title="SN36 Validator Leaderboard",
181
- css=custom_css,
182
- theme=gr.themes.Soft().set(
183
- body_background_fill="rgba(17, 24, 39, 0.95)",
184
- background_fill_secondary="rgba(17, 24, 39, 0.95)",
185
- )
186
- )
187
 
188
- with app:
189
- gr.HTML(header_html)
190
-
191
- with gr.Tabs(elem_id="main-tabs"):
192
- with gr.Tab("📊 Leaderboard", elem_id="leaderboard-tab"):
193
- # Initialize with preloaded data
194
- leaderboard = gr.DataFrame(
195
- value=initial_df,
196
- headers=["Name", "UID", "Axon", "API", "Step", "Recent Bits", "Updated", "VTrust"],
197
- datatype=["str", "number", "str", "html", "number", "str", "number", "number"],
198
- elem_id="leaderboard-table",
199
- render=True
200
- )
201
-
202
- # Initialize with preloaded timestamp
203
- status_message = gr.Markdown(
204
- value=f"Last updated: {initial_timestamp}",
205
- elem_classes=["status-msg"]
206
- )
207
-
208
- with gr.Row(equal_height=True):
209
- refresh_button = gr.Button("🔄 Refresh Data", variant="primary", elem_classes=["refresh-btn"])
210
- auto_refresh = gr.Checkbox(
211
- label="Auto-refresh (5 min)",
212
- value=True,
213
- interactive=True
214
- )
215
-
216
- with gr.Tab("ℹ️ About"):
217
- gr.Markdown(
218
- """
219
- <div style="color: white;">
220
- ## About this Leaderboard
221
-
222
- This dashboard shows real-time information about validators on the network:
223
-
224
- - **Name**: Validator's registered name on the network
225
- - **UID**: Unique identifier of the validator
226
- - **Axon**: Validator's Axon address (IP:port)
227
- - **API**: API status (✅ online, ❌ offline)
228
- - **Step**: Current step count (0 if unavailable)
229
- - **Range**: Validator's bit range (0 if unavailable)
230
- - **Updated**: Blocks since last update (0 if unavailable)
231
- - **VTrust**: Validator's trust score (0 if unavailable)
232
-
233
- Data is automatically refreshed every 5 minutes, or you can manually refresh using the button.
234
- </div>
235
- """
236
- )
237
-
238
- def update_leaderboard():
239
- df = get_validator_data()
240
- timestamp = pd.Timestamp.now().strftime("%Y-%m-%d %H:%M:%S UTC")
241
- return df, f"Last updated: {timestamp}"
242
-
243
- refresh_button.click(
244
- fn=update_leaderboard,
245
- outputs=[leaderboard, status_message],
246
- queue=False
247
- )
248
 
249
- # Auto-refresh logic
250
- def setup_auto_refresh():
251
- app.scheduler = BackgroundScheduler()
252
- app.scheduler.add_job(
253
- lambda: app.queue(update_leaderboard),
254
- 'interval',
255
- minutes=5
256
- )
257
- app.scheduler.start()
 
 
 
258
 
259
- # Initial data load
260
- app.load(
261
- fn=update_leaderboard,
262
- outputs=[leaderboard, status_message]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
  )
264
 
265
- setup_auto_refresh()
 
 
 
 
 
 
 
266
 
267
- # Launch the interface with file serving enabled
268
- app.launch(
269
- share=False
270
- )
 
1
  import gradio as gr
2
  import pandas as pd
3
+ from concurrent.futures import ThreadPoolExecutor
4
+ from datetime import datetime, timedelta
5
+ from math import ceil
6
+ from typing import TypeAlias, Optional, Tuple
7
 
8
+ import aiohttp
9
+ import asyncio
10
+
11
+ from fiber.chain.interface import get_substrate
12
+ from fiber.chain.metagraph import Metagraph
13
+ from fiber.chain.models import Node
14
+ from substrateinterface.storage import StorageKey
15
+
16
+ Weight: TypeAlias = float
17
+ Hotkey: TypeAlias = str
18
+ Uid: TypeAlias = int
19
+
20
+ NET_UID = 36
21
+ VALIDATOR_IDENTITIES: dict[Hotkey, str] = {}
22
+ UPDATED: dict[Hotkey, int] = {}
23
+ UIDS_BY_HOTKEY: dict[Hotkey, Uid] = {}
24
+ HOTKEYS_BY_UID: dict[Uid, Hotkey] = {}
25
+
26
+ substrate = get_substrate()
27
+ metagraph = Metagraph(substrate, netuid=NET_UID, load_old_nodes=False)
28
+
29
+ def query_subtensor(storage_keys: list[StorageKey], block: int) -> list:
30
+ global substrate
31
  try:
32
+ return substrate.query_multi(
33
+ storage_keys=storage_keys,
34
+ block_hash=substrate.get_block_hash(block),
35
+ )
36
+ except Exception:
37
+ substrate = get_substrate()
38
+ raise
39
+
40
+ def is_validator(node: Node) -> bool:
41
+ if not hasattr(node, 'vtrust') or not hasattr(node, 'ip'):
42
+ return False
43
+ return node.vtrust > 0 and str(node.ip) != "0.0.0.0"
44
+
45
+ def fetch_updated(block: int):
46
+ UPDATED.clear()
47
+ for hotkey, node in metagraph.nodes.items():
48
+ UPDATED[hotkey] = ceil(block - node.last_updated)
49
+
50
+ def fetch_identities(block: int):
51
+ VALIDATOR_IDENTITIES.clear()
52
+ storage_keys: list[StorageKey] = []
53
+ for hotkey, node in metagraph.nodes.items():
54
+ if not is_validator(node): continue
55
+ storage_keys.append(substrate.create_storage_key(
56
+ "SubtensorModule",
57
+ "Identities",
58
+ [node.coldkey]
59
+ ))
60
+
61
+ identities = query_subtensor(storage_keys, block)
62
+ for hotkey, node in metagraph.nodes.items():
63
+ for storage, info in identities:
64
+ if node.coldkey != storage.params[0]: continue
65
+ if info is not None:
66
+ VALIDATOR_IDENTITIES[hotkey] = info.value["name"]
67
+ break
68
+
69
+ async def fetch_validator_stats(session: aiohttp.ClientSession, ip: str) -> Tuple[Optional[int], Optional[str], bool]:
70
+ try:
71
+ # Fetch current step (in bits)
72
+ step_url = f"http://{ip}/step"
73
+ async with session.get(step_url, timeout=5) as resp:
74
+ if resp.status == 200:
75
+ step = await resp.json()
76
+ byte_pos = step // 8
77
+ byte_range = f"bytes={byte_pos}-{byte_pos}"
78
+ print(f"Got step {step}, using range: {byte_range}")
79
+ else:
80
+ print(f"Failed to get step from {ip}: {resp.status}")
81
+ return None, None, False
82
+
83
+ # Get byte at step position
84
+ bits_url = f"http://{ip}/bits"
85
+ headers = {'Range': byte_range}
86
+ async with session.get(bits_url, headers=headers, timeout=5) as resp:
87
+ if resp.status == 206:
88
+ bytes_data = await resp.read()
89
+ if bytes_data:
90
+ last_byte = format(bytes_data[0], '08b')
91
+ print(f"Got byte from {ip}: {last_byte}")
92
+ return step, last_byte, True
93
+ else:
94
+ print(f"No byte data from {ip}")
95
+ return None, None, False
96
+ else:
97
+ print(f"Failed byte request for {ip}: {resp.status}")
98
+ return None, None, False
99
+
100
  except Exception as e:
101
+ print(f"Error for {ip}: {str(e)}")
102
+ return None, None, False
103
+
104
+ async def fetch_all_validators(ips: list[str]) -> dict[str, Tuple[Optional[int], Optional[str], bool]]:
105
+ async with aiohttp.ClientSession() as session:
106
+ tasks = [fetch_validator_stats(session, ip) for ip in ips]
107
+ results = await asyncio.gather(*tasks)
108
+ return dict(zip(ips, results))
109
 
110
+ def get_validator_data() -> pd.DataFrame:
111
  results = []
112
 
113
+ ips = [f"{node.ip}:{node.port}" for hotkey, node in metagraph.nodes.items()
114
+ if is_validator(node)]
115
+
116
+ stats = asyncio.run(fetch_all_validators(ips))
117
+
118
+ for hotkey, node in metagraph.nodes.items():
119
+ if not is_validator(node):
120
+ continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
+ ip = f"{node.ip}:{node.port}"
123
+ step, last_byte, api_up = stats.get(ip, (None, None, False))
 
 
 
 
 
124
 
125
+ validator_info = {
126
+ 'Name': VALIDATOR_IDENTITIES.get(hotkey, 'unnamed'),
127
+ 'UID': UIDS_BY_HOTKEY.get(hotkey, -1),
128
+ 'VTrust': float(node.vtrust),
129
+ 'IP': ip,
130
+ 'API': '✅' if api_up else '❌',
131
+ 'Step': step if step is not None else 'N/A',
132
+ 'Last Byte': last_byte if last_byte is not None else 'N/A',
133
+ 'Updated': UPDATED.get(hotkey, 0)
134
+ }
135
  results.append(validator_info)
136
 
137
  df = pd.DataFrame(results)
138
  df['VTrust'] = df['VTrust'].round(4)
139
+ return df.sort_values('VTrust', ascending=False)
140
 
141
+ # Sync logic
142
+ last_sync: datetime = datetime.fromtimestamp(0)
143
+ last_identity_sync: datetime = datetime.fromtimestamp(0)
144
+
145
+ def sync_metagraph(timeout: int = 10):
146
+ global substrate, last_sync
147
+ now = datetime.now()
148
+ if now - last_sync < timedelta(minutes=5):
149
+ return
150
+ last_sync = now
151
+
152
+ def sync_task():
153
+ print("Syncing metagraph...")
154
+ block = substrate.get_block_number(None)
155
+ metagraph.sync_nodes()
156
+
157
+ for uid, node in enumerate(metagraph.nodes.values()):
158
+ UIDS_BY_HOTKEY[node.hotkey] = uid
159
+ HOTKEYS_BY_UID[uid] = node.hotkey
160
+
161
+ fetch_updated(block)
162
+
163
+ global last_identity_sync
164
+ if now - last_identity_sync > timedelta(hours=1):
165
+ print("Syncing identities...")
166
+ last_identity_sync = now
167
+ fetch_identities(block)
168
+
169
+ with ThreadPoolExecutor(max_workers=1) as executor:
170
+ future = executor.submit(sync_task)
171
+ try:
172
+ future.result(timeout=timeout)
173
+ except Exception as e:
174
+ print(f"Error syncing metagraph: {e}")
175
+ substrate = get_substrate()
176
+
177
+ # Create Gradio interface
178
  custom_css = """
179
+ :root {
180
+ --primary: #2A4365; /* Base blue */
181
+ --primary-light: #3B5C8F; /* Lighter blue for hover states */
182
+ --primary-dark: #1A2F4C; /* Darker blue for backgrounds */
183
+ --primary-fade: #4A6285; /* Faded blue for secondary elements */
184
+ --text-primary: #EDF2F7; /* Light gray for main text */
185
+ --text-secondary: #CBD5E0; /* Darker gray for secondary text */
186
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
+ .gradio-container {
189
+ background-image: url('https://huggingface.co/spaces/wombo/pyramid-scheme-validator-states/resolve/main/assets/background2.png') !important;
190
+ background-size: cover !important;
191
+ background-position: center !important;
192
+ background-attachment: fixed !important;
193
+ min-height: 100vh !important;
194
+ }
195
 
196
+ /* Style the table */
197
+ .table-wrap {
198
+ background-color: var(--primary) !important;
199
+ border-radius: 8px !important;
200
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
201
+ opacity: 0.95 !important; /* Slight transparency to show background */
202
+ }
 
 
203
 
204
+ /* Style the table headers */
205
+ thead tr th {
206
+ background-color: var(--primary-fade) !important;
207
+ color: var(--text-primary) !important;
208
+ font-weight: 600 !important;
209
+ border-bottom: 2px solid var(--primary-light) !important;
210
+ }
 
 
 
 
 
 
 
 
 
 
 
211
 
212
+ /* Style table cells */
213
+ tbody tr td {
214
+ color: var(--text-primary) !important;
215
+ border-bottom: 1px solid var(--primary-light) !important;
216
+ }
 
 
 
 
 
217
 
218
+ /* Alternating row colors */
219
+ tbody tr:nth-child(even) {
220
+ background-color: var(--primary-dark) !important;
221
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
 
223
+ /* Row hover effect */
224
+ tbody tr:hover {
225
+ background-color: var(--primary-light) !important;
226
+ }
227
+
228
+ /* Style the refresh button */
229
+ button.primary {
230
+ background-color: var(--primary) !important;
231
+ color: var(--text-primary) !important;
232
+ border: 1px solid var(--primary-light) !important;
233
+ transition: all 0.2s ease !important;
234
+ }
235
 
236
+ button.primary:hover {
237
+ background-color: var(--primary-light) !important;
238
+ transform: translateY(-1px) !important;
239
+ }
240
+
241
+ /* Style the title */
242
+ h1 {
243
+ color: var(--text-primary) !important;
244
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
245
+ }
246
+ """
247
+
248
+ with gr.Blocks(title="📊 SN36 Validator States", css=custom_css) as demo:
249
+ gr.Markdown("""
250
+ <h1 style="text-align: center; font-size: 3em; margin: 0.5em 0;">
251
+ 📊 SN36 Validator States
252
+ </h1>
253
+ """, elem_id="title")
254
+
255
+ # Initialize table with empty DataFrame
256
+ sync_metagraph() # Initial sync
257
+ initial_df = get_validator_data()
258
+
259
+ table = gr.DataFrame(
260
+ value=initial_df,
261
+ headers=['Name', 'UID', 'VTrust', 'IP', 'API', 'Step', 'Last Byte', 'Updated'],
262
+ datatype=['str', 'number', 'number', 'str', 'str', 'str', 'str', 'number'],
263
+ interactive=False
264
  )
265
 
266
+ refresh_btn = gr.Button("Refresh")
267
+
268
+ def update():
269
+ sync_metagraph()
270
+ return get_validator_data()
271
+
272
+ refresh_btn.click(fn=update, outputs=table)
273
+ demo.load(fn=update, outputs=table)
274
 
275
+ if __name__ == "__main__":
276
+ demo.launch(share=False, debug=True, allowed_paths=["assets"])
 
 
requirements.txt CHANGED
@@ -1,5 +1,119 @@
1
- gradio==5.4.0
2
- fastapi==0.110.1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  pandas>=2.2.3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  requests>=2.32.3
5
- apscheduler==3.10.4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fiber @ git+https://github.com/rayonlabs/fiber.git@1.0.0#egg=fiber[chain]
2
+ aiofiles>=23.2.1
3
+ aiohappyeyeballs>=2.4.3
4
+ aiohttp>=3.10.11
5
+ aiosignal>=1.3.1
6
+ annotated-types>=0.7.0
7
+ ansible>=6.7.0
8
+ ansible-core>=2.13.13
9
+ ansible-vault>=2.1.0
10
+ anyio>=4.6.2.post1
11
+ async-property>=0.2.2
12
+ async-timeout>=5.0.1
13
+ attrs>=24.2.0
14
+ backoff>=2.2.1
15
+ base58>=2.1.1
16
+ bittensor>=8.2.1
17
+ bittensor-cli>=8.3.1
18
+ bittensor-wallet>=2.1.1
19
+ bt-decode>=0.2.0a0
20
+ certifi>=2024.8.30
21
+ cffi>=1.17.1
22
+ charset-normalizer>=3.4.0
23
+ click>=8.1.7
24
+ colorama>=0.4.6
25
+ cryptography>=43.0.3
26
+ cytoolz>=1.0.0
27
+ decorator>=5.1.1
28
+ ecdsa>=0.19.0
29
+ eth-hash>=0.7.0
30
+ eth-keys>=0.6.0
31
+ eth-typing>=5.0.0
32
+ eth-utils>=2.2.2
33
+ exceptiongroup>=1.2.2
34
+ fastapi>=0.110.3
35
+ ffmpy>=0.4.0
36
+ fiber>=1.0.0
37
+ filelock>=3.16.1
38
+ frozenlist>=1.5.0
39
+ fsspec>=2024.10.0
40
+ fuzzywuzzy>=0.18.0
41
+ gitdb>=4.0.11
42
+ GitPython>=3.1.43
43
+ gradio>=5.1.0
44
+ gradio_client>=1.4.0
45
+ h11>=0.14.0
46
+ httpcore>=1.0.7
47
+ httpx>=0.27.2
48
+ huggingface-hub>=0.26.2
49
+ idna>=3.10
50
+ iniconfig>=2.0.0
51
+ Jinja2>=3.1.4
52
+ Levenshtein>=0.26.1
53
+ markdown-it-py>=3.0.0
54
+ MarkupSafe>=2.1.5
55
+ mdurl>=0.1.2
56
+ more-itertools>=10.5.0
57
+ msgpack>=1.1.0
58
+ msgpack-numpy-opentensor>=0.5.0
59
+ multidict>=6.1.0
60
+ munch>=2.5.0
61
+ nest-asyncio>=1.6.0
62
+ netaddr>=1.3.0
63
+ numpy>=2.0.2
64
+ orjson>=3.10.11
65
+ packaging>=24.2
66
  pandas>=2.2.3
67
+ password-strength>=0.0.3.post2
68
+ pillow>=10.4.0
69
+ pluggy>=1.5.0
70
+ propcache>=0.2.0
71
+ py>=1.11.0
72
+ py-bip39-bindings>=0.1.11
73
+ py-ed25519-zebra-bindings>=1.1.0
74
+ py-sr25519-bindings>=0.2.1
75
+ pycparser>=2.22
76
+ pycryptodome>=3.21.0
77
+ pydantic>=2.9.2
78
+ pydantic_core>=2.23.4
79
+ pydub>=0.25.1
80
+ Pygments>=2.18.0
81
+ PyNaCl>=1.5.0
82
+ pytest>=8.3.3
83
+ python-dateutil>=2.9.0.post0
84
+ python-dotenv>=1.0.1
85
+ python-Levenshtein>=0.26.1
86
+ python-multipart>=0.0.17
87
+ python-statemachine>=2.4.0
88
+ pytz>=2024.2
89
+ PyYAML>=6.0.2
90
+ RapidFuzz>=3.10.1
91
  requests>=2.32.3
92
+ resolvelib>=0.8.1
93
+ retry>=0.9.2
94
+ rich>=13.9.4
95
+ ruff>=0.7.4
96
+ scalecodec>=1.2.11
97
+ semantic-version>=2.10.0
98
+ shellingham>=1.5.4
99
+ six>=1.16.0
100
+ smmap>=5.0.1
101
+ sniffio>=1.3.1
102
+ starlette>=0.37.2
103
+ substrate-interface>=1.7.10
104
+ tenacity>=9.0.0
105
+ termcolor>=2.5.0
106
+ toml>=0.10.0
107
+ tomli>=2.1.0
108
+ tomlkit>=0.12.0
109
+ toolz>=1.0.0
110
+ tqdm>=4.67.0
111
+ typer>=0.13.1
112
+ typing_extensions>=4.12.2
113
+ tzdata>=2024.2
114
+ urllib3>=2.2.3
115
+ uvicorn>=0.32.1
116
+ websocket-client>=1.8.0
117
+ websockets>=12.0
118
+ xxhash>=3.5.0
119
+ yarl>=1.18.0