1
0
mirror of https://github.com/coalaura/whiskr.git synced 2025-12-02 20:22:52 +00:00

track actual time to first token

This commit is contained in:
Laura
2025-11-15 18:52:43 +01:00
parent 195b916004
commit 865bf1648e
2 changed files with 63 additions and 10 deletions

View File

@@ -455,6 +455,8 @@ body:not(.loading) #loading {
} }
.message .time { .message .time {
display: flex;
gap: 4px;
font-family: var(--font-mono); font-family: var(--font-mono);
font-size: 10px; font-size: 10px;
line-height: 10px; line-height: 10px;
@@ -464,6 +466,11 @@ body:not(.loading) #loading {
color: var(--c-subtext); color: var(--c-subtext);
} }
.message .time .ttft-real::after {
content: "/";
padding-left: 4px;
}
.tool .call, .tool .call,
.reasoning .toggle { .reasoning .toggle {
position: relative; position: relative;

View File

@@ -175,6 +175,7 @@
#tool; #tool;
#tags = []; #tags = [];
#time = 0; #time = 0;
#ttft = 0;
#statistics; #statistics;
#error = false; #error = false;
@@ -206,6 +207,7 @@
this.#text = data.text || ""; this.#text = data.text || "";
this.#time = data.time; this.#time = data.time;
this.#ttft = data.ttft;
this.#_diff = document.createElement("div"); this.#_diff = document.createElement("div");
@@ -278,10 +280,6 @@
// time // time
this.#_time = make("div", "time"); this.#_time = make("div", "time");
if (this.#time) {
this.#_time.textContent = formatMilliseconds(this.#time * 1000);
}
_body.appendChild(this.#_time); _body.appendChild(this.#_time);
// loader // loader
@@ -767,6 +765,28 @@
this.#_message.classList.toggle("has-statistics", !!html); this.#_message.classList.toggle("has-statistics", !!html);
} }
if (!only || only === "time") {
this.#_time.innerHTML = "";
if (this.#time) {
if (this.#ttft) {
const ttft = make("span", "ttft-real");
ttft.title = "Real time to first token";
ttft.textContent = `${formatMilliseconds(this.#ttft * 1000)}`;
this.#_time.appendChild(ttft);
}
const time = make("span");
time.title = "Total time taken";
time.textContent = formatMilliseconds(this.#time * 1000);
this.#_time.appendChild(time);
}
}
if (this.#error) { if (this.#error) {
return; return;
} }
@@ -874,6 +894,10 @@
if (this.#time && full) { if (this.#time && full) {
data.time = this.#time; data.time = this.#time;
if (this.#ttft) {
data.ttft = this.#ttft;
}
} }
if (this.#_message.classList.contains("collapsed") && full) { if (this.#_message.classList.contains("collapsed") && full) {
@@ -894,11 +918,17 @@
this.#save(); this.#save();
} }
setTime(time) { setTime(time, ttft, final = false) {
this.#time = time; this.#time = time;
if (this.#time) { if (ttft && !this.#ttft) {
this.#_time.textContent = formatMilliseconds(this.#time * 1000); this.#ttft = ttft;
}
this.#render("time");
if (final) {
this.#save();
} }
} }
@@ -1321,7 +1351,7 @@
$chat.classList.add("completing"); $chat.classList.add("completing");
let message, generationID, stopTimeout, timeInterval, started; let message, generationID, stopTimeout, timeInterval, started, receivedToken;
function startLoadingTimeout() { function startLoadingTimeout() {
stopTimeout?.(); stopTimeout?.();
@@ -1354,7 +1384,9 @@
clearInterval(timeInterval); clearInterval(timeInterval);
msg.setTime(Math.round((Date.now() - started) / 100) / 10); const took = Math.round((Date.now() - started) / 100) / 10;
msg.setTime(took, false);
msg.setState(false); msg.setState(false);
@@ -1362,6 +1394,8 @@
msg.loadGenerationData(genID); msg.loadGenerationData(genID);
}, 1000); }, 1000);
receivedToken = false;
message = null; message = null;
generationID = null; generationID = null;
} }
@@ -1388,7 +1422,9 @@
return; return;
} }
message.setTime(Math.round((Date.now() - started) / 100) / 10); const took = Math.round((Date.now() - started) / 100) / 10;
message.setTime(took, receivedToken ? took : false);
}, 100); }, 100);
} }
@@ -1454,6 +1490,8 @@
break; break;
case "tool": case "tool":
receivedToken = true;
message.setState("tooling"); message.setState("tooling");
message.setTool(chunk.data); message.setTool(chunk.data);
@@ -1467,19 +1505,27 @@
break; break;
case "image": case "image":
receivedToken = true;
message.addImage(chunk.data); message.addImage(chunk.data);
break; break;
case "reason": case "reason":
receivedToken = true;
message.setState("reasoning"); message.setState("reasoning");
message.addReasoning(chunk.data); message.addReasoning(chunk.data);
break; break;
case "reason_type": case "reason_type":
receivedToken = true;
message.setReasoningType(chunk.data); message.setReasoningType(chunk.data);
break; break;
case "text": case "text":
receivedToken = true;
message.setState("receiving"); message.setState("receiving");
message.addText(chunk.data); message.addText(chunk.data);