Skip to main content

rig_core/providers/gemini/
mod.rs

1//! Gemini provider configuration and endpoint wires.
2//!
3//! ```no_run
4//! use rig_core::providers::gemini;
5//!
6//! # fn run() -> Result<(), Box<dyn std::error::Error>> {
7//! let provider = gemini::Gemini::from_env()?;
8//!
9//! let embeddings = provider.embedding(gemini::EMBEDDING_001, None);
10//! # Ok(())
11//! # }
12//! ```
13//!
14//! Pair a wire with a transport in a [`Model`](crate::driver::Model) to call it.
15
16#[cfg(feature = "audio")]
17#[cfg_attr(docsrs, doc(cfg(feature = "audio")))]
18pub mod audio_generation;
19pub mod cached_content;
20pub mod caching;
21pub mod completion;
22pub mod embedding;
23pub mod extension;
24#[cfg(feature = "image")]
25#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
26pub mod image_generation;
27pub mod interactions_api;
28pub mod model_listing;
29mod options;
30pub mod streaming;
31pub mod transcription;
32
33pub use crate::client::gemini::Gemini;
34pub use crate::client::gemini_caching::Caching;
35#[cfg(feature = "audio")]
36pub use audio_generation::{GEMINI_3_8_FLASH_LITE_TTS, GEMINI_3_8_FLASH_TTS};
37pub use cached_content::{CacheExpiry, CachedContent, CachedContents, NewCachedContent};
38pub use caching::{AutoCache, CacheBook, CacheEvent, CacheReport, Clock, CreatedCache, Lease};
39pub use completion::ThoughtReplay;
40pub use embedding::{EMBEDDING_001, EMBEDDING_004};
41#[cfg(feature = "image")]
42pub use image_generation::{
43    GEMINI_2_5_FLASH_IMAGE, GEMINI_3_1_FLASH_IMAGE, GEMINI_3_1_FLASH_LITE_IMAGE,
44    GEMINI_3_PRO_IMAGE, GEMINI_NANO_BANANA_2_1,
45};
46pub use interactions_api::{DEEP_RESEARCH_MAX_PREVIEW_04_2026, DEEP_RESEARCH_PREVIEW_04_2026};
47pub use model_listing::*;
48
49use crate::client::env::{self, EnvError};
50use crate::wire::Secret;
51
52/// Stable descriptor name for both Gemini surfaces, as records and
53/// telemetry spell it.
54pub use completion::PROVIDER_NAME;
55
56/// Where both Gemini surfaces live.
57pub const BASE_URL: &str = "https://generativelanguage.googleapis.com";
58
59/// The environment variable holding the API key.
60pub const API_KEY_ENV: &str = "GEMINI_API_KEY";
61
62/// The settings of Gemini's GenerateContent and Interactions APIs:
63/// serializable, and the key is never serialized. [`connect`](Self::connect)
64/// puts it on a transport as a [`Gemini`] client.
65#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
66#[serde(deny_unknown_fields)]
67pub struct GeminiConfig {
68    /// The API key, redacted in `Debug` and in serialized form.
69    pub api_key: Secret,
70    /// The API root every wire builds its URI from.
71    pub base_url: String,
72}
73
74impl GeminiConfig {
75    /// The provider configured with `api_key` and the public base URL.
76    pub fn new(api_key: impl Into<Secret>) -> Self {
77        Self {
78            api_key: api_key.into(),
79            base_url: BASE_URL.to_owned(),
80        }
81    }
82
83    /// Load `GEMINI_API_KEY`, returning an error if it is missing or invalid.
84    pub fn from_env() -> Result<Self, EnvError> {
85        Ok(Self::new(env::required(API_KEY_ENV)?))
86    }
87
88    /// Send to a different API root (a proxy, a regional endpoint).
89    pub fn with_base_url(mut self, base_url: impl Into<String>) -> Self {
90        self.base_url = base_url.into();
91        self
92    }
93
94    /// Build a GenerateContent URI, appending the API key after any path query.
95    /// The returned URI contains credentials and must not be logged.
96    pub(crate) fn uri(&self, path: &str) -> String {
97        let trimmed = path.trim_start_matches('/');
98        let separator = if trimmed.contains('?') { "&" } else { "?" };
99        let base = self.base_url.trim_end_matches('/');
100        format!("{base}/{trimmed}{separator}key={}", self.api_key.expose())
101    }
102
103    /// The URI for an Interactions-family `path`. No key: that family
104    /// authenticates by the `x-goog-api-key` header instead.
105    pub(crate) fn interactions_uri(&self, path: &str) -> String {
106        let base = self.base_url.trim_end_matches('/');
107        format!("{base}/{}", path.trim_start_matches('/'))
108    }
109
110    /// The header that authenticates an Interactions-family request.
111    pub(crate) const INTERACTIONS_KEY_HEADER: &'static str = "x-goog-api-key";
112
113    /// The `generateContent` / `streamGenerateContent` completion wire.
114    pub(crate) fn completion(&self, model: impl Into<String>) -> completion::GenerateContent {
115        completion::GenerateContent::new(self.clone(), model)
116    }
117
118    /// The Interactions API completion wire.
119    pub(crate) fn interactions(&self, model: impl Into<String>) -> interactions_api::Interactions {
120        interactions_api::Interactions::new(self.clone(), model)
121    }
122}
123
124/// The size of a generated image. Each model takes some of them; the
125/// API refuses the others.
126#[non_exhaustive]
127#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
128pub enum ImageSize {
129    /// `512`: 512 by 512 pixels at 1:1.
130    #[serde(rename = "512")]
131    FiveTwelve,
132    /// `1K`: 1024 by 1024 pixels at 1:1, the API's default.
133    #[serde(rename = "1K")]
134    OneK,
135    /// `2K`: 2048 by 2048 pixels at 1:1.
136    #[serde(rename = "2K")]
137    TwoK,
138    /// `4K`: 4096 by 4096 pixels at 1:1.
139    #[serde(rename = "4K")]
140    FourK,
141}
142
143#[cfg(test)]
144mod tests;