repair-guy / core /store.py
airayven7's picture
Sync from GitHub b4f1871
2ad630b verified
Raw
History Blame Contribute Delete
3.27 kB
"""Shared on-disk document store conventions (base class for both approaches).
Layout: <store root>/<doc_id>/
doc.pdf original PDF, kept to re-render retrieved pages at answer time
index.json metadata; always contains "name" and "method", written LAST —
a directory without it is an interrupted ingest and is
ignored (and overwritten on the next attempt)
... per-method data files (see VisualStore / ParsedStore)
The "method" field guards against pointing a store at the other method's
directory: docs whose method doesn't match are skipped loudly in list_docs
and rejected by meta()/exists().
"""
from __future__ import annotations
import json
import os
import re
import shutil
import numpy as np
EMB_DTYPE = np.float16
def slugify(name: str) -> str:
slug = re.sub(r"[^a-z0-9]+", "-", name.lower()).strip("-")
return slug or "doc"
class DocStore:
method: str = "" # subclasses set "visual" / "parsed"
def __init__(self, root: str):
self.root = os.path.abspath(root)
os.makedirs(self.root, exist_ok=True)
def _dir(self, doc_id: str) -> str:
return os.path.join(self.root, doc_id)
def _read_meta(self, doc_id: str) -> dict | None:
path = os.path.join(self._dir(doc_id), "index.json")
if not os.path.isfile(path):
return None
with open(path) as f:
return json.load(f)
def exists(self, doc_id: str) -> bool:
meta = self._read_meta(doc_id)
return meta is not None and meta.get("method") == self.method
def meta(self, doc_id: str) -> dict:
meta = self._read_meta(doc_id)
if meta is None:
raise FileNotFoundError(f"No indexed doc at {self._dir(doc_id)}")
if meta.get("method") != self.method:
raise ValueError(
f"{doc_id} was indexed with method={meta.get('method')!r}, "
f"but this is a {self.method!r} store"
)
return meta
def pdf_path(self, doc_id: str) -> str:
return os.path.join(self._dir(doc_id), "doc.pdf")
def _page_count(self, meta: dict) -> int:
raise NotImplementedError
def list_docs(self) -> list[dict]:
docs = []
for doc_id in sorted(os.listdir(self.root)):
if not os.path.isdir(self._dir(doc_id)):
continue
meta = self._read_meta(doc_id)
if meta is None:
continue
if meta.get("method") != self.method:
print(
f"Skipping {doc_id}: method={meta.get('method')!r} in a "
f"{self.method!r} store"
)
continue
size = sum(
os.path.getsize(os.path.join(self._dir(doc_id), f))
for f in os.listdir(self._dir(doc_id))
)
docs.append(
{
"doc_id": doc_id,
"name": meta["name"],
"pages": self._page_count(meta),
"size_mb": size / 1e6,
}
)
return docs
def delete(self, doc_id: str) -> None:
shutil.rmtree(self._dir(doc_id), ignore_errors=True)