Skip to main content

rig_core/client/
gemini.rs

1//! The Gemini client: a [`GeminiConfig`] on a transport, and the models it
2//! builds.
3
4use crate::client::macros::http_client;
5use crate::driver::Model;
6use crate::error::ProviderError;
7use crate::model::ModelList;
8
9use crate::providers::gemini::GeminiConfig;
10#[cfg(feature = "audio")]
11use crate::providers::gemini::audio_generation::Speech;
12use crate::providers::gemini::cached_content::CachedContents;
13use crate::providers::gemini::completion::GenerateContent;
14use crate::providers::gemini::embedding::Embeddings;
15#[cfg(feature = "image")]
16use crate::providers::gemini::image_generation::Images;
17use crate::providers::gemini::interactions_api::{InteractionResume, Interactions};
18use crate::providers::gemini::transcription::Transcriptions;
19
20http_client!(
21    /// Gemini: its [`GeminiConfig`] on a transport. Every model it builds
22    /// sends through that transport.
23    Gemini,
24    GeminiConfig
25);
26
27impl Gemini {
28    /// Gemini with `api_key` and the public base URL, on the shared reqwest
29    /// client.
30    #[cfg(feature = "reqwest")]
31    #[cfg_attr(docsrs, doc(cfg(feature = "reqwest")))]
32    pub fn new(api_key: impl Into<crate::wire::Secret>) -> Self {
33        GeminiConfig::new(api_key).client()
34    }
35
36    /// Gemini from `GEMINI_API_KEY`, on the shared reqwest client.
37    #[cfg(feature = "reqwest")]
38    #[cfg_attr(docsrs, doc(cfg(feature = "reqwest")))]
39    pub fn from_env() -> Result<Self, crate::client::env::EnvError> {
40        Ok(GeminiConfig::from_env()?.client())
41    }
42
43    /// The `generateContent` / `streamGenerateContent` model for `model`.
44    pub fn completion(&self, model: impl Into<String>) -> Model<GenerateContent> {
45        self.model(self.config.completion(model))
46    }
47
48    /// The Interactions API model for `model`.
49    pub fn interactions(&self, model: impl Into<String>) -> Model<Interactions> {
50        self.model(self.config.interactions(model))
51    }
52
53    /// The `batchEmbedContents` embedding model for `model`. `ndims`
54    /// defaults from the model identifier.
55    pub fn embedding(&self, model: impl Into<String>, ndims: Option<usize>) -> Model<Embeddings> {
56        self.model(self.config.embedding(model, ndims))
57    }
58
59    /// The audio transcription model for `model`.
60    pub fn transcription(&self, model: impl Into<String>) -> Model<Transcriptions> {
61        self.model(self.config.transcription(model))
62    }
63
64    /// The image-generation model for `model`.
65    #[cfg(feature = "image")]
66    #[cfg_attr(docsrs, doc(cfg(feature = "image")))]
67    pub fn image_generation(&self, model: impl Into<String>) -> Model<Images> {
68        self.model(self.config.image_generation(model))
69    }
70
71    /// The text-to-speech model for `model`.
72    #[cfg(feature = "audio")]
73    #[cfg_attr(docsrs, doc(cfg(feature = "audio")))]
74    pub fn audio_generation(&self, model: impl Into<String>) -> Model<Speech> {
75        self.model(self.config.audio_generation(model))
76    }
77
78    /// Gemini's explicit context cache (`cachedContents`).
79    pub fn cached_contents(&self) -> Model<CachedContents> {
80        self.model(self.config.cached_contents())
81    }
82
83    /// The model that retrieves the interaction `interaction_id`, or resumes
84    /// its stream. A unary call fetches the current resource; the caller
85    /// controls repeated polling.
86    pub fn interaction(&self, interaction_id: impl Into<String>) -> Model<InteractionResume> {
87        self.model(InteractionResume::new(self.config.clone(), interaction_id))
88    }
89
90    /// [`Self::interaction`], resuming a streamed read after the last event
91    /// the consumer saw.
92    pub fn interaction_resumed(
93        &self,
94        interaction_id: impl Into<String>,
95        last_event_id: Option<&str>,
96    ) -> Model<InteractionResume> {
97        let wire = InteractionResume::new(self.config.clone(), interaction_id);
98        self.model(match last_event_id {
99            Some(last_event_id) => wire.after_event(last_event_id),
100            None => wire,
101        })
102    }
103
104    /// The models this API key can use, every page followed.
105    pub async fn list_models(&self) -> Result<ModelList, ProviderError> {
106        self.model(self.config.models()).list().await
107    }
108
109    /// Check that the provider accepts the configured key. A 401 or 403
110    /// reply is [`ProviderError::InvalidAuthentication`].
111    pub async fn verify(&self) -> Result<(), ProviderError> {
112        self.model(self.config.verify()).verify().await
113    }
114}