aurum_core/provider_platform/
registry.rs1use super::descriptor::ProviderDescriptor;
4use super::factory::TranscriptionProviderFactory;
5use super::id::ProviderId;
6use crate::error::{Result, UserError};
7use std::collections::BTreeMap;
8use std::sync::Arc;
9
10#[cfg(feature = "tts")]
11use super::factory::SynthesisProviderFactory;
12
13#[derive(Clone)]
18pub struct ProviderRegistry {
19 stt: BTreeMap<String, Arc<dyn TranscriptionProviderFactory>>,
20 #[cfg(feature = "tts")]
21 tts: BTreeMap<String, Arc<dyn SynthesisProviderFactory>>,
22 order: Vec<ProviderId>,
24}
25
26impl std::fmt::Debug for ProviderRegistry {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 let mut d = f.debug_struct("ProviderRegistry");
29 d.field("stt", &self.stt.keys().collect::<Vec<_>>());
30 #[cfg(feature = "tts")]
31 d.field("tts", &self.tts.keys().collect::<Vec<_>>());
32 d.field("order", &self.order).finish()
33 }
34}
35
36impl ProviderRegistry {
37 pub fn builder() -> ProviderRegistryBuilder {
38 ProviderRegistryBuilder::default()
39 }
40
41 pub fn builtin() -> Result<Self> {
43 super::builtin::build_builtin_registry()
44 }
45
46 pub fn stt_factory(&self, id: &ProviderId) -> Result<&dyn TranscriptionProviderFactory> {
47 self.stt
48 .get(id.as_str())
49 .map(|f| f.as_ref())
50 .ok_or_else(|| unknown_or_unsupported(id, "stt"))
51 }
52
53 #[cfg(feature = "tts")]
54 pub fn tts_factory(&self, id: &ProviderId) -> Result<&dyn SynthesisProviderFactory> {
55 self.tts
56 .get(id.as_str())
57 .map(|f| f.as_ref())
58 .ok_or_else(|| unknown_or_unsupported(id, "tts"))
59 }
60
61 pub fn descriptors(&self) -> Vec<&ProviderDescriptor> {
63 let mut out = Vec::new();
64 let mut seen = std::collections::HashSet::new();
65 for id in &self.order {
66 if !seen.insert(id.as_str()) {
67 continue;
68 }
69 if let Some(f) = self.stt.get(id.as_str()) {
70 out.push(f.descriptor());
71 continue;
72 }
73 #[cfg(feature = "tts")]
74 if let Some(f) = self.tts.get(id.as_str()) {
75 out.push(f.descriptor());
76 }
77 }
78 out
79 }
80
81 pub fn list_stt_ids(&self) -> Vec<ProviderId> {
82 self.stt.keys().map(|k| ProviderId::must(k)).collect()
83 }
84
85 #[cfg(feature = "tts")]
86 pub fn list_tts_ids(&self) -> Vec<ProviderId> {
87 self.tts.keys().map(|k| ProviderId::must(k)).collect()
88 }
89
90 pub fn known_provider_hint(&self) -> String {
91 let mut ids: Vec<&str> = self.order.iter().map(|p| p.as_str()).collect();
92 ids.sort_unstable();
93 ids.dedup();
94 ids.join(", ")
95 }
96}
97
98fn unknown_or_unsupported(id: &ProviderId, op: &str) -> crate::error::TranscriptionError {
99 UserError::InvalidProvider {
100 provider: format!(
101 "{id} (no {op} factory registered; known: use ProviderRegistry::descriptors)"
102 ),
103 }
104 .into()
105}
106
107#[derive(Default)]
109pub struct ProviderRegistryBuilder {
110 stt: BTreeMap<String, Arc<dyn TranscriptionProviderFactory>>,
112 #[cfg(feature = "tts")]
113 tts: BTreeMap<String, Arc<dyn SynthesisProviderFactory>>,
114 order: Vec<ProviderId>,
115}
116
117impl ProviderRegistryBuilder {
118 pub fn register_stt(mut self, factory: Arc<dyn TranscriptionProviderFactory>) -> Result<Self> {
119 let desc = factory.descriptor();
120 if !desc.operations.supports_stt() {
121 return Err(UserError::InvalidConfig {
122 reason: format!(
123 "factory '{}' cannot register as STT: operations.stt is false",
124 desc.id
125 ),
126 }
127 .into());
128 }
129 let key = desc.id.as_str().to_string();
130 if self.stt.contains_key(&key) {
131 return Err(UserError::InvalidConfig {
132 reason: format!("duplicate STT provider registration: {key}"),
133 }
134 .into());
135 }
136 if !self.order.iter().any(|p| p.as_str() == key) {
137 self.order.push(desc.id.clone());
138 }
139 self.stt.insert(key, factory);
140 Ok(self)
141 }
142
143 #[cfg(feature = "tts")]
144 pub fn register_tts(mut self, factory: Arc<dyn SynthesisProviderFactory>) -> Result<Self> {
145 let desc = factory.descriptor();
146 if !desc.operations.supports_tts() {
147 return Err(UserError::InvalidConfig {
148 reason: format!(
149 "factory '{}' cannot register as TTS: operations.tts is false",
150 desc.id
151 ),
152 }
153 .into());
154 }
155 let key = desc.id.as_str().to_string();
156 if self.tts.contains_key(&key) {
157 return Err(UserError::InvalidConfig {
158 reason: format!("duplicate TTS provider registration: {key}"),
159 }
160 .into());
161 }
162 if !self.order.iter().any(|p| p.as_str() == key) {
163 self.order.push(desc.id.clone());
164 }
165 self.tts.insert(key, factory);
166 Ok(self)
167 }
168
169 pub fn build(self) -> ProviderRegistry {
170 ProviderRegistry {
171 stt: self.stt,
172 #[cfg(feature = "tts")]
173 tts: self.tts,
174 order: self.order,
175 }
176 }
177}