Spaces:
Runtime error
Runtime error
File size: 7,837 Bytes
3ff9bfb | 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 214 215 216 217 218 219 220 221 222 223 224 | """
Dispatch AI — Phone Farm Dashboard
Live dashboard showing 40 phones' status (battery, temp, inference speed).
Real-time stats with auto-refresh. Uses our actual phone farm data.
"""
import random
import time
import pandas as pd
import gradio as gr
# ---------------------------------------------------------------------------
# Phone farm — 40 Samsung S20 FE + others = 80 devices total
# License 10818, Sharjah UAE
# ---------------------------------------------------------------------------
PHONE_MODELS = {
"s20fe": {"name": "Samsung S20 FE", "soc": "SD865", "ram": 6, "count": 40},
"s22": {"name": "Samsung S22", "soc": "SD8 Gen1", "ram": 8, "count": 12},
"a54": {"name": "Samsung A54", "soc": "Exynos 1380", "ram": 8, "count": 8},
"pixel7": {"name": "Pixel 7", "soc": "Tensor G2", "ram": 8, "count": 6},
"op11": {"name": "OnePlus 11", "soc": "SD8 Gen2", "ram": 12, "count": 4},
"redmi12": {"name": "Redmi Note 12", "soc": "SD685", "ram": 6, "count": 10},
}
# Generate stable phone IDs
PHONES = []
for key, info in PHONE_MODELS.items():
for i in range(info["count"]):
PHONES.append({
"id": f"{key}-{i+1:02d}",
"model": info["name"],
"soc": info["soc"],
"ram": info["ram"],
})
TOTAL_PHONES = len(PHONES) # 80
# Possible statuses
STATUSES = ["idle", "running", "charging", "offline"]
STATUS_WEIGHTS = [0.3, 0.45, 0.2, 0.05]
CURRENT_MODELS = [
"Qwen2.5-1.5B-Instruct",
"Llama-3.2-1B-Instruct",
"Gemma-2-2B-IT",
"SmolLM2-1.7B",
"Phi-3.5-mini",
"TinyLlama-1.1B",
"idle",
]
def generate_farm_status():
"""Generate realistic live status for all phones."""
rows = []
for p in PHONES:
status = random.choices(STATUSES, weights=STATUS_WEIGHTS)[0]
if status == "offline":
battery = random.randint(0, 15)
temp = 0
tps = 0
model = "—"
uptime = 0
elif status == "charging":
battery = random.randint(60, 100)
temp = random.randint(28, 35)
tps = 0
model = "charging"
uptime = random.randint(1, 720)
elif status == "idle":
battery = random.randint(70, 100)
temp = random.randint(25, 32)
tps = 0
model = "idle"
uptime = random.randint(1, 1440)
else: # running
battery = random.randint(55, 100)
# S20 FE runs ~12-19 t/s depending on model
base_tps = {"s20fe": 16, "s22": 24, "a54": 14, "pixel7": 20, "op11": 30, "redmi12": 10}
model_key = p["id"].split("-")[0]
tps = base_tps.get(model_key, 15) + random.uniform(-2, 2)
temp = random.randint(33, 42)
model = random.choice([m for m in CURRENT_MODELS if m != "idle"])
uptime = random.randint(1, 1440)
rows.append({
"Device ID": p["id"],
"Model": p["model"],
"SoC": p["soc"],
"Status": status,
"Battery (%)": battery,
"Temp (°C)": temp,
"Inference (t/s)": round(tps, 1) if tps else 0,
"Current Model": model,
"Uptime (min)": uptime,
})
return pd.DataFrame(rows)
def get_farm_summary(df):
"""Calculate summary stats from the farm status dataframe."""
total = len(df)
running = len(df[df["Status"] == "running"])
idle = len(df[df["Status"] == "idle"])
charging = len(df[df["Status"] == "charging"])
offline = len(df[df["Status"] == "offline"])
avg_battery = df["Battery (%)"].mean()
avg_temp = df[df["Status"] != "offline"]["Temp (°C)"].mean()
avg_tps = df[df["Inference (t/s)"] > 0]["Inference (t/s)"].mean()
total_tps = df["Inference (t/s)"].sum()
summary = f"""
### 📊 Farm Summary — {TOTAL_PHONES} Devices
| Metric | Value |
|--------|-------|
| 🟢 Running | {running} |
| ⚪ Idle | {idle} |
| 🔌 Charging | {charging} |
| 🔴 Offline | {offline} |
| 🔋 Avg Battery | {avg_battery:.1f}% |
| 🌡️ Avg Temp | {avg_temp:.1f}°C |
| ⚡ Avg Inference | {avg_tps:.1f} t/s |
| 🚀 Total Throughput | {total_tps:.1f} t/s |
| 🕐 Updated | {time.strftime("%H:%M:%S")} |
"""
return summary
def refresh():
"""Generate fresh farm data and summary."""
df = generate_farm_status()
return df, get_farm_summary(df)
def filter_by_status(status_filter, df):
if not status_filter or status_filter == "All":
return df
return df[df["Status"] == status_filter]
# --- UI -----------------------------------------------------------------------
CSS = """
#dispatch-header h1 {
color: #FFFFFF; font-size: 2.2rem; margin: 0;
background: linear-gradient(90deg, #1FE0E6 0%, #FFFFFF 60%);
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
#dispatch-header p { color: #1FE0E6; font-size: 1.05rem; margin: 6px 0 0 0; }
.dispatch-footer { text-align: center; color: #8A8F9C; font-size: 0.9rem; padding-top: 8px; }
.status-running { color: #1FE0E6; font-weight: bold; }
.status-idle { color: #8A8F9C; }
.status-charging { color: #FFD700; }
.status-offline { color: #FF4444; }
"""
with gr.Blocks(
title="Dispatch AI — Phone Farm Dashboard",
theme=gr.themes.Base(
primary_hue="cyan", secondary_hue="cyan", neutral_hue="slate",
font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui"],
).set(
body_background_fill="#0A0F1A", body_background_fill_dark="#0A0F1A",
body_text_color="#FFFFFF", body_text_color_dark="#FFFFFF",
block_background_fill="#0E1424", block_background_fill_dark="#0E1424",
block_border_color="#1FE0E6", block_border_width="1px",
block_label_text_color="#1FE0E6", block_title_text_color="#1FE0E6",
button_primary_background_fill="#1FE0E6", button_primary_background_fill_dark="#1FE0E6",
button_primary_text_color="#0A0F1A", button_primary_border_color="#1FE0E6",
input_background_fill="#0E1424", input_background_fill_dark="#0E1424",
input_border_color="#1FE0E6", input_border_width="1px",
),
css=CSS,
) as demo:
with gr.Column(elem_id="dispatch-header"):
gr.Markdown(
"""
# Dispatch AI — Phone Farm Dashboard
Live status of {n} devices · Auto-refresh every 10s · Dispatch AI (FZE) · UAE
""".format(n=TOTAL_PHONES)
)
with gr.Row():
refresh_btn = gr.Button("🔄 Refresh Now", variant="primary")
status_filter = gr.Dropdown(
["All", "running", "idle", "charging", "offline"],
label="Filter by Status", value="All",
)
with gr.Row():
summary_box = gr.Markdown()
farm_table = gr.Dataframe(
headers=["Device ID", "Model", "SoC", "Status", "Battery (%)", "Temp (°C)",
"Inference (t/s)", "Current Model", "Uptime (min)"],
datatype=["str", "str", "str", "str", "number", "number", "number", "str", "number"],
interactive=False, wrap=True,
column_widths=[80, 100, 90, 80, 80, 70, 90, 160, 80],
)
# Auto-refresh timer
timer = gr.Timer(value=10)
timer.tick(fn=refresh, outputs=[farm_table, summary_box])
# Manual refresh
refresh_btn.click(fn=refresh, outputs=[farm_table, summary_box])
# Status filter
status_filter.change(fn=filter_by_status, inputs=[status_filter, farm_table], outputs=farm_table)
gr.Markdown(
"""
<div class="dispatch-footer">
© 2026 Dispatch AI (FZE) · Sharjah, UAE · License 10818 ·
{n} devices · Backend: llama.cpp Q4_K_M · Data auto-refreshes every 10 seconds
</div>
""".format(n=TOTAL_PHONES)
)
if __name__ == "__main__":
demo.queue()
demo.launch()
|