Honest summarize progress: backend percent pins at 99 the moment tokens start (thinking models stream immediately) then holds there for minutes — so streaming now shows 'Summarizing… working · m:ss' with an indeterminate bar; '0% waiting for model' stays for the pre-token wait; 100 only on success. Transcribe keeps its real percentage.
This commit is contained in:
parent
8586bc2476
commit
1eb6d55f4d
3 changed files with 34 additions and 30 deletions
|
|
@ -1667,13 +1667,15 @@ class DesktopState(private val appDir: File = defaultAppDir()) {
|
|||
else -> LiveProgress("transcribing…", null)
|
||||
}
|
||||
s != null && s.status == "running" ->
|
||||
if (s.progress != null)
|
||||
LiveProgress("summarizing… ${s.progress}%", s.progress / 100f)
|
||||
// No tokens yet: the LLM is cold or the server is busy
|
||||
// queueing. Still show a number (0%) — a summarize must
|
||||
// always display a percentage (user request) — plus the
|
||||
// reason and wait time so 0% doesn't look frozen.
|
||||
else LiveProgress("summarizing… 0% waiting for model" +
|
||||
if (s.progress == null)
|
||||
LiveProgress("summarizing… 0% waiting for model" +
|
||||
waitSuffix(s.startedAt, nowMs), null)
|
||||
// Backend summarize progress saturates at 99 the moment
|
||||
// the first tokens arrive (thinking models stream
|
||||
// reasoning immediately), so the number means
|
||||
// "streaming", never "how far". Elapsed time is the
|
||||
// honest signal; the bar stays indeterminate.
|
||||
else LiveProgress("summarizing… working" +
|
||||
waitSuffix(s.startedAt, nowMs), null)
|
||||
else -> null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -777,8 +777,11 @@ fun DetailScreen(state: DesktopState) {
|
|||
val sJob = detail.jobs.firstOrNull { it.jobType == "summarize" }
|
||||
sJob?.takeIf { it.status == "running" || it.status == "queued" }?.let {
|
||||
val label = when {
|
||||
// Streaming summarize shows elapsed time, not the backend
|
||||
// number: it pins at 99% the moment tokens start.
|
||||
it.status == "running" && it.progress != null ->
|
||||
"Summarizing… ${it.progress}%"
|
||||
"Summarizing… working" +
|
||||
DesktopState.waitSuffix(it.startedAt, System.currentTimeMillis())
|
||||
it.status == "running" -> "Summarizing… 0% waiting for model" +
|
||||
DesktopState.waitSuffix(it.startedAt, System.currentTimeMillis())
|
||||
else -> "Summary queued" +
|
||||
|
|
@ -788,16 +791,9 @@ fun DetailScreen(state: DesktopState) {
|
|||
color = MaterialTheme.colorScheme.primary)
|
||||
if (it.status == "running") {
|
||||
Spacer(Modifier.height(4.dp))
|
||||
if (it.progress != null) {
|
||||
LinearProgressIndicator(
|
||||
progress = { it.progress / 100f },
|
||||
modifier = Modifier.fillMaxWidth().height(4.dp),
|
||||
)
|
||||
} else {
|
||||
LinearProgressIndicator(
|
||||
modifier = Modifier.fillMaxWidth().height(4.dp),
|
||||
)
|
||||
}
|
||||
LinearProgressIndicator(
|
||||
modifier = Modifier.fillMaxWidth().height(4.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
detail.error?.let {
|
||||
|
|
@ -963,19 +959,18 @@ fun DetailScreen(state: DesktopState) {
|
|||
val sStatus = sJob?.status
|
||||
val sProg = sJob?.progress
|
||||
val sAttempt = sJob?.attempt ?: 0
|
||||
if (sStatus == "running" && sProg != null && sProg > 0) {
|
||||
LinearProgressIndicator(
|
||||
progress = { sProg.coerceIn(0, 99) / 100f },
|
||||
modifier = Modifier.fillMaxWidth())
|
||||
} else {
|
||||
LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
// Bar stays indeterminate while running: backend summarize
|
||||
// progress pins at 99 as soon as tokens start, so a
|
||||
// determinate bar would freeze near-full for minutes.
|
||||
LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
|
||||
Text(buildString {
|
||||
append(when {
|
||||
sStatus == "queued" -> "Queued…" +
|
||||
DesktopState.waitSuffix(sJob?.createdAt,
|
||||
System.currentTimeMillis())
|
||||
sProg != null && sProg > 0 -> "Summarizing… $sProg%"
|
||||
sProg != null && sProg > 0 -> "Summarizing… working" +
|
||||
DesktopState.waitSuffix(sJob?.startedAt,
|
||||
System.currentTimeMillis())
|
||||
else -> "Summarizing… 0% waiting for model" +
|
||||
DesktopState.waitSuffix(sJob?.startedAt,
|
||||
System.currentTimeMillis())
|
||||
|
|
|
|||
|
|
@ -49,13 +49,20 @@ class JobProgressTest {
|
|||
assertNull(p?.fraction)
|
||||
}
|
||||
|
||||
@Test fun `summarizing shows backend percentage`() {
|
||||
@Test fun `streaming summarize shows working plus elapsed, not fake percent`() {
|
||||
val t0 = System.currentTimeMillis() / 1000 * 1000
|
||||
val iso = java.time.LocalDateTime.ofInstant(
|
||||
java.time.Instant.ofEpochMilli(t0 - 42_000), java.time.ZoneOffset.UTC)
|
||||
.withNano(0).toString()
|
||||
val p = DesktopState.jobProgress(
|
||||
listOf(job("transcribe", "succeeded"),
|
||||
job("summarize", "running", progress = 37)),
|
||||
job("summarize", "running", progress = 99, startedIso = iso)),
|
||||
nowMs = t0,
|
||||
)
|
||||
assertEquals("summarizing… 37%", p?.label)
|
||||
assertEquals(0.37f, p!!.fraction!!, 0.0001f)
|
||||
// Backend progress pins at 99 as soon as tokens flow — the label
|
||||
// must not present it as a completion percentage.
|
||||
assertEquals("summarizing… working · 42s", p?.label)
|
||||
assertNull(p?.fraction)
|
||||
}
|
||||
|
||||
@Test fun `waiting label carries elapsed time`() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue