File size: 3,833 Bytes
0921221
 
 
 
 
 
 
 
e122263
 
 
 
0921221
e122263
 
 
0921221
 
 
e122263
0921221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e122263
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0921221
 
 
e122263
0921221
 
 
 
 
 
e122263
0921221
 
 
e122263
0921221
 
e122263
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0921221
 
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
<script lang="ts">
  let { messages } = $props();

  const totalEnergy = $derived(messages.reduce(
    (total: number, msg: any) => total + (msg.metadata?.energy_wh || msg.metadata?.energy_wh_sim || 0),
    0
  ));

  const totalDuration = $derived(messages.reduce(
    (total: number, msg: any) => total + (msg.metadata?.duration_seconds || 0),
    0
  ));   

  const isEstimated = $derived(!(
    typeof messages.at(-1)?.metadata?.energy_wh === 'number' &&
    messages.at(-1).metadata.energy_wh !== 0));

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

  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;
  }

  function convertToJoules(wh: number): number {
		return wh * 3600;
	}
</script>

<style>
    .tooltip {
    position: absolute;
    bottom: 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;
    }

</style>

{#if totalEnergy > 0}
  <div class="mb-4 flex flex-col sm:flex-row flex-wrap items-center justify-center gap-4 w-full">
    <!-- Bloc énergie totale -->
    <div class="text-xs text-gray-600 dark:text-gray-500 bg-gray-100 dark:bg-gray-800 px-3 py-1 rounded transform hover:scale-105 transition duration-150 ease-in-out cursor-pointer" on:click={() => (showJoules = !showJoules)}>
        Total Energy: 
        {#if showJoules}
            {convertToJoules(totalEnergy).toFixed(2)} J
        {:else}
            {totalEnergy.toFixed(4)} Wh
        {/if}
      {#if isEstimated} (estimated) {/if}
    </div>  

    <!-- Bloc équivalent charge téléphone -->
    <div class="text-xs text-gray-600 dark:text-gray-500 bg-gray-100 dark:bg-gray-800 px-3 py-1 rounded cursor-pointer transform hover:scale-105 transition duration-150 ease-in-out" on:click={cycleEquivalent}>
      {equivalents[equivalentIndex](totalEnergy)}
    </div>

    <!-- Bloc d urée -->
    <div class="text-xs text-gray-600 dark:text-gray-500 bg-gray-100 dark:bg-gray-800 px-3 py-1 rounded">
      Total Duration: {totalDuration.toFixed(3)} sec
    </div>

    <!-- 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 all messages. Use Qwen/Qwen/Qwen2.5-VL-7B-Instruct model for exact results.
          {:else}
              Energy consumption measured directly on the GPU during inference for all messages.
          {/if}
      </div>
  {/if}
    </div>
  </div>
{/if}