use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum SemanticConfigError {
#[error("Invalid weight configuration: {0}")]
InvalidWeight(String),
#[error("Invalid threshold value: {0}")]
InvalidThreshold(String),
#[error("Configuration validation failed: {0}")]
ValidationError(String),
#[error("Preset configuration not found: {0}")]
PresetNotFound(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SemanticConfig {
pub general: GeneralSemanticConfig,
pub coherence: CoherenceAnalysisConfig,
pub meaning: MeaningAnalysisConfig,
pub context: ContextAnalysisConfig,
pub relations: RelationsAnalysisConfig,
pub advanced: AdvancedSemanticConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GeneralSemanticConfig {
pub case_sensitive: bool,
pub min_word_length: usize,
pub max_word_length: usize,
pub enable_lemmatization: bool,
pub filter_stopwords: bool,
pub language: String,
pub timeout_seconds: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoherenceAnalysisConfig {
pub coherence_weight: f64,
pub similarity_threshold: f64,
pub context_window: usize,
pub enable_field_coherence: bool,
pub enable_overlap_analysis: bool,
pub calculation_method: CoherenceMethod,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MeaningAnalysisConfig {
pub preservation_weight: f64,
pub clarity_weight: f64,
pub consistency_threshold: f64,
pub enable_depth_analysis: bool,
pub enable_drift_detection: bool,
pub ambiguity_sensitivity: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContextAnalysisConfig {
pub context_weight: f64,
pub window_size: usize,
pub enable_transitions: bool,
pub smoothness_threshold: f64,
pub enable_adaptation: bool,
pub change_sensitivity: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RelationsAnalysisConfig {
pub enable_synonymy: bool,
pub enable_antonymy: bool,
pub enable_hyponymy: bool,
pub enable_meronymy: bool,
pub relation_threshold: f64,
pub build_networks: bool,
pub max_network_depth: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdvancedSemanticConfig {
pub appropriateness_weight: f64,
pub enable_advanced_relations: bool,
pub enable_discourse_analysis: bool,
pub enable_topic_analysis: bool,
pub enable_figurative_analysis: bool,
pub enable_information_structure: bool,
pub min_semantic_coverage: f64,
pub analysis_depth: AnalysisDepth,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CoherenceMethod {
Overlap,
WeightedSimilarity,
VectorSimilarity,
GraphBased,
Hybrid,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AnalysisDepth {
Basic,
Standard,
Advanced,
Comprehensive,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum InconsistencyType {
ContradictoryStatements,
InconsistentTerminology,
SemanticFieldMixing,
ConceptualDrift,
ReferenceInconsistency,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum CoherenceRelationType {
Causal,
Temporal,
Contrastive,
Additive,
Elaboration,
Background,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum FocusType {
NewInformation,
Contrastive,
Corrective,
Selective,
}
impl Default for SemanticConfig {
fn default() -> Self {
Self {
general: GeneralSemanticConfig::default(),
coherence: CoherenceAnalysisConfig::default(),
meaning: MeaningAnalysisConfig::default(),
context: ContextAnalysisConfig::default(),
relations: RelationsAnalysisConfig::default(),
advanced: AdvancedSemanticConfig::default(),
}
}
}
impl Default for GeneralSemanticConfig {
fn default() -> Self {
Self {
case_sensitive: false,
min_word_length: 2,
max_word_length: 50,
enable_lemmatization: true,
filter_stopwords: true,
language: "en".to_string(),
timeout_seconds: 300,
}
}
}
impl Default for CoherenceAnalysisConfig {
fn default() -> Self {
Self {
coherence_weight: 0.25,
similarity_threshold: 0.5,
context_window: 3,
enable_field_coherence: true,
enable_overlap_analysis: true,
calculation_method: CoherenceMethod::WeightedSimilarity,
}
}
}
impl Default for MeaningAnalysisConfig {
fn default() -> Self {
Self {
preservation_weight: 0.20,
clarity_weight: 0.20,
consistency_threshold: 0.6,
enable_depth_analysis: true,
enable_drift_detection: true,
ambiguity_sensitivity: 0.7,
}
}
}
impl Default for ContextAnalysisConfig {
fn default() -> Self {
Self {
context_weight: 0.20,
window_size: 3,
enable_transitions: true,
smoothness_threshold: 0.6,
enable_adaptation: true,
change_sensitivity: 0.5,
}
}
}
impl Default for RelationsAnalysisConfig {
fn default() -> Self {
Self {
enable_synonymy: true,
enable_antonymy: true,
enable_hyponymy: true,
enable_meronymy: true,
relation_threshold: 0.5,
build_networks: true,
max_network_depth: 4,
}
}
}
impl Default for AdvancedSemanticConfig {
fn default() -> Self {
Self {
appropriateness_weight: 0.15,
enable_advanced_relations: true,
enable_discourse_analysis: true,
enable_topic_analysis: true,
enable_figurative_analysis: false,
enable_information_structure: false,
min_semantic_coverage: 0.6,
analysis_depth: AnalysisDepth::Standard,
}
}
}
impl SemanticConfig {
pub fn minimal() -> Self {
Self {
general: GeneralSemanticConfig {
case_sensitive: false,
min_word_length: 3,
max_word_length: 30,
enable_lemmatization: false,
filter_stopwords: false,
language: "en".to_string(),
timeout_seconds: 60,
},
coherence: CoherenceAnalysisConfig {
coherence_weight: 0.5,
similarity_threshold: 0.6,
context_window: 2,
enable_field_coherence: false,
enable_overlap_analysis: true,
calculation_method: CoherenceMethod::Overlap,
},
meaning: MeaningAnalysisConfig {
preservation_weight: 0.3,
clarity_weight: 0.2,
consistency_threshold: 0.5,
enable_depth_analysis: false,
enable_drift_detection: false,
ambiguity_sensitivity: 0.5,
},
context: ContextAnalysisConfig {
context_weight: 0.2,
window_size: 2,
enable_transitions: false,
smoothness_threshold: 0.5,
enable_adaptation: false,
change_sensitivity: 0.3,
},
relations: RelationsAnalysisConfig {
enable_synonymy: true,
enable_antonymy: false,
enable_hyponymy: false,
enable_meronymy: false,
relation_threshold: 0.6,
build_networks: false,
max_network_depth: 2,
},
advanced: AdvancedSemanticConfig {
appropriateness_weight: 0.0,
enable_advanced_relations: false,
enable_discourse_analysis: false,
enable_topic_analysis: false,
enable_figurative_analysis: false,
enable_information_structure: false,
min_semantic_coverage: 0.3,
analysis_depth: AnalysisDepth::Basic,
},
}
}
pub fn comprehensive() -> Self {
Self {
general: GeneralSemanticConfig {
case_sensitive: true,
min_word_length: 1,
max_word_length: 100,
enable_lemmatization: true,
filter_stopwords: true,
language: "en".to_string(),
timeout_seconds: 600,
},
coherence: CoherenceAnalysisConfig {
coherence_weight: 0.3,
similarity_threshold: 0.4,
context_window: 5,
enable_field_coherence: true,
enable_overlap_analysis: true,
calculation_method: CoherenceMethod::Hybrid,
},
meaning: MeaningAnalysisConfig {
preservation_weight: 0.25,
clarity_weight: 0.25,
consistency_threshold: 0.7,
enable_depth_analysis: true,
enable_drift_detection: true,
ambiguity_sensitivity: 0.8,
},
context: ContextAnalysisConfig {
context_weight: 0.25,
window_size: 5,
enable_transitions: true,
smoothness_threshold: 0.7,
enable_adaptation: true,
change_sensitivity: 0.7,
},
relations: RelationsAnalysisConfig {
enable_synonymy: true,
enable_antonymy: true,
enable_hyponymy: true,
enable_meronymy: true,
relation_threshold: 0.4,
build_networks: true,
max_network_depth: 6,
},
advanced: AdvancedSemanticConfig {
appropriateness_weight: 0.2,
enable_advanced_relations: true,
enable_discourse_analysis: true,
enable_topic_analysis: true,
enable_figurative_analysis: true,
enable_information_structure: true,
min_semantic_coverage: 0.8,
analysis_depth: AnalysisDepth::Comprehensive,
},
}
}
pub fn for_academic_text() -> Self {
Self {
general: GeneralSemanticConfig {
case_sensitive: true,
min_word_length: 3,
max_word_length: 50,
enable_lemmatization: true,
filter_stopwords: false,
language: "en".to_string(),
timeout_seconds: 300,
},
coherence: CoherenceAnalysisConfig {
coherence_weight: 0.35,
similarity_threshold: 0.6,
context_window: 4,
enable_field_coherence: true,
enable_overlap_analysis: true,
calculation_method: CoherenceMethod::GraphBased,
},
meaning: MeaningAnalysisConfig {
preservation_weight: 0.3,
clarity_weight: 0.25,
consistency_threshold: 0.75,
enable_depth_analysis: true,
enable_drift_detection: true,
ambiguity_sensitivity: 0.8,
},
context: ContextAnalysisConfig {
context_weight: 0.2,
window_size: 4,
enable_transitions: true,
smoothness_threshold: 0.7,
enable_adaptation: true,
change_sensitivity: 0.6,
},
relations: RelationsAnalysisConfig {
enable_synonymy: true,
enable_antonymy: true,
enable_hyponymy: true,
enable_meronymy: true,
relation_threshold: 0.5,
build_networks: true,
max_network_depth: 5,
},
advanced: AdvancedSemanticConfig {
appropriateness_weight: 0.15,
enable_advanced_relations: true,
enable_discourse_analysis: true,
enable_topic_analysis: true,
enable_figurative_analysis: false,
enable_information_structure: true,
min_semantic_coverage: 0.7,
analysis_depth: AnalysisDepth::Advanced,
},
}
}
pub fn for_creative_writing() -> Self {
Self {
general: GeneralSemanticConfig {
case_sensitive: false,
min_word_length: 1,
max_word_length: 100,
enable_lemmatization: false,
filter_stopwords: false,
language: "en".to_string(),
timeout_seconds: 300,
},
coherence: CoherenceAnalysisConfig {
coherence_weight: 0.2,
similarity_threshold: 0.4,
context_window: 5,
enable_field_coherence: true,
enable_overlap_analysis: true,
calculation_method: CoherenceMethod::VectorSimilarity,
},
meaning: MeaningAnalysisConfig {
preservation_weight: 0.15,
clarity_weight: 0.15,
consistency_threshold: 0.5,
enable_depth_analysis: true,
enable_drift_detection: true,
ambiguity_sensitivity: 0.6,
},
context: ContextAnalysisConfig {
context_weight: 0.3,
window_size: 5,
enable_transitions: true,
smoothness_threshold: 0.5,
enable_adaptation: true,
change_sensitivity: 0.8,
},
relations: RelationsAnalysisConfig {
enable_synonymy: true,
enable_antonymy: true,
enable_hyponymy: true,
enable_meronymy: true,
relation_threshold: 0.4,
build_networks: true,
max_network_depth: 4,
},
advanced: AdvancedSemanticConfig {
appropriateness_weight: 0.35,
enable_advanced_relations: true,
enable_discourse_analysis: true,
enable_topic_analysis: true,
enable_figurative_analysis: true,
enable_information_structure: true,
min_semantic_coverage: 0.5,
analysis_depth: AnalysisDepth::Comprehensive,
},
}
}
pub fn validate(&self) -> Result<(), SemanticConfigError> {
let total_weight = self.coherence.coherence_weight
+ self.meaning.preservation_weight
+ self.meaning.clarity_weight
+ self.context.context_weight
+ self.advanced.appropriateness_weight;
if total_weight > 1.2 || total_weight < 0.8 {
return Err(SemanticConfigError::ValidationError(format!(
"Total weights ({:.2}) should be approximately 1.0",
total_weight
)));
}
if self.coherence.similarity_threshold < 0.0 || self.coherence.similarity_threshold > 1.0 {
return Err(SemanticConfigError::InvalidThreshold(
"Similarity threshold must be between 0.0 and 1.0".to_string(),
));
}
if self.meaning.consistency_threshold < 0.0 || self.meaning.consistency_threshold > 1.0 {
return Err(SemanticConfigError::InvalidThreshold(
"Consistency threshold must be between 0.0 and 1.0".to_string(),
));
}
if self.coherence.context_window == 0 {
return Err(SemanticConfigError::ValidationError(
"Context window must be greater than 0".to_string(),
));
}
if self.context.window_size == 0 {
return Err(SemanticConfigError::ValidationError(
"Context window size must be greater than 0".to_string(),
));
}
Ok(())
}
pub fn cache_key(&self) -> String {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
self.coherence.coherence_weight.to_bits().hash(&mut hasher);
self.meaning.preservation_weight.to_bits().hash(&mut hasher);
self.context.context_weight.to_bits().hash(&mut hasher);
self.coherence
.similarity_threshold
.to_bits()
.hash(&mut hasher);
self.coherence.context_window.hash(&mut hasher);
self.relations.enable_synonymy.hash(&mut hasher);
self.relations.enable_antonymy.hash(&mut hasher);
self.advanced.enable_advanced_relations.hash(&mut hasher);
format!("{:x}", hasher.finish())
}
}
pub struct SemanticConfigBuilder {
config: SemanticConfig,
}
impl SemanticConfigBuilder {
pub fn new() -> Self {
Self {
config: SemanticConfig::default(),
}
}
pub fn coherence_weight(mut self, weight: f64) -> Self {
self.config.coherence.coherence_weight = weight;
self
}
pub fn preservation_weight(mut self, weight: f64) -> Self {
self.config.meaning.preservation_weight = weight;
self
}
pub fn context_weight(mut self, weight: f64) -> Self {
self.config.context.context_weight = weight;
self
}
pub fn similarity_threshold(mut self, threshold: f64) -> Self {
self.config.coherence.similarity_threshold = threshold;
self
}
pub fn enable_advanced_relations(mut self, enable: bool) -> Self {
self.config.advanced.enable_advanced_relations = enable;
self
}
pub fn analysis_depth(mut self, depth: AnalysisDepth) -> Self {
self.config.advanced.analysis_depth = depth;
self
}
pub fn build(self) -> Result<SemanticConfig, SemanticConfigError> {
self.config.validate()?;
Ok(self.config)
}
}
impl Default for SemanticConfigBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = SemanticConfig::default();
assert!(config.validate().is_ok());
}
#[test]
fn test_minimal_config() {
let config = SemanticConfig::minimal();
assert!(config.validate().is_ok());
assert_eq!(config.advanced.analysis_depth, AnalysisDepth::Basic);
}
#[test]
fn test_comprehensive_config() {
let config = SemanticConfig::comprehensive();
assert!(config.validate().is_ok());
assert_eq!(config.advanced.analysis_depth, AnalysisDepth::Comprehensive);
assert!(config.advanced.enable_figurative_analysis);
}
#[test]
fn test_academic_config() {
let config = SemanticConfig::for_academic_text();
assert!(config.validate().is_ok());
assert!(config.general.case_sensitive);
assert!(config.meaning.enable_depth_analysis);
}
#[test]
fn test_creative_config() {
let config = SemanticConfig::for_creative_writing();
assert!(config.validate().is_ok());
assert!(config.advanced.enable_figurative_analysis);
assert_eq!(config.context.context_weight, 0.3);
}
#[test]
fn test_config_builder() {
let config = SemanticConfigBuilder::new()
.coherence_weight(0.4)
.similarity_threshold(0.7)
.enable_advanced_relations(true)
.analysis_depth(AnalysisDepth::Advanced)
.build();
assert!(config.is_ok());
let config = config.expect("operation should succeed");
assert_eq!(config.coherence.coherence_weight, 0.4);
assert_eq!(config.coherence.similarity_threshold, 0.7);
assert!(config.advanced.enable_advanced_relations);
}
#[test]
fn test_invalid_weights() {
let mut config = SemanticConfig::default();
config.coherence.coherence_weight = 2.0; assert!(config.validate().is_err());
}
#[test]
fn test_invalid_threshold() {
let mut config = SemanticConfig::default();
config.coherence.similarity_threshold = 1.5; assert!(config.validate().is_err());
}
#[test]
fn test_cache_key_generation() {
let config1 = SemanticConfig::default();
let config2 = SemanticConfig::default();
let config3 = SemanticConfig::minimal();
assert_eq!(config1.cache_key(), config2.cache_key());
assert_ne!(config1.cache_key(), config3.cache_key());
}
#[test]
fn test_enum_serialization() {
let config = SemanticConfig::comprehensive();
let serialized = serde_json::to_string(&config);
assert!(serialized.is_ok());
let deserialized: Result<SemanticConfig, _> = serde_json::from_str(&serialized.expect("operation should succeed"));
assert!(deserialized.is_ok());
}
}