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.file_name()
63 .and_then(|n| n.to_str())
64 .map(|s| s.to_string());
65 let mime = path.extension()
66 .and_then(|ext| ext.to_str())
67 .and_then(|ext| match ext.to_lowercase().as_str() {
68 "png" => Some("image/png"),
69 "jpg" | "jpeg" => Some("image/jpeg"),
70 "gif" => Some("image/gif"),
71 "webp" => Some("image/webp"),
72 "svg" => Some("image/svg+xml"),
73 _ => None,
74 })
75 .map(|s| s.to_string());
76
77 Content::Image {
78 url: None, mime,
80 name,
81 }
82 }
83
84 pub fn from_audio_file<P: AsRef<std::path::Path>>(path: P) -> Self {
87 let path = path.as_ref();
88 let mime = path.extension()
89 .and_then(|ext| ext.to_str())
90 .and_then(|ext| match ext.to_lowercase().as_str() {
91 "mp3" => Some("audio/mpeg"),
92 "wav" => Some("audio/wav"),
93 "ogg" => Some("audio/ogg"),
94 "m4a" => Some("audio/mp4"),
95 "flac" => Some("audio/flac"),
96 _ => None,
97 })
98 .map(|s| s.to_string());
99
100 Content::Audio {
101 url: None, mime,
103 }
104 }
105
106 pub fn from_data_url(data_url: String, mime: Option<String>, name: Option<String>) -> Self {
108 Content::Image {
109 url: Some(data_url),
110 mime,
111 name,
112 }
113 }
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct Message {
118 pub role: Role,
119 pub content: Content,
120 pub function_call: Option<crate::types::function_call::FunctionCall>,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub enum Role {
126 #[serde(rename = "system")]
127 System,
128 #[serde(rename = "user")]
129 User,
130 #[serde(rename = "assistant")]
131 Assistant,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct Choice {
136 pub index: u32,
137 pub message: Message,
138 pub finish_reason: Option<String>,
139}
140
141#[deprecated(note = "Usage has been moved to `ai_lib::types::response::Usage`. Please import from there or use `ai_lib::Usage`. This alias will be removed before 1.0.")]
146pub use crate::types::response::Usage;
147
148#[deprecated(note = "UsageStatus has been moved to `ai_lib::types::response::UsageStatus`. Please import from there or use `ai_lib::UsageStatus`. This alias will be removed before 1.0.")]
149pub use crate::types::response::UsageStatus;