1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5use super::common::{
6 AssistantMessage, ChatCompletionTool, Message, ResponseFormat, StopSequence, ToolChoice, ToolType, Usage,
7};
8use crate::cost;
9
10#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "snake_case")]
15pub enum FinishReason {
16 #[default]
17 Stop,
18 Length,
19 ToolCalls,
20 ContentFilter,
21 #[serde(rename = "function_call")]
23 FunctionCall,
24 #[serde(other)]
32 Other,
33}
34
35#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
39#[serde(rename_all = "lowercase")]
40pub enum ReasoningEffort {
41 Low,
42 #[default]
43 Medium,
44 High,
45}
46
47#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
50#[serde(deny_unknown_fields)]
51pub struct ChatCompletionRequest {
52 pub model: String,
53 pub messages: Vec<Message>,
54 #[serde(default, skip_serializing_if = "Option::is_none")]
55 pub temperature: Option<f64>,
56 #[serde(default, skip_serializing_if = "Option::is_none")]
57 pub top_p: Option<f64>,
58 #[serde(default, skip_serializing_if = "Option::is_none")]
59 pub n: Option<u32>,
60 #[serde(default, skip_serializing_if = "Option::is_none")]
64 pub stream: Option<bool>,
65 #[serde(default, skip_serializing_if = "Option::is_none")]
66 pub stop: Option<StopSequence>,
67 #[serde(default, skip_serializing_if = "Option::is_none")]
68 pub max_tokens: Option<u64>,
69 #[serde(default, skip_serializing_if = "Option::is_none")]
70 pub presence_penalty: Option<f64>,
71 #[serde(default, skip_serializing_if = "Option::is_none")]
72 pub frequency_penalty: Option<f64>,
73 #[serde(default, skip_serializing_if = "Option::is_none")]
74 pub logit_bias: Option<BTreeMap<String, f64>>,
77 #[serde(default, skip_serializing_if = "Option::is_none")]
78 pub user: Option<String>,
79 #[serde(default, skip_serializing_if = "Option::is_none")]
80 pub tools: Option<Vec<ChatCompletionTool>>,
81 #[serde(default, skip_serializing_if = "Option::is_none")]
82 pub tool_choice: Option<ToolChoice>,
83 #[serde(default, skip_serializing_if = "Option::is_none")]
84 pub parallel_tool_calls: Option<bool>,
85 #[serde(default, skip_serializing_if = "Option::is_none")]
86 pub response_format: Option<ResponseFormat>,
87 #[serde(default, skip_serializing_if = "Option::is_none")]
88 pub stream_options: Option<StreamOptions>,
89 #[serde(default, skip_serializing_if = "Option::is_none")]
90 pub seed: Option<i64>,
91 #[serde(default, skip_serializing_if = "Option::is_none")]
92 pub reasoning_effort: Option<ReasoningEffort>,
93 #[serde(default, skip_serializing_if = "Option::is_none")]
96 pub extra_body: Option<serde_json::Value>,
97}
98
99#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
100#[serde(deny_unknown_fields)]
101pub struct StreamOptions {
102 #[serde(default, skip_serializing_if = "Option::is_none")]
103 pub include_usage: Option<bool>,
104}
105
106#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
109pub struct ChatCompletionResponse {
110 pub id: String,
111 pub object: String,
114 pub created: u64,
115 pub model: String,
116 pub choices: Vec<Choice>,
117 #[serde(default, skip_serializing_if = "Option::is_none")]
118 pub usage: Option<Usage>,
119 #[serde(default, skip_serializing_if = "Option::is_none")]
120 pub system_fingerprint: Option<String>,
121 #[serde(default, skip_serializing_if = "Option::is_none")]
122 pub service_tier: Option<String>,
123}
124
125impl ChatCompletionResponse {
126 #[must_use]
141 pub fn estimated_cost(&self) -> Option<f64> {
142 let usage = self.usage.as_ref()?;
143 cost::completion_cost(&self.model, usage.prompt_tokens, usage.completion_tokens)
144 }
145}
146
147#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
148pub struct Choice {
149 pub index: u32,
150 pub message: AssistantMessage,
151 pub finish_reason: Option<FinishReason>,
152}
153
154#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
157pub struct ChatCompletionChunk {
158 pub id: String,
159 pub object: String,
162 pub created: u64,
163 pub model: String,
164 pub choices: Vec<StreamChoice>,
165 #[serde(default, skip_serializing_if = "Option::is_none")]
166 pub usage: Option<Usage>,
167 #[serde(default, skip_serializing_if = "Option::is_none")]
168 pub system_fingerprint: Option<String>,
169 #[serde(default, skip_serializing_if = "Option::is_none")]
170 pub service_tier: Option<String>,
171}
172
173#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
174pub struct StreamChoice {
175 pub index: u32,
176 pub delta: StreamDelta,
177 pub finish_reason: Option<FinishReason>,
178}
179
180#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
181pub struct StreamDelta {
182 #[serde(default, skip_serializing_if = "Option::is_none")]
183 pub role: Option<String>,
184 #[serde(default, skip_serializing_if = "Option::is_none")]
185 pub content: Option<String>,
186 #[serde(default, skip_serializing_if = "Option::is_none")]
187 pub tool_calls: Option<Vec<StreamToolCall>>,
188 #[serde(default, skip_serializing_if = "Option::is_none")]
190 pub function_call: Option<StreamFunctionCall>,
191 #[serde(default, skip_serializing_if = "Option::is_none")]
192 pub refusal: Option<String>,
193}
194
195#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
196pub struct StreamToolCall {
197 pub index: u32,
198 #[serde(default, skip_serializing_if = "Option::is_none")]
199 pub id: Option<String>,
200 #[serde(default, skip_serializing_if = "Option::is_none", rename = "type")]
201 pub call_type: Option<ToolType>,
202 #[serde(default, skip_serializing_if = "Option::is_none")]
203 pub function: Option<StreamFunctionCall>,
204}
205
206#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
207pub struct StreamFunctionCall {
208 #[serde(default, skip_serializing_if = "Option::is_none")]
209 pub name: Option<String>,
210 #[serde(default, skip_serializing_if = "Option::is_none")]
211 pub arguments: Option<String>,
212}