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