classifier: Point at gemma4:26b and retry transient fetches

Every classification returned "HTTP Error 404" because the configured
model gemma4:26b-64k no longer exists on the Ollama host: the tag was
retired upstream and the local weights were deleted, so all pending
updates fell back to manual review. Switch to the current gemma4:26b
tag (25.2B, 262k context) and make it explicit in .env so the
classifier no longer depends on the code default matching reality.

PieFed intermittently returned an empty body, which surfaced as a
current version error in the digest. Retry version fetches with a
short backoff so one bad response no longer triggers an alert.

Leave-one-out validation for the new model: immich 6/7 (the miss is
the conditional-breaking example where the model follows the written
rule that thresholds below the running version do not apply),
freshrss 6/6, uptime-kuma 4/4.
This commit is contained in:
Jeena 2026-09-14 05:37:37 +00:00
parent f046ebf504
commit 7e15e63dae
4 changed files with 31 additions and 5 deletions

View file

@ -1,4 +1,5 @@
import json
import time
from typing import Any, Dict, List, Optional, Tuple
from .comparator import compare_versions
@ -7,6 +8,29 @@ from .fetcher import authenticate_service, build_headers, fetch_response, fetch_
from .models import ServiceConfig
def fetch_version_with_retries(
url: str,
timeout: float,
user_agent: str,
extra_headers: Optional[Dict[str, str]] = None,
attempts: int = 3,
) -> tuple[str, Dict[str, str]]:
"""Fetch a version endpoint with retries for transient failures
(empty bodies, timeouts)."""
last_exc: Optional[Exception] = None
for attempt in range(attempts):
try:
body, headers = fetch_response(url, timeout, user_agent, extra_headers)
if body.strip():
return body, headers
last_exc = ValueError("empty response body")
except Exception as exc:
last_exc = exc
if attempt < attempts - 1:
time.sleep(2 * (attempt + 1))
raise last_exc if last_exc else RuntimeError("fetch failed")
def check_service(service: ServiceConfig, timeout: float, user_agent: str) -> Dict[str, Any]:
result: Dict[str, Any] = {
"name": service.name,
@ -25,7 +49,9 @@ def check_service(service: ServiceConfig, timeout: float, user_agent: str) -> Di
login_cookie = authenticate_service(service, timeout, user_agent)
if login_cookie:
headers.setdefault("Cookie", login_cookie)
body, response_headers = fetch_response(service.current_version_url, timeout, user_agent, headers)
body, response_headers = fetch_version_with_retries(
service.current_version_url, timeout, user_agent, headers
)
result["current"] = extract_version(body, service.current_version_extract, response_headers)
except Exception as exc:
result["current_error"] = str(exc)
@ -38,7 +64,7 @@ def check_service(service: ServiceConfig, timeout: float, user_agent: str) -> Di
if service.upstream_latest_version_url and service.upstream_latest_extract:
headers = build_headers(service.upstream_latest_headers)
try:
body, response_headers = fetch_response(
body, response_headers = fetch_version_with_retries(
service.upstream_latest_version_url, timeout, user_agent, headers
)
result["latest"] = extract_version(body, service.upstream_latest_extract, response_headers)

View file

@ -31,7 +31,7 @@ class Classifier:
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-64k")
self.model = model or os.getenv("OLLAMA_MODEL", "gemma4:26b")
def classify(
self,