Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Commit
·
e122263
1
Parent(s):
0921221
improved design and preprompts
Browse files
PREPROMPT.md
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
You are a helpful assistant based on Qwen/Qwen2.5-72B-Instruct; your primary role is to assist users like a normal chatbot—answering questions, helping with tasks, and holding conversations; in addition, if the user asks about the energy indicators displayed below messages (e.g., “Energy”, “≈ phone charge”, “Duration”), you can explain what they mean and how they are calculated; you do not have access to the actual values, but you can clarify that some values are measured using NVIDIA's NVML API on supported GPUs like the T4 (recorded in millijoules, converted to Wh), while others are estimated from inference time using estimated_energy = average_power × inference_time with average_power ≈ 70W; 1 Wh = 3600 J; real-world equivalents help users understand energy use (e.g., phone charge ≈ 19 Wh); users can click on energy values to toggle Wh/J, and on equivalents to cycle through different comparisons; adapt explanations based on user expertise—keep it simple for general audiences and precise for technical questions.
|
src/lib/components/chat/EnergyDisplay.svelte
CHANGED
@@ -10,6 +10,20 @@
|
|
10 |
function convertToJoules(wh: number): number {
|
11 |
return wh * 3600;
|
12 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
</script>
|
14 |
|
15 |
<style>
|
@@ -22,20 +36,22 @@
|
|
22 |
transform: scale(1.05);
|
23 |
}
|
24 |
.tooltip {
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
|
|
|
|
39 |
.info-button {
|
40 |
transition: transform 0.2s ease;
|
41 |
cursor: pointer;
|
@@ -49,24 +65,16 @@
|
|
49 |
{#if durationSeconds || energyToDisplay}
|
50 |
<div class="mt-2 flex gap-2 items-center relative">
|
51 |
|
52 |
-
|
53 |
-
<div
|
54 |
-
class="relative"
|
55 |
-
on:mouseover={() => (showTooltip = true)}
|
56 |
-
on:mouseleave={() => (showTooltip = false)}>
|
57 |
-
<button
|
58 |
-
class="text-xs text-gray-500 dark:text-gray-500 bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded-full info-button">
|
59 |
-
ⓘ
|
60 |
-
</button>
|
61 |
-
</div>
|
62 |
|
63 |
|
64 |
<!-- Energy Box -->
|
65 |
{#if energyToDisplay}
|
66 |
<div
|
67 |
-
class="text-xs text-gray-
|
68 |
on:click={() => (showJoules = !showJoules)}
|
69 |
>
|
|
|
70 |
{#if showJoules}
|
71 |
{convertToJoules(energyToDisplay).toFixed(2)} J {isEstimated ? "(estimated)" : ""}
|
72 |
{:else}
|
@@ -75,26 +83,44 @@
|
|
75 |
</div>
|
76 |
{/if}
|
77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
|
79 |
<!-- Duration -->
|
80 |
{#if durationSeconds}
|
81 |
<div
|
82 |
-
class="text-xs text-gray-
|
83 |
-
>
|
84 |
-
{durationSeconds} sec
|
85 |
</div>
|
86 |
{/if}
|
87 |
|
88 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
<!-- Tooltip -->
|
90 |
{#if showTooltip}
|
91 |
<div class="tooltip">
|
92 |
{#if isEstimated}
|
93 |
-
Estimated energy consumption based on the average GPU power and inference duration. Use Qwen/Qwen/Qwen2.5-VL-7B-Instruct model for exact results.
|
94 |
{:else}
|
95 |
-
Energy consumption measured directly on the GPU during inference.
|
96 |
{/if}
|
97 |
</div>
|
98 |
{/if}
|
|
|
|
|
99 |
</div>
|
100 |
{/if}
|
|
|
10 |
function convertToJoules(wh: number): number {
|
11 |
return wh * 3600;
|
12 |
}
|
13 |
+
|
14 |
+
let equivalentIndex = $state(0);
|
15 |
+
|
16 |
+
const equivalents = [
|
17 |
+
(wh: number) => `≈ ${((wh / 19) * 100).toFixed(2)}% of a phone charge (19Wh)`,
|
18 |
+
(wh: number) => `≈ ${(wh / 0.04).toFixed(2)} minutes of LED bulb (10W)`, // 0.04Wh/min
|
19 |
+
(wh: number) => `≈ ${(wh / 1.5).toFixed(2)} seconds of microwave (1000W)`,
|
20 |
+
(wh: number) => `≈ ${(wh / 0.2).toFixed(2)} pedal strokes on an e-bike (200W)`,
|
21 |
+
(wh: number) => `≈ ${(wh / 12).toFixed(2)} seconds of toaster use (1kW)`
|
22 |
+
];
|
23 |
+
|
24 |
+
function cycleEquivalent() {
|
25 |
+
equivalentIndex = (equivalentIndex + 1) % equivalents.length;
|
26 |
+
}
|
27 |
</script>
|
28 |
|
29 |
<style>
|
|
|
36 |
transform: scale(1.05);
|
37 |
}
|
38 |
.tooltip {
|
39 |
+
position: absolute;
|
40 |
+
top: 100%; /* Positionne au-dessus de l’élément parent */
|
41 |
+
margin-bottom: 0.5rem; /* Équivalent de mb-2 */
|
42 |
+
left: 50%;
|
43 |
+
transform: translateX(-50%);
|
44 |
+
background-color: #f3f4f6; /* bg-gray-200 */
|
45 |
+
color: #1f2937; /* text-gray-800 */
|
46 |
+
font-size: 0.75rem; /* text-xs */
|
47 |
+
padding: 0.5rem 0.75rem; /* px-3 py-2 */
|
48 |
+
border-radius: 0.25rem; /* rounded */
|
49 |
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
50 |
+
0 4px 6px -4px rgba(0, 0, 0, 0.1); /* shadow-lg */
|
51 |
+
z-index: 10;
|
52 |
+
width: 16rem; /* w-64 */
|
53 |
+
text-align: center;
|
54 |
+
}
|
55 |
.info-button {
|
56 |
transition: transform 0.2s ease;
|
57 |
cursor: pointer;
|
|
|
65 |
{#if durationSeconds || energyToDisplay}
|
66 |
<div class="mt-2 flex gap-2 items-center relative">
|
67 |
|
68 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
|
71 |
<!-- Energy Box -->
|
72 |
{#if energyToDisplay}
|
73 |
<div
|
74 |
+
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"
|
75 |
on:click={() => (showJoules = !showJoules)}
|
76 |
>
|
77 |
+
Energy:
|
78 |
{#if showJoules}
|
79 |
{convertToJoules(energyToDisplay).toFixed(2)} J {isEstimated ? "(estimated)" : ""}
|
80 |
{:else}
|
|
|
83 |
</div>
|
84 |
{/if}
|
85 |
|
86 |
+
<!-- Equivalent -->
|
87 |
+
<div
|
88 |
+
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"
|
89 |
+
on:click={cycleEquivalent}
|
90 |
+
>
|
91 |
+
{equivalents[equivalentIndex](energyToDisplay)}
|
92 |
+
</div>
|
93 |
+
|
94 |
|
95 |
<!-- Duration -->
|
96 |
{#if durationSeconds}
|
97 |
<div
|
98 |
+
class="text-xs text-gray-600 dark:text-gray-500 bg-gray-100 dark:bg-gray-800 px-3 py-1 rounded w-fit"
|
99 |
+
>
|
100 |
+
Duration: {durationSeconds.toFixed(3)} sec
|
101 |
</div>
|
102 |
{/if}
|
103 |
|
104 |
+
<!-- Info button -->
|
105 |
+
<div
|
106 |
+
class="relative"
|
107 |
+
on:mouseover={() => (showTooltip = true)}
|
108 |
+
on:mouseleave={() => (showTooltip = false)}>
|
109 |
+
<button
|
110 |
+
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">
|
111 |
+
ⓘ
|
112 |
+
</button>
|
113 |
<!-- Tooltip -->
|
114 |
{#if showTooltip}
|
115 |
<div class="tooltip">
|
116 |
{#if isEstimated}
|
117 |
+
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.
|
118 |
{:else}
|
119 |
+
Energy consumption measured directly on the GPU during inference for this message.
|
120 |
{/if}
|
121 |
</div>
|
122 |
{/if}
|
123 |
+
</div>
|
124 |
+
|
125 |
</div>
|
126 |
{/if}
|
src/lib/components/chat/EnergySummary.svelte
CHANGED
@@ -6,14 +6,18 @@
|
|
6 |
0
|
7 |
));
|
8 |
|
9 |
-
const
|
10 |
-
|
11 |
-
|
|
|
12 |
|
13 |
-
const
|
|
|
|
|
14 |
|
15 |
let showJoules = $state(false);
|
16 |
let equivalentIndex = $state(0);
|
|
|
17 |
|
18 |
const equivalents = [
|
19 |
(wh: number) => `≈ ${((wh / 19) * 100).toFixed(2)}% of a phone charge (19Wh)`,
|
@@ -32,22 +36,70 @@
|
|
32 |
}
|
33 |
</script>
|
34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
{#if totalEnergy > 0}
|
36 |
<div class="mb-4 flex flex-col sm:flex-row flex-wrap items-center justify-center gap-4 w-full">
|
37 |
<!-- Bloc énergie totale -->
|
38 |
-
<div class="text-xs text-gray-
|
39 |
Total Energy:
|
40 |
{#if showJoules}
|
41 |
{convertToJoules(totalEnergy).toFixed(2)} J
|
42 |
{:else}
|
43 |
{totalEnergy.toFixed(4)} Wh
|
44 |
{/if}
|
45 |
-
{#if
|
46 |
</div>
|
47 |
|
48 |
<!-- Bloc équivalent charge téléphone -->
|
49 |
-
<div class="text-xs text-gray-
|
50 |
{equivalents[equivalentIndex](totalEnergy)}
|
51 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
</div>
|
53 |
{/if}
|
|
|
6 |
0
|
7 |
));
|
8 |
|
9 |
+
const totalDuration = $derived(messages.reduce(
|
10 |
+
(total: number, msg: any) => total + (msg.metadata?.duration_seconds || 0),
|
11 |
+
0
|
12 |
+
));
|
13 |
|
14 |
+
const isEstimated = $derived(!(
|
15 |
+
typeof messages.at(-1)?.metadata?.energy_wh === 'number' &&
|
16 |
+
messages.at(-1).metadata.energy_wh !== 0));
|
17 |
|
18 |
let showJoules = $state(false);
|
19 |
let equivalentIndex = $state(0);
|
20 |
+
let showTooltip = $state(false);
|
21 |
|
22 |
const equivalents = [
|
23 |
(wh: number) => `≈ ${((wh / 19) * 100).toFixed(2)}% of a phone charge (19Wh)`,
|
|
|
36 |
}
|
37 |
</script>
|
38 |
|
39 |
+
<style>
|
40 |
+
.tooltip {
|
41 |
+
position: absolute;
|
42 |
+
bottom: 100%; /* Positionne au-dessus de l’élément parent */
|
43 |
+
margin-bottom: 0.5rem; /* Équivalent de mb-2 */
|
44 |
+
left: 50%;
|
45 |
+
transform: translateX(-50%);
|
46 |
+
background-color: #f3f4f6; /* bg-gray-200 */
|
47 |
+
color: #1f2937; /* text-gray-800 */
|
48 |
+
font-size: 0.75rem; /* text-xs */
|
49 |
+
padding: 0.5rem 0.75rem; /* px-3 py-2 */
|
50 |
+
border-radius: 0.25rem; /* rounded */
|
51 |
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
52 |
+
0 4px 6px -4px rgba(0, 0, 0, 0.1); /* shadow-lg */
|
53 |
+
z-index: 10;
|
54 |
+
width: 16rem; /* w-64 */
|
55 |
+
text-align: center;
|
56 |
+
}
|
57 |
+
|
58 |
+
</style>
|
59 |
+
|
60 |
{#if totalEnergy > 0}
|
61 |
<div class="mb-4 flex flex-col sm:flex-row flex-wrap items-center justify-center gap-4 w-full">
|
62 |
<!-- Bloc énergie totale -->
|
63 |
+
<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)}>
|
64 |
Total Energy:
|
65 |
{#if showJoules}
|
66 |
{convertToJoules(totalEnergy).toFixed(2)} J
|
67 |
{:else}
|
68 |
{totalEnergy.toFixed(4)} Wh
|
69 |
{/if}
|
70 |
+
{#if isEstimated} (estimated) {/if}
|
71 |
</div>
|
72 |
|
73 |
<!-- Bloc équivalent charge téléphone -->
|
74 |
+
<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}>
|
75 |
{equivalents[equivalentIndex](totalEnergy)}
|
76 |
</div>
|
77 |
+
|
78 |
+
<!-- Bloc d urée -->
|
79 |
+
<div class="text-xs text-gray-600 dark:text-gray-500 bg-gray-100 dark:bg-gray-800 px-3 py-1 rounded">
|
80 |
+
Total Duration: {totalDuration.toFixed(3)} sec
|
81 |
+
</div>
|
82 |
+
|
83 |
+
<!-- info button -->
|
84 |
+
<div
|
85 |
+
class="relative"
|
86 |
+
on:mouseover={() => (showTooltip = true)}
|
87 |
+
on:mouseleave={() => (showTooltip = false)}>
|
88 |
+
<button
|
89 |
+
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">
|
90 |
+
ⓘ
|
91 |
+
</button>
|
92 |
+
|
93 |
+
<!-- Tooltip -->
|
94 |
+
{#if showTooltip}
|
95 |
+
<div class="tooltip">
|
96 |
+
{#if isEstimated}
|
97 |
+
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.
|
98 |
+
{:else}
|
99 |
+
Energy consumption measured directly on the GPU during inference for all messages.
|
100 |
+
{/if}
|
101 |
+
</div>
|
102 |
+
{/if}
|
103 |
+
</div>
|
104 |
</div>
|
105 |
{/if}
|