url-preview 0.6.0

High-performance URL preview generator for messaging and social media applications
Documentation
//! Mock implementation showing how claude-code-sdk integration would work
//!
//! This example uses a mock implementation to demonstrate the integration pattern
//! until the claude-code-sdk compilation issue is resolved.
//!
//! Run with: cargo run --example test_claude_code_mock --features llm

use url_preview::{
    LLMExtractor, LLMExtractorConfig, LLMProvider, 
    PreviewError, ContentFormat, Fetcher,
};
use serde::{Deserialize, Serialize};
use schemars::JsonSchema;
use async_trait::async_trait;
use serde_json::Value;
use std::sync::Arc;

// Mock implementation of ClaudeCodeProvider
// This shows how the real implementation would work
struct MockClaudeCodeProvider {
    system_prompt: String,
    model: String,
}

impl MockClaudeCodeProvider {
    fn new() -> Self {
        Self {
            system_prompt: "You are an expert at extracting structured data from web content.".to_string(),
            model: "claude-3-opus-20240229".to_string(),
        }
    }
    
    fn with_sonnet(mut self) -> Self {
        self.model = "claude-3-sonnet-20240229".to_string();
        self
    }
}

#[async_trait]
impl LLMProvider for MockClaudeCodeProvider {
    fn name(&self) -> &str {
        "claude-code-mock"
    }
    
    async fn generate(
        &self,
        _prompt: String,
        schema: Value,
        _config: &LLMExtractorConfig,
    ) -> Result<Value, PreviewError> {
        // Mock response based on schema
        if let Some(properties) = schema.get("properties") {
            let mut result = serde_json::Map::new();
            
            if let Some(props) = properties.as_object() {
                for (key, _) in props {
                    match key.as_str() {
                        "title" => result.insert(key.clone(), Value::String("Rust Programming Language".to_string())),
                        "description" => result.insert(key.clone(), Value::String("A language empowering everyone to build reliable and efficient software.".to_string())),
                        "topics" => result.insert(key.clone(), Value::Array(vec![
                            Value::String("systems programming".to_string()),
                            Value::String("memory safety".to_string()),
                            Value::String("concurrency".to_string()),
                        ])),
                        "key_features" => result.insert(key.clone(), Value::Array(vec![
                            Value::String("Zero-cost abstractions".to_string()),
                            Value::String("Memory safety without garbage collection".to_string()),
                            Value::String("Concurrency without data races".to_string()),
                        ])),
                        _ => result.insert(key.clone(), Value::String(format!("Mock value for {}", key))),
                    };
                }
            }
            
            Ok(Value::Object(result))
        } else {
            Ok(Value::Object(serde_json::Map::new()))
        }
    }
}

// Define data structures
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
struct WebPageAnalysis {
    title: String,
    description: String,
    topics: Vec<String>,
    key_features: Vec<String>,
}

#[derive(Debug, Serialize, Deserialize, JsonSchema)]
struct ProductComparison {
    product_name: String,
    competitors: Vec<String>,
    unique_features: Vec<String>,
    market_position: String,
}

async fn demonstrate_basic_usage() -> Result<(), PreviewError> {
    println!("\n📝 Basic Usage Example");
    println!("{}", "=".repeat(50));
    
    // Create provider
    let provider = Arc::new(MockClaudeCodeProvider::new());
    
    // Create fetcher
    let fetcher = Fetcher::new();
    
    // Create extractor
    let extractor = LLMExtractor::new(provider);
    
    // Extract data
    let url = "https://www.rust-lang.org/";
    let result = extractor.extract::<WebPageAnalysis>(url, &fetcher).await?;
    
    println!("URL: {}", url);
    println!("\nExtracted Data:");
    println!("Title: {}", result.data.title);
    println!("Description: {}", result.data.description);
    println!("\nTopics:");
    for topic in &result.data.topics {
        println!("{}", topic);
    }
    println!("\nKey Features:");
    for feature in &result.data.key_features {
        println!("{}", feature);
    }
    
    Ok(())
}

async fn demonstrate_custom_config() -> Result<(), PreviewError> {
    println!("\n\n⚙️ Custom Configuration Example");
    println!("{}", "=".repeat(50));
    
    // Create provider with custom settings
    let provider = Arc::new(MockClaudeCodeProvider::new().with_sonnet());
    
    // Create custom config
    let config = LLMExtractorConfig {
        format: ContentFormat::Markdown,
        clean_html: true,
        max_content_length: 5000,
        model_params: Default::default(),
    };
    
    // Create fetcher
    let fetcher = Fetcher::new();
    
    // Create extractor with custom config
    let extractor = LLMExtractor::with_config(provider, config);
    
    // Extract data
    let url = "https://crates.io/";
    let result = extractor.extract::<ProductComparison>(url, &fetcher).await?;
    
    println!("URL: {}", url);
    println!("\nProduct Analysis:");
    println!("Product: {}", result.data.product_name);
    println!("Market Position: {}", result.data.market_position);
    
    Ok(())
}

async fn demonstrate_concurrent_extraction() -> Result<(), PreviewError> {
    println!("\n\n🚀 Concurrent Extraction Example");
    println!("{}", "=".repeat(50));
    
    let provider = Arc::new(MockClaudeCodeProvider::new());
    let fetcher = Arc::new(Fetcher::new());
    let extractor = Arc::new(LLMExtractor::new(provider));
    
    let urls = vec![
        "https://www.rust-lang.org/",
        "https://doc.rust-lang.org/",
        "https://crates.io/",
    ];
    
    let mut handles = vec![];
    
    for url in urls {
        let extractor = Arc::clone(&extractor);
        let fetcher = Arc::clone(&fetcher);
        let url_string = url.to_string();
        let url_clone = url_string.clone();
        
        let handle = tokio::spawn(async move {
            extractor.extract::<WebPageAnalysis>(&url_string, &*fetcher).await
        });
        
        handles.push((url_clone, handle));
    }
    
    println!("Extracting from multiple URLs concurrently...\n");
    
    for (url, handle) in handles {
        match handle.await {
            Ok(Ok(result)) => {
                println!("{} - {}", url, result.data.title);
            }
            Ok(Err(e)) => {
                println!("{} - Error: {}", url, e);
            }
            Err(e) => {
                println!("{} - Task error: {}", url, e);
            }
        }
    }
    
    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("🤖 Claude Code SDK Integration Pattern Demo");
    println!("{}", "=".repeat(50));
    println!("This demonstrates how the claude-code-sdk would integrate");
    println!("with url-preview once the SDK compilation issue is fixed.\n");
    
    // Run demonstrations
    demonstrate_basic_usage().await?;
    demonstrate_custom_config().await?;
    demonstrate_concurrent_extraction().await?;
    
    println!("\n\n📋 Integration Steps:");
    println!("1. Fix the claude-code-sdk compilation issue");
    println!("2. Add to Cargo.toml:");
    println!("   claude-code-sdk = {{ path = \"../rust-claude-code-api/claude-code-sdk-rs\" }}");
    println!("3. Use ClaudeCodeProvider from url_preview:");
    println!("   use url_preview::{{LLMExtractor, ClaudeCodeProvider}};");
    println!("   let provider = ClaudeCodeProvider::new();");
    println!("   let extractor = LLMExtractor::with_provider(Box::new(provider));");
    
    println!("\n🎯 The actual ClaudeCodeProvider implementation is in:");
    println!("   src/llm_providers/claude_code.rs");
    
    Ok(())
}