feat: keep Ollama models in memory for 5 minutes
- Add OLLAMA_KEEP_ALIVE_MINUTES config (default: 5) - schedule_ollama_unload(): delays Ollama unload when switching to Jean - cancel_ollama_unload(): cancels timer if returning to Ollama - Ollama models stay in VRAM for X minutes after last use - Timer resets on each Ollama request
This commit is contained in:
+38
-4
@@ -24,6 +24,7 @@ OLLAMA_DIRECT_HOST = os.getenv("OLLAMA_DIRECT_HOST", JEAN_WEB_HOST)
|
|||||||
OLLAMA_DIRECT_PORT = int(os.getenv("OLLAMA_DIRECT_PORT", "11434"))
|
OLLAMA_DIRECT_PORT = int(os.getenv("OLLAMA_DIRECT_PORT", "11434"))
|
||||||
ENABLE_OLLAMA = os.getenv("ENABLE_OLLAMA", "true").lower() == "true"
|
ENABLE_OLLAMA = os.getenv("ENABLE_OLLAMA", "true").lower() == "true"
|
||||||
ENABLE_VRAM_MANAGEMENT = os.getenv("ENABLE_VRAM_MANAGEMENT", "true").lower() == "true"
|
ENABLE_VRAM_MANAGEMENT = os.getenv("ENABLE_VRAM_MANAGEMENT", "true").lower() == "true"
|
||||||
|
OLLAMA_KEEP_ALIVE_MINUTES = int(os.getenv("OLLAMA_KEEP_ALIVE_MINUTES", "5"))
|
||||||
LISTEN_PORT = int(os.getenv("LISTEN_PORT", "3014"))
|
LISTEN_PORT = int(os.getenv("LISTEN_PORT", "3014"))
|
||||||
SWITCH_TIMEOUT = int(os.getenv("SWITCH_TIMEOUT", "90"))
|
SWITCH_TIMEOUT = int(os.getenv("SWITCH_TIMEOUT", "90"))
|
||||||
CHECK_INTERVAL = int(os.getenv("CHECK_INTERVAL", "2"))
|
CHECK_INTERVAL = int(os.getenv("CHECK_INTERVAL", "2"))
|
||||||
@@ -41,6 +42,7 @@ CACHE_TTL = 30
|
|||||||
switch_lock = threading.Lock()
|
switch_lock = threading.Lock()
|
||||||
vram_lock = threading.Lock()
|
vram_lock = threading.Lock()
|
||||||
vram_state = {"active_backend": "jean"}
|
vram_state = {"active_backend": "jean"}
|
||||||
|
ollama_unload_timer = None
|
||||||
|
|
||||||
|
|
||||||
def get_presets(force_refresh=False):
|
def get_presets(force_refresh=False):
|
||||||
@@ -246,11 +248,41 @@ def unload_ollama() -> bool:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def schedule_ollama_unload():
|
||||||
|
"""Programme le déchargement d'Ollama après OLLAMA_KEEP_ALIVE_MINUTES"""
|
||||||
|
global ollama_unload_timer
|
||||||
|
|
||||||
|
def delayed_unload():
|
||||||
|
log.info(f"[VRAM] Timer écoulé ({OLLAMA_KEEP_ALIVE_MINUTES}min), déchargement Ollama...")
|
||||||
|
unload_ollama()
|
||||||
|
|
||||||
|
if ollama_unload_timer:
|
||||||
|
ollama_unload_timer.cancel()
|
||||||
|
log.info("[VRAM] Timer précédent annulé")
|
||||||
|
|
||||||
|
ollama_unload_timer = threading.Timer(
|
||||||
|
OLLAMA_KEEP_ALIVE_MINUTES * 60,
|
||||||
|
delayed_unload
|
||||||
|
)
|
||||||
|
ollama_unload_timer.daemon = True
|
||||||
|
ollama_unload_timer.start()
|
||||||
|
log.info(f"[VRAM] Déchargement Ollama programmé dans {OLLAMA_KEEP_ALIVE_MINUTES} minutes")
|
||||||
|
|
||||||
|
|
||||||
|
def cancel_ollama_unload():
|
||||||
|
"""Annule le déchargement programmé d'Ollama"""
|
||||||
|
global ollama_unload_timer
|
||||||
|
if ollama_unload_timer:
|
||||||
|
ollama_unload_timer.cancel()
|
||||||
|
ollama_unload_timer = None
|
||||||
|
log.info("[VRAM] Timer de déchargement Ollama annulé")
|
||||||
|
|
||||||
|
|
||||||
def ensure_vram_for_backend(target_backend: str) -> bool:
|
def ensure_vram_for_backend(target_backend: str) -> bool:
|
||||||
"""
|
"""
|
||||||
S'assure que la VRAM est disponible pour le backend cible.
|
S'assure que la VRAM est disponible pour le backend cible.
|
||||||
- Si target=ollama et jean actif → arrête Jean
|
- Si target=ollama et jean actif → arrête Jean, annule timer unload Ollama
|
||||||
- Si target=jean et ollama actif → décharge Ollama
|
- Si target=jean et ollama actif → programme déchargement Ollama dans X min, démarre Jean
|
||||||
"""
|
"""
|
||||||
if not ENABLE_VRAM_MANAGEMENT:
|
if not ENABLE_VRAM_MANAGEMENT:
|
||||||
return True
|
return True
|
||||||
@@ -263,6 +295,7 @@ def ensure_vram_for_backend(target_backend: str) -> bool:
|
|||||||
|
|
||||||
if target_backend == "ollama" and current == "jean":
|
if target_backend == "ollama" and current == "jean":
|
||||||
log.info("[VRAM] Switch Jean → Ollama")
|
log.info("[VRAM] Switch Jean → Ollama")
|
||||||
|
cancel_ollama_unload()
|
||||||
if not stop_jean():
|
if not stop_jean():
|
||||||
return False
|
return False
|
||||||
vram_state["active_backend"] = "ollama"
|
vram_state["active_backend"] = "ollama"
|
||||||
@@ -270,8 +303,7 @@ def ensure_vram_for_backend(target_backend: str) -> bool:
|
|||||||
|
|
||||||
elif target_backend == "jean" and current == "ollama":
|
elif target_backend == "jean" and current == "ollama":
|
||||||
log.info("[VRAM] Switch Ollama → Jean")
|
log.info("[VRAM] Switch Ollama → Jean")
|
||||||
if not unload_ollama():
|
schedule_ollama_unload()
|
||||||
return False
|
|
||||||
if not start_jean():
|
if not start_jean():
|
||||||
return False
|
return False
|
||||||
vram_state["active_backend"] = "jean"
|
vram_state["active_backend"] = "jean"
|
||||||
@@ -384,6 +416,8 @@ def chat_completions():
|
|||||||
if not ensure_vram_for_backend("ollama"):
|
if not ensure_vram_for_backend("ollama"):
|
||||||
return jsonify({"error": "Failed to prepare VRAM for Ollama"}), 503
|
return jsonify({"error": "Failed to prepare VRAM for Ollama"}), 503
|
||||||
|
|
||||||
|
cancel_ollama_unload()
|
||||||
|
|
||||||
upstream_url = f"http://{OLLAMA_PROXY_HOST}:{OLLAMA_PROXY_PORT}/v1/chat/completions"
|
upstream_url = f"http://{OLLAMA_PROXY_HOST}:{OLLAMA_PROXY_PORT}/v1/chat/completions"
|
||||||
log.info(f"[Router] → Ollama ({model_id})")
|
log.info(f"[Router] → Ollama ({model_id})")
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user