diff --git a/.env.sample b/.env.sample index d4d11d0..73cf4a0 100644 --- a/.env.sample +++ b/.env.sample @@ -23,3 +23,4 @@ UPTIME_KUMA_PASSWORD=your-password # Ollama for AI-driven auto-update classification OLLAMA_BASE_URL=http://192.168.1.20:11434 OLLAMA_MODEL=gemma4:26b +OLLAMA_FALLBACK_MODEL=gemma4:12b diff --git a/update_monitor/classifier.py b/update_monitor/classifier.py index a27d797..9a072d1 100644 --- a/update_monitor/classifier.py +++ b/update_monitor/classifier.py @@ -29,9 +29,11 @@ class Classifier: self, base_url: str = "", model: str = "", + fallback_model: str = "", ) -> None: self.base_url = base_url or os.getenv("OLLAMA_BASE_URL", "http://192.168.1.20:11434") self.model = model or os.getenv("OLLAMA_MODEL", "gemma4:26b") + self.fallback_model = fallback_model or os.getenv("OLLAMA_FALLBACK_MODEL", "gemma4:12b") def classify( self, @@ -54,9 +56,23 @@ class Classifier: context = context_file.read_text(encoding="utf-8").strip() if context_file.is_file() else None messages = self._build_messages(service_dir.name, examples, release_notes, current, latest, context) + try: + return self._classify_with_model(self.model, messages, timeout) + except Exception as primary_exc: + if not self.fallback_model or self.fallback_model == self.model: + return {"action": "manual", "reason": f"Classification error: {primary_exc}"} + try: + return self._classify_with_model(self.fallback_model, messages, timeout) + except Exception as fallback_exc: + return { + "action": "manual", + "reason": f"Classification error: {primary_exc}; fallback ({self.fallback_model}) also failed: {fallback_exc}", + } + + def _classify_with_model(self, model: str, messages: List[Dict[str, str]], timeout: float) -> Dict[str, str]: try: payload = json.dumps({ - "model": self.model, + "model": model, "messages": messages, "stream": False, "options": {"temperature": 0}, @@ -79,7 +95,7 @@ class Classifier: raise ValueError(f"Unexpected action value: {action!r}") return {"action": action, "reason": result.get("reason", "")} except Exception as exc: - return {"action": "manual", "reason": f"Classification error: {exc}"} + raise RuntimeError(f"model {model}: {exc}") from exc def _build_messages( self,