use std::collections::HashSet;
use terraphim_rolegraph::RoleGraph;
use terraphim_types::shared_learning::{SharedLearning, TrustLevel};
use terraphim_types::{Document, DocumentType, IndexedDocument};
#[derive(Debug, Clone)]
pub struct LearningIndexerConfig {
pub min_trust_level: TrustLevel,
pub rank_boost_factor: f64,
pub include_content: bool,
}
impl Default for LearningIndexerConfig {
fn default() -> Self {
Self {
min_trust_level: TrustLevel::L2,
rank_boost_factor: 100.0,
include_content: true,
}
}
}
pub fn learning_to_indexed_document(
learning: &SharedLearning,
config: &LearningIndexerConfig,
) -> IndexedDocument {
let base_rank = 1u64;
let quality_boost =
(learning.quality.success_rate.unwrap_or(0.5) * config.rank_boost_factor) as u64;
let agent_boost = learning.quality.agent_count as u64 * 10;
let rank = base_rank + quality_boost + agent_boost;
let doc = Document {
id: learning.id.clone(),
url: String::new(),
title: learning.title.clone(),
body: if config.include_content {
learning.content.clone()
} else {
String::new()
},
description: None,
summarization: None,
stub: None,
doc_type: DocumentType::Document,
rank: Some(rank),
tags: Some(learning.keywords.clone()),
source_haystack: None,
synonyms: None,
route: None,
priority: None,
quality_score: None,
};
IndexedDocument {
id: doc.id.clone(),
matched_edges: Vec::new(),
rank,
tags: doc.tags.clone().unwrap_or_default(),
nodes: Vec::new(), quality_score: None,
}
}
pub fn index_learning(
graph: &mut RoleGraph,
learning: &SharedLearning,
config: &LearningIndexerConfig,
) -> Result<IndexedDocument, LearningIndexError> {
if learning.trust_level < config.min_trust_level {
return Err(LearningIndexError::TrustLevelTooLow {
got: learning.trust_level,
need: config.min_trust_level,
});
}
let mut indexed = learning_to_indexed_document(learning, config);
for keyword in &learning.keywords {
let node_ids = graph.find_matching_node_ids(keyword);
indexed.nodes.extend(node_ids);
}
let unique_nodes: HashSet<_> = indexed.nodes.iter().cloned().collect();
indexed.nodes = unique_nodes.into_iter().collect();
graph
.index_learning_document(indexed.clone())
.map_err(LearningIndexError::Graph)?;
Ok(indexed)
}
pub fn index_learnings(
graph: &mut RoleGraph,
learnings: &[SharedLearning],
config: &LearningIndexerConfig,
) -> Vec<Result<IndexedDocument, LearningIndexError>> {
learnings
.iter()
.map(|learning| index_learning(graph, learning, config))
.collect()
}
#[derive(Debug, thiserror::Error)]
pub enum LearningIndexError {
#[error("learning trust level {got:?} below minimum {need:?}")]
TrustLevelTooLow { got: TrustLevel, need: TrustLevel },
#[error("graph error: {0}")]
Graph(terraphim_rolegraph::Error),
}