| |
| """ |
| LanceDB Initialization Script for ATOM Platform |
| |
| This script initializes the LanceDB database with sample data to enable |
| search functionality in the ATOM platform. |
| |
| Usage: |
| python initialize_lancedb.py |
| """ |
|
|
| from datetime import datetime, timezone |
| import json |
| import logging |
| import os |
| import sys |
| from typing import Any, Dict, List |
| import uuid |
|
|
| |
| logging.basicConfig( |
| level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" |
| ) |
| logger = logging.getLogger(__name__) |
|
|
|
|
| def initialize_lancedb(): |
| """Initialize LanceDB with sample data for search functionality""" |
|
|
| try: |
| |
| import lancedb |
| import numpy as np |
| import pandas as pd |
| import pyarrow as pa |
| except ImportError as e: |
| logger.error(f"LanceDB dependencies not available: {e}") |
| logger.info( |
| "Please install required packages: pip install lancedb pyarrow pandas numpy" |
| ) |
| return False |
|
|
| |
| db_path = os.environ.get("LANCEDB_URI", "/tmp/atom_lancedb") |
| logger.info(f"Initializing LanceDB at: {db_path}") |
|
|
| try: |
| |
| db = lancedb.connect(db_path) |
| logger.info("Connected to LanceDB") |
|
|
| |
| chunk_schema = pa.schema( |
| [ |
| pa.field("chunk_id", pa.string()), |
| pa.field("doc_id", pa.string()), |
| pa.field("user_id", pa.string()), |
| pa.field("chunk_index", pa.int32()), |
| pa.field("chunk_text", pa.string()), |
| pa.field("metadata", pa.string()), |
| pa.field( |
| "vector_embedding", pa.list_(pa.float32(), 1536) |
| ), |
| pa.field("created_at", pa.string()), |
| ] |
| ) |
|
|
| |
| table_name = "document_chunks" |
| if table_name in db.table_names(): |
| logger.info(f"Table {table_name} already exists, opening...") |
| table = db.open_table(table_name) |
| else: |
| logger.info(f"Creating new table: {table_name}") |
| table = db.create_table(table_name, schema=chunk_schema) |
|
|
| |
| sample_documents = [ |
| { |
| "title": "Project Planning Meeting", |
| "content": "Discussed project timelines, resource allocation, and milestones for Q4 2024. Team agreed on aggressive but achievable deadlines.", |
| "tags": ["meeting", "planning", "project"], |
| }, |
| { |
| "title": "Technical Architecture Review", |
| "content": "Reviewed the microservices architecture and API design patterns. Decided to use GraphQL for frontend communication.", |
| "tags": ["technical", "architecture", "api"], |
| }, |
| { |
| "title": "Customer Feedback Analysis", |
| "content": "Analyzed customer feedback from Q3. Key themes: improved UI/UX, faster response times, better documentation.", |
| "tags": ["customer", "feedback", "analysis"], |
| }, |
| { |
| "title": "Security Audit Report", |
| "content": "Completed security audit with penetration testing. Identified vulnerabilities in authentication system.", |
| "tags": ["security", "audit", "vulnerabilities"], |
| }, |
| { |
| "title": "Team Standup Notes", |
| "content": "Daily standup: backend team working on authentication, frontend team implementing search UI, QA team testing workflows.", |
| "tags": ["standup", "team", "progress"], |
| }, |
| ] |
|
|
| |
| logger.info("Generating embeddings for sample data...") |
|
|
| try: |
| from note_utils import get_text_embedding_openai |
|
|
| embedding_function_available = True |
| except ImportError: |
| logger.warning("note_utils not available, using mock embeddings") |
| embedding_function_available = False |
|
|
| |
| data_to_insert = [] |
| user_id = "default_user" |
|
|
| for doc_idx, doc in enumerate(sample_documents): |
| doc_id = str(uuid.uuid4()) |
|
|
| |
| chunks = [ |
| { |
| "text": doc["content"], |
| "metadata": { |
| "title": doc["title"], |
| "tags": doc["tags"], |
| "source": "sample_data", |
| }, |
| } |
| ] |
|
|
| for chunk_idx, chunk in enumerate(chunks): |
| |
| if embedding_function_available: |
| embedding_result = get_text_embedding_openai(chunk["text"]) |
| if embedding_result["status"] == "success": |
| embedding = embedding_result["data"] |
| else: |
| logger.warning( |
| f"Failed to generate embedding: {embedding_result.get('message')}" |
| ) |
| |
| embedding = [0.01] * 1536 |
| else: |
| |
| embedding = [0.01] * 1536 |
|
|
| |
| chunk_record = { |
| "chunk_id": str(uuid.uuid4()), |
| "doc_id": doc_id, |
| "user_id": user_id, |
| "chunk_index": chunk_idx, |
| "chunk_text": chunk["text"], |
| "metadata": json.dumps(chunk["metadata"]), |
| "vector_embedding": embedding, |
| "created_at": datetime.now(timezone.utc).isoformat(), |
| } |
| data_to_insert.append(chunk_record) |
|
|
| |
| if data_to_insert: |
| logger.info(f"Inserting {len(data_to_insert)} document chunks...") |
| table.add(data_to_insert) |
| logger.info("Sample data inserted successfully!") |
| else: |
| logger.warning("No data to insert") |
|
|
| |
| count = table.count_rows() |
| logger.info(f"Table now contains {count} rows") |
|
|
| |
| logger.info("Testing search functionality...") |
|
|
| |
| test_query = "project planning" |
| if embedding_function_available: |
| embedding_result = get_text_embedding_openai(test_query) |
| if embedding_result["status"] == "success": |
| query_embedding = embedding_result["data"] |
|
|
| |
| results = table.search(query_embedding).limit(3).to_list() |
| logger.info(f"Search test returned {len(results)} results") |
|
|
| |
| for i, result in enumerate(results): |
| logger.info( |
| f"Result {i + 1}: {result.get('chunk_text', '')[:100]}..." |
| ) |
| else: |
| logger.warning("Could not test search - embedding generation failed") |
| else: |
| logger.info("Search test skipped - mock embeddings in use") |
|
|
| logger.info("LanceDB initialization completed successfully!") |
| return True |
|
|
| except Exception as e: |
| logger.error(f"Failed to initialize LanceDB: {e}") |
| return False |
|
|
|
|
| def create_meeting_transcripts_table(): |
| """Create meeting_transcripts_embeddings table if needed""" |
|
|
| try: |
| import lancedb |
| import pyarrow as pa |
|
|
| db_path = os.environ.get("LANCEDB_URI", "/tmp/atom_lancedb") |
| db = lancedb.connect(db_path) |
|
|
| table_name = "meeting_transcripts_embeddings" |
| if table_name not in db.table_names(): |
| logger.info(f"Creating table: {table_name}") |
|
|
| |
| schema = pa.schema( |
| [ |
| pa.field("transcript_id", pa.string()), |
| pa.field("user_id", pa.string()), |
| pa.field("meeting_title", pa.string()), |
| pa.field("content", pa.string()), |
| pa.field("timestamp", pa.string()), |
| pa.field("vector_embedding", pa.list_(pa.float32(), 1536)), |
| pa.field("metadata", pa.string()), |
| ] |
| ) |
|
|
| db.create_table(table_name, schema=schema) |
| logger.info(f"Table {table_name} created successfully") |
| else: |
| logger.info(f"Table {table_name} already exists") |
|
|
| return True |
|
|
| except Exception as e: |
| logger.error(f"Failed to create meeting transcripts table: {e}") |
| return False |
|
|
|
|
| def main(): |
| """Main execution function""" |
| logger.info("Starting LanceDB initialization...") |
|
|
| |
| if not initialize_lancedb(): |
| logger.error("LanceDB initialization failed") |
| sys.exit(1) |
|
|
| |
| create_meeting_transcripts_table() |
|
|
| logger.info("LanceDB setup completed!") |
| logger.info( |
| "You can now test search functionality at: http://localhost:5058/semantic_search_meetings" |
| ) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|