use serde::{Deserialize, Serialize};
use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProsodicConfig {
pub general: GeneralProsodicConfig,
pub rhythm: RhythmAnalysisConfig,
pub stress: StressAnalysisConfig,
pub intonation: IntonationAnalysisConfig,
pub timing: TimingAnalysisConfig,
pub phonological: PhonologicalAnalysisConfig,
pub advanced: AdvancedProsodicConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GeneralProsodicConfig {
pub enabled: bool,
pub max_text_length: usize,
pub sentence_delimiters: Vec<char>,
pub word_delimiters: Vec<char>,
pub use_caching: bool,
pub cache_size_limit: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RhythmAnalysisConfig {
pub enabled: bool,
pub rhythm_weight: f64,
pub prefer_regular_rhythm: bool,
pub enable_template_matching: bool,
pub max_rhythm_templates: usize,
pub beat_detection_sensitivity: f64,
pub alternation_preference: f64,
pub enable_rhythm_classification: bool,
pub rhythm_complexity_threshold: f64,
pub min_pattern_length: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StressAnalysisConfig {
pub enabled: bool,
pub stress_weight: f64,
pub enable_stress_prediction: bool,
pub enable_metrical_analysis: bool,
pub metrical_consistency_threshold: f64,
pub enable_prominence_analysis: bool,
pub foot_boundary_accuracy: f64,
pub detect_stress_clashes: bool,
pub primary_stress_preference: f64,
pub enable_accent_analysis: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntonationAnalysisConfig {
pub enabled: bool,
pub intonation_weight: f64,
pub enable_pitch_contour: bool,
pub enable_boundary_tone: bool,
pub detect_focus_patterns: bool,
pub classify_sentence_types: bool,
pub analyze_pitch_range: bool,
pub detect_intonational_phrases: bool,
pub contour_smoothness_preference: f64,
pub enable_tonal_accents: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimingAnalysisConfig {
pub enabled: bool,
pub pause_weight: f64,
pub enable_break_detection: bool,
pub pause_accuracy_threshold: f64,
pub enable_tempo_analysis: bool,
pub tempo_regularity_preference: f64,
pub enable_duration_analysis: bool,
pub analyze_syllable_timing: bool,
pub calculate_speech_rate: bool,
pub analyze_timing_variability: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PhonologicalAnalysisConfig {
pub enabled: bool,
pub detect_alliteration: bool,
pub detect_assonance: bool,
pub detect_consonance: bool,
pub detect_rhyme: bool,
pub pattern_sensitivity: f64,
pub sound_similarity_threshold: f64,
pub enable_phonotactics: bool,
pub analyze_syllable_structure: bool,
pub analyze_euphony: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdvancedProsodicConfig {
pub enabled: bool,
pub analyze_prosodic_hierarchy: bool,
pub analyze_complexity: bool,
pub complexity_method: ComplexityMethod,
pub calculate_entropy: bool,
pub use_ml_features: bool,
pub feature_dimensions: usize,
pub use_neural_modeling: bool,
pub advanced_caching: bool,
pub enable_profiling: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ComplexityMethod {
InformationEntropy,
PatternVariation,
HierarchicalComplexity,
Combined,
}
#[derive(Debug, Clone, Copy)]
pub enum ProsodicAnalysisPreset {
Minimal,
Comprehensive,
SpeechSynthesis,
LanguageLearning,
LinguisticResearch,
ReadingFluency,
}
impl ProsodicConfig {
pub fn minimal() -> Self {
Self {
general: GeneralProsodicConfig {
enabled: true,
max_text_length: 10000,
sentence_delimiters: vec!['.', '!', '?'],
word_delimiters: vec![' ', '\t', '\n'],
use_caching: false,
cache_size_limit: 1000,
},
rhythm: RhythmAnalysisConfig {
enabled: true,
rhythm_weight: 0.4,
prefer_regular_rhythm: true,
enable_template_matching: false,
max_rhythm_templates: 10,
beat_detection_sensitivity: 0.5,
alternation_preference: 0.6,
enable_rhythm_classification: false,
rhythm_complexity_threshold: 0.7,
min_pattern_length: 3,
},
stress: StressAnalysisConfig {
enabled: true,
stress_weight: 0.3,
enable_stress_prediction: false,
enable_metrical_analysis: false,
metrical_consistency_threshold: 0.6,
enable_prominence_analysis: false,
foot_boundary_accuracy: 0.7,
detect_stress_clashes: false,
primary_stress_preference: 0.8,
enable_accent_analysis: false,
},
intonation: IntonationAnalysisConfig {
enabled: true,
intonation_weight: 0.3,
enable_pitch_contour: false,
enable_boundary_tone: false,
detect_focus_patterns: false,
classify_sentence_types: true,
analyze_pitch_range: false,
detect_intonational_phrases: false,
contour_smoothness_preference: 0.7,
enable_tonal_accents: false,
},
timing: TimingAnalysisConfig {
enabled: false,
pause_weight: 0.0,
enable_break_detection: false,
pause_accuracy_threshold: 0.7,
enable_tempo_analysis: false,
tempo_regularity_preference: 0.6,
enable_duration_analysis: false,
analyze_syllable_timing: false,
calculate_speech_rate: false,
analyze_timing_variability: false,
},
phonological: PhonologicalAnalysisConfig {
enabled: false,
detect_alliteration: false,
detect_assonance: false,
detect_consonance: false,
detect_rhyme: false,
pattern_sensitivity: 0.5,
sound_similarity_threshold: 0.6,
enable_phonotactics: false,
analyze_syllable_structure: false,
analyze_euphony: false,
},
advanced: AdvancedProsodicConfig {
enabled: false,
analyze_prosodic_hierarchy: false,
analyze_complexity: false,
complexity_method: ComplexityMethod::InformationEntropy,
calculate_entropy: false,
use_ml_features: false,
feature_dimensions: 50,
use_neural_modeling: false,
advanced_caching: false,
enable_profiling: false,
},
}
}
pub fn comprehensive() -> Self {
Self {
general: GeneralProsodicConfig {
enabled: true,
max_text_length: 50000,
sentence_delimiters: vec!['.', '!', '?', ';', ':'],
word_delimiters: vec![' ', '\t', '\n', '-', '_'],
use_caching: true,
cache_size_limit: 10000,
},
rhythm: RhythmAnalysisConfig {
enabled: true,
rhythm_weight: 0.25,
prefer_regular_rhythm: true,
enable_template_matching: true,
max_rhythm_templates: 50,
beat_detection_sensitivity: 0.7,
alternation_preference: 0.8,
enable_rhythm_classification: true,
rhythm_complexity_threshold: 0.5,
min_pattern_length: 2,
},
stress: StressAnalysisConfig {
enabled: true,
stress_weight: 0.20,
enable_stress_prediction: true,
enable_metrical_analysis: true,
metrical_consistency_threshold: 0.8,
enable_prominence_analysis: true,
foot_boundary_accuracy: 0.9,
detect_stress_clashes: true,
primary_stress_preference: 0.9,
enable_accent_analysis: true,
},
intonation: IntonationAnalysisConfig {
enabled: true,
intonation_weight: 0.20,
enable_pitch_contour: true,
enable_boundary_tone: true,
detect_focus_patterns: true,
classify_sentence_types: true,
analyze_pitch_range: true,
detect_intonational_phrases: true,
contour_smoothness_preference: 0.8,
enable_tonal_accents: true,
},
timing: TimingAnalysisConfig {
enabled: true,
pause_weight: 0.15,
enable_break_detection: true,
pause_accuracy_threshold: 0.8,
enable_tempo_analysis: true,
tempo_regularity_preference: 0.7,
enable_duration_analysis: true,
analyze_syllable_timing: true,
calculate_speech_rate: true,
analyze_timing_variability: true,
},
phonological: PhonologicalAnalysisConfig {
enabled: true,
detect_alliteration: true,
detect_assonance: true,
detect_consonance: true,
detect_rhyme: true,
pattern_sensitivity: 0.7,
sound_similarity_threshold: 0.8,
enable_phonotactics: true,
analyze_syllable_structure: true,
analyze_euphony: true,
},
advanced: AdvancedProsodicConfig {
enabled: true,
analyze_prosodic_hierarchy: true,
analyze_complexity: true,
complexity_method: ComplexityMethod::Combined,
calculate_entropy: true,
use_ml_features: true,
feature_dimensions: 100,
use_neural_modeling: true,
advanced_caching: true,
enable_profiling: true,
},
}
}
pub fn speech_synthesis() -> Self {
let mut config = Self::comprehensive();
config.rhythm.rhythm_weight = 0.35;
config.stress.stress_weight = 0.30;
config.intonation.intonation_weight = 0.25;
config.timing.pause_weight = 0.10;
config.rhythm.enable_rhythm_classification = true;
config.stress.enable_prominence_analysis = true;
config.intonation.enable_pitch_contour = true;
config.timing.enable_tempo_analysis = true;
config
}
pub fn language_learning() -> Self {
let mut config = Self::comprehensive();
config.stress.stress_weight = 0.35;
config.intonation.intonation_weight = 0.30;
config.rhythm.rhythm_weight = 0.25;
config.phonological.pattern_sensitivity = 0.8;
config.stress.detect_stress_clashes = true;
config.intonation.classify_sentence_types = true;
config.phonological.analyze_euphony = true;
config
}
pub fn linguistic_research() -> Self {
let mut config = Self::comprehensive();
config.advanced.analyze_prosodic_hierarchy = true;
config.advanced.calculate_entropy = true;
config.advanced.use_ml_features = true;
config.advanced.enable_profiling = true;
config.phonological.enable_phonotactics = true;
config.timing.analyze_timing_variability = true;
config.stress.enable_metrical_analysis = true;
config
}
pub fn reading_fluency() -> Self {
let mut config = Self::minimal();
config.rhythm.enabled = true;
config.rhythm.rhythm_weight = 0.40;
config.stress.enabled = true;
config.stress.stress_weight = 0.30;
config.timing.enabled = true;
config.timing.pause_weight = 0.20;
config.intonation.intonation_weight = 0.10;
config.timing.enable_break_detection = true;
config.timing.calculate_speech_rate = true;
config.rhythm.prefer_regular_rhythm = true;
config
}
pub fn from_preset(preset: ProsodicAnalysisPreset) -> Self {
match preset {
ProsodicAnalysisPreset::Minimal => Self::minimal(),
ProsodicAnalysisPreset::Comprehensive => Self::comprehensive(),
ProsodicAnalysisPreset::SpeechSynthesis => Self::speech_synthesis(),
ProsodicAnalysisPreset::LanguageLearning => Self::language_learning(),
ProsodicAnalysisPreset::LinguisticResearch => Self::linguistic_research(),
ProsodicAnalysisPreset::ReadingFluency => Self::reading_fluency(),
}
}
pub fn validate(&self) -> Result<(), String> {
let total_weight = self.rhythm.rhythm_weight
+ self.stress.stress_weight
+ self.intonation.intonation_weight
+ self.timing.pause_weight;
if total_weight <= 0.0 {
return Err("Sum of component weights must be positive".to_string());
}
if self.stress.metrical_consistency_threshold < 0.0
|| self.stress.metrical_consistency_threshold > 1.0
{
return Err("Metrical consistency threshold must be between 0.0 and 1.0".to_string());
}
if self.phonological.sound_similarity_threshold < 0.0
|| self.phonological.sound_similarity_threshold > 1.0
{
return Err("Sound similarity threshold must be between 0.0 and 1.0".to_string());
}
if self.general.cache_size_limit == 0 && self.general.use_caching {
return Err("Cache size limit must be positive when caching is enabled".to_string());
}
Ok(())
}
pub fn cache_key(&self) -> u64 {
let mut hasher = DefaultHasher::new();
self.general.max_text_length.hash(&mut hasher);
self.rhythm.enabled.hash(&mut hasher);
self.stress.enabled.hash(&mut hasher);
self.intonation.enabled.hash(&mut hasher);
self.timing.enabled.hash(&mut hasher);
self.phonological.enabled.hash(&mut hasher);
self.advanced.enabled.hash(&mut hasher);
hasher.finish()
}
}
impl Default for ProsodicConfig {
fn default() -> Self {
Self::comprehensive()
}
}
impl Hash for ProsodicConfig {
fn hash<H: Hasher>(&self, state: &mut H) {
self.general.enabled.hash(state);
self.rhythm.enabled.hash(state);
self.stress.enabled.hash(state);
self.intonation.enabled.hash(state);
self.timing.enabled.hash(state);
self.phonological.enabled.hash(state);
self.advanced.enabled.hash(state);
((self.rhythm.rhythm_weight * 1000.0) as i32).hash(state);
((self.stress.stress_weight * 1000.0) as i32).hash(state);
((self.intonation.intonation_weight * 1000.0) as i32).hash(state);
((self.timing.pause_weight * 1000.0) as i32).hash(state);
}
}
pub struct ProsodicConfigBuilder {
config: ProsodicConfig,
}
impl ProsodicConfigBuilder {
pub fn new() -> Self {
Self {
config: ProsodicConfig::default(),
}
}
pub fn from_preset(preset: ProsodicAnalysisPreset) -> Self {
Self {
config: ProsodicConfig::from_preset(preset),
}
}
pub fn rhythm_analysis(mut self, enabled: bool) -> Self {
self.config.rhythm.enabled = enabled;
self
}
pub fn rhythm_weight(mut self, weight: f64) -> Self {
self.config.rhythm.rhythm_weight = weight;
self
}
pub fn stress_analysis(mut self, enabled: bool) -> Self {
self.config.stress.enabled = enabled;
self
}
pub fn stress_weight(mut self, weight: f64) -> Self {
self.config.stress.stress_weight = weight;
self
}
pub fn intonation_analysis(mut self, enabled: bool) -> Self {
self.config.intonation.enabled = enabled;
self
}
pub fn intonation_weight(mut self, weight: f64) -> Self {
self.config.intonation.intonation_weight = weight;
self
}
pub fn timing_analysis(mut self, enabled: bool) -> Self {
self.config.timing.enabled = enabled;
self
}
pub fn pause_weight(mut self, weight: f64) -> Self {
self.config.timing.pause_weight = weight;
self
}
pub fn phonological_analysis(mut self, enabled: bool) -> Self {
self.config.phonological.enabled = enabled;
self
}
pub fn advanced_analysis(mut self, enabled: bool) -> Self {
self.config.advanced.enabled = enabled;
self
}
pub fn cache_size(mut self, size: usize) -> Self {
self.config.general.cache_size_limit = size;
self
}
pub fn build(self) -> Result<ProsodicConfig, String> {
self.config.validate()?;
Ok(self.config)
}
}
impl Default for ProsodicConfigBuilder {
fn default() -> Self {
Self::new()
}
}