import gradio as gr import plotly.graph_objects as go import pandas as pd import numpy as np def calculate_runpod_cost_revised( requests_per_hour, execution_time_per_request, active_cost_per_second, flex_cost_per_second, cold_start_penalty, num_active_workers, concurrent_batch_size=1 # How many requests can be processed simultaneously by one worker ): # Monthly hours and requests monthly_hours = 24 * 30 seconds_per_hour = 3600 monthly_requests = requests_per_hour * monthly_hours # Calculate active worker capacity (requests per hour) # Each worker can process (concurrent_batch_size) requests at a time active_capacity_per_hour = (seconds_per_hour / execution_time_per_request) * num_active_workers * concurrent_batch_size # Total requests handled by active workers over the month active_requests_handled = min(monthly_requests, active_capacity_per_hour * monthly_hours) # Remaining requests go to flex workers flex_requests = max(0, monthly_requests - active_requests_handled) # Active worker cost (constant regardless of actual usage) active_cost = num_active_workers * active_cost_per_second * seconds_per_hour * monthly_hours # For flex workers, we calculate cold starts based on request arrival pattern # This is simplified - in reality depends on actual traffic patterns avg_requests_per_cold_start = concurrent_batch_size * 2 # Estimate that batches arrive close enough to reuse some workers cold_starts = flex_requests / avg_requests_per_cold_start if flex_requests > 0 else 0 # Flex worker cost (only pay for processing time + cold starts) flex_processing_cost = flex_requests * execution_time_per_request * flex_cost_per_second flex_cold_start_cost = cold_starts * cold_start_penalty * flex_cost_per_second flex_cost = flex_processing_cost + flex_cold_start_cost # Active worker utilization active_utilization = (active_requests_handled / (active_capacity_per_hour * monthly_hours) * 100) if num_active_workers > 0 else 0 total_monthly_cost = active_cost + flex_cost return { "monthly_requests": monthly_requests, "active_requests": active_requests_handled, "flex_requests": flex_requests, "active_cost": active_cost, "flex_cost": flex_cost, "total_monthly_cost": total_monthly_cost, "active_utilization": active_utilization } def generate_cost_projection( min_requests, max_requests, execution_time, active_cost, flex_cost, num_active_workers, cold_start, concurrent_batch_size ): # Generate data for different request volumes request_volumes = np.linspace(min_requests, max_requests, 20) results = [] for req_vol in request_volumes: result = calculate_runpod_cost_revised( req_vol, execution_time, active_cost, flex_cost, cold_start, num_active_workers, concurrent_batch_size ) results.append({ 'requests_per_hour': req_vol, 'monthly_requests': result['monthly_requests'], 'active_cost': result['active_cost'], 'flex_cost': result['flex_cost'], 'total_cost': result['total_monthly_cost'], 'active_utilization': result['active_utilization'] }) df = pd.DataFrame(results) # Create plotly figure fig = go.Figure() fig.add_trace(go.Scatter( x=df['requests_per_hour'], y=df['active_cost'], name='Active Worker Cost', line=dict(color='blue') )) fig.add_trace(go.Scatter( x=df['requests_per_hour'], y=df['flex_cost'], name='Flex Worker Cost', line=dict(color='orange') )) fig.add_trace(go.Scatter( x=df['requests_per_hour'], y=df['total_cost'], name='Total Cost', line=dict(color='green', width=3) )) fig.update_layout( title='RunPod Serverless Monthly Cost Projection', xaxis_title='Requests per Hour', yaxis_title='Monthly Cost ($)', hovermode='x unified' ) return fig def calculate_specific_cost( requests, execution_time, active_cost, flex_cost, num_active_workers, cold_start, concurrent_batch_size ): result = calculate_runpod_cost_revised( requests, execution_time, active_cost, flex_cost, cold_start, num_active_workers, concurrent_batch_size ) # Format the output HTML for the table html = f"""
Metric Value
Monthly Requests {result['monthly_requests']:,.0f}
Requests Handled by Active Workers {result['active_requests']:,.0f}
Requests Handled by Flex Workers {result['flex_requests']:,.0f}
Active Worker Cost ${result['active_cost']:,.2f}
Flex Worker Cost ${result['flex_cost']:,.2f}
Total Monthly Cost ${result['total_monthly_cost']:,.2f}
Active Worker Utilization {result['active_utilization']:.1f}%
""" return html # Create theme theme = gr.themes.Default( primary_hue=gr.themes.colors.red, secondary_hue=gr.themes.colors.red, neutral_hue=gr.themes.colors.slate, ) # Create Gradio interface with gr.Blocks(title="RunPod Serverless Cost Estimator", theme=theme) as demo: gr.Markdown("# RunPod Serverless Cost Estimator") gr.Markdown("Estimate your monthly RunPod Serverless costs based on request volume and execution time") with gr.Row(): with gr.Column(scale=1): min_requests = gr.Slider(minimum=100, maximum=50000, value=1000, step=1000, label="Minimum Requests/Hour") max_requests = gr.Slider(minimum=1000, maximum=100000, value=20000, step=1000, label="Maximum Requests/Hour") execution_time = gr.Slider(minimum=1, maximum=120, value=30, step=1, label="Execution Time per Request (seconds)") active_cost = gr.Number(value=0.00019, label="Active Worker Cost ($/second)", precision=5) flex_cost = gr.Number(value=0.00031, label="Flex Worker Cost ($/second)", precision=5) num_active_workers = gr.Slider(minimum=0, maximum=600, value=30, step=10, label="Number of Active Workers") cold_start = gr.Slider(minimum=0, maximum=60, value=1, step=1, label="Cold Start Penalty (seconds)") concurrent_batch_size = gr.Slider(minimum=1, maximum=10, value=2, step=1, label="Concurrent Requests per Worker") plot_button = gr.Button("Generate Cost Projection") with gr.Column(scale=2): plot_output = gr.Plot(label="Cost Projection") gr.Markdown("## Cost Breakdown for Specific Request Volume") with gr.Row(): with gr.Column(scale=1): specific_requests = gr.Number(value=10000, label="Requests per Hour", precision=0) calc_button = gr.Button("Calculate Cost") with gr.Column(scale=2): cost_table = gr.HTML() plot_button.click( generate_cost_projection, inputs=[min_requests, max_requests, execution_time, active_cost, flex_cost, num_active_workers, cold_start, concurrent_batch_size], outputs=plot_output ) calc_button.click( calculate_specific_cost, inputs=[specific_requests, execution_time, active_cost, flex_cost, num_active_workers, cold_start, concurrent_batch_size], outputs=cost_table ) # Launch the app if __name__ == "__main__": demo.launch()