use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum DocumentStructureType {
Academic,
Technical,
Narrative,
Argumentative,
Expository,
Descriptive,
Report,
BlogPost,
Unknown,
}
impl Default for DocumentStructureType {
fn default() -> Self {
DocumentStructureType::Unknown
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum HierarchicalLevel {
Document,
Chapter,
Section,
Subsection,
Paragraph,
Sentence,
Phrase,
}
impl Default for HierarchicalLevel {
fn default() -> Self {
HierarchicalLevel::Paragraph
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum DiscoursePatternType {
ProblemSolution,
CauseEffect,
CompareContrast,
Chronological,
Spatial,
Classification,
Definition,
Process,
Mixed,
}
impl Default for DiscoursePatternType {
fn default() -> Self {
DiscoursePatternType::Mixed
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum StructuralMarkerType {
Introduction,
Transition,
Conclusion,
Enumeration,
Example,
Emphasis,
Reference,
Section,
}
impl Default for StructuralMarkerType {
fn default() -> Self {
StructuralMarkerType::Transition
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StructuralCoherenceConfig {
pub general: GeneralAnalysisConfig,
pub hierarchical: HierarchicalAnalysisConfig,
pub discourse: DiscoursePatternConfig,
pub markers: StructuralMarkerConfig,
pub boundaries: BoundaryDetectionConfig,
pub coherence: CoherenceCalculationConfig,
pub advanced: AdvancedAnalysisConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GeneralAnalysisConfig {
pub structural_weight: f64,
pub min_paragraph_length: usize,
pub expected_structure_type: Option<DocumentStructureType>,
pub consistency_sensitivity: f64,
pub use_comprehensive_analysis: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HierarchicalAnalysisConfig {
pub enable_analysis: bool,
pub max_depth: usize,
pub balance_threshold: f64,
pub transition_sensitivity: f64,
pub generate_structural_tree: bool,
pub min_level_confidence: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiscoursePatternConfig {
pub enable_detection: bool,
pub detection_sensitivity: f64,
pub min_pattern_strength: f64,
pub analyze_transitions: bool,
pub completeness_threshold: f64,
pub max_patterns_per_document: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StructuralMarkerConfig {
pub enable_analysis: bool,
pub detection_sensitivity: f64,
pub analyze_effectiveness: bool,
pub density_threshold: f64,
pub detect_missing_markers: bool,
pub custom_markers: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BoundaryDetectionConfig {
pub enable_detection: bool,
pub strength_threshold: f64,
pub extract_titles: bool,
pub title_confidence_threshold: f64,
pub max_detection_depth: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoherenceCalculationConfig {
pub paragraph_threshold: f64,
pub section_threshold: f64,
pub transition_threshold: f64,
pub enable_semantic_continuity: bool,
pub lexical_overlap_weight: f64,
pub structural_continuity_weight: f64,
pub semantic_continuity_weight: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdvancedAnalysisConfig {
pub enable_advanced_analysis: bool,
pub analyze_global_coherence: bool,
pub analyze_rhetorical_structure: bool,
pub analyze_completeness: bool,
pub analyze_complexity: bool,
pub analysis_depth: usize,
}
impl Default for StructuralCoherenceConfig {
fn default() -> Self {
Self {
general: GeneralAnalysisConfig::default(),
hierarchical: HierarchicalAnalysisConfig::default(),
discourse: DiscoursePatternConfig::default(),
markers: StructuralMarkerConfig::default(),
boundaries: BoundaryDetectionConfig::default(),
coherence: CoherenceCalculationConfig::default(),
advanced: AdvancedAnalysisConfig::default(),
}
}
}
impl Default for GeneralAnalysisConfig {
fn default() -> Self {
Self {
structural_weight: 0.3,
min_paragraph_length: 50,
expected_structure_type: None,
consistency_sensitivity: 0.7,
use_comprehensive_analysis: true,
}
}
}
impl Default for HierarchicalAnalysisConfig {
fn default() -> Self {
Self {
enable_analysis: true,
max_depth: 6,
balance_threshold: 0.5,
transition_sensitivity: 0.7,
generate_structural_tree: true,
min_level_confidence: 0.6,
}
}
}
impl Default for DiscoursePatternConfig {
fn default() -> Self {
Self {
enable_detection: true,
detection_sensitivity: 0.7,
min_pattern_strength: 0.5,
analyze_transitions: true,
completeness_threshold: 0.6,
max_patterns_per_document: 10,
}
}
}
impl Default for StructuralMarkerConfig {
fn default() -> Self {
Self {
enable_analysis: true,
detection_sensitivity: 0.6,
analyze_effectiveness: true,
density_threshold: 0.1,
detect_missing_markers: true,
custom_markers: Vec::new(),
}
}
}
impl Default for BoundaryDetectionConfig {
fn default() -> Self {
Self {
enable_detection: true,
strength_threshold: 0.5,
extract_titles: true,
title_confidence_threshold: 0.7,
max_detection_depth: 4,
}
}
}
impl Default for CoherenceCalculationConfig {
fn default() -> Self {
Self {
paragraph_threshold: 0.5,
section_threshold: 0.6,
transition_threshold: 0.4,
enable_semantic_continuity: true,
lexical_overlap_weight: 0.4,
structural_continuity_weight: 0.3,
semantic_continuity_weight: 0.3,
}
}
}
impl Default for AdvancedAnalysisConfig {
fn default() -> Self {
Self {
enable_advanced_analysis: true,
analyze_global_coherence: true,
analyze_rhetorical_structure: true,
analyze_completeness: true,
analyze_complexity: true,
analysis_depth: 3,
}
}
}
pub struct StructuralCoherenceConfigBuilder {
config: StructuralCoherenceConfig,
}
impl StructuralCoherenceConfigBuilder {
pub fn new() -> Self {
Self {
config: StructuralCoherenceConfig::default(),
}
}
pub fn structural_weight(mut self, weight: f64) -> Self {
self.config.general.structural_weight = weight;
self
}
pub fn min_paragraph_length(mut self, length: usize) -> Self {
self.config.general.min_paragraph_length = length;
self
}
pub fn expected_structure_type(mut self, structure_type: DocumentStructureType) -> Self {
self.config.general.expected_structure_type = Some(structure_type);
self
}
pub fn enable_hierarchical_analysis(mut self, enable: bool) -> Self {
self.config.hierarchical.enable_analysis = enable;
self
}
pub fn hierarchical_depth(mut self, depth: usize) -> Self {
self.config.hierarchical.max_depth = depth;
self
}
pub fn enable_discourse_patterns(mut self, enable: bool) -> Self {
self.config.discourse.enable_detection = enable;
self
}
pub fn discourse_sensitivity(mut self, sensitivity: f64) -> Self {
self.config.discourse.detection_sensitivity = sensitivity;
self
}
pub fn enable_structural_markers(mut self, enable: bool) -> Self {
self.config.markers.enable_analysis = enable;
self
}
pub fn enable_boundary_detection(mut self, enable: bool) -> Self {
self.config.boundaries.enable_detection = enable;
self
}
pub fn paragraph_threshold(mut self, threshold: f64) -> Self {
self.config.coherence.paragraph_threshold = threshold;
self
}
pub fn enable_advanced_analysis(mut self, enable: bool) -> Self {
self.config.advanced.enable_advanced_analysis = enable;
self
}
pub fn use_comprehensive_analysis(mut self, use_comprehensive: bool) -> Self {
self.config.general.use_comprehensive_analysis = use_comprehensive;
self
}
pub fn build(self) -> StructuralCoherenceConfig {
self.config
}
}
impl Default for StructuralCoherenceConfigBuilder {
fn default() -> Self {
Self::new()
}
}
impl StructuralCoherenceConfig {
pub fn builder() -> StructuralCoherenceConfigBuilder {
StructuralCoherenceConfigBuilder::new()
}
pub fn for_academic_paper() -> Self {
Self::builder()
.expected_structure_type(DocumentStructureType::Academic)
.enable_hierarchical_analysis(true)
.hierarchical_depth(6)
.enable_discourse_patterns(true)
.discourse_sensitivity(0.8)
.enable_structural_markers(true)
.enable_boundary_detection(true)
.enable_advanced_analysis(true)
.build()
}
pub fn for_technical_document() -> Self {
Self::builder()
.expected_structure_type(DocumentStructureType::Technical)
.enable_hierarchical_analysis(true)
.hierarchical_depth(8)
.enable_discourse_patterns(true)
.enable_structural_markers(true)
.enable_boundary_detection(true)
.paragraph_threshold(0.6)
.build()
}
pub fn for_narrative() -> Self {
Self::builder()
.expected_structure_type(DocumentStructureType::Narrative)
.enable_hierarchical_analysis(false)
.enable_discourse_patterns(true)
.discourse_sensitivity(0.6)
.enable_structural_markers(false)
.paragraph_threshold(0.4)
.build()
}
pub fn lightweight() -> Self {
Self::builder()
.enable_hierarchical_analysis(false)
.enable_discourse_patterns(false)
.enable_structural_markers(false)
.enable_boundary_detection(false)
.enable_advanced_analysis(false)
.use_comprehensive_analysis(false)
.build()
}
pub fn validate(&self) -> Result<(), String> {
if self.general.structural_weight < 0.0 || self.general.structural_weight > 1.0 {
return Err("Structural weight must be between 0.0 and 1.0".to_string());
}
if self.general.min_paragraph_length == 0 {
return Err("Minimum paragraph length must be greater than 0".to_string());
}
if self.hierarchical.max_depth == 0 {
return Err("Maximum hierarchical depth must be greater than 0".to_string());
}
if self.coherence.paragraph_threshold < 0.0 || self.coherence.paragraph_threshold > 1.0 {
return Err("Paragraph threshold must be between 0.0 and 1.0".to_string());
}
let weight_sum = self.coherence.lexical_overlap_weight
+ self.coherence.structural_continuity_weight
+ self.coherence.semantic_continuity_weight;
if (weight_sum - 1.0).abs() > 0.01 {
return Err("Coherence calculation weights should sum to 1.0".to_string());
}
Ok(())
}
}