pub mod edit;
pub mod generate;
pub mod variation;
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Image {
pub b64_json: Option<String>,
pub revised_prompt: Option<String>,
pub url: Option<String>,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ImagesResponse {
pub created: u64,
pub data: Option<Vec<Image>>,
pub background: Option<String>,
pub output_format: Option<String>,
pub quality: Option<String>,
pub size: Option<String>,
pub usage: Option<Usage>,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
pub struct Usage {
pub input_tokens: u64,
pub input_tokens_details: UsageInputTokensDetails,
pub output_tokens: u64,
pub total_tokens: u64,
pub output_tokens_details: Option<UsageOutputTokensDetails>,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
pub struct UsageInputTokensDetails {
pub image_tokens: u64,
pub text_tokens: u64,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
pub struct UsageOutputTokensDetails {
pub image_tokens: u64,
pub text_tokens: u64,
}
crate::impl_from_str!(ImagesResponse);
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum Background {
Transparent,
Opaque,
Auto,
}
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum OutputFormat {
Png,
Jpeg,
Webp,
}
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum ImageResponseFormat {
Url,
B64Json,
}
pub(super) fn enum_to_literal<T: Serialize>(value: &T) -> Result<String, crate::errors::OapiError> {
serde_json::to_string(value)
.map(|json| json.trim_matches('"').to_string())
.map_err(|e| {
crate::errors::OapiError::ResponseError(format!("Failed to serialize field: {e}"))
})
}
#[cfg(test)]
mod tests {
#[test]
fn parse_url_response() {
let content = r#"{
"created": 1706745938,
"data": [
{
"url": "https://example.com/image.png",
"revised_prompt": "a painted nebula with stars"
}
]
}"#;
let response: super::ImagesResponse = content.parse().unwrap();
assert_eq!(response.created, 1706745938);
let data = response.data.unwrap();
assert_eq!(data.len(), 1);
assert_eq!(
data[0].url.as_deref(),
Some("https://example.com/image.png")
);
assert_eq!(
data[0].revised_prompt.as_deref(),
Some("a painted nebula with stars")
);
assert_eq!(data[0].b64_json, None);
assert_eq!(response.usage, None);
}
#[test]
fn parse_b64_response() {
let content = r#"{
"created": 1706745938,
"data": [
{
"b64_json": "aGVsbG8gd29ybGQ="
}
],
"background": "transparent",
"output_format": "png",
"quality": "high",
"size": "1024x1024",
"usage": {
"input_tokens": 10,
"input_tokens_details": {
"image_tokens": 5,
"text_tokens": 5
},
"output_tokens": 4096,
"total_tokens": 4106,
"output_tokens_details": {
"image_tokens": 4096,
"text_tokens": 0
}
}
}"#;
let response: super::ImagesResponse = content.parse().unwrap();
assert_eq!(response.background.as_deref(), Some("transparent"));
assert_eq!(response.output_format.as_deref(), Some("png"));
assert_eq!(response.quality.as_deref(), Some("high"));
assert_eq!(response.size.as_deref(), Some("1024x1024"));
let usage = response.usage.unwrap();
assert_eq!(usage.input_tokens, 10);
assert_eq!(usage.input_tokens_details.image_tokens, 5);
assert_eq!(usage.input_tokens_details.text_tokens, 5);
assert_eq!(usage.output_tokens, 4096);
assert_eq!(usage.total_tokens, 4106);
assert_eq!(
usage.output_tokens_details.as_ref().unwrap().image_tokens,
4096
);
let data = response.data.unwrap();
assert_eq!(data[0].b64_json.as_deref(), Some("aGVsbG8gd29ybGQ="));
assert_eq!(data[0].url, None);
}
}