Skip to main content

gproxy_protocol/openai/realtime/
items.rs

1use serde::{Deserialize, Serialize, de};
2use serde_json::Value;
3
4use crate::openai::common::Rest;
5
6#[derive(Debug, Clone, PartialEq, Serialize)]
7#[serde(untagged)]
8#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
9pub enum RealtimeItem {
10    Known(KnownRealtimeItem),
11    Unknown(UnknownRealtimeItem),
12}
13
14impl<'de> Deserialize<'de> for RealtimeItem {
15    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
16        let value = Value::deserialize(deserializer)?;
17        if let Ok(item) = serde_json::from_value(value.clone()) {
18            return Ok(Self::Known(item));
19        }
20        serde_json::from_value(value)
21            .map(Self::Unknown)
22            .map_err(de::Error::custom)
23    }
24}
25
26extensible_string!(RealtimeRole, KnownRealtimeRole {
27    User => "user", Assistant => "assistant", System => "system",
28});
29extensible_string!(RealtimeItemStatus, KnownRealtimeItemStatus {
30    InProgress => "in_progress", Completed => "completed", Incomplete => "incomplete",
31});
32
33#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
34#[serde(tag = "type")]
35#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
36pub enum KnownRealtimeItem {
37    #[serde(rename = "message")]
38    Message {
39        #[serde(skip_serializing_if = "Option::is_none")]
40        id: Option<String>,
41        role: RealtimeRole,
42        content: Vec<RealtimeContentPart>,
43        #[serde(skip_serializing_if = "Option::is_none")]
44        status: Option<RealtimeItemStatus>,
45        #[serde(default, flatten)]
46        rest: Rest,
47    },
48    #[serde(rename = "function_call")]
49    FunctionCall {
50        #[serde(skip_serializing_if = "Option::is_none")]
51        id: Option<String>,
52        #[serde(skip_serializing_if = "Option::is_none")]
53        call_id: Option<String>,
54        #[serde(skip_serializing_if = "Option::is_none")]
55        name: Option<String>,
56        #[serde(skip_serializing_if = "Option::is_none")]
57        arguments: Option<String>,
58        #[serde(skip_serializing_if = "Option::is_none")]
59        status: Option<RealtimeItemStatus>,
60        #[serde(default, flatten)]
61        rest: Rest,
62    },
63    #[serde(rename = "function_call_output")]
64    FunctionCallOutput {
65        #[serde(skip_serializing_if = "Option::is_none")]
66        id: Option<String>,
67        call_id: String,
68        output: String,
69        #[serde(skip_serializing_if = "Option::is_none")]
70        status: Option<RealtimeItemStatus>,
71        #[serde(default, flatten)]
72        rest: Rest,
73    },
74}
75
76#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
77#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
78pub struct UnknownRealtimeItem {
79    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
80    pub type_: Option<String>,
81    #[serde(default, flatten)]
82    pub rest: Rest,
83}
84
85#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
86#[serde(tag = "type")]
87#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
88pub enum RealtimeContentPart {
89    #[serde(rename = "input_text")]
90    InputText {
91        #[serde(skip_serializing_if = "Option::is_none")]
92        text: Option<String>,
93        #[serde(default, flatten)]
94        rest: Rest,
95    },
96    #[serde(rename = "input_audio")]
97    InputAudio {
98        #[serde(skip_serializing_if = "Option::is_none")]
99        audio: Option<String>,
100        #[serde(skip_serializing_if = "Option::is_none")]
101        transcript: Option<String>,
102        #[serde(default, flatten)]
103        rest: Rest,
104    },
105    #[serde(rename = "text")]
106    Text {
107        #[serde(skip_serializing_if = "Option::is_none")]
108        text: Option<String>,
109        #[serde(default, flatten)]
110        rest: Rest,
111    },
112    #[serde(rename = "audio")]
113    Audio {
114        #[serde(skip_serializing_if = "Option::is_none")]
115        audio: Option<String>,
116        #[serde(skip_serializing_if = "Option::is_none")]
117        transcript: Option<String>,
118        #[serde(default, flatten)]
119        rest: Rest,
120    },
121    #[serde(rename = "output_text")]
122    OutputText {
123        #[serde(skip_serializing_if = "Option::is_none")]
124        text: Option<String>,
125        #[serde(default, flatten)]
126        rest: Rest,
127    },
128    #[serde(rename = "output_audio")]
129    OutputAudio {
130        #[serde(skip_serializing_if = "Option::is_none")]
131        audio: Option<String>,
132        #[serde(skip_serializing_if = "Option::is_none")]
133        transcript: Option<String>,
134        #[serde(default, flatten)]
135        rest: Rest,
136    },
137}