use crate::common::ApiState;
use crate::common::{ApiError, ApiResult, Json, State};
use serde::Serialize;
use std::collections::HashMap;
#[utoipa::path(
get,
path = "/v1/input/vision",
tag = "input",
responses(
(status = 200, description = "Vision input configuration", body = HashMap<String, serde_json::Value>),
(status = 500, description = "Internal server error")
)
)]
pub async fn get_vision(
State(_state): State<ApiState>,
) -> ApiResult<Json<HashMap<String, serde_json::Value>>> {
Ok(Json(HashMap::new()))
}
#[utoipa::path(
post,
path = "/v1/input/vision",
tag = "input",
responses(
(status = 200, description = "Vision input updated", content_type = "application/json"),
(status = 500, description = "Not yet implemented")
)
)]
pub async fn post_vision(
State(_state): State<ApiState>,
Json(_req): Json<HashMap<String, serde_json::Value>>,
) -> ApiResult<Json<HashMap<String, String>>> {
Err(ApiError::internal("Not yet implemented"))
}
#[utoipa::path(get, path = "/v1/input/sources", tag = "input")]
pub async fn get_sources(State(_state): State<ApiState>) -> ApiResult<Json<Vec<String>>> {
Ok(Json(vec!["vision".to_string()]))
}
#[utoipa::path(post, path = "/v1/input/configure", tag = "input")]
pub async fn post_configure(
State(_state): State<ApiState>,
Json(_req): Json<HashMap<String, serde_json::Value>>,
) -> ApiResult<Json<HashMap<String, String>>> {
Ok(Json(HashMap::from([(
"message".to_string(),
"Input configured".to_string(),
)])))
}
#[derive(Serialize, Clone, Debug, utoipa::ToSchema)]
pub struct SensorTapSample {
pub x: u32,
pub y: u32,
pub z: u32,
pub potential: f32,
}
#[derive(Serialize, Clone, Debug, utoipa::ToSchema)]
pub struct SensorTapArea {
pub cortical_id: String,
pub cortical_idx: u32,
pub neuron_count: usize,
pub samples: Vec<SensorTapSample>,
}
#[derive(Serialize, Clone, Debug, utoipa::ToSchema)]
pub struct SensorSnapshotResponse {
pub burst_num: u64,
pub timestamp_ms: i64,
pub has_data: bool,
pub total_areas: usize,
pub total_neurons: usize,
pub areas: Vec<SensorTapArea>,
}
#[utoipa::path(
get,
path = "/v1/input/sensor_snapshot/last",
tag = "input",
params(
("cortical_id" = Option<String>, Query, description = "Filter areas by base64 cortical id")
),
responses(
(status = 200, description = "Latest sensory pipeline snapshot", body = SensorSnapshotResponse),
(status = 500, description = "Internal server error")
)
)]
pub async fn get_sensor_snapshot_last(
State(_state): State<ApiState>,
axum::extract::Query(query): axum::extract::Query<HashMap<String, String>>,
) -> ApiResult<Json<SensorSnapshotResponse>> {
let snap = feagi_npu_burst_engine::BurstTaps::instance().sensor_snapshot();
let cortical_filter = query.get("cortical_id").cloned();
let mut areas: Vec<SensorTapArea> = snap
.areas
.into_iter()
.filter(|a| match &cortical_filter {
Some(filter) => filter == &a.cortical_id,
None => true,
})
.map(|a| SensorTapArea {
cortical_id: a.cortical_id,
cortical_idx: a.cortical_idx,
neuron_count: a.neuron_count,
samples: a
.samples
.into_iter()
.map(|s| SensorTapSample {
x: s.x,
y: s.y,
z: s.z,
potential: s.potential,
})
.collect(),
})
.collect();
areas.sort_by(|a, b| a.cortical_id.cmp(&b.cortical_id));
let total_areas = areas.len();
let total_neurons: usize = areas.iter().map(|a| a.neuron_count).sum();
let has_data = total_areas > 0 && snap.burst_num > 0;
Ok(Json(SensorSnapshotResponse {
burst_num: snap.burst_num,
timestamp_ms: snap.timestamp_ms,
has_data,
total_areas,
total_neurons,
areas,
}))
}