gcp_vertex_ai_generative_language/
lib.rs1pub mod auth;
7
8pub use auth::Authentication;
9use google::ai::generativelanguage::v1beta2::discuss_service_client::DiscussServiceClient;
10use google::ai::generativelanguage::v1beta2::model_service_client::ModelServiceClient;
11use google::ai::generativelanguage::v1beta2::text_service_client::TextServiceClient;
12use tonic::codegen::http::uri::InvalidUri;
13use tonic::transport::{Certificate, Channel, ClientTlsConfig};
14
15#[derive(thiserror::Error, Debug)]
17pub enum Error {
18 #[error("tonic transport error - {0}")]
20 Tonic(#[from] tonic::transport::Error),
21 #[error("{0}")]
23 InvalidUri(#[from] InvalidUri),
24 #[error("Status: {}", .0.message())]
26 Status(#[from] tonic::Status),
27}
28
29const CERTIFICATES: &str = include_str!("../certs/roots.pem");
30
31#[derive(Clone)]
33pub enum Credentials {
34 ApiKey(String),
36 None,
38}
39
40#[allow(missing_docs)]
42pub mod google {
43
44 pub mod api {
46
47 include!(concat!(env!("OUT_DIR"), "/google.api.rs"));
48 }
49
50 pub mod ai {
52
53 pub mod generativelanguage {
55
56 pub mod v1beta2 {
58
59 include!(concat!(
60 env!("OUT_DIR"),
61 "/google.ai.generativelanguage.v1beta2.rs"
62 ));
63 }
64 }
65 }
66}
67
68#[derive(Clone)]
70pub struct LanguageClient {
71 pub discuss_service: DiscussServiceClient<
75 tonic::service::interceptor::InterceptedService<Channel, Authentication>,
76 >,
77 pub model_service: ModelServiceClient<
81 tonic::service::interceptor::InterceptedService<Channel, Authentication>,
82 >,
83 pub text_service:
87 TextServiceClient<tonic::service::interceptor::InterceptedService<Channel, Authentication>>,
88}
89
90impl LanguageClient {
91 pub async fn new(credentials: Credentials) -> Result<Self, Error> {
108 let domain_name = "generativelanguage.googleapis.com".to_string();
109
110 let tls_config = ClientTlsConfig::new()
111 .ca_certificate(Certificate::from_pem(CERTIFICATES))
112 .domain_name(&domain_name);
113
114 let endpoint = format!("https://{endpoint}", endpoint = domain_name);
115
116 let channel = Channel::from_shared(endpoint)?
117 .user_agent("github.com/ssoudan/gcp-vertex-ai-generative-ai")?
118 .tls_config(tls_config)?
119 .connect_lazy();
120
121 Self::from_channel(credentials, channel).await
122 }
123
124 pub async fn from_channel(
126 credentials: Credentials,
127 channel: Channel,
128 ) -> Result<LanguageClient, Error> {
129 let discuss_service = {
130 let auth = Authentication::build(credentials.clone()).await?;
131 DiscussServiceClient::with_interceptor(channel.clone(), auth)
132 };
133
134 let model_service = {
135 let auth = Authentication::build(credentials.clone()).await?;
136 ModelServiceClient::with_interceptor(channel.clone(), auth)
137 };
138
139 let text_service = {
140 let auth = Authentication::build(credentials).await?;
141 TextServiceClient::with_interceptor(channel, auth)
142 };
143
144 Ok(Self {
145 discuss_service,
146 model_service,
147 text_service,
148 })
149 }
150}
151
152#[cfg(test)]
153mod test;
154
155#[cfg(test)]
156mod common {
157 use std::env;
158
159 use crate::{Credentials, LanguageClient};
160
161 pub(crate) async fn test_client() -> LanguageClient {
162 let api_key = env::var("GOOGLE_API_KEY").expect("GOOGLE_API_KEY must be set");
163
164 LanguageClient::new(Credentials::ApiKey(api_key))
165 .await
166 .unwrap()
167 }
168}