298 lines
11 KiB
Rust
298 lines
11 KiB
Rust
use document_parser::config::init_global_config;
|
||
use document_parser::models::ImageInfo;
|
||
use document_parser::parsers::DualEngineParser;
|
||
use document_parser::processors::MarkdownProcessor;
|
||
use document_parser::processors::markdown_processor::MarkdownProcessorConfig;
|
||
use document_parser::services::{DocumentService, ImageProcessor, TaskService};
|
||
use std::sync::Arc;
|
||
use tokio::fs;
|
||
|
||
#[tokio::main]
|
||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||
println!("🚀 Markdown image processing core logic test");
|
||
println!("=====================================");
|
||
|
||
// 初始化全局配置
|
||
let config =
|
||
document_parser::config::AppConfig::load_config().expect("Failed to load configuration");
|
||
init_global_config(config).expect("Failed to initialize global config");
|
||
println!("✅ Global configuration initialization completed");
|
||
|
||
// 获取项目根目录
|
||
let project_root = std::env::current_dir()?;
|
||
let test_file_path = project_root
|
||
.join("document-parser")
|
||
.join("fixtures")
|
||
.join("upload_parse_test.md");
|
||
|
||
println!("📁 Test file path: {}", test_file_path.display());
|
||
|
||
// 检查测试文件是否存在
|
||
if !test_file_path.exists() {
|
||
eprintln!(
|
||
"❌ The test file does not exist: {}",
|
||
test_file_path.display()
|
||
);
|
||
return Ok(());
|
||
}
|
||
|
||
// 读取测试 Markdown 文件
|
||
let markdown_content = fs::read_to_string(&test_file_path).await?;
|
||
println!(
|
||
"📖 Read Markdown file successfully, content length: {} characters",
|
||
markdown_content.len()
|
||
);
|
||
|
||
// 创建 Markdown 处理器
|
||
let processor = MarkdownProcessor::new(MarkdownProcessorConfig::default(), None);
|
||
println!("🔧 Markdown processor created");
|
||
|
||
// 测试 1: 解析 Markdown 并构建章节层次结构
|
||
println!("\\n🧪 Test 1: Parse Markdown and build chapter hierarchy");
|
||
let doc_structure = processor.parse_markdown_with_toc(&markdown_content).await?;
|
||
|
||
println!("Document title: {}", doc_structure.title);
|
||
println!("Total number of chapters: {}", doc_structure.total_sections);
|
||
println!("Maximum level: {}", doc_structure.max_level);
|
||
println!("Number of TOC items: {}", doc_structure.toc.len());
|
||
|
||
// 显示前几个 TOC 项目
|
||
for (i, item) in doc_structure.toc.iter().take(5).enumerate() {
|
||
println!(
|
||
"{}. [{}] {} (Level: {})",
|
||
i + 1,
|
||
item.id,
|
||
item.title,
|
||
item.level
|
||
);
|
||
}
|
||
|
||
// 测试 2: 提取图片路径
|
||
println!("\\n🧪 Test 2: Extract image path in Markdown");
|
||
let image_paths = ImageProcessor::extract_image_paths(&markdown_content);
|
||
println!("Number of image paths found: {}", image_paths.len());
|
||
|
||
// 只显示前10个图片路径
|
||
for (i, path) in image_paths.iter().take(10).enumerate() {
|
||
println!(" {}. {}", i + 1, path);
|
||
}
|
||
if image_paths.len() > 10 {
|
||
println!("...and {} image paths", image_paths.len() - 10);
|
||
}
|
||
|
||
// 测试 3: 验证图片文件是否存在(修复路径匹配问题)
|
||
println!("\\n🧪 Test 3: Verify that the image file exists");
|
||
|
||
// 根据测试文件路径确定图片目录位置
|
||
let images_dir = if test_file_path.parent().unwrap().join("images").exists() {
|
||
test_file_path.parent().unwrap().join("images")
|
||
} else {
|
||
// 回退到默认位置
|
||
project_root
|
||
.join("document-parser")
|
||
.join("fixtures")
|
||
.join("images")
|
||
};
|
||
let mut existing_images = 0;
|
||
let mut missing_images = 0;
|
||
let mut valid_image_paths = Vec::new();
|
||
|
||
for image_name in &image_paths {
|
||
// 现在 image_paths 直接包含图片名称(如 filename.jpg)
|
||
let filename = image_name;
|
||
|
||
// 检查文件是否存在
|
||
let full_path = images_dir.join(filename);
|
||
if full_path.exists() {
|
||
let metadata = fs::metadata(&full_path).await?;
|
||
println!(" ✅ {} ({} bytes)", filename, metadata.len());
|
||
existing_images += 1;
|
||
valid_image_paths.push(image_name.clone());
|
||
} else {
|
||
// 如果直接匹配失败,尝试在 images 目录中查找
|
||
let mut found = false;
|
||
if let Ok(mut entries) = fs::read_dir(&images_dir).await {
|
||
while let Ok(Some(entry)) = entries.next_entry().await {
|
||
let entry_path = entry.path();
|
||
if let Some(entry_filename) = entry_path.file_name().and_then(|f| f.to_str()) {
|
||
if entry_filename == filename {
|
||
let metadata = fs::metadata(&entry_path).await?;
|
||
println!(
|
||
"✅ {} ({} bytes) [match by file name]",
|
||
filename,
|
||
metadata.len()
|
||
);
|
||
existing_images += 1;
|
||
valid_image_paths.push(image_name.clone());
|
||
found = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if !found {
|
||
println!("❌ {filename} (File does not exist)");
|
||
missing_images += 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
println!("Existing pictures: {existing_images}");
|
||
println!("Missing pictures: {missing_images}");
|
||
|
||
// 测试 4: 创建真实的图片上传结果(基于实际存在的图片)
|
||
println!("\\n🧪 Test 4: Create realistic image upload results");
|
||
|
||
let mut real_image_results = Vec::new();
|
||
for image_name in &valid_image_paths {
|
||
// 现在 valid_image_paths 直接包含图片名称(如 filename.jpg)
|
||
let filename = image_name;
|
||
|
||
// 模拟真实的 OSS URL(实际项目中这里会是真实的 OSS 上传结果)
|
||
let oss_url = format!(
|
||
"https://example-oss.com/processed_images/{}/{}",
|
||
uuid::Uuid::new_v4().to_string().split('-').next().unwrap(),
|
||
filename
|
||
);
|
||
|
||
// 获取实际文件大小
|
||
let full_path = images_dir.join(filename);
|
||
let file_size = fs::metadata(&full_path).await?.len() as u64;
|
||
|
||
// 为了创建 ImageInfo,我们需要构建完整的原始路径
|
||
let original_path = format!("images/{image_name}");
|
||
|
||
real_image_results.push(ImageInfo::new(
|
||
original_path,
|
||
oss_url,
|
||
file_size,
|
||
"image/jpeg".to_string(),
|
||
));
|
||
}
|
||
|
||
println!("Create real picture results: {}", real_image_results.len());
|
||
|
||
// 测试 5: 测试 Markdown 内容替换
|
||
if !real_image_results.is_empty() {
|
||
println!("\\n🧪 Test 5: Test Markdown content replacement");
|
||
|
||
// 创建临时的 DocumentService 来测试替换逻辑
|
||
let temp_oss_service = None; // 不使用真实的 OSS 服务
|
||
let temp_task_service = Arc::new(
|
||
TaskService::new(Arc::new(
|
||
sled::open(":memory:").expect("Failed to create in-memory DB"),
|
||
))
|
||
.expect("Failed to create task service"),
|
||
);
|
||
let temp_dual_parser = DualEngineParser::with_auto_venv_detection()
|
||
.expect("Failed to create dual engine parser");
|
||
let temp_markdown_processor =
|
||
MarkdownProcessor::new(MarkdownProcessorConfig::default(), None);
|
||
|
||
let temp_doc_service = DocumentService::new(
|
||
temp_dual_parser,
|
||
temp_markdown_processor,
|
||
temp_task_service,
|
||
temp_oss_service,
|
||
);
|
||
|
||
// 测试路径替换逻辑
|
||
let replaced_content = temp_doc_service
|
||
.replace_image_paths_in_markdown(&markdown_content, &real_image_results)
|
||
.await?;
|
||
|
||
println!(
|
||
"Original content length: {} characters",
|
||
markdown_content.len()
|
||
);
|
||
println!(
|
||
"Content length after replacement: {} characters",
|
||
replaced_content.len()
|
||
);
|
||
|
||
// 检查是否成功替换了图片路径
|
||
let original_image_count = image_paths.len();
|
||
let replaced_image_count = ImageProcessor::extract_image_paths(&replaced_content).len();
|
||
|
||
if replaced_image_count == 0 {
|
||
println!(
|
||
"✅ Image path replacement successful, all local paths have been replaced with OSS URLs"
|
||
);
|
||
} else {
|
||
println!(
|
||
"⚠️ There are still {replaced_image_count} image paths that have not been replaced"
|
||
);
|
||
}
|
||
|
||
// 显示替换前后的对比(前几行)
|
||
println!("\\n📝 Content replacement comparison (first 10 lines):");
|
||
println!("Original content:");
|
||
for (i, line) in markdown_content.lines().take(10).enumerate() {
|
||
if line.contains(" {
|
||
println!(" {}: {}", i + 1, line);
|
||
}
|
||
}
|
||
|
||
println!("Content after replacement:");
|
||
for (i, line) in replaced_content.lines().take(10).enumerate() {
|
||
if line.contains(" {
|
||
println!(" {}: {}", i + 1, line);
|
||
}
|
||
}
|
||
|
||
// 测试 6: 验证替换结果
|
||
println!("\\n🧪 Test 6: Verify replacement results");
|
||
let replaced_image_paths = ImageProcessor::extract_image_paths(&replaced_content);
|
||
let oss_url_count = replaced_content.matches("https://example-oss.com").count();
|
||
|
||
println!(
|
||
"Number of image paths after replacement: {}",
|
||
replaced_image_paths.len()
|
||
);
|
||
println!("OSS URL quantity: {oss_url_count}");
|
||
|
||
if oss_url_count > 0 {
|
||
println!("✅ Successfully replaced {oss_url_count} image paths with OSS URLs");
|
||
} else {
|
||
println!("❌ The OSS URL is not found and the replacement may fail.");
|
||
}
|
||
}
|
||
|
||
// 测试总结
|
||
println!("\\n📊 Test summary");
|
||
println!("=====================================");
|
||
println!("✅ Markdown parsing: Success");
|
||
println!(
|
||
"✅ Chapter hierarchy: {} chapters",
|
||
doc_structure.total_sections
|
||
);
|
||
println!("✅ Picture path extraction: {} pictures", image_paths.len());
|
||
println!(
|
||
"✅ Image file verification: {}/{} files exist",
|
||
existing_images,
|
||
image_paths.len()
|
||
);
|
||
println!("✅ Path replacement test: Completed");
|
||
|
||
if missing_images > 0 {
|
||
println!("⚠️ Missing pictures: {missing_images} (need to check picture files)");
|
||
}
|
||
|
||
if !real_image_results.is_empty() {
|
||
println!(
|
||
"✅ Image upload simulation: {} images",
|
||
real_image_results.len()
|
||
);
|
||
println!("✅ Markdown content replacement: Completed");
|
||
}
|
||
|
||
println!("\\n🎉 Core logic test completed!");
|
||
println!("\\n💡 Note: This is a test program, actual OSS upload requires:");
|
||
println!("1. Configure real OSS services");
|
||
println!("2. Call the ImageProcessor::batch_upload_images method");
|
||
println!("3. Use real OSS credentials");
|
||
|
||
Ok(())
|
||
}
|