Spaces:
Running
Running
File size: 5,303 Bytes
a99c2d3 | 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | """
document_loader.py
------------------
Handles loading and extracting text from different file types.
Supported formats:
- .txt (plain text)
- .pdf (PDF documents)
- .csv (comma-separated values)
- .docx (Microsoft Word documents)
Each loader returns a list of LangChain Document objects.
A Document has two fields:
- page_content : the extracted text
- metadata : a dict with extra info like the source file name
"""
import os
from langchain_core.documents import Document
# ββ helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def _make_doc(text: str, source: str) -> Document:
"""Wrap extracted text in a LangChain Document with source metadata."""
return Document(page_content=text, metadata={"source": source})
# ββ per-format loaders ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def load_txt(file_path: str) -> list[Document]:
"""Load a plain-text file and return it as a single Document."""
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
text = f.read()
return [_make_doc(text, file_path)]
def load_pdf(file_path: str) -> list[Document]:
"""
Load a PDF file page-by-page.
Each page becomes its own Document so we can cite the exact page later.
Requires: pypdf
"""
try:
from pypdf import PdfReader
except ImportError:
raise ImportError("pypdf is required for PDF support. Run: pip install pypdf")
reader = PdfReader(file_path)
documents = []
for page_num, page in enumerate(reader.pages):
text = page.extract_text() or ""
if text.strip(): # skip blank pages
doc = Document(
page_content=text,
metadata={"source": file_path, "page": page_num + 1},
)
documents.append(doc)
return documents
def load_csv(file_path: str) -> list[Document]:
"""
Load a CSV file.
Each row is turned into a readable 'key: value' string and stored as
one Document so every row is individually searchable.
Requires: pandas
"""
try:
import pandas as pd
except ImportError:
raise ImportError("pandas is required for CSV support. Run: pip install pandas")
df = pd.read_csv(file_path)
documents = []
for idx, row in df.iterrows():
# Build a human-readable string from each row
row_text = "\n".join(f"{col}: {val}" for col, val in row.items())
doc = Document(
page_content=row_text,
metadata={"source": file_path, "row": idx + 1},
)
documents.append(doc)
return documents
def load_docx(file_path: str) -> list[Document]:
"""
Load a Microsoft Word (.docx) file.
Each paragraph becomes its own Document.
Requires: python-docx
"""
try:
from docx import Document as WordDocument
except ImportError:
raise ImportError(
"python-docx is required for DOCX support. Run: pip install python-docx"
)
word_doc = WordDocument(file_path)
documents = []
for para_num, para in enumerate(word_doc.paragraphs):
text = para.text.strip()
if text: # skip empty paragraphs
doc = Document(
page_content=text,
metadata={"source": file_path, "paragraph": para_num + 1},
)
documents.append(doc)
return documents
# ββ main entry point ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def load_document(file_path: str) -> list[Document]:
"""
Detect the file extension and call the right loader.
Parameters
----------
file_path : str
Full path to the file on disk.
Returns
-------
list[Document]
A list of LangChain Document objects with extracted text.
Raises
------
ValueError β if the file type is not supported.
Exception β if loading fails for any reason.
"""
if not os.path.exists(file_path):
raise FileNotFoundError(f"File not found: {file_path}")
extension = os.path.splitext(file_path)[1].lower()
loaders = {
".txt": load_txt,
".pdf": load_pdf,
".csv": load_csv,
".docx": load_docx,
}
if extension not in loaders:
raise ValueError(
f"Unsupported file type: '{extension}'. "
f"Supported types: {', '.join(loaders.keys())}"
)
# Call the appropriate loader
documents = loaders[extension](file_path)
if not documents:
raise ValueError(f"No readable text found in: {file_path}")
print(f" OK: Loaded {len(documents)} chunk(s) from '{os.path.basename(file_path)}'")
return documents
|