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;
45pub mod json_accumulator;
46pub mod json_schema;
47pub mod language_model;
48pub mod options;
49pub mod output;
50pub mod prepare_tools;
51pub mod realtime;
52pub mod request;
53pub mod speech;
54pub mod stream;
55pub mod tools;
56pub mod transcription;
57pub mod video;
58
59use std::sync::Arc;
60
61use ferrin_provider_util::IdGenerator;
62use ferrin_provider_util::SharedTransport;
63use ferrin_spec::BatchRef;
64use ferrin_spec::EmbeddingModelRef;
65use ferrin_spec::FilesRef;
66use ferrin_spec::Headers;
67use ferrin_spec::ImageModelRef;
68use ferrin_spec::LanguageModelRef;
69use ferrin_spec::ProviderId;
70use ferrin_spec::RealtimeFactoryRef;
71use ferrin_spec::SpeechModelRef;
72use ferrin_spec::TranscriptionModelRef;
73use ferrin_spec::VideoModelRef;
74use ferrin_spec::error::NoSuchModelError;
75use ferrin_spec::error::ProviderError;
76use ferrin_spec::provider::Provider;
77use secrecy::SecretString;
78use url::Url;
79
80pub use crate::batch::GoogleBatch;
81pub use crate::config::GoogleConfig;
82pub use crate::config::SharedConfig;
83pub use crate::embedding::GoogleEmbeddingModel;
84pub use crate::files::GoogleFiles;
85pub use crate::image::GoogleImageModel;
86pub use crate::language_model::GoogleLanguageModel;
87pub use crate::realtime::GoogleRealtimeFactory;
88pub use crate::realtime::GoogleRealtimeModel;
89pub use crate::speech::GoogleSpeechModel;
90pub use crate::tools::GoogleTools;
91pub use crate::transcription::GoogleTranscriptionModel;
92pub use crate::video::GoogleVideoModel;
93
94pub const VERSION: &str = env!("CARGO_PKG_VERSION");
96
97#[derive(Default)]
99pub struct GoogleSettings {
100 pub base_url: Option<Url>,
102 pub api_key: Option<SecretString>,
105 pub headers: Headers,
107 pub name: Option<String>,
110 pub transport: Option<SharedTransport>,
112 pub id_generator: Option<Arc<dyn IdGenerator>>,
114}
115
116impl std::fmt::Debug for GoogleSettings {
117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118 f.debug_struct("GoogleSettings")
119 .field("base_url", &self.base_url)
120 .field("api_key", &self.api_key.as_ref().map(|_| "***"))
121 .field("headers", &self.headers)
122 .field("name", &self.name)
123 .finish_non_exhaustive()
124 }
125}
126
127pub fn create_google(settings: GoogleSettings) -> Result<GoogleProvider, ProviderError> {
135 let base_url = match settings.base_url {
136 Some(url) => ferrin_provider_util::base_url::parse_base_url(url.as_str())?,
137 None => ferrin_provider_util::base_url::parse_base_url(config::DEFAULT_BASE_URL)?,
138 };
139 let transport = match settings.transport {
140 Some(transport) => transport,
141 None => ferrin_provider_util::default_transport().map_err(ProviderError::other)?,
142 };
143 let mut config = GoogleConfig::with_transport(
144 settings
145 .name
146 .unwrap_or_else(|| config::DEFAULT_NAME.to_owned()),
147 base_url,
148 transport,
149 );
150 config.api_key = settings.api_key;
151 config.headers = settings.headers;
152 if let Some(id_generator) = settings.id_generator {
153 config.id_generator = id_generator;
154 }
155 Ok(GoogleProvider::from_config(Arc::new(config)))
156}
157
158#[derive(Debug, Clone)]
160pub struct GoogleProvider {
161 config: SharedConfig,
162 provider_id: ProviderId,
163 tools: GoogleTools,
164}
165
166impl GoogleProvider {
167 #[must_use]
169 pub fn from_config(config: SharedConfig) -> Self {
170 Self {
171 provider_id: ProviderId::new(config.name.clone()),
172 tools: GoogleTools::new(),
173 config,
174 }
175 }
176
177 #[must_use]
179 pub fn config(&self) -> &SharedConfig {
180 &self.config
181 }
182
183 #[must_use]
185 pub fn language_model(&self, model_id: &str) -> GoogleLanguageModel {
186 GoogleLanguageModel::new(self.config.clone(), model_id)
187 }
188
189 #[must_use]
191 pub fn chat(&self, model_id: &str) -> GoogleLanguageModel {
192 self.language_model(model_id)
193 }
194
195 #[must_use]
197 pub fn embedding(&self, model_id: &str) -> GoogleEmbeddingModel {
198 GoogleEmbeddingModel::new(self.config.clone(), model_id)
199 }
200
201 #[must_use]
203 pub fn text_embedding(&self, model_id: &str) -> GoogleEmbeddingModel {
204 self.embedding(model_id)
205 }
206
207 #[must_use]
209 pub fn image(&self, model_id: &str) -> GoogleImageModel {
210 GoogleImageModel::new(self.config.clone(), model_id)
211 }
212
213 #[must_use]
215 pub fn speech(&self, model_id: &str) -> GoogleSpeechModel {
216 GoogleSpeechModel::new(self.config.clone(), model_id)
217 }
218
219 #[must_use]
221 pub fn transcription(&self, model_id: &str) -> GoogleTranscriptionModel {
222 GoogleTranscriptionModel::new(self.config.clone(), model_id)
223 }
224
225 #[must_use]
227 pub fn video(&self, model_id: &str) -> GoogleVideoModel {
228 GoogleVideoModel::new(self.config.clone(), model_id)
229 }
230
231 #[must_use]
233 pub fn files(&self) -> GoogleFiles {
234 GoogleFiles::new(self.config.clone())
235 }
236
237 #[must_use]
239 pub fn batch(&self) -> GoogleBatch {
240 GoogleBatch::new(self.config.clone())
241 }
242
243 #[must_use]
245 pub fn realtime(&self) -> GoogleRealtimeFactory {
246 GoogleRealtimeFactory::new(self.config.clone())
247 }
248
249 #[must_use]
251 pub fn tools(&self) -> &GoogleTools {
252 &self.tools
253 }
254}
255
256impl Provider for GoogleProvider {
257 fn provider_id(&self) -> &ProviderId {
258 &self.provider_id
259 }
260
261 fn language_model(&self, model_id: &str) -> Result<LanguageModelRef, NoSuchModelError> {
262 Ok(GoogleProvider::language_model(self, model_id).into())
263 }
264
265 fn embedding_model(&self, model_id: &str) -> Result<EmbeddingModelRef, NoSuchModelError> {
266 Ok(self.embedding(model_id).into())
267 }
268
269 fn image_model(&self, model_id: &str) -> Result<ImageModelRef, NoSuchModelError> {
270 Ok(self.image(model_id).into())
271 }
272
273 fn transcription_model(
274 &self,
275 model_id: &str,
276 ) -> Result<TranscriptionModelRef, NoSuchModelError> {
277 Ok(self.transcription(model_id).into())
278 }
279
280 fn speech_model(&self, model_id: &str) -> Result<SpeechModelRef, NoSuchModelError> {
281 Ok(self.speech(model_id).into())
282 }
283
284 fn video_model(&self, model_id: &str) -> Result<VideoModelRef, NoSuchModelError> {
285 Ok(self.video(model_id).into())
286 }
287
288 fn realtime(&self) -> Option<RealtimeFactoryRef> {
289 Some(GoogleProvider::realtime(self).into())
290 }
291
292 fn files(&self) -> Option<FilesRef> {
293 Some(GoogleProvider::files(self).into())
294 }
295
296 fn batch(&self) -> Option<BatchRef> {
297 Some(GoogleProvider::batch(self).into())
298 }
299}