Skip to main content

cloudiful_docling_convert/processor/service/
remote.rs

1use super::DocumentConverter;
2use crate::api::{DoclingConvertRequest, DoclingResult};
3use crate::document::{InputDocument, OutputFormat, RemoteConvertOptions};
4use crate::error::{PdfConvertError, Result};
5use crate::models::TaskStatusResponse;
6
7impl DocumentConverter {
8    pub async fn convert_source_to_file_async(
9        &self,
10        url: &str,
11        filename: impl Into<String>,
12        input_kind: crate::document::InputKind,
13        output_formats: Vec<OutputFormat>,
14        options: &RemoteConvertOptions,
15        output_dir: std::path::PathBuf,
16        selected_output: OutputFormat,
17        overwrite: bool,
18    ) -> Result<crate::document::ConvertedFile> {
19        self.convert_source_to_file_async_with_docling_progress(
20            url,
21            filename,
22            input_kind,
23            output_formats,
24            options,
25            output_dir,
26            selected_output,
27            overwrite,
28            |_| async {},
29        )
30        .await
31    }
32
33    pub async fn convert_source_to_file_async_with_docling_progress<F, Fut>(
34        &self,
35        url: &str,
36        filename: impl Into<String>,
37        input_kind: crate::document::InputKind,
38        output_formats: Vec<OutputFormat>,
39        options: &RemoteConvertOptions,
40        output_dir: std::path::PathBuf,
41        selected_output: OutputFormat,
42        overwrite: bool,
43        mut on_status: F,
44    ) -> Result<crate::document::ConvertedFile>
45    where
46        F: FnMut(TaskStatusResponse) -> Fut + Send,
47        Fut: std::future::Future<Output = ()> + Send,
48    {
49        let filename = filename.into();
50        let input = InputDocument::new(
51            filename,
52            input_kind.canonical_media_type("source", None),
53            Vec::<u8>::new(),
54        )
55        .with_input_kind(input_kind);
56        let request = DoclingConvertRequest {
57            output_formats,
58            page_range: None,
59            chunker: options.chunker,
60            chunking: options.chunking.clone(),
61            pipeline: options.pipeline,
62        };
63        let task_id = self
64            .docling_client
65            .submit_source_async(url, input_kind, &request)
66            .await?;
67        let task_result = self
68            .docling_client
69            .wait_for_result_with_progress(&task_id, &mut on_status)
70            .await?;
71        let document = Self::document_from_task_result(&input, task_result)?;
72        let output_path =
73            Self::calculate_output_path(&output_dir, &document.filename, selected_output);
74        if !overwrite && output_path.exists() {
75            return Err(PdfConvertError::operation_error(
76                "writing output",
77                format!(
78                    "output already exists and overwrite is disabled: {}",
79                    output_path.display()
80                ),
81            ));
82        }
83        Self::write_output_file(&output_path, &document, selected_output).await?;
84        Ok(crate::document::ConvertedFile {
85            document,
86            output_paths: vec![output_path],
87        })
88    }
89
90    pub(super) async fn convert_remote_with_docling_progress<F, Fut>(
91        &self,
92        input: &InputDocument,
93        options: &RemoteConvertOptions,
94        output_formats: &[OutputFormat],
95        on_status: &mut F,
96    ) -> Result<crate::document::ConvertedDocument>
97    where
98        F: FnMut(TaskStatusResponse) -> Fut + Send,
99        Fut: std::future::Future<Output = ()> + Send,
100    {
101        let request = DoclingConvertRequest {
102            output_formats: output_formats.to_vec(),
103            page_range: None,
104            chunker: options.chunker,
105            chunking: options.chunking.clone(),
106            pipeline: options.pipeline,
107        };
108        let task_id = self
109            .docling_client
110            .submit_file_async(input, &request)
111            .await?;
112        let task_result = self
113            .docling_client
114            .wait_for_result_with_progress(&task_id, on_status)
115            .await?;
116        Self::document_from_task_result(input, task_result)
117    }
118
119    pub(super) async fn convert_remote<F, Fut>(
120        &self,
121        input: &InputDocument,
122        options: &RemoteConvertOptions,
123        output_formats: &[OutputFormat],
124        asynchronous: bool,
125        on_progress: &mut F,
126    ) -> Result<crate::document::ConvertedDocument>
127    where
128        F: FnMut(usize, usize) -> Fut + Send,
129        Fut: std::future::Future<Output = ()> + Send,
130    {
131        let request = DoclingConvertRequest {
132            output_formats: output_formats.to_vec(),
133            page_range: None,
134            chunker: options.chunker,
135            chunking: options.chunking.clone(),
136            pipeline: options.pipeline,
137        };
138
139        let result = if asynchronous {
140            let task_id = self
141                .docling_client
142                .submit_file_async(input, &request)
143                .await?;
144            let task_result = self.docling_client.wait_for_result(&task_id).await?;
145            let document = Self::document_from_task_result(input, task_result)?;
146            on_progress(1, 1).await;
147            return Ok(document);
148        } else {
149            let result = self.docling_client.convert_file(input, &request).await?;
150            on_progress(1, 1).await;
151            result
152        };
153
154        Self::document_from_result(input, result)
155    }
156
157    pub(super) fn document_from_result(
158        input: &InputDocument,
159        result: DoclingResult,
160    ) -> Result<crate::document::ConvertedDocument> {
161        let input_kind = input.kind()?;
162        match result {
163            DoclingResult::Failure(failure) => Err(PdfConvertError::api_task_failed(
164                "failure",
165                failure.failure.message,
166            )),
167            result => Ok(Self::build_document(input, input_kind, result)),
168        }
169    }
170
171    pub fn document_from_task_result(
172        input: &InputDocument,
173        task_result: crate::api::DoclingTaskResult,
174    ) -> Result<crate::document::ConvertedDocument> {
175        let mut document = Self::document_from_result(input, task_result.result)?;
176        document.errors.extend(task_result.errors);
177        document.errors.sort();
178        document.errors.dedup();
179        Ok(document)
180    }
181}