Skip to main content

zai_rs/tool/file_parser_result/
data.rs

1//! # File Parser Result API
2//!
3//! This module provides the file parser result client for retrieving file
4//! parsing results.
5
6use std::sync::Arc;
7
8use tracing::{debug, trace, warn};
9
10use super::{request::*, response::*};
11use crate::{
12    ZaiResult,
13    client::{
14        endpoints::{ApiBase, EndpointConfig, join_url, paths},
15        error::codes,
16        http::{HttpClientConfig, parse_typed_response, send_empty_request},
17    },
18};
19
20/// File parser result client.
21///
22/// This client provides functionality to retrieve file parsing results,
23/// supporting multiple result formats and asynchronous task monitoring.
24///
25/// ## Examples
26///
27/// ```rust,ignore
28/// use zai_rs::tool::file_parser_result::{FileParserResultRequest, FormatType};
29///
30/// let api_key = "your-api-key".to_string();
31/// let task_id = "task_123456789";
32///
33/// let request = FileParserResultRequest::new(api_key, task_id);
34///
35/// let response = request.get_result(FormatType::Text).await?;
36/// if let Some(content) = response.content() {
37///     println!("Parsed content: {}", content);
38/// }
39/// ```
40pub struct FileParserResultRequest {
41    /// API key for authentication
42    pub key: String,
43    endpoint_config: EndpointConfig,
44    api_base: ApiBase,
45    http_config: Arc<HttpClientConfig>,
46    /// Task ID for the parsing job
47    pub task_id: String,
48}
49
50impl FileParserResultRequest {
51    /// Creates a new file parser result request.
52    ///
53    /// ## Arguments
54    ///
55    /// * `key` - API key for authentication
56    /// * `task_id` - ID of the parsing task
57    ///
58    /// ## Returns
59    ///
60    /// A new `FileParserResultRequest` instance.
61    pub fn new(key: String, task_id: impl Into<String>) -> Self {
62        Self {
63            key,
64            endpoint_config: EndpointConfig::default(),
65            api_base: ApiBase::PaasV4,
66            http_config: Arc::new(HttpClientConfig::default()),
67            task_id: task_id.into(),
68        }
69    }
70
71    pub fn with_base_url(mut self, base_url: impl Into<String>) -> Self {
72        self.api_base = ApiBase::Custom(base_url.into());
73        self
74    }
75
76    pub fn with_endpoint_config(mut self, endpoint_config: EndpointConfig) -> Self {
77        self.endpoint_config = endpoint_config;
78        self
79    }
80
81    pub fn with_http_config(mut self, config: HttpClientConfig) -> Self {
82        self.http_config = Arc::new(config);
83        self
84    }
85
86    fn result_url(&self, format_type: &FormatType) -> String {
87        let path = join_url(
88            paths::FILE_PARSER_RESULT,
89            &join_url(&self.task_id, &format_type.to_string()),
90        );
91        self.endpoint_config.url(&self.api_base, &path)
92    }
93
94    /// Gets the parsing result for the given format type.
95    ///
96    /// ## Arguments
97    ///
98    /// * `format_type` - Format type for the result
99    ///
100    /// ## Returns
101    ///
102    /// A `FileParserResultResponse` containing the parsing result.
103    pub async fn get_result(&self, format_type: FormatType) -> ZaiResult<FileParserResultResponse> {
104        let url = self.result_url(&format_type);
105        trace!(url = %url, "Fetching file parser result");
106        let response = send_empty_request(
107            reqwest::Method::GET,
108            url,
109            self.key.clone(),
110            self.http_config.clone(),
111        )
112        .await?;
113        parse_typed_response::<FileParserResultResponse>(response).await
114    }
115
116    /// Polls for the result until it's completed or timeout is reached.
117    ///
118    /// ## Arguments
119    ///
120    /// * `format_type` - Format type for the result
121    /// * `timeout_seconds` - Maximum time to wait for result
122    /// * `poll_interval_seconds` - Interval between status checks
123    ///
124    /// ## Returns
125    ///
126    /// A `FileParserResultResponse` containing the parsing result.
127    pub async fn wait_for_result(
128        &self,
129        format_type: FormatType,
130        timeout_seconds: u64,
131        poll_interval_seconds: u64,
132    ) -> ZaiResult<FileParserResultResponse> {
133        debug!(
134            timeout_seconds,
135            poll_interval_seconds, "Polling file parser result"
136        );
137        let start_time = std::time::Instant::now();
138
139        loop {
140            trace!("Checking file parser result status");
141            let result = self.get_result(format_type.clone()).await?;
142
143            match result.status {
144                ParserStatus::Succeeded => {
145                    debug!("File parsing completed successfully");
146                    return Ok(result);
147                },
148                ParserStatus::Failed => {
149                    warn!(
150                        task_id = %self.task_id,
151                        message = %result.message,
152                        "File parsing task reported failure"
153                    );
154                    return Err(crate::client::error::ZaiError::ApiError {
155                        code: codes::SDK_EXTERNAL_TOOL,
156                        message: format!("Parsing failed: {}", result.message),
157                    });
158                },
159                ParserStatus::Processing => {
160                    let elapsed = start_time.elapsed().as_secs();
161                    trace!(elapsed, "File parser result still processing");
162                    if elapsed > timeout_seconds {
163                        warn!(
164                            task_id = %self.task_id,
165                            elapsed,
166                            timeout_seconds,
167                            "Polling timed out waiting for parsing result"
168                        );
169                        return Err(crate::client::error::ZaiError::ApiError {
170                            code: codes::SDK_TIMEOUT,
171                            message: "Timeout waiting for parsing result".to_string(),
172                        });
173                    }
174                    tokio::time::sleep(tokio::time::Duration::from_secs(poll_interval_seconds))
175                        .await;
176                },
177            }
178        }
179    }
180
181    /// Gets both text and download link results in a single request.
182    ///
183    /// ## Returns
184    ///
185    /// A tuple containing text result and download link result.
186    pub async fn get_all_results(
187        &self,
188    ) -> ZaiResult<(FileParserResultResponse, FileParserResultResponse)> {
189        let text_result = self.get_result(FormatType::Text).await?;
190        let download_result = self.get_result(FormatType::DownloadLink).await?;
191        Ok((text_result, download_result))
192    }
193}