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            picture_description_preset: options.picture_description_preset.clone(),
63        };
64        let task_id = self
65            .docling_client
66            .submit_source_async(url, input_kind, &request)
67            .await?;
68        let task_result = self
69            .docling_client
70            .wait_for_result_with_progress(&task_id, &mut on_status)
71            .await?;
72        let document = Self::document_from_task_result(&input, task_result)?;
73        let output_path =
74            Self::calculate_output_path(&output_dir, &document.filename, selected_output);
75        if !overwrite && output_path.exists() {
76            return Err(PdfConvertError::operation_error(
77                "writing output",
78                format!(
79                    "output already exists and overwrite is disabled: {}",
80                    output_path.display()
81                ),
82            ));
83        }
84        Self::write_output_file(&output_path, &document, selected_output).await?;
85        Ok(crate::document::ConvertedFile {
86            document,
87            output_paths: vec![output_path],
88        })
89    }
90
91    pub(super) async fn convert_remote_with_docling_progress<F, Fut>(
92        &self,
93        input: &InputDocument,
94        options: &RemoteConvertOptions,
95        output_formats: &[OutputFormat],
96        on_status: &mut F,
97    ) -> Result<crate::document::ConvertedDocument>
98    where
99        F: FnMut(TaskStatusResponse) -> Fut + Send,
100        Fut: std::future::Future<Output = ()> + Send,
101    {
102        let request = DoclingConvertRequest {
103            output_formats: output_formats.to_vec(),
104            page_range: None,
105            chunker: options.chunker,
106            chunking: options.chunking.clone(),
107            pipeline: options.pipeline,
108            picture_description_preset: options.picture_description_preset.clone(),
109        };
110        let task_id = self
111            .docling_client
112            .submit_file_async(input, &request)
113            .await?;
114        let task_result = self
115            .docling_client
116            .wait_for_result_with_progress(&task_id, on_status)
117            .await?;
118        Self::document_from_task_result(input, task_result)
119    }
120
121    pub(super) async fn convert_remote<F, Fut>(
122        &self,
123        input: &InputDocument,
124        options: &RemoteConvertOptions,
125        output_formats: &[OutputFormat],
126        asynchronous: bool,
127        on_progress: &mut F,
128    ) -> Result<crate::document::ConvertedDocument>
129    where
130        F: FnMut(usize, usize) -> Fut + Send,
131        Fut: std::future::Future<Output = ()> + Send,
132    {
133        let request = DoclingConvertRequest {
134            output_formats: output_formats.to_vec(),
135            page_range: None,
136            chunker: options.chunker,
137            chunking: options.chunking.clone(),
138            pipeline: options.pipeline,
139            picture_description_preset: options.picture_description_preset.clone(),
140        };
141
142        let result = if asynchronous {
143            let task_id = self
144                .docling_client
145                .submit_file_async(input, &request)
146                .await?;
147            let task_result = self.docling_client.wait_for_result(&task_id).await?;
148            let document = Self::document_from_task_result(input, task_result)?;
149            on_progress(1, 1).await;
150            return Ok(document);
151        } else {
152            let result = self.docling_client.convert_file(input, &request).await?;
153            on_progress(1, 1).await;
154            result
155        };
156
157        Self::document_from_result(input, result)
158    }
159
160    pub(super) fn document_from_result(
161        input: &InputDocument,
162        result: DoclingResult,
163    ) -> Result<crate::document::ConvertedDocument> {
164        let input_kind = input.kind()?;
165        match result {
166            DoclingResult::Failure(failure) => Err(PdfConvertError::api_task_failed(
167                "failure",
168                failure.failure.message,
169            )),
170            result => Ok(Self::build_document(input, input_kind, result)),
171        }
172    }
173
174    pub fn document_from_task_result(
175        input: &InputDocument,
176        task_result: crate::api::DoclingTaskResult,
177    ) -> Result<crate::document::ConvertedDocument> {
178        let mut document = Self::document_from_result(input, task_result.result)?;
179        document.errors.extend(task_result.errors);
180        document.errors.sort();
181        document.errors.dedup();
182        Ok(document)
183    }
184}