feagi_services/impls/
analytics_service_impl.rs1use std::sync::Arc;
12
13use async_trait::async_trait;
14use feagi_brain_development::ConnectomeManager;
15use feagi_npu_burst_engine::BurstLoopRunner;
16use feagi_state_manager::StateManager;
17use feagi_structures::genomic::cortical_area::CorticalID;
18use parking_lot::RwLock;
19use tracing::trace;
20
21use crate::traits::AnalyticsService;
22use crate::types::*;
23
24pub struct AnalyticsServiceImpl {
26 connectome: Arc<RwLock<ConnectomeManager>>,
27 burst_runner: Option<Arc<RwLock<BurstLoopRunner>>>,
28}
29
30impl AnalyticsServiceImpl {
31 pub fn new(
32 connectome: Arc<RwLock<ConnectomeManager>>,
33 burst_runner: Option<Arc<RwLock<BurstLoopRunner>>>,
34 ) -> Self {
35 Self {
36 connectome,
37 burst_runner,
38 }
39 }
40}
41
42#[async_trait]
43impl AnalyticsService for AnalyticsServiceImpl {
44 async fn get_system_health(&self) -> ServiceResult<SystemHealth> {
45 trace!(target: "feagi-services", "Getting system health");
46
47 let neuron_count = self.get_total_neuron_count().await?;
48 let manager = self.connectome.read();
49 let cortical_area_count = manager.get_cortical_area_count();
50 let neuron_capacity = manager.get_neuron_capacity();
51 let synapse_capacity = manager.get_synapse_capacity();
52
53 let (burst_engine_active, burst_count) = if let Some(ref runner) = self.burst_runner {
55 let runner_lock = runner.read();
56 (runner_lock.is_running(), runner_lock.get_burst_count())
57 } else {
58 (false, 0)
59 };
60
61 let brain_readiness = cortical_area_count > 0 && burst_engine_active;
64
65 Ok(SystemHealth {
66 burst_engine_active,
67 brain_readiness,
68 neuron_count,
69 neuron_capacity,
70 synapse_capacity,
71 cortical_area_count,
72 burst_count,
73 })
74 }
75
76 async fn get_cortical_area_stats(&self, cortical_id: &str) -> ServiceResult<CorticalAreaStats> {
77 trace!(target: "feagi-services", "Getting cortical area stats: {}", cortical_id);
78
79 let manager = self.connectome.read();
80 let neuron_count = manager.get_neuron_count_in_area(
81 &CorticalID::try_from_base_64(cortical_id)
82 .map_err(|e| ServiceError::InvalidInput(format!("Invalid cortical ID: {}", e)))?,
83 );
84 let synapse_count = manager.get_synapse_count_in_area(
85 &CorticalID::try_from_base_64(cortical_id)
86 .map_err(|e| ServiceError::InvalidInput(format!("Invalid cortical ID: {}", e)))?,
87 );
88 let density = manager.get_neuron_density(
89 &CorticalID::try_from_base_64(cortical_id)
90 .map_err(|e| ServiceError::InvalidInput(format!("Invalid cortical ID: {}", e)))?,
91 );
92 let populated = neuron_count > 0;
93
94 Ok(CorticalAreaStats {
95 cortical_id: cortical_id.to_string(),
96 neuron_count,
97 synapse_count,
98 density,
99 populated,
100 })
101 }
102
103 async fn get_all_cortical_area_stats(&self) -> ServiceResult<Vec<CorticalAreaStats>> {
104 trace!(target: "feagi-services", "Getting all cortical area stats");
105
106 let all_stats = self.connectome.read().get_all_area_stats();
107
108 let stats: Vec<CorticalAreaStats> = all_stats
109 .into_iter()
110 .map(
111 |(cortical_id, neuron_count, synapse_count, density)| CorticalAreaStats {
112 cortical_id,
113 neuron_count,
114 synapse_count,
115 density,
116 populated: neuron_count > 0,
117 },
118 )
119 .collect();
120
121 Ok(stats)
122 }
123
124 async fn get_connectivity_stats(
125 &self,
126 source_area: &str,
127 target_area: &str,
128 ) -> ServiceResult<ConnectivityStats> {
129 trace!(target: "feagi-services",
130 "Getting connectivity stats: {} -> {}",
131 source_area,
132 target_area
133 );
134
135 let source_id = CorticalID::try_from_base_64(source_area).map_err(|e| {
137 ServiceError::InvalidInput(format!("Invalid source cortical ID: {}", e))
138 })?;
139 let target_id = CorticalID::try_from_base_64(target_area).map_err(|e| {
140 ServiceError::InvalidInput(format!("Invalid target cortical ID: {}", e))
141 })?;
142
143 let manager = self.connectome.read();
144
145 if !manager.has_cortical_area(&source_id) {
147 return Err(ServiceError::NotFound {
148 resource: "CorticalArea".to_string(),
149 id: source_area.to_string(),
150 });
151 }
152 if !manager.has_cortical_area(&target_id) {
153 return Err(ServiceError::NotFound {
154 resource: "CorticalArea".to_string(),
155 id: target_area.to_string(),
156 });
157 }
158
159 let source_neurons = manager.get_neurons_in_area(&source_id);
161
162 let mut synapse_count = 0;
164 let mut total_weight: u64 = 0;
165 let mut excitatory_count = 0;
166 let mut inhibitory_count = 0;
167
168 for source_neuron_id in source_neurons {
169 let outgoing = manager.get_outgoing_synapses(source_neuron_id);
171
172 for (target_neuron_id, weight, _psp, synapse_type) in outgoing {
173 if let Some(target_cortical_id) =
175 manager.get_neuron_cortical_id(target_neuron_id as u64)
176 {
177 if target_cortical_id.as_base_64() == target_area {
178 synapse_count += 1;
179 total_weight += weight as u64;
180
181 if synapse_type == 0 {
183 excitatory_count += 1;
184 } else {
185 inhibitory_count += 1;
186 }
187 }
188 }
189 }
190 }
191
192 let avg_weight = if synapse_count > 0 {
193 (total_weight as f64 / synapse_count as f64) as f32
194 } else {
195 0.0
196 };
197
198 Ok(ConnectivityStats {
199 source_area: source_area.to_string(),
200 target_area: target_area.to_string(),
201 synapse_count,
202 avg_weight,
203 excitatory_count,
204 inhibitory_count,
205 })
206 }
207
208 async fn get_total_neuron_count(&self) -> ServiceResult<usize> {
209 trace!(target: "feagi-services", "Getting total neuron count");
210
211 let state_manager_instance = StateManager::instance();
213 let state_manager = state_manager_instance
214 .try_read()
215 .ok_or_else(|| ServiceError::Internal("Failed to read StateManager".to_string()))?;
216 let core_state = state_manager.get_core_state();
217 let count = core_state.get_neuron_count() as usize;
218
219 Ok(count)
220 }
221
222 async fn get_total_synapse_count(&self) -> ServiceResult<usize> {
223 trace!(target: "feagi-services", "Getting total synapse count");
224
225 let state_manager_instance = StateManager::instance();
227 let state_manager = state_manager_instance
228 .try_read()
229 .ok_or_else(|| ServiceError::Internal("Failed to read StateManager".to_string()))?;
230 let core_state = state_manager.get_core_state();
231 let count = core_state.get_synapse_count() as usize;
232
233 Ok(count)
234 }
235
236 async fn get_populated_areas(&self) -> ServiceResult<Vec<(String, usize)>> {
237 trace!(target: "feagi-services", "Getting populated areas");
238
239 let areas = self.connectome.read().get_populated_areas();
240 Ok(areas)
241 }
242
243 async fn get_neuron_density(&self, cortical_id: &str) -> ServiceResult<f32> {
244 trace!(target: "feagi-services", "Getting neuron density for area: {}", cortical_id);
245
246 let cortical_id_typed = CorticalID::try_from_base_64(cortical_id)
248 .map_err(|e| ServiceError::InvalidInput(format!("Invalid cortical ID: {}", e)))?;
249
250 let density = self
251 .connectome
252 .read()
253 .get_neuron_density(&cortical_id_typed);
254 Ok(density)
255 }
256
257 async fn is_brain_initialized(&self) -> ServiceResult<bool> {
258 trace!(target: "feagi-services", "Checking if brain is initialized");
259
260 let initialized = self.connectome.read().is_initialized();
261 Ok(initialized)
262 }
263
264 async fn is_burst_engine_ready(&self) -> ServiceResult<bool> {
265 trace!(target: "feagi-services", "Checking if burst engine is ready");
266
267 let ready = self.connectome.read().has_npu();
268 Ok(ready)
269 }
270
271 async fn get_regular_neuron_count(&self) -> ServiceResult<usize> {
272 trace!(target: "feagi-services", "Getting regular (non-memory) neuron count");
273
274 let state_manager_instance = StateManager::instance();
276 let state_manager = state_manager_instance
277 .try_read()
278 .ok_or_else(|| ServiceError::Internal("Failed to read StateManager".to_string()))?;
279 let core_state = state_manager.get_core_state();
280 let count = core_state.get_regular_neuron_count() as usize;
281
282 Ok(count)
283 }
284
285 async fn get_memory_neuron_count(&self) -> ServiceResult<usize> {
286 trace!(target: "feagi-services", "Getting memory neuron count");
287
288 let state_manager_instance = StateManager::instance();
290 let state_manager = state_manager_instance
291 .try_read()
292 .ok_or_else(|| ServiceError::Internal("Failed to read StateManager".to_string()))?;
293 let core_state = state_manager.get_core_state();
294 let count = core_state.get_memory_neuron_count() as usize;
295
296 Ok(count)
297 }
298}