File size: 9,598 Bytes
e0e93c4
50f19fa
044dd38
5919083
1c2b775
ea19e17
d2258bf
1c2b775
ea19e17
f630ea0
eef299f
 
ea19e17
9411fc2
9c1a1da
9411fc2
9c1a1da
 
 
 
 
9411fc2
eef299f
044dd38
 
 
 
 
 
 
 
1c2b775
a0c59c8
 
 
 
 
 
 
 
 
 
 
 
 
9411fc2
a0c59c8
 
 
 
 
1c2b775
a0c59c8
 
1c2b775
a0c59c8
 
 
564f119
7ebfebe
a0c59c8
 
 
 
 
 
564f119
a0c59c8
 
 
 
 
564f119
a0c59c8
 
 
 
 
 
 
 
ea19e17
eef299f
 
 
a0c59c8
01f5691
a0c59c8
01f5691
 
eef299f
 
 
01f5691
eef299f
 
a0c59c8
eef299f
 
80b9501
a0c59c8
 
 
 
ecaa1ea
a0c59c8
 
 
 
 
 
 
 
 
 
 
5919083
ecaa1ea
 
eef299f
50f19fa
ea19e17
 
 
044dd38
 
 
ecaa1ea
f4c03fc
80b9501
f4c03fc
 
80b9501
ecaa1ea
044dd38
 
 
73d3fc4
2d9906b
50f19fa
ecaa1ea
 
80b9501
b3b6d77
2d9906b
50f19fa
ecaa1ea
 
80b9501
73d3fc4
80b9501
 
ea19e17
f4c03fc
ea19e17
 
f4c03fc
 
7ebfebe
 
ea19e17
7ebfebe
 
9411fc2
5919083
 
1c2b775
 
 
9411fc2
 
1c2b775
 
9c1a1da
9411fc2
1c2b775
 
ea19e17
a0c59c8
 
 
 
50f19fa
 
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
import gradio as gr
import models
import pandas as pd
import theme
import matplotlib.pyplot as plt
    
text = "<h1 style='text-align: center; color: #333333; font-size: 40px;'>AI TCO Comparison Calculator"
text2 = "Please note that the cost/request only defines the infrastructure cost for deployment. The labor cost must be added for the whole AI model service deployment TCO."
description=f"""
<p>In this demo application, we help you compare different AI model services, such as SaaS or "Deploy yourself" solutions, based on the Total Cost of Ownership for their deployment. 😊</p> 
<p>Please note that we focus on getting the service up and running, but not the maintenance that follows.πŸš€</p>
<p>If you want to <strong>contribute to the calculator</strong> by adding your own AI service option, follow this <a href="https://huggingface.co/spaces/mithril-security/TCO_calculator/blob/main/How_to_contribute.md">tutorial</a> πŸ‘ˆ. </p>
"""
formula = r"""
$CR = \frac{CIT_{1K} \times IT + COT_{1K} \times OT}{1000}$  <br>
with: <br>
$CR$ = Cost per Request <br>
$CIT_{1K}$ = Cost per 1000 Input Tokens <br>
$COT_{1K}$ = Cost per 1000 Output Tokens <br>
$IT$ = Input Tokens <br>
$OT$ = Output Tokens
"""

def on_use_case_change(use_case):
    if use_case == "Summarize":
        return gr.update(value=500), gr.update(value=200)
    elif use_case == "Question-Answering":
        return gr.update(value=300), gr.update(value=300)
    else:
        return gr.update(value=50), gr.update(value=10)
    
def compare_info(tco1, tco2, dropdown, dropdown2):
    if error_occurred == False :
        #Compute the cost/request ratio
        r = tco1 / tco2   
        if r < 1:
            comparison_result = f"""The cost/request of the second {dropdown2} service is <b>{1/r:.5f} times more expensive</b> than the one of the first {dropdown} service."""   
        elif r > 1:
            comparison_result = f"""The cost/request of the second {dropdown2} service is <b>{r:.5f} times cheaper</b> than the one of the first {dropdown} service."""
        else:
            comparison_result = f"""Both solutions have the <b>same cost/request</b>."""
            
        # Create a bar chart
        services = [dropdown, dropdown2]
        costs_to_compare = [tco1, tco2]
        
        plt.figure(figsize=(6, 4))
        plt.bar(services, costs_to_compare, color=['red', 'green'])
        plt.xlabel('AI option services', fontsize=10)
        plt.ylabel('($) Cost/Request', fontsize=10)
        plt.title('Comparison of Cost/Request', fontsize=14)

        plt.tight_layout()
        plt.savefig('cost_comparison.png')  # Save to a file

        return gr.update(value='cost_comparison.png', visible=True), comparison_result
    else:
        return None, ""

def create_table(tco1, tco2, labor_cost1, labor_cost2, dropdown, dropdown2, latency, latency2):
    if error_occurred == False:
        list_values = []
        first_sol = [tco1, labor_cost1, latency]
        second_sol = [tco2, labor_cost2, latency2]
        list_values.append(first_sol)
        list_values.append(second_sol)

        data = pd.DataFrame(list_values, index=[dropdown, dropdown2], columns=["Cost/request ($) ", "Labor Cost ($/month)", "Average latency (s)"])
        
        formatted_data = data.copy()
        formatted_data["Cost/request ($) "] = formatted_data["Cost/request ($) "].apply('{:.5f}'.format)
        formatted_data["Labor Cost ($/month)"] = formatted_data["Labor Cost ($/month)"].apply('{:.0f}'.format)

        styled_data = formatted_data.style\
            .set_properties(**{'background-color': '#ffffff', 'color': '#000000', 'border-color': '#e0e0e0', 'border-width': '1px', 'border-style': 'solid'})\
            .to_html()
        centered_styled_data = f"<center>{styled_data}</center>"
        
        return gr.update(value=centered_styled_data)
    else:
        return ""

