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_provider_util::secure_url::UrlPolicy;
64use ferrin_spec::BatchRef;
65use ferrin_spec::EmbeddingModelRef;
66use ferrin_spec::FilesRef;
67use ferrin_spec::Headers;
68use ferrin_spec::ImageModelRef;
69use ferrin_spec::LanguageModelRef;
70use ferrin_spec::ProviderId;
71use ferrin_spec::RealtimeFactoryRef;
72use ferrin_spec::SpeechModelRef;
73use ferrin_spec::TranscriptionModelRef;
74use ferrin_spec::VideoModelRef;
75use ferrin_spec::error::NoSuchModelError;
76use ferrin_spec::error::ProviderError;
77use ferrin_spec::provider::Provider;
78use secrecy::SecretString;
79use url::Url;
80
81pub use crate::batch::GoogleBatch;
82pub use crate::config::GoogleConfig;
83pub use crate::config::SharedConfig;
84pub use crate::embedding::GoogleEmbeddingModel;
85pub use crate::files::GoogleFiles;
86pub use crate::image::GoogleImageModel;
87pub use crate::language_model::GoogleLanguageModel;
88pub use crate::realtime::GoogleRealtimeFactory;
89pub use crate::realtime::GoogleRealtimeModel;
90pub use crate::speech::GoogleSpeechModel;
91pub use crate::tools::GoogleTools;
92pub use crate::transcription::GoogleTranscriptionModel;
93pub use crate::video::GoogleVideoModel;
94
95pub const VERSION: &str = env!("CARGO_PKG_VERSION");
97
98#[derive(Default)]
100pub struct GoogleSettings {
101 pub base_url: Option<Url>,
103 pub api_key: Option<SecretString>,
106 pub headers: Headers,
108 pub name: Option<String>,
111 pub url_policy: UrlPolicy,
113 pub transport: Option<SharedTransport>,
115 pub id_generator: Option<Arc<dyn IdGenerator>>,
117}
118
119impl std::fmt::Debug for GoogleSettings {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 f.debug_struct("GoogleSettings")
122 .field("base_url", &self.base_url)
123 .field("api_key", &self.api_key.as_ref().map(|_| "***"))
124 .field("headers", &self.headers)
125 .field("name", &self.name)
126 .finish_non_exhaustive()
127 }
128}
129
130pub fn create_google(settings: GoogleSettings) -> Result<GoogleProvider, ProviderError> {
138 let base_url = match settings.base_url {
139 Some(url) => ferrin_provider_util::base_url::parse_base_url(url.as_str())?,
140 None => ferrin_provider_util::base_url::parse_base_url(config::DEFAULT_BASE_URL)?,
141 };
142 let transport = match settings.transport {
143 Some(transport) => transport,
144 None => ferrin_provider_util::default_transport().map_err(ProviderError::other)?,
145 };
146 let mut config = GoogleConfig::with_transport(
147 settings
148 .name
149 .unwrap_or_else(|| config::DEFAULT_NAME.to_owned()),
150 base_url,
151 transport,
152 );
153 config.api_key = settings.api_key;
154 config.headers = settings.headers;
155 config.url_policy = settings.url_policy;
156 if let Some(id_generator) = settings.id_generator {
157 config.id_generator = id_generator;
158 }
159 Ok(GoogleProvider::from_config(Arc::new(config)))
160}
161
162#[derive(Debug, Clone)]
164pub struct GoogleProvider {
165 config: SharedConfig,
166 provider_id: ProviderId,
167 tools: GoogleTools,
168}
169
170impl GoogleProvider {
171 #[must_use]
173 pub fn from_config(config: SharedConfig) -> Self {
174 Self {
175 provider_id: ProviderId::new(config.name.clone()),
176 tools: GoogleTools::new(),
177 config,
178 }
179 }
180
181 #[must_use]
183 pub fn config(&self) -> &SharedConfig {
184 &self.config
185 }
186
187 #[must_use]
189 pub fn language_model(&self, model_id: &str) -> GoogleLanguageModel {
190 GoogleLanguageModel::new(self.config.clone(), model_id)
191 }
192
193 #[must_use]
195 pub fn chat(&self, model_id: &str) -> GoogleLanguageModel {
196 self.language_model(model_id)
197 }
198
199 #[must_use]
201 pub fn embedding(&self, model_id: &str) -> GoogleEmbeddingModel {
202 GoogleEmbeddingModel::new(self.config.clone(), model_id)
203 }
204
205 #[must_use]
207 pub fn text_embedding(&self, model_id: &str) -> GoogleEmbeddingModel {
208 self.embedding(model_id)
209 }
210
211 #[must_use]
213 pub fn image(&self, model_id: &str) -> GoogleImageModel {
214 GoogleImageModel::new(self.config.clone(), model_id)
215 }
216
217 #[must_use]
219 pub fn speech(&self, model_id: &str) -> GoogleSpeechModel {
220 GoogleSpeechModel::new(self.config.clone(), model_id)
221 }
222
223 #[must_use]
225 pub fn transcription(&self, model_id: &str) -> GoogleTranscriptionModel {
226 GoogleTranscriptionModel::new(self.config.clone(), model_id)
227 }
228
229 #[must_use]
231 pub fn video(&self, model_id: &str) -> GoogleVideoModel {
232 GoogleVideoModel::new(self.config.clone(), model_id)
233 }
234
235 #[must_use]
237 pub fn files(&self) -> GoogleFiles {
238 GoogleFiles::new(self.config.clone())
239 }
240
241 #[must_use]
243 pub fn batch(&self) -> GoogleBatch {
244 GoogleBatch::new(self.config.clone())
245 }
246
247 #[must_use]
249 pub fn realtime(&self) -> GoogleRealtimeFactory {
250 GoogleRealtimeFactory::new(self.config.clone())
251 }
252
253 #[must_use]
255 pub fn tools(&self) -> &GoogleTools {
256 &self.tools
257 }
258}
259
260impl Provider for GoogleProvider {
261 fn provider_id(&self) -> &ProviderId {
262 &self.provider_id
263 }
264
265 fn language_model(&self, model_id: &str) -> Result<LanguageModelRef, NoSuchModelError> {
266 Ok(GoogleProvider::language_model(self, model_id).into())
267 }
268
269 fn embedding_model(&self, model_id: &str) -> Result<EmbeddingModelRef, NoSuchModelError> {
270 Ok(self.embedding(model_id).into())
271 }
272
273 fn image_model(&self, model_id: &str) -> Result<ImageModelRef, NoSuchModelError> {
274 Ok(self.image(model_id).into())
275 }
276
277 fn transcription_model(
278 &self,
279 model_id: &str,
280 ) -> Result<TranscriptionModelRef, NoSuchModelError> {
281 Ok(self.transcription(model_id).into())
282 }
283
284 fn speech_model(&self, model_id: &str) -> Result<SpeechModelRef, NoSuchModelError> {
285 Ok(self.speech(model_id).into())
286 }
287
288 fn video_model(&self, model_id: &str) -> Result<VideoModelRef, NoSuchModelError> {
289 Ok(self.video(model_id).into())
290 }
291
292 fn realtime(&self) -> Option<RealtimeFactoryRef> {
293 Some(GoogleProvider::realtime(self).into())
294 }
295
296 fn files(&self) -> Option<FilesRef> {
297 Some(GoogleProvider::files(self).into())
298 }
299
300 fn batch(&self) -> Option<BatchRef> {
301 Some(GoogleProvider::batch(self).into())
302 }
303}