cloudiful_docling_convert/processor/service/
remote.rs1use 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}