use std::path::PathBuf;
use std::sync::OnceLock;
const EMBEDDED_LEXICON: &str = include_str!("../../data/meta/dreaming-lexicon.lino");
#[derive(Debug, Default, Clone)]
pub struct DreamingLexicon {
pub task_kind_cues: Vec<String>,
pub task_intent_cues: Vec<String>,
pub topic_stopwords: Vec<String>,
pub learning_kind_cues: Vec<String>,
pub learning_content_cues: Vec<String>,
pub cache_kind_cues: Vec<String>,
pub cache_tool_cues: Vec<String>,
pub intermediate_kind_cues: Vec<String>,
}
impl DreamingLexicon {
fn push(&mut self, key: &str, value: String) {
match key {
"task_kind_cue" => self.task_kind_cues.push(value),
"task_intent_cue" => self.task_intent_cues.push(value),
"topic_stopword" => self.topic_stopwords.push(value),
"learning_kind_cue" => self.learning_kind_cues.push(value),
"learning_content_cue" => self.learning_content_cues.push(value),
"cache_kind_cue" => self.cache_kind_cues.push(value),
"cache_tool_cue" => self.cache_tool_cues.push(value),
"intermediate_kind_cue" => self.intermediate_kind_cues.push(value),
_ => {}
}
}
}
#[must_use]
pub fn parse_lexicon(text: &str) -> DreamingLexicon {
let mut lexicon = DreamingLexicon::default();
for line in text.lines() {
let line = line.trim();
let Some((key, rest)) = line.split_once(' ') else {
continue;
};
let Some(value) = rest
.trim()
.strip_prefix('"')
.and_then(|tail| tail.strip_suffix('"'))
else {
continue;
};
lexicon.push(key, value.to_lowercase());
}
lexicon
}
#[must_use]
pub fn data_document_path(file_name: &str) -> Option<PathBuf> {
if let Ok(dir) = std::env::var("FORMAL_AI_DATA_DIR") {
let trimmed = dir.trim();
if !trimmed.is_empty() {
let candidate = PathBuf::from(trimmed).join(file_name);
if candidate.is_file() {
return Some(candidate);
}
}
}
let repo_relative = PathBuf::from("data/meta").join(file_name);
repo_relative.is_file().then_some(repo_relative)
}
#[must_use]
pub fn load_data_document(file_name: &str, embedded: &'static str) -> String {
data_document_path(file_name)
.and_then(|path| std::fs::read_to_string(path).ok())
.unwrap_or_else(|| embedded.to_owned())
}
pub fn lexicon() -> &'static DreamingLexicon {
static LEXICON: OnceLock<DreamingLexicon> = OnceLock::new();
LEXICON.get_or_init(|| {
parse_lexicon(&load_data_document(
"dreaming-lexicon.lino",
EMBEDDED_LEXICON,
))
})
}