{
+ const res = await fetch("/api/system/stats");
+ return res.json();
+}
+
export async function getModels(): Promise<{
models: OllamaModel[];
default: string;
diff --git a/frontend/src/components/TopBar.tsx b/frontend/src/components/TopBar.tsx
index 3830b69..80b59eb 100644
--- a/frontend/src/components/TopBar.tsx
+++ b/frontend/src/components/TopBar.tsx
@@ -5,6 +5,7 @@ import { ModelSelector } from "./ModelSelector";
/** Barre supérieure sombre : logo, fil d'Ariane, statut Ollama, sélecteur. */
export function TopBar() {
const status = useStore((s) => s.status);
+ const stats = useStore((s) => s.systemStats);
const connected = status?.connected ?? false;
return (
@@ -24,6 +25,25 @@ export function TopBar() {
+ {/* Stats système temps réel : CPU, RAM, GPU/VRAM */}
+ {stats && (
+
+ CPU {stats.cpu_pct.toFixed(0)}%
+ ·
+ RAM {stats.ram_pct.toFixed(0)}%
+ {stats.gpu && (
+ <>
+ ·
+ GPU {stats.gpu.util_pct.toFixed(0)}%
+
+ VRAM {(stats.gpu.vram_used_mb / 1024).toFixed(1)}/
+ {(stats.gpu.vram_total_mb / 1024).toFixed(1)}G
+
+ >
+ )}
+
+ )}
+
{/* Statut Ollama */}
Promise;
setSelectedModel: (name: string) => void;
refreshStatus: () => Promise;
+ refreshSystemStats: () => Promise;
refreshModels: () => Promise;
refreshFiles: () => Promise;
@@ -69,6 +73,7 @@ let activeStreamController: AbortController | null = null;
export const useStore = create((set, get) => ({
status: null,
+ systemStats: null,
models: [],
selectedModel: "",
loadingModels: false,
@@ -154,6 +159,14 @@ export const useStore = create((set, get) => ({
}
},
+ refreshSystemStats: async () => {
+ try {
+ set({ systemStats: await getSystemStats() });
+ } catch {
+ set({ systemStats: null });
+ }
+ },
+
refreshModels: async () => {
set({ loadingModels: true });
try {