fix: graphmapper gracefully failing

This commit is contained in:
Per Stark
2025-06-06 23:15:09 +02:00
parent d2772bd09c
commit 811aaec554
2 changed files with 56 additions and 25 deletions

View File

@@ -6,9 +6,12 @@ use tokio::task;
use common::{ use common::{
error::AppError, error::AppError,
storage::types::{ storage::{
knowledge_entity::{KnowledgeEntity, KnowledgeEntityType}, db::SurrealDbClient,
knowledge_relationship::KnowledgeRelationship, types::{
knowledge_entity::{KnowledgeEntity, KnowledgeEntityType},
knowledge_relationship::KnowledgeRelationship,
},
}, },
utils::embedding::generate_embedding, utils::embedding::generate_embedding,
}; };
@@ -56,13 +59,20 @@ impl LLMEnrichmentResult {
source_id: &str, source_id: &str,
user_id: &str, user_id: &str,
openai_client: &async_openai::Client<async_openai::config::OpenAIConfig>, openai_client: &async_openai::Client<async_openai::config::OpenAIConfig>,
db_client: &SurrealDbClient,
) -> Result<(Vec<KnowledgeEntity>, Vec<KnowledgeRelationship>), AppError> { ) -> Result<(Vec<KnowledgeEntity>, Vec<KnowledgeRelationship>), AppError> {
// Create mapper and pre-assign IDs // Create mapper and pre-assign IDs
let mapper = Arc::new(Mutex::new(self.create_mapper()?)); let mapper = Arc::new(Mutex::new(self.create_mapper()?));
// Process entities // Process entities
let entities = self let entities = self
.process_entities(source_id, user_id, Arc::clone(&mapper), openai_client) .process_entities(
source_id,
user_id,
Arc::clone(&mapper),
openai_client,
db_client,
)
.await?; .await?;
// Process relationships // Process relationships
@@ -88,6 +98,7 @@ impl LLMEnrichmentResult {
user_id: &str, user_id: &str,
mapper: Arc<Mutex<GraphMapper>>, mapper: Arc<Mutex<GraphMapper>>,
openai_client: &async_openai::Client<async_openai::config::OpenAIConfig>, openai_client: &async_openai::Client<async_openai::config::OpenAIConfig>,
db_client: &SurrealDbClient,
) -> Result<Vec<KnowledgeEntity>, AppError> { ) -> Result<Vec<KnowledgeEntity>, AppError> {
let futures: Vec<_> = self let futures: Vec<_> = self
.knowledge_entities .knowledge_entities
@@ -98,10 +109,18 @@ impl LLMEnrichmentResult {
let source_id = source_id.to_string(); let source_id = source_id.to_string();
let user_id = user_id.to_string(); let user_id = user_id.to_string();
let entity = entity.clone(); let entity = entity.clone();
let db_client = db_client.clone();
task::spawn(async move { task::spawn(async move {
create_single_entity(&entity, &source_id, &user_id, mapper, &openai_client) create_single_entity(
.await &entity,
&source_id,
&user_id,
mapper,
&openai_client,
&db_client.clone(),
)
.await
}) })
}) })
.collect(); .collect();
@@ -120,14 +139,14 @@ impl LLMEnrichmentResult {
user_id: &str, user_id: &str,
mapper: Arc<Mutex<GraphMapper>>, mapper: Arc<Mutex<GraphMapper>>,
) -> Result<Vec<KnowledgeRelationship>, AppError> { ) -> Result<Vec<KnowledgeRelationship>, AppError> {
let mut mapper_guard = mapper let mapper_guard = mapper
.lock() .lock()
.map_err(|_| AppError::GraphMapper("Failed to lock mapper".into()))?; .map_err(|_| AppError::GraphMapper("Failed to lock mapper".into()))?;
self.relationships self.relationships
.iter() .iter()
.map(|rel| { .map(|rel| {
let source_db_id = mapper_guard.get_or_parse_id(&rel.source); let source_db_id = mapper_guard.get_or_parse_id(&rel.source)?;
let target_db_id = mapper_guard.get_or_parse_id(&rel.target); let target_db_id = mapper_guard.get_or_parse_id(&rel.target)?;
Ok(KnowledgeRelationship::new( Ok(KnowledgeRelationship::new(
source_db_id.to_string(), source_db_id.to_string(),
@@ -146,17 +165,13 @@ async fn create_single_entity(
user_id: &str, user_id: &str,
mapper: Arc<Mutex<GraphMapper>>, mapper: Arc<Mutex<GraphMapper>>,
openai_client: &async_openai::Client<async_openai::config::OpenAIConfig>, openai_client: &async_openai::Client<async_openai::config::OpenAIConfig>,
db_client: &SurrealDbClient,
) -> Result<KnowledgeEntity, AppError> { ) -> Result<KnowledgeEntity, AppError> {
let assigned_id = { let assigned_id = {
let mapper = mapper let mapper = mapper
.lock() .lock()
.map_err(|_| AppError::GraphMapper("Failed to lock mapper".into()))?; .map_err(|_| AppError::GraphMapper("Failed to lock mapper".into()))?;
mapper mapper.get_id(&llm_entity.key)?.to_string()
.get_id(&llm_entity.key)
.ok_or_else(|| {
AppError::GraphMapper(format!("ID not found for key: {}", llm_entity.key))
})?
.to_string()
}; };
let embedding_input = format!( let embedding_input = format!(
@@ -164,7 +179,7 @@ async fn create_single_entity(
llm_entity.name, llm_entity.description, llm_entity.entity_type llm_entity.name, llm_entity.description, llm_entity.entity_type
); );
let embedding = generate_embedding(openai_client, &embedding_input).await?; let embedding = generate_embedding(openai_client, &embedding_input, db_client).await?;
let now = Utc::now(); let now = Utc::now();
Ok(KnowledgeEntity { Ok(KnowledgeEntity {

View File

@@ -1,5 +1,6 @@
pub mod llm_instructions; pub mod llm_instructions;
use common::error::AppError;
use std::collections::HashMap; use std::collections::HashMap;
use uuid::Uuid; use uuid::Uuid;
@@ -21,24 +22,39 @@ impl GraphMapper {
key_to_id: HashMap::new(), key_to_id: HashMap::new(),
} }
} }
/// Get ID, tries to parse UUID /// Tries to get an ID by first parsing the key as a UUID,
pub fn get_or_parse_id(&mut self, key: &str) -> Uuid { /// and if that fails, looking it up in the internal map.
pub fn get_or_parse_id(&self, key: &str) -> Result<Uuid, AppError> {
// First, try to parse the key as a UUID.
if let Ok(parsed_uuid) = Uuid::parse_str(key) { if let Ok(parsed_uuid) = Uuid::parse_str(key) {
parsed_uuid return Ok(parsed_uuid);
} else {
*self.key_to_id.get(key).unwrap()
} }
// If parsing fails, look it up in the map.
self.key_to_id
.get(key)
.map(|id| *id) // Dereference the &Uuid to get Uuid
// If `get` returned None, create and return an error.
.ok_or_else(|| {
AppError::GraphMapper(format!(
"Key '{}' is not a valid UUID and was not found in the map.",
key
))
})
} }
/// Assigns a new UUID for a given key. /// Assigns a new UUID for a given key. (No changes needed here)
pub fn assign_id(&mut self, key: &str) -> Uuid { pub fn assign_id(&mut self, key: &str) -> Uuid {
let id = Uuid::new_v4(); let id = Uuid::new_v4();
self.key_to_id.insert(key.to_string(), id); self.key_to_id.insert(key.to_string(), id);
id id
} }
/// Retrieves the UUID for a given key. /// Retrieves the UUID for a given key, returning a Result for consistency.
pub fn get_id(&self, key: &str) -> Option<&Uuid> { pub fn get_id(&self, key: &str) -> Result<Uuid, AppError> {
self.key_to_id.get(key) self.key_to_id
.get(key)
.map(|id| *id)
.ok_or_else(|| AppError::GraphMapper(format!("Key '{}' not found in map.", key)))
} }
} }