Spaces:
Running
Running
| """RAG Chatbot for pythermalcomfort Documentation. | |
| This package provides a Retrieval-Augmented Generation (RAG) chatbot | |
| for the pythermalcomfort library documentation. The chatbot can answer | |
| questions about thermal comfort standards, calculations, and the | |
| pythermalcomfort Python library. | |
| Architecture: | |
| The package is organized into the following submodules: | |
| - config/ : Configuration management using Pydantic settings | |
| - extraction/ : PDF to Markdown conversion pipeline | |
| - chunking/ : Structure-aware text chunking with heading inheritance | |
| - embeddings/ : BGE encoder and embedding storage | |
| - retrieval/ : Hybrid retrieval (FAISS + BM25 with RRF fusion) | |
| - llm/ : Multi-provider LLM integration (Gemini, Groq, DeepSeek) | |
| - api/ : FastAPI endpoints with SSE streaming | |
| - qlog/ : Async query logging to HuggingFace dataset | |
| Lazy Loading: | |
| Heavy dependencies (torch, faiss, sentence-transformers) are loaded | |
| lazily on first access using the __getattr__ pattern. This ensures | |
| fast import times and minimal memory usage until features are needed. | |
| Exports: | |
| config: | |
| - Settings: Main configuration class with all application settings | |
| extraction: | |
| - ExtractedPage: Represents a single extracted PDF page | |
| - ExtractedDocument: Represents a fully extracted PDF document | |
| - Extractor: Protocol for synchronous PDF extractors | |
| - AsyncExtractor: Protocol for asynchronous PDF extractors | |
| - PDFExtractor: Main class for PDF document processing | |
| - MarkdownConverter: Converts extracted content to Markdown format | |
| chunking: | |
| - Chunker: Main class for document chunking | |
| - Chunk: Data class representing a single chunk | |
| - ChunkingStrategy: Base class for chunking strategies | |
| embeddings: | |
| - BGEEncoder: Generates embeddings using BGE models | |
| - EmbeddingStorage: Manages embedding persistence and loading | |
| retrieval: | |
| - FAISSIndex: Dense vector similarity search | |
| - BM25Retriever: Sparse keyword-based retrieval | |
| - HybridRetriever: Combines dense and sparse methods | |
| - RetrievalResult: Data class for retrieval results | |
| llm: | |
| - BaseLLM: Abstract base class for LLM providers | |
| - GeminiLLM: Gemini provider implementation | |
| - GroqLLM: Groq provider implementation | |
| - DeepSeekLLM: DeepSeek provider implementation | |
| - QuotaManager: Tracks provider usage and limits | |
| - ProviderStatus: Enum for provider status states | |
| api: | |
| - create_app: Factory function for FastAPI application | |
| qlog: | |
| - QueryLog: Pydantic model for log entries | |
| - HFDatasetWriter: Async writer for HuggingFace datasets | |
| Example: | |
| ------- | |
| >>> import rag_chatbot | |
| >>> # Package imports quickly without loading heavy dependencies | |
| >>> rag_chatbot.__version__ | |
| '0.1.0' | |
| >>> # Access exports lazily | |
| >>> from rag_chatbot import Settings, PDFExtractor, Chunker | |
| >>> settings = Settings() | |
| """ | |
| from __future__ import annotations | |
| from typing import TYPE_CHECKING | |
| # ============================================================================= | |
| # Type Checking Imports | |
| # ============================================================================= | |
| # These imports are only processed by type checkers (mypy, pyright) and IDEs. | |
| # They enable proper type hints and autocompletion without runtime overhead. | |
| # ============================================================================= | |
| if TYPE_CHECKING: | |
| from rag_chatbot.api import create_app | |
| from rag_chatbot.chunking import Chunker, ChunkingStrategy | |
| from rag_chatbot.chunking.models import Chunk | |
| from rag_chatbot.config import Settings | |
| from rag_chatbot.embeddings import BGEEncoder, EmbeddingStorage | |
| from rag_chatbot.extraction import ( | |
| AsyncExtractor, | |
| ExtractedDocument, | |
| ExtractedPage, | |
| Extractor, | |
| MarkdownConverter, | |
| PDFExtractor, | |
| ) | |
| from rag_chatbot.llm import ( | |
| BaseLLM, | |
| DeepSeekLLM, | |
| GeminiLLM, | |
| GroqLLM, | |
| QuotaManager, | |
| ) | |
| from rag_chatbot.llm.quota import ProviderStatus | |
| from rag_chatbot.qlog import HFDatasetWriter, QueryLog | |
| from rag_chatbot.retrieval import BM25Retriever, FAISSIndex, HybridRetriever | |
| from rag_chatbot.retrieval.models import RetrievalResult | |
| # ============================================================================= | |
| # Package Metadata | |
| # ============================================================================= | |
| # These are standard package metadata fields that tools and IDEs can use | |
| # to get information about the package. | |
| # ============================================================================= | |
| # Package version - follows semantic versioning (MAJOR.MINOR.PATCH) | |
| # This should be kept in sync with pyproject.toml version | |
| __version__: str = "0.1.0" | |
| # Author information | |
| __author__: str = "sadickam" | |
| # ============================================================================= | |
| # Public API | |
| # ============================================================================= | |
| # The __all__ list defines what is exported when using `from rag_chatbot import *` | |
| # All exports are lazy-loaded on first access for fast import times. | |
| # ============================================================================= | |
| __all__: list[str] = [ | |
| # Metadata | |
| "__version__", | |
| "__author__", | |
| # config | |
| "Settings", | |
| # extraction - data models | |
| "ExtractedPage", | |
| "ExtractedDocument", | |
| # extraction - protocols | |
| "Extractor", | |
| "AsyncExtractor", | |
| # extraction - implementations | |
| "PDFExtractor", | |
| "MarkdownConverter", | |
| # chunking | |
| "Chunker", | |
| "Chunk", | |
| "ChunkingStrategy", | |
| # embeddings | |
| "BGEEncoder", | |
| "EmbeddingStorage", | |
| # retrieval | |
| "FAISSIndex", | |
| "BM25Retriever", | |
| "HybridRetriever", | |
| "RetrievalResult", | |
| # llm | |
| "BaseLLM", | |
| "GeminiLLM", | |
| "GroqLLM", | |
| "DeepSeekLLM", | |
| "QuotaManager", | |
| "ProviderStatus", | |
| # api | |
| "create_app", | |
| # qlog | |
| "QueryLog", | |
| "HFDatasetWriter", | |
| ] | |
| # ============================================================================= | |
| # Lazy Loading Registry | |
| # ============================================================================= | |
| # Maps export names to their (module_path, attribute_name) for lazy loading. | |
| # This approach avoids excessive branches/returns in __getattr__. | |
| # ============================================================================= | |
| _LAZY_IMPORTS: dict[str, tuple[str, str]] = { | |
| # config | |
| "Settings": ("rag_chatbot.config", "Settings"), | |
| # extraction - data models | |
| "ExtractedPage": ("rag_chatbot.extraction", "ExtractedPage"), | |
| "ExtractedDocument": ("rag_chatbot.extraction", "ExtractedDocument"), | |
| # extraction - protocols | |
| "Extractor": ("rag_chatbot.extraction", "Extractor"), | |
| "AsyncExtractor": ("rag_chatbot.extraction", "AsyncExtractor"), | |
| # extraction - implementations | |
| "PDFExtractor": ("rag_chatbot.extraction", "PDFExtractor"), | |
| "MarkdownConverter": ("rag_chatbot.extraction", "MarkdownConverter"), | |
| # chunking | |
| "Chunker": ("rag_chatbot.chunking", "Chunker"), | |
| "Chunk": ("rag_chatbot.chunking.models", "Chunk"), | |
| "ChunkingStrategy": ("rag_chatbot.chunking", "ChunkingStrategy"), | |
| # embeddings | |
| "BGEEncoder": ("rag_chatbot.embeddings", "BGEEncoder"), | |
| "EmbeddingStorage": ("rag_chatbot.embeddings", "EmbeddingStorage"), | |
| # retrieval | |
| "FAISSIndex": ("rag_chatbot.retrieval", "FAISSIndex"), | |
| "BM25Retriever": ("rag_chatbot.retrieval", "BM25Retriever"), | |
| "HybridRetriever": ("rag_chatbot.retrieval", "HybridRetriever"), | |
| "RetrievalResult": ("rag_chatbot.retrieval.models", "RetrievalResult"), | |
| # llm | |
| "BaseLLM": ("rag_chatbot.llm", "BaseLLM"), | |
| "GeminiLLM": ("rag_chatbot.llm", "GeminiLLM"), | |
| "GroqLLM": ("rag_chatbot.llm", "GroqLLM"), | |
| "DeepSeekLLM": ("rag_chatbot.llm", "DeepSeekLLM"), | |
| "QuotaManager": ("rag_chatbot.llm", "QuotaManager"), | |
| "ProviderStatus": ("rag_chatbot.llm.quota", "ProviderStatus"), | |
| # api | |
| "create_app": ("rag_chatbot.api", "create_app"), | |
| # qlog | |
| "QueryLog": ("rag_chatbot.qlog", "QueryLog"), | |
| "HFDatasetWriter": ("rag_chatbot.qlog", "HFDatasetWriter"), | |
| } | |
| def __getattr__(name: str) -> object: | |
| """Lazy load module exports on first access. | |
| This function is called when an attribute is not found in the module's | |
| namespace. It enables lazy loading of heavy dependencies like torch, | |
| faiss, and sentence-transformers, ensuring fast import times. | |
| Args: | |
| ---- | |
| name: The name of the attribute being accessed. | |
| Returns: | |
| ------- | |
| The requested attribute if it exists in __all__. | |
| Raises: | |
| ------ | |
| AttributeError: If the attribute is not a valid export. | |
| """ | |
| if name in _LAZY_IMPORTS: | |
| module_path, attr_name = _LAZY_IMPORTS[name] | |
| import importlib | |
| module = importlib.import_module(module_path) | |
| return getattr(module, attr_name) | |
| msg = f"module {__name__!r} has no attribute {name!r}" | |
| raise AttributeError(msg) | |