UI: affichage de la RAM systeme dans la barre laterale

Nouvel endpoint /api/ram (lecture /proc/meminfo, used/total en Mo, 0 hors Linux)
et bloc RAM dans la sidebar a cote du GPU, rafraichi toutes les 3 s. Masque si
pas de /proc/meminfo (Windows/mac).
This commit is contained in:
nathaninline committed 2026-07-23 13:40:53 +02:00
1 parent ee76638f15
commit dbb0ac40a4
7 files changed
+60 -2

No files matched your search

+15 -1
View File
@@ -326,6 +326,9 @@ button:disabled{opacity:.5;cursor:not-allowed}
<details open><summary>GPU</summary>
<div id="vram" class="muted">…</div>
</details>
<details open id="ram-details"><summary>RAM</summary>
<div id="ram" class="muted">…</div>
</details>
<details open id="cfg-details"><summary>Config active</summary>
<div id="cfg" class="muted">…</div>
</details>
@@ -772,6 +775,16 @@ async function loadVram(){
'<div class="muted">'+(g.used/1024).toFixed(1)+' / '+(g.total/1024).toFixed(1)+' GiB · GPU '+g.util+'% · '+g.temp+'°C</div></div>';
}).join('') || '<span class="muted">(pas de GPU)</span>';
}
async function loadRam(){
const m=await jget('/api/ram');
const box=document.getElementById('ram-details');
if(!m || !m.total){ if(box) box.style.display='none'; return; }
if(box) box.style.display='';
const pct=Math.round(m.used*100/m.total);
document.getElementById('ram').innerHTML =
'<div style="margin:6px 0"><div class="bar"><div style="width:'+pct+'%"></div></div>'+
'<div class="muted">'+(m.used/1024).toFixed(1)+' / '+(m.total/1024).toFixed(1)+' GiB · '+pct+'%</div></div>';
}
async function loadCfg(){
const c=await jget('/api/config');
const keys=['BIN','MODEL','CTX','BATCH','UBATCH','NGL','PORT'];
@@ -998,7 +1011,7 @@ async function saveCrawlUrl(){
const url=document.getElementById('crawl-url').value.trim();
renderInternet(await jpost('/api/internet',{url}));
}
async function loadAll(){ await Promise.all([loadStatus(),loadVram(),loadCfg(),loadPresets(),loadAgent(),loadInternet(),loadApiKey(),loadPrefs(),loadLlamacpp()]); }
async function loadAll(){ await Promise.all([loadStatus(),loadVram(),loadRam(),loadCfg(),loadPresets(),loadAgent(),loadInternet(),loadApiKey(),loadPrefs(),loadLlamacpp()]); }
async function act(a){ toast(a+'…'); await jpost('/api/'+a); setTimeout(loadAll,1500); }
function openBenchModal(){ document.getElementById('bench-modal').style.display = 'flex'; }
function closeBenchModal(){ document.getElementById('bench-modal').style.display = 'none'; }
@@ -1661,6 +1674,7 @@ async function send(){
loadAll();
setInterval(loadStatus, 5000);
setInterval(loadVram, 3000);
setInterval(loadRam, 3000);
// Backend llama.cpp — la barre latérale sert UNIQUEMENT à installer les moteurs.
// ⚡ Version rapide = binaires officiels précompilés (aucune compilation)
// 🔧 Version optimisée = compilée pour la machine
+3
View File
@@ -29,6 +29,9 @@
<details open><summary>GPU</summary>
<div id="vram" class="muted">…</div>
</details>
<details open id="ram-details"><summary>RAM</summary>
<div id="ram" class="muted">…</div>
</details>
<details open id="cfg-details"><summary>Config active</summary>
<div id="cfg" class="muted">…</div>
</details>
+10
View File
@@ -64,6 +64,16 @@ async function loadVram(){
'<div class="muted">'+(g.used/1024).toFixed(1)+' / '+(g.total/1024).toFixed(1)+' GiB · GPU '+g.util+'% · '+g.temp+'°C</div></div>';
}).join('') || '<span class="muted">(pas de GPU)</span>';
}
async function loadRam(){
const m=await jget('/api/ram');
const box=document.getElementById('ram-details');
if(!m || !m.total){ if(box) box.style.display='none'; return; }
if(box) box.style.display='';
const pct=Math.round(m.used*100/m.total);
document.getElementById('ram').innerHTML =
'<div style="margin:6px 0"><div class="bar"><div style="width:'+pct+'%"></div></div>'+
'<div class="muted">'+(m.used/1024).toFixed(1)+' / '+(m.total/1024).toFixed(1)+' GiB · '+pct+'%</div></div>';
}
async function loadCfg(){
const c=await jget('/api/config');
const keys=['BIN','MODEL','CTX','BATCH','UBATCH','NGL','PORT'];
+1 -1
View File
@@ -216,5 +216,5 @@ async function saveCrawlUrl(){
const url=document.getElementById('crawl-url').value.trim();
renderInternet(await jpost('/api/internet',{url}));
}
async function loadAll(){ await Promise.all([loadStatus(),loadVram(),loadCfg(),loadPresets(),loadAgent(),loadInternet(),loadApiKey(),loadPrefs(),loadLlamacpp()]); }
async function loadAll(){ await Promise.all([loadStatus(),loadVram(),loadRam(),loadCfg(),loadPresets(),loadAgent(),loadInternet(),loadApiKey(),loadPrefs(),loadLlamacpp()]); }
async function act(a){ toast(a+'…'); await jpost('/api/'+a); setTimeout(loadAll,1500); }
+1
View File
@@ -144,3 +144,4 @@ async function send(){
loadAll();
setInterval(loadStatus, 5000);
setInterval(loadVram, 3000);
setInterval(loadRam, 3000);
+29
View File
@@ -70,6 +70,35 @@ func handleVram(w http.ResponseWriter, r *http.Request) {
sendJSON(w, 200, gpus)
}
// handleRam renvoie la RAM système {used, total} en Mo (mêmes unités que
// /api/vram → l'UI divise par 1024 pour des Gio). Lit /proc/meminfo (Linux, la
// box de prod). Sur un OS sans /proc, renvoie total=0 → l'UI masque le bloc.
func handleRam(w http.ResponseWriter, r *http.Request) {
out := map[string]any{"used": 0, "total": 0}
b, err := os.ReadFile("/proc/meminfo")
if err == nil {
var totalKB, availKB int
for _, line := range strings.Split(string(b), "\n") {
f := strings.Fields(line)
if len(f) < 2 {
continue
}
v, _ := strconv.Atoi(f[1]) // valeur en kB
switch f[0] {
case "MemTotal:":
totalKB = v
case "MemAvailable:":
availKB = v
}
}
if totalKB > 0 {
out["total"] = totalKB / 1024
out["used"] = (totalKB - availKB) / 1024
}
}
sendJSON(w, 200, out)
}
func handleConfigEnv(w http.ResponseWriter, r *http.Request) {
sendJSON(w, 200, ReadConfig())
}
+1
View File
@@ -79,6 +79,7 @@ func newWebMux() *http.ServeMux {
api("/api/ping", handlePing)
api("/api/status", handleStatus)
api("/api/vram", handleVram)
api("/api/ram", handleRam)
api("/api/config", handleConfigEnv)
api("/api/catalog", handleCatalog)
api("/api/update", handleUpdateCheck)