Spaces:
Runtime error
Runtime error
| """ | |
| 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() | |