Spaces:
Runtime error
Runtime error
File size: 8,266 Bytes
06c9fc9 e5457b7 06c9fc9 2fce877 64fdbb7 ae5716a 2fce877 ae5716a e5457b7 32253ac e5457b7 32253ac e5457b7 32253ac 64fdbb7 e5457b7 64fdbb7 e5457b7 64fdbb7 e5457b7 64fdbb7 32253ac 64fdbb7 6b92fa1 32253ac 64fdbb7 6b92fa1 32253ac 64fdbb7 32253ac 64fdbb7 32253ac 64fdbb7 604a5b9 64fdbb7 604a5b9 64fdbb7 e5457b7 64fdbb7 e5457b7 604a5b9 64fdbb7 e5457b7 2fce877 b5adfa8 2fce877 791fbae b5adfa8 06c9fc9 64fdbb7 2fce877 b5adfa8 64fdbb7 32253ac 64fdbb7 e5457b7 b5adfa8 e5457b7 b5adfa8 e2ec4cf e5457b7 64fdbb7 e5457b7 64fdbb7 e5457b7 ae5716a e5457b7 64fdbb7 e5457b7 64fdbb7 e5457b7 ae5716a e5457b7 06c9fc9 e5457b7 32253ac e5457b7 32253ac e5457b7 32253ac e5457b7 32253ac e5457b7 06c9fc9 2fce877 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
import gradio as gr
import bittensor as bt
import requests
import pandas as pd
from apscheduler.schedulers.background import BackgroundScheduler
background_url2 = 'https://media.discordapp.net/attachments/1294437373773484093/1305702292774719569/80-_.png?ex=6733fd85&is=6732ac05&hm=f94d26610cc6c9d39318a102fb2484eae6ab83a64226eba3af81fbe305245fc2&=&format=webp&quality=lossless&width=717&height=414'
background_url = 'https://media.discordapp.net/attachments/1294437373773484093/1299205237877510184/p7zQRQMPb8W1qitaFl_C9_c6ef80e2981d4a27a53c3708de43bb44.jpg?ex=67336cea&is=67321b6a&hm=aaa1d39210d631d9f800802da8a869c71e395802574ae61bee6030671f53ef3c&=&format=webp'
# Enhanced Custom CSS
custom_css = """
#component-0 {
max-width: 100% !important;
padding: 0 !important;
margin: 0 !important;
}
.gradio-container {
max-width: 100% !important;
padding: 0 !important;
margin: 0 !important;
background-image: url('""" + background_url + """') !important;
background-size: cover !important;
background-position: center !important;
background-repeat: no-repeat !important;
min-height: 100vh !important;
}
"""
# Add error handling for bittensor initialization
try:
subtensor = bt.subtensor()
metagraph = bt.metagraph(netuid=36)
except Exception as e:
print(f"Failed to initialize bittensor: {e}")
subtensor = None
metagraph = None
def get_validator_data() -> pd.DataFrame:
if subtensor is None or metagraph is None:
# Return empty DataFrame with correct columns if initialization failed
return pd.DataFrame(columns=['Name', 'UID', 'Axon', 'API', 'Step', 'Recent Bits', 'Updated', 'VTrust'])
try:
validator_ids = list(set([i for i in range(len(metagraph.validator_permit))
if metagraph.validator_permit[i] and
metagraph.active[i] and
str(metagraph.axons[i].ip) != "0.0.0.0"]))
except Exception as e:
print(f"Error getting validator IDs: {e}")
validator_ids = []
current_block = subtensor.block
results = []
for uid in validator_ids:
validator_info = {
'Name': 'unavailable',
'UID': uid,
'Axon': 'unavailable',
'Step': 0,
'Recent Bits': 0,
'Updated': 0,
'VTrust': 0,
'API': 'β'
}
try:
# Get validator name
try:
identity = subtensor.substrate.query('SubtensorModule', 'Identities', [metagraph.coldkeys[uid]])
validator_info['Name'] = identity.value["name"] if identity != None else 'unnamed'
except Exception as e:
print(f"Error getting Name for UID {uid}: {str(e)}")
validator_info['Axon'] = f"{metagraph.axons[uid].ip}:{metagraph.axons[uid].port}"
# Get Step and Range from endpoints
try:
axon_endpoint = f"http://{validator_info['Axon']}"
step_response = requests.get(f"{axon_endpoint}/step", timeout=5)
step_response.raise_for_status()
validator_info['Step'] = step_response.json()
bits_response = requests.get(
f"{axon_endpoint}/bits",
headers={"range": "bytes=-1"},
timeout=5
)
bits_response.raise_for_status()
binary_string = ''.join(format(byte, '08b') for byte in bits_response.content)
validator_info['Recent Bits'] = binary_string[-8:]
validator_info['API'] = '<span class="api-status api-up">β
</span>' if bits_response.ok else '<span class="api-status api-down">β</span>'
except requests.Timeout:
print(f"Timeout while connecting to {axon_endpoint}")
except Exception as e:
print(f"Error connecting to {axon_endpoint}: {e}")
try:
last_update = int(metagraph.last_update[uid])
validator_info['Updated'] = current_block - last_update
except Exception as e:
print(f"Error getting Updated for UID {uid}: {str(e)}")
try:
validator_info['VTrust'] = float(metagraph.validator_trust[uid])
except Exception as e:
print(f"Error getting VTrust for UID {uid}: {str(e)}")
except Exception as e:
print(f"Error getting Axon for UID {uid}: {str(e)}")
results.append(validator_info)
df = pd.DataFrame(results)
df['VTrust'] = df['VTrust'].round(4)
return df.sort_values('Step', ascending=False)[['Name', 'UID', 'Axon', 'API', 'Step', 'Recent Bits', 'Updated', 'VTrust']]
# Create the Gradio interface with custom theme
app = gr.Blocks(
title="SN36 Validator Leaderboard",
css=custom_css,
theme=gr.themes.Soft().set(
body_background_fill="rgba(17, 24, 39, 0.95)",
background_fill_secondary="rgba(17, 24, 39, 0.95)",
)
)
# Update the HTML template
header_html = """
<div style="text-align: center; max-width: 100%; padding: 1rem; background-color: #1f2937; border-radius: 1rem;">
<h1 style="color: white;">SN36 Validator Leaderboard</h1>
<p style="color: white;">Real-time tracking of validator performance and bits</p>
</div>
"""
with app:
gr.HTML(header_html)
with gr.Tabs(elem_id="main-tabs"):
with gr.Tab("π Leaderboard", elem_id="leaderboard-tab"):
leaderboard = gr.DataFrame(
headers=["Name", "UID", "Axon", "API", "Step", "Recent Bits", "Updated", "VTrust"],
datatype=["str", "number", "str", "html", "number", "str", "number", "number"],
elem_id="leaderboard-table",
render=True
)
with gr.Row(equal_height=True):
refresh_button = gr.Button("π Refresh Data", variant="primary", elem_classes=["refresh-btn"])
auto_refresh = gr.Checkbox(
label="Auto-refresh (5 min)",
value=True,
interactive=True
)
status_message = gr.Markdown("Last updated: Never", elem_classes=["status-msg"])
with gr.Tab("βΉοΈ About"):
gr.Markdown(
"""
<div style="color: white;">
## About this Leaderboard
This dashboard shows real-time information about validators on the network:
- **Name**: Validator's registered name on the network
- **UID**: Unique identifier of the validator
- **Axon**: Validator's Axon address (IP:port)
- **API**: API status (β
online, β offline)
- **Step**: Current step count (0 if unavailable)
- **Range**: Validator's bit range (0 if unavailable)
- **Updated**: Blocks since last update (0 if unavailable)
- **VTrust**: Validator's trust score (0 if unavailable)
Data is automatically refreshed every 5 minutes, or you can manually refresh using the button.
</div>
"""
)
def update_leaderboard():
df = get_validator_data()
timestamp = pd.Timestamp.now().strftime("%Y-%m-%d %H:%M:%S UTC")
return df, f"Last updated: {timestamp}"
refresh_button.click(
fn=update_leaderboard,
outputs=[leaderboard, status_message],
queue=False
)
# Auto-refresh logic
def setup_auto_refresh():
app.scheduler = BackgroundScheduler()
app.scheduler.add_job(
lambda: app.queue(update_leaderboard),
'interval',
minutes=5
)
app.scheduler.start()
# Initial data load
app.load(
fn=update_leaderboard,
outputs=[leaderboard, status_message]
)
setup_auto_refresh()
# Launch the interface with file serving enabled
app.launch(
share=False
) |