implemented the diagnostics api and migrated code for the improved documents model

This commit is contained in:
nilsk 2026-07-18 00:08:41 +02:00
parent 2b470c437b
commit 0d6739aa41
No known key found for this signature in database
GPG Key ID: A5C0151B4DDB172C

View File

@ -12,7 +12,7 @@ use calamine::{open_workbook_auto, Reader};
use file_format::{FileFormat, Kind};
use futures::{Stream, StreamExt};
use pdfium_render::prelude::Pdfium;
use pptx_to_md::{ImageHandlingMode, ParserConfig, PresentationContainer, PresentationFormat, PresentationMetadata };
use pptx_to_md::{DiagnosticSeverity, ImageHandlingMode, MarkdownOptions, ParserConfig, PresentationContainer, PresentationFormat, PresentationMetadata, ReadingOrder};
use serde::{Deserialize, Deserializer, Serialize};
use serde::de::{Error as SerdeError, Visitor};
use std::path::Path;
@ -460,25 +460,65 @@ async fn stream_presentation(file_path: &str, extract_images: bool, format: Pres
.compress_images(true)
.quality(75)
.image_handling_mode(ImageHandlingMode::Manually)
.include_slide_number_as_comment(true)
.include_speaker_notes(true)
.include_comments(true)
.include_presentation_metadata(true)
.build();
let markdown_options = MarkdownOptions {
reading_order: ReadingOrder::Spatial,
include_slide_number_as_comment: true,
include_speaker_notes: true,
include_comments: true,
render_unsupported_comments: true,
};
let mut streamer = tokio::task::spawn_blocking(move || {
PresentationContainer::open_as(&path, parser_config, format).map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
}).await??;
let (tx, rx) = mpsc::channel(32);
let worker_error_tx = tx.clone();
tokio::spawn(async move {
let metadata_md = presentation_metadata_to_markdown(streamer.metadata());
// Slide iteration performs synchronous ZIP/XML work and image compression,
// so the complete producer must stay outside Tokio's asynchronous workers.
let worker = tokio::task::spawn_blocking(move || {
let mut metadata_md = presentation_metadata_to_markdown(streamer.metadata());
for slide_result in streamer.iter_slides() {
match slide_result {
Ok(slide) => {
if let Some(mut content) = slide.convert_to_md() {
if slide.slide_number == 1 && let Some(metadata) = metadata_md.as_deref() {
let slide = match slide_result {
Ok(slide) => slide,
Err(e) => {
let _ = tx.blocking_send(Err(Box::new(e) as Box<dyn std::error::Error + Send + Sync>));
return;
},
};
for diagnostic in &slide.diagnostics {
let source = diagnostic.source.as_deref().unwrap_or("presentation");
match diagnostic.severity {
DiagnosticSeverity::Warning => warn!(
"Presentation slide {} warning in '{}': {}",
slide.slide_number,
source,
diagnostic.message
),
DiagnosticSeverity::Error => error!(
"Presentation slide {} error in '{}': {}",
slide.slide_number,
source,
diagnostic.message
),
}
}
let mut content = match slide.to_markdown(&markdown_options) {
Ok(content) => content,
Err(e) => {
let _ = tx.blocking_send(Err(Box::new(e) as Box<dyn std::error::Error + Send + Sync>));
return;
},
};
if let Some(metadata) = metadata_md.take() {
content = format!("{metadata}\n\n{content}");
}
@ -490,9 +530,8 @@ async fn stream_presentation(file_path: &str, extract_images: bool, format: Pres
}
);
if tx.send(Ok(chunk)).await.is_err() {
break;
}
if tx.blocking_send(Ok(chunk)).is_err() {
return;
}
if let Some(images) = slide.load_images_manually() {
@ -522,8 +561,8 @@ async fn stream_presentation(file_path: &str, extract_images: bool, format: Pres
}
);
if tx.send(Ok(chunk)).await.is_err() {
break;
if tx.blocking_send(Ok(chunk)).is_err() {
return;
}
offset = end;
@ -531,12 +570,12 @@ async fn stream_presentation(file_path: &str, extract_images: bool, format: Pres
}
}
}
},
Err(e) => {
let _ = tx.send(Err(Box::new(e) as Box<dyn std::error::Error + Send + Sync>)).await;
break;
}
}
});
tokio::spawn(async move {
if let Err(e) = worker.await {
let _ = worker_error_tx.send(Err(format!("Presentation parser task failed: {e}").into())).await;
}
});