cloudiful_docling_convert/processor/service/
mod.rs1use crate::api::DoclingClient;
2use crate::document::{
3 ConvertOptions, ConvertRequest, ConvertedDocument, ConvertedFile, FileConvertRequest, InputKind,
4};
5use crate::error::{PdfConvertError, Result};
6use std::future::Future;
7
8mod output;
9mod pdf;
10mod text;
11
12#[cfg(test)]
13mod tests;
14
15pub struct DocumentConverter {
16 docling_client: DoclingClient,
17}
18
19impl DocumentConverter {
20 pub fn new(docling_client: DoclingClient) -> Self {
21 Self { docling_client }
22 }
23
24 pub async fn convert(&self, request: ConvertRequest) -> Result<ConvertedDocument> {
25 self.convert_with_progress(request, |_, _| async {}).await
26 }
27
28 pub async fn convert_with_progress<F, Fut>(
29 &self,
30 request: ConvertRequest,
31 mut on_progress: F,
32 ) -> Result<ConvertedDocument>
33 where
34 F: FnMut(usize, usize) -> Fut + Send,
35 Fut: Future<Output = ()> + Send,
36 {
37 let input_kind = request.validate()?;
38
39 match (&request.options, input_kind) {
40 (ConvertOptions::Text(options), InputKind::Text) => {
41 let document =
42 self.convert_text(&request.input, options, &request.output_formats)?;
43 on_progress(1, 1).await;
44 Ok(document)
45 }
46 (ConvertOptions::Generic(options), _) if input_kind.uses_generic_convert_options() => {
47 let document = self
48 .convert_generic(&request.input, options, &request.output_formats)
49 .await?;
50 on_progress(1, 1).await;
51 Ok(document)
52 }
53 (ConvertOptions::Pdf(options), InputKind::Pdf) => {
54 self.convert_pdf(
55 &request.input,
56 options,
57 &request.output_formats,
58 &mut on_progress,
59 )
60 .await
61 }
62 _ => Err(PdfConvertError::validation_error(
63 "request",
64 "input kind and convert options do not match",
65 )),
66 }
67 }
68
69 pub async fn convert_to_file(&self, request: FileConvertRequest) -> Result<ConvertedFile> {
70 self.convert_to_file_with_progress(request, |_, _| async {})
71 .await
72 }
73
74 pub async fn convert_to_file_with_progress<F, Fut>(
75 &self,
76 request: FileConvertRequest,
77 on_progress: F,
78 ) -> Result<ConvertedFile>
79 where
80 F: FnMut(usize, usize) -> Fut + Send,
81 Fut: Future<Output = ()> + Send,
82 {
83 let document = self
84 .convert_with_progress(request.request.clone(), on_progress)
85 .await?;
86 let output_path = Self::calculate_output_path(
87 &request.output_dir,
88 &document.filename,
89 request.selected_output,
90 );
91
92 if !request.overwrite && output_path.exists() {
93 return Err(PdfConvertError::operation_error(
94 "writing output",
95 format!(
96 "output already exists and overwrite is disabled: {}",
97 output_path.display()
98 ),
99 ));
100 }
101
102 Self::write_output_file(&output_path, &document, request.selected_output).await?;
103
104 Ok(ConvertedFile {
105 document,
106 output_paths: vec![output_path],
107 })
108 }
109}