Spaces:
Sleeping
Sleeping
| from langchain_community.document_loaders import PyPDFLoader, DirectoryLoader | |
| from langchain_text_splitters import RecursiveCharacterTextSplitter | |
| from langchain_community.embeddings import HuggingFaceEmbeddings | |
| from langchain_core.documents import Document | |
| from datasets import load_dataset | |
| from typing import List, Optional, Dict, Any | |
| import csv | |
| import json | |
| from pathlib import Path | |
| # Extract Data From PDF file(s) | |
| def load_pdf_file(data_path: str) -> List[Document]: | |
| path = Path(data_path) | |
| if not path.exists(): | |
| raise FileNotFoundError(f"PDF path not found: {data_path}") | |
| if path.is_file(): | |
| if path.suffix.lower() != ".pdf": | |
| raise ValueError( | |
| "When DATA_SOURCE=pdf and path is a file, it must be a .pdf file" | |
| ) | |
| return PyPDFLoader(str(path)).load() | |
| loader = DirectoryLoader(str(path), glob="*.pdf", loader_cls=PyPDFLoader) | |
| return loader.load() | |
| # Load Student Q&A Dataset from Hugging Face | |
| def load_hf_dataset(dataset_name: str) -> List[Document]: | |
| dataset = load_dataset(dataset_name, split="train") | |
| documents = [] | |
| for row in dataset: | |
| # Build a rich text blob from all available fields in the row | |
| content_parts = [] | |
| for key, value in row.items(): | |
| if value: | |
| content_parts.append(f"{key.capitalize()}: {value}") | |
| page_content = "\n".join(content_parts) | |
| documents.append( | |
| Document(page_content=page_content, metadata={"source": dataset_name}) | |
| ) | |
| return documents | |
| def _parse_columns(columns: Optional[str]) -> Optional[List[str]]: | |
| if not columns: | |
| return None | |
| parsed = [col.strip() for col in columns.split(",") if col.strip()] | |
| return parsed or None | |
| def _row_to_document( | |
| row: Dict[str, Any], | |
| source_name: str, | |
| text_columns: Optional[List[str]] = None, | |
| ) -> Optional[Document]: | |
| content_parts: List[str] = [] | |
| if text_columns: | |
| for key in text_columns: | |
| value = row.get(key) | |
| if value is not None and str(value).strip(): | |
| content_parts.append(f"{key.capitalize()}: {value}") | |
| else: | |
| for key, value in row.items(): | |
| if value is not None and str(value).strip(): | |
| content_parts.append(f"{key.capitalize()}: {value}") | |
| if not content_parts: | |
| return None | |
| return Document( | |
| page_content="\n".join(content_parts), | |
| metadata={"source": source_name}, | |
| ) | |
| def load_local_dataset( | |
| local_path: str, text_columns: Optional[str] = None | |
| ) -> List[Document]: | |
| path = Path(local_path) | |
| if not path.exists(): | |
| raise FileNotFoundError(f"Dataset file not found: {local_path}") | |
| parsed_text_columns = _parse_columns(text_columns) | |
| ext = path.suffix.lower() | |
| documents: List[Document] = [] | |
| if ext == ".csv": | |
| with path.open("r", encoding="utf-8") as f: | |
| reader = csv.DictReader(f) | |
| for row in reader: | |
| doc = _row_to_document( | |
| row, source_name=str(path.name), text_columns=parsed_text_columns | |
| ) | |
| if doc: | |
| documents.append(doc) | |
| return documents | |
| if ext == ".json": | |
| with path.open("r", encoding="utf-8") as f: | |
| payload = json.load(f) | |
| if isinstance(payload, dict): | |
| payload = [payload] | |
| if not isinstance(payload, list): | |
| raise ValueError("JSON dataset must be an object or a list of objects") | |
| for row in payload: | |
| if isinstance(row, dict): | |
| doc = _row_to_document( | |
| row, source_name=str(path.name), text_columns=parsed_text_columns | |
| ) | |
| if doc: | |
| documents.append(doc) | |
| return documents | |
| if ext == ".jsonl": | |
| with path.open("r", encoding="utf-8") as f: | |
| for line in f: | |
| line = line.strip() | |
| if not line: | |
| continue | |
| row = json.loads(line) | |
| if isinstance(row, dict): | |
| doc = _row_to_document( | |
| row, | |
| source_name=str(path.name), | |
| text_columns=parsed_text_columns, | |
| ) | |
| if doc: | |
| documents.append(doc) | |
| return documents | |
| if ext in {".txt", ".md"}: | |
| text = path.read_text(encoding="utf-8") | |
| blocks = [block.strip() for block in text.split("\n\n") if block.strip()] | |
| for block in blocks: | |
| documents.append( | |
| Document(page_content=block, metadata={"source": str(path.name)}) | |
| ) | |
| return documents | |
| raise ValueError( | |
| "Unsupported dataset format. Use .csv, .json, .jsonl, .txt, or .md" | |
| ) | |
| def load_dataset_by_config( | |
| data_source: str, | |
| hf_dataset_name: Optional[str] = None, | |
| local_dataset_path: Optional[str] = None, | |
| text_columns: Optional[str] = None, | |
| ) -> List[Document]: | |
| source = (data_source or "hf").strip().lower() | |
| if source == "hf": | |
| if not hf_dataset_name: | |
| raise ValueError("HF_DATASET_NAME is required when DATA_SOURCE=hf") | |
| return load_hf_dataset(hf_dataset_name) | |
| if source == "local": | |
| if not local_dataset_path: | |
| raise ValueError("LOCAL_DATASET_PATH is required when DATA_SOURCE=local") | |
| return load_local_dataset(local_dataset_path, text_columns=text_columns) | |
| if source == "pdf": | |
| if not local_dataset_path: | |
| raise ValueError("LOCAL_DATASET_PATH is required when DATA_SOURCE=pdf") | |
| return load_pdf_file(local_dataset_path) | |
| raise ValueError("DATA_SOURCE must be one of: hf, local, pdf") | |
| def filter_to_minimal_docs(docs: List[Document]) -> List[Document]: | |
| """ | |
| Given a list of Document objects, return a new list of Document objects | |
| containing only 'source' in metadata and the original page_content. | |
| """ | |
| minimal_docs: List[Document] = [] | |
| for doc in docs: | |
| src = doc.metadata.get("source") | |
| minimal_docs.append( | |
| Document(page_content=doc.page_content, metadata={"source": src}) | |
| ) | |
| return minimal_docs | |
| # Split the Data into Text Chunks | |
| def text_split(extracted_data): | |
| text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=20) | |
| text_chunks = text_splitter.split_documents(extracted_data) | |
| return text_chunks | |
| # Download the Embeddings from HuggingFace | |
| def download_hugging_face_embeddings(): | |
| embeddings = HuggingFaceEmbeddings( | |
| model_name="sentence-transformers/all-MiniLM-L6-v2" | |
| ) # this model return 384 dimensions | |
| return embeddings | |