#![cfg(feature = "onnx")]
use std::io::Write;
use std::path::PathBuf;
use steeldb::text::{SpladeProjector, SpoTagger};
use steeldb::Corpus;
fn ml_bundle() -> PathBuf {
std::env::var("STEELDB_ML_BUNDLE").map(PathBuf::from).unwrap_or_default()
}
fn splade_dir() -> PathBuf {
std::env::var("STEELDB_SPLADE_DIR").map(PathBuf::from).unwrap_or_default()
}
#[test]
fn incremental_text_ingest_hot_engine() {
let dir = ml_bundle();
if !dir.join("spo.onnx").exists() {
eprintln!("skip: spo.onnx not present");
return;
}
let splade = splade_dir();
let splade_opt = splade.join("splade.onnx").exists().then_some(splade.as_path());
let mut eng = steeldb::projectors::TextEngine::load(&dir, splade_opt).expect("load engine");
let mut c = Corpus::new_incremental("live", vec!["sentence".into()], steeldb::CorpusKind::Text);
eng.project_text(
"Toyota reinforced the concrete beam with rebar to meet the 2024 seismic standard in Osaka.",
&mut |s| {
c.add_situation(s.tokens, s.display);
},
);
let before = c.stats().situations;
assert!(before >= 1, "expected at least one projected situation");
eng.project_text("Hyundai tested the EV battery pack in Korea.", &mut |s| {
c.add_situation(s.tokens, s.display);
});
let s = c.stats();
assert!(s.situations > before, "corpus should grow on further ingest");
assert!(s.vocab > 0, "expected a non-empty vocabulary");
}
#[test]
fn spo_tagger_multilingual() {
let dir = ml_bundle();
if !dir.join("spo.onnx").exists() {
eprintln!("skip: spo.onnx not present");
return;
}
let mut tagger = SpoTagger::load(&dir).expect("load tagger");
let cases = [
("en", "Toyota reinforced the concrete beam with rebar to meet the 2024 seismic standard in Osaka."),
("ja", "トヨタは大阪で2024年の耐震基準を満たすため、鉄筋でコンクリート梁を補強した。"),
("ko", "도요타는 오사카에서 2024년 내진 기준을 충족하기 위해 철근으로 콘크리트 보를 보강했다."),
];
for (lang, text) in cases {
let spans = tagger.tag(text).expect("tag");
eprintln!("[{lang}] {} spans:", spans.len());
for s in &spans {
eprintln!(" {:<5} {:?}", s.kind, s.text);
}
assert!(!spans.is_empty(), "{lang}: expected at least one span");
assert!(spans.iter().all(|s| !s.text.trim().is_empty()));
}
}
#[test]
fn splade_projects_english_facets() {
let dir = splade_dir();
if !dir.join("splade.onnx").exists() {
eprintln!("skip: splade.onnx not present");
return;
}
let mut splade = SpladeProjector::load(&dir, false).expect("load splade");
let terms = splade
.project(
"engineers reinforced the concrete beam using high-strength rebar to meet seismic standards",
8,
0.3,
)
.expect("project");
eprintln!("facets: {:?}", splade.facets());
for t in &terms {
eprintln!(" {:<24} w={:.3}", t.token, t.weight);
}
assert!(!terms.is_empty(), "expected facet activations");
assert!(terms.iter().all(|t| t.token.contains('/')));
}
#[test]
fn text_projector_end_to_end() {
let ml = ml_bundle();
if !ml.join("spo.onnx").exists() {
eprintln!("skip: tagger not present");
return;
}
let p = std::env::temp_dir().join("steeldb_text_e2e.txt");
let mut f = std::fs::File::create(&p).unwrap();
f.write_all(
"Toyota reinforced the concrete beam in Osaka. 도요타는 오사카에서 철근을 사용했다. トヨタは大阪で鉄筋を使用した。"
.as_bytes(),
)
.unwrap();
let splade = splade_dir();
let splade_opt = if splade.join("splade.onnx").exists() { Some(splade.as_path()) } else { None };
let corpus = Corpus::from_text(&p, &ml, splade_opt).expect("project text");
let s = corpus.stats();
eprintln!("text corpus: {} situations, {} tokens", s.situations, s.vocab);
assert!(s.situations >= 3, "expected one situation per sentence");
let out = corpus.query("geo/*", 10);
eprintln!("geo/* → {} hits", out.count);
assert!(out.count >= 1, "expected a geo span to be queryable");
}