Spaces:
Running
Running
| """Storage abstraction for book PDFs. | |
| Why this exists: stage 2 acquisition writes PDFs and stages 3+ read them. | |
| On a single laptop they all live under `data/raw/`; on cloud (Streamlit | |
| Community Cloud has an ephemeral disk) we want the same code reading | |
| from Cloudflare R2 without per-call branching. | |
| Public API: | |
| get_storage() -> Storage | |
| Storage.ensure_local(book_id) -> Path # download to local cache if remote | |
| Storage.put_pdf(book_id, src) -> str # returns the storage URI | |
| Storage.exists(book_id) -> bool | |
| Storage.delete(book_id) -> None | |
| Storage.list_book_ids() -> list[str] | |
| Backends are picked by `backends.storage` in config.yaml: | |
| - 'local' (default): files under cfg.paths.raw_dir. | |
| - 'r2': Cloudflare R2 bucket via boto3 (S3-compatible). | |
| Needs R2_* env vars from .env / st.secrets. | |
| Auto-promotion: when RUNTIME=cloud, `local` is silently promoted to `r2` | |
| so the cloud deploy never has to remember to flip config.yaml. Same | |
| pattern as the inventory_db backend. | |
| """ | |
| from __future__ import annotations | |
| from .base import Storage | |
| from .factory import get_storage | |
| __all__ = ["Storage", "get_storage"] | |