rig_core/providers/openai/extension/
chat.rs1use std::collections::BTreeMap;
5
6use serde::{Deserialize, Serialize};
7
8#[non_exhaustive]
11#[derive(Clone, Debug, Default, PartialEq, Serialize)]
12pub struct ChatOptions {
13 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
15 pub logit_bias: BTreeMap<String, i32>,
16 #[serde(skip_serializing_if = "Option::is_none")]
19 pub prediction: Option<Prediction>,
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub logprobs: Option<bool>,
23 #[serde(skip_serializing_if = "Option::is_none")]
25 pub top_logprobs: Option<u8>,
26 #[serde(skip_serializing_if = "Option::is_none")]
28 pub frequency_penalty: Option<f64>,
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub presence_penalty: Option<f64>,
32 #[serde(skip_serializing_if = "Vec::is_empty")]
34 pub modalities: Vec<Modality>,
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pub audio: Option<AudioOutput>,
38 #[serde(skip_serializing_if = "Option::is_none")]
40 pub web_search_options: Option<WebSearchOptions>,
41}
42
43impl ChatOptions {
44 pub fn new() -> Self {
46 Self::default()
47 }
48
49 pub fn logit_bias(mut self, token: u32, bias: i32) -> Self {
51 self.logit_bias.insert(token.to_string(), bias);
52 self
53 }
54
55 pub fn prediction(mut self, content: impl Into<String>) -> Self {
57 self.prediction = Some(Prediction::content(content));
58 self
59 }
60
61 pub fn logprobs(mut self, logprobs: bool) -> Self {
63 self.logprobs = Some(logprobs);
64 self
65 }
66
67 pub fn top_logprobs(mut self, count: u8) -> Self {
69 self.top_logprobs = Some(count);
70 self
71 }
72
73 pub fn frequency_penalty(mut self, penalty: f64) -> Self {
75 self.frequency_penalty = Some(penalty);
76 self
77 }
78
79 pub fn presence_penalty(mut self, penalty: f64) -> Self {
81 self.presence_penalty = Some(penalty);
82 self
83 }
84
85 pub fn modalities(mut self, modalities: impl IntoIterator<Item = Modality>) -> Self {
87 self.modalities = modalities.into_iter().collect();
88 self
89 }
90
91 pub fn audio(mut self, voice: impl Into<String>, format: AudioFormat) -> Self {
93 self.audio = Some(AudioOutput {
94 voice: voice.into(),
95 format,
96 });
97 self
98 }
99
100 pub fn web_search_options(mut self, options: WebSearchOptions) -> Self {
102 self.web_search_options = Some(options);
103 self
104 }
105}
106
107#[non_exhaustive]
109#[derive(Clone, Debug, PartialEq, Serialize)]
110#[serde(tag = "type", rename_all = "lowercase")]
111pub enum Prediction {
112 Content {
114 content: String,
116 },
117}
118
119impl Prediction {
120 pub fn content(content: impl Into<String>) -> Self {
122 Self::Content {
123 content: content.into(),
124 }
125 }
126}
127
128#[non_exhaustive]
130#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
131#[serde(rename_all = "lowercase")]
132pub enum Modality {
133 Text,
135 Audio,
137}
138
139#[non_exhaustive]
141#[derive(Clone, Debug, PartialEq, Serialize)]
142pub struct AudioOutput {
143 pub voice: String,
145 pub format: AudioFormat,
147}
148
149#[non_exhaustive]
151#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
152#[serde(rename_all = "lowercase")]
153pub enum AudioFormat {
154 Wav,
156 Aac,
158 Mp3,
160 Flac,
162 Opus,
164 Pcm16,
166}
167
168#[non_exhaustive]
170#[derive(Clone, Debug, Default, PartialEq, Serialize)]
171pub struct WebSearchOptions {
172 #[serde(skip_serializing_if = "Option::is_none")]
174 pub search_context_size: Option<SearchContextSize>,
175 #[serde(skip_serializing_if = "Option::is_none")]
177 pub user_location: Option<UserLocation>,
178}
179
180impl WebSearchOptions {
181 pub fn new() -> Self {
183 Self::default()
184 }
185
186 pub fn search_context_size(mut self, size: SearchContextSize) -> Self {
188 self.search_context_size = Some(size);
189 self
190 }
191
192 pub fn user_location(mut self, location: ApproximateLocation) -> Self {
194 self.user_location = Some(UserLocation::Approximate {
195 approximate: location,
196 });
197 self
198 }
199}
200
201#[non_exhaustive]
203#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
204#[serde(rename_all = "lowercase")]
205pub enum SearchContextSize {
206 Low,
208 Medium,
210 High,
212}
213
214#[non_exhaustive]
216#[derive(Clone, Debug, PartialEq, Serialize)]
217#[serde(tag = "type", rename_all = "lowercase")]
218pub enum UserLocation {
219 Approximate {
221 approximate: ApproximateLocation,
223 },
224}
225
226#[non_exhaustive]
228#[derive(Clone, Debug, Default, PartialEq, Serialize)]
229pub struct ApproximateLocation {
230 #[serde(skip_serializing_if = "Option::is_none")]
232 pub city: Option<String>,
233 #[serde(skip_serializing_if = "Option::is_none")]
235 pub country: Option<String>,
236 #[serde(skip_serializing_if = "Option::is_none")]
238 pub region: Option<String>,
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub timezone: Option<String>,
242}
243
244impl ApproximateLocation {
245 pub fn new() -> Self {
247 Self::default()
248 }
249
250 pub fn city(mut self, city: impl Into<String>) -> Self {
252 self.city = Some(city.into());
253 self
254 }
255
256 pub fn country(mut self, country: impl Into<String>) -> Self {
258 self.country = Some(country.into());
259 self
260 }
261
262 pub fn region(mut self, region: impl Into<String>) -> Self {
264 self.region = Some(region.into());
265 self
266 }
267
268 pub fn timezone(mut self, timezone: impl Into<String>) -> Self {
270 self.timezone = Some(timezone.into());
271 self
272 }
273}
274
275#[non_exhaustive]
277#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize)]
278pub struct PromptTokensDetails {
279 #[serde(default)]
281 pub cached_tokens: Option<u64>,
282 #[serde(default)]
284 pub audio_tokens: Option<u64>,
285 #[serde(default)]
287 pub cache_write_tokens: Option<u64>,
288}
289
290#[non_exhaustive]
292#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize)]
293pub struct CompletionTokensDetails {
294 #[serde(default)]
296 pub reasoning_tokens: Option<u64>,
297 #[serde(default)]
299 pub audio_tokens: Option<u64>,
300 #[serde(default)]
302 pub accepted_prediction_tokens: Option<u64>,
303 #[serde(default)]
305 pub rejected_prediction_tokens: Option<u64>,
306}