async_dashscope/operation/
task.rs1use serde::{Deserialize, Serialize};
2use std::time::Duration;
3use tokio::time::sleep;
4
5use crate::error::{DashScopeError, Result};
6use crate::{Client, operation::common::TaskStatus};
7const TASK_PATH: &str = "/tasks";
8
9#[derive(Serialize, Deserialize, Debug, Clone)]
10pub struct TaskOutput {
11 pub task_id: String,
12 pub task_status: TaskStatus,
13 pub submit_time: String,
14 pub scheduled_time: Option<String>,
15 pub end_time: Option<String>,
16 pub image_url: Option<String>,
17 pub code: Option<String>,
18 pub message: Option<String>,
19}
20
21#[derive(Serialize, Deserialize, Debug, Clone)]
22pub struct TaskResult {
23 pub request_id: String,
24 pub output: TaskOutput,
25 pub usage: Option<ImageUsage>,
26}
27
28#[derive(Serialize, Deserialize, Debug, Clone)]
29pub struct ImageUsage {
30 pub image_count: u32,
31}
32
33pub struct Task<'a> {
34 client: &'a Client,
35}
36
37impl<'a> Task<'a> {
38 pub fn new(client: &'a Client) -> Self {
39 Self { client }
40 }
41
42 pub(crate) async fn query(&self, task_id: &str) -> Result<TaskResult> {
43 let http_client = self.client.http_client();
44 let headers = self.client.config().headers();
45 let req = http_client
46 .get(
47 self.client
48 .config()
49 .url(format!("{}/{}", TASK_PATH, task_id).as_str()),
50 )
51 .headers(headers)
52 .build()?;
53
54 let resp = http_client.execute(req).await?.bytes().await?;
55
56 if resp.is_empty() {
58 return Err(DashScopeError::ApiError(crate::error::ApiError {
59 message: "API returned empty response".to_string(),
60 request_id: None,
61 code: Some("EmptyResponse".to_string()),
62 }));
63 }
64
65 let raw_response_str = String::from_utf8_lossy(resp.as_ref());
66 println!("Raw API response: {}", raw_response_str);
67
68 let resp_json = serde_json::from_slice::<TaskResult>(resp.as_ref()).map_err(|e| {
69 crate::error::DashScopeError::JSONDeserialize {
70 source: e,
71 raw_response: resp.to_vec(),
72 }
73 })?;
74
75 Ok(resp_json)
76 }
77
78 pub async fn poll_task_status(
99 &self,
100 task_id: &str,
101 interval: u64,
102 max_attempts: u32,
103 ) -> Result<TaskResult> {
104 for attempt in 1..=max_attempts {
105 println!("第 {} 次轮询...", attempt);
106
107 match self.query(task_id).await {
108 Ok(result) => {
109 let task_status = &result.output.task_status;
110
111 match task_status {
113 TaskStatus::Succeeded => {
114 return Ok(result);
115 }
116 TaskStatus::Failed => {
117 return Ok(result);
118 }
119 TaskStatus::Pending | TaskStatus::Running => {
120 sleep(Duration::from_secs(interval)).await;
122 }
123 TaskStatus::Canceled | TaskStatus::Unknown => {
124 sleep(Duration::from_secs(interval)).await;
125 }
126 }
127 }
128 Err(e) => {
129 match &e {
131 DashScopeError::JSONDeserialize {
132 source: _,
133 raw_response: _,
134 } => {
135 sleep(Duration::from_secs(interval)).await;
138 }
139 DashScopeError::Reqwest(_) => {
140 sleep(Duration::from_secs(interval)).await;
142 }
143 DashScopeError::ApiError(api_error) => {
144 if api_error.code.as_deref() == Some("EmptyResponse") {
146 sleep(Duration::from_secs(interval)).await;
147 } else {
148 return Err(e);
150 }
151 }
152 _ => {
153 return Err(e);
155 }
156 }
157 }
158 }
159 }
160
161 Err(DashScopeError::TimeoutError(
163 "轮询超时,任务未在预期时间内完成".to_string(),
164 ))
165 }
166}