1#![allow(clippy::enum_variant_names)]
28
29use serde::{Deserialize, Serialize};
30
31#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
33#[serde(rename_all = "lowercase")]
34pub enum Role {
35 User,
37 Model,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
43#[serde(untagged)]
44pub enum Part {
45 Text {
47 text: String,
49 #[serde(skip_serializing_if = "Option::is_none")]
51 thought: Option<bool>,
52 #[serde(rename = "thoughtSignature", skip_serializing_if = "Option::is_none")]
54 thought_signature: Option<String>,
55 },
56 InlineData {
57 #[serde(rename = "inlineData")]
59 inline_data: Blob,
60 },
61 FunctionCall {
63 #[serde(rename = "functionCall")]
65 function_call: super::tools::FunctionCall,
66 #[serde(rename = "thoughtSignature", skip_serializing_if = "Option::is_none")]
68 thought_signature: Option<String>,
69 },
70 FunctionResponse {
72 #[serde(rename = "functionResponse")]
74 function_response: super::tools::FunctionResponse,
75 },
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
80#[serde(rename_all = "camelCase")]
81pub struct Blob {
82 pub mime_type: String,
84 pub data: String,
86}
87
88impl Blob {
89 pub fn new(mime_type: impl Into<String>, data: impl Into<String>) -> Self {
91 Self {
92 mime_type: mime_type.into(),
93 data: data.into(),
94 }
95 }
96}
97
98#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
100#[serde(rename_all = "camelCase")]
101pub struct Content {
102 #[serde(skip_serializing_if = "Option::is_none")]
104 pub parts: Option<Vec<Part>>,
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub role: Option<Role>,
108}
109
110impl Content {
111 pub fn text(text: impl Into<String>) -> Self {
113 Self {
114 parts: Some(vec![Part::Text {
115 text: text.into(),
116 thought: None,
117 thought_signature: None,
118 }]),
119 role: None,
120 }
121 }
122
123 pub fn function_call(function_call: super::tools::FunctionCall) -> Self {
125 Self {
126 parts: Some(vec![Part::FunctionCall {
127 function_call,
128 thought_signature: None,
129 }]),
130 role: None,
131 }
132 }
133
134 pub fn function_call_with_thought(
136 function_call: super::tools::FunctionCall,
137 thought_signature: impl Into<String>,
138 ) -> Self {
139 Self {
140 parts: Some(vec![Part::FunctionCall {
141 function_call,
142 thought_signature: Some(thought_signature.into()),
143 }]),
144 role: None,
145 }
146 }
147
148 pub fn text_with_thought_signature(
150 text: impl Into<String>,
151 thought_signature: impl Into<String>,
152 ) -> Self {
153 Self {
154 parts: Some(vec![Part::Text {
155 text: text.into(),
156 thought: None,
157 thought_signature: Some(thought_signature.into()),
158 }]),
159 role: None,
160 }
161 }
162
163 pub fn thought_with_signature(
165 text: impl Into<String>,
166 thought_signature: impl Into<String>,
167 ) -> Self {
168 Self {
169 parts: Some(vec![Part::Text {
170 text: text.into(),
171 thought: Some(true),
172 thought_signature: Some(thought_signature.into()),
173 }]),
174 role: None,
175 }
176 }
177
178 pub fn function_response(function_response: super::tools::FunctionResponse) -> Self {
180 Self {
181 parts: Some(vec![Part::FunctionResponse { function_response }]),
182 role: None,
183 }
184 }
185
186 pub fn function_response_json(name: impl Into<String>, response: serde_json::Value) -> Self {
188 Self {
189 parts: Some(vec![Part::FunctionResponse {
190 function_response: super::tools::FunctionResponse::new(name, response),
191 }]),
192 role: None,
193 }
194 }
195
196 pub fn inline_data(mime_type: impl Into<String>, data: impl Into<String>) -> Self {
198 Self {
199 parts: Some(vec![Part::InlineData {
200 inline_data: Blob::new(mime_type, data),
201 }]),
202 role: None,
203 }
204 }
205
206 pub fn with_role(mut self, role: Role) -> Self {
208 self.role = Some(role);
209 self
210 }
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct Message {
216 pub content: Content,
218 pub role: Role,
220}
221
222impl Message {
223 pub fn user(text: impl Into<String>) -> Self {
225 Self {
226 content: Content::text(text).with_role(Role::User),
227 role: Role::User,
228 }
229 }
230
231 pub fn model(text: impl Into<String>) -> Self {
233 Self {
234 content: Content::text(text).with_role(Role::Model),
235 role: Role::Model,
236 }
237 }
238
239 pub fn embed(text: impl Into<String>) -> Self {
241 Self {
242 content: Content::text(text),
243 role: Role::Model,
244 }
245 }
246
247 pub fn function(name: impl Into<String>, response: serde_json::Value) -> Self {
249 Self {
250 content: Content::function_response_json(name, response).with_role(Role::Model),
251 role: Role::Model,
252 }
253 }
254
255 pub fn function_str(
257 name: impl Into<String>,
258 response: impl Into<String>,
259 ) -> Result<Self, serde_json::Error> {
260 let response_str = response.into();
261 let json = serde_json::from_str(&response_str)?;
262 Ok(Self {
263 content: Content::function_response_json(name, json).with_role(Role::Model),
264 role: Role::Model,
265 })
266 }
267}
268
269#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
271#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
272pub enum Modality {
273 ModalityUnspecified,
275 Text,
277 Image,
279 Audio,
281 Video,
283}