1#![allow(clippy::cast_precision_loss)] #![allow(clippy::cast_possible_truncation)] #![allow(clippy::cast_sign_loss)] #![allow(clippy::missing_errors_doc)] #![allow(clippy::missing_panics_doc)] #![allow(clippy::unused_self)] #![allow(clippy::must_use_candidate)] #![allow(clippy::doc_markdown)] #![allow(clippy::unnecessary_wraps)] #![allow(clippy::float_cmp)] #![allow(clippy::match_same_arms)] #![allow(clippy::module_name_repetitions)] #![allow(clippy::struct_excessive_bools)] #![allow(clippy::too_many_lines)] #![allow(clippy::needless_pass_by_value)] #![allow(clippy::similar_names)] #![allow(clippy::unused_async)] #![allow(clippy::needless_range_loop)] #![allow(clippy::uninlined_format_args)] #![allow(clippy::manual_clamp)] #![allow(clippy::return_self_not_must_use)] #![allow(clippy::cast_possible_wrap)] #![allow(clippy::cast_lossless)] #![allow(clippy::wildcard_imports)] #![allow(clippy::format_push_string)] #![allow(clippy::redundant_closure_for_method_calls)] #![warn(missing_docs)]
143#![warn(clippy::all)]
144#![allow(clippy::module_name_repetitions)]
145#![allow(clippy::field_reassign_with_default)]
146#![allow(clippy::manual_clamp)]
147#![allow(clippy::type_complexity)]
148#![allow(unused_comparisons)]
149#![allow(clippy::absurd_extreme_comparisons)]
150#![allow(clippy::assertions_on_constants)]
151#![allow(clippy::needless_range_loop)]
152#![allow(clippy::match_like_matches_macro)]
153#![allow(clippy::if_same_then_else)]
154#![allow(clippy::useless_vec)]
155#![allow(clippy::vec_init_then_push)]
156#![allow(clippy::too_many_arguments)]
157#![allow(clippy::redundant_locals)]
158#![allow(clippy::manual_range_contains)]
159#![allow(unused_must_use)]
160#![allow(clippy::to_string_trait_impl)]
161#![allow(clippy::module_inception)]
162#![allow(clippy::mixed_attributes_style)]
163#![allow(clippy::large_enum_variant)]
164#![allow(clippy::format_in_format_args)]
165#![allow(clippy::extra_unused_lifetimes)]
166#![allow(clippy::empty_line_after_doc_comments)]
167#![allow(clippy::duplicated_attributes)]
168#![allow(clippy::len_zero)]
169#![allow(clippy::approx_constant)]
170
171pub use voirs_evaluation::{ComparisonResult, PronunciationScore, QualityScore};
173pub use voirs_recognizer::traits::{PhonemeAlignment, Transcript};
174pub use voirs_sdk::{AudioBuffer, LanguageCode, Phoneme, VoirsError};
175
176use async_trait::async_trait;
178use std::time::Duration;
179
180pub mod accessibility;
182pub mod adaptive;
183pub mod ai_coaching;
184pub mod analytics;
185pub mod audit_trail;
186pub mod batch_utils;
187pub mod bi_dashboard;
188pub mod cdn_support;
189pub mod cloud_deployment;
190pub mod computer_vision;
191pub mod cultural_adaptation;
192pub mod data_anonymization;
193pub mod data_management;
194pub mod data_pipeline;
195pub mod data_quality;
196pub mod data_retention;
197#[cfg(feature = "adaptive")]
198pub mod deep_learning_feedback;
199pub mod emotional_intelligence;
201pub mod enhanced_performance;
202pub mod enterprise;
204pub mod error_context;
205pub mod error_tracking;
206pub mod float_utils;
207#[cfg(feature = "gamification")]
208pub mod gamification;
209pub mod gdpr;
210pub mod google_classroom;
211pub mod group_learning;
212pub mod health;
213pub mod i18n_formatting;
214pub mod i18n_support;
215pub mod integration;
216pub mod load_balancer;
217pub mod memory_monitor;
218pub mod metrics_dashboard;
219#[cfg(feature = "microservices")]
220pub mod microservices;
221pub mod natural_language_generation;
222pub mod oauth2_auth;
223pub mod peer_learning;
224pub mod performance_helpers;
225pub mod performance_monitoring;
226pub mod persistence;
227pub mod platform;
228pub mod progress;
229pub mod quality_monitor;
230pub mod rate_limiting;
231pub mod realtime;
232pub mod recovery;
233pub mod secure_sharing;
234pub mod statistical_helpers;
235pub mod third_party_bots;
236pub mod timezone_support;
237pub mod training;
238pub mod traits;
239pub mod tts_integration;
240pub mod usage_analytics;
241pub mod user_management;
242pub mod utils;
243pub mod ux_analytics;
244pub mod validation_helpers;
245pub mod visualization;
246pub mod voice_control;
247pub mod webhooks;
248
249pub use traits::*;
251
252pub use adaptive::core::AdaptiveFeedbackEngine;
254pub use progress::core::ProgressAnalyzer;
255pub use realtime::stream::FeedbackStream;
256pub use realtime::system::RealtimeFeedbackSystem;
257pub use training::core::InteractiveTrainer;
258
259pub const VERSION: &str = env!("CARGO_PKG_VERSION");
265
266pub mod prelude {
268 pub use crate::traits::{
271 AdaptiveConfig, AdaptiveLearner, FeedbackConfig, FeedbackProvider, FeedbackResult,
272 FeedbackSession, ProgressConfig, ProgressTracker, SessionState, TrainingExercise,
273 TrainingProvider, TrainingResult, UserFeedback,
274 };
275
276 pub use crate::adaptive::core::AdaptiveFeedbackEngine;
277 pub use crate::adaptive::types::LearningStyle;
278 pub use crate::bi_dashboard::{
279 BiDashboard, DashboardConfig, DashboardSnapshot, HealthStatus as DashboardHealthStatus,
280 KPIs, ReportFormat, TrendAnalysis, WidgetType,
281 };
282 pub use crate::cdn_support::{
283 CdnAsset, CdnConfig, CdnManager, CdnProvider, CdnReport, EdgeLocation, GeoRegion,
284 InvalidationRequest, PriceClass,
285 };
286 pub use crate::cloud_deployment::{
287 CloudOrchestrator, CloudProvider, DeploymentConfig, KubernetesOrchestrator,
288 };
289 pub use crate::data_management::{DataExportPackage, DataManager, ExportFormat, ImportOptions};
290 pub use crate::data_pipeline::{
291 DataPipeline, DataProcessor, DataSink, DataType, PipelineConfig,
292 };
293 pub use crate::error_context::{
294 ErrorCategory, ErrorContext, ErrorContextBuilder, ErrorSeverity,
295 };
296 pub use crate::gdpr::{
297 ConsentRecord, DataSubject, GdprCompliance, GdprComplianceManager, ProcessingPurpose,
298 };
299 pub use crate::health::{
300 ComponentHealth, HealthConfig, HealthMonitor, HealthReport, HealthStatus,
301 };
302 pub use crate::load_balancer::{
303 LoadBalancer, LoadBalancerConfig, LoadBalancingAlgorithm, WorkerNode,
304 };
305 pub use crate::progress::core::ProgressAnalyzer;
306 pub use crate::quality_monitor::{
307 QualityAlert, QualityMetrics, QualityMonitor, QualityMonitorConfig,
308 };
309 pub use crate::rate_limiting::{
310 RateLimitAlgorithm, RateLimitConfig, RateLimitStatus, RateLimiter as ApiRateLimiter,
311 TieredRateLimiter,
312 };
313 pub use crate::realtime::stream::FeedbackStream;
314 pub use crate::realtime::system::RealtimeFeedbackSystem;
315 pub use crate::training::core::InteractiveTrainer;
316 pub use crate::training::types::TrainingSession;
317 pub use crate::traits::UserProgress;
318 pub use crate::usage_analytics::{
319 AnalyticsEvent, CohortAnalysis, EventType, FeatureMetrics, FunnelAnalysis, TimeSeriesPoint,
320 UsageAnalytics, UsageReport,
321 };
322 pub use crate::voice_control::{
323 CommandCategory, VoiceCommand, VoiceControlConfig, VoiceControlManager, VoiceIntent,
324 };
325 pub use crate::webhooks::{
326 DeliveryStatus, RetryConfig, WebhookConfig, WebhookEvent, WebhookManager, WebhookStats,
327 };
328
329 pub use crate::accessibility::{
331 AccessibilityConfig, AccessibilityManager, AnnouncementPriority, Color, ColorBlindnessMode,
332 FocusNavigation, KeyboardShortcut, ScreenReaderAnnouncement, ShortcutCategory, WcagLevel,
333 };
334 pub use crate::audit_trail::{
335 AuditAction, AuditContext, AuditEntry, AuditLogger, AuditQuery, ComplianceReport,
336 ResourceType,
337 };
338 pub use crate::batch_utils::{
339 process_batches, AdaptiveBatchSize, BatchConfig, BatchProcessor, BatchResult, ChunkIterator,
340 };
341 pub use crate::data_anonymization::{
342 AnonymizationPolicy, AnonymizationRule, AnonymizationTechnique, DataAnonymizer,
343 RiskAssessment, SensitivityLevel,
344 };
345 pub use crate::data_quality::{
346 DataQualityMonitor, QualityDimension, QualityMetrics as DataQualityMetrics, QualityReport,
347 ValidationResult as DataValidationResult,
348 };
349 pub use crate::data_retention::{
350 DataCategory, RetentionAction, RetentionCondition, RetentionManager, RetentionPolicy,
351 RetentionReport, RetentionRule, RetentionStatistics,
352 };
353 pub use crate::error_tracking::{
354 ErrorContext as ErrorTrackingContext, ErrorEvent, ErrorGroup,
355 ErrorSeverity as ErrorTrackingSeverity, ErrorStatistics, ErrorTracker, ErrorTrend,
356 };
357 pub use crate::float_utils::{
358 approx_cmp, approx_eq, approx_eq_f32, approx_eq_f64, approx_eq_relative, approx_ge,
359 approx_gt, approx_le, approx_lt, approx_max, approx_min, approx_ne, approx_one,
360 approx_zero, clamp_with_epsilon, in_range, F32_EPSILON, F64_EPSILON, RELATIVE_EPSILON,
361 };
362 pub use crate::performance_monitoring::{
363 AlertRule, AlertSeverity, MetricStatistics, MetricType, PerformanceMonitor,
364 };
365 pub use crate::secure_sharing::{
366 AccessLevel, AccessLogEntry, AccessResult, DataCategory as SharingDataCategory,
367 SecureSharingManager, ShareConfig, ShareStatus, ShareToken, SharedDataPackage,
368 SharingProtocol, SharingStatistics,
369 };
370 pub use crate::statistical_helpers::{
371 coefficient_of_variation, correlation, detect_outliers, interquartile_range, kurtosis,
372 linear_regression, mean_absolute_error, median, mode, percentile, r_squared,
373 root_mean_squared_error, skewness, z_score,
374 };
375 pub use crate::timezone_support::{ScheduledEvent, TimeFormat, TimezoneInfo, TimezoneManager};
376 pub use crate::validation_helpers::{
377 validate_audio_buffer, validate_confidence, validate_duration, validate_email,
378 validate_not_empty, validate_percentage, validate_range, validate_sample_rate,
379 validate_score, validate_text_input, validate_username, ValidationResult,
380 };
381
382 #[cfg(feature = "gamification")]
383 pub use crate::gamification::achievements::AchievementSystem;
384 #[cfg(feature = "gamification")]
385 pub use crate::gamification::Leaderboard;
386
387 #[cfg(feature = "ui")]
388 pub use crate::visualization::charts::ProgressChart;
389 #[cfg(feature = "ui")]
390 pub use crate::visualization::core::FeedbackVisualizer;
391
392 pub use crate::performance_helpers::{
394 calculate_rtf, calculate_throughput, format_bytes, format_duration_auto, OperationProfiler,
395 PerformanceSnapshot, RateLimiter, Timer,
396 };
397 pub use crate::utils::{
398 clamp_score, confidence_interval, exponential_moving_average, format_duration,
399 improvement_rate, is_recent, merge_hashmaps, moving_average, normalize_scores,
400 percentage_to_score, sanitize_input, score_to_percentage, standard_deviation, time_since,
401 truncate_string, weighted_average,
402 };
403
404 pub use voirs_evaluation::{ComparisonResult, PronunciationScore, QualityScore};
406 pub use voirs_recognizer::traits::{PhonemeAlignment, Transcript};
407 pub use voirs_sdk::{AudioBuffer, LanguageCode, Phoneme, VoirsError};
408
409 pub use async_trait::async_trait;
411}
412
413#[derive(Debug, thiserror::Error)]
419pub enum FeedbackError {
420 #[error("Feedback generation failed: {message}")]
422 FeedbackGenerationError {
423 message: String,
425 #[source]
427 source: Option<Box<dyn std::error::Error + Send + Sync>>,
428 },
429
430 #[error("Session management failed: {message}")]
432 SessionError {
433 message: String,
435 #[source]
437 source: Option<Box<dyn std::error::Error + Send + Sync>>,
438 },
439
440 #[error("Adaptive learning failed: {message}")]
442 AdaptiveLearningError {
443 message: String,
445 #[source]
447 source: Option<Box<dyn std::error::Error + Send + Sync>>,
448 },
449
450 #[error("Progress tracking failed: {message}")]
452 ProgressTrackingError {
453 message: String,
455 #[source]
457 source: Option<Box<dyn std::error::Error + Send + Sync>>,
458 },
459
460 #[error("Training system failed: {message}")]
462 TrainingError {
463 message: String,
465 #[source]
467 source: Option<Box<dyn std::error::Error + Send + Sync>>,
468 },
469
470 #[error("Real-time processing failed: {message}")]
472 RealtimeError {
473 message: String,
475 #[source]
477 source: Option<Box<dyn std::error::Error + Send + Sync>>,
478 },
479
480 #[error("Configuration error: {message}")]
482 ConfigurationError {
483 message: String,
485 },
486
487 #[error("Invalid input: {message}")]
489 InvalidInput {
490 message: String,
492 },
493
494 #[error("Feature not supported: {feature}")]
496 FeatureNotSupported {
497 feature: String,
499 },
500
501 #[error("Processing error: {0}")]
503 ProcessingError(String),
504
505 #[error("Lock contention detected - operation aborted to preserve UI responsiveness")]
507 LockContention,
508
509 #[error("Operation timed out")]
511 Timeout,
512}
513
514impl From<FeedbackError> for VoirsError {
515 fn from(err: FeedbackError) -> Self {
516 log::warn!("Converting FeedbackError to VoirsError: {err}");
518
519 match err {
520 FeedbackError::FeedbackGenerationError { message, source: _ } => {
521 log::error!("Feedback generation failed: {message}");
522 VoirsError::AudioError {
523 message,
524 buffer_info: None,
525 }
526 }
527 FeedbackError::SessionError { message, source: _ } => {
528 log::error!("Session management error: {message}");
529 VoirsError::ConfigError {
530 field: "session".to_string(),
531 message,
532 }
533 }
534 FeedbackError::AdaptiveLearningError { message, source } => {
535 log::error!("Adaptive learning error: {message}");
536 VoirsError::ModelError {
537 model_type: voirs_sdk::error::ModelType::Vocoder,
538 message,
539 source,
540 }
541 }
542 FeedbackError::ProgressTrackingError { message, source: _ } => {
543 log::error!("Progress tracking error: {message}");
544 VoirsError::ConfigError {
545 field: "progress_tracking".to_string(),
546 message,
547 }
548 }
549 FeedbackError::TrainingError { message, source: _ } => {
550 log::error!("Training system error: {message}");
551 VoirsError::ConfigError {
552 field: "training".to_string(),
553 message,
554 }
555 }
556 FeedbackError::RealtimeError { message, source: _ } => {
557 log::error!("Real-time processing error: {message}");
558 VoirsError::AudioError {
559 message,
560 buffer_info: None,
561 }
562 }
563 FeedbackError::ConfigurationError { message } => {
564 log::error!("Configuration error: {message}");
565 VoirsError::ConfigError {
566 field: "configuration".to_string(),
567 message,
568 }
569 }
570 FeedbackError::InvalidInput { message } => {
571 log::warn!("Invalid input provided: {message}");
572 VoirsError::ConfigError {
573 field: "input".to_string(),
574 message: format!("Invalid input: {message}"),
575 }
576 }
577 FeedbackError::FeatureNotSupported { feature } => {
578 log::warn!("Feature not supported: {feature}");
579 VoirsError::ModelError {
580 model_type: voirs_sdk::error::ModelType::Vocoder,
581 message: format!("Feature not supported: {feature}"),
582 source: None,
583 }
584 }
585 FeedbackError::ProcessingError(message) => {
586 log::error!("Processing error: {message}");
587 VoirsError::AudioError {
588 message,
589 buffer_info: None,
590 }
591 }
592 FeedbackError::LockContention => {
593 log::warn!("Lock contention detected - preserving UI responsiveness");
594 VoirsError::AudioError {
595 message:
596 "Lock contention detected - operation aborted to preserve UI responsiveness"
597 .to_string(),
598 buffer_info: None,
599 }
600 }
601 FeedbackError::Timeout => {
602 log::error!("Operation timed out");
603 VoirsError::AudioError {
604 message: "Operation timed out".to_string(),
605 buffer_info: None,
606 }
607 }
608 }
609 }
610}
611
612impl From<VoirsError> for FeedbackError {
613 fn from(err: VoirsError) -> Self {
614 FeedbackError::FeedbackGenerationError {
615 message: err.to_string(),
616 source: Some(Box::new(err)),
617 }
618 }
619}
620
621pub struct FeedbackSystem {
627 realtime: RealtimeFeedbackSystem,
629 adaptive: AdaptiveFeedbackEngine,
631 progress: ProgressAnalyzer,
633 trainer: InteractiveTrainer,
635 config: FeedbackSystemConfig,
637 #[cfg(feature = "persistence")]
639 persistence_manager: std::sync::Arc<dyn crate::persistence::PersistenceManager>,
640}
641
642impl FeedbackSystem {
643 pub async fn new() -> Result<Self, FeedbackError> {
645 Self::with_config(FeedbackSystemConfig::default()).await
646 }
647
648 pub async fn with_config(config: FeedbackSystemConfig) -> Result<Self, FeedbackError> {
650 let realtime =
651 RealtimeFeedbackSystem::new()
652 .await
653 .map_err(|e| FeedbackError::RealtimeError {
654 message: format!("Failed to initialize real-time system: {e}"),
655 source: Some(Box::new(e)),
656 })?;
657
658 let adaptive = AdaptiveFeedbackEngine::new().await.map_err(|e| {
659 FeedbackError::AdaptiveLearningError {
660 message: format!("Failed to initialize adaptive engine: {e}"),
661 source: Some(Box::new(e)),
662 }
663 })?;
664
665 let progress =
666 ProgressAnalyzer::new()
667 .await
668 .map_err(|e| FeedbackError::ProgressTrackingError {
669 message: format!("Failed to initialize progress analyzer: {e}"),
670 source: Some(Box::new(e)),
671 })?;
672
673 let trainer =
674 InteractiveTrainer::new()
675 .await
676 .map_err(|e| FeedbackError::TrainingError {
677 message: format!("Failed to initialize trainer: {e}"),
678 source: Some(Box::new(e)),
679 })?;
680
681 #[cfg(feature = "persistence")]
682 let persistence_manager = {
683 use crate::persistence::backends::sqlite::SQLitePersistenceManager;
684 use crate::persistence::{PersistenceBackend, PersistenceConfig, PersistenceManager};
685
686 let db_path = config
687 .database_path
688 .clone()
689 .unwrap_or_else(|| "feedback.db".to_string());
690
691 let persistence_config = PersistenceConfig {
692 backend: PersistenceBackend::SQLite,
693 connection_string: db_path,
694 enable_encryption: false,
695 max_cache_size: 1000,
696 cache_ttl_seconds: 3600,
697 auto_cleanup_interval_hours: 24,
698 data_retention_days: 365,
699 enable_compression: true,
700 connection_pool_size: 10,
701 };
702
703 let mut manager = SQLitePersistenceManager::new(persistence_config)
704 .await
705 .map_err(|e| FeedbackError::SessionError {
706 message: format!("Failed to initialize persistence manager: {e}"),
707 source: Some(Box::new(e)),
708 })?;
709
710 manager
711 .initialize()
712 .await
713 .map_err(|e| FeedbackError::SessionError {
714 message: format!("Failed to initialize persistence backend: {e}"),
715 source: Some(Box::new(e)),
716 })?;
717
718 std::sync::Arc::new(manager)
719 as std::sync::Arc<dyn crate::persistence::PersistenceManager>
720 };
721
722 Ok(Self {
723 realtime,
724 adaptive,
725 progress,
726 trainer,
727 config,
728 #[cfg(feature = "persistence")]
729 persistence_manager,
730 })
731 }
732
733 pub async fn create_session(
735 &self,
736 user_id: &str,
737 ) -> Result<Box<dyn FeedbackSession>, FeedbackError> {
738 let session = FeedbackSessionImpl::new(
739 user_id.to_string(),
740 &self.realtime,
741 &self.adaptive,
742 &self.progress,
743 &self.trainer,
744 &self.config,
745 #[cfg(feature = "persistence")]
746 self.persistence_manager.clone(),
747 )
748 .await?;
749
750 Ok(Box::new(session))
751 }
752
753 #[must_use]
755 pub fn config(&self) -> &FeedbackSystemConfig {
756 &self.config
757 }
758
759 pub async fn get_statistics(&self) -> Result<FeedbackSystemStats, FeedbackError> {
761 let realtime_stats = self.realtime.get_statistics().await?;
762 let adaptive_stats = self.adaptive.get_statistics().await?;
763 let progress_stats = self.progress.get_statistics().await?;
764
765 log::info!(
767 "System statistics: {} sessions, {} active streams, {:.2}ms avg response time",
768 progress_stats.total_users,
769 realtime_stats.active_streams,
770 realtime_stats.average_latency_ms
771 );
772
773 Ok(FeedbackSystemStats {
774 total_sessions: progress_stats.total_users,
775 active_sessions: realtime_stats.active_streams,
776 total_feedback_generated: adaptive_stats.total_feedback_count,
777 average_response_time_ms: realtime_stats.average_latency_ms,
778 system_uptime: std::time::SystemTime::now()
779 .duration_since(std::time::UNIX_EPOCH)
780 .unwrap_or_default(),
781 })
782 }
783
784 pub async fn get_system_health(&self) -> Result<SystemHealthReport, FeedbackError> {
786 let stats = self.get_statistics().await?;
787
788 let mut health_score = 1.0;
789 let mut issues = Vec::new();
790 let mut recommendations = Vec::new();
791
792 if stats.average_response_time_ms > 500.0 {
794 health_score -= 0.3;
795 issues.push("High response time detected".to_string());
796 recommendations.push("Consider optimizing audio processing pipeline".to_string());
797 } else if stats.average_response_time_ms > 200.0 {
798 health_score -= 0.1;
799 issues.push("Elevated response time".to_string());
800 recommendations.push("Monitor system load and resource usage".to_string());
801 }
802
803 let max_sessions = self.config.max_concurrent_sessions;
805 let session_load = stats.active_sessions as f32 / max_sessions as f32;
806
807 if session_load > 0.9 {
808 health_score -= 0.2;
809 issues.push("Near maximum session capacity".to_string());
810 recommendations.push("Consider scaling up resources or load balancing".to_string());
811 } else if session_load > 0.7 {
812 health_score -= 0.1;
813 issues.push("High session load".to_string());
814 recommendations.push("Monitor for potential capacity issues".to_string());
815 }
816
817 let uptime_hours = stats.system_uptime.as_secs() as f32 / 3600.0;
819 if uptime_hours < 1.0 {
820 health_score -= 0.1;
821 issues.push("Recent system restart detected".to_string());
822 recommendations.push("Monitor for startup issues or crashes".to_string());
823 }
824
825 let health_status = if health_score >= 0.9 {
826 HealthStatus::Excellent
827 } else if health_score >= 0.7 {
828 HealthStatus::Good
829 } else if health_score >= 0.5 {
830 HealthStatus::Warning
831 } else {
832 HealthStatus::Critical
833 };
834
835 log::info!(
836 "System health: {:?} (score: {:.2}) - {} issues, {} recommendations",
837 health_status,
838 health_score,
839 issues.len(),
840 recommendations.len()
841 );
842
843 Ok(SystemHealthReport {
844 health_score,
845 health_status,
846 issues,
847 recommendations,
848 timestamp: chrono::Utc::now(),
849 statistics: stats,
850 })
851 }
852}
853
854#[derive(Debug, Clone)]
856pub struct FeedbackSystemConfig {
857 pub enable_realtime: bool,
859 pub enable_adaptive: bool,
861 pub enable_progress_tracking: bool,
863 pub enable_gamification: bool,
865 pub max_concurrent_sessions: usize,
867 pub response_timeout_ms: u64,
869 pub auto_save_interval_sec: u64,
871 #[cfg(feature = "persistence")]
873 pub database_path: Option<String>,
874}
875
876impl Default for FeedbackSystemConfig {
877 fn default() -> Self {
878 Self {
879 enable_realtime: true,
880 enable_adaptive: true,
881 enable_progress_tracking: true,
882 enable_gamification: false,
883 max_concurrent_sessions: 100,
884 response_timeout_ms: 500,
885 auto_save_interval_sec: 30,
886 #[cfg(feature = "persistence")]
887 database_path: None,
888 }
889 }
890}
891
892#[derive(Debug, Clone)]
894pub struct FeedbackSystemStats {
895 pub total_sessions: usize,
897 pub active_sessions: usize,
899 pub total_feedback_generated: usize,
901 pub average_response_time_ms: f32,
903 pub system_uptime: std::time::Duration,
905}
906
907#[derive(Debug, Clone)]
909pub struct SystemHealthReport {
910 pub health_score: f32,
912 pub health_status: HealthStatus,
914 pub issues: Vec<String>,
916 pub recommendations: Vec<String>,
918 pub timestamp: chrono::DateTime<chrono::Utc>,
920 pub statistics: FeedbackSystemStats,
922}
923
924#[derive(Debug, Clone, PartialEq)]
926pub enum HealthStatus {
927 Excellent,
929 Good,
931 Warning,
933 Critical,
935}
936
937struct FeedbackSessionImpl {
939 user_id: String,
940 state: SessionState,
941 realtime: RealtimeFeedbackSystem,
942 adaptive: AdaptiveFeedbackEngine,
943 progress: ProgressAnalyzer,
944 trainer: InteractiveTrainer,
945 config: FeedbackSystemConfig,
946 feedback_stream: Option<FeedbackStream>,
947 #[cfg(feature = "persistence")]
948 persistence_manager: std::sync::Arc<dyn crate::persistence::PersistenceManager>,
949}
950
951impl FeedbackSessionImpl {
952 async fn new(
953 user_id: String,
954 realtime: &RealtimeFeedbackSystem,
955 adaptive: &AdaptiveFeedbackEngine,
956 progress: &ProgressAnalyzer,
957 trainer: &InteractiveTrainer,
958 config: &FeedbackSystemConfig,
959 #[cfg(feature = "persistence")] persistence_manager: std::sync::Arc<
960 dyn crate::persistence::PersistenceManager,
961 >,
962 ) -> Result<Self, FeedbackError> {
963 let state = SessionState::new(&user_id).await?;
964
965 Ok(Self {
966 user_id,
967 state,
968 realtime: realtime.clone(),
969 adaptive: adaptive.clone(),
970 progress: progress.clone(),
971 trainer: trainer.clone(),
972 config: config.clone(),
973 feedback_stream: None,
974 #[cfg(feature = "persistence")]
975 persistence_manager,
976 })
977 }
978}
979
980#[async_trait]
981impl FeedbackSession for FeedbackSessionImpl {
982 async fn process_synthesis(
983 &mut self,
984 audio: &AudioBuffer,
985 text: &str,
986 ) -> FeedbackResult<FeedbackResponse> {
987 if self.feedback_stream.is_none() {
989 let stream = self
990 .realtime
991 .create_stream(&self.user_id, &self.state)
992 .await?;
993 self.feedback_stream = Some(stream);
994 }
995
996 let feedback = if let Some(stream) = &self.feedback_stream {
998 stream.process_audio(audio, text).await?
999 } else {
1000 return Err(FeedbackError::RealtimeError {
1001 message: "Failed to create feedback stream".to_string(),
1002 source: None,
1003 }
1004 .into());
1005 };
1006
1007 let user_feedback = UserFeedback {
1009 message: text.to_string(),
1010 suggestion: Some("Continue practicing".to_string()),
1011 confidence: 0.8,
1012 score: 0.8,
1013 priority: 0.5,
1014 metadata: std::collections::HashMap::new(),
1015 };
1016 let interaction = UserInteraction {
1017 user_id: self.user_id.clone(),
1018 timestamp: chrono::Utc::now(),
1019 interaction_type: InteractionType::Practice,
1020 audio: audio.clone(),
1021 text: text.to_string(),
1022 feedback: feedback.clone(),
1023 user_response: None,
1024 };
1025 self.adaptive.learn_from_interaction(&interaction).await?;
1026
1027 Ok(feedback)
1028 }
1029
1030 async fn start_exercise(&mut self, exercise: &TrainingExercise) -> FeedbackResult<()> {
1031 let exercise_session = crate::traits::ExerciseSession {
1033 exercise_id: exercise.exercise_id.clone(),
1034 exercise_name: exercise.name.clone(),
1035 start_time: chrono::Utc::now(),
1036 current_attempt: 0,
1037 progress: 0.0,
1038 };
1039
1040 self.state.current_exercise = Some(exercise_session);
1041 self.state.stats.exercises_completed += 1;
1042
1043 Ok(())
1044 }
1045
1046 async fn complete_exercise(&mut self) -> FeedbackResult<TrainingResult> {
1047 let exercise_session =
1048 self.state
1049 .current_exercise
1050 .take()
1051 .ok_or_else(|| FeedbackError::SessionError {
1052 message: "No active exercise to complete".to_string(),
1053 source: None,
1054 })?;
1055
1056 let completion_time = chrono::Utc::now()
1057 .signed_duration_since(exercise_session.start_time)
1058 .to_std()
1059 .unwrap_or_default();
1060
1061 let exercise = TrainingExercise {
1063 exercise_id: exercise_session.exercise_id,
1064 name: exercise_session.exercise_name,
1065 description: "Completed training exercise".to_string(),
1066 difficulty: 0.5,
1067 focus_areas: vec![FocusArea::Pronunciation, FocusArea::Quality],
1068 exercise_type: ExerciseType::FreeForm,
1069 target_text: "Practice text".to_string(),
1070 reference_audio: None,
1071 success_criteria: SuccessCriteria {
1072 min_quality_score: 0.7,
1073 min_pronunciation_score: 0.7,
1074 consistency_required: 1,
1075 max_attempts: 3,
1076 time_limit: Some(Duration::from_secs(300)),
1077 },
1078 estimated_duration: Duration::from_secs(300),
1079 };
1080
1081 let final_scores = TrainingScores {
1082 quality: self.state.stats.average_quality,
1083 pronunciation: self.state.stats.average_pronunciation,
1084 consistency: 0.8,
1085 improvement: 0.1,
1086 };
1087
1088 let success = final_scores.quality >= 0.7 && final_scores.pronunciation >= 0.7;
1089
1090 let feedback = FeedbackResponse {
1091 feedback_items: vec![UserFeedback {
1092 message: if success {
1093 "Great work! Exercise completed successfully.".to_string()
1094 } else {
1095 "Good effort! Keep practicing to improve.".to_string()
1096 },
1097 suggestion: Some("Continue with the next exercise".to_string()),
1098 confidence: 0.8,
1099 score: f32::midpoint(final_scores.quality, final_scores.pronunciation),
1100 priority: 0.5,
1101 metadata: std::collections::HashMap::new(),
1102 }],
1103 overall_score: f32::midpoint(final_scores.quality, final_scores.pronunciation),
1104 immediate_actions: vec!["Review feedback and continue training".to_string()],
1105 long_term_goals: vec!["Maintain consistent quality".to_string()],
1106 progress_indicators: ProgressIndicators {
1107 improving_areas: vec!["Overall Performance".to_string()],
1108 attention_areas: Vec::new(),
1109 stable_areas: vec!["Basic Skills".to_string()],
1110 overall_trend: 0.1,
1111 completion_percentage: exercise_session.progress,
1112 },
1113 timestamp: chrono::Utc::now(),
1114 processing_time: Duration::from_millis(100),
1115 feedback_type: FeedbackType::Quality,
1116 };
1117
1118 let improvement_recommendations = if success {
1119 vec![
1120 "Maintain current level of performance".to_string(),
1121 "Try more challenging exercises".to_string(),
1122 ]
1123 } else {
1124 vec![
1125 "Focus on audio quality improvement".to_string(),
1126 "Practice pronunciation accuracy".to_string(),
1127 ]
1128 };
1129
1130 Ok(TrainingResult {
1131 exercise,
1132 success,
1133 attempts_made: exercise_session.current_attempt + 1,
1134 completion_time,
1135 final_scores,
1136 feedback,
1137 improvement_recommendations,
1138 })
1139 }
1140
1141 async fn update_preferences(&mut self, preferences: UserPreferences) -> FeedbackResult<()> {
1142 self.state.preferences = preferences;
1144
1145 log::info!("Updated user preferences for user: {}", self.user_id);
1147
1148 Ok(())
1149 }
1150
1151 fn get_state(&self) -> &SessionState {
1152 &self.state
1153 }
1154
1155 async fn save_progress(&self) -> FeedbackResult<()> {
1156 log::info!(
1157 "Saving progress for user: {} at session: {}",
1158 self.user_id,
1159 self.state.session_id
1160 );
1161
1162 #[cfg(feature = "persistence")]
1163 {
1164 self.persistence_manager
1166 .save_session(&self.state)
1167 .await
1168 .map_err(|e| FeedbackError::SessionError {
1169 message: format!("Failed to save session to database: {e}"),
1170 source: Some(Box::new(e)),
1171 })?;
1172
1173 let user_progress = UserProgress {
1175 user_id: self.user_id.clone(),
1176 overall_skill_level: f32::midpoint(
1177 self.state.stats.average_quality,
1178 self.state.stats.average_pronunciation,
1179 ),
1180 skill_breakdown: std::collections::HashMap::new(),
1181 progress_history: vec![], achievements: vec![], session_count: 1, total_practice_time: self.state.stats.session_duration,
1185 training_stats: crate::traits::TrainingStatistics {
1186 total_sessions: 1, successful_sessions: 1, total_training_time: self.state.stats.session_duration,
1189 exercises_completed: self.state.stats.exercises_completed,
1190 success_rate: 1.0, average_improvement: 0.05, current_streak: 1, longest_streak: 1, },
1195 goals: vec![], last_updated: chrono::Utc::now(),
1197 average_scores: crate::traits::SessionScores {
1198 average_quality: self.state.stats.average_quality,
1199 average_pronunciation: self.state.stats.average_pronunciation,
1200 average_fluency: 0.0, overall_score: f32::midpoint(
1202 self.state.stats.average_quality,
1203 self.state.stats.average_pronunciation,
1204 ),
1205 improvement_trend: 0.05, },
1207 skill_levels: std::collections::HashMap::new(),
1208 recent_sessions: vec![],
1209 personal_bests: std::collections::HashMap::new(),
1210 };
1211
1212 self.persistence_manager
1214 .save_user_progress(&self.user_id, &user_progress)
1215 .await
1216 .map_err(|e| FeedbackError::SessionError {
1217 message: format!("Failed to save user progress to database: {e}"),
1218 source: Some(Box::new(e)),
1219 })?;
1220
1221 log::info!(
1222 "Successfully saved progress to database for user: {}",
1223 self.user_id
1224 );
1225 }
1226
1227 #[cfg(not(feature = "persistence"))]
1228 {
1229 let progress_data = serde_json::to_string(&self.state.stats).map_err(|e| {
1231 FeedbackError::SessionError {
1232 message: format!("Failed to serialize progress data: {e}"),
1233 source: Some(Box::new(e)),
1234 }
1235 })?;
1236
1237 log::debug!("Progress data (persistence disabled): {progress_data}");
1238 }
1239
1240 Ok(())
1241 }
1242}
1243
1244#[must_use]
1250pub fn default_feedback_config() -> FeedbackConfig {
1251 FeedbackConfig::default()
1252}
1253
1254#[must_use]
1256pub fn default_adaptive_config() -> AdaptiveConfig {
1257 AdaptiveConfig::default()
1258}
1259
1260#[must_use]
1262pub fn default_progress_config() -> ProgressConfig {
1263 ProgressConfig::default()
1264}
1265
1266pub fn validate_feedback_config(config: &FeedbackConfig) -> Result<(), FeedbackError> {
1268 if config.response_timeout_ms < 100 {
1269 return Err(FeedbackError::ConfigurationError {
1270 message: "Response timeout must be at least 100ms".to_string(),
1271 });
1272 }
1273
1274 if config.feedback_detail_level > 1.0 || config.feedback_detail_level < 0.0 {
1275 return Err(FeedbackError::ConfigurationError {
1276 message: "Feedback detail level must be between 0.0 and 1.0".to_string(),
1277 });
1278 }
1279
1280 Ok(())
1281}
1282
1283#[must_use]
1285pub fn calculate_feedback_priority(quality_score: f32, pronunciation_score: f32) -> f32 {
1286 let quality_urgency = 1.0 - quality_score;
1287 let pronunciation_urgency = 1.0 - pronunciation_score;
1288
1289 (quality_urgency * 0.4 + pronunciation_urgency * 0.6).min(1.0)
1291}
1292
1293#[must_use]
1295pub fn format_feedback_message(feedback: &UserFeedback, audience: FeedbackAudience) -> String {
1296 match audience {
1297 FeedbackAudience::Beginner => {
1298 let suggestion = feedback.suggestion.as_deref().unwrap_or("Keep practicing!");
1299 format!("š” {}\n\nš Tip: {suggestion}", feedback.message)
1300 }
1301 FeedbackAudience::Intermediate => {
1302 let suggestion = feedback
1303 .suggestion
1304 .as_deref()
1305 .unwrap_or("Continue refining your technique");
1306 format!("Analysis: {}\nImprovement: {suggestion}", feedback.message)
1307 }
1308 FeedbackAudience::Advanced => {
1309 let confidence = feedback.confidence * 100.0;
1310 let suggestion = feedback
1311 .suggestion
1312 .as_deref()
1313 .unwrap_or("Focus on advanced techniques");
1314 format!(
1315 "Technical feedback: {} (Confidence: {confidence:.1}%)\nOptimization: {suggestion}",
1316 feedback.message
1317 )
1318 }
1319 FeedbackAudience::Developer => {
1320 let message = &feedback.message;
1321 let score = feedback.score;
1322 let priority = feedback.priority;
1323 let metadata = &feedback.metadata;
1324 format!(
1325 "Debug: {message} | Score: {score:.3} | Priority: {priority:.3} | Metrics: {metadata:?}"
1326 )
1327 }
1328 }
1329}
1330
1331#[derive(Debug, Clone, PartialEq)]
1333pub enum FeedbackAudience {
1334 Beginner,
1336 Intermediate,
1338 Advanced,
1340 Developer,
1342}
1343
1344#[derive(Debug, Clone)]
1350pub struct PerformanceBenchmark {
1351 pub audio_throughput: f32,
1353 pub feedback_generation_rate: f32,
1355 pub memory_usage: MemoryUsageStats,
1357 pub cpu_utilization: f32,
1359 pub real_time_factor: f32,
1361 pub timestamp: chrono::DateTime<chrono::Utc>,
1363}
1364
1365#[derive(Debug, Clone)]
1367pub struct MemoryUsageStats {
1368 pub current_usage_bytes: usize,
1370 pub peak_usage_bytes: usize,
1372 pub allocation_rate: f32,
1374 pub buffer_pool_efficiency: f32,
1376}
1377
1378pub struct SystemProfiler {
1380 start_time: std::time::Instant,
1382 samples: Vec<PerformanceSample>,
1384 config: ProfilerConfig,
1386}
1387
1388#[derive(Debug, Clone)]
1390struct PerformanceSample {
1391 timestamp: std::time::Instant,
1393 audio_processing_time: Duration,
1395 feedback_generation_time: Duration,
1397 memory_usage: usize,
1399 active_sessions: usize,
1401}
1402
1403#[derive(Debug, Clone)]
1405pub struct ProfilerConfig {
1406 pub sample_interval: Duration,
1408 pub max_samples: usize,
1410 pub enable_memory_tracking: bool,
1412 pub enable_cpu_profiling: bool,
1414}
1415
1416impl Default for ProfilerConfig {
1417 fn default() -> Self {
1418 Self {
1419 sample_interval: Duration::from_secs(10),
1420 max_samples: 1000,
1421 enable_memory_tracking: true,
1422 enable_cpu_profiling: false, }
1424 }
1425}
1426
1427impl SystemProfiler {
1428 #[must_use]
1430 pub fn new(config: ProfilerConfig) -> Self {
1431 log::info!("Initializing system profiler with config: {config:?}");
1432
1433 Self {
1434 start_time: std::time::Instant::now(),
1435 samples: Vec::with_capacity(config.max_samples),
1436 config,
1437 }
1438 }
1439
1440 pub fn record_sample(
1442 &mut self,
1443 audio_processing_time: Duration,
1444 feedback_generation_time: Duration,
1445 active_sessions: usize,
1446 ) {
1447 let memory_usage = if self.config.enable_memory_tracking {
1448 self.get_current_memory_usage()
1449 } else {
1450 0
1451 };
1452
1453 let sample = PerformanceSample {
1454 timestamp: std::time::Instant::now(),
1455 audio_processing_time,
1456 feedback_generation_time,
1457 memory_usage,
1458 active_sessions,
1459 };
1460
1461 self.samples.push(sample);
1462
1463 if self.samples.len() > self.config.max_samples {
1465 self.samples.remove(0);
1466 }
1467
1468 log::debug!(
1469 "Recorded performance sample: audio_time={:?}, feedback_time={:?}, memory={}KB, sessions={}",
1470 audio_processing_time,
1471 feedback_generation_time,
1472 memory_usage / 1024,
1473 active_sessions
1474 );
1475 }
1476
1477 pub fn generate_benchmark(&self) -> Result<PerformanceBenchmark, FeedbackError> {
1479 if self.samples.is_empty() {
1480 return Err(FeedbackError::ConfigurationError {
1481 message: "No performance samples available for benchmark".to_string(),
1482 });
1483 }
1484
1485 let total_audio_time: Duration = self.samples.iter().map(|s| s.audio_processing_time).sum();
1486
1487 let total_feedback_time: Duration = self
1488 .samples
1489 .iter()
1490 .map(|s| s.feedback_generation_time)
1491 .sum();
1492
1493 let total_session_time = self.start_time.elapsed();
1494
1495 let audio_throughput = if total_session_time.as_secs_f32() > 0.0 {
1497 (self.samples.len() * 16000) as f32 / total_session_time.as_secs_f32()
1499 } else {
1500 0.0
1501 };
1502
1503 let feedback_generation_rate = if total_session_time.as_secs_f32() > 0.0 {
1504 self.samples.len() as f32 / total_session_time.as_secs_f32()
1505 } else {
1506 0.0
1507 };
1508
1509 let real_time_factor = if total_audio_time.as_secs_f32() > 0.0 {
1511 total_feedback_time.as_secs_f32() / total_audio_time.as_secs_f32()
1512 } else {
1513 0.0
1514 };
1515
1516 let memory_usage = self.calculate_memory_stats();
1518
1519 let cpu_utilization = self.estimate_cpu_utilization();
1521
1522 let benchmark = PerformanceBenchmark {
1523 audio_throughput,
1524 feedback_generation_rate,
1525 memory_usage,
1526 cpu_utilization,
1527 real_time_factor,
1528 timestamp: chrono::Utc::now(),
1529 };
1530
1531 log::info!(
1532 "Generated performance benchmark: throughput={:.0} samples/s, rate={:.2} req/s, RTF={:.3}, CPU={:.1}%",
1533 benchmark.audio_throughput,
1534 benchmark.feedback_generation_rate,
1535 benchmark.real_time_factor,
1536 benchmark.cpu_utilization
1537 );
1538
1539 Ok(benchmark)
1540 }
1541
1542 fn get_current_memory_usage(&self) -> usize {
1544 std::mem::size_of::<Self>()
1547 + (self.samples.len() * std::mem::size_of::<PerformanceSample>())
1548 }
1549
1550 fn calculate_memory_stats(&self) -> MemoryUsageStats {
1552 if self.samples.is_empty() {
1553 return MemoryUsageStats {
1554 current_usage_bytes: 0,
1555 peak_usage_bytes: 0,
1556 allocation_rate: 0.0,
1557 buffer_pool_efficiency: 1.0,
1558 };
1559 }
1560
1561 let current_usage = self.samples.last().unwrap().memory_usage;
1562 let peak_usage = self
1563 .samples
1564 .iter()
1565 .map(|s| s.memory_usage)
1566 .max()
1567 .unwrap_or(0);
1568
1569 let allocation_rate = if self.start_time.elapsed().as_secs_f32() > 0.0 {
1570 self.samples.len() as f32 / self.start_time.elapsed().as_secs_f32()
1571 } else {
1572 0.0
1573 };
1574
1575 let buffer_pool_efficiency = if peak_usage > 0 {
1577 (current_usage as f32 / peak_usage as f32).min(1.0)
1578 } else {
1579 1.0
1580 };
1581
1582 MemoryUsageStats {
1583 current_usage_bytes: current_usage,
1584 peak_usage_bytes: peak_usage,
1585 allocation_rate,
1586 buffer_pool_efficiency,
1587 }
1588 }
1589
1590 fn estimate_cpu_utilization(&self) -> f32 {
1592 if self.samples.is_empty() {
1593 return 0.0;
1594 }
1595
1596 let total_processing_time: Duration = self
1599 .samples
1600 .iter()
1601 .map(|s| s.audio_processing_time + s.feedback_generation_time)
1602 .sum();
1603
1604 let total_wall_time = self.start_time.elapsed();
1605
1606 if total_wall_time.as_secs_f32() > 0.0 {
1607 (total_processing_time.as_secs_f32() / total_wall_time.as_secs_f32() * 100.0).min(100.0)
1608 } else {
1609 0.0
1610 }
1611 }
1612
1613 pub fn reset(&mut self) {
1615 log::info!(
1616 "Resetting system profiler - clearing {} samples",
1617 self.samples.len()
1618 );
1619 self.start_time = std::time::Instant::now();
1620 self.samples.clear();
1621 }
1622
1623 #[must_use]
1625 pub fn sample_count(&self) -> usize {
1626 self.samples.len()
1627 }
1628
1629 #[must_use]
1631 pub fn profiling_duration(&self) -> Duration {
1632 self.start_time.elapsed()
1633 }
1634}
1635
1636#[cfg(test)]
1637mod tests {
1638 use super::*;
1639
1640 #[test]
1641 fn test_version() {
1642 assert!(!VERSION.is_empty());
1643 }
1644
1645 #[test]
1646 fn test_default_configs() {
1647 let feedback_config = default_feedback_config();
1648 assert!(feedback_config.enable_realtime);
1649
1650 let adaptive_config = default_adaptive_config();
1651 assert!(adaptive_config.enable_learning);
1652
1653 let progress_config = default_progress_config();
1654 assert!(progress_config.track_improvements);
1655 }
1656
1657 #[test]
1658 fn test_config_validation() {
1659 let mut config = default_feedback_config();
1660 assert!(validate_feedback_config(&config).is_ok());
1661
1662 config.response_timeout_ms = 50;
1664 assert!(validate_feedback_config(&config).is_err());
1665
1666 config.response_timeout_ms = 200;
1668 config.feedback_detail_level = 1.5;
1669 assert!(validate_feedback_config(&config).is_err());
1670 }
1671
1672 #[test]
1673 fn test_feedback_priority() {
1674 let priority = calculate_feedback_priority(0.8, 0.6);
1675 assert!(priority > 0.0);
1676 assert!(priority <= 1.0);
1677
1678 let high_priority = calculate_feedback_priority(0.3, 0.3);
1680 assert!(high_priority > priority);
1681 }
1682
1683 #[test]
1684 fn test_feedback_formatting() {
1685 let feedback = UserFeedback {
1686 message: "Test message".to_string(),
1687 suggestion: Some("Test suggestion".to_string()),
1688 confidence: 0.85,
1689 score: 0.7,
1690 priority: 0.5,
1691 metadata: std::collections::HashMap::new(),
1692 };
1693
1694 let beginner_msg = format_feedback_message(&feedback, FeedbackAudience::Beginner);
1695 assert!(beginner_msg.contains("š”"));
1696 assert!(beginner_msg.contains("š"));
1697
1698 let developer_msg = format_feedback_message(&feedback, FeedbackAudience::Developer);
1699 assert!(developer_msg.contains("Debug:"));
1700 assert!(developer_msg.contains("Score:"));
1701 }
1702}