use crate::Error;
use base64::{engine::general_purpose::STANDARD, Engine as _};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum MediaKind {
Image,
Audio,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MediaInput {
#[serde(rename = "type")]
pub kind: MediaKind,
pub data: String,
}
impl MediaInput {
pub fn image(data: &[u8]) -> Self {
Self { kind: MediaKind::Image, data: STANDARD.encode(data) }
}
pub fn audio(data: &[u8]) -> Self {
Self { kind: MediaKind::Audio, data: STANDARD.encode(data) }
}
pub fn from_base64(kind: MediaKind, data: impl Into<String>) -> Result<Self, Error> {
let input = Self { kind, data: data.into() };
input.validate()?;
Ok(input)
}
pub(crate) fn validate(&self) -> Result<(), Error> {
let lower = self.data.get(..8).unwrap_or(&self.data).to_ascii_lowercase();
if self.data.trim().is_empty() || lower.starts_with("http://") || lower.starts_with("https://") {
return Err(Error::InvalidRequest("media requires inline base64 or a data URL"));
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Language {
Pl,
En,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum MediaDetail {
Default,
High,
}
#[derive(Debug, Clone, Deserialize)]
pub struct MediaUsage {
pub images: u64,
pub audio: u64,
pub media_tokens: u64,
pub detail: MediaDetail,
}