1use serde::{Deserialize, Serialize};
2use serde_json::Value as JsonValue;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub enum Content {
7 #[serde(rename = "text")]
8 Text(String),
9 #[serde(rename = "json")]
11 Json(JsonValue),
12 #[serde(rename = "image")]
14 Image {
15 url: Option<String>,
16 mime: Option<String>,
17 name: Option<String>,
18 },
19 #[serde(rename = "audio")]
21 Audio {
22 url: Option<String>,
23 mime: Option<String>,
24 },
25}
26
27impl Content {
28 pub fn as_text(&self) -> String {
30 match self {
31 Content::Text(s) => s.clone(),
32 Content::Json(v) => v.to_string(),
33 Content::Image { url, .. } => url.clone().unwrap_or_default(),
34 Content::Audio { url, .. } => url.clone().unwrap_or_default(),
35 }
36 }
37
38 pub fn new_text<S: Into<String>>(s: S) -> Self {
40 Content::Text(s.into())
41 }
42
43 pub fn new_json(v: JsonValue) -> Self {
45 Content::Json(v)
46 }
47
48 pub fn new_image(url: Option<String>, mime: Option<String>, name: Option<String>) -> Self {
50 Content::Image { url, mime, name }
51 }
52
53 pub fn new_audio(url: Option<String>, mime: Option<String>) -> Self {
55 Content::Audio { url, mime }
56 }
57
58 pub fn from_image_file<P: AsRef<std::path::Path>>(path: P) -> Self {
61 let path = path.as_ref();
62 let name = path
63 .file_name()
64 .and_then(|n| n.to_str())
65 .map(|s| s.to_string());
66 let mime = path
67 .extension()
68 .and_then(|ext| ext.to_str())
69 .and_then(|ext| match ext.to_lowercase().as_str() {
70 "png" => Some("image/png"),
71 "jpg" | "jpeg" => Some("image/jpeg"),
72 "gif" => Some("image/gif"),
73 "webp" => Some("image/webp"),
74 "svg" => Some("image/svg+xml"),
75 _ => None,
76 })
77 .map(|s| s.to_string());
78
79 Content::Image {
80 url: None, mime,
82 name,
83 }
84 }
85
86 pub fn from_audio_file<P: AsRef<std::path::Path>>(path: P) -> Self {
89 let path = path.as_ref();
90 let mime = path
91 .extension()
92 .and_then(|ext| ext.to_str())
93 .and_then(|ext| match ext.to_lowercase().as_str() {
94 "mp3" => Some("audio/mpeg"),
95 "wav" => Some("audio/wav"),
96 "ogg" => Some("audio/ogg"),
97 "m4a" => Some("audio/mp4"),
98 "flac" => Some("audio/flac"),
99 _ => None,
100 })
101 .map(|s| s.to_string());
102
103 Content::Audio {
104 url: None, mime,
106 }
107 }
108
109 pub fn from_data_url(data_url: String, mime: Option<String>, name: Option<String>) -> Self {
111 Content::Image {
112 url: Some(data_url),
113 mime,
114 name,
115 }
116 }
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct Message {
121 pub role: Role,
122 pub content: Content,
123 pub function_call: Option<crate::types::function_call::FunctionCall>,
125}
126
127impl Message {
128 pub fn new(role: Role, content: impl Into<Content>) -> Self {
130 Self {
131 role,
132 content: content.into(),
133 function_call: None,
134 }
135 }
136
137 pub fn user<S: Into<String>>(text: S) -> Self {
147 Self {
148 role: Role::User,
149 content: Content::Text(text.into()),
150 function_call: None,
151 }
152 }
153
154 pub fn assistant<S: Into<String>>(text: S) -> Self {
164 Self {
165 role: Role::Assistant,
166 content: Content::Text(text.into()),
167 function_call: None,
168 }
169 }
170
171 pub fn system<S: Into<String>>(text: S) -> Self {
181 Self {
182 role: Role::System,
183 content: Content::Text(text.into()),
184 function_call: None,
185 }
186 }
187
188 pub fn user_with_content(content: Content) -> Self {
197 Self {
198 role: Role::User,
199 content,
200 function_call: None,
201 }
202 }
203
204 pub fn assistant_with_function_call(
206 text: impl Into<String>,
207 function_call: crate::types::function_call::FunctionCall,
208 ) -> Self {
209 Self {
210 role: Role::Assistant,
211 content: Content::Text(text.into()),
212 function_call: Some(function_call),
213 }
214 }
215}
216
217impl From<String> for Content {
219 fn from(s: String) -> Self {
220 Content::Text(s)
221 }
222}
223
224impl From<&str> for Content {
226 fn from(s: &str) -> Self {
227 Content::Text(s.to_string())
228 }
229}
230
231#[derive(Debug, Clone, Serialize, Deserialize)]
232pub enum Role {
233 #[serde(rename = "system")]
234 System,
235 #[serde(rename = "user")]
236 User,
237 #[serde(rename = "assistant")]
238 Assistant,
239}
240
241#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct Choice {
243 pub index: u32,
244 pub message: Message,
245 pub finish_reason: Option<String>,
246}
247
248