Platform bundle: marketing publish, IT ops, packaging, agents mesh.
Volledige Foodlinkk Command Center uitbreiding met social automatisering, reclamefolder filters, Proxmox monitoring en documentatie.
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
"""PA multi-site live status — 4 browser slots for Cockpit."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
PA_SITES = ("Airbnb", "Booking.com", "DuckDuckGo", "HolidayCheck")
|
||||
|
||||
_state: dict[str, Any] = {
|
||||
"job_id": None,
|
||||
"query": "",
|
||||
"chat_id": None,
|
||||
"user_name": "",
|
||||
"status": "idle",
|
||||
"updated_at": None,
|
||||
"slots": {
|
||||
site: {
|
||||
"label": site,
|
||||
"status": "idle",
|
||||
"url": None,
|
||||
"title": None,
|
||||
"error": None,
|
||||
"index": i + 1,
|
||||
"total": len(PA_SITES),
|
||||
"screenshot_b64": None,
|
||||
"updated_at": None,
|
||||
}
|
||||
for i, site in enumerate(PA_SITES)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _now() -> str:
|
||||
return datetime.now(timezone.utc).isoformat()
|
||||
|
||||
|
||||
def _slot(label: str) -> dict[str, Any]:
|
||||
slots = _state["slots"]
|
||||
if label not in slots:
|
||||
slots[label] = {
|
||||
"label": label,
|
||||
"status": "idle",
|
||||
"url": None,
|
||||
"title": None,
|
||||
"error": None,
|
||||
"index": 0,
|
||||
"total": len(PA_SITES),
|
||||
"screenshot_b64": None,
|
||||
"updated_at": _now(),
|
||||
}
|
||||
return slots[label]
|
||||
|
||||
|
||||
def start_job(
|
||||
job_id: str,
|
||||
query: str,
|
||||
*,
|
||||
chat_id: int | None = None,
|
||||
user_name: str = "",
|
||||
sites: list[str] | None = None,
|
||||
) -> None:
|
||||
site_list = sites or list(PA_SITES)
|
||||
_state["job_id"] = job_id
|
||||
_state["query"] = query[:200]
|
||||
_state["chat_id"] = chat_id
|
||||
_state["user_name"] = user_name
|
||||
_state["status"] = "running"
|
||||
_state["updated_at"] = _now()
|
||||
_state["slots"] = {
|
||||
site: {
|
||||
"label": site,
|
||||
"status": "waiting",
|
||||
"url": None,
|
||||
"title": None,
|
||||
"error": None,
|
||||
"index": i + 1,
|
||||
"total": len(site_list),
|
||||
"screenshot_b64": None,
|
||||
"updated_at": _now(),
|
||||
}
|
||||
for i, site in enumerate(site_list)
|
||||
}
|
||||
|
||||
|
||||
def set_comparing() -> None:
|
||||
_state["status"] = "comparing"
|
||||
_state["updated_at"] = _now()
|
||||
|
||||
|
||||
def finish_job() -> None:
|
||||
_state["status"] = "done"
|
||||
_state["updated_at"] = _now()
|
||||
|
||||
|
||||
def fail_job(error: str) -> None:
|
||||
_state["status"] = "failed"
|
||||
_state["updated_at"] = _now()
|
||||
_state["error"] = error[:200]
|
||||
|
||||
|
||||
def update_slot(
|
||||
label: str,
|
||||
*,
|
||||
status: str,
|
||||
url: str | None = None,
|
||||
title: str | None = None,
|
||||
error: str | None = None,
|
||||
index: int | None = None,
|
||||
total: int | None = None,
|
||||
screenshot_b64: str | None = None,
|
||||
) -> None:
|
||||
slot = _slot(label)
|
||||
slot["status"] = status
|
||||
slot["updated_at"] = _now()
|
||||
if url is not None:
|
||||
slot["url"] = url
|
||||
if title is not None:
|
||||
slot["title"] = title
|
||||
if error is not None:
|
||||
slot["error"] = error[:300]
|
||||
if index is not None:
|
||||
slot["index"] = index
|
||||
if total is not None:
|
||||
slot["total"] = total
|
||||
if screenshot_b64 is not None:
|
||||
slot["screenshot_b64"] = screenshot_b64
|
||||
_state["updated_at"] = _now()
|
||||
|
||||
|
||||
def get_live() -> dict[str, Any]:
|
||||
out = {
|
||||
"job_id": _state.get("job_id"),
|
||||
"query": _state.get("query"),
|
||||
"chat_id": _state.get("chat_id"),
|
||||
"user_name": _state.get("user_name"),
|
||||
"status": _state.get("status", "idle"),
|
||||
"updated_at": _state.get("updated_at"),
|
||||
"sites": list(PA_SITES),
|
||||
"slots": [],
|
||||
}
|
||||
for site in PA_SITES:
|
||||
slot = dict(_state["slots"].get(site) or _slot(site))
|
||||
slot.pop("screenshot_b64", None)
|
||||
slot["has_screenshot"] = bool(
|
||||
(_state["slots"].get(site) or {}).get("screenshot_b64")
|
||||
)
|
||||
out["slots"].append(slot)
|
||||
return out
|
||||
|
||||
|
||||
def get_slot_screenshot(label: str) -> bytes | None:
|
||||
slot = _state["slots"].get(label)
|
||||
if not slot or not slot.get("screenshot_b64"):
|
||||
return None
|
||||
import base64
|
||||
|
||||
return base64.b64decode(slot["screenshot_b64"])
|
||||
Reference in New Issue
Block a user