use oar_ocr_core::core::config::OrtSessionConfig;
use oar_ocr_core::core::traits::OrtConfigurable;
use oar_ocr_core::core::traits::adapter::AdapterBuilder;
use oar_ocr_core::core::{ModelSource, OCRError};
use std::path::{Path, PathBuf};
pub fn resolve_model_path(path: &Path) -> Result<PathBuf, OCRError> {
#[cfg(feature = "auto-download")]
{
oar_ocr_core::core::download::resolve_path(path)
}
#[cfg(not(feature = "auto-download"))]
{
Ok(path.to_path_buf())
}
}
pub fn resolve_model_source(source: &ModelSource) -> Result<ModelSource, OCRError> {
match source {
ModelSource::Path(path) => Ok(ModelSource::Path(resolve_model_path(path)?)),
memory @ ModelSource::Memory(_) => Ok(memory.clone()),
}
}
pub fn build_optional_adapter<B>(
model_source: Option<&ModelSource>,
ort_config: Option<&OrtSessionConfig>,
create_builder: impl FnOnce() -> B,
) -> Result<Option<B::Adapter>, OCRError>
where
B: AdapterBuilder + OrtConfigurable,
{
let Some(source) = model_source else {
return Ok(None);
};
let resolved = resolve_model_source(source)?;
let mut builder = create_builder();
if let Some(config) = ort_config {
builder = builder.with_ort_config(config.clone());
}
Ok(Some(builder.build(resolved)?))
}
pub(crate) fn resolve_device_batch_sizes(
ort_config: Option<&OrtSessionConfig>,
image_batch_size: Option<usize>,
region_batch_size: Option<usize>,
cpu_image_batch_size: usize,
cpu_region_batch_size: usize,
) -> (Option<usize>, Option<usize>) {
let uses_accelerator = ort_config.is_some_and(OrtSessionConfig::has_accelerator_provider);
if uses_accelerator {
(image_batch_size, region_batch_size)
} else {
(
image_batch_size.or(Some(cpu_image_batch_size)),
region_batch_size.or(Some(cpu_region_batch_size)),
)
}
}
pub(crate) fn default_cpu_region_batch_size(
model_source: Option<&ModelSource>,
model_name: Option<&str>,
) -> usize {
let source_name = model_source
.and_then(ModelSource::as_path)
.and_then(Path::file_stem)
.and_then(|name| name.to_str());
let is_tiny = model_name
.into_iter()
.chain(source_name)
.any(|name| name.to_ascii_lowercase().contains("tiny"));
if is_tiny { 16 } else { 4 }
}
#[cfg(test)]
mod tests {
use super::*;
use oar_ocr_core::core::config::OrtExecutionProvider;
#[test]
fn cpu_batch_defaults_are_applied_without_overriding_user_values() {
assert_eq!(
resolve_device_batch_sizes(None, None, None, 1, 4),
(Some(1), Some(4))
);
assert_eq!(
resolve_device_batch_sizes(None, Some(3), Some(7), 1, 4),
(Some(3), Some(7))
);
}
#[test]
fn accelerator_keeps_adapter_batch_defaults() {
let config = OrtSessionConfig::new().with_execution_providers(vec![
OrtExecutionProvider::CUDA {
device_id: Some(0),
gpu_mem_limit: None,
arena_extend_strategy: None,
cudnn_conv_algo_search: None,
cudnn_conv_use_max_workspace: None,
},
OrtExecutionProvider::CPU,
]);
assert_eq!(
resolve_device_batch_sizes(Some(&config), None, None, 1, 4),
(None, None)
);
}
#[test]
fn cpu_recognition_batch_is_model_family_aware() {
let tiny = ModelSource::from("models/pp-ocrv6_tiny_rec.onnx");
let small = ModelSource::from("models/pp-ocrv6_small_rec.onnx");
let memory = ModelSource::from(vec![0u8; 8]);
assert_eq!(default_cpu_region_batch_size(Some(&tiny), None), 16);
assert_eq!(default_cpu_region_batch_size(Some(&small), None), 4);
assert_eq!(default_cpu_region_batch_size(Some(&memory), None), 4);
assert_eq!(
default_cpu_region_batch_size(Some(&small), Some("PP-OCRv6_tiny_rec")),
16
);
}
}