ReadabilityAnalysisServiceImpl.java
package com.kapil.verbametrics.services.impl;
import com.kapil.verbametrics.domain.ReadabilityMetrics;
import com.kapil.verbametrics.services.ReadabilityAnalysisService;
import com.kapil.verbametrics.services.calculators.FleschKincaidCalculator;
import com.kapil.verbametrics.services.calculators.FleschReadingEaseCalculator;
import com.kapil.verbametrics.services.calculators.SentenceLengthCalculator;
import com.kapil.verbametrics.services.calculators.SyllablePerWordCalculator;
import com.kapil.verbametrics.services.classifiers.ComplexityClassifier;
import com.kapil.verbametrics.services.classifiers.ReadingLevelClassifier;
import com.kapil.verbametrics.util.VerbaMetricsConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Objects;
/**
* Implementation of ReadabilityAnalysisService using various calculators and classifiers.
* Provides functionality to analyze text and return readability metrics.
*
* @author Kapil Garg
*/
@Service
public class ReadabilityAnalysisServiceImpl implements ReadabilityAnalysisService {
private static final Logger LOGGER = LoggerFactory.getLogger(ReadabilityAnalysisServiceImpl.class);
private final SentenceLengthCalculator sentenceLengthCalculator;
private final SyllablePerWordCalculator syllablePerWordCalculator;
private final FleschKincaidCalculator fleschKincaidCalculator;
private final FleschReadingEaseCalculator fleschReadingEaseCalculator;
private final ReadingLevelClassifier readingLevelClassifier;
private final ComplexityClassifier complexityClassifier;
@Autowired
public ReadabilityAnalysisServiceImpl(SentenceLengthCalculator sentenceLengthCalculator,
SyllablePerWordCalculator syllablePerWordCalculator,
FleschKincaidCalculator fleschKincaidCalculator,
FleschReadingEaseCalculator fleschReadingEaseCalculator,
ReadingLevelClassifier readingLevelClassifier,
ComplexityClassifier complexityClassifier) {
this.sentenceLengthCalculator = sentenceLengthCalculator;
this.syllablePerWordCalculator = syllablePerWordCalculator;
this.fleschKincaidCalculator = fleschKincaidCalculator;
this.fleschReadingEaseCalculator = fleschReadingEaseCalculator;
this.readingLevelClassifier = readingLevelClassifier;
this.complexityClassifier = complexityClassifier;
}
@Override
public ReadabilityMetrics analyzeReadability(String text) {
return analyzeReadability(text, true);
}
@Override
public ReadabilityMetrics analyzeReadability(String text, boolean includeComplexity) {
Objects.requireNonNull(text, "Text cannot be null");
LOGGER.debug("Starting readability analysis for text of length: {}", text.length());
try {
if (text.isBlank()) {
return new ReadabilityMetrics(0.0, 100.0, "Elementary", "Very Easy", 0.0, 0.0);
}
ReadabilityMetrics result = computeMetrics(text, includeComplexity);
LOGGER.debug("Readability analysis completed: {}", result);
return result;
} catch (Exception e) {
LOGGER.error("Failed to analyze readability", e);
throw new RuntimeException("Failed to analyze readability: " + e.getMessage(), e);
}
}
/**
* Computes the readability metrics based on the provided text.
*
* @param text the text to analyze
* @param includeComplexity whether to include complexity classification
* @return the computed readability metrics
*/
private ReadabilityMetrics computeMetrics(String text, boolean includeComplexity) {
double averageSentenceLength = sentenceLengthCalculator.calculateAverageSentenceLength(text);
double averageSyllablesPerWord = syllablePerWordCalculator.calculateAverageSyllablesPerWord(text);
double fleschKincaidScore = fleschKincaidCalculator.calculateScore(averageSentenceLength, averageSyllablesPerWord);
double fleschReadingEaseRaw = fleschReadingEaseCalculator.calculateScore(averageSentenceLength, averageSyllablesPerWord);
// Clamp FRE to [0, 100] for reporting/validation consistency
double fleschReadingEase = Math.max(VerbaMetricsConstants.FLESCH_READING_EASE_MIN, Math.min(VerbaMetricsConstants.FLESCH_READING_EASE_MAX, fleschReadingEaseRaw));
String readingLevel = readingLevelClassifier.determineReadingLevel(fleschKincaidScore);
String complexity = includeComplexity ? complexityClassifier.determineComplexity(fleschReadingEase) : "Unknown";
return new ReadabilityMetrics(
fleschKincaidScore, fleschReadingEase, readingLevel, complexity,
averageSentenceLength, averageSyllablesPerWord
);
}
}