def compute_cost_per_request(*args):
    dropdown_id = args[-2]
    dropdown_id2 = args[-1]
    global error_occurred 
    if dropdown_id!="" and dropdown_id2!="":
        error_occurred = False
        args_page1 = list(args) + [dropdown_id, input_tokens, output_tokens]
        args_page2 = list(args) + [dropdown_id2, input_tokens, output_tokens]
        result_page1 = page1.compute_cost_per_token(*args_page1)
        result_page2 = page2.compute_cost_per_token(*args_page2)
        tco1, latency, labor_cost1 = result_page1
        tco2, latency2, labor_cost2 = result_page2   
        return tco1, latency, labor_cost1, tco2, latency2, labor_cost2
    else: 
        error_occurred = True
        raise gr.Error("Please select two AI service options.")

def update_plot(tco1, tco2, dropdown, dropdown2, labour_cost1, labour_cost2):
    if error_occurred == False:
        request_ranges = list(range(0, 1001, 100)) + list(range(1000, 10001, 500)) + list(range(10000, 100001, 1000)) + list(range(100000, 2000001, 100000))
        costs_tco1 = [(tco1 * req + labour_cost1) for req in request_ranges]
        costs_tco2 = [(tco2 * req + labour_cost2) for req in request_ranges]

        data = pd.DataFrame({
            "Number of requests": request_ranges * 2,
            "Cost ($)": costs_tco1 + costs_tco2,
            "AI model service": ["1)" + " " + dropdown] * len(request_ranges) + ["2)" + " " + dropdown2] * len(request_ranges)
            }
        )
        return gr.LinePlot.update(data, visible=True, x="Number of requests", y="Cost ($)",color="AI model service",color_legend_position="bottom", title="Set-up TCO for one month", height=300, width=500, tooltip=["Number of requests", "Cost ($)", "AI model service"])
    else:
        return ""
    
error_occurred = False
style = theme.Style()

with gr.Blocks(theme=style) as demo:
    Models: list[models.BaseTCOModel] = [models.OpenAIModelGPT4, models.OpenAIModelGPT3_5, models.CohereModel, models.DIYLlama2Model]
    model_names = [Model().get_name() for Model in Models]
    gr.Markdown(value=text)
    gr.Markdown(value=description)
    
    with gr.Row():
        with gr.Column():
            with gr.Row():
                use_case = gr.Dropdown(["Summarize", "Question-Answering", "Classification"], value="Question-Answering", label=" Describe your use case ")
            with gr.Accordion("Click here if you want to customize the number of input and output tokens per request", open=False):    
                with gr.Row():
                    input_tokens = gr.Slider(minimum=1, maximum=1000, value=300, step=1, label=" Input tokens per request", info="We suggest a value that we believe best suit your use case choice but feel free to adjust", interactive=True)
                    output_tokens = gr.Slider(minimum=1, maximum=1000, value=300, step=1, label=" Output tokens per request", info="We suggest a value that we believe best suit your use case choice but feel free to adjust", interactive=True)
                with gr.Row(visible=False):    
                    num_users = gr.Number(value="1000", interactive = True, label=" Number of users for your service ")
    
    use_case.change(on_use_case_change, inputs=use_case, outputs=[input_tokens, output_tokens])
    
    with gr.Row():
        with gr.Column():
            page1 = models.ModelPage(Models)
            dropdown = gr.Dropdown(model_names, interactive=True, label=" First AI service option ")
            with gr.Accordion("Click here for more information on the computation parameters for your first AI service option", open=False):    
                page1.render()

        with gr.Column():
            page2 = models.ModelPage(Models)
            dropdown2 = gr.Dropdown(model_names, interactive=True, label=" Second AI service option ")
            with gr.Accordion("Click here for more information on the computation parameters for your second AI service option", open=False):        
                page2.render()
            
    dropdown.change(page1.make_model_visible, inputs=[dropdown, use_case], outputs=page1.get_all_components())
    dropdown2.change(page2.make_model_visible, inputs=[dropdown2, use_case], outputs=page2.get_all_components())
    
    compute_tco_btn = gr.Button("Compute & Compare", size="lg", variant="primary", scale=1) 
    tco1 = gr.State()
    tco2 = gr.State()
    labor_cost1 = gr.State()
    labor_cost2 = gr.State()
    latency = gr.State()
    latency2 = gr.State()
    
    with gr.Row():
        with gr.Accordion("Click here to see the cost/request computation formula", open=False):
            tco_formula = gr.Markdown(formula)
        
    with gr.Row(variant='panel'):
        with gr.Column():
            with gr.Row():
                table = gr.Markdown()
            with gr.Row():
                info = gr.Markdown(text2)
            with gr.Row():
                with gr.Column(scale=1):
                    image = gr.Image(visible=False)
                    ratio = gr.Markdown()
                with gr.Column(scale=2):
                    plot = gr.LinePlot(visible=False)
    
    compute_tco_btn.click(compute_cost_per_request, inputs=page1.get_all_components_for_cost_computing() + page2.get_all_components_for_cost_computing() + [dropdown, dropdown2], outputs=[tco1, latency, labor_cost1, tco2, latency2, labor_cost2])\
        .then(create_table, inputs=[tco1, tco2, labor_cost1, labor_cost2, dropdown, dropdown2, latency, latency2], outputs=table)\
        .then(compare_info, inputs=[tco1, tco2, dropdown, dropdown2], outputs=[image, ratio])\
        .then(update_plot, inputs=[tco1, tco2, dropdown, dropdown2, labor_cost1, labor_cost2], outputs=plot)

demo.launch(debug=True)