//! AI Backend Example: RAG System with Batch Operations //! //! Demonstrates: //! - Creating a RAG (Retrieval-Augmented Generation) system //! - Adding documents using batch operations (efficient) //! - Retrieving relevant documents for queries //! - Removing documents using batch operations //! - Performance comparison: batch vs sequential operations //! //! Run with: cargo run --example main --features ai_backend //! Or via just: just build::ai && cargo run --example main --features ai_backend #[cfg(feature = "ai_backend")] fn main() -> Result<(), Box> { use std::time::Instant; use typedialog_core::ai::rag::{RagConfig, RagSystem}; println!("\n╔════════════════════════════════════════════════════════╗"); println!("║ TypeDialog AI Backend - RAG System Example ║"); println!("║ Batch Operations Performance Demonstration ║"); println!("╚════════════════════════════════════════════════════════╝\n"); // Create RAG system with default configuration let mut rag = RagSystem::new(RagConfig::default())?; println!("✓ Created RAG system with default config"); println!(" - Semantic weight: 0.6"); println!(" - Keyword weight: 0.4"); println!(" - Max results: 5\n"); // === BATCH ADD DOCUMENTS === println!("╔════════════════════════════════════════════════════════╗"); println!("║ 1. BATCH ADD DOCUMENTS (Efficient) ║"); println!("╚════════════════════════════════════════════════════════╝\n"); let documents = vec![ ( "doc1".to_string(), "Rust is a systems programming language with memory safety guarantees." .to_string(), ), ( "doc2".to_string(), "TypeDialog is an interactive forms library for multiple backends." .to_string(), ), ( "doc3".to_string(), "RAG combines retrieval with generation for better LLM responses.".to_string(), ), ( "doc4".to_string(), "Knowledge graphs model relationships between entities in data." .to_string(), ), ( "doc5".to_string(), "Embeddings transform text into dense vector representations." .to_string(), ), ]; let start = Instant::now(); rag.add_documents_batch(documents)?; let batch_duration = start.elapsed(); println!("✓ Added 5 documents using batch operation"); println!(" Duration: {:.2}ms", batch_duration.as_secs_f64() * 1000.0); println!(" Document count: {}\n", rag.doc_count()); // === RETRIEVE DOCUMENTS === println!("╔════════════════════════════════════════════════════════╗"); println!("║ 2. RETRIEVE RELEVANT DOCUMENTS ║"); println!("╚════════════════════════════════════════════════════════╝\n"); let query = "programming language memory safety"; println!("Query: \"{}\"\n", query); let results = rag.retrieve(query)?; println!("Retrieved {} document(s):\n", results.len()); for (idx, result) in results.iter().enumerate() { println!( "{}. [{}] Score: {:.3} (Semantic: {:.3}, Keyword: {:.3})", idx + 1, result.doc_id, result.combined_score, result.semantic_score, result.keyword_score ); println!(" Content: {}\n", result.content); } // === BATCH REMOVE DOCUMENTS === println!("╔════════════════════════════════════════════════════════╗"); println!("║ 3. BATCH REMOVE DOCUMENTS (Efficient) ║"); println!("╚════════════════════════════════════════════════════════╝\n"); let to_remove = vec!["doc2", "doc4"]; println!("Removing: {:?}", to_remove); let removed = rag.remove_documents_batch(&to_remove); println!( "✓ Removed {} document(s)", removed ); println!(" Remaining documents: {}\n", rag.doc_count()); // === PERFORMANCE COMPARISON === println!("╔════════════════════════════════════════════════════════╗"); println!("║ 4. PERFORMANCE: BATCH vs SEQUENTIAL (20 docs) ║"); println!("╚════════════════════════════════════════════════════════╝\n"); let large_docs: Vec<_> = (0..20) .map(|i| { ( format!("perf_doc{}", i), format!("Performance test document number {}", i), ) }) .collect(); // Sequential let mut rag_seq = RagSystem::new(RagConfig::default())?; let start = Instant::now(); rag_seq.add_documents(large_docs.clone())?; let seq_duration = start.elapsed(); // Batch let mut rag_batch = RagSystem::new(RagConfig::default())?; let start = Instant::now(); rag_batch.add_documents_batch(large_docs)?; let batch_duration = start.elapsed(); let speedup = seq_duration.as_nanos() as f64 / batch_duration.as_nanos() as f64; println!("Sequential add (20 docs): {:.2}ms", seq_duration.as_secs_f64() * 1000.0); println!("Batch add (20 docs): {:.2}ms", batch_duration.as_secs_f64() * 1000.0); println!("Speedup: {:.2}x\n", speedup); println!("💡 Tip: Use batch operations for large document sets (100+)"); println!(" Batch avoids multiple HNSW index rebuilds!\n"); // === SUMMARY === println!("╔════════════════════════════════════════════════════════╗"); println!("║ SUMMARY ║"); println!("╚════════════════════════════════════════════════════════╝\n"); println!("RAG System Features:"); println!(" ✓ Semantic search (vector embeddings)"); println!(" ✓ Keyword search (full-text indexing)"); println!(" ✓ Hybrid retrieval (combines both)"); println!(" ✓ Batch operations (efficient bulk processing)"); println!(" ✓ Configurable weights and thresholds"); println!(" ✓ Persistence (save/load to disk)\n"); println!("Next Steps:"); println!(" • Build with Knowledge Graph integration"); println!(" • Use with different embedding models"); println!(" • Integrate with LLM backends"); println!(" • Add custom similarity metrics\n"); Ok(()) } #[cfg(not(feature = "ai_backend"))] fn main() { eprintln!("This example requires the 'ai_backend' feature."); eprintln!("Run with: cargo run --example main --features ai_backend"); std::process::exit(1); }