1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::str::FromStr;
6
7pub type VoirsResult<T> = std::result::Result<T, crate::VoirsError>;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
12pub enum LanguageCode {
13 EnUs,
15 EnGb,
17 JaJp,
19 EsEs,
21 EsMx,
23 FrFr,
25 DeDe,
27 ZhCn,
29 PtBr,
31 RuRu,
33 ItIt,
35 KoKr,
37 NlNl,
39 SvSe,
41 NoNo,
43 DaDk,
45
46 De,
49 Fr,
51 Es,
53 It,
55 Pt,
57 Ja,
59 Ko,
61 Ru,
63 Ar,
65 Hi,
67 Th,
69 Vi,
71 Id,
73 Ms,
75 Nl,
77 Sv,
79 No,
81 Da,
83 Pl,
85 Cs,
87 Sk,
89 Hu,
91 Ro,
93 Bg,
95 Hr,
97 Sr,
99 Sl,
101 Et,
103 Lv,
105 Lt,
107 Fi,
109 El,
111 Tr,
113 He,
115 Fa,
117 Ur,
119 Bn,
121 Ta,
123 Te,
125 Ml,
127 Kn,
129 Gu,
131 Mr,
133 Pa,
135 Or,
137 As,
139}
140
141impl LanguageCode {
142 pub fn as_str(&self) -> &'static str {
144 match self {
145 Self::EnUs => "en-US",
146 Self::EnGb => "en-GB",
147 Self::JaJp => "ja-JP",
148 Self::EsEs => "es-ES",
149 Self::EsMx => "es-MX",
150 Self::FrFr => "fr-FR",
151 Self::DeDe => "de-DE",
152 Self::ZhCn => "zh-CN",
153 Self::PtBr => "pt-BR",
154 Self::RuRu => "ru-RU",
155 Self::ItIt => "it-IT",
156 Self::KoKr => "ko-KR",
157 Self::NlNl => "nl-NL",
158 Self::SvSe => "sv-SE",
159 Self::NoNo => "no-NO",
160 Self::DaDk => "da-DK",
161
162 Self::De => "de",
164 Self::Fr => "fr",
165 Self::Es => "es",
166 Self::It => "it",
167 Self::Pt => "pt",
168 Self::Ja => "ja",
169 Self::Ko => "ko",
170 Self::Ru => "ru",
171 Self::Ar => "ar",
172 Self::Hi => "hi",
173 Self::Th => "th",
174 Self::Vi => "vi",
175 Self::Id => "id",
176 Self::Ms => "ms",
177 Self::Nl => "nl",
178 Self::Sv => "sv",
179 Self::No => "no",
180 Self::Da => "da",
181 Self::Pl => "pl",
182 Self::Cs => "cs",
183 Self::Sk => "sk",
184 Self::Hu => "hu",
185 Self::Ro => "ro",
186 Self::Bg => "bg",
187 Self::Hr => "hr",
188 Self::Sr => "sr",
189 Self::Sl => "sl",
190 Self::Et => "et",
191 Self::Lv => "lv",
192 Self::Lt => "lt",
193 Self::Fi => "fi",
194 Self::El => "el",
195 Self::Tr => "tr",
196 Self::He => "he",
197 Self::Fa => "fa",
198 Self::Ur => "ur",
199 Self::Bn => "bn",
200 Self::Ta => "ta",
201 Self::Te => "te",
202 Self::Ml => "ml",
203 Self::Kn => "kn",
204 Self::Gu => "gu",
205 Self::Mr => "mr",
206 Self::Pa => "pa",
207 Self::Or => "or",
208 Self::As => "as",
209 }
210 }
211
212 pub fn parse(s: &str) -> Option<Self> {
214 match s {
215 "en-US" => Some(Self::EnUs),
216 "en-GB" => Some(Self::EnGb),
217 "ja-JP" => Some(Self::JaJp),
218 "es-ES" => Some(Self::EsEs),
219 "es-MX" => Some(Self::EsMx),
220 "fr-FR" => Some(Self::FrFr),
221 "de-DE" => Some(Self::DeDe),
222 "zh-CN" => Some(Self::ZhCn),
223 "pt-BR" => Some(Self::PtBr),
224 "ru-RU" => Some(Self::RuRu),
225 "it-IT" => Some(Self::ItIt),
226 "ko-KR" => Some(Self::KoKr),
227 "nl-NL" => Some(Self::NlNl),
228 "sv-SE" => Some(Self::SvSe),
229 "no-NO" => Some(Self::NoNo),
230 "da-DK" => Some(Self::DaDk),
231
232 "de" => Some(Self::De),
234 "fr" => Some(Self::Fr),
235 "es" => Some(Self::Es),
236 "it" => Some(Self::It),
237 "pt" => Some(Self::Pt),
238 "ja" => Some(Self::Ja),
239 "ko" => Some(Self::Ko),
240 "ru" => Some(Self::Ru),
241 "ar" => Some(Self::Ar),
242 "hi" => Some(Self::Hi),
243 "th" => Some(Self::Th),
244 "vi" => Some(Self::Vi),
245 "id" => Some(Self::Id),
246 "ms" => Some(Self::Ms),
247 "nl" => Some(Self::Nl),
248 "sv" => Some(Self::Sv),
249 "no" => Some(Self::No),
250 "da" => Some(Self::Da),
251 "pl" => Some(Self::Pl),
252 "cs" => Some(Self::Cs),
253 "sk" => Some(Self::Sk),
254 "hu" => Some(Self::Hu),
255 "ro" => Some(Self::Ro),
256 "bg" => Some(Self::Bg),
257 "hr" => Some(Self::Hr),
258 "sr" => Some(Self::Sr),
259 "sl" => Some(Self::Sl),
260 "et" => Some(Self::Et),
261 "lv" => Some(Self::Lv),
262 "lt" => Some(Self::Lt),
263 "fi" => Some(Self::Fi),
264 "el" => Some(Self::El),
265 "tr" => Some(Self::Tr),
266 "he" => Some(Self::He),
267 "fa" => Some(Self::Fa),
268 "ur" => Some(Self::Ur),
269 "bn" => Some(Self::Bn),
270 "ta" => Some(Self::Ta),
271 "te" => Some(Self::Te),
272 "ml" => Some(Self::Ml),
273 "kn" => Some(Self::Kn),
274 "gu" => Some(Self::Gu),
275 "mr" => Some(Self::Mr),
276 "pa" => Some(Self::Pa),
277 "or" => Some(Self::Or),
278 "as" => Some(Self::As),
279 _ => None,
280 }
281 }
282}
283
284impl std::fmt::Display for LanguageCode {
285 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
286 write!(f, "{}", self.as_str())
287 }
288}
289
290#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
292pub struct Phoneme {
293 pub symbol: String,
295
296 pub ipa_symbol: String,
298
299 pub stress: u8,
301
302 pub syllable_position: SyllablePosition,
304
305 pub duration_ms: Option<f32>,
307
308 pub confidence: f32,
310}
311
312impl Phoneme {
313 pub fn new(symbol: impl Into<String>) -> Self {
315 let symbol_str = symbol.into();
316 Self {
317 symbol: symbol_str.clone(),
318 ipa_symbol: symbol_str, stress: 0,
320 syllable_position: SyllablePosition::Unknown,
321 duration_ms: None,
322 confidence: 1.0,
323 }
324 }
325
326 pub fn with_stress(mut self, stress: u8) -> Self {
328 self.stress = stress;
329 self
330 }
331
332 pub fn with_duration(mut self, duration_ms: f32) -> Self {
334 self.duration_ms = Some(duration_ms);
335 self
336 }
337}
338
339#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
341pub enum SyllablePosition {
342 Unknown,
344 Onset,
346 Nucleus,
348 Coda,
350}
351
352#[derive(Debug, Clone, Serialize, Deserialize)]
354pub struct MelSpectrogram {
355 pub data: Vec<Vec<f32>>,
357
358 pub sample_rate: u32,
360
361 pub hop_length: u32,
363
364 pub n_mels: u32,
366
367 pub n_frames: u32,
369}
370
371impl MelSpectrogram {
372 pub fn new(data: Vec<Vec<f32>>, sample_rate: u32, hop_length: u32) -> Self {
374 let n_mels = data.len() as u32;
375 let n_frames = data.first().map(|row| row.len()).unwrap_or(0) as u32;
376
377 Self {
378 data,
379 sample_rate,
380 hop_length,
381 n_mels,
382 n_frames,
383 }
384 }
385
386 pub fn duration(&self) -> f32 {
388 (self.n_frames * self.hop_length) as f32 / self.sample_rate as f32
389 }
390
391 pub fn frame(&self, frame_idx: usize) -> Option<Vec<f32>> {
393 if frame_idx >= self.n_frames as usize {
394 return None;
395 }
396
397 Some(self.data.iter().map(|row| row[frame_idx]).collect())
398 }
399}
400
401#[derive(Debug, Clone, Copy, PartialEq)]
403pub struct AudioSample {
404 pub value: f32,
406 pub index: usize,
408}
409
410#[derive(Debug, Clone, Serialize, Deserialize)]
412pub struct VoiceConfig {
413 pub id: String,
415
416 pub name: String,
418
419 pub language: LanguageCode,
421
422 pub characteristics: VoiceCharacteristics,
424
425 pub model_config: ModelConfig,
427
428 pub metadata: HashMap<String, String>,
430}
431
432#[derive(Debug, Clone, Serialize, Deserialize)]
434pub struct VoiceCharacteristics {
435 pub gender: Option<Gender>,
437
438 pub age: Option<AgeRange>,
440
441 pub style: SpeakingStyle,
443
444 pub emotion_support: bool,
446
447 pub quality: QualityLevel,
449}
450
451impl Default for VoiceCharacteristics {
452 fn default() -> Self {
453 Self {
454 gender: None,
455 age: None,
456 style: SpeakingStyle::Neutral,
457 emotion_support: false,
458 quality: QualityLevel::Medium,
459 }
460 }
461}
462
463#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
465pub enum Gender {
466 Male,
467 Female,
468 NonBinary,
469}
470
471impl std::fmt::Display for Gender {
472 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
473 match self {
474 Gender::Male => write!(f, "Male"),
475 Gender::Female => write!(f, "Female"),
476 Gender::NonBinary => write!(f, "NonBinary"),
477 }
478 }
479}
480
481#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
483pub enum AgeRange {
484 Child, Teen, YoungAdult, Adult, Senior, }
490
491#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
493pub enum SpeakingStyle {
494 Neutral,
495 Conversational,
496 News,
497 Formal,
498 Casual,
499 Energetic,
500 Calm,
501 Dramatic,
502 Whisper,
503}
504
505impl std::fmt::Display for SpeakingStyle {
506 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
507 match self {
508 SpeakingStyle::Neutral => write!(f, "Neutral"),
509 SpeakingStyle::Conversational => write!(f, "Conversational"),
510 SpeakingStyle::News => write!(f, "News"),
511 SpeakingStyle::Formal => write!(f, "Formal"),
512 SpeakingStyle::Casual => write!(f, "Casual"),
513 SpeakingStyle::Energetic => write!(f, "Energetic"),
514 SpeakingStyle::Calm => write!(f, "Calm"),
515 SpeakingStyle::Dramatic => write!(f, "Dramatic"),
516 SpeakingStyle::Whisper => write!(f, "Whisper"),
517 }
518 }
519}
520
521#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
523pub enum QualityLevel {
524 Low,
525 Medium,
526 High,
527 Ultra,
528}
529
530#[derive(Debug, Clone, Serialize, Deserialize)]
532pub struct ModelConfig {
533 pub g2p_model: Option<String>,
535
536 pub acoustic_model: String,
538
539 pub vocoder_model: String,
541
542 pub format: ModelFormat,
544
545 pub device_requirements: DeviceRequirements,
547}
548
549impl Default for ModelConfig {
550 fn default() -> Self {
551 Self {
552 g2p_model: None,
553 acoustic_model: "default-acoustic.safetensors".to_string(),
554 vocoder_model: "default-vocoder.safetensors".to_string(),
555 format: ModelFormat::Candle,
556 device_requirements: DeviceRequirements::default(),
557 }
558 }
559}
560
561#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
563pub enum ModelFormat {
564 Candle,
565 Onnx,
566 PyTorch,
567 TensorFlow,
568}
569
570#[derive(Debug, Clone, Serialize, Deserialize)]
572pub struct DeviceRequirements {
573 pub min_memory_mb: u32,
575
576 pub gpu_support: bool,
578
579 pub compute_capabilities: Vec<String>,
581}
582
583impl Default for DeviceRequirements {
584 fn default() -> Self {
585 Self {
586 min_memory_mb: 512,
587 gpu_support: false,
588 compute_capabilities: vec![],
589 }
590 }
591}
592
593#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
595pub enum AudioFormat {
596 Wav,
597 Flac,
598 Mp3,
599 Opus,
600 Ogg,
601}
602
603impl AudioFormat {
604 pub fn extension(&self) -> &'static str {
606 match self {
607 Self::Wav => "wav",
608 Self::Flac => "flac",
609 Self::Mp3 => "mp3",
610 Self::Opus => "opus",
611 Self::Ogg => "ogg",
612 }
613 }
614}
615
616impl std::fmt::Display for AudioFormat {
617 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
618 write!(f, "{}", self.extension())
619 }
620}
621
622#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
624pub enum AudioEffect {
625 Reverb {
627 room_size: f32,
628 damping: f32,
629 wet_level: f32,
630 },
631 Delay {
633 delay_time: f32,
634 feedback: f32,
635 wet_level: f32,
636 },
637 Equalizer {
639 low_gain: f32,
640 mid_gain: f32,
641 high_gain: f32,
642 },
643 Compressor {
645 threshold: f32,
646 ratio: f32,
647 attack: f32,
648 release: f32,
649 },
650}
651
652#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
654pub struct SynthesisConfig {
655 pub speaking_rate: f32,
657
658 pub pitch_shift: f32,
660
661 pub volume_gain: f32,
663
664 pub enable_enhancement: bool,
666
667 pub output_format: AudioFormat,
669
670 pub sample_rate: u32,
672
673 pub quality: QualityLevel,
675
676 pub language: LanguageCode,
678
679 pub effects: Vec<AudioEffect>,
681
682 pub streaming_chunk_size: Option<usize>,
684
685 pub seed: Option<u64>,
687
688 pub enable_emotion: bool,
690
691 pub emotion_type: Option<String>,
693
694 pub emotion_intensity: f32,
696
697 pub emotion_preset: Option<String>,
699
700 pub auto_emotion_detection: bool,
702
703 pub enable_cloning: bool,
706 pub cloning_method: Option<crate::builder::features::CloningMethod>,
708 pub cloning_quality: f32,
710
711 pub enable_conversion: bool,
714 pub conversion_target: Option<crate::builder::features::ConversionTarget>,
716 pub realtime_conversion: bool,
718
719 pub enable_singing: bool,
722 pub singing_voice_type: Option<crate::builder::features::SingingVoiceType>,
724 pub singing_technique: Option<crate::builder::features::SingingTechnique>,
726 pub musical_key: Option<crate::builder::features::MusicalKey>,
728 pub tempo: Option<f32>,
730
731 pub enable_spatial: bool,
734 pub listener_position: Option<crate::builder::features::Position3D>,
736 pub hrtf_enabled: bool,
738 pub room_size: Option<crate::builder::features::RoomSize>,
740 pub reverb_level: f32,
742}
743
744impl Default for SynthesisConfig {
745 fn default() -> Self {
746 Self {
747 speaking_rate: 1.0,
748 pitch_shift: 0.0,
749 volume_gain: 0.0,
750 enable_enhancement: true,
751 output_format: AudioFormat::Wav,
752 sample_rate: 22050,
753 quality: QualityLevel::High,
754 language: LanguageCode::EnUs,
755 effects: Vec::new(),
756 streaming_chunk_size: None,
757 seed: None,
758 enable_emotion: false,
759 emotion_type: None,
760 emotion_intensity: 0.7,
761 emotion_preset: None,
762 auto_emotion_detection: false,
763
764 enable_cloning: false,
766 cloning_method: None,
767 cloning_quality: 0.85,
768
769 enable_conversion: false,
771 conversion_target: None,
772 realtime_conversion: false,
773
774 enable_singing: false,
776 singing_voice_type: None,
777 singing_technique: None,
778 musical_key: None,
779 tempo: None,
780
781 enable_spatial: false,
783 listener_position: None,
784 hrtf_enabled: false,
785 room_size: None,
786 reverb_level: 0.3,
787 }
788 }
789}
790
791impl crate::config::hierarchy::ConfigHierarchy for SynthesisConfig {
792 fn merge_with(&mut self, other: &Self) {
793 if (other.speaking_rate - 1.0).abs() > f32::EPSILON {
794 self.speaking_rate = other.speaking_rate;
795 }
796 if other.pitch_shift.abs() > f32::EPSILON {
797 self.pitch_shift = other.pitch_shift;
798 }
799 if other.volume_gain.abs() > f32::EPSILON {
800 self.volume_gain = other.volume_gain;
801 }
802 if !other.enable_enhancement {
803 self.enable_enhancement = other.enable_enhancement;
804 }
805 if other.output_format != AudioFormat::Wav {
806 self.output_format = other.output_format;
807 }
808 if other.sample_rate != 22050 {
809 self.sample_rate = other.sample_rate;
810 }
811 if other.quality != QualityLevel::High {
812 self.quality = other.quality;
813 }
814 if other.language != LanguageCode::EnUs {
815 self.language = other.language;
816 }
817 if other.streaming_chunk_size.is_some() {
818 self.streaming_chunk_size = other.streaming_chunk_size;
819 }
820
821 if other.enable_emotion {
823 self.enable_emotion = other.enable_emotion;
824 }
825 if other.emotion_type.is_some() {
826 self.emotion_type = other.emotion_type.clone();
827 }
828 if (other.emotion_intensity - 0.7).abs() > f32::EPSILON {
829 self.emotion_intensity = other.emotion_intensity;
830 }
831 if other.emotion_preset.is_some() {
832 self.emotion_preset = other.emotion_preset.clone();
833 }
834 if other.auto_emotion_detection {
835 self.auto_emotion_detection = other.auto_emotion_detection;
836 }
837
838 self.effects.extend(other.effects.clone());
840 }
841
842 fn validate(&self) -> Result<(), crate::config::hierarchy::ConfigValidationError> {
843 if self.speaking_rate < 0.5 || self.speaking_rate > 2.0 {
844 return Err(crate::config::hierarchy::ConfigValidationError {
845 field: "speaking_rate".to_string(),
846 message: "Speaking rate must be between 0.5 and 2.0".to_string(),
847 });
848 }
849
850 if self.pitch_shift < -12.0 || self.pitch_shift > 12.0 {
851 return Err(crate::config::hierarchy::ConfigValidationError {
852 field: "pitch_shift".to_string(),
853 message: "Pitch shift must be between -12.0 and 12.0 semitones".to_string(),
854 });
855 }
856
857 if self.volume_gain < -20.0 || self.volume_gain > 20.0 {
858 return Err(crate::config::hierarchy::ConfigValidationError {
859 field: "volume_gain".to_string(),
860 message: "Volume gain must be between -20.0 and 20.0 dB".to_string(),
861 });
862 }
863
864 if self.sample_rate < 8000 || self.sample_rate > 96000 {
865 return Err(crate::config::hierarchy::ConfigValidationError {
866 field: "sample_rate".to_string(),
867 message: "Sample rate must be between 8000 and 96000 Hz".to_string(),
868 });
869 }
870
871 if self.emotion_intensity < 0.0 || self.emotion_intensity > 1.0 {
872 return Err(crate::config::hierarchy::ConfigValidationError {
873 field: "emotion_intensity".to_string(),
874 message: "Emotion intensity must be between 0.0 and 1.0".to_string(),
875 });
876 }
877
878 Ok(())
879 }
880}
881
882impl Default for AudioFormat {
884 fn default() -> Self {
885 AudioFormat::Wav
886 }
887}
888
889impl FromStr for AudioFormat {
891 type Err = String;
892
893 fn from_str(s: &str) -> Result<Self, Self::Err> {
894 match s.to_lowercase().as_str() {
895 "wav" => Ok(AudioFormat::Wav),
896 "flac" => Ok(AudioFormat::Flac),
897 "mp3" => Ok(AudioFormat::Mp3),
898 "opus" => Ok(AudioFormat::Opus),
899 "ogg" => Ok(AudioFormat::Ogg),
900 _ => Err(format!("Unknown audio format: {s}")),
901 }
902 }
903}
904
905#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
907pub enum ModelFeature {
908 MultiSpeaker,
910 EmotionControl,
912 StyleControl,
914 ProsodyControl,
916 VoiceCloning,
918 StreamingSupport,
920 BatchProcessing,
922 GPUAcceleration,
924}
925
926#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
928pub struct SystemCapabilities {
929 pub available_features: Vec<AdvancedFeature>,
931 pub hardware: HardwareCapabilities,
933 pub resource_limits: ResourceLimits,
935 pub model_capabilities: HashMap<String, ModelCapabilities>,
937}
938
939#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
941pub enum AdvancedFeature {
942 EmotionControl,
944 VoiceCloning,
946 VoiceConversion,
948 SingingSynthesis,
950 SpatialAudio,
952 StreamingSynthesis,
954 GpuAcceleration,
956 WasmSupport,
958 CloudProcessing,
960 HighQualityVocoding,
962 RealtimeProcessing,
964}
965
966#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
968pub struct HardwareCapabilities {
969 pub gpu_available: bool,
971 pub gpu_memory_mb: Option<u64>,
973 pub cpu_cores: u32,
975 pub system_memory_mb: u64,
977 pub fast_storage: bool,
979}
980
981#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
983pub struct ResourceLimits {
984 pub max_memory_mb: u64,
986 pub max_cpu_percent: u8,
988 pub max_latency_ms: u32,
990 pub battery_optimization: bool,
992}
993
994#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
996pub struct ModelCapabilities {
997 pub supported_features: Vec<AdvancedFeature>,
999 pub hardware_requirements: HardwareRequirements,
1001 pub performance_profile: PerformanceProfile,
1003}
1004
1005#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1007pub struct HardwareRequirements {
1008 pub min_memory_mb: u64,
1010 pub min_gpu_memory_mb: Option<u64>,
1012 pub requires_gpu: bool,
1014 pub min_cpu_cores: u32,
1016}
1017
1018#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1020pub struct PerformanceProfile {
1021 pub init_latency_ms: u32,
1023 pub synthesis_latency_ms_per_sec: u32,
1025 pub synthesis_memory_mb: u64,
1027 pub quality_score: u8, }
1030
1031#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1033pub struct CapabilityRequest {
1034 pub desired_features: Vec<AdvancedFeature>,
1036 pub feature_priorities: Vec<FeaturePriority>,
1038 pub constraints: ResourceLimits,
1040 pub fallback_strategy: FallbackStrategy,
1042}
1043
1044#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
1046pub enum FeaturePriority {
1047 Optional,
1049 Preferred,
1051 Required,
1053 Critical,
1055}
1056
1057#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1059pub enum FallbackStrategy {
1060 FailFast,
1062 GracefulDegradation,
1064 UseAlternatives,
1066 BasicFunctionality,
1068}
1069
1070#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1072pub struct CapabilityNegotiation {
1073 pub enabled_features: Vec<AdvancedFeature>,
1075 pub unavailable_features: Vec<AdvancedFeature>,
1077 pub warnings: Vec<String>,
1079 pub selected_models: HashMap<String, String>,
1081 pub estimated_usage: ResourceUsage,
1083}
1084
1085#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1087pub struct ResourceUsage {
1088 pub memory_mb: u64,
1090 pub init_time_ms: u32,
1092 pub processing_latency_ms: u32,
1094 pub cpu_usage_percent: u8,
1096}
1097
1098impl Default for SystemCapabilities {
1099 fn default() -> Self {
1100 Self {
1101 available_features: vec![
1102 AdvancedFeature::EmotionControl,
1103 AdvancedFeature::StreamingSynthesis,
1104 AdvancedFeature::RealtimeProcessing,
1105 ],
1106 hardware: HardwareCapabilities::default(),
1107 resource_limits: ResourceLimits::default(),
1108 model_capabilities: HashMap::new(),
1109 }
1110 }
1111}
1112
1113impl Default for HardwareCapabilities {
1114 fn default() -> Self {
1115 Self {
1116 gpu_available: false,
1117 gpu_memory_mb: None,
1118 cpu_cores: num_cpus::get() as u32,
1119 system_memory_mb: 4096, fast_storage: true,
1121 }
1122 }
1123}
1124
1125impl Default for ResourceLimits {
1126 fn default() -> Self {
1127 Self {
1128 max_memory_mb: 2048,
1129 max_cpu_percent: 80,
1130 max_latency_ms: 500,
1131 battery_optimization: false,
1132 }
1133 }
1134}
1135
1136impl Default for CapabilityRequest {
1137 fn default() -> Self {
1138 Self {
1139 desired_features: vec![AdvancedFeature::StreamingSynthesis],
1140 feature_priorities: vec![FeaturePriority::Preferred],
1141 constraints: ResourceLimits::default(),
1142 fallback_strategy: FallbackStrategy::GracefulDegradation,
1143 }
1144 }
1145}
1146
1147impl Default for QualityLevel {
1149 fn default() -> Self {
1150 QualityLevel::High
1151 }
1152}
1153
1154impl FromStr for QualityLevel {
1156 type Err = String;
1157
1158 fn from_str(s: &str) -> Result<Self, Self::Err> {
1159 match s.to_lowercase().as_str() {
1160 "low" => Ok(QualityLevel::Low),
1161 "medium" => Ok(QualityLevel::Medium),
1162 "high" => Ok(QualityLevel::High),
1163 "ultra" => Ok(QualityLevel::Ultra),
1164 _ => Err(format!("Unknown quality level: {s}")),
1165 }
1166 }
1167}