Rabbook / rag /registry.py
Matcry's picture
Deploy snapshot
c76423f
Raw
History Blame Contribute Delete
3.92 kB
import json
from pathlib import Path
from langchain_core.documents import Document
from core.config import REGISTRY_PATH
def load_chunk_registry(registry_path=REGISTRY_PATH):
registry_file = Path(registry_path)
if not registry_file.exists():
return {"by_document": {}, "by_chunk_id": {}}
return json.loads(registry_file.read_text(encoding="utf-8"))
def update_chunk_registry(chunks, registry_path=REGISTRY_PATH):
"""
Persist a lightweight chunk registry for fast neighbor lookup at query time.
"""
registry = load_chunk_registry(registry_path)
by_document = registry.setdefault("by_document", {})
by_chunk_id = registry.setdefault("by_chunk_id", {})
for chunk in chunks:
metadata = dict(chunk.metadata)
document_id = metadata.get("document_id")
chunk_id = metadata.get("chunk_id")
chunk_index = metadata.get("chunk_index")
if document_id is None or chunk_id is None or chunk_index is None:
continue
chunk_record = {
"page_content": chunk.page_content,
"metadata": metadata,
}
by_document.setdefault(document_id, {})[str(int(chunk_index))] = chunk_record
by_chunk_id[chunk_id] = chunk_record
Path(registry_path).write_text(
json.dumps(registry, indent=2, ensure_ascii=False),
encoding="utf-8",
)
def list_documents(registry_path=REGISTRY_PATH):
registry = load_chunk_registry(registry_path)
documents = {}
for document_id, chunks in registry.get("by_document", {}).items():
chunk_records = list(chunks.values())
if not chunk_records:
continue
first_metadata = chunk_records[0].get("metadata", {})
pages = [
chunk_record.get("metadata", {}).get("page")
for chunk_record in chunk_records
if chunk_record.get("metadata", {}).get("page") is not None
]
documents[document_id] = {
"document_id": document_id,
"file_name": first_metadata.get("file_name", "Unknown"),
"file_type": first_metadata.get("file_type", "unknown"),
"chunk_count": len(chunk_records),
"page_count": (max(int(page) for page in pages) + 1) if pages else None,
"source": first_metadata.get("source", ""),
}
return sorted(documents.values(), key=lambda item: item["file_name"].lower())
def delete_document_from_registry(document_id, registry_path=REGISTRY_PATH):
registry = load_chunk_registry(registry_path)
by_document = registry.get("by_document", {})
by_chunk_id = registry.get("by_chunk_id", {})
removed_document = by_document.pop(document_id, None)
if not removed_document:
return False
for chunk_record in removed_document.values():
chunk_id = chunk_record.get("metadata", {}).get("chunk_id")
if not chunk_id:
continue
by_chunk_id.pop(chunk_id, None)
Path(registry_path).write_text(
json.dumps(registry, indent=2, ensure_ascii=False),
encoding="utf-8",
)
return True
def rebuild_chunk_registry_from_vectorstore(vectorstore, registry_path=REGISTRY_PATH):
"""
Rebuild the registry from the current Chroma collection contents.
"""
collection = vectorstore._collection.get(include=["documents", "metadatas"])
documents = []
for page_content, metadata in zip(
collection.get("documents", []),
collection.get("metadatas", []),
):
if not page_content:
continue
documents.append(Document(page_content=page_content, metadata=metadata or {}))
Path(registry_path).write_text(
json.dumps({"by_document": {}, "by_chunk_id": {}}, indent=2, ensure_ascii=False),
encoding="utf-8",
)
update_chunk_registry(documents, registry_path=registry_path)
return len(documents)