From 32e433cafc86b126dd3dd1ebde861c48abe6e9eb Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Sun, 14 Jun 2026 10:40:33 -0600 Subject: [PATCH] Allow GenAI providers to be initialized lazily (#23482) * allow GenAI providers to be initialized even if they failed on previous attempts * mypy --- frigate/genai/__init__.py | 33 +++++++++++++++++++++++++++++++++ frigate/genai/manager.py | 6 ++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/frigate/genai/__init__.py b/frigate/genai/__init__.py index bca5e6d691..e1f91e31d7 100644 --- a/frigate/genai/__init__.py +++ b/frigate/genai/__init__.py @@ -5,6 +5,7 @@ import json import logging import os import re +import time from typing import Any, AsyncGenerator, Callable, Optional import numpy as np @@ -50,6 +51,10 @@ def register_genai_provider(key: GenAIProviderEnum) -> Callable: class GenAIClient: """Generative AI client for Frigate.""" + # Minimum seconds between re-initialization attempts when the provider was + # offline at startup + REINIT_INTERVAL = 60.0 + def __init__( self, genai_config: GenAIConfig, @@ -60,6 +65,34 @@ class GenAIClient: self.timeout = timeout self.validate_model = validate_model self.provider = self._init_provider() + self._last_init_attempt = time.monotonic() + + def ensure_provider(self) -> bool: + """Ensure a provider is available, retrying initialization if needed. + + Providers can fail to initialize at startup when their backing service + isn't online yet (common when both are started together). This retries + ``_init_provider`` lazily — throttled to ``REINIT_INTERVAL`` — so the + client recovers on its own once the service is reachable, without a + config reload. + + Returns True if a provider is available. + """ + if self.provider is not None: + return True + + now = time.monotonic() + if now - self._last_init_attempt < self.REINIT_INTERVAL: + return False + + self._last_init_attempt = now + self.provider = self._init_provider() + if self.provider is not None: + logger.info( + "GenAI provider %s is now available", + self.genai_config.provider, + ) + return self.provider is not None def generate_review_description( self, diff --git a/frigate/genai/manager.py b/frigate/genai/manager.py index a1325d3279..a545f81f4a 100644 --- a/frigate/genai/manager.py +++ b/frigate/genai/manager.py @@ -62,7 +62,9 @@ class GenAIClientManager: def _get_client(self, name: str) -> "Optional[GenAIClient]": """Return the client for *name*, creating it on first access.""" if name in self._clients: - return self._clients[name] + client = self._clients[name] + client.ensure_provider() + return client from frigate.genai import PROVIDERS @@ -78,7 +80,7 @@ class GenAIClientManager: return None try: - client: "GenAIClient" = provider_cls(genai_cfg) + client = provider_cls(genai_cfg) except Exception as e: logger.exception( "Failed to create GenAI client for provider %s: %s",