use std::path::{Path, PathBuf};
use steeldb::vocabulary::{candidate_fields, merge_existing, sample_docs, seed_from_sample, VocabularySpace};
fn main() -> Result<(), String> {
let args: Vec<String> = std::env::args().collect();
let dir = args
.iter()
.skip(1)
.find(|a| !a.starts_with("--"))
.cloned()
.ok_or("usage: sense_ontology <dir> [--sample N] [--min-support N] [--pretty]")?;
let flag = |name: &str| -> Option<usize> {
args.iter().position(|a| a == name).and_then(|i| args.get(i + 1)).and_then(|v| v.parse().ok())
};
let n_sample = flag("--sample").unwrap_or(96);
let min_support = flag("--min-support").unwrap_or(3);
let pretty = args.iter().any(|a| a == "--pretty");
let path = PathBuf::from(&dir);
if !path.exists() {
return Err(format!("{dir}: no such path"));
}
let samples = sample_docs(&path, n_sample, 4000);
if samples.is_empty() {
return Err(format!("no sampleable documents under {dir}"));
}
let candidates = candidate_fields(&samples);
let seed = seed_from_sample(&dir, &samples, min_support);
let existing = VocabularySpace::for_corpus(&path);
let spec = match &existing {
Some(e) => merge_existing(seed, e),
None => seed,
};
let out = serde_json::json!({
"corpus": dir,
"sampled_docs": samples.len(),
"min_support": min_support,
"entity_facets": spec.entity_facets.iter().map(|f| serde_json::json!({
"name": f.name,
"path": spec.facet_path(&f.name),
"parent": f.parent,
"description": f.description,
"structural": f.structural,
"examples": f.examples,
})).collect::<Vec<_>>(),
"relation_facets": spec.relation_facets.iter().map(|r| serde_json::json!({
"name": r.name, "head": r.head, "tail": r.tail, "uri": format!("rel/{}/+", r.name),
})).collect::<Vec<_>>(),
"wildcard_stems": spec.valid_prefixes(),
"taggable_facets": spec.taggable_facets(),
"gazetteer_size": spec.gazetteer.len(),
"candidate_fields": candidates.iter().map(|(name, n)| serde_json::json!({
"field": name, "support": n, "kept": *n >= min_support,
})).collect::<Vec<_>>(),
"existing_spec_on_disk": existing.as_ref().map(|e| serde_json::json!({
"entity_facets": e.entity_facets.len(),
"relation_facets": e.relation_facets.len(),
})),
"valid": spec.validate().is_ok(),
"validation_error": spec.validate().err().map(|e| e.to_string()),
});
let body = if pretty {
serde_json::to_string_pretty(&out).map_err(|e| e.to_string())?
} else {
serde_json::to_string(&out).map_err(|e| e.to_string())?
};
println!("{body}");
Ok(())
}
#[allow(dead_code)]
fn unused(_: &Path) {}