use serde::Serialize;
use core::time::Duration;
use crate::{ ChatRequest, GenerateRequest };
#[ derive( Debug, Clone, Serialize ) ]
pub struct BatchChatRequest
{
pub requests : Vec< ChatRequest >,
pub batch_config : Option< BatchOperationConfig >,
pub parallel_execution : bool,
pub fail_fast : bool,
pub timeout : Option< Duration >,
}
#[ derive( Debug, Clone, Serialize ) ]
pub struct BatchChatResponse
{
pub results : Vec< BatchResult >,
pub total_requests : usize,
pub successful_requests : usize,
pub failed_requests : usize,
pub execution_time_ms : u64,
pub throughput_requests_per_second : f64,
pub batch_optimizations : Option< Vec< String > >,
pub errors : Vec< String >,
}
#[ derive( Debug, Clone, Serialize ) ]
pub struct BatchGenerateRequest
{
pub requests : Vec< GenerateRequest >,
pub batch_config : Option< BatchOperationConfig >,
pub parallel_execution : bool,
pub fail_fast : bool,
pub timeout : Option< Duration >,
}
#[ derive( Debug, Clone, Serialize ) ]
pub struct BatchGenerateResponse
{
pub results : Vec< BatchResult >,
pub total_requests : usize,
pub successful_requests : usize,
pub failed_requests : usize,
pub execution_time_ms : u64,
pub throughput_requests_per_second : f64,
pub batch_optimizations : Option< Vec< String > >,
pub errors : Vec< String >,
}
#[ derive( Debug, Clone, Serialize ) ]
pub struct BatchOperationConfig
{
max_batch_size : usize,
concurrent_limit : usize,
retry_failed : bool,
preserve_order : bool,
timeout_per_request : Option< Duration >,
chunk_size : usize,
}
#[ derive( Debug, Clone, Serialize ) ]
pub enum BatchResult
{
Success( serde_json::Value ),
Error( BatchError ),
}
#[ derive( Debug, Clone, Serialize ) ]
pub struct BatchError
{
pub request_index : usize,
pub error_code : String,
pub error_message : String,
pub recoverable : bool,
}
impl BatchChatRequest
{
#[ inline ]
#[ must_use ]
pub fn new( requests : Vec< ChatRequest > ) -> Self
{
Self
{
requests,
batch_config : None,
parallel_execution : true,
fail_fast : false,
timeout : None,
}
}
#[ inline ]
#[ must_use ]
pub fn with_config( mut self, config : BatchOperationConfig ) -> Self
{
self.batch_config = Some( config );
self
}
#[ inline ]
#[ must_use ]
pub fn with_parallel_execution( mut self, parallel : bool ) -> Self
{
self.parallel_execution = parallel;
self
}
#[ inline ]
#[ must_use ]
pub fn with_fail_fast( mut self, fail_fast : bool ) -> Self
{
self.fail_fast = fail_fast;
self
}
#[ inline ]
#[ must_use ]
pub fn with_timeout( mut self, timeout : Duration ) -> Self
{
self.timeout = Some( timeout );
self
}
#[ inline ]
#[ must_use ]
pub fn request_count( &self ) -> usize
{
self.requests.len()
}
#[ inline ]
#[ must_use ]
pub fn is_empty( &self ) -> bool
{
self.requests.is_empty()
}
}
impl BatchGenerateRequest
{
#[ inline ]
#[ must_use ]
pub fn new( requests : Vec< GenerateRequest > ) -> Self
{
Self
{
requests,
batch_config : None,
parallel_execution : true,
fail_fast : false,
timeout : None,
}
}
#[ inline ]
#[ must_use ]
pub fn with_config( mut self, config : BatchOperationConfig ) -> Self
{
self.batch_config = Some( config );
self
}
#[ inline ]
#[ must_use ]
pub fn with_parallel_execution( mut self, parallel : bool ) -> Self
{
self.parallel_execution = parallel;
self
}
#[ inline ]
#[ must_use ]
pub fn with_fail_fast( mut self, fail_fast : bool ) -> Self
{
self.fail_fast = fail_fast;
self
}
#[ inline ]
#[ must_use ]
pub fn with_timeout( mut self, timeout : Duration ) -> Self
{
self.timeout = Some( timeout );
self
}
#[ inline ]
#[ must_use ]
pub fn request_count( &self ) -> usize
{
self.requests.len()
}
#[ inline ]
#[ must_use ]
pub fn is_empty( &self ) -> bool
{
self.requests.is_empty()
}
}
impl BatchOperationConfig
{
#[ inline ]
#[ must_use ]
pub fn new() -> Self
{
Self
{
max_batch_size : 100,
concurrent_limit : 5,
retry_failed : false,
preserve_order : true,
timeout_per_request : None,
chunk_size : 10,
}
}
#[ inline ]
#[ must_use ]
pub fn with_max_batch_size( mut self, max_size : usize ) -> Self
{
self.max_batch_size = max_size.max( 1 ); self
}
#[ inline ]
#[ must_use ]
pub fn with_concurrent_limit( mut self, limit : usize ) -> Self
{
self.concurrent_limit = limit.max( 1 ); self
}
#[ inline ]
#[ must_use ]
pub fn with_retry_failed( mut self, retry : bool ) -> Self
{
self.retry_failed = retry;
self
}
#[ inline ]
#[ must_use ]
pub fn with_preserve_order( mut self, preserve : bool ) -> Self
{
self.preserve_order = preserve;
self
}
#[ inline ]
#[ must_use ]
pub fn with_timeout_per_request( mut self, timeout : Duration ) -> Self
{
self.timeout_per_request = Some( timeout );
self
}
#[ inline ]
#[ must_use ]
pub fn with_chunk_size( mut self, size : usize ) -> Self
{
self.chunk_size = size.max( 1 ); self
}
#[ inline ]
#[ must_use ]
pub fn max_batch_size( &self ) -> usize
{
self.max_batch_size
}
#[ inline ]
#[ must_use ]
pub fn concurrent_limit( &self ) -> usize
{
self.concurrent_limit
}
#[ inline ]
#[ must_use ]
pub fn retry_failed( &self ) -> bool
{
self.retry_failed
}
#[ inline ]
#[ must_use ]
pub fn preserve_order( &self ) -> bool
{
self.preserve_order
}
#[ inline ]
#[ must_use ]
pub fn timeout_per_request( &self ) -> Option< Duration >
{
self.timeout_per_request
}
#[ inline ]
#[ must_use ]
pub fn chunk_size( &self ) -> usize
{
self.chunk_size
}
}
impl Default for BatchOperationConfig
{
#[ inline ]
fn default() -> Self
{
Self::new()
}
}
impl BatchResult
{
#[ inline ]
#[ must_use ]
pub fn is_success( &self ) -> bool
{
matches!( self, BatchResult::Success( _ ) )
}
#[ inline ]
#[ must_use ]
pub fn is_error( &self ) -> bool
{
matches!( self, BatchResult::Error( _ ) )
}
#[ inline ]
#[ must_use ]
pub fn success_value( &self ) -> Option< &serde_json::Value >
{
match self
{
BatchResult::Success( value ) => Some( value ),
BatchResult::Error( _ ) => None,
}
}
#[ inline ]
#[ must_use ]
pub fn error_value( &self ) -> Option< &BatchError >
{
match self
{
BatchResult::Success( _ ) => None,
BatchResult::Error( error ) => Some( error ),
}
}
}
impl BatchError
{
#[ inline ]
#[ must_use ]
pub fn new( request_index : usize, error_code : String, error_message : String, recoverable : bool ) -> Self
{
Self
{
request_index,
error_code,
error_message,
recoverable,
}
}
#[ inline ]
#[ must_use ]
pub fn recoverable( request_index : usize, error_code : String, error_message : String ) -> Self
{
Self::new( request_index, error_code, error_message, true )
}
#[ inline ]
#[ must_use ]
pub fn non_recoverable( request_index : usize, error_code : String, error_message : String ) -> Self
{
Self::new( request_index, error_code, error_message, false )
}
#[ inline ]
#[ must_use ]
pub fn is_recoverable( &self ) -> bool
{
self.recoverable
}
}
impl BatchChatResponse
{
#[ inline ]
#[ must_use ]
pub fn success_rate( &self ) -> f64
{
if self.total_requests == 0
{
return 0.0;
}
( self.successful_requests as f64 / self.total_requests as f64 ) * 100.0
}
#[ inline ]
#[ must_use ]
pub fn all_successful( &self ) -> bool
{
self.failed_requests == 0
}
#[ inline ]
#[ must_use ]
pub fn has_failures( &self ) -> bool
{
self.failed_requests > 0
}
#[ inline ]
#[ must_use ]
pub fn successful_results( &self ) -> Vec< &serde_json::Value >
{
self.results.iter()
.filter_map( | result | result.success_value() )
.collect()
}
#[ inline ]
#[ must_use ]
pub fn error_results( &self ) -> Vec< &BatchError >
{
self.results.iter()
.filter_map( | result | result.error_value() )
.collect()
}
}
impl BatchGenerateResponse
{
#[ inline ]
#[ must_use ]
pub fn success_rate( &self ) -> f64
{
if self.total_requests == 0
{
return 0.0;
}
( self.successful_requests as f64 / self.total_requests as f64 ) * 100.0
}
#[ inline ]
#[ must_use ]
pub fn all_successful( &self ) -> bool
{
self.failed_requests == 0
}
#[ inline ]
#[ must_use ]
pub fn has_failures( &self ) -> bool
{
self.failed_requests > 0
}
#[ inline ]
#[ must_use ]
pub fn successful_results( &self ) -> Vec< &serde_json::Value >
{
self.results.iter()
.filter_map( | result | result.success_value() )
.collect()
}
#[ inline ]
#[ must_use ]
pub fn error_results( &self ) -> Vec< &BatchError >
{
self.results.iter()
.filter_map( | result | result.error_value() )
.collect()
}
}