1use super::shared::{ReasoningEffort, WebSearchContextSize};
2use crate::params::shared::StopToken;
3use crate::params::shared::{FinishReason, Usage};
4use derive_builder::Builder;
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use std::collections::HashMap;
8use std::fmt::Display;
9
10#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
11pub struct ChatCompletionResponse {
12 #[serde(skip_serializing_if = "Option::is_none")]
14 pub id: Option<String>,
15 pub choices: Vec<ChatCompletionChoice>,
17 pub created: u32,
19 pub model: String,
21 #[serde(skip_serializing_if = "Option::is_none")]
23 pub service_tier: Option<String>,
24 #[serde(skip_serializing_if = "Option::is_none")]
26 pub system_fingerprint: Option<String>,
27 pub object: String,
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub usage: Option<Usage>,
32}
33
34#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
35pub struct ChatCompletionChunkResponse {
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub id: Option<String>,
39 pub choices: Vec<ChatCompletionChunkChoice>,
41 pub created: u32,
43 pub model: String,
45 #[serde(skip_serializing_if = "Option::is_none")]
48 pub system_fingerprint: Option<String>,
49 pub object: String,
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub usage: Option<Usage>,
54}
55
56#[derive(Serialize, Deserialize, Debug, Default, Builder, Clone, PartialEq)]
57#[builder(name = "ChatCompletionParametersBuilder")]
58#[builder(setter(into, strip_option), default)]
59pub struct ChatCompletionParameters {
60 pub messages: Vec<ChatMessage>,
62 pub model: String,
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub store: Option<bool>,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub reasoning_effort: Option<ReasoningEffort>,
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub metadata: Option<HashMap<String, String>>,
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub enable_thinking: Option<bool>,
75 #[serde(skip_serializing_if = "Option::is_none")]
78 pub frequency_penalty: Option<f32>,
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub logit_bias: Option<HashMap<String, i32>>,
82 #[serde(skip_serializing_if = "Option::is_none")]
85 pub logprobs: Option<bool>,
86 #[serde(skip_serializing_if = "Option::is_none")]
89 pub top_logprobs: Option<u32>,
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub max_tokens: Option<u32>,
93 #[serde(skip_serializing_if = "Option::is_none")]
95 pub max_completion_tokens: Option<u32>,
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub n: Option<u32>,
99 #[serde(skip_serializing_if = "Option::is_none")]
101 pub modalities: Option<Vec<Modality>>,
102 #[serde(skip_serializing_if = "Option::is_none")]
105 pub prediction: Option<PredictedOutput>,
106 #[serde(skip_serializing_if = "Option::is_none")]
108 pub audio: Option<AudioParameters>,
109 #[serde(skip_serializing_if = "Option::is_none")]
112 pub presence_penalty: Option<f32>,
113 #[serde(skip_serializing_if = "Option::is_none")]
118 pub response_format: Option<ChatCompletionResponseFormat>,
119 #[serde(skip_serializing_if = "Option::is_none")]
124 pub seed: Option<u32>,
125 #[serde(skip_serializing_if = "Option::is_none")]
127 pub stop: Option<StopToken>,
128 #[serde(skip_serializing_if = "Option::is_none")]
131 pub stream: Option<bool>,
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub stream_options: Option<ChatCompletionStreamOptions>,
135 #[serde(skip_serializing_if = "Option::is_none")]
138 pub temperature: Option<f32>,
139 #[serde(skip_serializing_if = "Option::is_none")]
142 pub top_p: Option<f32>,
143 #[serde(skip_serializing_if = "Option::is_none")]
144 pub top_k: Option<usize>,
145 #[serde(skip_serializing_if = "Option::is_none")]
149 pub repeat_penalty: Option<f32>,
150 #[serde(skip_serializing_if = "Option::is_none")]
154 pub repeat_last_n: Option<usize>,
155 #[serde(skip_serializing_if = "Option::is_none")]
158 pub tools: Option<Vec<ChatCompletionTool>>,
159 #[serde(skip_serializing_if = "Option::is_none")]
164 pub tool_choice: Option<ChatCompletionToolChoice>,
165 #[serde(skip_serializing_if = "Option::is_none")]
167 pub parallel_tool_calls: Option<bool>,
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub safety_identifier: Option<String>,
171 #[serde(skip_serializing_if = "Option::is_none")]
173 pub prompt_cache_key: Option<String>,
174 #[serde(skip_serializing_if = "Option::is_none")]
176 pub web_search_options: Option<WebSearchOptions>,
177 #[serde(flatten)]
179 #[serde(skip_serializing_if = "Option::is_none")]
180 pub extra_body: Option<Value>,
181 #[serde(skip_serializing_if = "Option::is_none")]
184 pub query_params: Option<HashMap<String, String>>,
185}
186
187#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
188pub struct ChatCompletionStreamOptions {
189 pub include_usage: Option<bool>,
191 #[serde(skip_serializing_if = "Option::is_none")]
192 pub continuous_usage_stats: Option<bool>,
193}
194
195#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
196pub struct ChatCompletionToolChoiceFunction {
197 #[serde(skip_serializing_if = "Option::is_none")]
199 pub r#type: Option<ChatCompletionToolType>,
200 pub function: ChatCompletionToolChoiceFunctionName,
202}
203
204#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
205pub struct ChatCompletionToolChoiceFunctionName {
206 pub name: String,
208}
209
210#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
211pub struct ChatCompletionFunction {
212 pub name: String,
214 #[serde(skip_serializing_if = "Option::is_none")]
216 pub description: Option<String>,
217 pub parameters: serde_json::Value,
219}
220
221#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
222#[serde(tag = "type", rename_all = "snake_case")]
223pub enum ChatCompletionResponseFormat {
224 Text,
225 JsonObject,
226 JsonSchema { json_schema: JsonSchema },
227}
228
229#[derive(Serialize, Deserialize, Debug, Default, Builder, Clone, PartialEq)]
230#[builder(name = "JsonSchemaBuilder")]
231#[builder(setter(into, strip_option), default)]
232pub struct JsonSchema {
233 #[serde(skip_serializing_if = "Option::is_none")]
235 description: Option<String>,
236 name: String,
238 #[serde(skip_serializing_if = "Option::is_none")]
240 schema: Option<serde_json::Value>,
241 #[serde(skip_serializing_if = "Option::is_none")]
243 strict: Option<bool>,
244}
245
246#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
247pub struct ChatCompletionTool {
248 pub r#type: ChatCompletionToolType,
250 pub function: ChatCompletionFunction,
252}
253
254#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
255#[serde(tag = "role", rename_all = "snake_case")]
256pub enum ChatMessage {
257 Developer {
258 content: ChatMessageContent,
260 #[serde(skip_serializing_if = "Option::is_none")]
262 name: Option<String>,
263 },
264 System {
265 content: ChatMessageContent,
267 #[serde(skip_serializing_if = "Option::is_none")]
269 name: Option<String>,
270 },
271 User {
272 content: ChatMessageContent,
274 #[serde(skip_serializing_if = "Option::is_none")]
276 name: Option<String>,
277 },
278 Assistant {
279 #[serde(skip_serializing_if = "Option::is_none")]
281 content: Option<ChatMessageContent>,
282 #[serde(skip_serializing_if = "Option::is_none")]
284 reasoning_content: Option<String>,
285 #[serde(skip_serializing_if = "Option::is_none")]
287 refusal: Option<String>,
288 #[serde(skip_serializing_if = "Option::is_none")]
290 name: Option<String>,
291 #[serde(skip_serializing_if = "Option::is_none")]
293 audio: Option<AudioDataIdParameter>,
294 #[serde(skip_serializing_if = "Option::is_none")]
296 tool_calls: Option<Vec<ToolCall>>,
297 },
298 Tool {
299 content: ChatMessageContent,
301 tool_call_id: String,
303 },
304}
305
306impl ChatMessage {
307 pub fn message(&self) -> Option<&ChatMessageContent> {
309 match self {
310 ChatMessage::Developer { content, .. }
311 | ChatMessage::System { content, .. }
312 | ChatMessage::User { content, .. }
313 | ChatMessage::Assistant {
314 content: Some(content),
315 ..
316 } => Some(content),
317 ChatMessage::Assistant { content: None, .. } => None,
318 ChatMessage::Tool { .. } => None,
319 }
320 }
321
322 pub fn text(&self) -> Option<&str> {
324 match self {
325 ChatMessage::Developer { content, .. }
326 | ChatMessage::System { content, .. }
327 | ChatMessage::User { content, .. }
328 | ChatMessage::Tool { content, .. }
329 | ChatMessage::Assistant {
330 content: Some(content),
331 ..
332 } => {
333 if let ChatMessageContent::Text(text) = content {
334 Some(text)
335 } else {
336 None
337 }
338 }
339 ChatMessage::Assistant { content: None, .. } => None,
340 }
341 }
342
343 pub fn name(&self) -> Option<&str> {
345 match self {
346 ChatMessage::Developer { name, .. }
347 | ChatMessage::System { name, .. }
348 | ChatMessage::User { name, .. }
349 | ChatMessage::Assistant { name, .. } => name.as_deref(),
350 ChatMessage::Tool { .. } => None,
351 }
352 }
353}
354
355#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
356#[serde(tag = "role", rename_all = "snake_case")]
357pub enum DeltaChatMessage {
358 Developer {
359 content: ChatMessageContent,
361 #[serde(skip_serializing_if = "Option::is_none")]
363 name: Option<String>,
364 },
365 System {
366 content: ChatMessageContent,
368 #[serde(skip_serializing_if = "Option::is_none")]
370 name: Option<String>,
371 },
372 User {
373 content: ChatMessageContent,
375 #[serde(skip_serializing_if = "Option::is_none")]
377 name: Option<String>,
378 },
379 Assistant {
380 #[serde(skip_serializing_if = "Option::is_none")]
382 content: Option<ChatMessageContent>,
383 #[serde(skip_serializing_if = "Option::is_none")]
385 reasoning_content: Option<String>,
386 #[serde(skip_serializing_if = "Option::is_none")]
388 refusal: Option<String>,
389 #[serde(skip_serializing_if = "Option::is_none")]
391 name: Option<String>,
392 #[serde(skip_serializing_if = "Option::is_none")]
394 tool_calls: Option<Vec<DeltaToolCall>>,
395 },
396 Tool {
397 content: String,
399 tool_call_id: String,
401 },
402 #[serde(untagged)]
403 Untagged {
404 #[serde(skip_serializing_if = "Option::is_none")]
405 content: Option<ChatMessageContent>,
406 #[serde(skip_serializing_if = "Option::is_none")]
407 reasoning_content: Option<String>,
408 #[serde(skip_serializing_if = "Option::is_none")]
409 refusal: Option<String>,
410 #[serde(skip_serializing_if = "Option::is_none")]
411 name: Option<String>,
412 #[serde(skip_serializing_if = "Option::is_none")]
413 tool_calls: Option<Vec<DeltaToolCall>>,
414 #[serde(skip_serializing_if = "Option::is_none")]
415 tool_call_id: Option<String>,
416 },
417}
418
419#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
420pub struct ToolCall {
421 pub id: String,
423 pub r#type: String,
425 pub function: Function,
427}
428
429#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
430pub struct DeltaToolCall {
431 #[serde(skip_serializing_if = "Option::is_none")]
433 pub index: Option<u32>,
434 #[serde(skip_serializing_if = "Option::is_none")]
436 pub id: Option<String>,
437 #[serde(skip_serializing_if = "Option::is_none")]
439 pub r#type: Option<String>,
440 pub function: DeltaFunction,
442}
443
444#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
445pub struct Function {
446 pub name: String,
448 pub arguments: String,
450}
451
452#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
453pub struct DeltaFunction {
454 #[serde(skip_serializing_if = "Option::is_none")]
456 pub name: Option<String>,
457 #[serde(skip_serializing_if = "Option::is_none")]
459 pub arguments: Option<String>,
460}
461
462#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
463pub struct ChatCompletionChoice {
464 pub index: u32,
466 pub message: ChatMessage,
468 #[serde(skip_serializing_if = "Option::is_none")]
470 pub finish_reason: Option<FinishReason>,
471 #[serde(skip_serializing_if = "Option::is_none")]
473 pub logprobs: Option<LogProps>,
474}
475
476#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
477pub struct AudioDataIdParameter {
478 pub id: String,
480}
481
482#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
483pub struct AudioParameters {
484 pub voice: Voice,
486 pub format: AudioFormat,
488}
489
490#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
491pub struct LogProps {
492 #[serde(skip_serializing_if = "Option::is_none")]
494 pub content: Option<Vec<LogPropsContent>>,
495 #[serde(skip_serializing_if = "Option::is_none")]
497 pub refusal: Option<Vec<LogPropsContent>>,
498}
499
500#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
501pub struct LogPropsContent {
502 #[serde(flatten)]
504 pub token_info: LogProbsContentInfo,
505 pub top_logprobs: Vec<LogProbsContentInfo>,
507}
508
509#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
510pub struct LogProbsContentInfo {
511 pub token: String,
513 pub logprob: f32,
516 pub bytes: Option<Vec<u8>>,
518}
519
520#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
521pub struct ChatCompletionChunkChoice {
522 pub index: Option<u32>,
524 pub delta: DeltaChatMessage,
526 #[serde(skip_serializing_if = "Option::is_none")]
528 pub finish_reason: Option<FinishReason>,
529 #[serde(skip_serializing_if = "Option::is_none")]
531 pub logprobs: Option<LogProps>,
532}
533
534#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
535pub struct ImageUrlType {
536 pub url: String,
538 #[serde(skip_serializing_if = "Option::is_none")]
540 pub detail: Option<ImageUrlDetail>,
541}
542
543#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
544pub struct AudioUrlType {
545 pub url: String,
547}
548
549#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
550pub struct VideoUrlType {
551 pub url: String,
553}
554
555#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
556pub struct PredictedOutput {
557 pub r#type: PredictedOutputType,
559 pub content: PredictedOutputContent,
562}
563
564#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
565#[serde(untagged)]
566pub enum PredictedOutputContent {
567 String(String),
568 Array(Vec<PredictedOutputArrayPart>),
569}
570
571#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
572pub struct PredictedOutputArrayPart {
573 pub r#type: String,
575 pub text: String,
577}
578
579#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
580#[serde(rename_all = "snake_case")]
581pub enum PredictedOutputType {
582 Content,
583}
584
585#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
586#[serde(rename_all = "snake_case")]
587pub enum Modality {
588 Text,
589 Audio,
590}
591
592#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
593#[serde(rename_all = "snake_case")]
594pub enum ImageUrlDetail {
595 Auto,
596 High,
597 Low,
598}
599
600#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
601#[serde(untagged)]
602pub enum ChatMessageContent {
603 Text(String),
604 ContentPart(Vec<ChatMessageContentPart>),
605 None,
606}
607
608#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
609#[serde(untagged)]
610pub enum ChatMessageContentPart {
611 Text(ChatMessageTextContentPart),
612 Image(ChatMessageImageContentPart),
613 Audio(ChatMessageAudioContentPart),
614 Video(ChatMessageVideoContentPart),
615}
616
617#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
618pub struct ChatMessageTextContentPart {
619 pub r#type: String,
621 pub text: String,
623}
624
625#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
626pub struct ChatMessageImageContentPart {
627 pub r#type: String,
629 pub image_url: ImageUrlType,
631}
632
633#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
634pub struct ChatMessageAudioContentPart {
635 pub r#type: String,
637 pub audio_url: AudioUrlType,
639}
640
641#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
642pub struct ChatMessageVideoContentPart {
643 pub r#type: String,
645 pub video_url: VideoUrlType,
647}
648
649#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
650pub struct ChatMessageImageUrl {
651 pub url: String,
653 pub detail: String,
655}
656
657#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
658pub struct InputAudioData {
659 pub data: String,
661 pub format: String,
663}
664
665#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
666pub struct WebSearchOptions {
667 #[serde(skip_serializing_if = "Option::is_none")]
669 pub search_context_size: Option<WebSearchContextSize>,
670 #[serde(skip_serializing_if = "Option::is_none")]
672 pub user_location: Option<ApproximateUserLocation>,
673}
674
675#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
676pub struct ApproximateUserLocation {
677 pub r#type: UserLocationType,
678 pub approximate: WebSearchUserLocation,
680}
681
682impl Display for ChatMessageContent {
683 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
684 match self {
685 ChatMessageContent::Text(text) => write!(f, "{text}"),
686 ChatMessageContent::ContentPart(tcp) => {
687 for part in tcp {
688 write!(f, "{part:?}")?;
689 }
690 Ok(())
691 }
692 ChatMessageContent::None => write!(f, ""),
693 }
694 }
695}
696
697#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
698#[serde(rename_all = "snake_case")]
699pub enum ChatCompletionToolType {
700 Function,
701}
702
703#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
704#[serde(rename_all = "snake_case")]
705pub enum ChatCompletionToolChoice {
706 None,
707 Auto,
708 Required,
709 #[serde(untagged)]
710 ChatCompletionToolChoiceFunction(ChatCompletionToolChoiceFunction),
711}
712
713#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
714pub struct WebSearchUserLocation {
715 pub city: Option<String>,
716 pub country: Option<String>,
717 pub region: Option<String>,
718 pub timezone: Option<String>,
719}
720
721#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
722#[serde(rename_all = "snake_case")]
723pub enum UserLocationType {
724 Approximate,
725}
726
727#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
728#[serde(rename_all = "snake_case")]
729pub enum Voice {
730 Alloy,
731 Ash,
732 Ballad,
733 Coral,
734 Echo,
735 Sage,
736 Shimmer,
737 Verse,
738}
739
740#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
741#[serde(rename_all = "snake_case")]
742pub enum AudioFormat {
743 Wav,
744 Mp3,
745 Flac,
746 Opus,
747 Pcm16,
748}
749
750impl Default for ChatMessageContent {
751 fn default() -> Self {
752 ChatMessageContent::Text("".to_string())
753 }
754}
755
756impl DeltaFunction {
757 pub fn merge(&mut self, other: &Self) {
758 if self.name.is_none() && other.name.is_some() {
759 self.name.clone_from(&other.name);
760 }
761
762 if let Some(arguments) = &other.arguments {
763 if let Some(self_arguments) = &mut self.arguments {
764 self_arguments.push_str(arguments);
765 } else {
766 self.arguments = Some(arguments.clone());
767 }
768 }
769 }
770
771 pub fn is_empty(&self) -> bool {
772 self.name.is_none() && self.arguments.is_none()
773 }
774}