gemini_genai_rs/chats/
mod.rs1use crate::client::Client;
9use crate::generate::{GenerateContentConfig, GenerateContentResponse, GenerateError};
10use crate::protocol::types::{Content, ModelId};
11
12pub struct ChatSession<'a> {
17 client: &'a Client,
18 model: ModelId,
19 history: Vec<Content>,
20 system_instruction: Option<String>,
21}
22
23impl<'a> ChatSession<'a> {
24 pub async fn send_message(
28 &mut self,
29 text: impl Into<String>,
30 ) -> Result<GenerateContentResponse, GenerateError> {
31 let user_content = Content::user(text);
32 self.history.push(user_content);
33
34 let mut config = GenerateContentConfig::from_contents(self.history.clone());
35 if let Some(ref si) = self.system_instruction {
36 config = config.system_instruction(si.clone());
37 }
38
39 let response = self
40 .client
41 .generate_content_with(config, Some(&self.model))
42 .await?;
43
44 if let Some(candidate) = response.candidates.first()
46 && let Some(content) = &candidate.content
47 {
48 self.history.push(content.clone());
49 }
50
51 Ok(response)
52 }
53
54 pub fn history(&self) -> &[Content] {
56 &self.history
57 }
58
59 pub fn turn_count(&self) -> usize {
61 self.history.len()
62 }
63}
64
65impl Client {
66 pub fn chat(&self) -> ChatSessionBuilder<'_> {
68 ChatSessionBuilder {
69 client: self,
70 model: self.default_model().clone(),
71 history: vec![],
72 system_instruction: None,
73 }
74 }
75}
76
77pub struct ChatSessionBuilder<'a> {
79 client: &'a Client,
80 model: ModelId,
81 history: Vec<Content>,
82 system_instruction: Option<String>,
83}
84
85impl<'a> ChatSessionBuilder<'a> {
86 pub fn model(mut self, model: impl Into<ModelId>) -> Self {
88 self.model = model.into();
89 self
90 }
91
92 pub fn history(mut self, history: Vec<Content>) -> Self {
94 self.history = history;
95 self
96 }
97
98 pub fn system_instruction(mut self, instruction: impl Into<String>) -> Self {
100 self.system_instruction = Some(instruction.into());
101 self
102 }
103
104 pub fn build(self) -> ChatSession<'a> {
106 ChatSession {
107 client: self.client,
108 model: self.model,
109 history: self.history,
110 system_instruction: self.system_instruction,
111 }
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn chat_builder() {
121 let client = Client::from_api_key("key");
122 let chat = client
123 .chat()
124 .model(ModelId::from_static("models/gemini-2.0-flash-live-001"))
125 .system_instruction("You are helpful")
126 .build();
127 assert_eq!(chat.turn_count(), 0);
128 assert!(chat.history().is_empty());
129 }
130
131 #[test]
132 fn chat_with_initial_history() {
133 use crate::protocol::types::{Part, Role};
134 let client = Client::from_api_key("key");
135 let history = vec![
136 Content::user("Hello"),
137 Content {
138 role: Some(Role::Model),
139 parts: vec![Part::text("Hi there!")],
140 },
141 ];
142 let chat = client.chat().history(history).build();
143 assert_eq!(chat.turn_count(), 2);
144 }
145}