oar_ocr_core/core/traits/adapter.rs
1//! Model adapter trait definitions for the OCR pipeline.
2//!
3//! This module defines the `ModelAdapter` trait and related types that adapt
4//! various model implementations to conform to task interfaces. Adapters handle
5//! preprocessing, inference, and postprocessing for specific models.
6
7use super::task::{Task, TaskSchema, TaskType};
8use crate::core::OCRError;
9use std::fmt::Debug;
10
11/// Information about a model adapter.
12#[derive(Debug, Clone)]
13pub struct AdapterInfo {
14 /// Name of the model (e.g., "DB", "CRNN", "RT-DETR")
15 pub model_name: String,
16 /// Task type this adapter supports
17 pub task_type: TaskType,
18 /// Description of the model
19 pub description: String,
20}
21
22impl AdapterInfo {
23 /// Creates a new adapter info.
24 pub fn new(
25 model_name: impl Into<String>,
26 task_type: TaskType,
27 description: impl Into<String>,
28 ) -> Self {
29 Self {
30 model_name: model_name.into(),
31 task_type,
32 description: description.into(),
33 }
34 }
35}
36
37/// Core trait for model adapters.
38///
39/// Adapters bridge the gap between task interfaces and concrete model implementations.
40/// They handle model-specific preprocessing, inference, and postprocessing while
41/// conforming to the task's input/output schema.
42pub trait ModelAdapter: Send + Sync + Debug {
43 /// The task type this adapter executes
44 type Task: Task;
45
46 /// Returns information about this adapter.
47 fn info(&self) -> AdapterInfo;
48
49 /// Returns the schema that this adapter conforms to.
50 fn schema(&self) -> TaskSchema {
51 TaskSchema::new(
52 self.info().task_type,
53 vec!["image".to_string()], // Most adapters work with images
54 vec!["result".to_string()],
55 )
56 }
57
58 /// Executes the model on the given input.
59 ///
60 /// This method handles the complete pipeline:
61 /// 1. Validate input
62 /// 2. Preprocess
63 /// 3. Run inference
64 /// 4. Postprocess
65 /// 5. Validate output
66 ///
67 /// # Arguments
68 ///
69 /// * `input` - The task input to process
70 /// * `config` - Optional configuration for execution
71 ///
72 /// # Returns
73 ///
74 /// The task output or an error
75 fn execute(
76 &self,
77 input: <Self::Task as Task>::Input,
78 config: Option<&<Self::Task as Task>::Config>,
79 ) -> Result<<Self::Task as Task>::Output, OCRError>;
80
81 /// Validates that this adapter is compatible with the given task schema.
82 ///
83 /// # Arguments
84 ///
85 /// * `schema` - The schema to check compatibility with
86 ///
87 /// # Returns
88 ///
89 /// Result indicating success or incompatibility error
90 fn validate_compatibility(&self, schema: &TaskSchema) -> Result<(), OCRError> {
91 let adapter_schema = self.schema();
92 if adapter_schema.task_type != schema.task_type {
93 return Err(OCRError::ConfigError {
94 message: format!(
95 "Adapter task type {:?} does not match required task type {:?}",
96 adapter_schema.task_type, schema.task_type
97 ),
98 });
99 }
100 Ok(())
101 }
102
103 /// Returns whether this adapter can handle batched inputs efficiently.
104 fn supports_batching(&self) -> bool {
105 true // Most models support batching
106 }
107
108 /// Returns the recommended batch size for this adapter.
109 fn recommended_batch_size(&self) -> usize {
110 6 // Default from constants
111 }
112}
113
114/// Builder trait for creating model adapters.
115///
116/// This trait defines the interface for building adapters with specific configurations.
117pub trait AdapterBuilder: Sized {
118 /// The configuration type for this builder
119 type Config: Send + Sync + Debug + Clone;
120
121 /// The adapter type that this builder creates
122 type Adapter: ModelAdapter;
123
124 /// Builds an adapter from a model source.
125 ///
126 /// # Arguments
127 ///
128 /// * `model_source` - Model file path or in-memory model bytes
129 ///
130 /// # Returns
131 ///
132 /// The built adapter or an error
133 fn build(
134 self,
135 model_source: impl Into<crate::core::inference::ModelSource>,
136 ) -> Result<Self::Adapter, OCRError>;
137
138 /// Configures the builder with the given configuration.
139 ///
140 /// # Arguments
141 ///
142 /// * `config` - The configuration to use
143 ///
144 /// # Returns
145 ///
146 /// The configured builder
147 fn with_config(self, config: Self::Config) -> Self;
148
149 /// Returns the adapter type identifier.
150 fn adapter_type(&self) -> &str;
151}
152
153/// Trait for adapter builders that support ONNX Runtime session configuration.
154///
155/// This trait is implemented by builders that can be configured with ORT session
156/// settings like execution providers, thread count, and memory optimization.
157pub trait OrtConfigurable: Sized {
158 /// Configures the builder with ONNX Runtime session settings.
159 fn with_ort_config(self, config: crate::core::config::OrtSessionConfig) -> Self;
160}
161
162/// A wrapper that implements Task for an adapter's task type.
163///
164/// This allows adapters to be used polymorphically through the Task trait.
165#[derive(Debug)]
166pub struct AdapterTask<A: ModelAdapter> {
167 adapter: A,
168}
169
170impl<A: ModelAdapter> AdapterTask<A> {
171 /// Creates a new adapter task.
172 pub fn new(adapter: A) -> Self {
173 Self { adapter }
174 }
175
176 /// Returns a reference to the adapter.
177 pub fn adapter(&self) -> &A {
178 &self.adapter
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn test_adapter_info_creation() {
188 let info = AdapterInfo::new(
189 "DB",
190 TaskType::TextDetection,
191 "Differentiable Binarization text detector",
192 );
193
194 assert_eq!(info.model_name, "DB");
195 assert_eq!(info.task_type, TaskType::TextDetection);
196 }
197
198 #[test]
199 fn test_schema_validation() {
200 // This is a conceptual test - actual validation would be done with real adapters
201 let schema = TaskSchema::new(
202 TaskType::TextDetection,
203 vec!["image".to_string()],
204 vec!["text_boxes".to_string()],
205 );
206
207 assert_eq!(schema.task_type, TaskType::TextDetection);
208 assert_eq!(schema.input_types, vec!["image".to_string()]);
209 }
210}