"""Progress/reporting shim. The pipeline in `inference.py` and `vectorize.py` is ported from the FraXtex QGIS plugin, where every algorithm receives a `QgsProcessingFeedback`. Keeping the same call surface here is what lets the two implementations stay diffable: the ported code is identical apart from its imports, and this object absorbs the difference between a QGIS progress dialog and a Gradio one. See CLAUDE.md: qfraxtex is canonical for pipeline logic. """ class FatalError(RuntimeError): """Raised by `reportError(..., fatalError=True)`. In QGIS the algorithm returns `{}` after reporting; here the caller is a Gradio handler, so an exception is the equivalent way to abandon the run and surface the message to the user. """ class Feedback: """Collects log lines and forwards progress to an optional Gradio progress bar.""" def __init__(self, progress=None): self._progress = progress self.messages = [] self.warnings = [] def pushInfo(self, text): self.messages.append(str(text)) def pushWarning(self, text): text = str(text) self.warnings.append(text) self.messages.append(f"⚠️ {text}") def reportError(self, text, fatalError=False): text = str(text) self.messages.append(f"❌ {text}") if fatalError: raise FatalError(text) def isCanceled(self): # Gradio has no cancellation signal that reaches a running handler. return False def setProgress(self, percent): if self._progress is not None: self._progress(percent / 100.0) def log(self): return "\n".join(self.messages)