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.read();
214 let core_state = state_manager.get_core_state();
215 let count = core_state.get_neuron_count() as usize;
216
217 Ok(count)
218 }
219
220 async fn get_total_synapse_count(&self) -> ServiceResult<usize> {
221 trace!(target: "feagi-services", "Getting total synapse count");
222
223 let state_manager_instance = StateManager::instance();
225 let state_manager = state_manager_instance.read();
226 let core_state = state_manager.get_core_state();
227 let count = core_state.get_synapse_count() as usize;
228
229 Ok(count)
230 }
231
232 async fn get_populated_areas(&self) -> ServiceResult<Vec<(String, usize)>> {
233 trace!(target: "feagi-services", "Getting populated areas");
234
235 let areas = self.connectome.read().get_populated_areas();
236 Ok(areas)
237 }
238
239 async fn get_neuron_density(&self, cortical_id: &str) -> ServiceResult<f32> {
240 trace!(target: "feagi-services", "Getting neuron density for area: {}", cortical_id);
241
242 let cortical_id_typed = CorticalID::try_from_base_64(cortical_id)
244 .map_err(|e| ServiceError::InvalidInput(format!("Invalid cortical ID: {}", e)))?;
245
246 let density = self
247 .connectome
248 .read()
249 .get_neuron_density(&cortical_id_typed);
250 Ok(density)
251 }
252
253 async fn is_brain_initialized(&self) -> ServiceResult<bool> {
254 trace!(target: "feagi-services", "Checking if brain is initialized");
255
256 let initialized = self.connectome.read().is_initialized();
257 Ok(initialized)
258 }
259
260 async fn is_burst_engine_ready(&self) -> ServiceResult<bool> {
261 trace!(target: "feagi-services", "Checking if burst engine is ready");
262
263 let ready = self.connectome.read().has_npu();
264 Ok(ready)
265 }
266
267 async fn get_regular_neuron_count(&self) -> ServiceResult<usize> {
268 trace!(target: "feagi-services", "Getting regular (non-memory) neuron count");
269
270 let state_manager_instance = StateManager::instance();
272 let state_manager = state_manager_instance.read();
273 let core_state = state_manager.get_core_state();
274 let count = core_state.get_regular_neuron_count() as usize;
275
276 Ok(count)
277 }
278
279 async fn get_memory_neuron_count(&self) -> ServiceResult<usize> {
280 trace!(target: "feagi-services", "Getting memory neuron count");
281
282 let state_manager_instance = StateManager::instance();
284 let state_manager = state_manager_instance.read();
285 let core_state = state_manager.get_core_state();
286 let count = core_state.get_memory_neuron_count() as usize;
287
288 Ok(count)
289 }
290}