Update app.py
Browse files
app.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
import pandas as pd
|
| 3 |
from huggingface_hub import hf_hub_download
|
|
|
|
| 4 |
|
| 5 |
# --- Constants ---
|
| 6 |
REPO_ID = "DontPlanToEnd/UGI-Leaderboard"
|
|
@@ -14,7 +15,7 @@ def make_clickable_model(model_name, link):
|
|
| 14 |
|
| 15 |
def get_data():
|
| 16 |
"""
|
| 17 |
-
Downloads, processes, and returns the leaderboard
|
| 18 |
"""
|
| 19 |
print("π Starting download...")
|
| 20 |
try:
|
|
@@ -26,19 +27,22 @@ def get_data():
|
|
| 26 |
df = pd.read_csv(file_path, encoding='utf-8-sig')
|
| 27 |
df.columns = df.columns.str.strip()
|
| 28 |
|
| 29 |
-
# 3. Fuzzy Column Matching
|
| 30 |
def get_col(keyword):
|
| 31 |
matches = [c for c in df.columns if keyword.lower() in c.lower()]
|
| 32 |
return matches[0] if matches else None
|
| 33 |
|
| 34 |
-
#
|
| 35 |
-
model_col = get_col("author") or get_col("model")
|
| 36 |
-
link_col = get_col("link")
|
| 37 |
-
ugi_col = get_col("ugi")
|
| 38 |
-
natint_col = get_col("natint")
|
| 39 |
-
w10_col = get_col("w/10")
|
|
|
|
|
|
|
|
|
|
| 40 |
|
| 41 |
-
# 4. Check if we found
|
| 42 |
if not all([model_col, ugi_col, natint_col, w10_col]):
|
| 43 |
missing = []
|
| 44 |
if not model_col: missing.append("Model")
|
|
@@ -47,38 +51,43 @@ def get_data():
|
|
| 47 |
if not w10_col: missing.append("W/10")
|
| 48 |
return pd.DataFrame(), f"β Error: Could not find columns: {', '.join(missing)}. Found: {list(df.columns)}"
|
| 49 |
|
| 50 |
-
# 5.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
for col in [ugi_col, natint_col, w10_col]:
|
| 52 |
df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
|
| 53 |
|
| 54 |
-
#
|
| 55 |
-
# Formula: (UGI + NatInt) * (W/10
|
| 56 |
df['UGI Index'] = (df[ugi_col] + df[natint_col]) * (df[w10_col] ** 2)
|
| 57 |
df['UGI Index'] = df['UGI Index'].round(2)
|
| 58 |
|
| 59 |
-
# 7. Format Links
|
| 60 |
-
if link_col:
|
| 61 |
-
df[model_col] = df.apply(lambda x: make_clickable_model(x[model_col], x[link_col]), axis=1)
|
| 62 |
-
|
| 63 |
# 8. Sort and Rank
|
| 64 |
df = df.sort_values(by='UGI Index', ascending=False)
|
| 65 |
df.insert(0, 'Rank', range(1, len(df) + 1))
|
| 66 |
|
| 67 |
-
# 9.
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
df = df
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
final_df = df[display_cols]
|
| 80 |
-
|
| 81 |
-
return final_df, f"β
Successfully loaded {len(final_df)} models."
|
| 82 |
|
| 83 |
except Exception as e:
|
| 84 |
print(f"Error: {e}")
|
|
@@ -87,23 +96,32 @@ def get_data():
|
|
| 87 |
# Global cache for search to use
|
| 88 |
CACHED_DF = pd.DataFrame()
|
| 89 |
|
| 90 |
-
def
|
| 91 |
-
"""
|
| 92 |
-
global CACHED_DF
|
| 93 |
-
df, status = get_data()
|
| 94 |
-
CACHED_DF = df
|
| 95 |
-
return df, status
|
| 96 |
-
|
| 97 |
-
def search(query):
|
| 98 |
-
"""Filters the cached dataframe."""
|
| 99 |
if CACHED_DF.empty:
|
| 100 |
return CACHED_DF
|
| 101 |
|
| 102 |
-
|
| 103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
|
| 105 |
-
|
| 106 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
|
| 108 |
# --- UI ---
|
| 109 |
custom_css = """
|
|
@@ -114,29 +132,31 @@ footer {visibility: hidden}
|
|
| 114 |
with gr.Blocks(css=custom_css, title="UGI Index Leaderboard") as demo:
|
| 115 |
gr.Markdown("# π UGI Index")
|
| 116 |
|
| 117 |
-
#
|
| 118 |
gr.Markdown("""
|
| 119 |
### βΉοΈ How is the Score Calculated?
|
| 120 |
-
The **UGI Index** ranks LLMs based on data from [DontPlanToEnd/UGI-Leaderboard](https://huggingface.co/spaces/DontPlanToEnd/UGI-Leaderboard) with a simple holistic mathematical equation that ensures top ranked models posses a high amount of Uncensored Information, are Naturally very Intelligent, and most importantly they are OBEDIENT to the user.
|
| 121 |
|
| 122 |
-
$$ \\text{UGI Index} = (\\text{UGI} + \\text{NatInt}) \\times
|
| 123 |
|
| 124 |
* **UGI:** Uncensored General Intelligence
|
| 125 |
* **NatInt:** Natural Intelligence
|
| 126 |
-
* **W/10:** Willingness
|
|
|
|
|
|
|
| 127 |
""")
|
| 128 |
-
# ------------------------------------------
|
| 129 |
|
| 130 |
with gr.Row():
|
| 131 |
status_box = gr.Textbox(label="Status", value="Initializing...", interactive=False, scale=4)
|
| 132 |
refresh_btn = gr.Button("Refresh Data", scale=1)
|
| 133 |
|
| 134 |
with gr.Row():
|
| 135 |
-
search_box = gr.Textbox(label="Search Models", placeholder="Type model name...", interactive=True)
|
|
|
|
| 136 |
|
| 137 |
# Initialize with empty dataframe
|
| 138 |
data_table = gr.Dataframe(
|
| 139 |
-
headers=['Rank', 'Model', 'UGI Index', 'UGI', 'NatInt', 'W/10'],
|
| 140 |
datatype="markdown",
|
| 141 |
interactive=False,
|
| 142 |
wrap=True
|
|
@@ -144,13 +164,14 @@ with gr.Blocks(css=custom_css, title="UGI Index Leaderboard") as demo:
|
|
| 144 |
|
| 145 |
# Wire up events
|
| 146 |
# 1. On Load: Fetch data, update table and status
|
| 147 |
-
demo.load(fn=app_load, outputs=[data_table, status_box])
|
| 148 |
|
| 149 |
# 2. On Refresh: Fetch data again
|
| 150 |
-
refresh_btn.click(fn=app_load, outputs=[data_table, status_box])
|
| 151 |
|
| 152 |
-
# 3. On Search: Filter existing data
|
| 153 |
-
search_box.change(fn=search, inputs=search_box, outputs=data_table)
|
|
|
|
| 154 |
|
| 155 |
if __name__ == "__main__":
|
| 156 |
demo.launch()
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import pandas as pd
|
| 3 |
from huggingface_hub import hf_hub_download
|
| 4 |
+
import re
|
| 5 |
|
| 6 |
# --- Constants ---
|
| 7 |
REPO_ID = "DontPlanToEnd/UGI-Leaderboard"
|
|
|
|
| 15 |
|
| 16 |
def get_data():
|
| 17 |
"""
|
| 18 |
+
Downloads, processes, and returns the full leaderboard dataframe + status message.
|
| 19 |
"""
|
| 20 |
print("π Starting download...")
|
| 21 |
try:
|
|
|
|
| 27 |
df = pd.read_csv(file_path, encoding='utf-8-sig')
|
| 28 |
df.columns = df.columns.str.strip()
|
| 29 |
|
| 30 |
+
# 3. Exact & Fuzzy Column Matching
|
| 31 |
def get_col(keyword):
|
| 32 |
matches = [c for c in df.columns if keyword.lower() in c.lower()]
|
| 33 |
return matches[0] if matches else None
|
| 34 |
|
| 35 |
+
# Prioritize exact names from the CSV, fallback to fuzzy matching
|
| 36 |
+
model_col = "author/model_name" if "author/model_name" in df.columns else (get_col("author") or get_col("model"))
|
| 37 |
+
link_col = "Model Link" if "Model Link" in df.columns else get_col("link")
|
| 38 |
+
ugi_col = "UGI π" if "UGI π" in df.columns else get_col("ugi")
|
| 39 |
+
natint_col = "NatInt π‘" if "NatInt π‘" in df.columns else get_col("natint")
|
| 40 |
+
w10_col = "W/10 π" if "W/10 π" in df.columns else get_col("w/10")
|
| 41 |
+
|
| 42 |
+
# We need TOTAL parameters to accurately estimate the GGUF file size
|
| 43 |
+
param_col = "Total Parameters" if "Total Parameters" in df.columns else (get_col("param") or get_col("size"))
|
| 44 |
|
| 45 |
+
# 4. Check if we found required columns
|
| 46 |
if not all([model_col, ugi_col, natint_col, w10_col]):
|
| 47 |
missing = []
|
| 48 |
if not model_col: missing.append("Model")
|
|
|
|
| 51 |
if not w10_col: missing.append("W/10")
|
| 52 |
return pd.DataFrame(), f"β Error: Could not find columns: {', '.join(missing)}. Found: {list(df.columns)}"
|
| 53 |
|
| 54 |
+
# 5. Extract Parameter Size & Calculate Q4_K_M size
|
| 55 |
+
if param_col:
|
| 56 |
+
df['Params (B)'] = pd.to_numeric(df[param_col], errors='coerce').fillna(0)
|
| 57 |
+
else:
|
| 58 |
+
# Fallback: Extract from model name (e.g., "Llama-3-70B" -> 70)
|
| 59 |
+
df['Params (B)'] = df[model_col].astype(str).str.extract(r'(?i)(\d+\.?\d*)[bB]').astype(float).fillna(0)
|
| 60 |
+
|
| 61 |
+
# Q4_K_M size formula: Parameter count * 0.6 GB (e.g., 24B * 0.6 = 14.4 GB)
|
| 62 |
+
df['Q4_K_M Size (GB)'] = (df['Params (B)'] * 0.6).round(1)
|
| 63 |
+
|
| 64 |
+
# Friendly string representation for the UI
|
| 65 |
+
df['Q4_K_M Size'] = df['Q4_K_M Size (GB)'].apply(lambda x: f"{x} GB" if x > 0 else "API / Unknown")
|
| 66 |
+
|
| 67 |
+
# 6. Clean Numeric Data
|
| 68 |
for col in [ugi_col, natint_col, w10_col]:
|
| 69 |
df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
|
| 70 |
|
| 71 |
+
# 7. Calculate UGI Index (UPDATED LOGIC)
|
| 72 |
+
# Formula: (UGI + NatInt) * (W/10 ^ 2)
|
| 73 |
df['UGI Index'] = (df[ugi_col] + df[natint_col]) * (df[w10_col] ** 2)
|
| 74 |
df['UGI Index'] = df['UGI Index'].round(2)
|
| 75 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
# 8. Sort and Rank
|
| 77 |
df = df.sort_values(by='UGI Index', ascending=False)
|
| 78 |
df.insert(0, 'Rank', range(1, len(df) + 1))
|
| 79 |
|
| 80 |
+
# 9. Normalize display columns
|
| 81 |
+
if link_col:
|
| 82 |
+
df['Model'] = df.apply(lambda x: make_clickable_model(x[model_col], x[link_col]), axis=1)
|
| 83 |
+
else:
|
| 84 |
+
df['Model'] = df[model_col]
|
| 85 |
+
|
| 86 |
+
df['UGI'] = df[ugi_col]
|
| 87 |
+
df['NatInt'] = df[natint_col]
|
| 88 |
+
df['W/10'] = df[w10_col]
|
| 89 |
+
|
| 90 |
+
return df, f"β
Successfully loaded {len(df)} models."
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
except Exception as e:
|
| 93 |
print(f"Error: {e}")
|
|
|
|
| 96 |
# Global cache for search to use
|
| 97 |
CACHED_DF = pd.DataFrame()
|
| 98 |
|
| 99 |
+
def search(query, max_size):
|
| 100 |
+
"""Filters the cached dataframe by search query and Q4_K_M Size."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
if CACHED_DF.empty:
|
| 102 |
return CACHED_DF
|
| 103 |
|
| 104 |
+
df = CACHED_DF.copy()
|
| 105 |
+
|
| 106 |
+
# Text Filter
|
| 107 |
+
if query:
|
| 108 |
+
df = df[df['Model'].astype(str).str.contains(query, case=False, na=False)]
|
| 109 |
+
|
| 110 |
+
# Size Filter (128 is the arbitrary "Show All" max value)
|
| 111 |
+
if max_size < 128:
|
| 112 |
+
# Hide API models (Size == 0) and models that exceed the selected size
|
| 113 |
+
df = df[(df['Q4_K_M Size (GB)'] <= max_size) & (df['Q4_K_M Size (GB)'] > 0)]
|
| 114 |
|
| 115 |
+
display_cols = ['Rank', 'Model', 'Q4_K_M Size', 'UGI Index', 'UGI', 'NatInt', 'W/10']
|
| 116 |
+
return df[display_cols]
|
| 117 |
+
|
| 118 |
+
def app_load(query, max_size):
|
| 119 |
+
"""Called when app starts or refreshes."""
|
| 120 |
+
global CACHED_DF
|
| 121 |
+
df, status = get_data()
|
| 122 |
+
CACHED_DF = df
|
| 123 |
+
filtered_df = search(query, max_size)
|
| 124 |
+
return filtered_df, status
|
| 125 |
|
| 126 |
# --- UI ---
|
| 127 |
custom_css = """
|
|
|
|
| 132 |
with gr.Blocks(css=custom_css, title="UGI Index Leaderboard") as demo:
|
| 133 |
gr.Markdown("# π UGI Index")
|
| 134 |
|
| 135 |
+
# (UPDATED MARKDOWN FORMULA)
|
| 136 |
gr.Markdown("""
|
| 137 |
### βΉοΈ How is the Score Calculated?
|
| 138 |
+
The **UGI Index** ranks LLMs based on data from [DontPlanToEnd/UGI-Leaderboard](https://huggingface.co/spaces/DontPlanToEnd/UGI-Leaderboard) with a simple holistic mathematical equation that ensures top ranked models posses a high amount of Uncensored Information, are Naturally very Intelligent, and most importantly they are OBEDIENT to the user. This is just my personal "rule of thumb" method for choosing the best uncensored model for LOCAL use on any given hardware I have laying around. Ajust the slider to the amount of RAM on your device to see the best uncensored model for your hardware. It uses Q4_K_M as a refrence point for GGUF size, however there are tons of options so it can be flexable. If your brand new and just want to try a uncensored local LLM for the first time do this: Grab a **mradermacher** quant in **i1-IQ4_XS** and run with **LMstudio.ai**
|
| 139 |
|
| 140 |
+
$$ \\text{UGI Index} = (\\text{UGI} + \\text{NatInt}) \\times \\text{W/10}^2 $$
|
| 141 |
|
| 142 |
* **UGI:** Uncensored General Intelligence
|
| 143 |
* **NatInt:** Natural Intelligence
|
| 144 |
+
* **W/10:** Willingness (Squared)
|
| 145 |
+
|
| 146 |
+
*π‘ **Note on Model Size:** GGUF size is calculated at standard **Q4_K_M** quantization (`Total Parameters Γ 0.6 GB`). Lowering the slider automatically hides closed-source API models.*
|
| 147 |
""")
|
|
|
|
| 148 |
|
| 149 |
with gr.Row():
|
| 150 |
status_box = gr.Textbox(label="Status", value="Initializing...", interactive=False, scale=4)
|
| 151 |
refresh_btn = gr.Button("Refresh Data", scale=1)
|
| 152 |
|
| 153 |
with gr.Row():
|
| 154 |
+
search_box = gr.Textbox(label="Search Models", placeholder="Type model name...", interactive=True, scale=1)
|
| 155 |
+
size_slider = gr.Slider(minimum=1, maximum=128, value=128, step=1, label="π» Running Local? Max Q4_K_M Size (GB) - Set to 128 to include API models", interactive=True, scale=1)
|
| 156 |
|
| 157 |
# Initialize with empty dataframe
|
| 158 |
data_table = gr.Dataframe(
|
| 159 |
+
headers=['Rank', 'Model', 'Q4_K_M Size', 'UGI Index', 'UGI', 'NatInt', 'W/10'],
|
| 160 |
datatype="markdown",
|
| 161 |
interactive=False,
|
| 162 |
wrap=True
|
|
|
|
| 164 |
|
| 165 |
# Wire up events
|
| 166 |
# 1. On Load: Fetch data, update table and status
|
| 167 |
+
demo.load(fn=app_load, inputs=[search_box, size_slider], outputs=[data_table, status_box])
|
| 168 |
|
| 169 |
# 2. On Refresh: Fetch data again
|
| 170 |
+
refresh_btn.click(fn=app_load, inputs=[search_box, size_slider], outputs=[data_table, status_box])
|
| 171 |
|
| 172 |
+
# 3. On Search or Slider Change: Filter existing data
|
| 173 |
+
search_box.change(fn=search, inputs=[search_box, size_slider], outputs=data_table)
|
| 174 |
+
size_slider.change(fn=search, inputs=[search_box, size_slider], outputs=data_table)
|
| 175 |
|
| 176 |
if __name__ == "__main__":
|
| 177 |
demo.launch()
|