Filesystem sampler.
Polls the watch dir recursively for the newest .slp (HDF5) and the
newest training_log.csv under any models/ directory. Recursion
matters: start.sh clones the tutorial repository into a subfolder of the
watch dir, and SLEAP writes models/ next to the project file — a
top-level-only scan misses everyone who follows the tutorial layout.
Returns numeric progress signals only — no filenames, no paths, no file
contents leave this module.
A partially-written .slp may raise on open; we swallow and return
None for that field, letting the next tick try again.
Attributes
FRAMES_DATASET = 'frames'
module-attribute
LOSS_COLUMN_CANDIDATES = ('val/loss', 'train/loss', 'val_loss', 'train_loss', 'loss')
module-attribute
logger = logging.getLogger(__name__)
module-attribute
Functions:
count_labeled_frames(slp)
Source code in packages/client/src/lablink_client_service/monitoring/samplers/filesystem.py
| def count_labeled_frames(slp: Path) -> int | None:
try:
with h5py.File(slp, "r") as f:
ds = f.get(FRAMES_DATASET)
if ds is None:
return None
return int(ds.shape[0])
except (OSError, KeyError, ValueError) as e:
logger.debug("h5py read of %s failed: %s", slp, e)
return None
|
parse_training_log(log)
Source code in packages/client/src/lablink_client_service/monitoring/samplers/filesystem.py
| def parse_training_log(log: Path) -> tuple[int | None, float | None]:
try:
with log.open() as f:
rows = list(csv.DictReader(f))
except OSError as e:
logger.debug("training_log read failed: %s", e)
return None, None
if not rows:
return None, None
last = rows[-1]
try:
epoch = int(float(last.get("epoch", "0")))
except (TypeError, ValueError):
return None, None
return epoch, _pick_loss(last)
|
sample(watch_dir)
Source code in packages/client/src/lablink_client_service/monitoring/samplers/filesystem.py
| def sample(watch_dir: str) -> tuple[int | None, int | None, float | None]:
root = Path(watch_dir)
if not root.exists():
return None, None, None
# ponytail: full directory walk every tick; cache/inotify if a large
# dataset under the watch dir ever makes this visible in profiles.
slp = _latest(root.glob("**/*.slp"))
frames = count_labeled_frames(slp) if slp is not None else None
log = _latest(root.glob("**/models/**/training_log.csv"))
epoch, loss = (None, None)
if log is not None:
epoch, loss = parse_training_log(log)
return frames, epoch, loss
|