Skip to main content

gproxy_protocol/openai/create_image_edit/
stream.rs

1use serde::{Deserialize, Serialize};
2
3use crate::openai::create_image::types::{
4    OpenAiApiError, OpenAiImageBackground, OpenAiImageOutputFormat, OpenAiImageUsage,
5};
6use crate::openai::create_image_edit::types::{OpenAiImageEditQuality, OpenAiImageEditSize};
7
8/// Parsed SSE stream body for `POST /images/edits` with `stream=true`.
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
10pub struct OpenAiCreateImageEditSseStreamBody {
11    /// SSE events in receive order.
12    #[serde(default, skip_serializing_if = "Vec::is_empty")]
13    pub events: Vec<OpenAiCreateImageEditSseEvent>,
14}
15
16/// A single SSE event frame.
17#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
18pub struct OpenAiCreateImageEditSseEvent {
19    /// Optional SSE `event` field.
20    #[serde(default, skip_serializing_if = "Option::is_none")]
21    pub event: Option<String>,
22    /// SSE `data` field payload.
23    pub data: OpenAiCreateImageEditSseData,
24}
25
26/// SSE `data` payload.
27#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
28#[serde(untagged)]
29pub enum OpenAiCreateImageEditSseData {
30    /// A regular stream event object.
31    Event(ImageEditStreamEvent),
32    /// Stream end marker (`[DONE]`).
33    Done(String),
34}
35
36impl OpenAiCreateImageEditSseData {
37    pub fn is_done(&self) -> bool {
38        matches!(self, Self::Done(marker) if marker == "[DONE]")
39    }
40}
41
42/// Stream event union documented by OpenAI image edit streaming.
43#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
44#[serde(tag = "type")]
45pub enum ImageEditStreamEvent {
46    #[serde(rename = "image_edit.partial_image")]
47    PartialImage {
48        b64_json: String,
49        background: OpenAiImageBackground,
50        created_at: u64,
51        output_format: OpenAiImageOutputFormat,
52        partial_image_index: u32,
53        quality: OpenAiImageEditQuality,
54        size: OpenAiImageEditSize,
55    },
56    #[serde(rename = "image_edit.completed")]
57    Completed {
58        b64_json: String,
59        background: OpenAiImageBackground,
60        created_at: u64,
61        output_format: OpenAiImageOutputFormat,
62        quality: OpenAiImageEditQuality,
63        size: OpenAiImageEditSize,
64        usage: OpenAiImageUsage,
65    },
66    #[serde(rename = "error")]
67    Error { error: OpenAiApiError },
68    /// Undocumented heartbeat frame some OpenAI-compatible backends ship
69    /// mid-stream (`{"type":"keepalive"}`). Ignored during aggregation.
70    #[serde(rename = "keepalive")]
71    Keepalive {
72        #[serde(default, skip_serializing_if = "Option::is_none")]
73        sequence_number: Option<u64>,
74    },
75}