Update app.py
Browse files
app.py
CHANGED
|
@@ -4,16 +4,44 @@ import numpy as np
|
|
| 4 |
import plotly.express as px
|
| 5 |
import plotly.graph_objects as go
|
| 6 |
|
| 7 |
-
#
|
| 8 |
-
# Only matching T4-based instances for fair comparison:
|
| 9 |
aws_instances = {
|
| 10 |
-
|
| 11 |
-
"g4dn.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
}
|
| 13 |
|
| 14 |
gcp_instances = {
|
| 15 |
-
|
| 16 |
-
"n1-standard-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
}
|
| 18 |
|
| 19 |
api_pricing = {
|
|
@@ -69,8 +97,8 @@ def calculate_gcp_cost(instance, hours, storage, reserved=False, spot=False, yea
|
|
| 69 |
|
| 70 |
def calculate_api_cost(provider, model, in_tokens, out_tokens, calls):
|
| 71 |
m = api_pricing[provider][model]
|
| 72 |
-
input_cost = in_tokens * m['input_per_1M']
|
| 73 |
-
output_cost = out_tokens * m['output_per_1M']
|
| 74 |
call_cost = calls * 0.0001 if provider == 'TogetherAI' else 0
|
| 75 |
return {'total_cost': input_cost + output_cost + call_cost, 'details': m}
|
| 76 |
|
|
@@ -91,45 +119,53 @@ def filter_compatible(instances, min_mem):
|
|
| 91 |
|
| 92 |
def generate_cost_comparison(
|
| 93 |
compute_hours, tokens_per_month, input_ratio, api_calls,
|
| 94 |
-
model_size, storage_gb, reserved_instances, spot_instances, multi_year_commitment
|
|
|
|
| 95 |
):
|
| 96 |
years = int(multi_year_commitment)
|
| 97 |
-
in_tokens = tokens_per_month * (input_ratio/100)
|
| 98 |
-
out_tokens = tokens_per_month - in_tokens
|
| 99 |
min_mem = model_sizes[model_size]['memory_required']
|
| 100 |
|
|
|
|
| 101 |
aws_comp = filter_compatible(aws_instances, min_mem)
|
| 102 |
gcp_comp = filter_compatible(gcp_instances, min_mem)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
|
| 104 |
results = []
|
| 105 |
|
| 106 |
# AWS table
|
| 107 |
aws_html = '<h3>AWS Instances</h3>'
|
| 108 |
-
aws_html += '<table width="100%"><tr><th>Instance</th><th>vCPUs</th><th>Memory</th><th>GPU</th><th>Monthly Cost ($)</th></tr>'
|
| 109 |
if aws_comp:
|
| 110 |
for inst in aws_comp:
|
| 111 |
res = calculate_aws_cost(inst, compute_hours, storage_gb, reserved_instances, spot_instances, years)
|
| 112 |
-
aws_html += f'<tr><td>{inst}</td><td>{res["details"]["vcpus"]}</td><td>{res["details"]["memory"]}GB</td><td>{res["details"]["gpu"]}</td><td>${res["total_cost"]:.2f}</td></tr>'
|
| 113 |
# best AWS
|
| 114 |
best_aws = min(aws_comp, key=lambda x: calculate_aws_cost(x, compute_hours, storage_gb, reserved_instances, spot_instances, years)['total_cost'])
|
| 115 |
best_aws_cost = calculate_aws_cost(best_aws, compute_hours, storage_gb, reserved_instances, spot_instances, years)['total_cost']
|
| 116 |
-
|
|
|
|
| 117 |
else:
|
| 118 |
-
aws_html += '<tr><td colspan="
|
| 119 |
aws_html += '</table>'
|
| 120 |
|
| 121 |
# GCP table
|
| 122 |
gcp_html = '<h3>GCP Instances</h3>'
|
| 123 |
-
gcp_html += '<table width="100%"><tr><th>Instance</th><th>vCPUs</th><th>Memory</th><th>GPU</th><th>Monthly Cost ($)</th></tr>'
|
| 124 |
if gcp_comp:
|
| 125 |
for inst in gcp_comp:
|
| 126 |
res = calculate_gcp_cost(inst, compute_hours, storage_gb, reserved_instances, spot_instances, years)
|
| 127 |
-
gcp_html += f'<tr><td>{inst}</td><td>{res["details"]["vcpus"]}</td><td>{res["details"]["memory"]}GB</td><td>{res["details"]["gpu"
|
| 128 |
best_gcp = min(gcp_comp, key=lambda x: calculate_gcp_cost(x, compute_hours, storage_gb, reserved_instances, spot_instances, years)['total_cost'])
|
| 129 |
best_gcp_cost = calculate_gcp_cost(best_gcp, compute_hours, storage_gb, reserved_instances, spot_instances, years)['total_cost']
|
| 130 |
-
|
|
|
|
| 131 |
else:
|
| 132 |
-
gcp_html += '<tr><td colspan="
|
| 133 |
gcp_html += '</table>'
|
| 134 |
|
| 135 |
# API table
|
|
@@ -140,28 +176,71 @@ def generate_cost_comparison(
|
|
| 140 |
for mdl in api_pricing[prov]:
|
| 141 |
res = calculate_api_cost(prov, mdl, in_tokens, out_tokens, api_calls)
|
| 142 |
details = api_pricing[prov][mdl]
|
| 143 |
-
api_html += f'<tr><td>{prov}</td><td>{mdl}</td><td>${in_tokens * details["input_per_1M"]:.2f}</td><td>${out_tokens * details["output_per_1M"]:.2f}</td><td>${res["total_cost"]:.2f}</td><td>{details["token_context"]:,}</td></tr>'
|
| 144 |
api_costs[(prov, mdl)] = res['total_cost']
|
| 145 |
api_html += '</table>'
|
| 146 |
-
|
| 147 |
-
|
|
|
|
|
|
|
| 148 |
|
| 149 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
|
| 151 |
# Chart with annotations
|
| 152 |
df = pd.DataFrame(results)
|
| 153 |
-
colors = {
|
| 154 |
|
| 155 |
# Create figure using plotly graph objects for more control
|
| 156 |
fig = go.Figure()
|
| 157 |
|
| 158 |
# Add bars
|
| 159 |
for i, row in df.iterrows():
|
|
|
|
| 160 |
fig.add_trace(go.Bar(
|
| 161 |
x=[row['provider']],
|
| 162 |
y=[row['cost']],
|
| 163 |
name=row['provider'],
|
| 164 |
-
marker_color=
|
| 165 |
))
|
| 166 |
|
| 167 |
# Add annotations on top of each bar
|
|
@@ -186,6 +265,7 @@ def generate_cost_comparison(
|
|
| 186 |
|
| 187 |
html = f"""
|
| 188 |
<div style='padding:20px;font-family:Arial;'>
|
|
|
|
| 189 |
{aws_html}
|
| 190 |
{gcp_html}
|
| 191 |
{api_html}
|
|
@@ -204,6 +284,7 @@ with gr.Blocks(title="Cloud Cost Estimator", theme=gr.themes.Soft(primary_hue="i
|
|
| 204 |
api_calls = gr.Slider(label="API Calls per Month", minimum=100, maximum=100000, value=5000, step=100)
|
| 205 |
model_size = gr.Dropdown(label="Model Size", choices=list(model_sizes.keys()), value="Medium (13B parameters)")
|
| 206 |
storage_gb = gr.Slider(label="Storage (GB)", minimum=10, maximum=1000, value=100)
|
|
|
|
| 207 |
reserved_instances = gr.Checkbox(label="Reserved Instances", value=False)
|
| 208 |
spot_instances = gr.Checkbox(label="Spot Instances", value=False)
|
| 209 |
multi_year_commitment = gr.Radio(label="Commitment Period (years)", choices=["1","3"], value="1")
|
|
@@ -213,21 +294,14 @@ with gr.Blocks(title="Cloud Cost Estimator", theme=gr.themes.Soft(primary_hue="i
|
|
| 213 |
|
| 214 |
# Create inputs list for the function
|
| 215 |
inputs = [compute_hours, tokens_per_month, input_ratio, api_calls,
|
| 216 |
-
model_size, storage_gb, reserved_instances, spot_instances, multi_year_commitment]
|
| 217 |
outputs = [out_html, out_plot]
|
| 218 |
|
| 219 |
# Initial calculation on load
|
| 220 |
demo.load(generate_cost_comparison, inputs, outputs)
|
| 221 |
|
| 222 |
# Update on each input change
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
input_ratio.change(generate_cost_comparison, inputs, outputs)
|
| 226 |
-
api_calls.change(generate_cost_comparison, inputs, outputs)
|
| 227 |
-
model_size.change(generate_cost_comparison, inputs, outputs)
|
| 228 |
-
storage_gb.change(generate_cost_comparison, inputs, outputs)
|
| 229 |
-
reserved_instances.change(generate_cost_comparison, inputs, outputs)
|
| 230 |
-
spot_instances.change(generate_cost_comparison, inputs, outputs)
|
| 231 |
-
multi_year_commitment.change(generate_cost_comparison, inputs, outputs)
|
| 232 |
|
| 233 |
demo.launch()
|
|
|
|
| 4 |
import plotly.express as px
|
| 5 |
import plotly.graph_objects as go
|
| 6 |
|
| 7 |
+
# Updated pricing data - restructured for better comparison
|
|
|
|
| 8 |
aws_instances = {
|
| 9 |
+
# T4 GPU Instances (entry level)
|
| 10 |
+
"g4dn.xlarge": {"vcpus": 4, "memory": 16, "gpu": "1x NVIDIA T4", "hourly_rate": 0.526, "gpu_memory": "16GB", "tier": "Entry"},
|
| 11 |
+
"g4dn.2xlarge": {"vcpus": 8, "memory": 32, "gpu": "1x NVIDIA T4", "hourly_rate": 0.752, "gpu_memory": "16GB", "tier": "Entry"},
|
| 12 |
+
|
| 13 |
+
# A10G GPU Instances (mid-tier)
|
| 14 |
+
"g5.xlarge": {"vcpus": 4, "memory": 16, "gpu": "1x NVIDIA A10G", "hourly_rate": 0.65, "gpu_memory": "24GB", "tier": "Mid"},
|
| 15 |
+
"g5.2xlarge": {"vcpus": 8, "memory": 32, "gpu": "1x NVIDIA A10G", "hourly_rate": 1.006, "gpu_memory": "24GB", "tier": "Mid"},
|
| 16 |
+
|
| 17 |
+
# V100 GPU Instances (high-tier)
|
| 18 |
+
"p3.2xlarge": {"vcpus": 8, "memory": 61, "gpu": "1x NVIDIA V100", "hourly_rate": 3.06, "gpu_memory": "16GB", "tier": "High"},
|
| 19 |
+
|
| 20 |
+
# A100 GPU Instances (premium)
|
| 21 |
+
"p4d.24xlarge": {"vcpus": 96, "memory": 1152, "gpu": "8x NVIDIA A100", "hourly_rate": 32.77, "gpu_memory": "8x40GB", "tier": "Premium"},
|
| 22 |
+
|
| 23 |
+
# Added comparable instances to match GCP
|
| 24 |
+
"p4d.xlarge": {"vcpus": 12, "memory": 85, "gpu": "1x NVIDIA A100", "hourly_rate": 4.10, "gpu_memory": "40GB", "tier": "Premium"},
|
| 25 |
+
"p4d.2xlarge": {"vcpus": 24, "memory": 170, "gpu": "2x NVIDIA A100", "hourly_rate": 8.20, "gpu_memory": "2x40GB", "tier": "Premium"},
|
| 26 |
+
"p4d.4xlarge": {"vcpus": 48, "memory": 340, "gpu": "4x NVIDIA A100", "hourly_rate": 16.40, "gpu_memory": "4x40GB", "tier": "Premium"},
|
| 27 |
}
|
| 28 |
|
| 29 |
gcp_instances = {
|
| 30 |
+
# T4 GPU Instances (entry level)
|
| 31 |
+
"n1-standard-4-t4": {"vcpus": 4, "memory": 15, "gpu": "1x NVIDIA T4", "hourly_rate": 0.49, "gpu_memory": "16GB", "tier": "Entry"},
|
| 32 |
+
"n1-standard-8-t4": {"vcpus": 8, "memory": 30, "gpu": "1x NVIDIA T4", "hourly_rate": 0.69, "gpu_memory": "16GB", "tier": "Entry"},
|
| 33 |
+
|
| 34 |
+
# L4 GPU Instances (mid-tier)
|
| 35 |
+
"g2-standard-4": {"vcpus": 4, "memory": 16, "gpu": "1x NVIDIA L4", "hourly_rate": 0.59, "gpu_memory": "24GB", "tier": "Mid"},
|
| 36 |
+
"g2-standard-8": {"vcpus": 8, "memory": 32, "gpu": "1x NVIDIA L4", "hourly_rate": 0.89, "gpu_memory": "24GB", "tier": "Mid"},
|
| 37 |
+
|
| 38 |
+
# Added comparable V100 instance
|
| 39 |
+
"n1-standard-8-v100": {"vcpus": 8, "memory": 60, "gpu": "1x NVIDIA V100", "hourly_rate": 2.95, "gpu_memory": "16GB", "tier": "High"},
|
| 40 |
+
|
| 41 |
+
# A100 GPU Instances (premium)
|
| 42 |
+
"a2-highgpu-1g": {"vcpus": 12, "memory": 85, "gpu": "1x NVIDIA A100", "hourly_rate": 1.46, "gpu_memory": "40GB", "tier": "Premium"},
|
| 43 |
+
"a2-highgpu-2g": {"vcpus": 24, "memory": 170, "gpu": "2x NVIDIA A100", "hourly_rate": 2.93, "gpu_memory": "2x40GB", "tier": "Premium"},
|
| 44 |
+
"a2-highgpu-4g": {"vcpus": 48, "memory": 340, "gpu": "4x NVIDIA A100", "hourly_rate": 5.86, "gpu_memory": "4x40GB", "tier": "Premium"},
|
| 45 |
}
|
| 46 |
|
| 47 |
api_pricing = {
|
|
|
|
| 97 |
|
| 98 |
def calculate_api_cost(provider, model, in_tokens, out_tokens, calls):
|
| 99 |
m = api_pricing[provider][model]
|
| 100 |
+
input_cost = in_tokens * m['input_per_1M'] / 1000000
|
| 101 |
+
output_cost = out_tokens * m['output_per_1M'] / 1000000
|
| 102 |
call_cost = calls * 0.0001 if provider == 'TogetherAI' else 0
|
| 103 |
return {'total_cost': input_cost + output_cost + call_cost, 'details': m}
|
| 104 |
|
|
|
|
| 119 |
|
| 120 |
def generate_cost_comparison(
|
| 121 |
compute_hours, tokens_per_month, input_ratio, api_calls,
|
| 122 |
+
model_size, storage_gb, reserved_instances, spot_instances, multi_year_commitment,
|
| 123 |
+
comparison_tier
|
| 124 |
):
|
| 125 |
years = int(multi_year_commitment)
|
| 126 |
+
in_tokens = tokens_per_month * 1000000 * (input_ratio/100)
|
| 127 |
+
out_tokens = tokens_per_month * 1000000 - in_tokens
|
| 128 |
min_mem = model_sizes[model_size]['memory_required']
|
| 129 |
|
| 130 |
+
# Filter by both memory requirements and tier if a tier is selected
|
| 131 |
aws_comp = filter_compatible(aws_instances, min_mem)
|
| 132 |
gcp_comp = filter_compatible(gcp_instances, min_mem)
|
| 133 |
+
|
| 134 |
+
if comparison_tier != "All":
|
| 135 |
+
aws_comp = {k: v for k, v in aws_comp.items() if v.get('tier', '') == comparison_tier}
|
| 136 |
+
gcp_comp = {k: v for k, v in gcp_comp.items() if v.get('tier', '') == comparison_tier}
|
| 137 |
|
| 138 |
results = []
|
| 139 |
|
| 140 |
# AWS table
|
| 141 |
aws_html = '<h3>AWS Instances</h3>'
|
| 142 |
+
aws_html += '<table width="100%"><tr><th>Instance</th><th>vCPUs</th><th>Memory</th><th>GPU</th><th>Tier</th><th>Monthly Cost ($)</th></tr>'
|
| 143 |
if aws_comp:
|
| 144 |
for inst in aws_comp:
|
| 145 |
res = calculate_aws_cost(inst, compute_hours, storage_gb, reserved_instances, spot_instances, years)
|
| 146 |
+
aws_html += f'<tr><td>{inst}</td><td>{res["details"]["vcpus"]}</td><td>{res["details"]["memory"]}GB</td><td>{res["details"]["gpu"]}</td><td>{res["details"].get("tier", "")}</td><td>${res["total_cost"]:.2f}</td></tr>'
|
| 147 |
# best AWS
|
| 148 |
best_aws = min(aws_comp, key=lambda x: calculate_aws_cost(x, compute_hours, storage_gb, reserved_instances, spot_instances, years)['total_cost'])
|
| 149 |
best_aws_cost = calculate_aws_cost(best_aws, compute_hours, storage_gb, reserved_instances, spot_instances, years)['total_cost']
|
| 150 |
+
best_aws_tier = aws_instances[best_aws].get('tier', '')
|
| 151 |
+
results.append({'provider': f'AWS ({best_aws})', 'cost': best_aws_cost, 'type': 'Cloud', 'tier': best_aws_tier})
|
| 152 |
else:
|
| 153 |
+
aws_html += '<tr><td colspan="6">No compatible instances</td></tr>'
|
| 154 |
aws_html += '</table>'
|
| 155 |
|
| 156 |
# GCP table
|
| 157 |
gcp_html = '<h3>GCP Instances</h3>'
|
| 158 |
+
gcp_html += '<table width="100%"><tr><th>Instance</th><th>vCPUs</th><th>Memory</th><th>GPU</th><th>Tier</th><th>Monthly Cost ($)</th></tr>'
|
| 159 |
if gcp_comp:
|
| 160 |
for inst in gcp_comp:
|
| 161 |
res = calculate_gcp_cost(inst, compute_hours, storage_gb, reserved_instances, spot_instances, years)
|
| 162 |
+
gcp_html += f'<tr><td>{inst}</td><td>{res["details"]["vcpus"]}</td><td>{res["details"]["memory"]}GB</td><td>{res["details"]["gpu"]}</td><td>{res["details"].get("tier", "")}</td><td>${res["total_cost"]:.2f}</td></tr>'
|
| 163 |
best_gcp = min(gcp_comp, key=lambda x: calculate_gcp_cost(x, compute_hours, storage_gb, reserved_instances, spot_instances, years)['total_cost'])
|
| 164 |
best_gcp_cost = calculate_gcp_cost(best_gcp, compute_hours, storage_gb, reserved_instances, spot_instances, years)['total_cost']
|
| 165 |
+
best_gcp_tier = gcp_instances[best_gcp].get('tier', '')
|
| 166 |
+
results.append({'provider': f'GCP ({best_gcp})', 'cost': best_gcp_cost, 'type': 'Cloud', 'tier': best_gcp_tier})
|
| 167 |
else:
|
| 168 |
+
gcp_html += '<tr><td colspan="6">No compatible instances</td></tr>'
|
| 169 |
gcp_html += '</table>'
|
| 170 |
|
| 171 |
# API table
|
|
|
|
| 176 |
for mdl in api_pricing[prov]:
|
| 177 |
res = calculate_api_cost(prov, mdl, in_tokens, out_tokens, api_calls)
|
| 178 |
details = api_pricing[prov][mdl]
|
| 179 |
+
api_html += f'<tr><td>{prov}</td><td>{mdl}</td><td>${in_tokens * details["input_per_1M"] / 1000000:.2f}</td><td>${out_tokens * details["output_per_1M"] / 1000000:.2f}</td><td>${res["total_cost"]:.2f}</td><td>{details["token_context"]:,}</td></tr>'
|
| 180 |
api_costs[(prov, mdl)] = res['total_cost']
|
| 181 |
api_html += '</table>'
|
| 182 |
+
|
| 183 |
+
if api_costs:
|
| 184 |
+
best_api = min(api_costs, key=api_costs.get)
|
| 185 |
+
results.append({'provider': f'{best_api[0]} ({best_api[1]})', 'cost': api_costs[best_api], 'type': 'API', 'tier': 'API'})
|
| 186 |
|
| 187 |
+
# Direct comparison tables for similar instances
|
| 188 |
+
direct_comparison_html = ""
|
| 189 |
+
if comparison_tier != "All" and comparison_tier != "API":
|
| 190 |
+
direct_comparison_html = f'<h3>Direct {comparison_tier} Tier Comparison</h3>'
|
| 191 |
+
direct_comparison_html += '<table width="100%"><tr><th>Provider</th><th>Instance</th><th>vCPUs</th><th>Memory</th><th>GPU</th><th>Monthly Cost ($)</th></tr>'
|
| 192 |
+
|
| 193 |
+
aws_filtered = {k: v for k, v in aws_instances.items() if v.get('tier', '') == comparison_tier}
|
| 194 |
+
gcp_filtered = {k: v for k, v in gcp_instances.items() if v.get('tier', '') == comparison_tier}
|
| 195 |
+
|
| 196 |
+
# Group by vCPU for comparison
|
| 197 |
+
vcpu_groups = {}
|
| 198 |
+
for inst, data in aws_filtered.items():
|
| 199 |
+
vcpu = data['vcpus']
|
| 200 |
+
if vcpu not in vcpu_groups:
|
| 201 |
+
vcpu_groups[vcpu] = {'aws': [], 'gcp': []}
|
| 202 |
+
vcpu_groups[vcpu]['aws'].append(inst)
|
| 203 |
+
|
| 204 |
+
for inst, data in gcp_filtered.items():
|
| 205 |
+
vcpu = data['vcpus']
|
| 206 |
+
if vcpu not in vcpu_groups:
|
| 207 |
+
vcpu_groups[vcpu] = {'aws': [], 'gcp': []}
|
| 208 |
+
vcpu_groups[vcpu]['gcp'].append(inst)
|
| 209 |
+
|
| 210 |
+
# Display direct comparisons
|
| 211 |
+
for vcpu in sorted(vcpu_groups.keys()):
|
| 212 |
+
group = vcpu_groups[vcpu]
|
| 213 |
+
for aws_inst in group['aws']:
|
| 214 |
+
aws_cost = calculate_aws_cost(aws_inst, compute_hours, storage_gb, reserved_instances, spot_instances, years)
|
| 215 |
+
aws_data = aws_cost['details']
|
| 216 |
+
direct_comparison_html += f'<tr><td>AWS</td><td>{aws_inst}</td><td>{aws_data["vcpus"]}</td><td>{aws_data["memory"]}GB</td><td>{aws_data["gpu"]}</td><td>${aws_cost["total_cost"]:.2f}</td></tr>'
|
| 217 |
+
|
| 218 |
+
for gcp_inst in group['gcp']:
|
| 219 |
+
gcp_cost = calculate_gcp_cost(gcp_inst, compute_hours, storage_gb, reserved_instances, spot_instances, years)
|
| 220 |
+
gcp_data = gcp_cost['details']
|
| 221 |
+
direct_comparison_html += f'<tr><td>GCP</td><td>{gcp_inst}</td><td>{gcp_data["vcpus"]}</td><td>{gcp_data["memory"]}GB</td><td>{gcp_data["gpu"]}</td><td>${gcp_cost["total_cost"]:.2f}</td></tr>'
|
| 222 |
+
|
| 223 |
+
# Add separator between different vCPU groups
|
| 224 |
+
if vcpu != sorted(vcpu_groups.keys())[-1]:
|
| 225 |
+
direct_comparison_html += '<tr><td colspan="6" style="border-bottom: 1px solid #ccc; height: 10px;"></td></tr>'
|
| 226 |
+
|
| 227 |
+
direct_comparison_html += '</table>'
|
| 228 |
|
| 229 |
# Chart with annotations
|
| 230 |
df = pd.DataFrame(results)
|
| 231 |
+
colors = {'Entry': '#66BB6A', 'Mid': '#42A5F5', 'High': '#FFA726', 'Premium': '#EF5350', 'API': '#AB47BC'}
|
| 232 |
|
| 233 |
# Create figure using plotly graph objects for more control
|
| 234 |
fig = go.Figure()
|
| 235 |
|
| 236 |
# Add bars
|
| 237 |
for i, row in df.iterrows():
|
| 238 |
+
tier_color = colors.get(row.get('tier', 'API'), '#9E9E9E')
|
| 239 |
fig.add_trace(go.Bar(
|
| 240 |
x=[row['provider']],
|
| 241 |
y=[row['cost']],
|
| 242 |
name=row['provider'],
|
| 243 |
+
marker_color=tier_color
|
| 244 |
))
|
| 245 |
|
| 246 |
# Add annotations on top of each bar
|
|
|
|
| 265 |
|
| 266 |
html = f"""
|
| 267 |
<div style='padding:20px;font-family:Arial;'>
|
| 268 |
+
{direct_comparison_html}
|
| 269 |
{aws_html}
|
| 270 |
{gcp_html}
|
| 271 |
{api_html}
|
|
|
|
| 284 |
api_calls = gr.Slider(label="API Calls per Month", minimum=100, maximum=100000, value=5000, step=100)
|
| 285 |
model_size = gr.Dropdown(label="Model Size", choices=list(model_sizes.keys()), value="Medium (13B parameters)")
|
| 286 |
storage_gb = gr.Slider(label="Storage (GB)", minimum=10, maximum=1000, value=100)
|
| 287 |
+
comparison_tier = gr.Radio(label="Comparison Tier", choices=["All", "Entry", "Mid", "High", "Premium", "API"], value="All")
|
| 288 |
reserved_instances = gr.Checkbox(label="Reserved Instances", value=False)
|
| 289 |
spot_instances = gr.Checkbox(label="Spot Instances", value=False)
|
| 290 |
multi_year_commitment = gr.Radio(label="Commitment Period (years)", choices=["1","3"], value="1")
|
|
|
|
| 294 |
|
| 295 |
# Create inputs list for the function
|
| 296 |
inputs = [compute_hours, tokens_per_month, input_ratio, api_calls,
|
| 297 |
+
model_size, storage_gb, reserved_instances, spot_instances, multi_year_commitment, comparison_tier]
|
| 298 |
outputs = [out_html, out_plot]
|
| 299 |
|
| 300 |
# Initial calculation on load
|
| 301 |
demo.load(generate_cost_comparison, inputs, outputs)
|
| 302 |
|
| 303 |
# Update on each input change
|
| 304 |
+
for input_component in inputs:
|
| 305 |
+
input_component.change(generate_cost_comparison, inputs, outputs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 306 |
|
| 307 |
demo.launch()
|