Report-Genius / backend /scripts /dedupe_document_records.py
StormShadow308's picture
Deploy RICS v2 backend (CPU embedder + reranker, baked jina models)
a671976
Raw
History Blame Contribute Delete
2 kB
"""One-off: collapse duplicate reference uploads (metadata + disk files).
Keeps one library row and one physical file per unique document content. Shared
FAISS chunks are untouched — only ``compat_documents`` rows and surplus files
under ``reference_uploads/`` are removed.
Usage::
python -m backend.scripts.dedupe_document_records [tenant_id ...]
With no tenant ids, all tenants under ``DATA_DIR/tenants/`` are processed.
"""
from __future__ import annotations
import sys
from backend.rag.store import get_rag_store
from backend.rag.types import TIER_REFERENCE
from backend.storage import tenant_store
from backend.storage.document_library import dedupe_tenant_storage
from backend.storage.report_session import list_documents
def dedupe_tenant(tenant_id: str) -> dict:
store = get_rag_store()
before_chunks = store.count(tenant_id, TIER_REFERENCE)
stats = dedupe_tenant_storage(tenant_id)
after_chunks = store.count(tenant_id, TIER_REFERENCE)
return {
"tenant": tenant_id,
"docs_before": stats["docs_before"],
"docs_after": stats["docs_after"],
"records_removed": stats["records_removed"],
"files_removed": stats["files_removed"],
"ref_chunks_before": before_chunks,
"ref_chunks_after": after_chunks,
}
def main(argv: list[str]) -> int:
tenants = argv[1:]
if not tenants:
root = tenant_store.tenant_root("").parent
tenants = (
[p.name for p in root.iterdir() if p.is_dir()] if root.is_dir() else []
)
for tenant_id in tenants:
res = dedupe_tenant(tenant_id)
if res["records_removed"] or res["files_removed"]:
print(res)
assert (
res["ref_chunks_before"] == res["ref_chunks_after"]
), f"chunk count changed for {tenant_id}: {res}"
assert len(list_documents(tenant_id)) == res["docs_after"]
print("done")
return 0
if __name__ == "__main__":
raise SystemExit(main(sys.argv))