1use serde::{Deserialize, Serialize};
4
5use super::tools::ToolCall;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct Message {
10 pub role: String,
12
13 #[serde(skip_serializing_if = "Option::is_none")]
15 pub content: Option<String>,
16
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub name: Option<String>,
20
21 #[serde(skip_serializing_if = "Option::is_none")]
23 pub tool_calls: Option<Vec<ToolCall>>,
24
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub tool_call_id: Option<String>,
28}
29
30impl Message {
31 pub fn user(content: impl Into<String>) -> Self {
33 Self {
34 role: "user".to_string(),
35 content: Some(content.into()),
36 name: None,
37 tool_calls: None,
38 tool_call_id: None,
39 }
40 }
41
42 pub fn system(content: impl Into<String>) -> Self {
44 Self {
45 role: "system".to_string(),
46 content: Some(content.into()),
47 name: None,
48 tool_calls: None,
49 tool_call_id: None,
50 }
51 }
52
53 pub fn assistant(content: impl Into<String>) -> Self {
55 Self {
56 role: "assistant".to_string(),
57 content: Some(content.into()),
58 name: None,
59 tool_calls: None,
60 tool_call_id: None,
61 }
62 }
63
64 pub fn tool(tool_call_id: impl Into<String>, content: impl Into<String>) -> Self {
66 Self {
67 role: "tool".to_string(),
68 content: Some(content.into()),
69 name: None,
70 tool_calls: None,
71 tool_call_id: Some(tool_call_id.into()),
72 }
73 }
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct Usage {
79 pub prompt_tokens: u32,
81
82 pub completion_tokens: u32,
84
85 pub total_tokens: u32,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct Choice {
92 pub index: u32,
94
95 pub message: Message,
97
98 #[serde(skip_serializing_if = "Option::is_none")]
100 pub finish_reason: Option<String>,
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct ChatCompletion {
106 pub id: String,
108
109 pub object: String,
111
112 pub created: i64,
114
115 pub model: String,
117
118 pub choices: Vec<Choice>,
120
121 #[serde(skip_serializing_if = "Option::is_none")]
123 pub usage: Option<Usage>,
124}
125
126impl ChatCompletion {
127 pub fn content(&self) -> Option<&str> {
129 self.choices
130 .first()
131 .and_then(|c| c.message.content.as_deref())
132 }
133
134 pub fn message(&self) -> Option<&Message> {
136 self.choices.first().map(|c| &c.message)
137 }
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize, Default)]
144pub struct ChoiceDelta {
145 #[serde(skip_serializing_if = "Option::is_none")]
147 pub role: Option<String>,
148
149 #[serde(skip_serializing_if = "Option::is_none")]
151 pub content: Option<String>,
152
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub tool_calls: Option<Vec<ToolCall>>,
156}
157
158#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct StreamChoice {
161 pub index: u32,
163
164 pub delta: ChoiceDelta,
166
167 #[serde(skip_serializing_if = "Option::is_none")]
169 pub finish_reason: Option<String>,
170}
171
172#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct ChatCompletionChunk {
175 pub id: String,
177
178 pub object: String,
180
181 pub created: i64,
183
184 pub model: String,
186
187 pub choices: Vec<StreamChoice>,
189}
190
191impl ChatCompletionChunk {
192 pub fn content(&self) -> Option<&str> {
194 self.choices
195 .first()
196 .and_then(|c| c.delta.content.as_deref())
197 }
198}
199
200#[derive(Debug, Clone, Serialize)]
204pub struct ChatCompletionRequest {
205 pub model: String,
207
208 pub messages: Vec<Message>,
210
211 #[serde(skip_serializing_if = "Option::is_none")]
213 pub temperature: Option<f32>,
214
215 #[serde(skip_serializing_if = "Option::is_none")]
217 pub max_tokens: Option<u32>,
218
219 #[serde(skip_serializing_if = "Option::is_none")]
221 pub stream: Option<bool>,
222
223 #[serde(skip_serializing_if = "Option::is_none")]
225 pub tools: Option<Vec<super::tools::ToolDefinition>>,
226
227 #[serde(skip_serializing_if = "Option::is_none")]
229 pub top_p: Option<f32>,
230
231 #[serde(skip_serializing_if = "Option::is_none")]
233 pub stop: Option<Vec<String>>,
234
235 #[serde(skip_serializing_if = "Option::is_none")]
237 pub presence_penalty: Option<f32>,
238
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub frequency_penalty: Option<f32>,
242
243 #[serde(skip_serializing_if = "Option::is_none")]
245 pub user: Option<String>,
246
247 #[serde(skip_serializing_if = "Option::is_none")]
258 pub metadata: Option<std::collections::HashMap<String, serde_json::Value>>,
259}
260
261impl ChatCompletionRequest {
262 pub fn new(model: impl Into<String>, messages: Vec<Message>) -> Self {
264 Self {
265 model: model.into(),
266 messages,
267 temperature: None,
268 max_tokens: None,
269 stream: None,
270 tools: None,
271 top_p: None,
272 stop: None,
273 presence_penalty: None,
274 frequency_penalty: None,
275 user: None,
276 metadata: None,
277 }
278 }
279
280 pub fn metadata(
284 mut self,
285 metadata: std::collections::HashMap<String, serde_json::Value>,
286 ) -> Self {
287 self.metadata = Some(metadata);
288 self
289 }
290
291 pub fn temperature(mut self, temperature: f32) -> Self {
293 self.temperature = Some(temperature);
294 self
295 }
296
297 pub fn max_tokens(mut self, max_tokens: u32) -> Self {
299 self.max_tokens = Some(max_tokens);
300 self
301 }
302
303 pub fn stream(mut self, stream: bool) -> Self {
305 self.stream = Some(stream);
306 self
307 }
308
309 pub fn tools(mut self, tools: Vec<super::tools::ToolDefinition>) -> Self {
311 self.tools = Some(tools);
312 self
313 }
314}