openai_tools/videos/response.rs
1//! OpenAI Videos API Response Module
2//!
3//! Response types returned by the Videos API (`/v1/videos`).
4
5use serde::{Deserialize, Serialize};
6
7/// Lifecycle status of a video generation job.
8///
9/// Unrecognised values deserialize into [`Other`](VideoStatus::Other) so that a
10/// new server-side status does not break existing clients.
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "snake_case")]
13#[non_exhaustive]
14pub enum VideoStatus {
15 /// Job accepted and waiting to start
16 Queued,
17 /// Job is currently generating
18 InProgress,
19 /// Job finished successfully; assets are downloadable
20 Completed,
21 /// Job failed; see [`Video::error`]
22 Failed,
23 /// A status this library does not know about yet
24 #[serde(untagged)]
25 Other(String),
26}
27
28/// Error details attached to a failed video job.
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
30pub struct VideoError {
31 /// Machine-readable error code
32 pub code: String,
33 /// Human-readable description
34 pub message: String,
35}
36
37/// A video generation job.
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct Video {
40 /// Unique identifier for the job
41 pub id: String,
42 /// Object type, always "video"
43 pub object: String,
44 /// The model used for generation
45 pub model: String,
46 /// Current lifecycle status
47 pub status: VideoStatus,
48 /// Approximate completion percentage (0-100)
49 #[serde(default)]
50 pub progress: u32,
51 /// The prompt used for generation
52 #[serde(default, skip_serializing_if = "Option::is_none")]
53 pub prompt: Option<String>,
54 /// Unix timestamp (seconds) when the job was created
55 pub created_at: i64,
56 /// Unix timestamp (seconds) when the job finished, if it has
57 #[serde(default, skip_serializing_if = "Option::is_none")]
58 pub completed_at: Option<i64>,
59 /// Unix timestamp (seconds) when the generated assets expire
60 #[serde(default, skip_serializing_if = "Option::is_none")]
61 pub expires_at: Option<i64>,
62 /// Source video ID when this job is a remix
63 #[serde(default, skip_serializing_if = "Option::is_none")]
64 pub remixed_from_video_id: Option<String>,
65 /// Clip duration in seconds, as returned by the API (a string)
66 #[serde(default, skip_serializing_if = "Option::is_none")]
67 pub seconds: Option<String>,
68 /// Output resolution
69 #[serde(default, skip_serializing_if = "Option::is_none")]
70 pub size: Option<String>,
71 /// Error details when [`status`](Video::status) is
72 /// [`Failed`](VideoStatus::Failed)
73 #[serde(default, skip_serializing_if = "Option::is_none")]
74 pub error: Option<VideoError>,
75}
76
77impl Video {
78 /// Returns `true` once the job has settled - successfully or not.
79 ///
80 /// Use this to end a polling loop.
81 ///
82 /// # Example
83 ///
84 /// ```rust
85 /// use openai_tools::videos::response::{Video, VideoStatus};
86 ///
87 /// let json = r#"{"id":"v1","object":"video","model":"sora-2",
88 /// "status":"completed","progress":100,"created_at":1}"#;
89 /// let video: Video = serde_json::from_str(json).unwrap();
90 /// assert!(video.is_terminal());
91 /// ```
92 pub fn is_terminal(&self) -> bool {
93 matches!(self.status, VideoStatus::Completed | VideoStatus::Failed)
94 }
95
96 /// Returns `true` only when the job completed successfully and its assets
97 /// can be downloaded.
98 pub fn is_completed(&self) -> bool {
99 self.status == VideoStatus::Completed
100 }
101}
102
103/// A page of video jobs.
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct VideoListResponse {
106 /// Object type, always "list"
107 pub object: String,
108 /// The videos in this page
109 pub data: Vec<Video>,
110 /// ID of the first item, for pagination
111 #[serde(default, skip_serializing_if = "Option::is_none")]
112 pub first_id: Option<String>,
113 /// ID of the last item, for pagination
114 #[serde(default, skip_serializing_if = "Option::is_none")]
115 pub last_id: Option<String>,
116 /// Whether more items are available
117 #[serde(default)]
118 pub has_more: bool,
119}
120
121/// Result of deleting a video.
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct DeleteVideoResponse {
124 /// The deleted video identifier
125 pub id: String,
126 /// Object type, always "video.deleted"
127 pub object: String,
128 /// Whether the video was successfully deleted
129 pub deleted: bool,
130}