File size: 3,947 Bytes
145a107
0897191
145a107
0897191
 
145a107
0897191
 
145a107
 
 
 
e122263
 
 
 
 
 
 
 
 
 
 
 
 
 
145a107
 
 
 
 
 
 
 
 
 
 
 
e122263
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145a107
 
 
 
 
 
 
 
 
 
 
 
 
e122263
145a107
 
 
 
 
e122263
145a107
 
e122263
145a107
 
 
 
 
 
 
 
e122263
 
 
 
 
 
 
 
145a107
 
 
 
e122263
 
 
145a107
 
 
e122263
 
 
 
 
 
 
 
 
145a107
 
 
 
e122263
145a107
e122263
145a107
 
 
e122263
 
145a107
 
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
<script lang="ts">
	let { energyWh, energyWhSim, durationSeconds } = $props();

	let showJoules = $state(false);
	let showTooltip = $state(false);

    const isEstimated = $derived(!(typeof energyWh === 'number' && energyWh !== 0));
    const energyToDisplay = $derived(isEstimated ? energyWhSim : energyWh);

	function convertToJoules(wh: number): number {
		return wh * 3600;
	}

    let equivalentIndex = $state(0);

    const equivalents = [
    (wh: number) => `≈ ${((wh / 19) * 100).toFixed(2)}% of a phone charge (19Wh)`,
    (wh: number) => `≈ ${(wh / 0.04).toFixed(2)} minutes of LED bulb (10W)`, // 0.04Wh/min
    (wh: number) => `≈ ${(wh / 1.5).toFixed(2)} seconds of microwave (1000W)`,
    (wh: number) => `≈ ${(wh / 0.2).toFixed(2)} pedal strokes on an e-bike (200W)`,
    (wh: number) => `≈ ${(wh / 12).toFixed(2)} seconds of toaster use (1kW)`
    ];

    function cycleEquivalent() {
        equivalentIndex = (equivalentIndex + 1) % equivalents.length;
    }
</script>

<style>
	.energy-box {
		transition: transform 0.2s ease;
		cursor: pointer;
		position: relative;
	}
	.energy-box:hover {
		transform: scale(1.05);
	}
	.tooltip {
    position: absolute;
    top: 100%; /* Positionne au-dessus de l’élément parent */
    margin-bottom: 0.5rem; /* Équivalent de mb-2 */
    left: 50%;
    transform: translateX(-50%);
    background-color: #f3f4f6; /* bg-gray-200 */
    color: #1f2937; /* text-gray-800 */
    font-size: 0.75rem; /* text-xs */
    padding: 0.5rem 0.75rem; /* px-3 py-2 */
    border-radius: 0.25rem; /* rounded */
    box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
                0 4px 6px -4px rgba(0, 0, 0, 0.1); /* shadow-lg */
    z-index: 10;
    width: 16rem; /* w-64 */
    text-align: center;
    }
    .info-button {
        transition: transform 0.2s ease;
        cursor: pointer;
        position: relative;
    }
    .info-button:hover {
        transform: scale(1.2);
    }
</style>

{#if durationSeconds || energyToDisplay}
	<div class="mt-2 flex gap-2 items-center relative">

        
        

		<!-- Energy Box -->
		{#if energyToDisplay}
			<div
				class="text-xs text-gray-600 dark:text-gray-500 bg-gray-100 dark:bg-gray-800 px-3 py-1 rounded w-fit energy-box"
				on:click={() => (showJoules = !showJoules)}
			>
            Energy:
				{#if showJoules}
					{convertToJoules(energyToDisplay).toFixed(2)} J {isEstimated ? "(estimated)" : ""}
				{:else}
					{energyToDisplay.toFixed(4)} Wh {isEstimated ? "(estimated)" : ""}
				{/if}
			</div>
		{/if}

        <!-- Equivalent -->
        <div
            class="text-xs text-gray-600 dark:text-gray-500 bg-gray-100 dark:bg-gray-800 px-3 py-1 rounded w-fit cursor-pointer transform hover:scale-105 transition duration-150 ease-in-out"
            on:click={cycleEquivalent}
        >
            {equivalents[equivalentIndex](energyToDisplay)}
        </div>

		
        <!-- Duration -->
		{#if durationSeconds}
        <div
            class="text-xs text-gray-600 dark:text-gray-500 bg-gray-100 dark:bg-gray-800 px-3 py-1 rounded w-fit"
        > 
            Duration: {durationSeconds.toFixed(3)} sec
        </div>
    {/if}
		
        <!-- Info button -->
        <div
        class="relative"
        on:mouseover={() => (showTooltip = true)}
        on:mouseleave={() => (showTooltip = false)}>
            <button
                class="text-xs text-gray-600 dark:text-gray-500 bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded-full info-button">

            </button>
		<!-- Tooltip -->
		{#if showTooltip}
			<div class="tooltip">
				{#if isEstimated}
					Estimated energy consumption based on the average GPU power and inference duration for this message. Use Qwen/Qwen/Qwen2.5-VL-7B-Instruct model for exact results.
				{:else}
					Energy consumption measured directly on the GPU during inference for this message.
				{/if}
			</div>
		{/if}
        </div>
        
	</div>
{/if}