1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
5#[serde(rename_all = "lowercase")]
6pub enum Role {
7 User,
9 Model,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
15#[serde(untagged)]
16pub enum Part {
17 Text {
19 text: String,
21 },
22 FunctionCall {
24 #[serde(rename = "functionCall")]
26 function_call: super::tools::FunctionCall,
27 },
28 FunctionResponse {
30 #[serde(rename = "functionResponse")]
32 function_response: super::tools::FunctionResponse,
33 },
34}
35
36#[derive(Debug, Default, Clone, Serialize, Deserialize)]
38pub struct Content {
39 pub parts: Vec<Part>,
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub role: Option<Role>,
44}
45
46impl Content {
47 pub fn text(text: impl Into<String>) -> Self {
49 Self {
50 parts: vec![Part::Text { text: text.into() }],
51 role: None,
52 }
53 }
54
55 pub fn function_call(function_call: super::tools::FunctionCall) -> Self {
57 Self {
58 parts: vec![Part::FunctionCall { function_call }],
59 role: None,
60 }
61 }
62
63 pub fn function_response(function_response: super::tools::FunctionResponse) -> Self {
65 Self {
66 parts: vec![Part::FunctionResponse { function_response }],
67 role: None,
68 }
69 }
70
71 pub fn function_response_json(name: impl Into<String>, response: serde_json::Value) -> Self {
73 Self {
74 parts: vec![Part::FunctionResponse {
75 function_response: super::tools::FunctionResponse::new(name, response),
76 }],
77 role: None,
78 }
79 }
80
81 pub fn with_role(mut self, role: Role) -> Self {
83 self.role = Some(role);
84 self
85 }
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct Message {
91 pub content: Content,
93 pub role: Role,
95}
96
97impl Message {
98 pub fn user(text: impl Into<String>) -> Self {
100 Self {
101 content: Content::text(text).with_role(Role::User),
102 role: Role::User,
103 }
104 }
105
106 pub fn model(text: impl Into<String>) -> Self {
108 Self {
109 content: Content::text(text).with_role(Role::Model),
110 role: Role::Model,
111 }
112 }
113
114 pub fn function(name: impl Into<String>, response: serde_json::Value) -> Self {
116 Self {
117 content: Content::function_response_json(name, response).with_role(Role::Model),
118 role: Role::Model,
119 }
120 }
121
122 pub fn function_str(
124 name: impl Into<String>,
125 response: impl Into<String>,
126 ) -> Result<Self, serde_json::Error> {
127 let response_str = response.into();
128 let json = serde_json::from_str(&response_str)?;
129 Ok(Self {
130 content: Content::function_response_json(name, json).with_role(Role::Model),
131 role: Role::Model,
132 })
133 }
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct SafetyRating {
139 pub category: String,
141 pub probability: String,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct CitationMetadata {
148 pub citation_sources: Vec<CitationSource>,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct CitationSource {
155 pub uri: Option<String>,
157 pub title: Option<String>,
159 pub start_index: Option<i32>,
161 pub end_index: Option<i32>,
163 pub license: Option<String>,
165 pub publication_date: Option<String>,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct Candidate {
172 pub content: Content,
174 #[serde(skip_serializing_if = "Option::is_none")]
176 pub safety_ratings: Option<Vec<SafetyRating>>,
177 #[serde(skip_serializing_if = "Option::is_none")]
179 pub citation_metadata: Option<CitationMetadata>,
180 #[serde(skip_serializing_if = "Option::is_none")]
182 pub finish_reason: Option<String>,
183 #[serde(skip_serializing_if = "Option::is_none")]
185 pub usage_metadata: Option<UsageMetadata>,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize)]
190pub struct UsageMetadata {
191 pub prompt_token_count: i32,
193 pub candidates_token_count: i32,
195 pub total_token_count: i32,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize)]
201pub struct GenerationResponse {
202 pub candidates: Vec<Candidate>,
204 #[serde(skip_serializing_if = "Option::is_none")]
206 pub prompt_feedback: Option<PromptFeedback>,
207 #[serde(skip_serializing_if = "Option::is_none")]
209 pub usage_metadata: Option<UsageMetadata>,
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct PromptFeedback {
215 pub safety_ratings: Vec<SafetyRating>,
217 #[serde(skip_serializing_if = "Option::is_none")]
219 pub block_reason: Option<String>,
220}
221
222impl GenerationResponse {
223 pub fn text(&self) -> String {
225 self.candidates
226 .first()
227 .and_then(|c| {
228 c.content.parts.first().and_then(|p| match p {
229 Part::Text { text } => Some(text.clone()),
230 _ => None,
231 })
232 })
233 .unwrap_or_default()
234 }
235
236 pub fn function_calls(&self) -> Vec<&super::tools::FunctionCall> {
238 self.candidates
239 .iter()
240 .flat_map(|c| {
241 c.content.parts.iter().filter_map(|p| match p {
242 Part::FunctionCall { function_call } => Some(function_call),
243 _ => None,
244 })
245 })
246 .collect()
247 }
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize)]
252pub struct GenerateContentRequest {
253 pub contents: Vec<Content>,
255 #[serde(skip_serializing_if = "Option::is_none")]
257 pub generation_config: Option<GenerationConfig>,
258 #[serde(skip_serializing_if = "Option::is_none")]
260 pub safety_settings: Option<Vec<SafetySetting>>,
261 #[serde(skip_serializing_if = "Option::is_none")]
263 pub tools: Option<Vec<super::tools::Tool>>,
264 #[serde(skip_serializing_if = "Option::is_none")]
266 pub tool_config: Option<ToolConfig>,
267 #[serde(skip_serializing_if = "Option::is_none")]
269 pub system_instruction: Option<Content>,
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize)]
274pub struct GenerationConfig {
275 #[serde(skip_serializing_if = "Option::is_none")]
280 pub temperature: Option<f32>,
281
282 #[serde(skip_serializing_if = "Option::is_none")]
288 pub top_p: Option<f32>,
289
290 #[serde(skip_serializing_if = "Option::is_none")]
295 pub top_k: Option<i32>,
296
297 #[serde(skip_serializing_if = "Option::is_none")]
301 pub max_output_tokens: Option<i32>,
302
303 #[serde(skip_serializing_if = "Option::is_none")]
307 pub candidate_count: Option<i32>,
308
309 #[serde(skip_serializing_if = "Option::is_none")]
313 pub stop_sequences: Option<Vec<String>>,
314
315 #[serde(skip_serializing_if = "Option::is_none")]
319 pub response_mime_type: Option<String>,
320
321 #[serde(skip_serializing_if = "Option::is_none")]
325 pub response_schema: Option<serde_json::Value>,
326}
327
328impl Default for GenerationConfig {
329 fn default() -> Self {
330 Self {
331 temperature: Some(0.7),
332 top_p: Some(0.95),
333 top_k: Some(40),
334 max_output_tokens: Some(1024),
335 candidate_count: Some(1),
336 stop_sequences: None,
337 response_mime_type: None,
338 response_schema: None,
339 }
340 }
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize)]
345pub struct ToolConfig {
346 #[serde(skip_serializing_if = "Option::is_none")]
348 pub function_calling_config: Option<FunctionCallingConfig>,
349}
350
351#[derive(Debug, Clone, Serialize, Deserialize)]
353pub struct FunctionCallingConfig {
354 pub mode: FunctionCallingMode,
356}
357
358#[derive(Debug, Clone, Serialize, Deserialize)]
360#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
361pub enum FunctionCallingMode {
362 Auto,
364 Any,
366 None,
368}
369
370#[derive(Debug, Clone, Serialize, Deserialize)]
372pub struct SafetySetting {
373 pub category: HarmCategory,
375 pub threshold: HarmBlockThreshold,
377}
378
379#[derive(Debug, Clone, Serialize, Deserialize)]
381#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
382pub enum HarmCategory {
383 Dangerous,
385 Harassment,
387 HateSpeech,
389 SexuallyExplicit,
391}
392
393#[allow(clippy::enum_variant_names)]
395#[derive(Debug, Clone, Serialize, Deserialize)]
396#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
397pub enum HarmBlockThreshold {
398 BlockLowAndAbove,
400 BlockMediumAndAbove,
402 BlockHighAndAbove,
404 BlockOnlyHigh,
406 BlockNone,
408}