Skip to main content

runifold_model/
media.rs

1//! Provider-neutral image, speech, and transcription task boundaries.
2
3use serde::{Deserialize, Serialize};
4
5use crate::{MediaSource, ModelCallContext, ModelError, ModelFuture, ModelRef};
6
7/// Image output encoding requested from a generation model.
8#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
9#[serde(rename_all = "snake_case")]
10#[non_exhaustive]
11pub enum ImageFormat {
12    /// Portable Network Graphics.
13    #[default]
14    Png,
15    /// WebP image.
16    Webp,
17    /// JPEG image.
18    Jpeg,
19}
20
21impl ImageFormat {
22    /// Returns the canonical media type.
23    #[must_use]
24    pub const fn media_type(self) -> &'static str {
25        match self {
26            Self::Png => "image/png",
27            Self::Webp => "image/webp",
28            Self::Jpeg => "image/jpeg",
29        }
30    }
31}
32
33/// Provider-neutral image-generation request.
34#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
35pub struct ImageGenerationRequest {
36    /// Provider and model identity.
37    pub model: ModelRef,
38    /// Natural-language image description.
39    pub prompt: String,
40    /// Number of requested images.
41    pub count: u8,
42    /// Provider-supported size such as `1024x1024` or `auto`.
43    pub size: Option<String>,
44    /// Provider-supported quality such as `low`, `high`, or `auto`.
45    pub quality: Option<String>,
46    /// Requested output encoding.
47    pub format: ImageFormat,
48    /// Whether a transparent background is required.
49    pub transparent: bool,
50}
51
52/// One generated image.
53#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
54pub struct GeneratedImage {
55    /// Inline or remotely hosted image source.
56    pub source: MediaSource,
57    /// Provider-revised prompt, when supplied.
58    pub revised_prompt: Option<String>,
59}
60
61/// Complete image-generation result.
62#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
63pub struct ImageGenerationResponse {
64    /// Generated images in provider order.
65    pub images: Vec<GeneratedImage>,
66}
67
68/// Independent image-generation model boundary.
69pub trait ImageGenerationModel: Send + Sync {
70    /// Generates complete image outputs.
71    fn generate_image(
72        &self,
73        request: ImageGenerationRequest,
74        context: ModelCallContext,
75    ) -> ModelFuture<'_, Result<ImageGenerationResponse, ModelError>>;
76}
77
78/// Audio encoding requested from a speech model.
79#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
80#[serde(rename_all = "snake_case")]
81#[non_exhaustive]
82pub enum SpeechFormat {
83    /// MPEG Layer III.
84    #[default]
85    Mp3,
86    /// Opus audio.
87    Opus,
88    /// Advanced Audio Coding.
89    Aac,
90    /// Free Lossless Audio Codec.
91    Flac,
92    /// Waveform Audio File Format.
93    Wav,
94    /// Headerless PCM audio.
95    Pcm,
96}
97
98impl SpeechFormat {
99    /// Returns the canonical media type.
100    #[must_use]
101    pub const fn media_type(self) -> &'static str {
102        match self {
103            Self::Mp3 => "audio/mpeg",
104            Self::Opus => "audio/opus",
105            Self::Aac => "audio/aac",
106            Self::Flac => "audio/flac",
107            Self::Wav => "audio/wav",
108            Self::Pcm => "audio/L16",
109        }
110    }
111}
112
113/// Provider-neutral text-to-speech request.
114#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
115pub struct SpeechRequest {
116    /// Provider and model identity.
117    pub model: ModelRef,
118    /// Text to synthesize.
119    pub input: String,
120    /// Built-in or provider-specific voice identity.
121    pub voice: String,
122    /// Optional performance instructions.
123    pub instructions: Option<String>,
124    /// Output encoding.
125    pub format: SpeechFormat,
126    /// Playback speed multiplier.
127    pub speed: Option<f32>,
128}
129
130/// Complete synthesized speech bytes.
131#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
132pub struct SpeechResponse {
133    /// Canonical media type matching the requested format.
134    pub media_type: String,
135    /// Encoded audio bytes.
136    #[serde(with = "byte_serde")]
137    pub bytes: Vec<u8>,
138}
139
140/// Independent text-to-speech model boundary.
141pub trait SpeechModel: Send + Sync {
142    /// Synthesizes one complete audio output.
143    fn synthesize_speech(
144        &self,
145        request: SpeechRequest,
146        context: ModelCallContext,
147    ) -> ModelFuture<'_, Result<SpeechResponse, ModelError>>;
148}
149
150/// Provider-neutral audio-transcription request.
151#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
152pub struct TranscriptionRequest {
153    /// Provider and model identity.
154    pub model: ModelRef,
155    /// Input file name used by multipart providers.
156    pub file_name: String,
157    /// Input audio media type.
158    pub media_type: String,
159    /// Encoded audio bytes.
160    #[serde(with = "byte_serde")]
161    pub bytes: Vec<u8>,
162    /// Optional ISO-639-1 input language.
163    pub language: Option<String>,
164    /// Optional vocabulary or style hint.
165    pub prompt: Option<String>,
166}
167
168/// Complete transcription result.
169#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
170pub struct TranscriptionResponse {
171    /// Transcribed text.
172    pub text: String,
173    /// Provider-reported language, when present.
174    pub language: Option<String>,
175    /// Provider-reported duration in seconds, when present.
176    pub duration_seconds: Option<f64>,
177}
178
179/// Independent speech-to-text model boundary.
180pub trait TranscriptionModel: Send + Sync {
181    /// Transcribes one complete audio input.
182    fn transcribe(
183        &self,
184        request: TranscriptionRequest,
185        context: ModelCallContext,
186    ) -> ModelFuture<'_, Result<TranscriptionResponse, ModelError>>;
187}
188
189mod byte_serde {
190    use serde::{Deserialize, Deserializer, Serializer};
191
192    pub fn serialize<S>(value: &[u8], serializer: S) -> Result<S::Ok, S::Error>
193    where
194        S: Serializer,
195    {
196        serializer.serialize_bytes(value)
197    }
198
199    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
200    where
201        D: Deserializer<'de>,
202    {
203        Vec::<u8>::deserialize(deserializer)
204    }
205}