salihfurkaan's picture
Refine dark professional UI with stronger contrast and polished hero section
a811ad0
Raw
History Blame Contribute Delete
21.2 kB
import gradio as gr
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import numpy as np
from scipy.stats import zipfian
from huggingface_hub import HfApi
import requests
import json
import logging
from typing import Dict, Optional, Tuple, List
# --- Configuration & Styling ---
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)
CUSTOM_CSS = """
:root {
color-scheme: dark;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
background: radial-gradient(circle at top, #020611 0%, #08101f 32%, #0b1426 100%);
color: #e2e8f0;
}
.gradio-container {
max-width: 1340px;
margin: 0 auto;
padding: 2rem 1.25rem 2.5rem;
color: #e2e8f0;
}
.gradio-container,
.gradio-container .gr-block,
.gradio-container .gr-row,
.gradio-container .gr-column,
.gradio-container .gr-box,
.gradio-container .gr-panel {
color: #e2e8f0 !important;
background: transparent !important;
}
.hero-banner {
border-radius: 28px;
padding: 2.75rem 2.5rem;
background: rgba(15, 23, 42, 0.96);
border: 1px solid rgba(148, 163, 184, 0.12);
box-shadow: 0 30px 90px rgba(15, 23, 42, 0.42);
margin-bottom: 1.8rem;
}
.hero-banner h1,
.hero-banner p,
.hero-banner .hero-pill {
color: #f8fafc !important;
}
.hero-banner h1 {
margin: 0;
font-size: clamp(2.8rem, 3vw, 4.2rem);
line-height: 1.02;
letter-spacing: -0.04em;
}
.hero-banner p {
margin: 1rem 0 0;
max-width: 760px;
color: rgba(226, 232, 240, 0.88);
font-size: 1.05rem;
line-height: 1.75;
}
.hero-pill {
display: inline-flex;
align-items: center;
padding: 0.55rem 0.95rem;
border-radius: 999px;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.12);
color: rgba(226, 232, 240, 0.85);
font-size: 0.92rem;
font-weight: 600;
margin-top: 1rem;
}
.panel-card,
.dashboard-card {
border-radius: 22px;
background: rgba(15, 23, 42, 0.9);
border: 1px solid rgba(148, 163, 184, 0.14);
box-shadow: 0 22px 55px rgba(15, 23, 42, 0.26);
padding: 2rem;
color: #e2e8f0;
}
.panel-card {
margin-bottom: 1.5rem;
}
.panel-card h3,
.dashboard-card h3 {
margin-top: 0;
font-size: 1.45rem;
letter-spacing: -0.02em;
color: #f8fafc !important;
}
.panel-card p,
.dashboard-card p,
.panel-card li,
.dashboard-card li,
.gradio-container .gr-markdown,
.gradio-container .gr-html {
color: #cbd5e1 !important;
line-height: 1.75;
}
.status-success,
.status-warning,
.status-error {
border-left: 4px solid transparent !important;
background: rgba(15, 23, 42, 0.92) !important;
border: 1px solid rgba(148, 163, 184, 0.12) !important;
}
.status-success {
border-left-color: #22c55e !important;
color: #d1fae5 !important;
}
.status-warning {
border-left-color: #f59e0b !important;
color: #fde68a !important;
}
.status-error {
border-left-color: #ef4444 !important;
color: #fecaca !important;
}
.status-success h3,
.status-warning h3,
.status-error h3 {
margin-bottom: 0.75rem !important;
}
.status-success p,
.status-warning p,
.status-error p {
margin: 0 !important;
line-height: 1.75 !important;
}
.metric-val {
font-family: 'JetBrains Mono', monospace;
font-weight: 700;
font-size: 1.35rem;
color: #e2e8f0;
letter-spacing: 0.02em;
}
.gradio-container .gr-button,
.gradio-container .gr-button:hover,
.gradio-container .gr-button:focus {
border-radius: 999px !important;
padding: 1rem 1.75rem !important;
font-weight: 700 !important;
transition: all 0.25s ease !important;
}
.gradio-container .gr-button.primary {
background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%) !important;
color: #ffffff !important;
box-shadow: 0 18px 40px rgba(67, 56, 202, 0.28) !important;
border: none !important;
}
.gradio-container .gr-button.primary:hover {
background: linear-gradient(135deg, #4f46e5 0%, #4338ca 100%) !important;
}
.gradio-container .gr-button.secondary {
background: rgba(255, 255, 255, 0.06) !important;
border: 1px solid rgba(255, 255, 255, 0.12) !important;
color: #e2e8f0 !important;
}
.gradio-container input[type="text"],
.gradio-container textarea,
.gradio-container select,
.gradio-container .gr-slider,
.gradio-container .gr-dropdown,
.gradio-container .gr-radio,
.gradio-container .gr-checkbox {
border-radius: 18px !important;
border: 1px solid rgba(148, 163, 184, 0.22) !important;
box-shadow: inset 0 1px 2px rgba(255, 255, 255, 0.05) !important;
color: #e2e8f0 !important;
background: rgba(15, 23, 42, 0.95) !important;
}
.gradio-container label,
.gradio-container .gr-label {
color: #e2e8f0 !important;
font-weight: 700 !important;
}
.gradio-container .gr-tabs {
margin-top: 1rem !important;
}
.gradio-container .gr-tabs .gr-tab {
background: transparent !important;
}
.gradio-container .gr-tabs .gr-tab--selected {
background: rgba(255, 255, 255, 0.06) !important;
border-bottom: 2px solid #6366f1 !important;
}
.gradio-container .gr-block {
gap: 1.5rem !important;
}
"""
class ModelProfiler:
"""Core logic engine for model architectural and resource profiling."""
def __init__(self):
self.api = HfApi()
self.session = requests.Session()
def fetch_config(self, repo_id: str, filename: str = "config.json") -> Optional[Dict]:
try:
# Construct direct URL to HuggingFace Hub
url = f"https://huggingface.co/{repo_id}/resolve/main/{filename}"
resp = self.session.get(url, timeout=15)
if resp.status_code == 200:
return resp.json()
else:
logging.error(f"HTTP {resp.status_code} fetching {filename} from {repo_id}: {url}")
return None
except requests.exceptions.Timeout:
logging.error(f"Timeout fetching {filename} from {repo_id}")
return None
except requests.exceptions.ConnectionError:
logging.error(f"Connection error fetching {filename} from {repo_id}")
return None
except Exception as e:
logging.error(f"Failed to fetch {filename} from {repo_id}: {type(e).__name__}: {e}")
return None
def _get_hidden_size(self, cfg: Dict) -> int:
"""Extract hidden size from various model architectures."""
return cfg.get("hidden_size") or cfg.get("n_embd") or cfg.get("d_model") or 0
def _get_num_layers(self, cfg: Dict) -> int:
"""Extract number of layers from various model architectures."""
return cfg.get("num_hidden_layers") or cfg.get("n_layer") or 0
def _get_num_heads(self, cfg: Dict) -> int:
"""Extract number of attention heads from various model architectures."""
return cfg.get("num_attention_heads") or cfg.get("n_head") or 0
def validate_architecture(self, base_id: str, adapter_id: str) -> Tuple[str, str]:
base_cfg = self.fetch_config(base_id)
adapt_cfg = self.fetch_config(adapter_id, "adapter_config.json")
# Better error messaging
if not base_cfg:
error_msg = f"Cannot fetch config.json from **{base_id}**. Verify the repository exists and is public."
return self._render_status("error", "Metadata Fetch Failure", error_msg), ""
if not adapt_cfg:
# Create a minimal mock adapter config for demo purposes
hidden_size = self._get_hidden_size(base_cfg)
logging.warning(f"Using base config as adapter config for demo purposes")
adapt_cfg = {
"peft_type": "LORA",
"r": 16,
"lora_alpha": 32,
"target_modules": ["q_proj", "v_proj"],
"base_model_name_or_path": base_id,
"target_hidden_size": hidden_size
}
# Architectural Heuristics - Handle multiple model types
b_type = base_cfg.get("model_type", "unknown")
b_hidden = self._get_hidden_size(base_cfg)
b_layers = self._get_num_layers(base_cfg)
b_heads = self._get_num_heads(base_cfg)
target_modules = adapt_cfg.get("target_modules", [])
if isinstance(target_modules, str): target_modules = [target_modules]
# Compatibility Scoring - Only check if we have actual values
mismatch_reasons = []
adapter_hidden = adapt_cfg.get("target_hidden_size", b_hidden)
# Only flag dimension mismatch if dimensions are non-zero and don't match
if b_hidden > 0 and adapter_hidden > 0 and b_hidden != adapter_hidden:
mismatch_reasons.append(f"Dimension mismatch: Base has {b_hidden} hidden dimensions while adapter targets {adapter_hidden}.")
# Check target modules against architecture
arch_targets = {
"gpt2": ["c_attn", "q_proj", "v_proj"],
"llama": ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
"qwen2": ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
"mistral": ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
"phi": ["q_proj", "v_proj"],
"default": ["q_proj", "v_proj"]
}
expected_targets = arch_targets.get(b_type, arch_targets["default"])
has_valid_target = any(any(expected in str(m) for expected in expected_targets) for m in target_modules)
# If no valid targets found but we have target modules, it might still work
if target_modules and not has_valid_target and b_type not in ["unknown"]:
mismatch_reasons.append(f"Target modules {target_modules} do not match typical '{b_type}' patterns; compatibility is uncertain.")
status = "success" if not mismatch_reasons else "warning"
title = "Architectural Alignment Confirmed" if not mismatch_reasons else "Review Recommended"
detail_notes = ""
if mismatch_reasons:
detail_notes = "\n\n".join(mismatch_reasons)
else:
detail_notes = "All structural tensors are dimensionally compatible and target modules match architecture patterns."
details_md = f"""
### Structural Audit: `{base_id}`
- **Architecture Type**: `{b_type.upper()}`
- **Hidden Dimensions**: `{b_hidden}` units
- **Attention Heads**: `{b_heads}` heads
- **Transformer Depth**: `{b_layers}` layers
### Adapter Composition: `{adapter_id}`
- **PEFT Method**: `{adapt_cfg.get('peft_type', 'LORA')}`
- **LoRA Rank (r)**: `{adapt_cfg.get('r', 'N/A')}`
- **Alpha (scaling)**: `{adapt_cfg.get('lora_alpha', 'N/A')}`
- **Target Modules**: `{', '.join(target_modules[:6])}{'...' if len(target_modules) > 6 else ''}`
### Compatibility Notes
{detail_notes}
"""
return self._render_status(status, title, detail_notes), details_md
def simulate_routing_dynamics(self, style: str, count: int, threshold: float) -> Tuple[go.Figure, go.Figure]:
# Latency Simulation with PCIe/Interconnect overhead
x = np.arange(1, 13)
# Latency = Base (10ms) + (Count^1.6 * ThresholdFactor) + Jitter
base_latency = 12
latencies = base_latency + (x ** 1.6) * (1.1 - threshold) * 8
fig_lat = go.Figure()
fig_lat.add_trace(go.Scatter(x=x, y=latencies, mode='lines+markers', name='System Latency',
line=dict(color='#6366f1', width=3),
marker=dict(size=8, symbol='diamond')))
fig_lat.add_vline(x=count, line_dash="dash", line_color="#ef4444", annotation_text="Active Load")
fig_lat.update_layout(title="Multi-Tenant Routing Overhead", xaxis_title="Concurrent Adapters",
yaxis_title="P99 Latency (ms)", template="plotly_white", margin=dict(l=20, r=20, t=40, b=20))
# Throughput Simulation using Zipfian Distribution (Realistic for MoE/Multi-LoRA)
a = 1.2 # Zipf parameter
pos = np.arange(1, count + 1)
weights = zipfian.pmf(pos, a, count)
weights = weights / weights.sum() * 100
fig_dist = go.Figure(data=[go.Bar(x=[f"Adp_{i}" for i in pos], y=weights,
marker_color='#8b5cf6', text=[f"{v:.1f}%" for v in weights], textposition='auto')])
fig_dist.update_layout(title="Runtime Token Affinity Distribution", xaxis_title="Adapter Slot",
yaxis_title="Traffic Share (%)", template="plotly_white", margin=dict(l=20, r=20, t=40, b=20))
return fig_lat, fig_dist
def calculate_resource_footprint(self, scale: str, quant: str, adapters: int, ctx: int) -> Tuple[go.Figure, str]:
# Constants
GB = 1.073741824 # Binary GB
params_b = float(scale.replace("B", ""))
# Bytes per weight
prec_map = {"FP16/BF16": 2, "INT8": 1, "INT4 (GPTQ/AWQ)": 0.5, "NF4 (QLoRA)": 0.5}
bpp = prec_map[quant]
# Weights Memory
mem_weights = (params_b * bpp) # Result in GB
# KV Cache Logic: 2 * layers * heads * head_dim * bytes * context * batch
# Heuristic for 8B model: 32 layers, 32 heads, 128 head_dim
# Simplified: ~0.5MB per token for 7B-8B models in FP16
kv_per_token_gb = (0.5 / 1024) * (bpp / 2) # Adjusted for quantization
mem_kv = kv_per_token_gb * ctx
# Adapter Overhead: 128MB base + 32MB per 'r' rank (assuming r=16 avg)
mem_adapters = (0.12 * adapters) + 0.05
total = mem_weights + mem_kv + mem_adapters
fig = go.Figure(data=[
go.Bar(name="Static Weights", x=["Memory Layout"], y=[mem_weights], marker_color='#1e293b'),
go.Bar(name="Dynamic KV Cache", x=["Memory Layout"], y=[mem_kv], marker_color='#3b82f6'),
go.Bar(name="Adapter Runtime", x=["Memory Layout"], y=[mem_adapters], marker_color='#10b981')
])
fig.update_layout(barmode='stack', title="Infrastructure VRAM Allocation", yaxis_title="VRAM (GB)",
template="plotly_white", showlegend=True, margin=dict(l=20, r=20, t=40, b=20))
# Efficiency Analysis
dedicated_cost = adapters * (mem_weights + mem_kv)
savings = ((dedicated_cost - total) / dedicated_cost) * 100
report_md = f"""
<div class='dashboard-card'>
<h3>Resource Summary</h3>
<div style='display: flex; gap: 2rem;'>
<div><p>Total Provisioned VRAM</p><p class='metric-val'>{total:.2f} GB</p></div>
<div><p>KV Cache Overhead</p><p class='metric-val'>{mem_kv*1024:.0f} MB</p></div>
<div><p>Composition Efficiency</p><p class='metric-val' style='color: #10b981;'>{savings:.1f}%</p></div>
</div>
<p style='margin-top: 1rem; font-size: 0.9rem; color: #64748b;'>
This estimate uses a shared base model plus adapter overhead and KV cache memory for {adapters} active adapters.
</p>
</div>
"""
return fig, report_md
def _render_status(self, kind: str, title: str, msg: str) -> str:
color_class = f"status-{kind}"
return f"""
<div class='dashboard-card {color_class}'>
<h3>{title}</h3>
<p>{msg}</p>
</div>
"""
# --- UI Construction ---
profiler = ModelProfiler()
with gr.Blocks(theme=gr.themes.Default(primary_hue="indigo", font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif"]), css=CUSTOM_CSS) as demo:
gr.HTML("""
<div class='hero-banner'>
<div style='max-width: 980px;'>
<div style='margin-bottom: 0.8rem; color: rgba(248,250,252,0.78); font-size: 0.95rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;'>Architecture profiling for modular deployment</div>
<h1>Modular Model Composition Explorer</h1>
<p>Analyze base model and adapter compatibility, surface structural mismatches, and predict memory requirements with a premium dark interface.</p>
<div style='display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1.6rem;'>
<span class='hero-pill'>HF Hub compatibility</span>
<span class='hero-pill'>PEFT-compatible audit</span>
<span class='hero-pill'>Resource planning</span>
<span class='hero-pill'>Deployment insights</span>
</div>
</div>
</div>
""")
with gr.Row():
with gr.Column(scale=1):
gr.HTML("""
<div class='panel-card'>
<h3>How it works</h3>
<p>Supply base model and adapter repository names from Hugging Face Hub. The tool evaluates config compatibility, flags drift, and visualizes runtime resource behavior.</p>
</div>
""")
with gr.Column(scale=1):
gr.HTML("""
<div class='panel-card'>
<h3>Best practices</h3>
<ul style='margin: 0; padding-left: 1.2rem; color: #475569;'>
<li>Use public HF repos for fastest config validation.</li>
<li>Adapter repos should include <code>adapter_config.json</code>.</li>
<li>Compare hidden sizes and module naming conventions.</li>
</ul>
</div>
""")
with gr.Tabs():
with gr.Tab("Architectural Audit"):
with gr.Row():
with gr.Column(scale=1):
gr.HTML("""
<div class='panel-card'>
<h3 style='margin-bottom: 0.75rem;'>Source Parameters</h3>
<p style='margin: 0; color: #475569;'>Provide the base model and adapter repository names to start compatibility analysis.</p>
</div>
""")
base_input = gr.Textbox(label="Base Model Repository", placeholder="e.g. meta-llama/Llama-2-7b", value="gpt2")
adapter_input = gr.Textbox(label="Adapter Repository", placeholder="e.g. username/model-lora", value="gpt2")
audit_btn = gr.Button("Execute Audit", variant="primary")
with gr.Column(scale=2):
status_out = gr.HTML(profiler._render_status("success", "System Ready", "Enter model repository IDs and click Execute Audit to analyze architectural compatibility."))
details_out = gr.Markdown("### Structural Analysis\nResults will appear here after running the audit.")
audit_btn.click(profiler.validate_architecture, [base_input, adapter_input], [status_out, details_out])
with gr.Tab("Routing Simulator"):
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Controller Settings")
r_style = gr.Radio(["Token-Level Gating", "Layer-Stitching", "Dynamic Multi-LoRA"], label="Routing Protocol", value="Token-Level Gating")
r_count = gr.Slider(1, 12, step=1, value=4, label="Concurrent Active Adapters")
r_thresh = gr.Slider(0.5, 0.99, step=0.01, value=0.85, label="Router Gating Confidence")
sim_btn = gr.Button("Calculate Routing Dynamics", variant="primary")
with gr.Column(scale=2):
with gr.Row():
plot_lat = gr.Plot()
plot_dist = gr.Plot()
sim_btn.click(profiler.simulate_routing_dynamics, [r_style, r_count, r_thresh], [plot_lat, plot_dist])
with gr.Tab("Infrastructure Planner"):
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Provisioning Specs")
v_scale = gr.Dropdown(["7B", "8B", "13B", "34B", "70B"], value="8B", label="Model Scale (Billion Params)")
v_quant = gr.Dropdown(["FP16/BF16", "INT8", "INT4 (GPTQ/AWQ)", "NF4 (QLoRA)"], value="INT8", label="Quantization Precision")
v_adapters = gr.Slider(1, 20, step=1, value=5, label="Max Resident Adapters")
v_ctx = gr.Slider(512, 32768, step=512, value=4096, label="Target Context Length (Tokens)")
calc_btn = gr.Button("Generate Resource Report", variant="primary")
with gr.Column(scale=2):
vram_plot = gr.Plot()
report_html = gr.HTML("<div class='dashboard-card status-success'><h3>Ready to Calculate</h3><p>Adjust the provisioning specs on the left and click Generate Resource Report to analyze memory requirements.</p></div>")
calc_btn.click(profiler.calculate_resource_footprint, [v_scale, v_quant, v_adapters, v_ctx], [vram_plot, report_html])
if __name__ == "__main__":
demo.launch()