mod private
{
use crate::{ error::{ Result, HuggingFaceError }, secret::Secret };
use reqwest::header::{ HeaderMap, HeaderValue, AUTHORIZATION, USER_AGENT };
use url::Url;
pub trait HuggingFaceEnvironment
{
fn api_key( &self ) -> &Secret;
fn base_url( &self ) -> &str;
fn user_agent( &self ) -> &str;
fn endpoint_url( &self, path : &str ) -> Result< Url >;
}
pub trait EnvironmentInterface
{
fn headers( &self ) -> Result< HeaderMap >;
}
#[ derive( Debug, Clone ) ]
pub struct HuggingFaceEnvironmentImpl
{
pub api_key : Secret,
pub base_url : String,
pub user_agent : String,
}
impl HuggingFaceEnvironmentImpl
{
#[ inline ]
pub fn build(
api_key : Secret,
base_url : Option< String >
) -> Result< Self >
{
let base_url = base_url.unwrap_or_else( || Self::recommended_base_url().to_string() );
let user_agent = Self::recommended_user_agent().to_string();
Ok( Self
{
api_key,
base_url,
user_agent,
})
}
#[ inline ]
pub fn with_explicit_config(
api_key : Secret,
base_url : String,
user_agent : String,
) -> Result< Self >
{
Ok( Self
{
api_key,
base_url,
user_agent,
})
}
#[ inline ]
#[ must_use ]
pub fn recommended_base_url() -> &'static str
{
"https://router.huggingface.co/v1/"
}
#[ inline ]
#[ must_use ]
pub fn recommended_user_agent() -> &'static str
{
"llm-tools-huggingface/0.2.0"
}
#[ inline ]
pub fn from_env() -> Result< Self >
{
let api_key = Secret::load_from_env( "HUGGINGFACE_API_KEY" )
.map_err( | e | HuggingFaceError::Authentication( e.to_string() ) )?;
let base_url = std::env::var( "HUGGINGFACE_BASE_URL" ).ok();
Self::build( api_key, base_url )
}
}
impl HuggingFaceEnvironment for HuggingFaceEnvironmentImpl
{
#[ inline ]
fn api_key( &self ) -> &Secret
{
&self.api_key
}
#[ inline ]
fn base_url( &self ) -> &str
{
&self.base_url
}
#[ inline ]
fn user_agent( &self ) -> &str
{
&self.user_agent
}
#[ inline ]
fn endpoint_url( &self, path : &str ) -> Result< Url >
{
let base = Url::parse( &self.base_url )
.map_err( | e | HuggingFaceError::InvalidArgument( format!( "Invalid base URL: {e}" ) ) )?;
base.join( path )
.map_err( | e | HuggingFaceError::InvalidArgument( format!( "Invalid endpoint path : {e}" ) ) )
}
}
impl EnvironmentInterface for HuggingFaceEnvironmentImpl
{
#[ inline ]
fn headers( &self ) -> Result< HeaderMap >
{
let mut headers = HeaderMap::new();
let auth_value = format!( "Bearer {}", self.api_key.expose_secret() );
let auth_header = HeaderValue::from_str( &auth_value )
.map_err( | e | HuggingFaceError::Authentication( format!( "Invalid API key format : {e}" ) ) )?;
headers.insert( AUTHORIZATION, auth_header );
let user_agent_header = HeaderValue::from_str( &self.user_agent )
.map_err( | e | HuggingFaceError::InvalidArgument( format!( "Invalid user agent : {e}" ) ) )?;
headers.insert( USER_AGENT, user_agent_header );
Ok( headers )
}
}
}
crate::mod_interface!
{
exposed use
{
private::HuggingFaceEnvironment,
private::EnvironmentInterface,
private::HuggingFaceEnvironmentImpl,
};
}