File size: 11,323 Bytes
704c39c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
"""
Dispatch AI — AI Cost Calculator
Input: cloud API usage (tokens/month) → Output: cost savings by switching to on-device.
Shows breakeven point, 1-year savings, CO2 reduction.
"""

import gradio as gr

# ---------------------------------------------------------------------------
# Pricing assumptions (USD per 1M tokens) — approximate 2026 rates
# ---------------------------------------------------------------------------
CLOUD_PRICING = {
    "GPT-4o (input)": 2.50,
    "GPT-4o (output)": 10.00,
    "GPT-4o-mini (input)": 0.15,
    "GPT-4o-mini (output)": 0.60,
    "Claude 3.5 Sonnet (input)": 3.00,
    "Claude 3.5 Sonnet (output)": 15.00,
    "Claude 3.5 Haiku (input)": 0.25,
    "Claude 3.5 Haiku (output)": 1.25,
    "Llama 3.1 70B (Together AI)": 0.88,
    "Llama 3.1 8B (Together AI)": 0.18,
    "Mistral Large (input)": 2.00,
    "Mistral Large (output)": 6.00,
    "Gemini 1.5 Pro (input)": 1.25,
    "Gemini 1.5 Pro (output)": 5.00,
    "Gemini 1.5 Flash (input)": 0.075,
    "Gemini 1.5 Flash (output)": 0.30,
}

# On-device cost: amortized phone hardware + electricity
# Phone cost ~$400 amortized over 2 years = $0.0167/day
# Power: ~4W * 8h = 0.032 kWh/day * $0.12/kWh = $0.00384/day
# On-device cost per 1M tokens: effectively $0 (amortized) but we show the hardware cost
PHONE_COST = 400  # USD, one-time
PHONE_LIFETIME_MONTHS = 24
ELECTRICITY_PER_MONTH = 2.50  # USD, charging phones
INFERENCE_SPEED_TPS = 16  # tokens/sec on S20 FE Q4_K_M

# CO2: 1 kWh = ~0.4 kg CO2 (US grid average)
# Cloud data center: ~0.5 kg CO2 / kWh (including cooling overhead)
# On-device: 4W * 8h * 30 days = 0.96 kWh/month → 0.384 kg CO2/month per phone
# Cloud: roughly 0.0004 kg CO2 per 1000 tokens generated
CLOUD_CO2_PER_1M_TOKENS = 0.4  # kg CO2 per 1M tokens (server-side)
ONDEVICE_CO2_PER_MONTH = 0.384  # kg CO2 per phone per month


def calculate_savings(
    input_tokens_m, output_tokens_m, cloud_provider, num_phones, months
):
    """
    Calculate cost savings of switching from cloud API to on-device inference.

    Args:
        input_tokens_m: Input tokens per month in millions
        output_tokens_m: Output tokens per month in millions
        cloud_provider: Key into CLOUD_PRICING
        num_phones: Number of phones to deploy
        months: Number of months to project
    """
    try:
        inp = float(input_tokens_m) if input_tokens_m else 0
        outp = float(output_tokens_m) if output_tokens_m else 0
        phones = int(num_phones) if num_phones else 1
        mos = int(months) if months else 12
    except (ValueError, TypeError):
        return "❌ Invalid input. Please enter numeric values.", "", "", ""

    # Cloud cost
    # We pair input/output pricing: find the matching output key
    base = cloud_provider.replace(" (input)", "").replace(" (output)", "")
    in_key = f"{base} (input)"
    out_key = f"{base} (output)"
    in_price = CLOUD_PRICING.get(in_key, CLOUD_PRICING.get(cloud_provider, 1.0))
    out_price = CLOUD_PRICING.get(out_key, in_price)

    cloud_monthly = (inp * in_price) + (outp * out_price)
    cloud_total = cloud_monthly * mos

    # On-device cost
    # Hardware amortized
    hardware_monthly_per_phone = PHONE_COST / PHONE_LIFETIME_MONTHS
    hardware_total = hardware_monthly_per_phone * phones * mos
    electricity_total = ELECTRICITY_PER_MONTH * phones * mos
    ondevice_total = hardware_total + electricity_total
    ondevice_monthly = hardware_monthly_per_phone * phones + ELECTRICITY_PER_MONTH * phones

    # Savings
    savings = cloud_total - ondevice_total
    savings_pct = (savings / cloud_total * 100) if cloud_total > 0 else 0

    # Breakeven: how many months until on-device cost < cumulative cloud cost
    if cloud_monthly > 0 and ondevice_monthly < cloud_monthly:
        # Month 0: on-device = hardware_monthly * phones, cloud = cloud_monthly
        # After M months: on-device = (hardware_monthly + elec_monthly) * phones * M
        # Cloud = cloud_monthly * M
        # Breakeven: (hardware_monthly + elec_monthly) * phones * M = cloud_monthly * M
        # Actually hardware is amortized so: on-device cumulative = hardware_monthly*phones*M + elec*phones*M
        # Cloud cumulative = cloud_monthly * M
        # Breakeven when cloud > on-device: from month 1 if cloud_monthly > ondevice_monthly
        ondevice_monthly_total = (hardware_monthly_per_phone + ELECTRICITY_PER_MONTH) * phones
        if ondevice_monthly_total < cloud_monthly:
            breakeven = 1  # immediate
        else:
            breakeven = float('inf')
    else:
        breakeven = float('inf')

    breakeven_str = f"Month {breakeven}" if breakeven != float('inf') else "Never (cloud is cheaper)"

    # CO2
    cloud_co2 = (inp + outp) * mos * CLOUD_CO2_PER_1M_TOKENS  # kg
    ondevice_co2 = ONDEVICE_CO2_PER_MONTH * phones * mos
    co2_saved = cloud_co2 - ondevice_co2
    co2_saved_pct = (co2_saved / cloud_co2 * 100) if cloud_co2 > 0 else 0

    # Throughput check: can the phones handle the load?
    phone_capacity_monthly = (INFERENCE_SPEED_TPS * 3600 * 8 * 30) / 1_000_000  # 1M tokens/month per phone (8h/day)
    total_capacity = phone_capacity_monthly * phones
    capacity_note = (
        f"✅ Your {phones} phone(s) can generate ~{total_capacity:.1f}M tokens/month "
        f"(8h/day at {INFERENCE_SPEED_TPS} t/s)"
        if total_capacity >= (inp + outp)
        else f"⚠️ Your {phones} phone(s) can only generate ~{total_capacity:.1f}M tokens/month. "
             f"You need {(inp + outp) / phone_capacity_monthly:.0f} phones for {inp + outp}M tokens/month."
    )

    summary = f"""
## 💰 Cost Comparison — {mos} months

| Metric | Cloud API | On-Device |
|--------|-----------|-----------|
| Monthly Cost | ${cloud_monthly:,.2f} | ${ondevice_monthly:,.2f} |
| {mos}-Month Total | ${cloud_total:,.2f} | ${ondevice_total:,.2f} |
| CO2 Emissions | {cloud_co2:,.1f} kg | {ondevice_co2:,.1f} kg |

---

### 📊 Key Results

- **Total Savings: ${savings:,.2f}** ({savings_pct:.1f}% reduction)
- **Breakeven Point:** {breakeven_str}
- **Monthly Savings:** ${cloud_monthly - ondevice_monthly:,.2f}/month
- **CO2 Reduction:** {co2_saved:,.1f} kg ({co2_saved_pct:.1f}% less)
- **Equivalent to:** {co2_saved / 120:,.1f} trees planted* 🌳

---

### {capacity_note}

---

### 📋 Assumptions

- Cloud provider: **{base}** ($ {in_price}/1M input, ${out_price}/1M output)
- Phone: Samsung S20 FE ($400, 24-month lifespan)
- Inference: {INFERENCE_SPEED_TPS} t/s (Qwen2.5-1.5B Q4_K_M on SD865)
- Electricity: ${ELECTRICITY_PER_MONTH}/month/phone
- CO2: 0.4 kg/1M tokens (cloud) vs 0.384 kg/month (phone)
- *1 tree absorbs ~120 kg CO2/year

---

### 🌍 Environmental Impact

Switching to on-device AI reduces your carbon footprint by **{co2_saved:,.1f} kg of CO2** over {mos} months.
That's equivalent to driving **{co2_saved / 0.4:,.0f} km** less in a petrol car.
"""

    return summary, f"${savings:,.2f}", f"{co2_saved:,.1f} kg", f"{breakeven_str}"


