File size: 6,064 Bytes
478332b
 
 
 
 
 
b8e14a1
0765653
9f4a5ad
 
 
b8e14a1
9f4a5ad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b8e14a1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0765653
b8e14a1
 
478332b
 
0765653
 
 
 
 
 
 
ff2df59
0765653
 
 
 
 
 
9f4a5ad
478332b
 
 
 
 
 
 
9f4a5ad
 
 
478332b
9f4a5ad
478332b
9f4a5ad
478332b
9f4a5ad
b8e14a1
478332b
9f4a5ad
b8e14a1
b761223
 
b8e14a1
 
 
 
9f4a5ad
7ca82d7
b8e14a1
 
9f4a5ad
478332b
9f4a5ad
b8e14a1
 
478332b
 
9f4a5ad
 
 
b8e14a1
9f4a5ad
7bf2513
e9fd2ea
b8e14a1
 
 
 
9f4a5ad
 
 
 
b8e14a1
 
 
 
9f4a5ad
 
b8e14a1
 
9f4a5ad
b8e14a1
9f4a5ad
 
 
 
 
 
 
 
 
 
b8e14a1
9f4a5ad
b8e14a1
9f4a5ad
 
b8e14a1
9f4a5ad
b8e14a1
 
 
478332b
 
 
b8e14a1
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
"""
Streamlit dashboard for the Dippy Roleplay Subnet Leaderboard
"""
import requests
import streamlit as st
import pandas as pd
import numpy as np

st.set_page_config(layout="wide")

REMOTE_LEADERBOARD_URL = "https://dippy-bittensor-subnet.com/minerboard"

def iswin(score_i, score_j, block_i, block_j):
    MAX_PENALTY = 0.03  # Adjust this value as needed
    penalty = MAX_PENALTY
    score_i = (1 - penalty) * score_i if block_i > block_j else score_i
    score_j = (1 - penalty) * score_j if block_j > block_i else score_j
    return score_i > score_j

def calculate_win_rate(df):
    n = len(df)
    win_counts = np.zeros(n)
    
    for i in range(n):
        for j in range(n):
            if i != j:
                if iswin(df.loc[i, 'total_score'], df.loc[j, 'total_score'],
                         df.loc[i, 'block'], df.loc[j, 'block']):
                    win_counts[i] += 1
    
    return win_counts / (n - 1)  # Divide by (n-1) as each row isn't compared with itself

def apply_block_threshold_mutation(df, block_threshold):
    """
    Apply mutation to rows where block is less than the threshold.
    Changes total_score, judge_score, and notes columns for these rows.
    
    Args:
        df: DataFrame to modify
        block_threshold: Rows with block value less than this will be modified
    
    Returns:
        Modified DataFrame
    """
    # Create a copy to avoid modifying the original DataFrame
    modified_df = df.copy()
    
    # Identify rows where block is less than the threshold
    mask = modified_df['block'] < block_threshold
    
    # Apply mutations to these rows
    if mask.any():
        modified_df.loc[mask, 'total_score'] = 0.0  # Set total_score to 0
        modified_df.loc[mask, 'judge_score'] = 0.0  # Set judge_score to 0
        modified_df.loc[mask, 'notes'] = "Scoring reset"

    
    return modified_df

def leaderboard_dashboard():
    # load the logo from image.txt file as base64
    with open("image.txt", "r") as f:
        image = f.read()

    st.markdown(
        f"""
        <div style="text-align: center;">
            <img src="data:image/png;base64,{image}" alt="Dippy Roleplay Logo" width="600" height="300" style="margin-bottom: 2rem;">
            <h1 style="margin-top: 0;">SN11-Dippy-Roleplay Leaderboard</h1>
            <div style="font-size: 18px;">This is the leaderboard for the Dippy validation API hosted by SN11.</div>
        </div>
        """,
        unsafe_allow_html=True,
    )
    
    # Add emojis based on the status
    status_emojis = {
        'COMPLETED': '✅COMPLETED',
        'FAILED': '❌FAILED',
        'QUEUED': '🕒QUEUED',
        'RUNNING': '🏃RUNNING'
    }
    
    # Get the minerboard data from the API
    response = requests.get(REMOTE_LEADERBOARD_URL)
    if response.status_code != 200:
        st.error("Failed to fetch minerboard data.")
        return

    # Parse the response JSON data
    minerboard_data = response.json()

    # Convert the data to a DataFrame
    minerboard = pd.DataFrame(minerboard_data)
    
    # Set FAILED entries to have total_score as 0
    minerboard.loc[minerboard['status'] == 'FAILED', 'total_score'] = 0
    block_threshold = 5207777
    # Apply block threshold mutation
    minerboard = apply_block_threshold_mutation(minerboard, block_threshold)
    
    minerboard['status'] = minerboard['status'].map(lambda status: status_emojis.get(status, status))
    minerboard['total_score'] = minerboard['judge_score']
    
    # Sort the minerboard by the total_score column
    minerboard = minerboard.sort_values(by='total_score', ascending=False, ignore_index=True)

    front_order = ['uid', 'hotkey', 'total_score', 'status', 'chat_template_type', 'hash']
    if 'notes' in minerboard.columns:
        front_order.append('notes')

    # move status column to the front
    column_order = front_order + [column for column in minerboard.columns if column not in front_order]
    minerboard = minerboard[column_order]
    
    # Win rate calculation
    minerboard_winrate = pd.DataFrame(minerboard_data)
    minerboard_winrate['total_score'] = minerboard_winrate['judge_score']
    minerboard_winrate.loc[minerboard_winrate['status'] == 'FAILED', 'total_score'] = 0
    
    # Apply block threshold mutation to winrate dataframe too
    minerboard_winrate = apply_block_threshold_mutation(minerboard_winrate, block_threshold)
    
    minerboard_winrate['status'] = minerboard_winrate['status'].map(lambda status: status_emojis.get(status, status))
    minerboard_winrate['win_rate'] = calculate_win_rate(minerboard_winrate)
    minerboard_winrate = minerboard_winrate.sort_values(by='win_rate', ascending=False, ignore_index=True)
            
    column_order = ['uid', 'win_rate', 'hotkey', 'repo_namespace', 'repo_name', 'total_score', 'block', 'judge_score']
    if 'notes' in minerboard_winrate.columns:
        column_order.append('notes')
    
    # Create a new DataFrame with only the specified columns
    minerboard_winrate = minerboard_winrate[column_order]
    
    st.header("Leaderboard by Win Rate")
    st.dataframe(minerboard_winrate, hide_index=True)
    
    with st.expander("See detailed calculation method"):
        st.write("The win rate is calculated by comparing each miner against every other miner. Note that this board is only an approximation as queued miners have a score of 0, validators are omitted, etc.")
        st.code("""
    Example of calculating a win:
    def iswin(score_i, score_j, block_i, block_j):
        penalty = 0.03
        score_i = (1 - penalty) * score_i if block_i > block_j else score_i
        score_j = (1 - penalty) * score_j if block_j > block_i else score_j
        return score_i > score_j
    """)
    
    st.markdown("---")
    
    st.header("Minerboard")
    st.dataframe(minerboard, hide_index=True)
    
    st.markdown("---")
    
    if block_threshold > 0:
        st.info(f"Note: Entries with block values below {block_threshold} have had their scores set to 0.")


if __name__ == '__main__':
    leaderboard_dashboard()