use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use super::node::NodeId;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum EdgeType {
HasAttribute,
InheritsFrom,
DependsOn,
SimilarTo,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StateEdge {
pub source_episode: Uuid,
pub target_node: NodeId,
pub edge_type: EdgeType,
pub strength: f32,
pub created_at: DateTime<Utc>,
pub metadata: EdgeMetadata,
}
fn clamp_confidence_val(val: f32) -> f32 {
val.clamp(0.0, 1.0)
}
fn deserialize_confidence<'de, D>(deserializer: D) -> Result<f32, D::Error>
where
D: serde::Deserializer<'de>,
{
let val = f32::deserialize(deserializer)?;
Ok(clamp_confidence_val(val))
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct EdgeMetadata {
pub source_field: Option<String>,
pub is_primary: bool,
#[serde(deserialize_with = "deserialize_confidence")]
pub confidence: f32,
}
impl EdgeMetadata {
pub fn set_confidence(&mut self, confidence: f32) {
self.confidence = clamp_confidence_val(confidence);
}
}
impl StateEdge {
#[must_use]
pub fn new(source_episode: Uuid, target_node: NodeId, edge_type: EdgeType) -> Self {
Self {
source_episode,
target_node,
edge_type,
strength: 1.0,
created_at: Utc::now(),
metadata: EdgeMetadata::default(),
}
}
#[must_use]
pub fn attribute(source_episode: Uuid, target_node: NodeId, source_field: String) -> Self {
Self {
source_episode,
target_node,
edge_type: EdgeType::HasAttribute,
strength: 1.0,
created_at: Utc::now(),
metadata: EdgeMetadata {
source_field: Some(source_field),
is_primary: true,
confidence: 1.0,
},
}
}
pub fn set_strength(&mut self, strength: f32) {
self.strength = strength.clamp(0.0, 1.0);
}
pub fn set_primary(&mut self, is_primary: bool) {
self.metadata.is_primary = is_primary;
}
#[must_use]
pub fn is_primary(&self) -> bool {
self.metadata.is_primary
}
#[must_use]
pub fn source_field(&self) -> Option<&str> {
self.metadata.source_field.as_deref()
}
#[must_use]
pub fn estimated_tokens(&self) -> usize {
3
}
}
impl PartialEq for StateEdge {
fn eq(&self, other: &Self) -> bool {
self.source_episode == other.source_episode
&& self.target_node == other.target_node
&& self.edge_type == other.edge_type
}
}
impl Eq for StateEdge {}
impl std::hash::Hash for StateEdge {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.source_episode.hash(state);
self.target_node.hash(state);
self.edge_type.hash(state);
}
}