use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum DiscourseCoherenceError {
#[error("Empty text provided for discourse analysis")]
EmptyText,
#[error("Invalid discourse configuration: {0}")]
InvalidConfiguration(String),
#[error("Discourse marker analysis error: {0}")]
DiscourseMarkerError(String),
#[error("Rhetorical structure analysis error: {0}")]
RhetoricalStructureError(String),
#[error("Cohesion analysis error: {0}")]
CohesionAnalysisError(String),
#[error("Transition analysis failed: {0}")]
TransitionAnalysisError(String),
#[error("Discourse processing error: {0}")]
ProcessingError(String),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub enum DiscourseMarkerType {
Addition,
Contrast,
Cause,
Temporal,
Conditional,
Concession,
Elaboration,
Exemplification,
Summary,
Emphasis,
Comparison,
Alternative,
Reformulation,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum RhetoricalRelationType {
Elaboration,
Background,
Circumstance,
Solutionhood,
Enablement,
Motivation,
Evidence,
Justify,
Antithesis,
Concession,
Sequence,
Contrast,
Joint,
List,
Restatement,
Summary,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum CohesiveDeviceType {
PersonalPronoun,
Demonstrative,
Comparative,
Substitution,
Ellipsis,
Conjunction,
Repetition,
Synonymy,
Antonymy,
Hyponymy,
Meronymy,
Collocation,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum TransitionQuality {
Excellent,
Good,
Fair,
Poor,
VeryPoor,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiscourseCoherenceConfig {
pub general: GeneralDiscourseConfig,
pub markers: DiscourseMarkerConfig,
pub rhetorical: RhetoricalStructureConfig,
pub cohesion: CohesionAnalysisConfig,
pub transitions: TransitionAnalysisConfig,
pub information: InformationStructureConfig,
pub advanced: AdvancedAnalysisConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GeneralDiscourseConfig {
pub enable_caching: bool,
pub parallel_processing: bool,
pub detailed_metrics: bool,
pub min_sentence_length: usize,
pub max_analysis_depth: usize,
pub debug_output: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiscourseMarkerConfig {
pub enabled: bool,
pub analyze_multiword_markers: bool,
pub include_context_analysis: bool,
pub min_confidence_threshold: f64,
pub context_window_size: usize,
pub marker_weights: HashMap<DiscourseMarkerType, f64>,
pub custom_markers: HashMap<String, DiscourseMarkerType>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RhetoricalStructureConfig {
pub enabled: bool,
pub build_discourse_tree: bool,
pub max_tree_depth: usize,
pub min_relation_confidence: f64,
pub relation_weights: HashMap<RhetoricalRelationType, f64>,
pub nucleus_satellite_detection: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CohesionAnalysisConfig {
pub enabled: bool,
pub analyze_reference_cohesion: bool,
pub analyze_lexical_cohesion: bool,
pub analyze_conjunctive_cohesion: bool,
pub max_reference_distance: usize,
pub device_weights: HashMap<CohesiveDeviceType, f64>,
pub detect_ambiguous_references: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransitionAnalysisConfig {
pub enabled: bool,
pub analyze_lexical_overlap: bool,
pub analyze_semantic_continuity: bool,
pub analyze_structural_continuity: bool,
pub lexical_overlap_weight: f64,
pub semantic_continuity_weight: f64,
pub structural_continuity_weight: f64,
pub transition_marker_weight: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InformationStructureConfig {
pub enabled: bool,
pub analyze_given_new_balance: bool,
pub analyze_topic_focus: bool,
pub analyze_thematic_progression: bool,
pub calculate_information_density: bool,
pub analyze_information_packaging: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdvancedAnalysisConfig {
pub enabled: bool,
pub cognitive_analysis: bool,
pub genre_analysis: bool,
pub information_theoretic_measures: bool,
pub build_coherence_networks: bool,
pub temporal_coherence_analysis: bool,
}
impl Default for DiscourseCoherenceConfig {
fn default() -> Self {
Self {
general: GeneralDiscourseConfig::default(),
markers: DiscourseMarkerConfig::default(),
rhetorical: RhetoricalStructureConfig::default(),
cohesion: CohesionAnalysisConfig::default(),
transitions: TransitionAnalysisConfig::default(),
information: InformationStructureConfig::default(),
advanced: AdvancedAnalysisConfig::default(),
}
}
}
impl Default for GeneralDiscourseConfig {
fn default() -> Self {
Self {
enable_caching: true,
parallel_processing: true,
detailed_metrics: false,
min_sentence_length: 3,
max_analysis_depth: 10,
debug_output: false,
}
}
}
impl Default for DiscourseMarkerConfig {
fn default() -> Self {
Self {
enabled: true,
analyze_multiword_markers: true,
include_context_analysis: true,
min_confidence_threshold: 0.5,
context_window_size: 3,
marker_weights: Self::default_marker_weights(),
custom_markers: HashMap::new(),
}
}
}
impl DiscourseMarkerConfig {
fn default_marker_weights() -> HashMap<DiscourseMarkerType, f64> {
let mut weights = HashMap::new();
weights.insert(DiscourseMarkerType::Addition, 1.0);
weights.insert(DiscourseMarkerType::Contrast, 1.2);
weights.insert(DiscourseMarkerType::Cause, 1.3);
weights.insert(DiscourseMarkerType::Temporal, 1.1);
weights.insert(DiscourseMarkerType::Conditional, 1.2);
weights.insert(DiscourseMarkerType::Concession, 1.4);
weights.insert(DiscourseMarkerType::Elaboration, 1.0);
weights.insert(DiscourseMarkerType::Exemplification, 1.1);
weights.insert(DiscourseMarkerType::Summary, 1.3);
weights.insert(DiscourseMarkerType::Emphasis, 1.1);
weights.insert(DiscourseMarkerType::Comparison, 1.2);
weights.insert(DiscourseMarkerType::Alternative, 1.1);
weights.insert(DiscourseMarkerType::Reformulation, 1.2);
weights
}
}
impl Default for RhetoricalStructureConfig {
fn default() -> Self {
Self {
enabled: true,
build_discourse_tree: false,
max_tree_depth: 5,
min_relation_confidence: 0.6,
relation_weights: Self::default_relation_weights(),
nucleus_satellite_detection: false,
}
}
}
impl RhetoricalStructureConfig {
fn default_relation_weights() -> HashMap<RhetoricalRelationType, f64> {
let mut weights = HashMap::new();
weights.insert(RhetoricalRelationType::Elaboration, 1.0);
weights.insert(RhetoricalRelationType::Background, 1.1);
weights.insert(RhetoricalRelationType::Circumstance, 1.0);
weights.insert(RhetoricalRelationType::Solutionhood, 1.3);
weights.insert(RhetoricalRelationType::Enablement, 1.2);
weights.insert(RhetoricalRelationType::Motivation, 1.2);
weights.insert(RhetoricalRelationType::Evidence, 1.4);
weights.insert(RhetoricalRelationType::Justify, 1.3);
weights.insert(RhetoricalRelationType::Antithesis, 1.4);
weights.insert(RhetoricalRelationType::Concession, 1.3);
weights.insert(RhetoricalRelationType::Sequence, 1.1);
weights.insert(RhetoricalRelationType::Contrast, 1.2);
weights.insert(RhetoricalRelationType::Joint, 0.9);
weights.insert(RhetoricalRelationType::List, 0.8);
weights.insert(RhetoricalRelationType::Restatement, 1.0);
weights.insert(RhetoricalRelationType::Summary, 1.2);
weights
}
}
impl Default for CohesionAnalysisConfig {
fn default() -> Self {
Self {
enabled: true,
analyze_reference_cohesion: true,
analyze_lexical_cohesion: true,
analyze_conjunctive_cohesion: true,
max_reference_distance: 5,
device_weights: Self::default_device_weights(),
detect_ambiguous_references: true,
}
}
}
impl CohesionAnalysisConfig {
fn default_device_weights() -> HashMap<CohesiveDeviceType, f64> {
let mut weights = HashMap::new();
weights.insert(CohesiveDeviceType::PersonalPronoun, 1.2);
weights.insert(CohesiveDeviceType::Demonstrative, 1.3);
weights.insert(CohesiveDeviceType::Comparative, 1.1);
weights.insert(CohesiveDeviceType::Substitution, 1.0);
weights.insert(CohesiveDeviceType::Ellipsis, 0.9);
weights.insert(CohesiveDeviceType::Conjunction, 1.4);
weights.insert(CohesiveDeviceType::Repetition, 0.8);
weights.insert(CohesiveDeviceType::Synonymy, 1.2);
weights.insert(CohesiveDeviceType::Antonymy, 1.1);
weights.insert(CohesiveDeviceType::Hyponymy, 1.3);
weights.insert(CohesiveDeviceType::Meronymy, 1.2);
weights.insert(CohesiveDeviceType::Collocation, 1.0);
weights
}
}
impl Default for TransitionAnalysisConfig {
fn default() -> Self {
Self {
enabled: true,
analyze_lexical_overlap: true,
analyze_semantic_continuity: true,
analyze_structural_continuity: true,
lexical_overlap_weight: 0.3,
semantic_continuity_weight: 0.4,
structural_continuity_weight: 0.2,
transition_marker_weight: 0.1,
}
}
}
impl Default for InformationStructureConfig {
fn default() -> Self {
Self {
enabled: true,
analyze_given_new_balance: true,
analyze_topic_focus: true,
analyze_thematic_progression: true,
calculate_information_density: true,
analyze_information_packaging: true,
}
}
}
impl Default for AdvancedAnalysisConfig {
fn default() -> Self {
Self {
enabled: false,
cognitive_analysis: false,
genre_analysis: false,
information_theoretic_measures: false,
build_coherence_networks: false,
temporal_coherence_analysis: false,
}
}
}
impl DiscourseCoherenceConfig {
pub fn minimal() -> Self {
Self {
general: GeneralDiscourseConfig {
enable_caching: false,
parallel_processing: false,
detailed_metrics: false,
min_sentence_length: 1,
max_analysis_depth: 3,
debug_output: false,
},
markers: DiscourseMarkerConfig {
enabled: true,
analyze_multiword_markers: false,
include_context_analysis: false,
min_confidence_threshold: 0.7,
context_window_size: 1,
marker_weights: DiscourseMarkerConfig::default_marker_weights(),
custom_markers: HashMap::new(),
},
rhetorical: RhetoricalStructureConfig {
enabled: false,
build_discourse_tree: false,
max_tree_depth: 2,
min_relation_confidence: 0.8,
relation_weights: RhetoricalStructureConfig::default_relation_weights(),
nucleus_satellite_detection: false,
},
cohesion: CohesionAnalysisConfig {
enabled: true,
analyze_reference_cohesion: true,
analyze_lexical_cohesion: false,
analyze_conjunctive_cohesion: false,
max_reference_distance: 3,
device_weights: CohesionAnalysisConfig::default_device_weights(),
detect_ambiguous_references: false,
},
transitions: TransitionAnalysisConfig {
enabled: true,
analyze_lexical_overlap: true,
analyze_semantic_continuity: false,
analyze_structural_continuity: false,
lexical_overlap_weight: 1.0,
semantic_continuity_weight: 0.0,
structural_continuity_weight: 0.0,
transition_marker_weight: 0.0,
},
information: InformationStructureConfig {
enabled: false,
analyze_given_new_balance: false,
analyze_topic_focus: false,
analyze_thematic_progression: false,
calculate_information_density: false,
analyze_information_packaging: false,
},
advanced: AdvancedAnalysisConfig {
enabled: false,
cognitive_analysis: false,
genre_analysis: false,
information_theoretic_measures: false,
build_coherence_networks: false,
temporal_coherence_analysis: false,
},
}
}
pub fn comprehensive() -> Self {
Self {
general: GeneralDiscourseConfig {
enable_caching: true,
parallel_processing: true,
detailed_metrics: true,
min_sentence_length: 1,
max_analysis_depth: 15,
debug_output: false,
},
markers: DiscourseMarkerConfig {
enabled: true,
analyze_multiword_markers: true,
include_context_analysis: true,
min_confidence_threshold: 0.3,
context_window_size: 5,
marker_weights: DiscourseMarkerConfig::default_marker_weights(),
custom_markers: HashMap::new(),
},
rhetorical: RhetoricalStructureConfig {
enabled: true,
build_discourse_tree: true,
max_tree_depth: 10,
min_relation_confidence: 0.4,
relation_weights: RhetoricalStructureConfig::default_relation_weights(),
nucleus_satellite_detection: true,
},
cohesion: CohesionAnalysisConfig {
enabled: true,
analyze_reference_cohesion: true,
analyze_lexical_cohesion: true,
analyze_conjunctive_cohesion: true,
max_reference_distance: 10,
device_weights: CohesionAnalysisConfig::default_device_weights(),
detect_ambiguous_references: true,
},
transitions: TransitionAnalysisConfig {
enabled: true,
analyze_lexical_overlap: true,
analyze_semantic_continuity: true,
analyze_structural_continuity: true,
lexical_overlap_weight: 0.3,
semantic_continuity_weight: 0.4,
structural_continuity_weight: 0.2,
transition_marker_weight: 0.1,
},
information: InformationStructureConfig {
enabled: true,
analyze_given_new_balance: true,
analyze_topic_focus: true,
analyze_thematic_progression: true,
calculate_information_density: true,
analyze_information_packaging: true,
},
advanced: AdvancedAnalysisConfig {
enabled: true,
cognitive_analysis: true,
genre_analysis: true,
information_theoretic_measures: true,
build_coherence_networks: true,
temporal_coherence_analysis: true,
},
}
}
pub fn for_academic_papers() -> Self {
let mut config = Self::comprehensive();
config.rhetorical.enabled = true;
config.rhetorical.build_discourse_tree = true;
config.rhetorical.min_relation_confidence = 0.5;
config.markers.analyze_multiword_markers = true;
config.markers.min_confidence_threshold = 0.4;
config.cohesion.analyze_lexical_cohesion = true;
config.cohesion.max_reference_distance = 8;
config.advanced.enabled = true;
config.advanced.genre_analysis = true;
config
}
pub fn for_narratives() -> Self {
let mut config = Self::default();
config.advanced.temporal_coherence_analysis = true;
config.cohesion.analyze_reference_cohesion = true;
config.cohesion.max_reference_distance = 10;
config
.markers
.marker_weights
.insert(DiscourseMarkerType::Temporal, 1.5);
config.information.enabled = false;
config
}
pub fn for_technical_docs() -> Self {
let mut config = Self::default();
config.rhetorical.enabled = true;
config.rhetorical.build_discourse_tree = false;
config.transitions.analyze_structural_continuity = true;
config.cohesion.analyze_lexical_cohesion = true;
config.information.analyze_information_packaging = true;
config
}
pub fn builder() -> DiscourseCoherenceConfigBuilder {
DiscourseCoherenceConfigBuilder::new()
}
}
pub struct DiscourseCoherenceConfigBuilder {
config: DiscourseCoherenceConfig,
}
impl DiscourseCoherenceConfigBuilder {
pub fn new() -> Self {
Self {
config: DiscourseCoherenceConfig::default(),
}
}
pub fn general_config(mut self, general: GeneralDiscourseConfig) -> Self {
self.config.general = general;
self
}
pub fn marker_config(mut self, markers: DiscourseMarkerConfig) -> Self {
self.config.markers = markers;
self
}
pub fn rhetorical_config(mut self, rhetorical: RhetoricalStructureConfig) -> Self {
self.config.rhetorical = rhetorical;
self
}
pub fn cohesion_config(mut self, cohesion: CohesionAnalysisConfig) -> Self {
self.config.cohesion = cohesion;
self
}
pub fn transition_config(mut self, transitions: TransitionAnalysisConfig) -> Self {
self.config.transitions = transitions;
self
}
pub fn information_config(mut self, information: InformationStructureConfig) -> Self {
self.config.information = information;
self
}
pub fn advanced_config(mut self, advanced: AdvancedAnalysisConfig) -> Self {
self.config.advanced = advanced;
self
}
pub fn build(self) -> DiscourseCoherenceConfig {
self.config
}
}