#[ cfg( feature = "sync_api" ) ]
mod private
{
use core::time::Duration;
use std::sync::Arc;
use error_tools::untyped::{ format_err, Result as OllamaResult };
use crate::client::OllamaClient;
#[ derive( Clone ) ]
pub struct SyncOllamaClient
{
async_client : OllamaClient,
runtime : Arc< tokio::runtime::Runtime >,
config : SyncApiConfig,
}
#[ derive( Debug, Clone ) ]
pub struct SyncApiConfig
{
pub base_url : String,
pub timeout : Duration,
pub thread_pool_size : usize,
pub enable_keepalive : bool,
}
#[ derive( Debug ) ]
pub struct SyncRuntimeManager
{
thread_count : usize,
#[ allow( dead_code ) ]
runtime : Arc< tokio::runtime::Runtime >,
}
#[ derive( Debug ) ]
pub struct SyncApiConfigBuilder
{
base_url : Option< String >,
timeout : Option< Duration >,
thread_pool_size : Option< usize >,
enable_keepalive : Option< bool >,
}
#[ cfg( feature = "streaming" ) ]
pub struct SyncChatStream
{
runtime : Arc< tokio::runtime::Runtime >,
inner : std::pin::Pin< Box< dyn futures_core::Stream< Item = OllamaResult< crate::ChatResponse > > + Send > >,
}
#[ cfg( feature = "streaming" ) ]
impl std::fmt::Debug for SyncChatStream
{
fn fmt( &self, f : &mut std::fmt::Formatter< '_ > ) -> std::fmt::Result
{
f.debug_struct( "SyncChatStream" ).finish_non_exhaustive()
}
}
#[ cfg( feature = "streaming" ) ]
pub struct SyncGenerateStream
{
runtime : Arc< tokio::runtime::Runtime >,
inner : std::pin::Pin< Box< dyn futures_core::Stream< Item = OllamaResult< crate::GenerateResponse > > + Send > >,
}
#[ cfg( feature = "streaming" ) ]
impl std::fmt::Debug for SyncGenerateStream
{
fn fmt( &self, f : &mut std::fmt::Formatter< '_ > ) -> std::fmt::Result
{
f.debug_struct( "SyncGenerateStream" ).finish_non_exhaustive()
}
}
#[ cfg( feature = "streaming" ) ]
impl SyncChatStream
{
#[ inline ]
fn new( runtime : Arc< tokio::runtime::Runtime >, stream : std::pin::Pin< Box< dyn futures_core::Stream< Item = OllamaResult< crate::ChatResponse > > + Send > > ) -> Self
{
Self { runtime, inner : stream }
}
}
#[ cfg( feature = "streaming" ) ]
impl SyncGenerateStream
{
#[ inline ]
fn new( runtime : Arc< tokio::runtime::Runtime >, stream : std::pin::Pin< Box< dyn futures_core::Stream< Item = OllamaResult< crate::GenerateResponse > > + Send > > ) -> Self
{
Self { runtime, inner : stream }
}
}
#[ cfg( feature = "streaming" ) ]
impl Iterator for SyncChatStream
{
type Item = OllamaResult< crate::ChatResponse >;
#[ inline ]
fn next( &mut self ) -> Option< Self::Item >
{
use futures_util::StreamExt;
self.runtime.block_on( self.inner.next() )
}
}
#[ cfg( feature = "streaming" ) ]
impl Iterator for SyncGenerateStream
{
type Item = OllamaResult< crate::GenerateResponse >;
#[ inline ]
fn next( &mut self ) -> Option< Self::Item >
{
use futures_util::StreamExt;
self.runtime.block_on( self.inner.next() )
}
}
impl SyncOllamaClient
{
#[ inline ]
#[ must_use ]
pub fn new( base_url : &str, timeout : Duration ) -> OllamaResult< Self >
{
let async_client = OllamaClient::new( base_url.to_string(), timeout );
let runtime = tokio::runtime::Builder::new_current_thread().enable_all().build()
.map_err( | e | format_err!( "Failed to create tokio runtime : {}", e ) )?;
let config = SyncApiConfig
{
base_url : base_url.to_string(),
timeout,
thread_pool_size : 4,
enable_keepalive : true,
};
Ok( SyncOllamaClient
{
async_client,
runtime : Arc::new( runtime ),
config,
})
}
#[ inline ]
#[ must_use ]
pub fn with_config( config : SyncApiConfig ) -> OllamaResult< Self >
{
let async_client = OllamaClient::new( config.base_url.clone(), config.timeout );
let mut builder = tokio::runtime::Builder::new_current_thread();
builder.enable_all();
let runtime = builder.build()
.map_err( | e | format_err!( "Failed to create tokio runtime : {}", e ) )?;
Ok( SyncOllamaClient {
async_client,
runtime : Arc::new( runtime ),
config,
})
}
#[ inline ]
pub fn from_async( async_client : OllamaClient ) -> OllamaResult< Self >
{
let runtime = tokio::runtime::Builder::new_current_thread().enable_all().build()
.map_err( | e | format_err!( "Failed to create tokio runtime : {}", e ) )?;
let config = SyncApiConfig::default();
Ok( SyncOllamaClient {
async_client,
runtime : Arc::new( runtime ),
config,
})
}
#[ inline ]
#[ must_use ]
pub fn base_url( &self ) -> &str
{
&self.config.base_url
}
#[ inline ]
#[ must_use ]
pub fn timeout( &self ) -> Duration
{
self.config.timeout
}
#[ inline ]
#[ must_use ]
pub fn thread_pool_size( &self ) -> usize
{
self.config.thread_pool_size
}
#[ inline ]
#[ must_use ]
pub fn keepalive_enabled( &self ) -> bool
{
self.config.enable_keepalive
}
#[ inline ]
pub fn chat( &mut self, request : crate::ChatRequest ) -> OllamaResult< crate::ChatResponse >
{
let runtime = Arc::clone( &self.runtime );
runtime.block_on( self.async_client.chat( request ) )
}
#[ inline ]
pub fn generate( &mut self, request : crate::GenerateRequest ) -> OllamaResult< crate::GenerateResponse >
{
let runtime = Arc::clone( &self.runtime );
runtime.block_on( self.async_client.generate( request ) )
}
#[ inline ]
pub fn list_models( &mut self ) -> OllamaResult< crate::TagsResponse >
{
let runtime = Arc::clone( &self.runtime );
runtime.block_on( self.async_client.list_models() )
}
#[ cfg( feature = "model_details" ) ]
#[ inline ]
pub fn delete_model( &mut self, request : crate::DeleteModelRequest ) -> OllamaResult< () >
{
let runtime = Arc::clone( &self.runtime );
runtime.block_on( self.async_client.delete_model( request ) )
}
#[ cfg( feature = "embeddings" ) ]
#[ inline ]
pub fn embeddings( &mut self, request : crate::EmbeddingsRequest ) -> OllamaResult< crate::EmbeddingsResponse >
{
let runtime = Arc::clone( &self.runtime );
runtime.block_on( self.async_client.embeddings( request ) )
}
#[ cfg( feature = "count_tokens" ) ]
#[ inline ]
pub fn count_tokens( &mut self, request : crate::TokenCountRequest ) -> OllamaResult< crate::TokenCountResponse >
{
let runtime = Arc::clone( &self.runtime );
runtime.block_on( self.async_client.count_tokens( request ) )
}
#[ cfg( feature = "cached_content" ) ]
#[ inline ]
pub fn cache_content( &mut self, request : crate::CachedContentRequest ) -> OllamaResult< crate::CachedContentResponse >
{
let runtime = Arc::clone( &self.runtime );
runtime.block_on( self.async_client.cache_content( request ) )
}
#[ cfg( feature = "cached_content" ) ]
#[ inline ]
pub fn invalidate_cache( &mut self, request : crate::CacheInvalidationRequest ) -> OllamaResult< crate::CacheInvalidationResponse >
{
let runtime = Arc::clone( &self.runtime );
runtime.block_on( self.async_client.invalidate_cache( request ) )
}
#[ cfg( feature = "cached_content" ) ]
#[ inline ]
pub fn cache_metrics( &mut self ) -> OllamaResult< crate::CachePerformanceMetrics >
{
let runtime = Arc::clone( &self.runtime );
runtime.block_on( self.async_client.cache_metrics() )
}
#[ cfg( feature = "streaming" ) ]
#[ inline ]
pub fn chat_stream( &mut self, request : crate::ChatRequest ) -> OllamaResult< SyncChatStream >
{
let runtime = Arc::clone( &self.runtime );
let async_stream = runtime.block_on( self.async_client.chat_stream( request ) )?;
Ok( SyncChatStream::new( runtime, async_stream ) )
}
#[ cfg( feature = "streaming" ) ]
#[ inline ]
pub fn generate_stream( &mut self, request : crate::GenerateRequest ) -> OllamaResult< SyncGenerateStream >
{
let runtime = Arc::clone( &self.runtime );
let async_stream = runtime.block_on( self.async_client.generate_stream( request ) )?;
Ok( SyncGenerateStream::new( runtime, async_stream ) )
}
#[ inline ]
#[ must_use ]
pub fn config( &self ) -> &SyncApiConfig
{
&self.config
}
}
impl core::fmt::Debug for SyncOllamaClient
{
#[ inline ]
fn fmt( &self, f : &mut core::fmt::Formatter< '_ > ) -> core::fmt::Result
{
f.debug_struct( "SyncOllamaClient" )
.field( "config", &self.config )
.finish()
}
}
impl SyncApiConfig
{
#[ inline ]
#[ must_use ]
pub fn builder() -> SyncApiConfigBuilder
{
SyncApiConfigBuilder::default()
}
}
impl Default for SyncApiConfig
{
#[ inline ]
fn default() -> Self
{
Self
{
base_url : "http://localhost:11434".to_string(),
timeout : OllamaClient::recommended_timeout_fast(),
thread_pool_size : 4,
enable_keepalive : true,
}
}
}
impl SyncRuntimeManager
{
#[ inline ]
#[ must_use ]
pub fn new( thread_count : usize ) -> Self
{
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect( "Failed to create runtime" );
Self
{
thread_count,
runtime : Arc::new( runtime ),
}
}
#[ inline ]
#[ must_use ]
pub fn thread_count( &self ) -> usize
{
self.thread_count
}
#[ inline ]
#[ must_use ]
pub fn is_healthy( &self ) -> bool
{
true }
#[ inline ]
pub fn spawn_blocking< F, R >( &self, f : F ) -> OllamaResult< std::thread::JoinHandle< R > >
where
F : FnOnce() -> R + Send + 'static,
R : Send + 'static,
{
let handle = std::thread::spawn( f );
Ok( handle )
}
#[ inline ]
pub fn block_on< F : std::future::Future >( &self, future : F ) -> F::Output
{
self.runtime.block_on( future )
}
#[ inline ]
pub fn spawn< F >( &self, future : F ) -> tokio::task::JoinHandle< F::Output >
where
F : std::future::Future + Send + 'static,
F::Output : Send + 'static,
{
self.runtime.spawn( future )
}
}
impl SyncApiConfigBuilder
{
#[ inline ]
#[ must_use ]
pub fn new() -> Self
{
Self
{
base_url : None,
timeout : None,
thread_pool_size : None,
enable_keepalive : None,
}
}
#[ inline ]
#[ must_use ]
pub fn base_url( mut self, url : &str ) -> Self
{
self.base_url = Some( url.to_string() );
self
}
#[ inline ]
#[ must_use ]
pub fn timeout( mut self, timeout : Duration ) -> Self
{
self.timeout = Some( timeout );
self
}
#[ inline ]
#[ must_use ]
pub fn thread_pool_size( mut self, size : usize ) -> Self
{
self.thread_pool_size = Some( size );
self
}
#[ inline ]
#[ must_use ]
pub fn enable_keepalive( mut self, enable : bool ) -> Self
{
self.enable_keepalive = Some( enable );
self
}
#[ inline ]
pub fn build( self ) -> OllamaResult< SyncApiConfig >
{
let base_url = self.base_url
.ok_or_else( || format_err!( "base_url is required" ) )?;
let timeout = self.timeout.unwrap_or( Duration::from_secs( 30 ) );
let thread_pool_size = self.thread_pool_size.unwrap_or( 4 );
let enable_keepalive = self.enable_keepalive.unwrap_or( true );
Ok( SyncApiConfig {
base_url,
timeout,
thread_pool_size,
enable_keepalive,
})
}
}
impl Default for SyncApiConfigBuilder
{
#[ inline ]
fn default() -> Self
{
Self::new()
}
}
}
#[ cfg( feature = "sync_api" ) ]
crate ::mod_interface!
{
exposed use private::SyncOllamaClient;
exposed use private::SyncApiConfig;
exposed use private::SyncRuntimeManager;
exposed use private::SyncApiConfigBuilder;
#[ cfg( feature = "streaming" ) ]
exposed use private::SyncChatStream;
#[ cfg( feature = "streaming" ) ]
exposed use private::SyncGenerateStream;
}