from __future__ import annotations import hashlib from pathlib import Path class Settings: def __init__(self) -> None: self._models_dir: Path | None = None self._grammars_dir: Path | None = None self._db_path: Path | None = None self._samples_dir: Path | None = None self._webhook_url: str | None = None self._webhook_secret: str | None = None @property def models_dir(self) -> Path: if self._models_dir is not None: return self._models_dir p = Path(__file__).resolve().parent.parent.parent / "models" if not p.exists(): p = Path.cwd() / "models" return p @models_dir.setter def models_dir(self, value: Path) -> None: self._models_dir = value @property def grammars_dir(self) -> Path: if self._grammars_dir is not None: return self._grammars_dir p = Path(__file__).resolve().parent.parent.parent / "grammars" if not p.exists(): p = Path.cwd() / "grammars" return p @grammars_dir.setter def grammars_dir(self, value: Path) -> None: self._grammars_dir = value @property def db_path(self) -> Path: if self._db_path is not None: return self._db_path return Path.cwd() / "pageparse.db" @db_path.setter def db_path(self, value: Path) -> None: self._db_path = value @property def samples_dir(self) -> Path: if self._samples_dir is not None: return self._samples_dir p = Path(__file__).resolve().parent.parent.parent / "samples" if not p.exists(): p = Path.cwd() / "samples" return p @samples_dir.setter def samples_dir(self, value: Path) -> None: self._samples_dir = value @property def webhook_url(self) -> str | None: return self._webhook_url @webhook_url.setter def webhook_url(self, value: str) -> None: self._webhook_url = value @property def webhook_secret(self) -> str | None: return self._webhook_secret @webhook_secret.setter def webhook_secret(self, value: str) -> None: self._webhook_secret = value airgap: bool = False confidence_threshold: float = 0.5 ollama_url: str = "http://localhost:11434" slm_model: str = "llama3.2:1b" vision_model: str = "moondream" ocr_model: str = "tr_ocr_base_handwritten.onnx" embedding_model: str = "all-MiniLM-L6-v2.onnx" whisper_model: str = "ggml-tiny.en-q5_0.bin" tts_enabled: bool = False auto_schema: bool = True diff_sync_enabled: bool = False max_workers: int = 4 prometheus_enabled: bool = True tracing_enabled: bool = True def model_path(self, name: str) -> Path: return self.models_dir / name def grammar_path(self, name: str = "task.gbnf") -> Path: return self.grammars_dir / name def content_hash(self, content: bytes) -> str: return hashlib.sha256(content).hexdigest() def should_reprocess(self, source_id: int, content_hash: str) -> bool: if not self.diff_sync_enabled: return True from pageparse.store import Store store = Store() sources = store.list_sources() for s in sources: if s.get("content_hash") == content_hash: return False return True settings = Settings()