Skip to main content

basal_client/
media.rs

1//! Inline media and request language settings. No helper reads files or fetches URLs.
2use crate::Error;
3use base64::{engine::general_purpose::STANDARD, Engine as _};
4use serde::{Deserialize, Serialize};
5
6/// Supported inline input kinds.
7#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
8#[serde(rename_all = "lowercase")]
9pub enum MediaKind {
10    /// Encoded image.
11    Image,
12    /// Encoded audio.
13    Audio,
14}
15/// One inline media item, in request order.
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct MediaInput {
18    /// Image or audio.
19    #[serde(rename = "type")]
20    pub kind: MediaKind,
21    /// Base64 or a data URL. HTTP URLs are not fetched.
22    pub data: String,
23}
24impl MediaInput {
25    /// Encode image bytes. The server validates the codec and limits.
26    pub fn image(data: &[u8]) -> Self {
27        Self { kind: MediaKind::Image, data: STANDARD.encode(data) }
28    }
29    /// Encode audio bytes. The server validates the codec and limits.
30    pub fn audio(data: &[u8]) -> Self {
31        Self { kind: MediaKind::Audio, data: STANDARD.encode(data) }
32    }
33    /// Use existing base64 or a data URL, without fetching remote content.
34    pub fn from_base64(kind: MediaKind, data: impl Into<String>) -> Result<Self, Error> {
35        let input = Self { kind, data: data.into() };
36        input.validate()?;
37        Ok(input)
38    }
39    pub(crate) fn validate(&self) -> Result<(), Error> {
40        let lower = self.data.get(..8).unwrap_or(&self.data).to_ascii_lowercase();
41        if self.data.trim().is_empty() || lower.starts_with("http://") || lower.starts_with("https://") {
42            return Err(Error::InvalidRequest("media requires inline base64 or a data URL"));
43        }
44        Ok(())
45    }
46}
47/// Explicit prompt language.
48#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
49#[serde(rename_all = "lowercase")]
50pub enum Language {
51    /// Polish.
52    Pl,
53    /// English.
54    En,
55}
56/// Image resolution budget.
57#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
58#[serde(rename_all = "lowercase")]
59pub enum MediaDetail {
60    /// Default image budget.
61    Default,
62    /// High image budget.
63    High,
64}
65/// Media accounting reported by the server.
66#[derive(Debug, Clone, Deserialize)]
67pub struct MediaUsage {
68    /// Number of images.
69    pub images: u64,
70    /// Number of audio inputs.
71    pub audio: u64,
72    /// Total soft tokens over executed prompts.
73    pub media_tokens: u64,
74    /// Requested image detail.
75    pub detail: MediaDetail,
76}