Skip to main content

gproxy_protocol/openai/audio/
stream.rs

1use serde::{Deserialize, Serialize, de};
2use serde_json::Value;
3
4use crate::openai::common::Rest;
5
6use super::{AudioTokenUsage, TranscriptionLanguage, TranscriptionLogprob};
7
8/// Speech SSE payload observed by compatible backends. The OpenAI snapshot
9/// confirms SSE transport but does not name its events; `type`, `delta`, and
10/// `audio` are session-derived aliases and every other field remains opaque.
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12#[serde(untagged)]
13#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
14pub enum SpeechStreamEvent {
15    Event(SpeechEvent),
16    Raw(Value),
17}
18
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
20#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
21pub struct SpeechEvent {
22    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
23    pub type_: Option<String>,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub delta: Option<String>,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub audio: Option<String>,
28    #[serde(default, flatten)]
29    pub rest: Rest,
30}
31
32#[derive(Debug, Clone, PartialEq, Serialize)]
33#[serde(untagged)]
34#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
35pub enum TranscriptionStreamEvent {
36    Delta(TranscriptionTextDeltaEvent),
37    Done(TranscriptionTextDoneEvent),
38    Segment(TranscriptionTextSegmentEvent),
39    Unknown(UnknownTranscriptionStreamEvent),
40}
41
42impl<'de> Deserialize<'de> for TranscriptionStreamEvent {
43    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
44        let value = Value::deserialize(deserializer)?;
45        let known = match value.get("type").and_then(Value::as_str) {
46            Some("transcript.text.delta") => serde_json::from_value(value.clone()).map(Self::Delta),
47            Some("transcript.text.done") => serde_json::from_value(value.clone()).map(Self::Done),
48            Some("transcript.text.segment") => {
49                serde_json::from_value(value.clone()).map(Self::Segment)
50            }
51            _ => serde_json::from_value(value.clone()).map(Self::Unknown),
52        };
53        known
54            .or_else(|_| serde_json::from_value(value).map(Self::Unknown))
55            .map_err(de::Error::custom)
56    }
57}
58
59#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
60#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
61pub struct UnknownTranscriptionStreamEvent {
62    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
63    pub type_: Option<String>,
64    #[serde(default, flatten)]
65    pub rest: Rest,
66}
67
68#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
69#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
70pub struct TranscriptionTextDeltaEvent {
71    #[serde(rename = "type")]
72    pub type_: TranscriptionTextDeltaType,
73    pub delta: String,
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub logprobs: Option<Vec<TranscriptionLogprob>>,
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub segment_id: Option<String>,
78    #[serde(default, flatten)]
79    pub rest: Rest,
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
83#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
84pub enum TranscriptionTextDeltaType {
85    #[serde(rename = "transcript.text.delta")]
86    Delta,
87}
88
89#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
90#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
91pub struct TranscriptionTextDoneEvent {
92    #[serde(rename = "type")]
93    pub type_: TranscriptionTextDoneType,
94    pub text: String,
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub languages: Option<Vec<TranscriptionLanguage>>,
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub logprobs: Option<Vec<TranscriptionLogprob>>,
99    #[serde(skip_serializing_if = "Option::is_none")]
100    pub usage: Option<AudioTokenUsage>,
101    #[serde(default, flatten)]
102    pub rest: Rest,
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
106#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
107pub enum TranscriptionTextDoneType {
108    #[serde(rename = "transcript.text.done")]
109    Done,
110}
111
112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
113#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
114pub struct TranscriptionTextSegmentEvent {
115    #[serde(rename = "type")]
116    pub type_: TranscriptionTextSegmentType,
117    pub id: String,
118    pub end: f64,
119    pub speaker: String,
120    pub start: f64,
121    pub text: String,
122    #[serde(default, flatten)]
123    pub rest: Rest,
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
127#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
128pub enum TranscriptionTextSegmentType {
129    #[serde(rename = "transcript.text.segment")]
130    Segment,
131}