PrintGuard 2.0 — ShuffleNetV2 + few-shot prototypical network, TFLite via LiteRT, ≈5 MB, runs unmodified in the browser (Pyodide) and on CPython [P]

Reddit r/MachineLearning Tools

Summary

PrintGuard 2.0 is a major rewrite of a few-shot FDM fault detector using a ShuffleNetV2 backbone and prototypical network, now with a single Python engine that runs unmodified on both CPython and Pyodide in the browser via a platform abstraction layer, enabling per-printer sensitivity tuning and fair inference scheduling.

Hi everyone, I shared PrintGuard here about a year ago as a few-shot FDM failure detector built on a ShuffleNetV2 backbone classified by a prototypical network — the model from my dissertation, packaged with a hub and a web UI. v2.0 ships today and is a complete rewrite of everything around the model, so I wanted to walk you through what's changed and what hasn't. What hasn't changed is the model. It's still a ShuffleNetV2 encoder classified by nearest prototype, trained for few-shot FDM fault detection in [Edge-FDM-Fault-Detection](https://github.com/oliverbravery/Edge-FDM-Fault-Detection) (with a technical write-up in the repo). What has changed is the runtime: the model is now a ≈5 MB TFLite export via LiteRT, classified by nearest prototype, with per-printer sensitivity and threshold sliders that map directly onto the prototype distances — so you can tune for camera and lighting without retraining. The interesting bit for this sub is the architecture around the model. v2.0 is a single Python engine that runs unmodified on CPython (hub mode) and on Pyodide in the browser (local mode). Everything mode-specific is confined to one `Platform` implementation per runtime — the two modes cannot drift apart because they execute the same files. The methods on the `Platform` contract are exactly the ones that aren't portable: `infer(rgb)`, `discover_cameras()`, `open_camera(id, source)`, `http(...)`, `encode_jpeg(rgb)`, `load_state` / `save_state`. On the CPython side, `infer` is `ai-edge-litert` on CPU threads, `discover_cameras` walks the MediaMTX path list, and `open_camera` is a PyAV reader thread per RTSP stream. On the browser side, `infer` is LiteRT.js in WASM via a JS bridge, `discover_cameras` is `enumerateDevices()`, and `open_camera` is `getUserMedia` \+ canvas grabs. The UI is presentation-only and speaks one JSON command/event protocol — over a WebSocket in hub mode, over an in-page Pyodide bridge in local mode. The engine cannot tell which transport it is on. **No mode-specific logic lives anywhere else**; if a feature needs a runtime service, it extends the `Platform` contract on both sides. Inference scheduling is fully dynamic and fairness-aware: 1. A smoothed estimate of observed inference latency continuously yields the sustainable total rate (`workers / latency`). 2. That capacity is water-filled across in-use cameras (max-min fairness): no camera is allocated beyond its native fps, and surplus flows to cameras that can use it. 3. A free worker takes the most overdue camera and grabs its **freshest** frame at dispatch time. Frames carry a sequence identity, so the same frame is never inferred twice, and results always describe the present, not a backlog. On RTSP, MediaMTX bursts the buffered GOP on connect, so stream fps is trusted from the SDP `average_rate` where available, and measured only after a warm-up otherwise. The defect pipeline is a monitor on top of a per-printer score stream. `score ≥ threshold` for `N` consecutive frames triggers the configured action (alert only, pause, or cancel) on the linked OctoPrint or Moonraker service, with retries on failure; the alert event carries the action and its outcome, the UI error feed gets a copy, and the snapshot goes out to every enabled notification channel (ntfy, Telegram, Discord). The fail-safe behaviour is the part I most want feedback on, because I have strong opinions about it. A printer's *watching* state gates inference: |Linked service reports|Watched?|Why| |:-|:-|:-| |no service linked|yes|nothing to gate on| |`printing`|yes|the job needs eyes| |no state yet / `unknown`|yes|can't tell → watch| |`offline` (unreachable)|yes|losing the signal must not stop monitoring| |`idle` / `paused` / `error`|no (standby)|positively not printing| Only a *positive* "not printing" stands inference down. The watchdog then warns on the dashboard *and* through notification channels when a camera drops, a feed freezes or a printer service stops answering, and a failed pause is announced, never swallowed. I'd be very interested to hear how this stance interacts with people who run multiple printers with mixed reliability on their printer services. There's a [live browser demo](https://oliverbravery.github.io/PrintGuard/) (the whole engine in Pyodide + LiteRT.js WASM), the [Docker image](https://github.com/oliverbravery/PrintGuard/pkgs/container/printguard) is multi-arch, and the [architecture doc](https://github.com/oliverbravery/PrintGuard/blob/main/docs/architecture.md) goes into all of the above in more detail with diagrams of the engine layout and the defect pipeline. This is a major version — nothing from 1.x migrates, and a 2.0 hub starts from a fresh configuration. Issues, especially around the fairness scheduler, the CORS / mixed-content / `host.docker.internal` edge cases, and the LiteRT ↔ Pyodide bridge, are very welcome. Let's keep failure detection open-source, local and accessible for all.
Original Article

Similar Articles

PrefixGuard: From LLM-Agent Traces to Online Failure-Warning Monitors

Hugging Face Daily Papers

# Paper page - PrefixGuard: From LLM-Agent Traces to Online Failure-Warning Monitors Source: [https://huggingface.co/papers/2605.06455](https://huggingface.co/papers/2605.06455) ## Abstract PrefixGuard enables effective online monitoring of LLM agents through trace analysis and prefix\-based risk scoring, demonstrating strong performance across multiple benchmark tasks while providing diagnostic insights for alert reliability\. Large language model \(LLM\) agents now execute long, tool\-using ta