webpage_quality_analyzer 1.0.2

High-performance webpage quality analyzer with 115 comprehensive metrics - Rust library with WASM, C++, and Python bindings
Documentation
pub mod content_validator;
pub mod profile_aware_scorer;
pub mod profile_compiler;
/// Scoring Module - Phase 3: Profile-Aware Scoring Engine
/// Provides complete scoring functionality with compiled profiles and content validation
pub mod utils;

// Re-export key types for easier access
pub use content_validator::{
    ContentAnalysis, ContentPenalty, ContentValidationResult, ContentValidator, ContentViolation,
    HeadingAnalysis, MediaAnalysis, SeoAnalysis, TechnicalAnalysis, ViolationSeverity,
    WordCountAnalysis,
};
pub use profile_aware_scorer::{
    AppliedBonus, AppliedPenalty, ContentComplianceResult, ProfileAwareScorer, ScoringResult,
};
pub use profile_compiler::{
    CompiledBonus, CompiledMetricRule, CompiledPenalty, CompiledProfile, ProfileCompiler,
};
// Scoring functions will be implemented separately
// pub use scoring::{calculate_score, ScoreBreakdown};
// Utils functions will be implemented separately
// pub use utils::{normalize_score, apply_weights};

/// Phase 3 Scoring System Entry Point
///
/// This module provides the complete Phase 3 profile-aware scoring system with:
/// - ProfileCompiler: Pre-compiles profile configurations for optimal performance
/// - ProfileAwareScorer: Core scoring engine with category-based scoring and caching
/// - ContentValidator: Validates content expectations with detailed analysis
///
/// Usage:
/// ```no_run
/// use webpage_quality_analyzer::scoring::{ProfileCompiler, ProfileAwareScorer, ContentValidator};
///
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// // Compile profile for performance
/// let compiler = ProfileCompiler::new();
/// // let compiled_profile = compiler.compile_profile(&profile_config)?;
///
/// // Score page with compiled profile  
/// let scorer = ProfileAwareScorer::new();
/// // let result = scorer.calculate_score(&metrics, &compiled_profile, &document).await?;
///
/// // Validate content expectations
/// let validator = ContentValidator::new();
/// // let validation = validator.validate_content_expectations(&expectations, &metrics, &document)?;
/// # Ok(())
/// # }
/// ```
pub struct Phase3ScoringSystem {
    compiler: ProfileCompiler,
    scorer: ProfileAwareScorer,
    validator: ContentValidator,
}

impl Phase3ScoringSystem {
    /// Create a new Phase 3 scoring system
    pub fn new() -> Self {
        Self {
            compiler: ProfileCompiler::new(),
            scorer: ProfileAwareScorer::new(),
            validator: ContentValidator::new(),
        }
    }

    /// Get the profile compiler
    pub fn compiler(&self) -> &ProfileCompiler {
        &self.compiler
    }

    /// Get the profile-aware scorer
    pub fn scorer(&self) -> &ProfileAwareScorer {
        &self.scorer
    }

    /// Get the content validator
    pub fn validator(&self) -> &ContentValidator {
        &self.validator
    }

    /// Compile a profile for repeated use
    pub fn compile_profile(
        &self,
        config: &crate::config::enhanced_models::EnhancedScoringProfile,
    ) -> Result<CompiledProfile, crate::AnalyzeError> {
        self.compiler
            .compile_profile(config)
            .map_err(|e| crate::AnalyzeError::ConfigError(format!("Compilation failed: {}", e)))
    }

    /// Calculate score using compiled profile
    pub fn calculate_score(
        &self,
        _compiled_profile: &CompiledProfile,
        metrics: &crate::models::models::PageMetrics,
        metadata: &crate::models::models::ExtractedMetadata,
        document: &crate::models::models::ProcessedDocument,
    ) -> Result<ScoringResult, crate::AnalyzeError> {
        // Create a mutable scorer to call the method
        let mut scorer = self.scorer.clone();
        scorer
            .calculate_score(metrics, metadata, document)
            .map_err(|e| crate::AnalyzeError::ConfigError(format!("Scoring failed: {}", e)))
    }

    /// Validate content expectations
    pub fn validate_content(
        &self,
        expectations: &crate::config::enhanced_models::ContentExpectations,
        metrics: &crate::models::models::PageMetrics,
        document: &crate::models::models::ProcessedDocument,
    ) -> Result<ContentValidationResult, content_validator::ContentValidationError> {
        self.validator
            .validate_content_expectations(expectations, metrics, document)
    }

    /// Complete scoring pipeline with compilation, scoring, and validation
    pub fn complete_analysis(
        &self,
        config: &crate::config::enhanced_models::EnhancedScoringProfile,
        metrics: &crate::models::models::PageMetrics,
        metadata: &crate::models::models::ExtractedMetadata,
        document: &crate::models::models::ProcessedDocument,
    ) -> Result<CompleteAnalysisResult, Phase3Error> {
        // Compile profile
        let compiled_profile = self
            .compile_profile(config)
            .map_err(Phase3Error::ConfigError)?;

        // Calculate score
        let scoring_result = self
            .calculate_score(&compiled_profile, metrics, metadata, document)
            .map_err(Phase3Error::ConfigError)?;

        // Validate content if expectations are provided
        let content_validation = Some(
            self.validate_content(&config.content_expectations, metrics, document)
                .map_err(Phase3Error::ValidationError)?,
        );

        Ok(CompleteAnalysisResult {
            scoring_result,
            content_validation,
            compiled_profile,
        })
    }
}

impl Default for Phase3ScoringSystem {
    fn default() -> Self {
        Self::new()
    }
}

/// Complete analysis result from Phase 3 system
#[derive(Debug, Clone)]
pub struct CompleteAnalysisResult {
    pub scoring_result: ScoringResult,
    pub content_validation: Option<ContentValidationResult>,
    pub compiled_profile: CompiledProfile,
}

/// Phase 3 error types
#[derive(Debug, thiserror::Error)]
pub enum Phase3Error {
    #[error("Configuration error: {0}")]
    ConfigError(#[from] crate::AnalyzeError),

    #[error("Content validation error: {0}")]
    ValidationError(#[from] content_validator::ContentValidationError),

    #[error("Scoring error: {0}")]
    ScoringError(String),
}

/// Performance monitoring for Phase 3 operations
#[derive(Debug, Clone, Default)]
pub struct Phase3Performance {
    pub compilation_time_ms: f64,
    pub scoring_time_ms: f64,
    pub validation_time_ms: f64,
    pub total_time_ms: f64,
    pub cache_hit_rate: f64,
    pub metrics_processed: usize,
}

impl Phase3Performance {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn total_time(&self) -> f64 {
        self.compilation_time_ms + self.scoring_time_ms + self.validation_time_ms
    }

    pub fn efficiency_score(&self) -> f64 {
        let total = self.total_time();
        if total > 0.0 {
            (self.metrics_processed as f64 / total) * 1000.0 // metrics per second
        } else {
            0.0
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_phase3_system_creation() {
        let system = Phase3ScoringSystem::new();
        assert!(!std::ptr::eq(
            system.compiler(),
            system.scorer() as *const _ as *const ProfileCompiler
        ));
    }

    #[test]
    fn test_performance_metrics() {
        let mut perf = Phase3Performance::new();
        perf.compilation_time_ms = 10.0;
        perf.scoring_time_ms = 20.0;
        perf.validation_time_ms = 5.0;
        perf.metrics_processed = 100;

        assert_eq!(perf.total_time(), 35.0);
        assert!(perf.efficiency_score() > 0.0);
    }
}