Skip to main content

voirs_g2p/
advanced.rs

1//! Advanced G2P features and enhancements.
2//!
3//! This module provides cutting-edge features for G2P conversion including
4//! real-time adaptation, multilingual support, and emotion-aware processing.
5
6use crate::{LanguageCode, Phoneme, PhoneticFeatures, Result};
7use serde::{Deserialize, Serialize};
8use std::collections::{HashMap, VecDeque};
9use std::sync::{Arc, Mutex};
10use std::time::{Instant, SystemTime};
11use tokio::sync::mpsc;
12
13/// Real-time pronunciation adaptation system
14pub struct AdaptivePronunciationSystem {
15    /// Language code
16    pub language: LanguageCode,
17    /// User correction history
18    pub correction_history: Arc<Mutex<VecDeque<UserCorrection>>>,
19    /// Adaptation model
20    pub adaptation_model: AdaptationModel,
21    /// Real-time learning rate
22    pub learning_rate: f32,
23    /// Minimum corrections before adaptation
24    pub min_corrections_threshold: usize,
25    /// Maximum history size
26    pub max_history_size: usize,
27}
28
29/// User correction for pronunciation adaptation
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct UserCorrection {
32    /// Original text
33    pub text: String,
34    /// Original phonemes generated
35    pub original_phonemes: Vec<Phoneme>,
36    /// User-corrected phonemes
37    pub corrected_phonemes: Vec<Phoneme>,
38    /// Correction timestamp
39    pub timestamp: SystemTime,
40    /// Correction context
41    pub context: Option<String>,
42    /// User confidence in correction
43    pub user_confidence: f32,
44}
45
46/// Adaptation model for learning from corrections
47#[derive(Debug, Clone, Serialize, Deserialize, Default)]
48pub struct AdaptationModel {
49    /// Word-specific adaptations
50    pub word_adaptations: HashMap<String, AdaptationRule>,
51    /// Pattern-based adaptations
52    pub pattern_adaptations: Vec<PatternAdaptation>,
53    /// Context-specific adaptations
54    pub context_adaptations: HashMap<String, Vec<AdaptationRule>>,
55    /// Adaptation statistics
56    pub stats: AdaptationStats,
57}
58
59/// Adaptation rule for pronunciation changes
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct AdaptationRule {
62    /// Source phoneme sequence
63    pub source_phonemes: Vec<String>,
64    /// Target phoneme sequence
65    pub target_phonemes: Vec<String>,
66    /// Adaptation strength (0.0-1.0)
67    pub strength: f32,
68    /// Number of corrections supporting this rule
69    pub support_count: usize,
70    /// Last updated timestamp
71    pub last_updated: SystemTime,
72}
73
74/// Pattern-based adaptation for phoneme sequences
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct PatternAdaptation {
77    /// Source pattern (regex)
78    pub source_pattern: String,
79    /// Target replacement pattern
80    pub target_pattern: String,
81    /// Pattern confidence
82    pub confidence: f32,
83    /// Usage count
84    pub usage_count: usize,
85}
86
87/// Adaptation statistics
88#[derive(Debug, Clone, Default, Serialize, Deserialize)]
89pub struct AdaptationStats {
90    /// Total corrections processed
91    pub total_corrections: usize,
92    /// Total adaptations created
93    pub total_adaptations: usize,
94    /// Average adaptation confidence
95    pub avg_confidence: f32,
96    /// Most frequent adaptations
97    pub frequent_adaptations: HashMap<String, usize>,
98}
99
100/// Multilingual phoneme mapping system
101pub struct MultilingualPhonemeMapper {
102    /// Cross-language phoneme mappings
103    pub cross_lang_mappings: HashMap<(LanguageCode, LanguageCode), PhonemeMapping>,
104    /// Universal phoneme inventory
105    pub universal_phonemes: UniversalPhonemeInventory,
106    /// Language-specific phoneme systems
107    pub language_systems: HashMap<LanguageCode, LanguagePhonemeSystem>,
108}
109
110/// Phoneme mapping between languages
111#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct PhonemeMapping {
113    /// Direct phoneme mappings
114    pub direct_mappings: HashMap<String, String>,
115    /// Approximate mappings with similarity scores
116    pub approximate_mappings: HashMap<String, Vec<(String, f32)>>,
117    /// Context-dependent mappings
118    pub context_mappings: HashMap<String, Vec<ContextualMapping>>,
119}
120
121/// Contextual phoneme mapping
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct ContextualMapping {
124    /// Source phoneme
125    pub source: String,
126    /// Target phoneme
127    pub target: String,
128    /// Context conditions
129    pub context_conditions: Vec<String>,
130    /// Mapping confidence
131    pub confidence: f32,
132}
133
134/// Universal phoneme inventory system
135#[derive(Debug, Clone, Serialize, Deserialize, Default)]
136pub struct UniversalPhonemeInventory {
137    /// IPA-based universal phonemes
138    pub universal_phonemes: HashMap<String, UniversalPhoneme>,
139    /// Feature-based phoneme classification
140    pub feature_matrix: HashMap<String, PhoneticFeatures>,
141    /// Similarity matrix between phonemes
142    pub similarity_matrix: HashMap<(String, String), f32>,
143}
144
145/// Universal phoneme representation
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct UniversalPhoneme {
148    /// IPA symbol
149    pub ipa_symbol: String,
150    /// Phonetic features
151    pub features: PhoneticFeatures,
152    /// Language-specific realizations
153    pub language_realizations: HashMap<LanguageCode, Vec<String>>,
154    /// Articulatory description
155    pub articulatory_description: String,
156}
157
158/// Language-specific phoneme system
159#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct LanguagePhonemeSystem {
161    /// Language code
162    pub language: LanguageCode,
163    /// Native phoneme inventory
164    pub native_phonemes: Vec<String>,
165    /// Allophone variations
166    pub allophones: HashMap<String, Vec<String>>,
167    /// Phonotactic constraints
168    pub phonotactic_rules: Vec<PhonotacticRule>,
169    /// Stress patterns
170    pub stress_patterns: StressPatternSystem,
171}
172
173/// Phonotactic rule for valid phoneme sequences
174#[derive(Debug, Clone, Serialize, Deserialize)]
175pub struct PhonotacticRule {
176    /// Rule type (onset, coda, nucleus)
177    pub rule_type: String,
178    /// Allowed phoneme sequences
179    pub allowed_sequences: Vec<Vec<String>>,
180    /// Forbidden sequences
181    pub forbidden_sequences: Vec<Vec<String>>,
182    /// Rule strength
183    pub strength: f32,
184}
185
186/// Stress pattern system for a language
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct StressPatternSystem {
189    /// Default stress pattern
190    pub default_pattern: Vec<u8>,
191    /// Word-specific stress rules
192    pub word_rules: HashMap<String, Vec<u8>>,
193    /// Pattern-based stress rules
194    pub pattern_rules: Vec<StressPatternRule>,
195}
196
197/// Stress pattern rule
198#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct StressPatternRule {
200    /// Word pattern (regex)
201    pub word_pattern: String,
202    /// Stress pattern to apply
203    pub stress_pattern: Vec<u8>,
204    /// Rule confidence
205    pub confidence: f32,
206}
207
208/// Phoneme quality scoring system
209pub struct PhonemeQualityScorer {
210    /// Language-specific quality models
211    pub quality_models: HashMap<LanguageCode, QualityModel>,
212    /// Cross-linguistic quality factors
213    pub global_factors: GlobalQualityFactors,
214    /// Quality assessment history
215    pub assessment_history: VecDeque<QualityAssessment>,
216}
217
218/// Quality model for phoneme assessment
219#[derive(Debug, Clone, Serialize, Deserialize)]
220pub struct QualityModel {
221    /// Phoneme-specific quality factors
222    pub phoneme_factors: HashMap<String, PhonemeQualityFactors>,
223    /// Sequence quality patterns
224    pub sequence_patterns: Vec<SequenceQualityPattern>,
225    /// Context-dependent quality adjustments
226    pub context_adjustments: HashMap<String, f32>,
227}
228
229/// Quality factors for individual phonemes
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct PhonemeQualityFactors {
232    /// Base quality score
233    pub base_quality: f32,
234    /// Frequency-based adjustment
235    pub frequency_factor: f32,
236    /// Articulatory complexity
237    pub complexity_factor: f32,
238    /// Cross-linguistic stability
239    pub stability_factor: f32,
240}
241
242/// Quality pattern for phoneme sequences
243#[derive(Debug, Clone, Serialize, Deserialize)]
244pub struct SequenceQualityPattern {
245    /// Phoneme sequence pattern
246    pub sequence_pattern: Vec<String>,
247    /// Quality modifier
248    pub quality_modifier: f32,
249    /// Pattern confidence
250    pub confidence: f32,
251}
252
253/// Global quality factors across languages
254#[derive(Debug, Clone, Serialize, Deserialize, Default)]
255pub struct GlobalQualityFactors {
256    /// Phonetic naturalness weights
257    pub naturalness_weights: HashMap<String, f32>,
258    /// Perceptual distinctiveness factors
259    pub distinctiveness_factors: HashMap<String, f32>,
260    /// Acoustic clarity measures
261    pub acoustic_factors: HashMap<String, f32>,
262}
263
264/// Quality assessment for phoneme generation
265#[derive(Debug, Clone, Serialize, Deserialize)]
266pub struct QualityAssessment {
267    /// Original text
268    pub text: String,
269    /// Generated phonemes
270    pub phonemes: Vec<Phoneme>,
271    /// Overall quality score
272    pub overall_score: f32,
273    /// Per-phoneme quality scores
274    pub phoneme_scores: Vec<f32>,
275    /// Quality factors breakdown
276    pub factor_breakdown: HashMap<String, f32>,
277    /// Assessment timestamp
278    pub timestamp: SystemTime,
279}
280
281/// Streaming G2P processor for real-time conversion
282pub struct StreamingG2pProcessor {
283    /// Language code
284    pub language: LanguageCode,
285    /// Text buffer for processing
286    pub text_buffer: Arc<Mutex<String>>,
287    /// Phoneme output stream
288    pub phoneme_sender: mpsc::UnboundedSender<StreamingPhoneme>,
289    /// Processing configuration
290    pub config: StreamingConfig,
291    /// Processing statistics
292    pub stats: Arc<Mutex<StreamingStats>>,
293}
294
295/// Streaming phoneme with timing information
296#[derive(Debug, Clone, Serialize, Deserialize)]
297pub struct StreamingPhoneme {
298    /// Phoneme data
299    pub phoneme: Phoneme,
300    /// Start time offset (milliseconds)
301    pub start_time_ms: f32,
302    /// Duration (milliseconds)
303    pub duration_ms: f32,
304    /// Streaming confidence
305    pub streaming_confidence: f32,
306    /// Word boundary indicator
307    pub is_word_boundary: bool,
308}
309
310/// Configuration for streaming G2P processing
311#[derive(Debug, Clone, Serialize, Deserialize)]
312pub struct StreamingConfig {
313    /// Buffer size for text processing
314    pub buffer_size: usize,
315    /// Processing chunk size
316    pub chunk_size: usize,
317    /// Lookahead window size
318    pub lookahead_size: usize,
319    /// Minimum processing latency (ms)
320    pub min_latency_ms: f32,
321    /// Maximum processing latency (ms)
322    pub max_latency_ms: f32,
323    /// Enable real-time adaptation
324    pub enable_adaptation: bool,
325}
326
327/// Streaming processing statistics
328#[derive(Debug, Clone, Default, Serialize, Deserialize)]
329pub struct StreamingStats {
330    /// Total characters processed
331    pub total_chars_processed: usize,
332    /// Total phonemes generated
333    pub total_phonemes_generated: usize,
334    /// Average processing latency
335    pub avg_latency_ms: f32,
336    /// Peak processing latency
337    pub peak_latency_ms: f32,
338    /// Processing throughput (chars/sec)
339    pub throughput_cps: f32,
340    /// Buffer utilization
341    pub buffer_utilization: f32,
342}
343
344/// Emotion-aware phoneme generation system
345pub struct EmotionAwareG2pProcessor {
346    /// Base G2P processor
347    pub base_processor: Arc<dyn crate::G2p>,
348    /// Emotion classification model
349    pub emotion_classifier: EmotionClassifier,
350    /// Emotion-specific phoneme modifications
351    pub emotion_modifications: HashMap<EmotionType, EmotionModification>,
352    /// Processing history
353    pub processing_history: VecDeque<EmotionProcessingEntry>,
354}
355
356/// Emotion types for phoneme modification
357#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
358pub enum EmotionType {
359    /// Neutral emotion
360    Neutral,
361    /// Happy/joyful
362    Happy,
363    /// Sad/melancholic
364    Sad,
365    /// Angry/frustrated
366    Angry,
367    /// Fearful/anxious
368    Fearful,
369    /// Surprised
370    Surprised,
371    /// Disgusted
372    Disgusted,
373    /// Excited/enthusiastic
374    Excited,
375    /// Calm/relaxed
376    Calm,
377}
378
379/// Emotion classification system
380#[derive(Debug, Clone, Serialize, Deserialize, Default)]
381pub struct EmotionClassifier {
382    /// Emotion keywords and weights
383    pub emotion_keywords: HashMap<EmotionType, HashMap<String, f32>>,
384    /// Punctuation-based emotion indicators
385    pub punctuation_indicators: HashMap<String, HashMap<EmotionType, f32>>,
386    /// Syntactic pattern indicators
387    pub syntax_indicators: Vec<SyntaxEmotionPattern>,
388    /// Classification thresholds
389    pub classification_thresholds: HashMap<EmotionType, f32>,
390}
391
392/// Syntactic pattern for emotion detection
393#[derive(Debug, Clone, Serialize, Deserialize)]
394pub struct SyntaxEmotionPattern {
395    /// Pattern description
396    pub pattern: String,
397    /// Associated emotion scores
398    pub emotion_scores: HashMap<EmotionType, f32>,
399    /// Pattern confidence
400    pub confidence: f32,
401}
402
403/// Emotion-specific phoneme modifications
404#[derive(Debug, Clone, Serialize, Deserialize)]
405pub struct EmotionModification {
406    /// Pitch modifications
407    pub pitch_modifications: HashMap<String, f32>,
408    /// Duration modifications
409    pub duration_modifications: HashMap<String, f32>,
410    /// Stress pattern changes
411    pub stress_modifications: HashMap<String, u8>,
412    /// Voice quality adjustments
413    pub voice_quality_adjustments: VoiceQualityAdjustments,
414}
415
416/// Voice quality adjustments for emotions
417#[derive(Debug, Clone, Serialize, Deserialize)]
418pub struct VoiceQualityAdjustments {
419    /// Breathiness factor
420    pub breathiness: f32,
421    /// Creakiness factor
422    pub creakiness: f32,
423    /// Tenseness factor
424    pub tenseness: f32,
425    /// Nasality factor
426    pub nasality: f32,
427}
428
429/// Emotion processing entry
430#[derive(Debug, Clone, Serialize, Deserialize)]
431pub struct EmotionProcessingEntry {
432    /// Input text
433    pub text: String,
434    /// Detected emotion
435    pub detected_emotion: EmotionType,
436    /// Emotion confidence
437    pub emotion_confidence: f32,
438    /// Original phonemes
439    pub original_phonemes: Vec<Phoneme>,
440    /// Emotion-modified phonemes
441    pub modified_phonemes: Vec<Phoneme>,
442    /// Processing timestamp
443    pub timestamp: SystemTime,
444}
445
446// Implementation for AdaptivePronunciationSystem
447impl AdaptivePronunciationSystem {
448    /// Create new adaptive pronunciation system
449    pub fn new(language: LanguageCode) -> Self {
450        Self {
451            language,
452            correction_history: Arc::new(Mutex::new(VecDeque::new())),
453            adaptation_model: AdaptationModel::default(),
454            learning_rate: 0.1,
455            min_corrections_threshold: 3,
456            max_history_size: 1000,
457        }
458    }
459
460    /// Add user correction
461    pub fn add_correction(&mut self, correction: UserCorrection) -> Result<()> {
462        {
463            let mut history = self
464                .correction_history
465                .lock()
466                .expect("lock should not be poisoned");
467
468            // Add to history
469            history.push_back(correction.clone());
470
471            // Maintain history size
472            if history.len() > self.max_history_size {
473                history.pop_front();
474            }
475        } // Drop the lock here
476
477        // Update adaptation model
478        self.update_adaptation_model(&correction)?;
479
480        Ok(())
481    }
482
483    /// Update adaptation model based on correction
484    fn update_adaptation_model(&mut self, correction: &UserCorrection) -> Result<()> {
485        // Extract phoneme sequences
486        let source_phonemes: Vec<String> = correction
487            .original_phonemes
488            .iter()
489            .map(|p| p.symbol.clone())
490            .collect();
491
492        let target_phonemes: Vec<String> = correction
493            .corrected_phonemes
494            .iter()
495            .map(|p| p.symbol.clone())
496            .collect();
497
498        // Update word-specific adaptation
499        let key = correction.text.to_lowercase();
500        if let Some(existing_rule) = self.adaptation_model.word_adaptations.get_mut(&key) {
501            existing_rule.support_count += 1;
502            existing_rule.strength = (existing_rule.strength + correction.user_confidence) / 2.0;
503            existing_rule.last_updated = SystemTime::now();
504        } else {
505            let new_rule = AdaptationRule {
506                source_phonemes,
507                target_phonemes,
508                strength: correction.user_confidence,
509                support_count: 1,
510                last_updated: SystemTime::now(),
511            };
512            self.adaptation_model.word_adaptations.insert(key, new_rule);
513        }
514
515        // Update statistics
516        self.adaptation_model.stats.total_corrections += 1;
517
518        Ok(())
519    }
520
521    /// Apply adaptations to phoneme sequence
522    pub fn apply_adaptations(&self, text: &str, phonemes: Vec<Phoneme>) -> Result<Vec<Phoneme>> {
523        let mut adapted_phonemes = phonemes;
524
525        // Apply word-specific adaptations
526        let key = text.to_lowercase();
527        if let Some(adaptation) = self.adaptation_model.word_adaptations.get(&key) {
528            if adaptation.support_count >= self.min_corrections_threshold {
529                // Create new phonemes based on adaptation
530                adapted_phonemes = adaptation
531                    .target_phonemes
532                    .iter()
533                    .map(|symbol| Phoneme::new(symbol.clone()))
534                    .collect();
535            }
536        }
537
538        Ok(adapted_phonemes)
539    }
540
541    /// Get adaptation statistics
542    pub fn get_statistics(&self) -> AdaptationStats {
543        self.adaptation_model.stats.clone()
544    }
545}
546
547impl Default for MultilingualPhonemeMapper {
548    fn default() -> Self {
549        Self::new()
550    }
551}
552
553// Implementation for MultilingualPhonemeMapper
554impl MultilingualPhonemeMapper {
555    /// Create new multilingual phoneme mapper
556    pub fn new() -> Self {
557        let mut mapper = Self {
558            cross_lang_mappings: HashMap::new(),
559            universal_phonemes: UniversalPhonemeInventory::default(),
560            language_systems: HashMap::new(),
561        };
562
563        // Initialize with basic language systems
564        mapper.initialize_language_systems();
565
566        mapper
567    }
568
569    /// Initialize basic language phoneme systems
570    fn initialize_language_systems(&mut self) {
571        // English phoneme system
572        let english_system = LanguagePhonemeSystem {
573            language: LanguageCode::EnUs,
574            native_phonemes: vec![
575                "æ".to_string(),
576                "ɑ".to_string(),
577                "ɔ".to_string(),
578                "ɛ".to_string(),
579                "ɪ".to_string(),
580                "ʊ".to_string(),
581                "ʌ".to_string(),
582                "ə".to_string(),
583                "i".to_string(),
584                "u".to_string(),
585                "eɪ".to_string(),
586                "oʊ".to_string(),
587                "aɪ".to_string(),
588                "aʊ".to_string(),
589                "ɔɪ".to_string(),
590            ],
591            allophones: HashMap::new(),
592            phonotactic_rules: Vec::new(),
593            stress_patterns: StressPatternSystem::default(),
594        };
595        self.language_systems
596            .insert(LanguageCode::EnUs, english_system);
597
598        // Add other language systems as needed
599    }
600
601    /// Map phonemes from source to target language
602    pub fn map_phonemes(
603        &self,
604        phonemes: &[Phoneme],
605        source_lang: LanguageCode,
606        target_lang: LanguageCode,
607    ) -> Result<Vec<Phoneme>> {
608        let mapping_key = (source_lang, target_lang);
609
610        if let Some(mapping) = self.cross_lang_mappings.get(&mapping_key) {
611            let mapped_phonemes = phonemes
612                .iter()
613                .map(|phoneme| self.map_single_phoneme(phoneme, mapping))
614                .collect();
615
616            Ok(mapped_phonemes)
617        } else {
618            // Use universal phoneme system for mapping
619            self.map_via_universal(phonemes, source_lang, target_lang)
620        }
621    }
622
623    /// Map single phoneme using mapping rules
624    fn map_single_phoneme(&self, phoneme: &Phoneme, mapping: &PhonemeMapping) -> Phoneme {
625        // Try direct mapping first
626        if let Some(mapped_symbol) = mapping.direct_mappings.get(&phoneme.symbol) {
627            let mut mapped_phoneme = phoneme.clone();
628            mapped_phoneme.symbol = mapped_symbol.clone();
629            return mapped_phoneme;
630        }
631
632        // Try approximate mapping
633        if let Some(approximate) = mapping.approximate_mappings.get(&phoneme.symbol) {
634            if let Some((mapped_symbol, _confidence)) = approximate.first() {
635                let mut mapped_phoneme = phoneme.clone();
636                mapped_phoneme.symbol = mapped_symbol.clone();
637                return mapped_phoneme;
638            }
639        }
640
641        // Return original if no mapping found
642        phoneme.clone()
643    }
644
645    /// Map phonemes via universal phoneme system
646    fn map_via_universal(
647        &self,
648        phonemes: &[Phoneme],
649        _source_lang: LanguageCode,
650        _target_lang: LanguageCode,
651    ) -> Result<Vec<Phoneme>> {
652        // Simplified universal mapping - in practice would use sophisticated algorithms
653        Ok(phonemes.to_vec())
654    }
655}
656
657impl Default for StressPatternSystem {
658    fn default() -> Self {
659        Self {
660            default_pattern: vec![1, 0],
661            word_rules: HashMap::new(),
662            pattern_rules: Vec::new(),
663        }
664    }
665}
666
667impl Default for PhonemeQualityScorer {
668    fn default() -> Self {
669        Self::new()
670    }
671}
672
673// Implementation for PhonemeQualityScorer
674impl PhonemeQualityScorer {
675    /// Create new phoneme quality scorer
676    pub fn new() -> Self {
677        Self {
678            quality_models: HashMap::new(),
679            global_factors: GlobalQualityFactors::default(),
680            assessment_history: VecDeque::new(),
681        }
682    }
683
684    /// Assess quality of phoneme sequence
685    pub fn assess_quality(
686        &mut self,
687        text: &str,
688        phonemes: &[Phoneme],
689        language: LanguageCode,
690    ) -> QualityAssessment {
691        let overall_score = self.calculate_overall_quality(phonemes, language);
692        let phoneme_scores = self.calculate_phoneme_scores(phonemes, language);
693        let factor_breakdown = self.calculate_factor_breakdown(phonemes, language);
694
695        let assessment = QualityAssessment {
696            text: text.to_string(),
697            phonemes: phonemes.to_vec(),
698            overall_score,
699            phoneme_scores,
700            factor_breakdown,
701            timestamp: SystemTime::now(),
702        };
703
704        // Add to history
705        self.assessment_history.push_back(assessment.clone());
706        if self.assessment_history.len() > 1000 {
707            self.assessment_history.pop_front();
708        }
709
710        assessment
711    }
712
713    /// Calculate overall quality score
714    fn calculate_overall_quality(&self, phonemes: &[Phoneme], _language: LanguageCode) -> f32 {
715        if phonemes.is_empty() {
716            return 0.0;
717        }
718
719        let total_confidence: f32 = phonemes.iter().map(|p| p.confidence).sum();
720        total_confidence / phonemes.len() as f32
721    }
722
723    /// Calculate per-phoneme quality scores
724    fn calculate_phoneme_scores(&self, phonemes: &[Phoneme], _language: LanguageCode) -> Vec<f32> {
725        phonemes.iter().map(|p| p.confidence).collect()
726    }
727
728    /// Calculate quality factor breakdown
729    fn calculate_factor_breakdown(
730        &self,
731        phonemes: &[Phoneme],
732        _language: LanguageCode,
733    ) -> HashMap<String, f32> {
734        let mut breakdown = HashMap::new();
735
736        breakdown.insert(
737            "confidence".to_string(),
738            phonemes.iter().map(|p| p.confidence).sum::<f32>() / phonemes.len() as f32,
739        );
740        breakdown.insert("naturalness".to_string(), 0.8);
741        breakdown.insert("distinctiveness".to_string(), 0.85);
742        breakdown.insert("acoustic_clarity".to_string(), 0.9);
743
744        breakdown
745    }
746}
747
748// Implementation for StreamingG2pProcessor
749impl StreamingG2pProcessor {
750    /// Create new streaming G2P processor
751    pub fn new(
752        language: LanguageCode,
753        phoneme_sender: mpsc::UnboundedSender<StreamingPhoneme>,
754    ) -> Self {
755        Self {
756            language,
757            text_buffer: Arc::new(Mutex::new(String::new())),
758            phoneme_sender,
759            config: StreamingConfig::default(),
760            stats: Arc::new(Mutex::new(StreamingStats::default())),
761        }
762    }
763
764    /// Add text to processing buffer
765    pub fn add_text(&self, text: &str) -> Result<()> {
766        let mut buffer = self
767            .text_buffer
768            .lock()
769            .expect("lock should not be poisoned");
770        buffer.push_str(text);
771
772        // Update statistics
773        let mut stats = self.stats.lock().expect("lock should not be poisoned");
774        stats.total_chars_processed += text.len();
775
776        Ok(())
777    }
778
779    /// Process buffered text and generate streaming phonemes
780    pub async fn process_buffer(&self) -> Result<()> {
781        let start_time = Instant::now();
782
783        let text_to_process = {
784            let mut buffer = self
785                .text_buffer
786                .lock()
787                .expect("lock should not be poisoned");
788            let to_process = buffer.clone();
789            buffer.clear();
790            to_process
791        };
792
793        if text_to_process.is_empty() {
794            return Ok(());
795        }
796
797        // Simple processing - in practice would use sophisticated streaming algorithms
798        let mut time_offset = 0.0f32;
799
800        for word in text_to_process.split_whitespace() {
801            // Mock phoneme generation for each character
802            for (i, char) in word.chars().enumerate() {
803                let phoneme = Phoneme::new(char.to_string());
804                let duration = 100.0; // 100ms per phoneme
805
806                let streaming_phoneme = StreamingPhoneme {
807                    phoneme,
808                    start_time_ms: time_offset,
809                    duration_ms: duration,
810                    streaming_confidence: 0.8,
811                    is_word_boundary: i == word.len() - 1,
812                };
813
814                if self.phoneme_sender.send(streaming_phoneme).is_err() {
815                    break; // Receiver dropped
816                }
817
818                time_offset += duration;
819            }
820        }
821
822        // Update statistics
823        let processing_time = start_time.elapsed().as_millis() as f32;
824        let mut stats = self.stats.lock().expect("lock should not be poisoned");
825        stats.avg_latency_ms = (stats.avg_latency_ms + processing_time) / 2.0;
826        if processing_time > stats.peak_latency_ms {
827            stats.peak_latency_ms = processing_time;
828        }
829
830        Ok(())
831    }
832
833    /// Get streaming statistics
834    pub fn get_statistics(&self) -> StreamingStats {
835        self.stats
836            .lock()
837            .expect("lock should not be poisoned")
838            .clone()
839    }
840}
841
842impl Default for StreamingConfig {
843    fn default() -> Self {
844        Self {
845            buffer_size: 1024,
846            chunk_size: 64,
847            lookahead_size: 16,
848            min_latency_ms: 10.0,
849            max_latency_ms: 100.0,
850            enable_adaptation: true,
851        }
852    }
853}
854
855// Implementation for EmotionAwareG2pProcessor
856impl EmotionAwareG2pProcessor {
857    /// Create new emotion-aware G2P processor
858    pub fn new(base_processor: Arc<dyn crate::G2p>) -> Self {
859        Self {
860            base_processor,
861            emotion_classifier: EmotionClassifier::default(),
862            emotion_modifications: HashMap::new(),
863            processing_history: VecDeque::new(),
864        }
865    }
866
867    /// Process text with emotion awareness
868    pub async fn process_with_emotion(
869        &mut self,
870        text: &str,
871        language: Option<LanguageCode>,
872    ) -> Result<Vec<Phoneme>> {
873        // Classify emotion
874        let (detected_emotion, emotion_confidence) = self.classify_emotion(text);
875
876        // Generate base phonemes
877        let base_phonemes = self.base_processor.to_phonemes(text, language).await?;
878
879        // Apply emotion modifications
880        let modified_phonemes = self.apply_emotion_modifications(&base_phonemes, &detected_emotion);
881
882        // Record processing entry
883        let entry = EmotionProcessingEntry {
884            text: text.to_string(),
885            detected_emotion: detected_emotion.clone(),
886            emotion_confidence,
887            original_phonemes: base_phonemes,
888            modified_phonemes: modified_phonemes.clone(),
889            timestamp: SystemTime::now(),
890        };
891
892        self.processing_history.push_back(entry);
893        if self.processing_history.len() > 1000 {
894            self.processing_history.pop_front();
895        }
896
897        Ok(modified_phonemes)
898    }
899
900    /// Classify emotion from text
901    fn classify_emotion(&self, text: &str) -> (EmotionType, f32) {
902        let mut emotion_scores = HashMap::new();
903
904        // Initialize scores
905        for emotion_type in [
906            EmotionType::Neutral,
907            EmotionType::Happy,
908            EmotionType::Sad,
909            EmotionType::Angry,
910            EmotionType::Fearful,
911            EmotionType::Surprised,
912            EmotionType::Disgusted,
913            EmotionType::Excited,
914            EmotionType::Calm,
915        ] {
916            emotion_scores.insert(emotion_type, 0.0f32);
917        }
918
919        // Simple keyword-based classification
920        let words: Vec<&str> = text.split_whitespace().collect();
921        for word in words {
922            let word_lower = word
923                .to_lowercase()
924                .trim_matches(|c: char| !c.is_alphabetic())
925                .to_string();
926
927            // Simple emotion keywords with better matching
928            match word_lower.as_str() {
929                "happy" | "joy" | "glad" | "wonderful" | "very" => {
930                    *emotion_scores
931                        .get_mut(&EmotionType::Happy)
932                        .expect("key was pre-initialized") += 1.0;
933                }
934                "sad" | "unhappy" | "depressed" => {
935                    *emotion_scores
936                        .get_mut(&EmotionType::Sad)
937                        .expect("key was pre-initialized") += 1.0;
938                }
939                "angry" | "mad" | "furious" | "hate" => {
940                    *emotion_scores
941                        .get_mut(&EmotionType::Angry)
942                        .expect("key was pre-initialized") += 2.0;
943                    // Higher weight for angry
944                }
945                "terrible" => {
946                    *emotion_scores
947                        .get_mut(&EmotionType::Sad)
948                        .expect("key was pre-initialized") += 0.5; // Lower weight for terrible
949                }
950                "excited" | "amazing" | "fantastic" | "awesome" => {
951                    *emotion_scores
952                        .get_mut(&EmotionType::Excited)
953                        .expect("key was pre-initialized") += 1.0;
954                }
955                _ => {
956                    *emotion_scores
957                        .get_mut(&EmotionType::Neutral)
958                        .expect("key was pre-initialized") += 0.1;
959                }
960            }
961        }
962
963        // Find highest scoring emotion with preference order for ties
964        let emotion_priority = [
965            EmotionType::Angry,
966            EmotionType::Excited,
967            EmotionType::Happy,
968            EmotionType::Sad,
969            EmotionType::Fearful,
970            EmotionType::Surprised,
971            EmotionType::Disgusted,
972            EmotionType::Calm,
973            EmotionType::Neutral,
974        ];
975
976        let mut best_emotion = EmotionType::Neutral;
977        let mut best_score = 0.0;
978
979        for emotion in emotion_priority {
980            if let Some(&score) = emotion_scores.get(&emotion) {
981                if score > best_score {
982                    best_score = score;
983                    best_emotion = emotion;
984                }
985            }
986        }
987
988        let confidence = if best_score > 0.0 { 0.8 } else { 0.5 };
989
990        (best_emotion, confidence)
991    }
992
993    /// Apply emotion-specific modifications to phonemes
994    fn apply_emotion_modifications(
995        &self,
996        phonemes: &[Phoneme],
997        emotion: &EmotionType,
998    ) -> Vec<Phoneme> {
999        if let Some(modification) = self.emotion_modifications.get(emotion) {
1000            phonemes
1001                .iter()
1002                .map(|phoneme| {
1003                    let mut modified_phoneme = phoneme.clone();
1004
1005                    // Apply duration modifications
1006                    if let Some(duration_mod) =
1007                        modification.duration_modifications.get(&phoneme.symbol)
1008                    {
1009                        if let Some(original_duration) = modified_phoneme.duration_ms {
1010                            modified_phoneme.duration_ms = Some(original_duration * duration_mod);
1011                        }
1012                    }
1013
1014                    // Apply stress modifications
1015                    if let Some(stress_mod) = modification.stress_modifications.get(&phoneme.symbol)
1016                    {
1017                        modified_phoneme.stress = *stress_mod;
1018                    }
1019
1020                    modified_phoneme
1021                })
1022                .collect()
1023        } else {
1024            phonemes.to_vec()
1025        }
1026    }
1027
1028    /// Get emotion processing history
1029    pub fn get_processing_history(&self) -> Vec<EmotionProcessingEntry> {
1030        self.processing_history.iter().cloned().collect()
1031    }
1032}
1033
1034impl Default for VoiceQualityAdjustments {
1035    fn default() -> Self {
1036        Self {
1037            breathiness: 0.0,
1038            creakiness: 0.0,
1039            tenseness: 0.0,
1040            nasality: 0.0,
1041        }
1042    }
1043}
1044
1045#[cfg(test)]
1046mod tests {
1047    use super::*;
1048
1049    #[test]
1050    fn test_adaptive_pronunciation_system() {
1051        let mut system = AdaptivePronunciationSystem::new(LanguageCode::EnUs);
1052
1053        let correction = UserCorrection {
1054            text: "tomato".to_string(),
1055            original_phonemes: vec![Phoneme::new("təˈmeɪtoʊ")],
1056            corrected_phonemes: vec![Phoneme::new("təˈmɑːtoʊ")],
1057            timestamp: SystemTime::now(),
1058            context: None,
1059            user_confidence: 0.9,
1060        };
1061
1062        assert!(system.add_correction(correction).is_ok());
1063        assert_eq!(system.adaptation_model.word_adaptations.len(), 1);
1064    }
1065
1066    #[test]
1067    fn test_multilingual_phoneme_mapper() {
1068        let mapper = MultilingualPhonemeMapper::new();
1069
1070        let phonemes = vec![Phoneme::new("æ")];
1071        let result = mapper.map_phonemes(&phonemes, LanguageCode::EnUs, LanguageCode::De);
1072
1073        assert!(result.is_ok());
1074    }
1075
1076    #[test]
1077    fn test_phoneme_quality_scorer() {
1078        let mut scorer = PhonemeQualityScorer::new();
1079
1080        let phonemes = vec![
1081            Phoneme::with_confidence("h", 0.9),
1082            Phoneme::with_confidence("ɛ", 0.8),
1083            Phoneme::with_confidence("l", 0.85),
1084        ];
1085
1086        let assessment = scorer.assess_quality("hello", &phonemes, LanguageCode::EnUs);
1087
1088        assert!(assessment.overall_score > 0.0);
1089        assert_eq!(assessment.phoneme_scores.len(), 3);
1090    }
1091
1092    #[tokio::test]
1093    async fn test_streaming_g2p_processor() {
1094        let (sender, mut receiver) = mpsc::unbounded_channel();
1095        let processor = StreamingG2pProcessor::new(LanguageCode::EnUs, sender);
1096
1097        assert!(processor.add_text("hello").is_ok());
1098        assert!(processor.process_buffer().await.is_ok());
1099
1100        // Check if we received streaming phonemes
1101        if let Ok(streaming_phoneme) = receiver.try_recv() {
1102            assert!(!streaming_phoneme.phoneme.symbol.is_empty());
1103        }
1104    }
1105
1106    #[tokio::test]
1107    async fn test_emotion_aware_processor() {
1108        let dummy_processor = Arc::new(crate::DummyG2p::new());
1109        let mut emotion_processor = EmotionAwareG2pProcessor::new(dummy_processor);
1110
1111        let result = emotion_processor
1112            .process_with_emotion("I am very happy!", Some(LanguageCode::EnUs))
1113            .await;
1114
1115        assert!(result.is_ok());
1116        assert_eq!(emotion_processor.processing_history.len(), 1);
1117
1118        let entry = &emotion_processor.processing_history[0];
1119        // Should detect happy emotion
1120        assert_eq!(entry.detected_emotion, EmotionType::Happy);
1121    }
1122
1123    #[test]
1124    fn test_emotion_classification() {
1125        let dummy_processor = Arc::new(crate::DummyG2p::new());
1126        let emotion_processor = EmotionAwareG2pProcessor::new(dummy_processor);
1127
1128        let (emotion, confidence) =
1129            emotion_processor.classify_emotion("I am so excited about this!");
1130        assert_eq!(emotion, EmotionType::Excited);
1131        assert!(confidence > 0.0);
1132
1133        let (emotion, _) =
1134            emotion_processor.classify_emotion("This is terrible and makes me angry!");
1135        assert_eq!(emotion, EmotionType::Angry);
1136    }
1137}