mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-27 00:02:21 +01:00
Server-side photo editor: natural-language editor agent route
(/api/editor/agent), photo_editor tool family + style guide, image-op
provider proxy with progress, email server hardening, gallery/hwfit
routes, and graceful shutdown.
Source: vendor/photocraft (ad1cff44) editor-server files, merged onto
upstream/dev (a8c147b2). Conflict resolution documented in
pr_work/B_conflicts.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
62 lines
1.5 KiB
Python
62 lines
1.5 KiB
Python
"""In-flight activity counters (heavy image ops) for safe restarts/observability.
|
|
|
|
A deploy restart kills any in-flight long image op (a diffusion edit is 60-120 s),
|
|
so the operator needs to know whether the process is busy before issuing
|
|
``systemctl --user restart``. These counters are process-local and cheap.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import threading
|
|
import time
|
|
from contextlib import contextmanager
|
|
from typing import Dict
|
|
|
|
_lock = threading.Lock()
|
|
_image_ops = 0
|
|
_image_ops_by_name: Dict[str, int] = {}
|
|
_started_at = time.time()
|
|
|
|
|
|
def begin_image_op(name: str = "image") -> None:
|
|
global _image_ops
|
|
with _lock:
|
|
_image_ops += 1
|
|
_image_ops_by_name[name] = _image_ops_by_name.get(name, 0) + 1
|
|
|
|
|
|
def end_image_op(name: str = "image") -> None:
|
|
global _image_ops
|
|
with _lock:
|
|
_image_ops = max(0, _image_ops - 1)
|
|
if name in _image_ops_by_name:
|
|
_image_ops_by_name[name] -= 1
|
|
if _image_ops_by_name[name] <= 0:
|
|
_image_ops_by_name.pop(name, None)
|
|
|
|
|
|
@contextmanager
|
|
def image_op(name: str = "image"):
|
|
begin_image_op(name)
|
|
try:
|
|
yield
|
|
finally:
|
|
end_image_op(name)
|
|
|
|
|
|
def activity() -> Dict[str, object]:
|
|
with _lock:
|
|
return {
|
|
"image_ops": _image_ops,
|
|
"image_ops_by_name": dict(_image_ops_by_name),
|
|
"uptime_s": round(time.time() - _started_at, 1),
|
|
}
|
|
|
|
|
|
def heavy_image_ops_active() -> int:
|
|
with _lock:
|
|
return _image_ops
|
|
|
|
|
|
def busy() -> bool:
|
|
return heavy_image_ops_active() > 0
|