use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum TopicTransitionType {
Smooth,
Gradual,
Abrupt,
Return,
Branching,
Merging,
Elaboration,
Digression,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ThematicProgressionPattern {
Linear,
Spiral,
Hierarchical,
Circular,
TreeBranching,
Network,
Fragmented,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DevelopmentStage {
pub stage_name: String,
pub span: (usize, usize),
pub characteristics: Vec<String>,
pub intensity: f64,
pub duration_ratio: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TopicEvolution {
pub evolution_pattern: String,
pub intensity_trajectory: Vec<f64>,
pub development_stages: Vec<DevelopmentStage>,
pub peak_position: usize,
pub consistency_score: f64,
pub lifespan_ratio: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConceptualCluster {
pub cluster_name: String,
pub words: Vec<String>,
pub coherence: f64,
pub centrality: f64,
pub semantic_weight: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SemanticProfile {
pub semantic_fields: Vec<String>,
pub conceptual_clusters: Vec<ConceptualCluster>,
pub semantic_coherence: f64,
pub abstractness_level: f64,
pub semantic_diversity: f64,
pub conceptual_density: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TopicQualityMetrics {
pub internal_coherence: f64,
pub distinctiveness: f64,
pub focus: f64,
pub coverage: f64,
pub stability: f64,
pub interpretability: f64,
pub complexity: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TopicRelationship {
pub related_topic_id: String,
pub relationship_type: String,
pub strength: f64,
pub confidence: f64,
pub directionality: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Topic {
pub topic_id: String,
pub keywords: Vec<String>,
pub coherence_score: f64,
pub span: (usize, usize),
pub prominence: f64,
pub density: f64,
pub evolution: TopicEvolution,
pub semantic_profile: SemanticProfile,
pub quality_metrics: TopicQualityMetrics,
pub hierarchical_level: usize,
pub relationships: Vec<TopicRelationship>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TopicTransition {
pub from_topic: String,
pub to_topic: String,
pub position: usize,
pub transition_quality: f64,
pub transition_type: TopicTransitionType,
pub smoothness: f64,
pub bridging_elements: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DetailedTopicMetrics {
pub average_topic_coherence: f64,
pub topic_coherence_variance: f64,
pub average_transition_quality: f64,
pub high_quality_transitions: usize,
pub topic_coverage_ratio: f64,
pub average_topic_lifespan: f64,
pub topic_overlap_ratio: f64,
pub semantic_diversity: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TopicRelationshipAnalysis {
pub network_density: f64,
pub central_topics: Vec<String>,
pub topic_clusters: Vec<Vec<String>>,
pub average_relationship_strength: f64,
pub relationship_types_count: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdvancedTopicAnalysis {
pub hierarchical_structure: HashMap<String, Vec<String>>,
pub dynamic_patterns: Vec<String>,
pub network_characteristics: HashMap<String, f64>,
pub progression_pattern: ThematicProgressionPattern,
pub temporal_dynamics: Vec<f64>,
pub cross_topic_influences: HashMap<String, HashMap<String, f64>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TopicCoherenceResult {
pub topic_consistency: f64,
pub topic_shift_coherence: f64,
pub topic_development: f64,
pub thematic_unity: f64,
pub topics: Vec<Topic>,
pub topic_transitions: Vec<TopicTransition>,
pub topic_distribution: HashMap<String, f64>,
pub coherence_per_topic: HashMap<String, f64>,
pub detailed_metrics: DetailedTopicMetrics,
pub topic_relationships: TopicRelationshipAnalysis,
pub advanced_analysis: Option<AdvancedTopicAnalysis>,
pub analysis_metadata: AnalysisMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnalysisMetadata {
pub config_summary: String,
pub text_length: usize,
pub sentences_processed: usize,
pub analysis_duration_ms: u64,
pub timestamp: String,
pub analysis_version: String,
}
impl TopicCoherenceResult {
pub fn new() -> Self {
Self {
topic_consistency: 0.0,
topic_shift_coherence: 0.0,
topic_development: 0.0,
thematic_unity: 0.0,
topics: Vec::new(),
topic_transitions: Vec::new(),
topic_distribution: HashMap::new(),
coherence_per_topic: HashMap::new(),
detailed_metrics: DetailedTopicMetrics {
average_topic_coherence: 0.0,
topic_coherence_variance: 0.0,
average_transition_quality: 0.0,
high_quality_transitions: 0,
topic_coverage_ratio: 0.0,
average_topic_lifespan: 0.0,
topic_overlap_ratio: 0.0,
semantic_diversity: 0.0,
},
topic_relationships: TopicRelationshipAnalysis {
network_density: 0.0,
central_topics: Vec::new(),
topic_clusters: Vec::new(),
average_relationship_strength: 0.0,
relationship_types_count: 0,
},
advanced_analysis: None,
analysis_metadata: AnalysisMetadata {
config_summary: String::new(),
text_length: 0,
sentences_processed: 0,
analysis_duration_ms: 0,
timestamp: String::new(),
analysis_version: "2.0.0".to_string(),
},
}
}
pub fn overall_quality_score(&self) -> f64 {
(self.topic_consistency
+ self.topic_shift_coherence
+ self.topic_development
+ self.thematic_unity)
/ 4.0
}
pub fn topic_summary(&self) -> HashMap<String, f64> {
let mut summary = HashMap::new();
summary.insert("total_topics".to_string(), self.topics.len() as f64);
summary.insert(
"total_transitions".to_string(),
self.topic_transitions.len() as f64,
);
summary.insert(
"average_coherence".to_string(),
self.coherence_per_topic.values().sum::<f64>() / self.coherence_per_topic.len() as f64,
);
if !self.topics.is_empty() {
let avg_prominence =
self.topics.iter().map(|t| t.prominence).sum::<f64>() / self.topics.len() as f64;
summary.insert("average_prominence".to_string(), avg_prominence);
}
summary
}
}
impl Default for TopicCoherenceResult {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_result_creation() {
let result = TopicCoherenceResult::new();
assert_eq!(result.topics.len(), 0);
assert_eq!(result.topic_transitions.len(), 0);
assert_eq!(result.overall_quality_score(), 0.0);
}
#[test]
fn test_overall_quality_calculation() {
let mut result = TopicCoherenceResult::new();
result.topic_consistency = 0.8;
result.topic_shift_coherence = 0.7;
result.topic_development = 0.6;
result.thematic_unity = 0.9;
assert_eq!(result.overall_quality_score(), 0.75);
}
#[test]
fn test_result_serialization() {
let result = TopicCoherenceResult::new();
let serialized = serde_json::to_string(&result).expect("Should serialize");
let deserialized: TopicCoherenceResult =
serde_json::from_str(&serialized).expect("Should deserialize");
assert_eq!(result.topics.len(), deserialized.topics.len());
assert_eq!(
result.overall_quality_score(),
deserialized.overall_quality_score()
);
}
}