alex n
finalized colour changes
ae5716a
raw
history blame
8.27 kB
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
)