From f1fdca3efd3f1a5f0af2a6af19fc3e12df9410e6 Mon Sep 17 00:00:00 2001
From: Mikei386 <44135113+Mikei386@users.noreply.github.com>
Date: Thu, 3 Sep 2026 13:39:13 +0200
Subject: [PATCH] Fix live inference rate display
---
platform/llama-dashboard/app.py | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/platform/llama-dashboard/app.py b/platform/llama-dashboard/app.py
index 86e9728..4026ef6 100644
--- a/platform/llama-dashboard/app.py
+++ b/platform/llama-dashboard/app.py
@@ -651,6 +651,21 @@ const deNum=n=>n==null?'–':Number(n).toLocaleString('de-DE',{maximumFractionDi
const bytesRate=n=>n==null?'–':n>=1048576?`${(n/1048576).toFixed(1)} MiB/s`:`${(n/1024).toFixed(1)} KiB/s`;
const metric=(value,label)=>`
${value??'–'}${label}
`;
const boolLabel=v=>v===true?'ja':v===false?'nein':'–';
+const liveRateState={prompt:{tokens:null,seconds:null,value:null,seen:0},generation:{tokens:null,seconds:null,value:null,seen:0}};
+function stableLiveRate(kind,tokensTotal,secondsTotal,gauge,active){
+ const now=Date.now(),state=liveRateState[kind],tokens=Number(tokensTotal),seconds=Number(secondsTotal),raw=Number(gauge);
+ let measured=Number.isFinite(raw)&&raw>0?raw:null;
+ if(Number.isFinite(tokens)&&Number.isFinite(seconds)&&state.tokens!=null&&tokens>=state.tokens&&seconds>state.seconds){
+ const derived=(tokens-state.tokens)/(seconds-state.seconds);
+ if(Number.isFinite(derived)&&derived>0) measured=measured??derived;
+ }
+ if(Number.isFinite(tokens)&&Number.isFinite(seconds)){
+ state.tokens=tokens;state.seconds=seconds;
+ }
+ if(measured!=null&&measured<100000){state.value=measured;state.seen=now;}
+ if(state.value!=null&&(active||now-state.seen<8000)) return {text:`${deNum(state.value)} tok/s`,fresh:now-state.seen<2500};
+ return {text:active?'misst …':'–',fresh:false};
+}
function slotHtml(s){
let used=s.context_used||0,total=s.n_ctx||0,p=total?Math.min(100,used/total*100):0;
let state=s.processing?'arbeitet':'frei';
@@ -660,17 +675,18 @@ async function refreshFull(){
try{
let response=await fetch('/api/status',{cache:'no-store'}); if(!response.ok) return;
let d=await response.json(),rt=d.router||{},lt=rt.llama_telemetry||{},met=lt.metrics||{},props=lt.props||{},lr=d.llama_runtime||{},cpu=d.cpu||{},net=cpu.network||{};
- let gen=met.predicted_tokens_seconds,prompt=met.prompt_tokens_seconds;
- $('generationRate').textContent=gen==null?'–':`${deNum(gen)} tok/s`;
+ let running=Number(met.requests_processing??(rt.qwen||{}).active_chats??0),waiting=Number(met.requests_deferred||0),active=running>0;
+ let gen=stableLiveRate('generation',met.tokens_predicted_total,met.tokens_predicted_seconds_total,met.predicted_tokens_seconds,active);
+ let prompt=stableLiveRate('prompt',met.prompt_tokens_total,met.prompt_seconds_total,met.prompt_tokens_seconds,active);
+ $('generationRate').textContent=gen.text;
let genAvg=met.tokens_predicted_seconds_total?met.tokens_predicted_total/met.tokens_predicted_seconds_total:null;
- $('generationSub').textContent=genAvg==null?'Aktuelle llama.cpp-Messung':`Gesamtdurchschnitt ${deNum(genAvg)} tok/s`;
- $('promptRate').textContent=prompt==null?'–':`${deNum(prompt)} tok/s`;
+ $('generationSub').textContent=active&&!gen.fresh?'Anfrage läuft · letzter Messwert':(genAvg==null?'Aktuelle llama.cpp-Messung':`Gesamtdurchschnitt ${deNum(genAvg)} tok/s`);
+ $('promptRate').textContent=prompt.text;
let promptAvg=met.prompt_seconds_total?met.prompt_tokens_total/met.prompt_seconds_total:null;
- $('promptSub').textContent=promptAvg==null?'Aktuelle llama.cpp-Messung':`Gesamtdurchschnitt ${deNum(promptAvg)} tok/s`;
+ $('promptSub').textContent=active&&!prompt.fresh?'Prompt wird verarbeitet · letzter Messwert':(promptAvg==null?'Aktuelle llama.cpp-Messung':`Gesamtdurchschnitt ${deNum(promptAvg)} tok/s`);
let cached=Number(met.prompt_tokens_cached_total||0),processed=Number(met.prompt_tokens_total||0),hit=(cached+processed)?cached/(cached+processed)*100:null;
$('cacheHit').textContent=hit==null?'–':`${hit.toFixed(1)} %`;$('cacheBar').style.width=`${hit||0}%`;
$('cacheSub').textContent=hit==null?'Keine Cache-Metrik':`${deNum(cached)} wiederverwendet · ${deNum(processed)} neu`;
- let running=Number(met.requests_processing??(rt.qwen||{}).active_chats??0),waiting=Number(met.requests_deferred||0);
$('requestState').textContent=`${running} aktiv · ${waiting} wartet`;
$('requestSub').textContent=`${(lt.slots||[]).filter(s=>!s.processing).length} freie Slots`;
$('slotCards').innerHTML=(lt.slots||[]).map(slotHtml).join('')||'Slot-Telemetrie momentan nicht verfügbar
';