Compliance_Auditor / database_manager.py
Kushal Shah
Initial commit: AI Legal Compliance Auditor
bd510a2
Raw
History Blame Contribute Delete
7.16 kB
"""
Database management module for production deployment.
Handles initialization, indexing, and maintenance of the vector database.
"""
import os
from typing import List, Optional, Dict, Any
from pathlib import Path
from vector_db import get_vector_database
from document_processor import get_document_processor
from doc_utils import extract_text_from_path, is_supported_file_type
class DatabaseManager:
"""
Manages the vector database: initialization, indexing, updates.
"""
def __init__(self, reference_dir: str = "./reference_docs"):
"""
Initialize database manager.
Args:
reference_dir: Directory containing reference documents
"""
self.reference_dir = reference_dir
self.vector_db = get_vector_database()
self.doc_processor = get_document_processor()
def index_reference_documents(
self,
force_reindex: bool = False,
file_paths: Optional[List[str]] = None
) -> Dict[str, Any]:
"""
Index all reference documents into the vector database.
Args:
force_reindex: If True, clear existing data and reindex
file_paths: Optional list of specific files to index
Returns:
Dictionary with indexing results
"""
results = {
"indexed": 0,
"failed": 0,
"errors": []
}
# Clear if force reindex
if force_reindex:
print("Clearing existing database...")
self.vector_db.clear_collection()
# Get files to index
if file_paths:
files_to_index = file_paths
else:
files_to_index = self._get_reference_files()
if not files_to_index:
print("WARNING: No files found to index.")
return results
print(f"Indexing {len(files_to_index)} documents...")
# Process each file
all_documents = []
for file_path in files_to_index:
try:
# Check file type
is_valid, _ = is_supported_file_type(file_path)
if not is_valid:
results["failed"] += 1
results["errors"].append(f"Unsupported file type: {file_path}")
continue
# Get label
label = os.path.basename(file_path)
# Process file
documents = self.doc_processor.process_file(file_path, source_label=label)
if documents:
all_documents.extend(documents)
results["indexed"] += 1
print(f" OK: Indexed: {label} ({len(documents)} chunks)")
else:
results["failed"] += 1
results["errors"].append(f"No content extracted: {file_path}")
except Exception as e:
results["failed"] += 1
results["errors"].append(f"Error processing {file_path}: {str(e)}")
print(f" FAILED: {os.path.basename(file_path)} - {e}")
# Add all documents to vector database
if all_documents:
print(f"\nAdding {len(all_documents)} document chunks to vector database...")
try:
self.vector_db.add_documents(all_documents)
print(f"SUCCESS: Successfully indexed {results['indexed']} documents with {len(all_documents)} chunks")
except Exception as e:
results["errors"].append(f"Failed to add documents to database: {str(e)}")
print(f"ERROR: Error adding documents: {e}")
return results
def index_text(
self,
text: str,
source_label: str,
metadata: Optional[Dict[str, Any]] = None
) -> bool:
"""
Index a text document.
Args:
text: Text content
source_label: Label for the source
metadata: Optional metadata
Returns:
True if successful
"""
try:
documents = self.doc_processor.process_text(text, source_label, metadata)
if documents:
self.vector_db.add_documents(documents)
return True
return False
except Exception as e:
print(f"❌ Error indexing text: {e}")
return False
def _get_reference_files(self) -> List[str]:
"""
Get all reference files from the reference directory.
Returns:
List of file paths
"""
files = []
if not os.path.isdir(self.reference_dir):
return files
for name in os.listdir(self.reference_dir):
full_path = os.path.join(self.reference_dir, name)
if os.path.isfile(full_path):
is_valid, _ = is_supported_file_type(full_path)
if is_valid:
files.append(full_path)
return files
def get_database_stats(self) -> Dict[str, Any]:
"""
Get statistics about the database.
Returns:
Dictionary with statistics
"""
stats = self.vector_db.get_collection_info()
stats["reference_directory"] = self.reference_dir
stats["reference_files"] = len(self._get_reference_files())
return stats
def check_database_health(self) -> Dict[str, Any]:
"""
Check database health and readiness.
Returns:
Dictionary with health status
"""
health = {
"status": "healthy",
"database_exists": False,
"document_count": 0,
"reference_files": 0,
"warnings": []
}
try:
# Check database
stats = self.get_database_stats()
health["database_exists"] = True
health["document_count"] = stats.get("document_count", 0)
health["reference_files"] = stats.get("reference_files", 0)
# Check if database is empty
if health["document_count"] == 0:
health["status"] = "empty"
health["warnings"].append("Database is empty. Run indexing first.")
# Check if reference files exist
if health["reference_files"] == 0:
health["warnings"].append("No reference files found in reference_docs folder.")
except Exception as e:
health["status"] = "error"
health["warnings"].append(f"Database error: {str(e)}")
return health
# Global instance
_db_manager: Optional[DatabaseManager] = None
def get_database_manager() -> DatabaseManager:
"""Get or create global database manager instance."""
global _db_manager
if _db_manager is None:
_db_manager = DatabaseManager()
return _db_manager