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