gemini_live_api/client/
builder.rs

1use super::handle::GeminiLiveClient;
2use super::handlers::{
3    EventHandlerSimple, Handlers, ServerContentContext, ToolHandler, UsageMetadataContext,
4};
5use crate::error::GeminiError;
6use crate::types::*;
7use std::sync::Arc;
8use tokio::sync::{mpsc, oneshot};
9
10pub struct GeminiLiveClientBuilder<S: Clone + Send + Sync + 'static> {
11    pub(crate) api_key: String,
12    pub(crate) initial_setup: BidiGenerateContentSetup,
13    pub(crate) handlers: Handlers<S>,
14    pub(crate) state: S,
15}
16
17impl<S: Clone + Send + Sync + 'static + Default> GeminiLiveClientBuilder<S> {
18    pub fn new(api_key: String, model: String) -> Self {
19        Self::new_with_state(api_key, model, S::default())
20    }
21}
22
23impl<S: Clone + Send + Sync + 'static> GeminiLiveClientBuilder<S> {
24    pub fn new_with_state(api_key: String, model: String, state: S) -> Self {
25        Self {
26            api_key,
27            initial_setup: BidiGenerateContentSetup {
28                model,
29                ..Default::default()
30            },
31            handlers: Handlers::default(),
32            state,
33        }
34    }
35
36    pub fn generation_config(mut self, config: GenerationConfig) -> Self {
37        self.initial_setup.generation_config = Some(config);
38        self
39    }
40
41    pub fn system_instruction(mut self, instruction: Content) -> Self {
42        self.initial_setup.system_instruction = Some(instruction);
43        self
44    }
45
46    #[doc(hidden)]
47    pub fn add_tool_declaration(mut self, declaration: FunctionDeclaration) -> Self {
48        let tools_vec = self.initial_setup.tools.get_or_insert_with(Vec::new);
49        if let Some(tool_struct) = tools_vec.first_mut() {
50            tool_struct.function_declarations.push(declaration);
51        } else {
52            tools_vec.push(Tool {
53                function_declarations: vec![declaration],
54            });
55        }
56        self
57    }
58
59    #[doc(hidden)]
60    pub fn on_tool_call<F>(mut self, tool_name: impl Into<String>, handler: F) -> Self
61    where
62        F: ToolHandler<S> + 'static,
63    {
64        self.handlers
65            .tool_handlers
66            .insert(tool_name.into(), Arc::new(handler));
67        self
68    }
69
70    pub fn on_server_content(
71        mut self,
72        handler: impl EventHandlerSimple<ServerContentContext, S> + 'static,
73    ) -> Self {
74        self.handlers.on_server_content = Some(Arc::new(handler));
75        self
76    }
77
78    pub fn on_usage_metadata(
79        mut self,
80        handler: impl EventHandlerSimple<UsageMetadataContext, S> + 'static,
81    ) -> Self {
82        self.handlers.on_usage_metadata = Some(Arc::new(handler));
83        self
84    }
85
86    pub fn realtime_input_config(mut self, config: RealtimeInputConfig) -> Self {
87        self.initial_setup.realtime_input_config = Some(config);
88        self
89    }
90
91    pub fn output_audio_transcription(mut self, config: AudioTranscriptionConfig) -> Self {
92        self.initial_setup.output_audio_transcription = Some(config);
93        self
94    }
95
96    pub async fn connect(self) -> Result<GeminiLiveClient<S>, GeminiError> {
97        let (shutdown_tx, shutdown_rx) = oneshot::channel();
98        let (outgoing_sender, outgoing_receiver) = mpsc::channel(100);
99
100        let state_arc = Arc::new(self.state);
101        let handlers_arc = Arc::new(self.handlers);
102
103        super::connection::spawn_processing_task(
104            self.api_key.clone(),
105            self.initial_setup,
106            handlers_arc,
107            state_arc.clone(),
108            shutdown_rx,
109            outgoing_receiver,
110        );
111        tokio::time::sleep(std::time::Duration::from_millis(50)).await;
112        Ok(GeminiLiveClient {
113            shutdown_tx: Some(shutdown_tx),
114            outgoing_sender: Some(outgoing_sender),
115            state: state_arc,
116        })
117    }
118}