chto-ty-takoe-na-baze-kakih/src/pipeline/raw.py
Elshat 6c890fa20a v2: Python MVP — price pipeline + analytics + FastAPI dashboard + digest + tests
- pipeline: fetch/extract/normalize/categorize/validate/llm_extract/raw/orchestrator
- analytics: dynamics, spreads/arbitrage, seasonality, anomalies, alerts, forecast
- dashboard: FastAPI + Plotly (overview/products/product/countries/alerts/quality/sources)
- scheduler (APScheduler 07:30), digest (Telegram/SMTP dry-run), demo_data
- SQLite (PORTABLE) with idempotent upserts, quarantine, alerts dedup
- truthfulness: LLM quote-verified, source link + date on every price
- tests: 13 passed, 1 skipped (robots port)
2026-09-24 07:07:32 +00:00

33 lines
1.2 KiB
Python

"""Raw snapshot storage (thin wrapper around db.save_raw / db.read_raw)."""
from __future__ import annotations
from .. import db
from ..models import RawSnapshot
class RawStore:
"""Facade over the DB raw-snapshot API. Keeps the orchestrator decoupled from db."""
def save(self, source_id: str, url: str, content: bytes, content_type: str) -> RawSnapshot:
return db.save_raw(source_id, url, content, content_type)
def load(self, raw_snapshot_id: str) -> RawSnapshot | None:
data = db.read_raw(raw_snapshot_id)
if data is None:
return None
meta = db.get_raw(raw_snapshot_id)
if not meta:
return None
return RawSnapshot(
id=meta["id"], source_id=meta.get("source_id") or "", url=meta.get("url") or "",
fetched_at=__import__("datetime").datetime.fromisoformat(meta["fetched_at"]),
content_type=meta.get("content_type") or "application/octet-stream",
size=meta["size"], stored_path=meta["stored_path"],
)
@staticmethod
def read_bytes(raw_snapshot_id: str) -> bytes | None:
return db.read_raw(raw_snapshot_id)
__all__ = ["RawStore", "raw_store"]
raw_store = RawStore()