betterwithage commited on
Commit
30c3fde
·
verified ·
1 Parent(s): e59bd42

chore(sync): mirror backend .py + Dockerfile to Space (hf-sync-backend)

Browse files

Automated backend sync from szl-holdings/a11oy main via hf-sync-backend.
Updated (differed from the Space): serve.py, szl_energy_operator.py
Deleted (gone from the repo + Dockerfile COPY set): (none)

Keeps the Space-built backend (serve.py + the Dockerfile-COPY'd .py
modules) identical to GitHub main so the Space never rebuilds from a
stale backend, new endpoints don't 404 there, and orphaned modules
removed from the repo don't linger in the Space tree.

Files changed (2) hide show
  1. serve.py +7 -0
  2. szl_energy_operator.py +13 -0
serve.py CHANGED
@@ -1450,6 +1450,13 @@ try:
1450
  import szl_energy_ledger as _szl_energy_ledger
1451
  _szl_energy_ledger_paths = _szl_energy_ledger.register(app, ns="a11oy")
1452
  print(f"[a11oy] energy ledger wired: {_szl_energy_ledger_paths}", file=sys.stderr)
 
 
 
 
 
 
 
1453
  except Exception as _ledger_exc: # additive: never break the Space
1454
  print(f"[a11oy] energy ledger NOT mounted ({_ledger_exc!r}); SPA + API unaffected", file=sys.stderr)
1455
 
 
1450
  import szl_energy_ledger as _szl_energy_ledger
1451
  _szl_energy_ledger_paths = _szl_energy_ledger.register(app, ns="a11oy")
1452
  print(f"[a11oy] energy ledger wired: {_szl_energy_ledger_paths}", file=sys.stderr)
1453
+ try:
1454
+ import szl_energy_operator as _eo_wire
1455
+ import szl_energy_ledger as _el_wire
1456
+ _eo_wire.get_operator().subscribe(_el_wire.record_job)
1457
+ print("[a11oy] energy operator->ledger receipts hook wired", file=sys.stderr)
1458
+ except Exception as _eo_led_exc:
1459
+ print(f"[a11oy] energy operator->ledger hook NOT wired: {_eo_led_exc!r}", file=sys.stderr)
1460
  except Exception as _ledger_exc: # additive: never break the Space
1461
  print(f"[a11oy] energy ledger NOT mounted ({_ledger_exc!r}); SPA + API unaffected", file=sys.stderr)
1462
 
szl_energy_operator.py CHANGED
@@ -416,6 +416,7 @@ class OperatorDaemon:
416
  self._last_records: list[dict] = [] # rolling tail for status/dashboards
417
  self._subscribers: list[Callable[[dict], None]] = []
418
  self._grid_price_eur_mwh: Optional[float] = None # latest meter grid price
 
419
 
420
  # -- subscription (Dev2 receipts hook) --------------------------------
421
  def subscribe(self, cb: Callable[[dict], None]) -> None:
@@ -596,6 +597,9 @@ class OperatorDaemon:
596
  wall_s = time.time() - t0
597
  meter_after = _fetch_joule_meter()
598
  sample_after = _exporter_sample_for_node(meter_after, node.exporter_node)
 
 
 
599
  j_after = (sample_after or {}).get("joules_measured_total")
600
  joules_measured = None
601
  if (isinstance(j_before, (int, float)) and isinstance(j_after, (int, float))
@@ -661,6 +665,10 @@ class OperatorDaemon:
661
  "node_status": dict(self._node_status),
662
  "by_node": {k: dict(v) for k, v in st.by_node.items()},
663
  "uptime_s": round(uptime, 3),
 
 
 
 
664
  "grid_price_eur_mwh": self._grid_price_eur_mwh,
665
  "recent_jobs": list(self._last_records[-10:]),
666
  "exporter": _JOULE_METER_URL,
@@ -698,6 +706,11 @@ def get_operator() -> OperatorDaemon:
698
  return _OPERATOR
699
 
700
 
 
 
 
 
 
701
  # ---------------------------------------------------------------------------
702
  # Registration — dual-register under /api/{ns}/v1/energy/operator/* AND
703
  # /v1/energy/operator/* (mirrors the add_api_route pattern used across the repo).
 
416
  self._last_records: list[dict] = [] # rolling tail for status/dashboards
417
  self._subscribers: list[Callable[[dict], None]] = []
418
  self._grid_price_eur_mwh: Optional[float] = None # latest meter grid price
419
+ self._last_power_w: Optional[float] = None # latest live exporter power_w (W)
420
 
421
  # -- subscription (Dev2 receipts hook) --------------------------------
422
  def subscribe(self, cb: Callable[[dict], None]) -> None:
 
597
  wall_s = time.time() - t0
598
  meter_after = _fetch_joule_meter()
599
  sample_after = _exporter_sample_for_node(meter_after, node.exporter_node)
600
+ if sample_after is not None and sample_after.get("power_w_sample") is not None:
601
+ with self._lock:
602
+ self._last_power_w = float(sample_after["power_w_sample"])
603
  j_after = (sample_after or {}).get("joules_measured_total")
604
  joules_measured = None
605
  if (isinstance(j_before, (int, float)) and isinstance(j_after, (int, float))
 
665
  "node_status": dict(self._node_status),
666
  "by_node": {k: dict(v) for k, v in st.by_node.items()},
667
  "uptime_s": round(uptime, 3),
668
+ "window_seconds": round(uptime, 3),
669
+ "jobs_completed": st.jobs_done,
670
+ "exporter_node": next((n.exporter_node for n in self.nodes), None),
671
+ "power_w_sample": self._last_power_w,
672
  "grid_price_eur_mwh": self._grid_price_eur_mwh,
673
  "recent_jobs": list(self._last_records[-10:]),
674
  "exporter": _JOULE_METER_URL,
 
706
  return _OPERATOR
707
 
708
 
709
+ def handle_status() -> dict:
710
+ """Module-level status accessor for in-process readers (Dev3 projection)."""
711
+ return get_operator().status()
712
+
713
+
714
  # ---------------------------------------------------------------------------
715
  # Registration — dual-register under /api/{ns}/v1/energy/operator/* AND
716
  # /v1/energy/operator/* (mirrors the add_api_route pattern used across the repo).