from pathlib import Path from typing import List, Any from langchain_community.document_loaders import PyPDFLoader, TextLoader, CSVLoader from langchain_community.document_loaders import PyMuPDFLoader from langchain_community.document_loaders import Docx2txtLoader from langchain_community.document_loaders.excel import UnstructuredExcelLoader from langchain_community.document_loaders import JSONLoader SUPPORTED_EXTENSIONS = {".pdf", ".txt", ".csv", ".xlsx", ".docx", ".json"} def load_single_file(file_path: str, assets_dir: str = "") -> dict: """ Load a single file and return text Documents plus multimodal chunks. Returns: { "documents": List[Document], # LangChain docs for text chunking "multimodal_chunks": List[dict], # table/image chunks (already text, skip splitter) } """ path = Path(file_path).resolve() suffix = path.suffix.lower() if suffix not in SUPPORTED_EXTENSIONS: raise ValueError(f"Unsupported file type: {suffix}") loader_map = { ".pdf": lambda p: PyMuPDFLoader(str(p)), ".txt": lambda p: TextLoader(str(p)), ".csv": lambda p: CSVLoader(str(p)), ".xlsx": lambda p: UnstructuredExcelLoader(str(p)), ".docx": lambda p: Docx2txtLoader(str(p)), ".json": lambda p: JSONLoader(str(p), jq_schema=".", text_content=False), } loader = loader_map[suffix](path) docs = loader.load() for doc in docs: doc.metadata["source_file"] = path.name doc.metadata["file_type"] = suffix.lstrip(".") doc.metadata["chunk_type"] = "text" if "page" not in doc.metadata: doc.metadata["page"] = 0 # Extract tables and images for PDFs multimodal_chunks = [] if suffix == ".pdf" and assets_dir: try: from src.multimodal_extractor import extract_tables_and_images multimodal_chunks = extract_tables_and_images( pdf_path=str(path), assets_dir=assets_dir, source_file=path.name, ) except Exception as e: print(f"[WARN] Multimodal extraction failed for {path.name}: {e}") print(f"[INFO] Loaded {len(docs)} text docs + {len(multimodal_chunks)} multimodal chunks from {path.name}") return { "documents": docs, "multimodal_chunks": multimodal_chunks, } def load_all_documents(data_dir: str) -> List[Any]: """ Load all supported files from the data directory and convert to LangChain document structure. Supported: PDF, TXT, CSV, Excel, Word, JSON """ data_path = Path(data_dir).resolve() print(f"[DEBUG] Data path: {data_path}") documents = [] pdf_files = list(data_path.glob('**/*.pdf')) print(f"[DEBUG] Found {len(pdf_files)} PDF files: {[str(f) for f in pdf_files]}") for pdf_file in pdf_files: print(f"[DEBUG] Loading PDF: {pdf_file}") try: loader = PyPDFLoader(str(pdf_file)) loaded = loader.load() print(f"[DEBUG] Loaded {len(loaded)} PDF docs from {pdf_file}") documents.extend(loaded) except Exception as e: print(f"[ERROR] Failed to load PDF {pdf_file}: {e}") txt_files = list(data_path.glob('**/*.txt')) print(f"[DEBUG] Found {len(txt_files)} TXT files: {[str(f) for f in txt_files]}") for txt_file in txt_files: print(f"[DEBUG] Loading TXT: {txt_file}") try: loader = TextLoader(str(txt_file)) loaded = loader.load() print(f"[DEBUG] Loaded {len(loaded)} TXT docs from {txt_file}") documents.extend(loaded) except Exception as e: print(f"[ERROR] Failed to load TXT {txt_file}: {e}") csv_files = list(data_path.glob('**/*.csv')) print(f"[DEBUG] Found {len(csv_files)} CSV files: {[str(f) for f in csv_files]}") for csv_file in csv_files: print(f"[DEBUG] Loading CSV: {csv_file}") try: loader = CSVLoader(str(csv_file)) loaded = loader.load() print(f"[DEBUG] Loaded {len(loaded)} CSV docs from {csv_file}") documents.extend(loaded) except Exception as e: print(f"[ERROR] Failed to load CSV {csv_file}: {e}") xlsx_files = list(data_path.glob('**/*.xlsx')) print(f"[DEBUG] Found {len(xlsx_files)} Excel files: {[str(f) for f in xlsx_files]}") for xlsx_file in xlsx_files: print(f"[DEBUG] Loading Excel: {xlsx_file}") try: loader = UnstructuredExcelLoader(str(xlsx_file)) loaded = loader.load() print(f"[DEBUG] Loaded {len(loaded)} Excel docs from {xlsx_file}") documents.extend(loaded) except Exception as e: print(f"[ERROR] Failed to load Excel {xlsx_file}: {e}") docx_files = list(data_path.glob('**/*.docx')) print(f"[DEBUG] Found {len(docx_files)} Word files: {[str(f) for f in docx_files]}") for docx_file in docx_files: print(f"[DEBUG] Loading Word: {docx_file}") try: loader = Docx2txtLoader(str(docx_file)) loaded = loader.load() print(f"[DEBUG] Loaded {len(loaded)} Word docs from {docx_file}") documents.extend(loaded) except Exception as e: print(f"[ERROR] Failed to load Word {docx_file}: {e}") json_files = list(data_path.glob('**/*.json')) print(f"[DEBUG] Found {len(json_files)} JSON files: {[str(f) for f in json_files]}") for json_file in json_files: print(f"[DEBUG] Loading JSON: {json_file}") try: loader = JSONLoader(str(json_file)) loaded = loader.load() print(f"[DEBUG] Loaded {len(loaded)} JSON docs from {json_file}") documents.extend(loaded) except Exception as e: print(f"[ERROR] Failed to load JSON {json_file}: {e}") print(f"[DEBUG] Total loaded documents: {len(documents)}") return documents if __name__ == "__main__": docs = load_all_documents("data") print(f"Loaded {len(docs)} documents.") print("Example document:", docs[0] if docs else None)