use serde::{Deserialize, Serialize};
use crate::types::{Acceleration, Image};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ChatCompletionContent {
Text(String),
Parts(Vec<ChatCompletionContentPart>),
}
impl ChatCompletionContent {
pub fn flatten(&self) -> String {
match self {
Self::Text(text) => text.clone(),
Self::Parts(parts) => parts
.iter()
.filter_map(|part| match part {
ChatCompletionContentPart::Text { text } => Some(text.as_str()),
ChatCompletionContentPart::Refusal { refusal } => Some(refusal.as_str()),
_ => None,
})
.collect::<Vec<_>>()
.join("\n"),
}
}
pub fn is_text(&self) -> bool {
match self {
Self::Text(_) => true,
Self::Parts(parts) => parts.iter().all(|part| matches!(
part,
ChatCompletionContentPart::Text { .. } |
ChatCompletionContentPart::Refusal { .. }
)),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ChatCompletionContentPart {
Text {
text: String,
},
ImageUrl {
image_url: ChatCompletionContentPartImageUrl,
},
InputAudio {
input_audio: ChatCompletionContentPartInputAudio,
},
File {
file: ChatCompletionContentPartFile,
},
Refusal {
refusal: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletionContentPartImageUrl {
pub url: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub detail: Option<ChatCompletionImageDetail>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ChatCompletionImageDetail {
Auto,
Low,
High,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletionContentPartInputAudio {
pub data: String,
pub format: ChatCompletionInputAudioFormat,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ChatCompletionInputAudioFormat {
Wav,
Mp3,
}
impl ChatCompletionInputAudioFormat {
pub fn as_str(self) -> &'static str {
match self {
Self::Wav => "wav",
Self::Mp3 => "mp3",
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ChatCompletionContentPartFile {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub file_data: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub file_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub filename: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionDefinition {
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parameters: Option<serde_json::Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub strict: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletionFunctionTool {
pub r#type: String,
pub function: FunctionDefinition,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletionMessageFunctionToolCall {
pub id: String,
pub r#type: String,
pub function: ChatCompletionToolCallFunction,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletionToolCallFunction {
pub name: String,
pub arguments: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChoiceDeltaToolCall {
pub index: usize,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub r#type: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub function: Option<ChoiceDeltaToolCallFunction>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ChoiceDeltaToolCallFunction {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub arguments: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ChatCompletionToolChoice {
Auto,
None,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletionMessage {
pub role: String,
#[serde(default)]
pub content: Option<ChatCompletionContent>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reasoning_content: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tool_calls: Option<Vec<ChatCompletionMessageFunctionToolCall>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tool_call_id: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PromptTokensDetails {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub audio_tokens: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cache_write_tokens: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cached_tokens: Option<u64>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CompletionTokensDetails {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reasoning_tokens: Option<u64>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ChatCompletionUsage {
pub prompt_tokens: u64,
pub completion_tokens: u64,
pub total_tokens: u64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub prompt_tokens_details: Option<PromptTokensDetails>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub completion_tokens_details: Option<CompletionTokensDetails>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletionChoice {
pub index: usize,
pub message: ChatCompletionMessage,
#[serde(default)]
pub finish_reason: Option<String>,
#[serde(default)]
pub logprobs: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletion {
pub object: String,
pub id: String,
pub model: String,
pub choices: Vec<ChatCompletionChoice>,
pub created: u64,
#[serde(default)]
pub usage: Option<ChatCompletionUsage>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ChatCompletionDelta {
#[serde(default)]
pub role: Option<String>,
#[serde(default)]
pub content: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reasoning_content: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tool_calls: Option<Vec<ChoiceDeltaToolCall>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletionChunkChoice {
pub index: usize,
#[serde(default)]
pub delta: Option<ChatCompletionDelta>,
#[serde(default)]
pub finish_reason: Option<String>,
#[serde(default)]
pub logprobs: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletionChunk {
pub object: String,
pub id: String,
pub model: String,
pub choices: Vec<ChatCompletionChunkChoice>,
pub created: u64,
#[serde(default)]
pub usage: Option<ChatCompletionUsage>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ChatCompletionReasoningEffort {
#[serde(rename = "minimal")]
Minimal,
#[serde(rename = "low")]
Low,
#[serde(rename = "medium")]
Medium,
#[serde(rename = "high")]
High,
#[serde(rename = "xhigh")]
XHigh,
}
impl ChatCompletionReasoningEffort {
pub fn as_str(self) -> &'static str {
match self {
Self::Minimal => "minimal",
Self::Low => "low",
Self::Medium => "medium",
Self::High => "high",
Self::XHigh => "xhigh",
}
}
}
#[derive(Debug, Clone, Default)]
pub struct ChatCompletionCreateParams {
pub model: String,
pub messages: Vec<ChatCompletionMessage>,
pub tools: Option<Vec<ChatCompletionFunctionTool>>,
pub tool_choice: Option<ChatCompletionToolChoice>,
pub response_format: Option<serde_json::Map<String, serde_json::Value>>,
pub reasoning_effort: Option<ChatCompletionReasoningEffort>,
pub max_completion_tokens: Option<i32>,
pub temperature: Option<f32>,
pub top_p: Option<f32>,
pub frequency_penalty: Option<f32>,
pub presence_penalty: Option<f32>,
pub acceleration: Option<Acceleration>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum EmbeddingData {
Float(Vec<f32>),
Base64(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Embedding {
pub object: String,
pub embedding: EmbeddingData,
pub index: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmbeddingUsage {
pub prompt_tokens: u64,
pub total_tokens: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmbeddingCreateResponse {
pub object: String,
pub model: String,
pub data: Vec<Embedding>,
pub usage: EmbeddingUsage,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageData {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub b64_json: Option<String>,
#[serde(skip)]
pub image: Option<Image>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageUsage {
pub input_tokens: u64,
pub output_tokens: u64,
pub total_tokens: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageResponse {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub data: Option<Vec<ImageData>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub background: Option<String>,
pub created: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub usage: Option<ImageUsage>,
}