Spaces:
Sleeping
Sleeping
File size: 3,455 Bytes
f2eba97 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | from pathlib import Path
from typing import List
from langchain_core.documents import Document
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
import config
from utils.logger import get_logger
logger = get_logger(__name__)
# ββ Splitter shared for both PDF and TXT ββββββββββββββββββββ
def _get_splitter() -> RecursiveCharacterTextSplitter:
return RecursiveCharacterTextSplitter(
chunk_size=config.CHUNK_SIZE,
chunk_overlap=config.CHUNK_OVERLAP,
length_function=len,
separators=["\n\n", "\n", ". ", "? ", "! ", "; ", " ", ""],
)
# ββ PDF Loader ββββββββββββββββββββββββββββββββββββββββββββββ
def load_and_chunk_pdf(file_path: str, source_name: str = None) -> List[Document]:
path = Path(file_path)
if not path.exists():
raise FileNotFoundError(f"PDF not found: {file_path}")
if path.suffix.lower() != ".pdf":
raise ValueError(f"File is not a PDF: {file_path}")
source = source_name or path.name
logger.info(f"Loading PDF: {path.name}")
loader = PyPDFLoader(str(path))
pages = loader.load()
logger.info(f" β {len(pages)} pages loaded from '{path.name}'")
# Inject consistent source metadata
for doc in pages:
doc.metadata["source"] = source
doc.metadata["file_type"] = "pdf"
chunks = _get_splitter().split_documents(pages)
logger.info(f" β {len(chunks)} chunks created from PDF '{source}'")
return chunks
# ββ TXT Loader ββββββββββββββββββββββββββββββββββββββββββββββ
def load_and_chunk_txt(file_path: str, source_name: str = None) -> List[Document]:
path = Path(file_path)
if not path.exists():
raise FileNotFoundError(f"TXT file not found: {file_path}")
source = source_name or path.name
logger.info(f"Loading TXT: {path.name}")
text = path.read_text(encoding="utf-8", errors="ignore")
logger.info(f" β {len(text)} characters loaded from '{path.name}'")
base_doc = Document(
page_content=text,
metadata={
"source": source,
"file_type": "txt",
"page": 0,
},
)
chunks = _get_splitter().split_documents([base_doc])
# Enrich each chunk with section hint (first line of chunk as section label)
for i, chunk in enumerate(chunks):
first_line = chunk.page_content.strip().split("\n")[0][:60]
chunk.metadata["section"] = first_line
chunk.metadata["chunk_index"] = i
logger.info(f" β {len(chunks)} chunks created from TXT '{source}'")
return chunks
# ββ Universal entry point ββββββββββββββββββββββββββββββββββββ
def load_and_chunk_file(file_path: str, source_name: str = None) -> List[Document]:
"""Route to correct loader based on file extension."""
suffix = Path(file_path).suffix.lower()
if suffix == ".pdf":
return load_and_chunk_pdf(file_path, source_name)
elif suffix == ".txt":
return load_and_chunk_txt(file_path, source_name)
else:
raise ValueError(f"Unsupported file type: {suffix}. Supported: .pdf, .txt")
|