#[ cfg( feature = "embeddings" ) ]
mod private
{
use serde::{ Serialize, Deserialize };
#[ cfg( feature = "error-handling" ) ]
use crate::error::{ AnthropicError, AnthropicResult };
#[ cfg( not( feature = "error-handling" ) ) ]
type AnthropicError = crate::error_tools::Error;
#[ cfg( not( feature = "error-handling" ) ) ]
type AnthropicResult< T > = Result< T, crate::error_tools::Error >;
#[ derive( Debug, Clone, Serialize, Deserialize ) ]
pub struct EmbeddingRequest
{
model : String,
input : EmbeddingInput,
#[ serde( skip_serializing_if = "Option::is_none" ) ]
encoding_format : Option< String >,
#[ serde( skip_serializing_if = "Option::is_none" ) ]
dimensions : Option< u32 >,
#[ serde( skip_serializing_if = "Option::is_none" ) ]
user : Option< String >,
}
#[ derive( Debug, Clone, Serialize, Deserialize ) ]
#[ serde( untagged ) ]
pub enum EmbeddingInput
{
Single( String ),
Batch( Vec< String > ),
}
#[ derive( Debug, Clone, Serialize, Deserialize ) ]
pub struct EmbeddingResponse
{
object : String,
data : Vec< EmbeddingData >,
model : String,
usage : EmbeddingUsage,
}
#[ derive( Debug, Clone, Serialize, Deserialize ) ]
pub struct EmbeddingData
{
object : String,
index : usize,
embedding : Vec< f64 >,
}
#[ derive( Debug, Clone, Serialize, Deserialize ) ]
pub struct EmbeddingUsage
{
prompt_tokens : u32,
total_tokens : u32,
}
impl EmbeddingRequest
{
#[ inline ]
#[ must_use ]
pub fn new() -> Self
{
Self
{
model : String::new(),
input : EmbeddingInput::Single( String::new() ),
encoding_format : None,
dimensions : None,
user : None,
}
}
#[ inline ]
#[ must_use ]
pub fn model< S : Into< String > >( mut self, model : S ) -> Self
{
self.model = model.into();
self
}
#[ inline ]
#[ must_use ]
pub fn input< S : Into< String > >( mut self, input : S ) -> Self
{
self.input = EmbeddingInput::Single( input.into() );
self
}
#[ inline ]
#[ must_use ]
pub fn input_batch( mut self, inputs : Vec< String > ) -> Self
{
self.input = EmbeddingInput::Batch( inputs );
self
}
#[ inline ]
#[ must_use ]
pub fn encoding_format< S : Into< String > >( mut self, format : S ) -> Self
{
self.encoding_format = Some( format.into() );
self
}
#[ inline ]
#[ must_use ]
pub fn dimensions( mut self, dims : u32 ) -> Self
{
self.dimensions = Some( dims );
self
}
#[ inline ]
#[ must_use ]
pub fn user< S : Into< String > >( mut self, user : S ) -> Self
{
self.user = Some( user.into() );
self
}
#[ inline ]
#[ must_use ]
pub fn get_model( &self ) -> &str
{
&self.model
}
#[ inline ]
#[ must_use ]
pub fn get_input( &self ) -> &str
{
match &self.input
{
EmbeddingInput::Single( text ) => text,
EmbeddingInput::Batch( texts ) => texts.first().map_or( "", String::as_str ),
}
}
#[ inline ]
#[ must_use ]
pub fn get_input_batch( &self ) -> Vec< &str >
{
match &self.input
{
EmbeddingInput::Single( text ) => vec![ text ],
EmbeddingInput::Batch( texts ) => texts.iter().map( String::as_str ).collect(),
}
}
#[ inline ]
#[ must_use ]
pub fn get_encoding_format( &self ) -> &str
{
self.encoding_format.as_deref().unwrap_or( "float" )
}
#[ inline ]
#[ must_use ]
pub fn get_dimensions( &self ) -> Option< u32 >
{
self.dimensions
}
pub fn validate( &self ) -> AnthropicResult< () >
{
if self.model.trim().is_empty()
{
#[ cfg( feature = "error-handling" ) ]
return Err( AnthropicError::InvalidArgument( "Model cannot be empty".to_string() ) );
#[ cfg( not( feature = "error-handling" ) ) ]
return Err( crate::error_tools::Error::msg( "Model cannot be empty" ) );
}
match &self.input
{
EmbeddingInput::Single( text ) =>
{
if text.trim().is_empty()
{
#[ cfg( feature = "error-handling" ) ]
return Err( AnthropicError::InvalidArgument( "Input text cannot be empty".to_string() ) );
#[ cfg( not( feature = "error-handling" ) ) ]
return Err( crate::error_tools::Error::msg( "Input text cannot be empty" ) );
}
if text.len() > 50000
{
#[ cfg( feature = "error-handling" ) ]
return Err( AnthropicError::InvalidArgument( "Input text too long (max 50,000 characters)".to_string() ) );
#[ cfg( not( feature = "error-handling" ) ) ]
return Err( crate::error_tools::Error::msg( "Input text too long (max 50,000 characters)" ) );
}
}
EmbeddingInput::Batch( texts ) =>
{
if texts.is_empty()
{
#[ cfg( feature = "error-handling" ) ]
return Err( AnthropicError::InvalidArgument( "Batch input cannot be empty".to_string() ) );
#[ cfg( not( feature = "error-handling" ) ) ]
return Err( crate::error_tools::Error::msg( "Batch input cannot be empty" ) );
}
if texts.len() > 100
{
#[ cfg( feature = "error-handling" ) ]
return Err( AnthropicError::InvalidArgument( "Batch size too large (max 100 texts)".to_string() ) );
#[ cfg( not( feature = "error-handling" ) ) ]
return Err( crate::error_tools::Error::msg( "Batch size too large (max 100 texts)" ) );
}
for ( index, text ) in texts.iter().enumerate()
{
if text.trim().is_empty()
{
#[ cfg( feature = "error-handling" ) ]
return Err( AnthropicError::InvalidArgument( format!( "Text at index {index} is empty" ) ) );
#[ cfg( not( feature = "error-handling" ) ) ]
return Err( crate::error_tools::Error::msg( format!( "Text at index {index} is empty" ) ) );
}
if text.len() > 50000
{
#[ cfg( feature = "error-handling" ) ]
return Err( AnthropicError::InvalidArgument( format!( "Text at index {index} too long (max 50,000 characters)" ) ) );
#[ cfg( not( feature = "error-handling" ) ) ]
return Err( crate::error_tools::Error::msg( format!( "Text at index {index} too long (max 50,000 characters)" ) ) );
}
}
}
}
if let Some( dims ) = self.dimensions
{
if dims == 0 || dims > 4096
{
#[ cfg( feature = "error-handling" ) ]
return Err( AnthropicError::InvalidArgument( "Dimensions must be between 1 and 4096".to_string() ) );
#[ cfg( not( feature = "error-handling" ) ) ]
return Err( crate::error_tools::Error::msg( "Dimensions must be between 1 and 4096" ) );
}
}
Ok( () )
}
}
impl Default for EmbeddingRequest
{
fn default() -> Self
{
Self::new()
}
}
impl EmbeddingResponse
{
#[ inline ]
#[ must_use ]
pub fn data( &self ) -> &Vec< EmbeddingData >
{
&self.data
}
#[ inline ]
#[ must_use ]
pub fn model( &self ) -> &str
{
&self.model
}
#[ inline ]
#[ must_use ]
pub fn usage( &self ) -> &EmbeddingUsage
{
&self.usage
}
#[ inline ]
#[ must_use ]
pub fn embedding_count( &self ) -> usize
{
self.data.len()
}
}
impl EmbeddingData
{
#[ inline ]
#[ must_use ]
pub fn embedding( &self ) -> &Vec< f64 >
{
&self.embedding
}
#[ inline ]
#[ must_use ]
pub fn index( &self ) -> usize
{
self.index
}
#[ inline ]
#[ must_use ]
pub fn dimensions( &self ) -> usize
{
self.embedding.len()
}
}
impl EmbeddingUsage
{
#[ inline ]
#[ must_use ]
pub fn prompt_tokens( &self ) -> u32
{
self.prompt_tokens
}
#[ inline ]
#[ must_use ]
pub fn total_tokens( &self ) -> u32
{
self.total_tokens
}
}
}
#[ cfg( feature = "embeddings" ) ]
crate::mod_interface!
{
exposed use
{
EmbeddingRequest,
EmbeddingResponse,
EmbeddingData,
EmbeddingUsage,
EmbeddingInput,
};
}