use super::{converter::to_runtime_genome, GenomeParser};
use crate::{EvoResult, RuntimeGenome};
use serde_json::Value;
use std::fs;
use std::path::Path;
pub fn load_genome_from_file<P: AsRef<Path>>(path: P) -> EvoResult<RuntimeGenome> {
let json_str = fs::read_to_string(path)?;
load_genome_from_json(&json_str)
}
pub fn peek_quantization_precision<P: AsRef<Path>>(path: P) -> EvoResult<String> {
let json_str = fs::read_to_string(path)?;
let json_value: Value = serde_json::from_str(&json_str).map_err(|e| {
crate::types::EvoError::InvalidGenome(format!("Failed to parse JSON: {}", e))
})?;
let precision = json_value
.get("genome_physiology")
.and_then(|p| p.get("quantization_precision"))
.and_then(|q| q.as_str())
.unwrap_or("int8");
Ok(precision.to_lowercase())
}
pub fn load_genome_from_json(json_str: &str) -> EvoResult<RuntimeGenome> {
let json_value: Value = serde_json::from_str(json_str).map_err(|e| {
crate::types::EvoError::InvalidGenome(format!("Failed to parse JSON: {}", e))
})?;
let hierarchical_json = if is_flat_format(&json_value) {
crate::converter_flat_full::convert_flat_to_hierarchical_full(&json_value).map_err(|e| {
tracing::error!(target: "feagi-evo", "convert_flat_to_hierarchical_full failed: {}", e);
e
})?
} else {
json_value
};
let migrated_json = match crate::genome::migrator::migrate_genome(&hierarchical_json) {
Ok(migration_result) => {
if migration_result.cortical_ids_migrated > 0 {
tracing::info!(
"🔄 [GENOME-LOAD] Migrated {} cortical IDs from old format to new format",
migration_result.cortical_ids_migrated
);
for (old_id, new_id) in migration_result.id_mapping.iter().take(5) {
tracing::info!("🔄 [GENOME-LOAD] Example: '{}' → '{}'", old_id, new_id);
}
if !migration_result.warnings.is_empty() {
for warning in &migration_result.warnings {
tracing::warn!("⚠️ [GENOME-LOAD] Migration warning: {}", warning);
}
}
} else {
tracing::debug!("🔄 [GENOME-LOAD] No cortical IDs needed migration");
}
migration_result.genome
}
Err(e) => {
tracing::warn!(
"⚠️ [GENOME-LOAD] Migration failed: {}, continuing without migration",
e
);
hierarchical_json
}
};
let hierarchical_json_str = serde_json::to_string(&migrated_json).map_err(|e| {
crate::types::EvoError::InvalidGenome(format!(
"Failed to serialize converted genome: {}",
e
))
})?;
let parsed = GenomeParser::parse(&hierarchical_json_str).map_err(|e| {
tracing::error!(target: "feagi-evo", "GenomeParser::parse failed: {}", e);
e
})?;
let mut runtime_genome = to_runtime_genome(parsed, &hierarchical_json_str).map_err(|e| {
tracing::error!(target: "feagi-evo", "to_runtime_genome failed: {}", e);
e
})?;
let fixes_applied = crate::validator::auto_fix_genome(&mut runtime_genome);
if fixes_applied > 0 {
tracing::info!(
"🔧 [GENOME-LOAD] Applied {} auto-fixes to genome",
fixes_applied
);
}
Ok(runtime_genome)
}
fn is_flat_format(genome_value: &Value) -> bool {
let blueprint = match genome_value.get("blueprint") {
Some(bp) => bp,
None => return false,
};
let blueprint_obj = match blueprint.as_object() {
Some(obj) => obj,
None => return false,
};
blueprint_obj.keys().any(|key| {
key.starts_with("___") && key.contains('-') && key.len() > 20
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_load_minimal_genome() {
let json = r#"{
"genome_id": "test_genome",
"genome_title": "Test Genome",
"genome_description": "A test genome",
"version": "2.0",
"blueprint": {
"_power": {
"cortical_name": "Test Area",
"block_boundaries": [10, 10, 10],
"relative_coordinate": [0, 0, 0],
"cortical_type": "INTERCONNECT"
}
},
"brain_regions": {},
"neuron_morphologies": {},
"physiology": {
"simulation_timestep": 0.025,
"max_age": 10000000
},
"stats": {
"innate_cortical_area_count": 1,
"innate_neuron_count": 0,
"innate_synapse_count": 0
},
"signatures": {
"genome": "0000000000000000",
"blueprint": "0000000000000000",
"physiology": "0000000000000000"
},
"timestamp": 1234567890.0
}"#;
let genome = load_genome_from_json(json).unwrap();
assert_eq!(genome.metadata.genome_id, "test_genome");
assert_eq!(genome.metadata.version, "2.0");
assert_eq!(genome.cortical_areas.len(), 1);
assert_eq!(genome.physiology.simulation_timestep, 0.025);
}
}