use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use super::config::{CoherenceRelationType, FocusType, InconsistencyType};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SemanticFluencyResult {
pub overall_score: f64,
pub semantic_coherence: f64,
pub meaning_preservation: f64,
pub conceptual_clarity: f64,
pub semantic_appropriateness: f64,
pub context_sensitivity: f64,
pub semantic_density: f64,
pub ambiguity_score: f64,
pub semantic_relations: HashMap<String, f64>,
pub advanced_metrics: Option<AdvancedSemanticMetrics>,
pub insights: Vec<String>,
pub component_scores: HashMap<String, f64>,
pub metadata: AnalysisMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdvancedSemanticMetrics {
pub field_coverage: SemanticFieldCoverage,
pub conceptual_complexity: ConceptualComplexity,
pub consistency_analysis: ConsistencyAnalysis,
pub topic_coherence: Option<TopicCoherence>,
pub semantic_roles: Option<SemanticRoleAnalysis>,
pub figurative_language: Option<FigurativeLanguageAnalysis>,
pub discourse_analysis: Option<DiscourseAnalysis>,
pub information_structure: Option<InformationStructure>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SemanticFieldCoverage {
pub overall_coverage: f64,
pub semantic_fields: HashMap<String, f64>,
pub distribution_evenness: f64,
pub transition_coherence: f64,
pub dominant_field: Option<String>,
pub diversity_index: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConceptualComplexity {
pub overall_complexity: f64,
pub conceptual_depth: f64,
pub conceptual_density: f64,
pub abstract_concept_ratio: f64,
pub complexity_distribution: ComplexityDistribution,
pub hierarchy_depth: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComplexityDistribution {
pub variance: f64,
pub peaks: Vec<usize>,
pub progression_pattern: String,
pub clustering_coefficient: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConsistencyAnalysis {
pub overall_consistency: f64,
pub terminological_consistency: f64,
pub conceptual_consistency: f64,
pub field_consistency: f64,
pub inconsistencies: Vec<InconsistencyPattern>,
pub consistency_trend: Vec<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InconsistencyPattern {
pub inconsistency_type: InconsistencyType,
pub severity: f64,
pub locations: Vec<(usize, usize)>,
pub description: String,
pub suggested_resolution: Option<String>,
pub confidence: f64,
pub related_terms: Vec<String>,
pub context_examples: Vec<String>,
pub coherence_impact: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TopicCoherence {
pub overall_coherence: f64,
pub topic_consistency: f64,
pub transition_smoothness: f64,
pub main_topics: Vec<Topic>,
pub topic_distribution: HashMap<String, f64>,
pub evolution_pattern: Vec<String>,
pub topic_relationships: HashMap<(String, String), f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Topic {
pub id: String,
pub label: String,
pub keywords: Vec<String>,
pub strength: f64,
pub coverage: f64,
pub coherence_score: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SemanticRoleAnalysis {
pub role_clarity: f64,
pub role_consistency: f64,
pub role_ambiguity: f64,
pub complex_structures: Vec<ComplexRoleStructure>,
pub role_distribution: HashMap<String, f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComplexRoleStructure {
pub structure_type: String,
pub complexity_score: f64,
pub participants: Vec<String>,
pub relationships: HashMap<String, String>,
pub clarity_score: f64,
pub examples: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FigurativeLanguageAnalysis {
pub figurative_density: f64,
pub metaphor_analysis: MetaphorAnalysis,
pub metonymy_count: usize,
pub synecdoche_count: usize,
pub irony_score: f64,
pub figurative_coherence: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetaphorAnalysis {
pub metaphor_count: usize,
pub consistency: f64,
pub conceptual_coherence: f64,
pub metaphors: Vec<MetaphorInstance>,
pub dominant_themes: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetaphorInstance {
pub source_domain: String,
pub target_domain: String,
pub text: String,
pub position: (usize, usize),
pub novelty: f64,
pub coherence: f64,
pub mapping_strength: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiscourseAnalysis {
pub coherence_relations: Vec<CoherenceRelation>,
pub marker_analysis: DiscourseMarkerAnalysis,
pub rhetorical_coherence: f64,
pub information_flow: f64,
pub discourse_structure: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoherenceRelation {
pub relation_type: CoherenceRelationType,
pub source_segment: (usize, usize),
pub target_segment: (usize, usize),
pub strength: f64,
pub confidence: f64,
pub explicit_markers: Vec<String>,
pub description: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiscourseMarkerAnalysis {
pub marker_frequency: HashMap<String, usize>,
pub appropriateness: f64,
pub diversity: f64,
pub missing_markers: Vec<String>,
pub overused_markers: Vec<String>,
pub placement_accuracy: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InformationStructure {
pub given_new_balance: f64,
pub topic_comment_clarity: f64,
pub focus_structure: FocusStructure,
pub density_distribution: Vec<f64>,
pub progression_coherence: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FocusStructure {
pub focus_clarity: f64,
pub focus_points: Vec<FocusPoint>,
pub transition_coherence: f64,
pub distribution_evenness: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FocusPoint {
pub focus_type: FocusType,
pub position: (usize, usize),
pub strength: f64,
pub focused_element: String,
pub appropriateness: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnalysisMetadata {
pub timestamp: String,
pub duration_seconds: f64,
pub config_hash: String,
pub text_stats: TextStatistics,
pub processing_stats: ProcessingStatistics,
pub version: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TextStatistics {
pub character_count: usize,
pub word_count: usize,
pub sentence_count: usize,
pub avg_sentence_length: f64,
pub vocabulary_size: usize,
pub type_token_ratio: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProcessingStatistics {
pub memory_usage_mb: f64,
pub cache_hit_rate: f64,
pub cache_misses: usize,
pub stages_completed: Vec<String>,
pub error_count: usize,
pub warning_count: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SemanticRelation {
pub source: String,
pub target: String,
pub relation_type: String,
pub strength: f64,
pub confidence: f64,
pub context: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SemanticNode {
pub id: String,
pub label: String,
pub centrality: f64,
pub semantic_field: Option<String>,
pub node_type: String,
pub frequency: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SemanticEdge {
pub source: String,
pub target: String,
pub weight: f64,
pub edge_type: String,
pub confidence: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SemanticNetwork {
pub nodes: Vec<SemanticNode>,
pub edges: Vec<SemanticEdge>,
pub density: f64,
pub diameter: usize,
pub clustering_coefficient: f64,
pub connected_components: usize,
}
impl SemanticFluencyResult {
pub fn new() -> Self {
Self {
overall_score: 0.0,
semantic_coherence: 0.0,
meaning_preservation: 0.0,
conceptual_clarity: 0.0,
semantic_appropriateness: 0.0,
context_sensitivity: 0.0,
semantic_density: 0.0,
ambiguity_score: 0.0,
semantic_relations: HashMap::new(),
advanced_metrics: None,
insights: Vec::new(),
component_scores: HashMap::new(),
metadata: AnalysisMetadata::default(),
}
}
pub fn calculate_overall_score(&mut self, weights: &HashMap<String, f64>) {
let mut weighted_sum = 0.0;
let mut total_weight = 0.0;
for (component, score) in &self.component_scores {
if let Some(&weight) = weights.get(component) {
weighted_sum += score * weight;
total_weight += weight;
}
}
self.overall_score = if total_weight > 0.0 {
weighted_sum / total_weight
} else {
0.0
};
}
pub fn add_insight(&mut self, insight: String) {
self.insights.push(insight);
}
pub fn get_top_insights(&self, n: usize) -> Vec<&String> {
self.insights.iter().take(n).collect()
}
pub fn has_advanced_metrics(&self) -> bool {
self.advanced_metrics.is_some()
}
pub fn get_relation_score(&self, relation_type: &str) -> Option<f64> {
self.semantic_relations.get(relation_type).copied()
}
}
impl Default for AnalysisMetadata {
fn default() -> Self {
Self {
timestamp: chrono::Utc::now().to_rfc3339(),
duration_seconds: 0.0,
config_hash: String::new(),
text_stats: TextStatistics::default(),
processing_stats: ProcessingStatistics::default(),
version: "1.0.0".to_string(),
}
}
}
impl Default for TextStatistics {
fn default() -> Self {
Self {
character_count: 0,
word_count: 0,
sentence_count: 0,
avg_sentence_length: 0.0,
vocabulary_size: 0,
type_token_ratio: 0.0,
}
}
}
impl Default for ProcessingStatistics {
fn default() -> Self {
Self {
memory_usage_mb: 0.0,
cache_hit_rate: 0.0,
cache_misses: 0,
stages_completed: Vec::new(),
error_count: 0,
warning_count: 0,
}
}
}
impl TextStatistics {
pub fn from_sentences(sentences: &[String]) -> Self {
let character_count = sentences.iter().map(|s| s.len()).sum();
let sentence_count = sentences.len();
let all_words: Vec<String> = sentences
.iter()
.flat_map(|s| s.split_whitespace())
.map(|w| w.to_lowercase())
.collect();
let word_count = all_words.len();
let vocabulary: std::collections::HashSet<&String> = all_words.iter().collect();
let vocabulary_size = vocabulary.len();
let avg_sentence_length = if sentence_count > 0 {
word_count as f64 / sentence_count as f64
} else {
0.0
};
let type_token_ratio = if word_count > 0 {
vocabulary_size as f64 / word_count as f64
} else {
0.0
};
Self {
character_count,
word_count,
sentence_count,
avg_sentence_length,
vocabulary_size,
type_token_ratio,
}
}
}
extern crate chrono;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_result_creation() {
let result = SemanticFluencyResult::new();
assert_eq!(result.overall_score, 0.0);
assert!(result.insights.is_empty());
assert!(!result.has_advanced_metrics());
}
#[test]
fn test_overall_score_calculation() {
let mut result = SemanticFluencyResult::new();
result.component_scores.insert("coherence".to_string(), 0.8);
result.component_scores.insert("meaning".to_string(), 0.7);
result.component_scores.insert("context".to_string(), 0.9);
let mut weights = HashMap::new();
weights.insert("coherence".to_string(), 0.4);
weights.insert("meaning".to_string(), 0.3);
weights.insert("context".to_string(), 0.3);
result.calculate_overall_score(&weights);
let expected = (0.8 * 0.4 + 0.7 * 0.3 + 0.9 * 0.3) / 1.0;
assert!((result.overall_score - expected).abs() < 0.001);
}
#[test]
fn test_insights_management() {
let mut result = SemanticFluencyResult::new();
result.add_insight("Good semantic coherence detected".to_string());
result.add_insight("Consider improving meaning clarity".to_string());
result.add_insight("Context sensitivity could be enhanced".to_string());
assert_eq!(result.insights.len(), 3);
let top_insights = result.get_top_insights(2);
assert_eq!(top_insights.len(), 2);
}
#[test]
fn test_text_statistics_calculation() {
let sentences = vec![
"This is a test sentence.".to_string(),
"Another sentence for testing.".to_string(),
"Final test sentence here.".to_string(),
];
let stats = TextStatistics::from_sentences(&sentences);
assert_eq!(stats.sentence_count, 3);
assert!(stats.word_count > 0);
assert!(stats.vocabulary_size > 0);
assert!(stats.type_token_ratio > 0.0 && stats.type_token_ratio <= 1.0);
assert!(stats.avg_sentence_length > 0.0);
}
#[test]
fn test_relation_score_retrieval() {
let mut result = SemanticFluencyResult::new();
result
.semantic_relations
.insert("synonymy".to_string(), 0.8);
result
.semantic_relations
.insert("antonymy".to_string(), 0.3);
assert_eq!(result.get_relation_score("synonymy"), Some(0.8));
assert_eq!(result.get_relation_score("antonymy"), Some(0.3));
assert_eq!(result.get_relation_score("hyponymy"), None);
}
#[test]
fn test_serialization() {
let result = SemanticFluencyResult::new();
let serialized = serde_json::to_string(&result);
assert!(serialized.is_ok());
let deserialized: Result<SemanticFluencyResult, _> =
serde_json::from_str(&serialized.expect("operation should succeed"));
assert!(deserialized.is_ok());
}
#[test]
fn test_advanced_metrics_detection() {
let mut result = SemanticFluencyResult::new();
assert!(!result.has_advanced_metrics());
result.advanced_metrics = Some(AdvancedSemanticMetrics {
field_coverage: SemanticFieldCoverage {
overall_coverage: 0.8,
semantic_fields: HashMap::new(),
distribution_evenness: 0.7,
transition_coherence: 0.9,
dominant_field: None,
diversity_index: 0.6,
},
conceptual_complexity: ConceptualComplexity {
overall_complexity: 0.5,
conceptual_depth: 0.6,
conceptual_density: 0.4,
abstract_concept_ratio: 0.3,
complexity_distribution: ComplexityDistribution {
variance: 0.2,
peaks: vec![1, 3, 5],
progression_pattern: "increasing".to_string(),
clustering_coefficient: 0.7,
},
hierarchy_depth: 3,
},
consistency_analysis: ConsistencyAnalysis {
overall_consistency: 0.8,
terminological_consistency: 0.9,
conceptual_consistency: 0.7,
field_consistency: 0.8,
inconsistencies: Vec::new(),
consistency_trend: vec![0.8, 0.7, 0.9],
},
topic_coherence: None,
semantic_roles: None,
figurative_language: None,
discourse_analysis: None,
information_structure: None,
});
assert!(result.has_advanced_metrics());
}
}