robudget / app.py
robomotic's picture
Upload app.py with huggingface_hub
e98be38 verified
Raw
History Blame Contribute Delete
26.1 kB
import gradio as gr
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# โ”€โ”€ Robot database โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# speed_ratio: task throughput relative to an average human worker (1.0 = same
# speed). A ratio of 0.5 means the robot takes twice as long per task, so it
# delivers half the output per operating hour even at full accuracy.
# Sources: HumanoidBench, manufacturer pilot reports, Open X-Embodiment (2024-25).
ROBOTS = {
"Tesla Optimus Gen 2": {
"price_usd": 30000,
"power_w": 500,
"battery_h": 10,
"maintenance_pct": 0.10,
"lifespan_yr": 8,
"task_accuracy": 0.65,
"speed_ratio": 0.55,
"benchmark": "Open X-Embodiment / HumanoidBench",
"notes": "General-purpose; 2.3 kWh battery; commercial scale target price.",
},
"Unitree G1": {
"price_usd": 16000,
"power_w": 400,
"battery_h": 2,
"maintenance_pct": 0.20,
"lifespan_yr": 5,
"task_accuracy": 0.55,
"speed_ratio": 0.40,
"benchmark": "HumanoidBench (locomotion tasks)",
"notes": "Consumer-grade entry point; limited dexterity; short battery life.",
},
"Unitree H1": {
"price_usd": 90000,
"power_w": 600,
"battery_h": 3.5,
"maintenance_pct": 0.18,
"lifespan_yr": 6,
"task_accuracy": 0.58,
"speed_ratio": 0.45,
"benchmark": "HumanoidBench (manipulation tasks)",
"notes": "Research-grade; improved upper-body dexterity vs G1.",
},
"Figure 02": {
"price_usd": 40000,
"power_w": 600,
"battery_h": 4,
"maintenance_pct": 0.15,
"lifespan_yr": 7,
"task_accuracy": 0.68,
"speed_ratio": 0.60,
"benchmark": "Figure internal pilots + Open X-Embodiment",
"notes": "OpenAI-powered cognition; commercial warehouse focus.",
},
"Agility Robotics Digit": {
"price_usd": 250000,
"power_w": 800,
"battery_h": 8,
"maintenance_pct": 0.15,
"lifespan_yr": 6,
"task_accuracy": 0.70,
"speed_ratio": 0.70,
"benchmark": "BEHAVIOR Robot Suite",
"notes": "Amazon warehouse deployments; proven industrial reliability.",
},
"Sanctuary AI Phoenix": {
"price_usd": 65000,
"power_w": 450,
"battery_h": 6,
"maintenance_pct": 0.12,
"lifespan_yr": 7,
"task_accuracy": 0.64,
"speed_ratio": 0.55,
"benchmark": "BEHAVIOR Robot Suite (safety-critical tasks)",
"notes": "Carbon AI brain; general-purpose design; strong safety scores.",
},
"Boston Dynamics Atlas (Electric)": {
"price_usd": 370000,
"power_w": 1500,
"battery_h": 4,
"maintenance_pct": 0.15,
"lifespan_yr": 6,
"task_accuracy": 0.72,
"speed_ratio": 0.65,
"benchmark": "HumanoidBench + industrial pilot programs",
"notes": "Most agile humanoid; industrial & research grade; high energy draw.",
},
}
# โ”€โ”€ Task categories โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# accuracy_mod: scales robot's base accuracy for this task class.
# speed_mod: scales robot's base speed for this task class.
# >1.0 = task is more robot-friendly (repetitive/structured)
# <1.0 = task requires dexterity/judgment that slows robots down
TASKS = {
"House Cleaning / Maid": {
"accuracy_mod": 1.00,
"speed_mod": 0.90,
"description": "Vacuuming, mopping, dusting, laundry",
},
"Cooking / Meal Prep": {
"accuracy_mod": 0.70,
"speed_mod": 0.55,
"description": "Preparing meals, kitchen tasks โ€” high dexterity demand",
},
"Gardening / Landscaping": {
"accuracy_mod": 0.80,
"speed_mod": 1.05,
"description": "Mowing, trimming, planting, watering โ€” methodical, benefits robots",
},
"Warehouse / Logistics": {
"accuracy_mod": 0.85,
"speed_mod": 1.20,
"description": "Picking, packing, sorting โ€” structured environment, robot-friendly",
},
"General Maintenance": {
"accuracy_mod": 0.60,
"speed_mod": 0.70,
"description": "Minor repairs, furniture assembly, painting",
},
"Plumbing": {
"accuracy_mod": 0.45,
"speed_mod": 0.45,
"description": "Pipe repairs, installations, leak fixes โ€” complex manipulation",
},
"Electrical Work": {
"accuracy_mod": 0.40,
"speed_mod": 0.45,
"description": "Wiring, outlets, fixture installations โ€” high precision required",
},
"Elder / Child Care Assistance": {
"accuracy_mod": 0.35,
"speed_mod": 0.80,
"description": "Mobility assistance, simple care tasks",
},
}
# โ”€โ”€ Currencies โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
CURRENCIES = {
"USD ๐Ÿ‡บ๐Ÿ‡ธ": {"symbol": "$", "rate": 1.000},
"EUR ๐Ÿ‡ช๐Ÿ‡บ": {"symbol": "โ‚ฌ", "rate": 0.920},
"GBP ๐Ÿ‡ฌ๐Ÿ‡ง": {"symbol": "ยฃ", "rate": 0.790},
"JPY ๐Ÿ‡ฏ๐Ÿ‡ต": {"symbol": "ยฅ", "rate": 154.0},
"CNY ๐Ÿ‡จ๐Ÿ‡ณ": {"symbol": "ยฅ", "rate": 7.240},
"INR ๐Ÿ‡ฎ๐Ÿ‡ณ": {"symbol": "โ‚น", "rate": 83.50},
"AUD ๐Ÿ‡ฆ๐Ÿ‡บ": {"symbol": "A$", "rate": 1.520},
"CAD ๐Ÿ‡จ๐Ÿ‡ฆ": {"symbol": "C$", "rate": 1.360},
"BRL ๐Ÿ‡ง๐Ÿ‡ท": {"symbol": "R$", "rate": 5.050},
"MXN ๐Ÿ‡ฒ๐Ÿ‡ฝ": {"symbol": "M$", "rate": 17.20},
"CHF ๐Ÿ‡จ๐Ÿ‡ญ": {"symbol": "Fr", "rate": 0.900},
"KRW ๐Ÿ‡ฐ๐Ÿ‡ท": {"symbol": "โ‚ฉ", "rate": 1340.},
"SGD ๐Ÿ‡ธ๐Ÿ‡ฌ": {"symbol": "S$", "rate": 1.340},
"SEK ๐Ÿ‡ธ๐Ÿ‡ช": {"symbol": "kr", "rate": 10.50},
"NOK ๐Ÿ‡ณ๐Ÿ‡ด": {"symbol": "kr", "rate": 10.80},
}
ELEC_HINTS = {
"USD ๐Ÿ‡บ๐Ÿ‡ธ": 0.15, "EUR ๐Ÿ‡ช๐Ÿ‡บ": 0.28, "GBP ๐Ÿ‡ฌ๐Ÿ‡ง": 0.24,
"JPY ๐Ÿ‡ฏ๐Ÿ‡ต": 21.0, "CNY ๐Ÿ‡จ๐Ÿ‡ณ": 0.80, "INR ๐Ÿ‡ฎ๐Ÿ‡ณ": 6.50,
"AUD ๐Ÿ‡ฆ๐Ÿ‡บ": 0.30, "CAD ๐Ÿ‡จ๐Ÿ‡ฆ": 0.13, "BRL ๐Ÿ‡ง๐Ÿ‡ท": 0.70,
"MXN ๐Ÿ‡ฒ๐Ÿ‡ฝ": 1.10, "CHF ๐Ÿ‡จ๐Ÿ‡ญ": 0.22, "KRW ๐Ÿ‡ฐ๐Ÿ‡ท": 120.,
"SGD ๐Ÿ‡ธ๐Ÿ‡ฌ": 0.28, "SEK ๐Ÿ‡ธ๐Ÿ‡ช": 1.50, "NOK ๐Ÿ‡ณ๐Ÿ‡ด": 1.00,
}
# โ”€โ”€ Data sources reference โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
DATA_SOURCES_MD = """
## ๐Ÿ“š Data Sources & Methodology
### Accuracy benchmarks
| Benchmark | What it measures | Key finding |
|---|---|---|
| **[HumanoidBench](https://humanoid-bench.github.io/)** (He et al., 2024) | 27 whole-body tasks: 12 locomotion + 15 dexterous manipulation | Best policies reach ~40โ€“72% success on manipulation; locomotion is more reliable |
| **[BEHAVIOR Robot Suite](https://behavior.stanford.edu/behavior-1k/)** (Li et al., 2023) | 1,000 household activities in realistic home environments | Most robots fail >60% of tasks; safety-critical subset: ~64% safe-success |
| **[Open X-Embodiment](https://robotics-transformer-x.github.io/)** (Padalkar et al., 2023) | Cross-robot manipulation across 22 platforms, 500k+ trajectories | RT-2-X improves generalization by ~50% vs. single-robot policies |
| **[RoboSuite](https://robosuite.ai/)** (Zhu et al., 2020) | 9 manipulation tasks in MuJoCo physics simulation | Standard reproducible baseline; widely used in ablation studies |
| **Manufacturer pilot reports** | Real-world warehouse/factory deployments (2024โ€“25) | Amazon/Agility: ~70% task completion in structured environments |
---
### Speed benchmarks
Speed data is **less standardized** than accuracy. The values used here are derived from:
| Source | Method |
|---|---|
| HumanoidBench task-completion-time metrics | Ratio of median robot time vs. human baseline per task |
| Figure AI public demo videos (2024) | Frame-by-frame timing of pick-and-place vs. human operator |
| Agility Robotics / Amazon pilot reports | Packages-per-hour cited vs. human warehouse worker average |
| Boston Dynamics Atlas demos | Time-to-complete on obstacle/manipulation sequences |
**Speed ratio definition:** `1.0` = same throughput as a human worker. `0.5` = robot takes twice as long per task (delivers half the output per operating hour).
---
### How the model works
```
effective_speed = robot.base_speed ร— task.speed_modifier
effective_accuracy = robot.base_accuracy ร— task.accuracy_modifier
value_per_hour = effective_accuracy ร— effective_speed ร— hourly_wage
value_per_year = value_per_hour ร— operable_hours_per_year
annual_opex = energy_cost + maintenance_cost
annual_net_savings = value_per_year โˆ’ annual_opex
break_even_years = robot_purchase_price / annual_net_savings
```
**Key insight:** a robot that is half as fast as a human (speed = 0.5) delivers only half the value per operating hour, doubling the effective cost of the task even if accuracy is identical. Energy cost is *not* speed-adjusted โ€” the robot consumes power the whole time it runs.
---
### Accuracy modifiers by task
| Task | Accuracy mod | Speed mod | Rationale |
|---|---|---|---|
| House Cleaning | 1.00 | 0.90 | Baseline; unstructured but tolerable |
| Cooking / Meal Prep | 0.70 | 0.55 | High dexterity; fragile objects |
| Gardening | 0.80 | 1.05 | Methodical; no time pressure |
| Warehouse / Logistics | 0.85 | 1.20 | Structured; robots outpace humans at scale |
| General Maintenance | 0.60 | 0.70 | Variable tasks; judgment required |
| Plumbing | 0.45 | 0.45 | Fine manipulation; spatial reasoning |
| Electrical Work | 0.40 | 0.45 | Precision-critical; safety constraints |
| Elder / Child Care | 0.35 | 0.80 | Social intelligence bottleneck |
---
### Caveats & limitations
- Robot prices are list/target prices as of 2025; volume discounts and leasing models are not modelled.
- Accuracy and speed data are approximate; variance across environments is high.
- Maintenance costs (10โ€“20% of purchase price per year) are industry estimates; actual costs depend on usage intensity and support contracts.
- Exchange rates are approximate mid-2025 values embedded at build time.
- The model assumes the robot works independently; human supervision costs are not included.
---
*Built by [@paolodiprodi](https://x.com/paolodiprodi) ยท Suggestions via the [community tab](https://huggingface.co/spaces/robomotic/robudget/discussions) or on X.*
"""
# โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def _fmt(value: float, sym: str, decimals: int = 0) -> str:
return f"{sym}{value:,.{decimals}f}"
def _default_speed(robot_name: str, task_type: str) -> float:
"""Return the pre-computed effective speed for this robot+task pair."""
r = ROBOTS[robot_name]
t = TASKS[task_type]
return round(min(r["speed_ratio"] * t["speed_mod"], 1.5), 2)
def update_robot_info(robot_name: str, currency_key: str) -> str:
r = ROBOTS[robot_name]
c = CURRENCIES[currency_key]
price = r["price_usd"] * c["rate"]
maint = price * r["maintenance_pct"]
return (
f"**{robot_name}**\n\n"
f"| Specification | Value |\n|---|---|\n"
f"| Purchase price | {_fmt(price, c['symbol'])} |\n"
f"| Power draw | {r['power_w']} W |\n"
f"| Battery runtime | {r['battery_h']} h |\n"
f"| Annual maintenance | ~{r['maintenance_pct']*100:.0f}% โ‰ˆ {_fmt(maint, c['symbol'])}/yr |\n"
f"| Expected lifespan | {r['lifespan_yr']} years |\n"
f"| Base task accuracy | {r['task_accuracy']*100:.0f}% |\n"
f"| Base speed vs human | {r['speed_ratio']*100:.0f}% |\n"
f"| Benchmark source | {r['benchmark']} |\n\n"
f"*{r['notes']}*"
)
def suggest_electricity(currency_key: str) -> float:
return ELEC_HINTS.get(currency_key, 0.15)
def prefill_speed(robot_name: str, task_type: str) -> float:
return _default_speed(robot_name, task_type)
# โ”€โ”€ Core calculation โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def calculate(
task_type: str,
robot_name: str,
robot_currency_key: str,
wage_currency_key: str,
hourly_wage: float,
hours_per_day: float,
days_per_week: int,
electricity_cost: float,
analysis_years: int,
effective_speed: float,
) -> tuple:
robot = ROBOTS[robot_name]
task = TASKS[task_type]
robot_cur = CURRENCIES[robot_currency_key]
wage_cur = CURRENCIES[wage_currency_key]
robot_price_robot_cur = robot["price_usd"] * robot_cur["rate"]
robot_price_cmp = robot["price_usd"] * wage_cur["rate"]
rsym = robot_cur["symbol"]
wsym = wage_cur["symbol"]
effective_accuracy = min(robot["task_accuracy"] * task["accuracy_mod"], 1.0)
days_per_year = days_per_week * 52
hours_per_year = hours_per_day * days_per_year
# Robot operates up to battery limit per day
operable_h_per_day = min(hours_per_day, robot["battery_h"])
operable_h_per_year = operable_h_per_day * days_per_year
# Energy cost: based on actual hours operated (not speed-adjusted)
energy_kwh_yr = (robot["power_w"] / 1000) * operable_h_per_year
energy_cost_yr = energy_kwh_yr * electricity_cost
maintenance_yr = robot_price_cmp * robot["maintenance_pct"]
annual_opex = energy_cost_yr + maintenance_yr
# Human baseline
human_annual = hourly_wage * hours_per_year
# Value robot delivers: accuracy ร— speed ร— hours ร— wage
# A robot at 0.5x speed delivers half the output per hour, even at 100% accuracy.
robot_value_yr = effective_accuracy * effective_speed * operable_h_per_year * hourly_wage
annual_savings = robot_value_yr - annual_opex
if annual_savings <= 0:
breakeven_yr = None
breakeven_raw = None
else:
breakeven_raw = robot_price_cmp / annual_savings
breakeven_yr = breakeven_raw if breakeven_raw <= robot["lifespan_yr"] else None
# โ”€โ”€ Chart โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
step = 0.25
years = np.arange(0, analysis_years + step, step)
human_cum = human_annual * years
robot_spend_cum = robot_price_cmp + annual_opex * years
robot_net_cum = robot_spend_cum - robot_value_yr * years
fig = make_subplots(
rows=1, cols=2,
subplot_titles=(
"Cumulative Cost vs. Value Delivered",
f"Annual Cost Breakdown ({wsym})",
),
horizontal_spacing=0.13,
)
fig.add_trace(go.Scatter(
x=years, y=human_cum,
name="Human labor (total spend)",
line=dict(color="#e74c3c", width=2.5),
hovertemplate=f"Year %{{x:.2f}}<br>Human: {wsym}%{{y:,.0f}}<extra></extra>",
), row=1, col=1)
fig.add_trace(go.Scatter(
x=years, y=robot_spend_cum,
name="Robot (total spend)",
line=dict(color="#3498db", width=2.5, dash="dash"),
hovertemplate=f"Year %{{x:.2f}}<br>Robot spend: {wsym}%{{y:,.0f}}<extra></extra>",
), row=1, col=1)
fig.add_trace(go.Scatter(
x=years, y=np.maximum(robot_net_cum, 0),
name="Robot (net cost after value)",
line=dict(color="#27ae60", width=2, dash="dot"),
hovertemplate=f"Year %{{x:.2f}}<br>Robot net: {wsym}%{{y:,.0f}}<extra></extra>",
), row=1, col=1)
if breakeven_yr is not None:
be_y = robot_price_cmp + annual_opex * breakeven_yr
fig.add_vline(x=breakeven_yr, line_dash="dot", line_color="#27ae60", row=1, col=1)
fig.add_annotation(
x=breakeven_yr, y=be_y * 1.08,
text=f"Break-even<br>yr {breakeven_yr:.1f}",
showarrow=True, arrowhead=2, arrowcolor="#27ae60",
font=dict(color="#27ae60", size=11),
row=1, col=1,
)
amortized = robot_price_cmp / robot["lifespan_yr"]
bar_labels = ["Human\nLabor", "Robot:\nPurchase\n(amortized)", "Robot:\nEnergy", "Robot:\nMaintenance"]
bar_values = [human_annual, amortized, energy_cost_yr, maintenance_yr]
bar_colors = ["#e74c3c", "#3498db", "#2ecc71", "#f39c12"]
fig.add_trace(go.Bar(
x=bar_labels, y=bar_values,
marker_color=bar_colors,
text=[_fmt(v, wsym) for v in bar_values],
textposition="outside",
hovertemplate="%{x}<br>Annual: " + wsym + "%{y:,.0f}<extra></extra>",
showlegend=False,
), row=1, col=2)
fig.update_layout(
height=500, template="plotly_white", showlegend=True,
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="left", x=0),
margin=dict(t=70, b=50, l=50, r=20),
)
fig.update_yaxes(tickprefix=wsym, row=1, col=1)
fig.update_yaxes(tickprefix=wsym, row=1, col=2)
fig.update_xaxes(title_text="Years", row=1, col=1)
# โ”€โ”€ Summary โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
net_gain = robot_value_yr * robot["lifespan_yr"] - (robot_price_cmp + annual_opex * robot["lifespan_yr"])
if breakeven_yr is None:
if annual_savings <= 0:
be_block = (
"### โŒ No Break-even โ€” robot costs exceed value delivered\n\n"
f"Annual net savings: **{_fmt(annual_savings, wsym)}**. "
"Try a higher wage, more hours, or a cheaper/faster robot."
)
else:
be_block = (
f"### โš ๏ธ Break-even ({breakeven_raw:.1f} yr) exceeds lifespan ({robot['lifespan_yr']} yr)\n\n"
"The robot would eventually pay off, but not within its operational life."
)
else:
be_block = (
f"### โœ… Break-even at **{breakeven_yr:.1f} years**\n\n"
f"Annual net savings: **{_fmt(annual_savings, wsym)}/yr**\n\n"
f"Net gain over full {robot['lifespan_yr']}-yr lifespan: **{_fmt(net_gain, wsym)}**"
)
currency_note = ""
if robot_currency_key != wage_currency_key:
currency_note = (
f"\n> Robot price in **{rsym}**: {_fmt(robot_price_robot_cur, rsym)}. "
f"Chart values converted to **{wsym}** (approx. rates)."
)
default_spd = _default_speed(robot_name, task_type)
speed_note = ""
if abs(effective_speed - default_spd) > 0.01:
speed_note = f" *(manually overridden from benchmark default {default_spd:.2f})*"
summary = f"""
## {robot_name} โ†’ {task_type}
| Parameter | Value |
|---|---|
| Robot price | {_fmt(robot_price_robot_cur, rsym)} |
| Effective accuracy | {effective_accuracy*100:.1f}% *(base {robot['task_accuracy']*100:.0f}% ร— {task['accuracy_mod']*100:.0f}% task modifier)* |
| Effective speed vs human | {effective_speed*100:.0f}%{speed_note} |
| Operable hours/day | {operable_h_per_day:.1f} h *(battery capped from {hours_per_day:.1f} h)* |
| Annual energy cost | {_fmt(energy_cost_yr, wsym)} |
| Annual maintenance | {_fmt(maintenance_yr, wsym)} |
| Annual human labor | {_fmt(human_annual, wsym)} |
| Robot value delivered/yr | {_fmt(robot_value_yr, wsym)} *(accuracy ร— speed ร— hours ร— wage)* |
| **Annual net savings** | **{_fmt(annual_savings, wsym)}** |
---
{be_block}
---
**Benchmark:** {robot['benchmark']}
**Robot note:** {robot['notes']}
**Task note:** {task['description']}{currency_note}
*Exchange rates approximate (mid-2025). See the Data Sources tab for full methodology.*
"""
return fig, summary
# โ”€โ”€ UI โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
with gr.Blocks(title="RoBudget โ€” Humanoid Robot Investment Calculator") as demo:
gr.Markdown("""
# ๐Ÿค– RoBudget โ€” Should You Hire a Humanoid Robot?
Break-even analysis comparing the total cost of **human labor** vs. **buying and operating a humanoid robot**.
""")
with gr.Tabs():
# โ”€โ”€ Tab 1: Calculator โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
with gr.Tab("๐Ÿงฎ Calculator"):
with gr.Row():
# Left: inputs
with gr.Column(scale=1, min_width=330):
gr.Markdown("### ๐ŸŒ Currency")
with gr.Row():
robot_currency = gr.Dropdown(
choices=list(CURRENCIES.keys()), value="USD ๐Ÿ‡บ๐Ÿ‡ธ",
label="Robot price currency", scale=1,
)
wage_currency = gr.Dropdown(
choices=list(CURRENCIES.keys()), value="USD ๐Ÿ‡บ๐Ÿ‡ธ",
label="Wages & electricity currency", scale=1,
)
gr.Markdown("### ๐Ÿ”ง Task & Robot")
task_type = gr.Dropdown(
choices=list(TASKS.keys()), value="House Cleaning / Maid",
label="Task / Job type",
info="The chore or role the robot would replace",
)
robot_name = gr.Dropdown(
choices=list(ROBOTS.keys()), value="Tesla Optimus Gen 2",
label="Robot model",
)
gr.Markdown("### ๐Ÿ’ฐ Labor Cost")
hourly_wage = gr.Slider(
minimum=1, maximum=500, value=20, step=1,
label="Human hourly wage (wage currency)",
)
hours_per_day = gr.Slider(
minimum=0.5, maximum=12, value=4, step=0.5,
label="Hours of work per day",
)
days_per_week = gr.Slider(
minimum=1, maximum=7, value=5, step=1,
label="Days worked per week",
)
gr.Markdown("### โšก Energy")
electricity_cost = gr.Slider(
minimum=0.01, maximum=500, value=0.15, step=0.01,
label="Electricity cost per kWh (wage currency)",
info="US โ‰ˆ $0.15 ยท EU โ‰ˆ โ‚ฌ0.28 ยท UK โ‰ˆ ยฃ0.24 ยท JP โ‰ˆ ยฅ21",
)
gr.Markdown("### ๐ŸŽ๏ธ Robot Performance")
effective_speed = gr.Slider(
minimum=0.10, maximum=1.50, value=0.50, step=0.05,
label="Effective speed vs. human (auto-filled from benchmarks)",
info="1.0 = same speed as human ยท 0.5 = twice as slow ยท >1.0 = faster",
)
gr.Markdown(
"<small>*Pre-filled from benchmark data for the selected robot + task. "
"Override to model future improvements or your own observations.*</small>"
)
gr.Markdown("### ๐Ÿ“… Analysis Horizon")
analysis_years = gr.Slider(
minimum=1, maximum=20, value=10, step=1,
label="Years to project",
)
calc_btn = gr.Button("โšก Calculate Break-even", variant="primary")
# Right: outputs
with gr.Column(scale=2):
gr.Markdown("### ๐Ÿ“Š Results")
output_chart = gr.Plot(label="Cost Analysis")
output_summary = gr.Markdown(
"*Configure inputs and press **Calculate Break-even** to see results.*"
)
with gr.Accordion("โ„น๏ธ Selected Robot Specifications", open=False):
robot_spec = gr.Markdown()
# โ”€โ”€ Tab 2: Data Sources โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
with gr.Tab("๐Ÿ“š Data Sources & Methodology"):
gr.Markdown(DATA_SOURCES_MD)
gr.Markdown("""
---
Built by **[@paolodiprodi](https://x.com/paolodiprodi)** ยท Suggestions welcome โ€” open a discussion on the [community tab](https://huggingface.co/spaces/robomotic/robudget/discussions) or reach out on X.
""")
# โ”€โ”€ Wiring โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def on_robot_or_task_change(robot_name, task_type, robot_cur, wage_cur):
spec = update_robot_info(robot_name, robot_cur)
spd = prefill_speed(robot_name, task_type)
elec = suggest_electricity(wage_cur)
return spec, spd, elec
for trigger in [robot_name, task_type, robot_currency, wage_currency]:
trigger.change(
on_robot_or_task_change,
inputs=[robot_name, task_type, robot_currency, wage_currency],
outputs=[robot_spec, effective_speed, electricity_cost],
)
calc_btn.click(
calculate,
inputs=[
task_type, robot_name, robot_currency, wage_currency,
hourly_wage, hours_per_day, days_per_week,
electricity_cost, analysis_years, effective_speed,
],
outputs=[output_chart, output_summary],
)
demo.launch(theme=gr.themes.Soft())