use std::io::Read;
use std::sync::Arc;
use std::time::Instant;
use crate::api::{Config, Error, Input, Language, Output};
use crate::application::{DeltaStackProcessor, ExecutionMode, ProcessorConfig};
use crate::domain::language::{ConfigurableLanguageRules, LanguageRules};
pub struct SentenceProcessor {
processor: DeltaStackProcessor,
config: Config,
}
impl SentenceProcessor {
pub fn new() -> Self {
Self::with_config(Config::default()).expect("Default config should always be valid")
}
pub fn with_config(config: Config) -> Result<Self, Error> {
let language_rules = Self::create_language_rules(&config.language);
let processor_config = Self::build_processor_config(&config)?;
let processor = DeltaStackProcessor::new(processor_config, language_rules);
Ok(Self { processor, config })
}
pub fn with_custom_rules(
config: Config,
language_rules: Arc<dyn LanguageRules>,
) -> Result<Self, Error> {
let processor_config = Self::build_processor_config(&config)?;
let processor = DeltaStackProcessor::new(processor_config, language_rules);
Ok(Self { processor, config })
}
pub fn with_language(lang_code: impl Into<String>) -> Result<Self, Error> {
let config = Config::builder().language(lang_code)?.build()?;
Self::with_config(config)
}
fn create_language_rules(language: &Language) -> Arc<dyn LanguageRules> {
match language {
Language::English => Arc::new(
ConfigurableLanguageRules::from_code("en")
.expect("English configuration should be embedded"),
),
Language::Japanese => Arc::new(
ConfigurableLanguageRules::from_code("ja")
.expect("Japanese configuration should be embedded"),
),
}
}
pub fn process(&self, input: Input) -> Result<Output, Error> {
let start = Instant::now();
let text = input.into_text()?;
let mode = if let Some(threads) = self.config.threads {
if threads == 1 {
ExecutionMode::Sequential
} else {
ExecutionMode::Parallel {
threads: Some(threads),
}
}
} else {
ExecutionMode::Adaptive
};
let result = self.processor.process(&text, mode)?;
let duration = start.elapsed();
Ok(Output::from_delta_stack_result(result, &text, duration))
}
pub fn process_stream<R: Read + Send + Sync + 'static>(
&self,
reader: R,
) -> Result<Output, Error> {
self.process(Input::from_reader(reader))
}
pub fn config(&self) -> &Config {
&self.config
}
fn build_processor_config(config: &Config) -> Result<ProcessorConfig, Error> {
Ok(ProcessorConfig {
chunk_size: config.chunk_size,
parallel_threshold: config.parallel_threshold,
max_threads: config.threads,
overlap_size: config.overlap_size,
})
}
}
impl Default for SentenceProcessor {
fn default() -> Self {
Self::new()
}
}