use anyhow::Result;
use std::time::Instant;
use std::collections::HashSet;
use sysinfo::System;
use crate::worker::{PlaywrightWorker, ScrapingEngine, ScrapeOptions, ScrapeResponse};
use crate::cache::LocalCache;
use crate::clustering;
use crate::extractor;
use crate::semantic_extractor;
pub fn run_benchmark() -> Result<()> {
println!("\n=======================================================");
println!("📊 INICIANDO BENCHMARK INTEGRAL DE RECURSOS - bgustscraper");
println!("=======================================================\n");
let test_url = "https://example.com";
let test_prompt = "Extrae el titulo de la pagina y la descripcion basica";
let mut sys = System::new_all();
println!("🧪 [ESCENARIO 1] Iniciando Scraping Sintáctico Puro...");
let start_time_1 = Instant::now();
let mut worker_1 = PlaywrightWorker::new(true, ScrapingEngine::Playwright)?;
let scrape_opts_1 = ScrapeOptions {
deep_scan: false,
semantic_embeddings: None,
text: None,
prompt: None,
};
let response_1 = worker_1.scrape(test_url, Some(scrape_opts_1))?;
let mut _docs_1 = Vec::new();
if response_1.status == "success" {
let html = response_1.html.unwrap();
_docs_1 = extractor::find_documents(&html, test_url);
}
let ram_peak_1 = get_ecosystem_ram_usage(&mut sys)?;
worker_1.exit()?;
let duration_1 = start_time_1.elapsed();
println!("✅ Escenario 1 Completado.");
println!(" ↳ Tiempo: {:.2?}", duration_1);
println!(" ↳ RAM Pico Ecosistema: {:.2} MB", ram_peak_1);
let cache = LocalCache::new()?;
let cache_key = format!("scrape:{}", test_url);
let _ = cache.set(&cache_key, "");
println!("\n🧪 [ESCENARIO 2] Iniciando Scraping Semántico Completo (Modelos Locales)...");
let start_time_2 = Instant::now();
let mut worker_2 = PlaywrightWorker::new(true, ScrapingEngine::Playwright)?;
let scrape_opts_2 = ScrapeOptions {
deep_scan: false,
semantic_embeddings: Some(true),
text: None,
prompt: None,
};
let response_2 = worker_2.scrape(test_url, Some(scrape_opts_2))?;
let mut _docs_2 = Vec::new();
if response_2.status == "success" {
let markdown = response_2.markdown.clone().unwrap_or_default();
let compressed_text = if let (Some(sentences), Some(embeddings)) = (&response_2.sentences, &response_2.embeddings) {
let summary_sentences = clustering::compress_text_by_clustering(sentences, embeddings, 12);
summary_sentences.join("\n")
} else {
markdown.chars().take(2000).collect()
};
let extract_opts = ScrapeOptions {
deep_scan: false,
semantic_embeddings: None,
text: Some(compressed_text.clone()),
prompt: Some(test_prompt.to_string()),
};
let _extract_resp = worker_2.scrape("extract", Some(extract_opts))?;
if let Ok(sem_docs) = semantic_extractor::extract_semantic_documents(&mut worker_2, &compressed_text, test_url) {
_docs_2 = sem_docs;
}
}
let ram_peak_2 = get_ecosystem_ram_usage(&mut sys)?;
if response_2.status == "success" {
let resp_json = serde_json::to_string(&response_2)?;
cache.set(&cache_key, &resp_json)?;
}
worker_2.exit()?;
let duration_2 = start_time_2.elapsed();
println!("✅ Escenario 2 Completado.");
println!(" ↳ Tiempo: {:.2?}", duration_2);
println!(" ↳ RAM Pico Ecosistema: {:.2} MB", ram_peak_2);
println!("\n🧪 [ESCENARIO 3] Iniciando Scraping de Caché Embebida (redb)...");
let start_time_3 = Instant::now();
let mut worker_3 = PlaywrightWorker::new(true, ScrapingEngine::Playwright)?;
let response_3 = match cache.get(&cache_key) {
Ok(Some(cached_json)) => {
serde_json::from_str::<ScrapeResponse>(&cached_json)?
}
_ => {
return Err(anyhow::anyhow!("Fallo al recuperar los datos de la caché para el escenario 3"));
}
};
if response_3.status == "success" {
let markdown = response_3.markdown.unwrap_or_default();
let compressed_text = if let (Some(sentences), Some(embeddings)) = (&response_3.sentences, &response_3.embeddings) {
let summary_sentences = clustering::compress_text_by_clustering(sentences, embeddings, 12);
summary_sentences.join("\n")
} else {
markdown.chars().take(2000).collect()
};
let extract_opts = ScrapeOptions {
deep_scan: false,
semantic_embeddings: None,
text: Some(compressed_text.clone()),
prompt: Some(test_prompt.to_string()),
};
let _extract_resp = worker_3.scrape("extract", Some(extract_opts))?;
}
let ram_peak_3 = get_ecosystem_ram_usage(&mut sys)?;
worker_3.exit()?;
let duration_3 = start_time_3.elapsed();
println!("✅ Escenario 3 Completado.");
println!(" ↳ Tiempo: {:.2?}", duration_3);
println!(" ↳ RAM Pico Ecosistema: {:.2} MB", ram_peak_3);
println!("\n=======================================================");
println!("📊 REPORT COMPARATIVO DE SCRAPING Y RECURSOS");
println!("=======================================================");
println!("Escenario 1 (Sintáctico): Tiempo: {:.2?}, RAM Pico: {:.2} MB", duration_1, ram_peak_1);
println!("Escenario 2 (Semántico): Tiempo: {:.2?}, RAM Pico: {:.2} MB", duration_2, ram_peak_2);
println!("Escenario 3 (Caché redb): Tiempo: {:.2?}, RAM Pico: {:.2} MB", duration_3, ram_peak_3);
println!("=======================================================\n");
Ok(())
}
fn get_ecosystem_ram_usage(sys: &mut System) -> Result<f64> {
sys.refresh_all();
let current_pid = sysinfo::get_current_pid().map_err(|e| anyhow::anyhow!("No se pudo obtener el PID actual: {}", e))?;
let mut tracked_pids = HashSet::new();
tracked_pids.insert(current_pid);
let mut added_any = true;
while added_any {
added_any = false;
for (pid, process) in sys.processes() {
if let Some(parent_pid) = process.parent() {
if tracked_pids.contains(&parent_pid) && !tracked_pids.contains(pid) {
tracked_pids.insert(*pid);
added_any = true;
}
}
}
}
let mut total_memory_bytes = 0;
for pid in tracked_pids {
if let Some(proc) = sys.process(pid) {
total_memory_bytes += proc.memory();
}
}
let memory_mb = total_memory_bytes as f64 / 1024.0 / 1024.0;
Ok(memory_mb)
}