rag 0.1.1

A Rust library and CLI for Retrieval-Augmented Generation
Documentation
use rag::{Document, InMemoryVectorStore, MetadataFilter, VectorStore};
use tokio;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Vector Store with Metadata Filtering ===\n");

    let vector_store = InMemoryVectorStore::new();

    let doc1 = Document::new("Rust is a systems programming language".to_string())
        .with_metadata("category".to_string(), "programming".to_string())
        .with_metadata("language".to_string(), "Rust".to_string())
        .with_embedding(vec![1.0, 0.0, 0.0]);

    let doc2 = Document::new("Python is a high-level programming language".to_string())
        .with_metadata("category".to_string(), "programming".to_string())
        .with_metadata("language".to_string(), "Python".to_string())
        .with_embedding(vec![0.0, 1.0, 0.0]);

    let doc3 = Document::new("Machine learning is a subset of AI".to_string())
        .with_metadata("category".to_string(), "AI".to_string())
        .with_metadata("language".to_string(), "English".to_string())
        .with_embedding(vec![0.0, 0.0, 1.0]);

    let doc4 = Document::new("Deep learning uses neural networks".to_string())
        .with_metadata("category".to_string(), "AI".to_string())
        .with_metadata("language".to_string(), "English".to_string())
        .with_embedding(vec![0.5, 0.5, 0.5]);

    vector_store.add(doc1).await?;
    vector_store.add(doc2).await?;
    vector_store.add(doc3).await?;
    vector_store.add(doc4).await?;

    println!("Added 4 documents to the vector store\n");

    let count = vector_store.count().await?;
    println!("Total documents: {}\n", count);

    println!("=== All Documents ===");
    let all_docs = vector_store.list(10, 0).await?;
    for (i, doc) in all_docs.iter().enumerate() {
        println!("{}. {} ({})", i + 1, doc.content, doc.metadata.get("category").unwrap_or(&"?".to_string()));
    }
    println!();

    let query = vec![0.2, 0.2, 0.8];

    println!("=== Search without filter ===");
    let results = vector_store.search(&query, 3).await?;
    for (i, result) in results.iter().enumerate() {
        println!("{}. {:.3} - {}", i + 1, result.score, result.document.content);
    }
    println!();

    println!("=== Search with category filter (AI) ===");
    let filter = MetadataFilter::new().add("category".to_string(), "AI".to_string());
    let results = vector_store.search_with_filter(&query, 3, &filter).await?;
    for (i, result) in results.iter().enumerate() {
        println!("{}. {:.3} - {}", i + 1, result.score, result.document.content);
    }
    println!();

    println!("=== Search with language filter (Python) ===");
    let filter = MetadataFilter::new().add("language".to_string(), "Python".to_string());
    let results = vector_store.search_with_filter(&query, 3, &filter).await?;
    for (i, result) in results.iter().enumerate() {
        println!("{}. {:.3} - {}", i + 1, result.score, result.document.content);
    }
    println!();

    println!("=== Batch operations ===");
    let batch_docs = vec![
        Document::new("Rust's ownership system ensures memory safety".to_string())
            .with_metadata("category".to_string(), "programming".to_string())
            .with_metadata("language".to_string(), "Rust".to_string())
            .with_embedding(vec![0.8, 0.1, 0.1]),
        Document::new("Python's dynamic typing makes it easy to learn".to_string())
            .with_metadata("category".to_string(), "programming".to_string())
            .with_metadata("language".to_string(), "Python".to_string())
            .with_embedding(vec![0.1, 0.8, 0.1]),
    ];

    vector_store.add_batch(batch_docs).await?;
    let count = vector_store.count().await?;
    println!("After batch add, total documents: {}\n", count);

    println!("=== Persistence (Save to file) ===");
    vector_store.save_to_file("vector_store_backup.json").await?;
    println!("Saved vector store to vector_store_backup.json\n");

    println!("=== Load from file ===");
    let loaded_store = InMemoryVectorStore::load_from_file("vector_store_backup.json").await?;
    let loaded_count = loaded_store.count().await?;
    println!("Loaded {} documents from file\n", loaded_count);

    println!("=== Delete document ===");
    let all_docs = vector_store.list(10, 0).await?;
    if let Some(first_doc) = all_docs.first() {
        let deleted = vector_store.delete(&first_doc.id).await?;
        println!("Deleted document with ID: {} - {}", deleted, first_doc.id);
        let count = vector_store.count().await?;
        println!("Remaining documents: {}\n", count);
    }

    println!("=== Batch delete ===");
    let all_docs = vector_store.list(10, 0).await?;
    let ids_to_delete: Vec<String> = all_docs.iter().take(2).map(|d| d.id.clone()).collect();
    let deleted_count = vector_store.delete_batch(ids_to_delete).await?;
    println!("Deleted {} documents", deleted_count);
    let count = vector_store.count().await?;
    println!("Remaining documents: {}\n", count);

    println!("=== Clear all ===");
    vector_store.clear().await?;
    let count = vector_store.count().await?;
    println!("After clear, total documents: {}\n", count);

    std::fs::remove_file("vector_store_backup.json")?;

    println!("Demo completed successfully!");
    Ok(())
}