gemini_rust/
content_builder.rs1use std::{pin::Pin, sync::Arc};
2
3use futures::Stream;
4
5use crate::{
6 client::GeminiClient,
7 models::{FunctionCallingConfig, GenerateContentRequest, ThinkingConfig, ToolConfig},
8 Content, FunctionCallingMode, FunctionDeclaration, GenerationConfig, GenerationResponse,
9 Message, Result, Role, Tool,
10};
11
12pub struct ContentBuilder {
14 client: Arc<GeminiClient>,
15 pub contents: Vec<Content>,
16 generation_config: Option<GenerationConfig>,
17 tools: Option<Vec<Tool>>,
18 tool_config: Option<ToolConfig>,
19 system_instruction: Option<Content>,
20}
21
22impl ContentBuilder {
23 pub(crate) fn new(client: Arc<GeminiClient>) -> Self {
25 Self {
26 client,
27 contents: Vec::new(),
28 generation_config: None,
29 tools: None,
30 tool_config: None,
31 system_instruction: None,
32 }
33 }
34
35 pub fn with_system_prompt(self, text: impl Into<String>) -> Self {
37 self.with_system_instruction(text)
39 }
40
41 pub fn with_system_instruction(mut self, text: impl Into<String>) -> Self {
43 let content = Content::text(text);
45 self.system_instruction = Some(content);
46 self
47 }
48
49 pub fn with_user_message(mut self, text: impl Into<String>) -> Self {
51 let message = Message::user(text);
52 let content = message.content;
53 self.contents.push(content);
54 self
55 }
56
57 pub fn with_model_message(mut self, text: impl Into<String>) -> Self {
59 let message = Message::model(text);
60 let content = message.content;
61 self.contents.push(content);
62 self
63 }
64
65 pub fn with_inline_data(
67 mut self,
68 data: impl Into<String>,
69 mime_type: impl Into<String>,
70 ) -> Self {
71 let content = Content::inline_data(mime_type, data);
72 self.contents.push(content);
73 self
74 }
75
76 pub fn with_function_response(
78 mut self,
79 name: impl Into<String>,
80 response: serde_json::Value,
81 ) -> Self {
82 let content = Content::function_response_json(name, response).with_role(Role::User);
83 self.contents.push(content);
84 self
85 }
86
87 pub fn with_function_response_str(
89 mut self,
90 name: impl Into<String>,
91 response: impl Into<String>,
92 ) -> std::result::Result<Self, serde_json::Error> {
93 let response_str = response.into();
94 let json = serde_json::from_str(&response_str)?;
95 let content = Content::function_response_json(name, json).with_role(Role::User);
96 self.contents.push(content);
97 Ok(self)
98 }
99
100 pub fn with_message(mut self, message: Message) -> Self {
102 let content = message.content.clone();
103 match &content.role {
104 Some(role) => {
105 let role_clone = role.clone();
106 self.contents.push(content.with_role(role_clone));
107 }
108 None => {
109 self.contents.push(content.with_role(message.role));
110 }
111 }
112 self
113 }
114
115 pub fn with_messages(mut self, messages: impl IntoIterator<Item = Message>) -> Self {
117 for message in messages {
118 self = self.with_message(message);
119 }
120 self
121 }
122
123 pub fn with_generation_config(mut self, config: GenerationConfig) -> Self {
125 self.generation_config = Some(config);
126 self
127 }
128
129 pub fn with_temperature(mut self, temperature: f32) -> Self {
131 if self.generation_config.is_none() {
132 self.generation_config = Some(GenerationConfig::default());
133 }
134 if let Some(config) = &mut self.generation_config {
135 config.temperature = Some(temperature);
136 }
137 self
138 }
139
140 pub fn with_top_p(mut self, top_p: f32) -> Self {
142 if self.generation_config.is_none() {
143 self.generation_config = Some(GenerationConfig::default());
144 }
145 if let Some(config) = &mut self.generation_config {
146 config.top_p = Some(top_p);
147 }
148 self
149 }
150
151 pub fn with_top_k(mut self, top_k: i32) -> Self {
153 if self.generation_config.is_none() {
154 self.generation_config = Some(GenerationConfig::default());
155 }
156 if let Some(config) = &mut self.generation_config {
157 config.top_k = Some(top_k);
158 }
159 self
160 }
161
162 pub fn with_max_output_tokens(mut self, max_output_tokens: i32) -> Self {
164 if self.generation_config.is_none() {
165 self.generation_config = Some(GenerationConfig::default());
166 }
167 if let Some(config) = &mut self.generation_config {
168 config.max_output_tokens = Some(max_output_tokens);
169 }
170 self
171 }
172
173 pub fn with_candidate_count(mut self, candidate_count: i32) -> Self {
175 if self.generation_config.is_none() {
176 self.generation_config = Some(GenerationConfig::default());
177 }
178 if let Some(config) = &mut self.generation_config {
179 config.candidate_count = Some(candidate_count);
180 }
181 self
182 }
183
184 pub fn with_stop_sequences(mut self, stop_sequences: Vec<String>) -> Self {
186 if self.generation_config.is_none() {
187 self.generation_config = Some(GenerationConfig::default());
188 }
189 if let Some(config) = &mut self.generation_config {
190 config.stop_sequences = Some(stop_sequences);
191 }
192 self
193 }
194
195 pub fn with_response_mime_type(mut self, mime_type: impl Into<String>) -> Self {
197 if self.generation_config.is_none() {
198 self.generation_config = Some(GenerationConfig::default());
199 }
200 if let Some(config) = &mut self.generation_config {
201 config.response_mime_type = Some(mime_type.into());
202 }
203 self
204 }
205
206 pub fn with_response_schema(mut self, schema: serde_json::Value) -> Self {
208 if self.generation_config.is_none() {
209 self.generation_config = Some(GenerationConfig::default());
210 }
211 if let Some(config) = &mut self.generation_config {
212 config.response_schema = Some(schema);
213 }
214 self
215 }
216
217 pub fn with_tool(mut self, tool: Tool) -> Self {
219 if self.tools.is_none() {
220 self.tools = Some(Vec::new());
221 }
222 if let Some(tools) = &mut self.tools {
223 tools.push(tool);
224 }
225 self
226 }
227
228 pub fn with_function(mut self, function: FunctionDeclaration) -> Self {
230 let tool = Tool::new(function);
231 self = self.with_tool(tool);
232 self
233 }
234
235 pub fn with_function_calling_mode(mut self, mode: FunctionCallingMode) -> Self {
237 if self.tool_config.is_none() {
238 self.tool_config = Some(ToolConfig {
239 function_calling_config: Some(FunctionCallingConfig { mode }),
240 });
241 } else if let Some(tool_config) = &mut self.tool_config {
242 tool_config.function_calling_config = Some(FunctionCallingConfig { mode });
243 }
244 self
245 }
246
247 pub fn with_thinking_config(mut self, thinking_config: ThinkingConfig) -> Self {
249 if self.generation_config.is_none() {
250 self.generation_config = Some(GenerationConfig::default());
251 }
252 if let Some(config) = &mut self.generation_config {
253 config.thinking_config = Some(thinking_config);
254 }
255 self
256 }
257
258 pub fn with_thinking_budget(mut self, budget: i32) -> Self {
260 if self.generation_config.is_none() {
261 self.generation_config = Some(GenerationConfig::default());
262 }
263 if let Some(config) = &mut self.generation_config {
264 if config.thinking_config.is_none() {
265 config.thinking_config = Some(ThinkingConfig::default());
266 }
267 if let Some(thinking_config) = &mut config.thinking_config {
268 thinking_config.thinking_budget = Some(budget);
269 }
270 }
271 self
272 }
273
274 pub fn with_dynamic_thinking(self) -> Self {
276 self.with_thinking_budget(-1)
277 }
278
279 pub fn with_thoughts_included(mut self, include: bool) -> Self {
281 if self.generation_config.is_none() {
282 self.generation_config = Some(GenerationConfig::default());
283 }
284 if let Some(config) = &mut self.generation_config {
285 if config.thinking_config.is_none() {
286 config.thinking_config = Some(ThinkingConfig::default());
287 }
288 if let Some(thinking_config) = &mut config.thinking_config {
289 thinking_config.include_thoughts = Some(include);
290 }
291 }
292 self
293 }
294
295 pub fn build(self) -> GenerateContentRequest {
296 GenerateContentRequest {
297 contents: self.contents,
298 generation_config: self.generation_config,
299 safety_settings: None,
300 tools: self.tools,
301 tool_config: self.tool_config,
302 system_instruction: self.system_instruction,
303 }
304 }
305
306 pub async fn execute(self) -> Result<GenerationResponse> {
308 let client = self.client.clone();
309 let request = self.build();
310 client.generate_content_raw(request).await
311 }
312
313 pub async fn execute_stream(
315 self,
316 ) -> Result<Pin<Box<dyn Stream<Item = Result<GenerationResponse>> + Send>>> {
317 let request = GenerateContentRequest {
318 contents: self.contents,
319 generation_config: self.generation_config,
320 safety_settings: None,
321 tools: self.tools,
322 tool_config: self.tool_config,
323 system_instruction: self.system_instruction,
324 };
325
326 self.client.generate_content_stream(request).await
327 }
328}