|
""" |
|
Core context management module for efficient-context library. |
|
""" |
|
|
|
from typing import List, Dict, Any, Optional, Union |
|
import logging |
|
from pydantic import BaseModel, Field |
|
|
|
from efficient_context.compression.base import BaseCompressor |
|
from efficient_context.chunking.base import BaseChunker |
|
from efficient_context.retrieval.base import BaseRetriever |
|
from efficient_context.memory.memory_manager import MemoryManager |
|
|
|
|
|
logging.basicConfig(level=logging.INFO) |
|
logger = logging.getLogger(__name__) |
|
|
|
class Document(BaseModel): |
|
"""A document to be processed by the context manager.""" |
|
id: str = Field(..., description="Unique identifier for the document") |
|
content: str = Field(..., description="Text content of the document") |
|
metadata: Dict[str, Any] = Field(default_factory=dict, description="Optional metadata for the document") |
|
|
|
class ContextManager: |
|
""" |
|
Main class for managing context efficiently for LLMs in CPU-constrained environments. |
|
|
|
This class orchestrates the compression, chunking, retrieval, and memory management |
|
components to optimize context handling for LLMs running on limited hardware. |
|
""" |
|
|
|
def __init__( |
|
self, |
|
compressor: Optional[BaseCompressor] = None, |
|
chunker: Optional[BaseChunker] = None, |
|
retriever: Optional[BaseRetriever] = None, |
|
memory_manager: Optional[MemoryManager] = None, |
|
max_context_size: int = 4096, |
|
): |
|
""" |
|
Initialize the context manager with configurable components. |
|
|
|
Args: |
|
compressor: Component for compressing context content |
|
chunker: Component for chunking content |
|
retriever: Component for retrieving relevant chunks |
|
memory_manager: Component for managing memory usage |
|
max_context_size: Maximum size of context in tokens |
|
""" |
|
from efficient_context.compression import SemanticDeduplicator |
|
from efficient_context.chunking import SemanticChunker |
|
from efficient_context.retrieval import CPUOptimizedRetriever |
|
from efficient_context.memory import MemoryManager |
|
|
|
self.compressor = compressor or SemanticDeduplicator() |
|
self.chunker = chunker or SemanticChunker() |
|
self.retriever = retriever or CPUOptimizedRetriever() |
|
self.memory_manager = memory_manager or MemoryManager() |
|
self.max_context_size = max_context_size |
|
|
|
self.documents = {} |
|
self.chunks = [] |
|
|
|
logger.info("Context Manager initialized with max context size: %d", max_context_size) |
|
|
|
def add_document(self, document: Union[Document, Dict, str], document_id: Optional[str] = None) -> str: |
|
""" |
|
Add a document to the context manager. |
|
|
|
Args: |
|
document: Document to add (can be a Document object, dict, or string content) |
|
document_id: Optional ID for the document (generated if not provided) |
|
|
|
Returns: |
|
document_id: ID of the added document |
|
""" |
|
|
|
if isinstance(document, str): |
|
if document_id is None: |
|
import uuid |
|
document_id = str(uuid.uuid4()) |
|
doc = Document(id=document_id, content=document) |
|
elif isinstance(document, dict): |
|
if 'id' in document: |
|
document_id = document['id'] |
|
elif document_id is None: |
|
import uuid |
|
document_id = str(uuid.uuid4()) |
|
|
|
doc = Document( |
|
id=document_id, |
|
content=document.get('content', ''), |
|
metadata=document.get('metadata', {}) |
|
) |
|
else: |
|
doc = document |
|
document_id = doc.id |
|
|
|
|
|
self.documents[document_id] = doc |
|
|
|
|
|
with self.memory_manager.optimize_memory(): |
|
|
|
compressed_content = self.compressor.compress(doc.content) |
|
|
|
|
|
doc_chunks = self.chunker.chunk(compressed_content, metadata=doc.metadata, document_id=doc.id) |
|
|
|
|
|
self.retriever.index_chunks(doc_chunks) |
|
|
|
|
|
self.chunks.extend(doc_chunks) |
|
|
|
logger.info("Added document with ID %s (%d chunks)", document_id, len(doc_chunks)) |
|
return document_id |
|
|
|
def add_documents(self, documents: List[Union[Document, Dict, str]]) -> List[str]: |
|
""" |
|
Add multiple documents to the context manager. |
|
|
|
Args: |
|
documents: List of documents to add |
|
|
|
Returns: |
|
document_ids: List of IDs of added documents |
|
""" |
|
document_ids = [] |
|
for doc in documents: |
|
doc_id = self.add_document(doc) |
|
document_ids.append(doc_id) |
|
|
|
return document_ids |
|
|
|
def generate_context(self, query: str, max_size: Optional[int] = None) -> str: |
|
""" |
|
Generate optimized context for a given query. |
|
|
|
Args: |
|
query: The query for which to generate context |
|
max_size: Maximum size of the context (defaults to self.max_context_size) |
|
|
|
Returns: |
|
context: Optimized context for the query |
|
""" |
|
max_size = max_size or self.max_context_size |
|
|
|
with self.memory_manager.optimize_memory(): |
|
|
|
relevant_chunks = self.retriever.retrieve(query, top_k=max_size) |
|
|
|
|
|
context_parts = [chunk.content for chunk in relevant_chunks] |
|
|
|
|
|
combined_context = "\n\n".join(context_parts) |
|
if len(combined_context.split()) > max_size: |
|
combined_context = self.compressor.compress(combined_context, target_size=max_size) |
|
|
|
logger.info("Generated context of size ~%d tokens for query", len(combined_context.split())) |
|
return combined_context |
|
|
|
def clear(self): |
|
"""Clear all documents and chunks from the context manager.""" |
|
self.documents = {} |
|
self.chunks = [] |
|
self.retriever.clear() |
|
logger.info("Context manager cleared") |
|
|