Préchargement des modèles : warm + keep_alive + indicateur d'état

Évite le rechargement lent quand Ollama a déchargé le modèle de la VRAM :
- ollama_client.warm() : précharge un modèle (/api/generate sans prompt) ;
  chat() accepte keep_alive (durée de rétention en VRAM).
- agent.run_agent transmet keep_alive ; route chat le passe depuis la config.
- config : champ keep_alive (défaut 30m) par profil de modèle.
- routes/models : POST /api/models/warm, GET /api/models/loaded (placement
  GPU/CPU via /api/ps).
- main : préchargement du modèle par défaut au démarrage (arrière-plan,
  best-effort — n'empêche pas le démarrage si Ollama est absent).
- Frontend : préchargement automatique à la sélection d'un modèle, poll des
  modèles chargés (8s), pastille verte (GPU) / orange (CPU) / blanche (à
  charger) dans le sélecteur, réglage 'Maintien en VRAM' dans Configuration.

Tests : warm/loaded routes, keep_alive transmis, démarrage résilient sans
Ollama, build front.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
This commit is contained in:
Claude committed 2026-07-07 12:07:08 +00:00
1 parent d9be1c4dda
commit d9169a1d27
12 files changed
+205 -8

No files matched your search

+13
View File
@@ -7,6 +7,8 @@ import {
getSession,
getStatus,
getSystemStats,
getLoadedModels,
warmModel,
fileContent,
listFiles,
listSessions,
@@ -19,6 +21,7 @@ import {
type OllamaModel,
type OllamaStatus,
type Session,
type LoadedModel,
type SystemStats,
type ToolCall,
} from "../api/client";
@@ -26,6 +29,7 @@ import {
interface LokiState {
status: OllamaStatus | null;
systemStats: SystemStats | null;
loadedModels: LoadedModel[];
models: OllamaModel[];
selectedModel: string;
loadingModels: boolean;
@@ -59,6 +63,7 @@ interface LokiState {
setSelectedModel: (name: string) => void;
refreshStatus: () => Promise<void>;
refreshSystemStats: () => Promise<void>;
refreshLoadedModels: () => Promise<void>;
refreshModels: () => Promise<void>;
refreshFiles: () => Promise<void>;
@@ -75,6 +80,7 @@ let activeStreamController: AbortController | null = null;
export const useStore = create<LokiState>((set, get) => ({
status: null,
systemStats: null,
loadedModels: [],
models: [],
selectedModel: "",
loadingModels: false,
@@ -142,6 +148,9 @@ export const useStore = create<LokiState>((set, get) => ({
setSelectedModel: (name) => {
set({ selectedModel: name });
void get().refreshConfig();
// Préchargement : le modèle est chargé en VRAM dès la sélection.
const ka = get().config?.keep_alive ?? "30m";
void warmModel(name, ka).then(() => get().refreshLoadedModels());
},
refreshFiles: async () => {
@@ -169,6 +178,10 @@ export const useStore = create<LokiState>((set, get) => ({
}
},
refreshLoadedModels: async () => {
set({ loadedModels: await getLoadedModels() });
},
refreshModels: async () => {
set({ loadingModels: true });
try {