1pub mod api_types;
37pub mod batch;
38pub mod capabilities;
39pub mod config;
40pub mod convert_prompt;
41pub mod embedding;
42pub mod error;
43pub mod files;
44pub mod image;
45mod interactions;
46pub mod json_accumulator;
47pub mod json_schema;
48pub mod language_model;
49#[cfg(feature = "realtime")]
50mod live_audio;
51pub mod options;
52pub mod output;
53pub mod prepare_tools;
54pub mod realtime;
55pub mod request;
56pub mod speech;
57#[cfg(feature = "realtime")]
58pub mod speech_translation;
59pub mod stream;
60pub mod tools;
61pub mod transcription;
62pub mod video;
63
64use std::sync::Arc;
65
66use ferrin_provider_util::IdGenerator;
67use ferrin_provider_util::SharedTransport;
68use ferrin_provider_util::secure_url::UrlPolicy;
69use ferrin_spec::BatchRef;
70use ferrin_spec::EmbeddingModelRef;
71use ferrin_spec::FilesRef;
72use ferrin_spec::Headers;
73use ferrin_spec::ImageModelRef;
74use ferrin_spec::LanguageModelRef;
75use ferrin_spec::ProviderId;
76use ferrin_spec::RealtimeFactoryRef;
77use ferrin_spec::SpeechModelRef;
78use ferrin_spec::TranscriptionModelRef;
79use ferrin_spec::VideoModelRef;
80use ferrin_spec::error::NoSuchModelError;
81use ferrin_spec::error::ProviderError;
82use ferrin_spec::provider::Provider;
83use secrecy::SecretString;
84use url::Url;
85
86pub use crate::batch::GoogleBatch;
87pub use crate::config::GoogleConfig;
88pub use crate::config::SharedConfig;
89pub use crate::embedding::GoogleEmbeddingModel;
90pub use crate::files::GoogleFiles;
91pub use crate::image::GoogleImageModel;
92pub use crate::interactions::GoogleInteractionOptions;
93pub use crate::interactions::GoogleInteractionsLanguageModel;
94pub use crate::language_model::GoogleLanguageModel;
95pub use crate::realtime::GoogleRealtimeFactory;
96pub use crate::realtime::GoogleRealtimeModel;
97pub use crate::speech::GoogleSpeechModel;
98#[cfg(feature = "realtime")]
99pub use crate::speech_translation::GoogleSpeechTranslationModel;
100#[cfg(feature = "realtime")]
101pub use crate::speech_translation::GoogleSpeechTranslationOptions;
102pub use crate::tools::GoogleTools;
103pub use crate::transcription::GoogleTranscriptionModel;
104pub use crate::video::GoogleVideoModel;
105
106pub const VERSION: &str = env!("CARGO_PKG_VERSION");
108
109#[derive(Default)]
111pub struct GoogleSettings {
112 pub base_url: Option<Url>,
114 pub api_key: Option<SecretString>,
117 pub headers: Headers,
119 pub name: Option<String>,
122 pub url_policy: UrlPolicy,
124 pub transport: Option<SharedTransport>,
126 pub id_generator: Option<Arc<dyn IdGenerator>>,
128}
129
130impl std::fmt::Debug for GoogleSettings {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 f.debug_struct("GoogleSettings")
133 .field("base_url", &self.base_url)
134 .field("api_key", &self.api_key.as_ref().map(|_| "***"))
135 .field("headers", &self.headers)
136 .field("name", &self.name)
137 .finish_non_exhaustive()
138 }
139}
140
141pub fn create_google(settings: GoogleSettings) -> Result<GoogleProvider, ProviderError> {
149 let base_url = match settings.base_url {
150 Some(url) => ferrin_provider_util::base_url::parse_base_url(url.as_str())?,
151 None => ferrin_provider_util::base_url::parse_base_url(config::DEFAULT_BASE_URL)?,
152 };
153 let transport = match settings.transport {
154 Some(transport) => transport,
155 None => ferrin_provider_util::default_transport().map_err(ProviderError::other)?,
156 };
157 let mut config = GoogleConfig::with_transport(
158 settings
159 .name
160 .unwrap_or_else(|| config::DEFAULT_NAME.to_owned()),
161 base_url,
162 transport,
163 );
164 config.api_key = settings.api_key;
165 config.headers = settings.headers;
166 config.url_policy = settings.url_policy;
167 if let Some(id_generator) = settings.id_generator {
168 config.id_generator = id_generator;
169 }
170 Ok(GoogleProvider::from_config(Arc::new(config)))
171}
172
173#[derive(Debug, Clone)]
175pub struct GoogleProvider {
176 config: SharedConfig,
177 provider_id: ProviderId,
178 tools: GoogleTools,
179}
180
181impl GoogleProvider {
182 #[must_use]
184 pub fn from_config(config: SharedConfig) -> Self {
185 Self {
186 provider_id: ProviderId::new(config.name.clone()),
187 tools: GoogleTools::new(),
188 config,
189 }
190 }
191
192 #[must_use]
194 pub fn config(&self) -> &SharedConfig {
195 &self.config
196 }
197
198 #[must_use]
200 pub fn language_model(&self, model_id: &str) -> GoogleLanguageModel {
201 GoogleLanguageModel::new(self.config.clone(), model_id)
202 }
203
204 #[must_use]
206 pub fn interactions(&self, model_id: &str) -> GoogleInteractionsLanguageModel {
207 GoogleInteractionsLanguageModel::new(self.config.clone(), model_id)
208 }
209
210 #[must_use]
212 pub fn chat(&self, model_id: &str) -> GoogleLanguageModel {
213 self.language_model(model_id)
214 }
215
216 #[must_use]
218 pub fn embedding(&self, model_id: &str) -> GoogleEmbeddingModel {
219 GoogleEmbeddingModel::new(self.config.clone(), model_id)
220 }
221
222 #[must_use]
224 pub fn text_embedding(&self, model_id: &str) -> GoogleEmbeddingModel {
225 self.embedding(model_id)
226 }
227
228 #[must_use]
230 pub fn image(&self, model_id: &str) -> GoogleImageModel {
231 GoogleImageModel::new(self.config.clone(), model_id)
232 }
233
234 #[must_use]
236 pub fn speech(&self, model_id: &str) -> GoogleSpeechModel {
237 GoogleSpeechModel::new(self.config.clone(), model_id)
238 }
239
240 #[cfg(feature = "realtime")]
242 #[must_use]
243 pub fn speech_translation(&self, model_id: &str) -> GoogleSpeechTranslationModel {
244 GoogleSpeechTranslationModel::new(self.config.clone(), model_id)
245 }
246
247 #[must_use]
249 pub fn transcription(&self, model_id: &str) -> GoogleTranscriptionModel {
250 GoogleTranscriptionModel::new(self.config.clone(), model_id)
251 }
252
253 #[must_use]
255 pub fn video(&self, model_id: &str) -> GoogleVideoModel {
256 GoogleVideoModel::new(self.config.clone(), model_id)
257 }
258
259 #[must_use]
261 pub fn files(&self) -> GoogleFiles {
262 GoogleFiles::new(self.config.clone())
263 }
264
265 #[must_use]
267 pub fn batch(&self) -> GoogleBatch {
268 GoogleBatch::new(self.config.clone())
269 }
270
271 #[must_use]
273 pub fn realtime(&self) -> GoogleRealtimeFactory {
274 GoogleRealtimeFactory::new(self.config.clone())
275 }
276
277 #[must_use]
279 pub fn tools(&self) -> &GoogleTools {
280 &self.tools
281 }
282}
283
284impl Provider for GoogleProvider {
285 fn provider_id(&self) -> &ProviderId {
286 &self.provider_id
287 }
288
289 fn language_model(&self, model_id: &str) -> Result<LanguageModelRef, NoSuchModelError> {
290 Ok(GoogleProvider::language_model(self, model_id).into())
291 }
292
293 fn embedding_model(&self, model_id: &str) -> Result<EmbeddingModelRef, NoSuchModelError> {
294 Ok(self.embedding(model_id).into())
295 }
296
297 fn image_model(&self, model_id: &str) -> Result<ImageModelRef, NoSuchModelError> {
298 Ok(self.image(model_id).into())
299 }
300
301 fn transcription_model(
302 &self,
303 model_id: &str,
304 ) -> Result<TranscriptionModelRef, NoSuchModelError> {
305 Ok(self.transcription(model_id).into())
306 }
307
308 fn speech_model(&self, model_id: &str) -> Result<SpeechModelRef, NoSuchModelError> {
309 Ok(self.speech(model_id).into())
310 }
311
312 #[cfg(feature = "realtime")]
313 fn speech_translation_model(
314 &self,
315 model_id: &str,
316 ) -> Result<ferrin_spec::SpeechTranslationModelRef, NoSuchModelError> {
317 Ok(self.speech_translation(model_id).into())
318 }
319
320 fn video_model(&self, model_id: &str) -> Result<VideoModelRef, NoSuchModelError> {
321 Ok(self.video(model_id).into())
322 }
323
324 fn realtime(&self) -> Option<RealtimeFactoryRef> {
325 Some(GoogleProvider::realtime(self).into())
326 }
327
328 fn files(&self) -> Option<FilesRef> {
329 Some(GoogleProvider::files(self).into())
330 }
331
332 fn batch(&self) -> Option<BatchRef> {
333 Some(GoogleProvider::batch(self).into())
334 }
335}