# --- 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; }
"""

with gr.Blocks(
    title="Dispatch AI — AI Cost Calculator",
    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 — AI Cost Calculator
            Calculate savings by switching from cloud APIs to on-device inference · Dispatch AI (FZE) · UAE
            """
        )

    gr.Markdown(
        """
        Enter your current cloud API usage to see how much you'd save by running AI models on phones.
        Includes cost, breakeven point, and CO2 reduction.
        """
    )

    with gr.Row():
        with gr.Column(scale=1):
            input_tokens = gr.Number(
                label="Input Tokens / Month (millions)", value=10,
                info="e.g. 10 = 10 million input tokens/month",
            )
            output_tokens = gr.Number(
                label="Output Tokens / Month (millions)", value=5,
                info="e.g. 5 = 5 million output tokens/month",
            )
            cloud_provider = gr.Dropdown(
                list(dict.fromkeys(
                    k.replace(" (input)", "").replace(" (output)", "") for k in CLOUD_PRICING
                )),
                label="Cloud Provider / Model",
                value="GPT-4o",
                info="Which cloud API are you currently using?",
            )
            num_phones = gr.Number(
                label="Number of Phones to Deploy", value=1, minimum=1,
            )
            months = gr.Slider(
                minimum=1, maximum=36, value=12, step=1,
                label="Projection Period (months)",
            )
            calc_btn = gr.Button("💰 Calculate Savings", variant="primary")

        with gr.Column(scale=2):
            savings_big = gr.Textbox(label="💵 Total Savings", interactive=False, scale=1)
            co2_big = gr.Textbox(label="🌍 CO2 Reduction", interactive=False, scale=1)
            breakeven_big = gr.Textbox(label="⏱️ Breakeven Point", interactive=False, scale=1)
            summary_md = gr.Markdown()

    # Examples
    gr.Examples(
        examples=[
            [10, 5, "GPT-4o", 1, 12],
            [50, 25, "Claude 3.5 Sonnet", 5, 12],
            [100, 50, "GPT-4o", 10, 24],
            [5, 2, "GPT-4o-mini", 1, 12],
            [200, 100, "Claude 3.5 Sonnet", 20, 36],
        ],
        inputs=[input_tokens, output_tokens, cloud_provider, num_phones, months],
        label="Quick Scenarios — click to load",
    )

    # Events
    calc_btn.click(
        calculate_savings,
        inputs=[input_tokens, output_tokens, cloud_provider, num_phones, months],
        outputs=[summary_md, savings_big, co2_big, breakeven_big],
    )

    gr.Markdown(
        """
        <div class="dispatch-footer">
        © 2026 Dispatch AI (FZE) · Sharjah, UAE · License 10818 ·
        On-device inference via llama.cpp Q4_K_M on Snapdragon 865
        </div>
        """
    )

if __name__ == "__main__":
    demo.queue()
    demo.launch()