use serde::{Deserialize, Deserializer, Serialize};
use crate::client::Client;
use crate::error::Result;
fn deserialize_null_as_default<'de, D, T>(deserializer: D) -> std::result::Result<T, D::Error>
where
D: Deserializer<'de>,
T: Default + Deserialize<'de>,
{
Ok(Option::<T>::deserialize(deserializer)?.unwrap_or_default())
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct ImageRequest {
pub model: String,
pub prompt: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub count: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub aspect_ratio: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub quality: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub output_format: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub style: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub background: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub image_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub topology: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target_polycount: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub symmetry_mode: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pose_mode: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub enable_pbr: Option<bool>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ImageResponse {
#[serde(default, deserialize_with = "deserialize_null_as_default")]
pub images: Vec<GeneratedImage>,
#[serde(default)]
pub model: String,
#[serde(default)]
pub cost_ticks: i64,
#[serde(default)]
pub balance_after: i64,
#[serde(default)]
pub request_id: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct GeneratedImage {
pub base64: String,
pub format: String,
pub index: i32,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct ImageEditRequest {
pub model: String,
pub prompt: String,
pub input_images: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub count: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<String>,
}
pub type ImageEditResponse = ImageResponse;
impl Client {
pub async fn generate_image(&self, req: &ImageRequest) -> Result<ImageResponse> {
let (mut resp, meta) = self
.post_json::<ImageRequest, ImageResponse>("/qai/v1/images/generate", req)
.await?;
if resp.cost_ticks == 0 {
resp.cost_ticks = meta.cost_ticks;
}
if resp.balance_after == 0 {
resp.balance_after = meta.balance_after;
}
if resp.request_id.is_empty() {
resp.request_id = meta.request_id;
}
Ok(resp)
}
pub async fn edit_image(&self, req: &ImageEditRequest) -> Result<ImageEditResponse> {
let (mut resp, meta) = self
.post_json::<ImageEditRequest, ImageEditResponse>("/qai/v1/images/edit", req)
.await?;
if resp.cost_ticks == 0 {
resp.cost_ticks = meta.cost_ticks;
}
if resp.balance_after == 0 {
resp.balance_after = meta.balance_after;
}
if resp.request_id.is_empty() {
resp.request_id = meta.request_id;
}
Ok(resp)
}
}