Skip to content

Commit 4db44a8

Browse files
feature: Move ML prediction logic to PredictionUtils class
- Refactored the predictReadingLevel method from core class into PredictionUtils to enhance reusability and separation of concerns. - The utility class no longer includes logging statements, adhering to best practices. - Added a ReadingLevelConstants class responsible for containing all constants related to the Reading Level ML model. - Added unit test cases for ReadingLevelUtil class. Issue elimu-ai#1825
1 parent 76e0880 commit 4db44a8

File tree

4 files changed

+73
-34
lines changed

4 files changed

+73
-34
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,32 @@
11
package ai.elimu.util;
22

3-
public class AppConstants {
3+
public class ReadingLevelConstants {
44

55
public static class READING_LEVEL_CONSTANTS {
6+
7+
/**
8+
* Key for the number of chapters in a book
9+
*/
610
public static final String CHAPTER_COUNT_KEY = "chapter_count";
11+
12+
/**
13+
* Key for the number of paragraphs in a book
14+
*/
715
public static final String PARAGRAPH_COUNT_KEY = "paragraph_count";
16+
17+
/**
18+
* Key for the total word count in a book
19+
*/
820
public static final String WORD_COUNT_KEY = "word_count";
9-
public static final String LEVEL = "LEVEL";
10-
}
1121

22+
/**
23+
* Key for the predicted reading level output
24+
*/
25+
public static final String READING_LEVEL_KEY = "LEVEL";
26+
27+
/**
28+
* Reading level file pmml path key
29+
*/
30+
public static final String READING_LEVEL_MODEL_FILE_PATH_KEY = "src/main/resources/ai/elimu/web/content/storybook/step2_2_model.pmml";
31+
}
1232
}

src/main/java/ai/elimu/util/ml/ReadingLevelUtil.java

+28-5
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,41 @@
66
import java.util.Arrays;
77
import java.util.Map;
88

9-
import static ai.elimu.util.AppConstants.READING_LEVEL_CONSTANTS.*;
9+
import static ai.elimu.util.ReadingLevelConstants.READING_LEVEL_CONSTANTS.*;
1010

1111
public class ReadingLevelUtil {
1212

13+
/**
14+
* Predicts the reading level based on chapter count, paragraph count, and word count using a machine learning model.
15+
*
16+
* <p>This method loads a pre-trained machine learning model and predicts the reading level by passing the
17+
* given chapter count, paragraph count, and word count as input features. The model returns a numeric
18+
* prediction, which is then converted into a corresponding {@link ReadingLevel} enum.</p>
19+
*
20+
* @param chapterCount The number of chapters in the text. Must be an integer value.
21+
* @param paragraphCount The number of paragraphs in the text. Must be an integer value.
22+
* @param wordCount The number of words in the text. Must be an integer value.
23+
*
24+
* @return The predicted {@link ReadingLevel} based on the input features.
25+
*
26+
* <p>Example usage:</p>
27+
* <pre>
28+
* {@code
29+
* int chapterCount = 10;
30+
* int paragraphCount = 50;
31+
* int wordCount = 300;
32+
* ReadingLevel readingLevel = PredictionUtils.predictReadingLevel(chapterCount, paragraphCount, wordCount);
33+
* System.out.println("Predicted Reading Level: " + readingLevel);
34+
* }
35+
* </pre>
36+
*/
1337
public static ReadingLevel predictReadingLevel(
1438
int chapterCount,
1539
int paragraphCount,
16-
int wordCount,
17-
String modelFilePath
40+
int wordCount
1841
) {
1942

20-
Model model = Model.fromFile(modelFilePath);
43+
Model model = Model.fromFile(READING_LEVEL_MODEL_FILE_PATH_KEY);
2144
Map<String, Double> features = Map.of(
2245
CHAPTER_COUNT_KEY, (double) chapterCount,
2346
PARAGRAPH_COUNT_KEY, (double) paragraphCount,
@@ -34,7 +57,7 @@ public static ReadingLevel predictReadingLevel(
3457
Double resultAsDouble = (Double) result;
3558
int resultAsInteger = resultAsDouble.intValue();
3659

37-
String readingLevelAsString = LEVEL + resultAsInteger;
60+
String readingLevelAsString = READING_LEVEL_KEY + resultAsInteger;
3861
return ReadingLevel.valueOf(readingLevelAsString);
3962

4063
}

src/main/java/ai/elimu/web/content/storybook/StoryBookCreateFromEPubController.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -542,14 +542,12 @@ private ReadingLevel predictReadingLevel(int chapterCount, int paragraphCount, i
542542

543543
// Load the machine learning model (https://github.com/elimu-ai/ml-storybook-reading-level)
544544

545-
String modelFilePath = Objects.requireNonNull(getClass().getResource("step2_2_model.pmml")).getFile();
546-
547545
logger.info(
548-
"Predicting reading level for chapter: {}, paragraph: {}, word: {}, modelPath: {} ",
549-
chapterCount, paragraphCount, wordCount, modelFilePath
546+
"Predicting reading level for chapter: {}, paragraph: {}, word: {} ",
547+
chapterCount, paragraphCount, wordCount
550548
);
551549

552-
ReadingLevel readingLevel = ReadingLevelUtil.predictReadingLevel(chapterCount, paragraphCount, wordCount, modelFilePath);
550+
ReadingLevel readingLevel = ReadingLevelUtil.predictReadingLevel(chapterCount, paragraphCount, wordCount);
553551
logger.info("Predicted reading level: {}", readingLevel);
554552

555553
return readingLevel;

src/test/java/ai/elimu/util/ml/ReadingLevelUtilTest.java

+19-21
Original file line numberDiff line numberDiff line change
@@ -3,57 +3,55 @@
33
import ai.elimu.model.v2.enums.ReadingLevel;
44
import org.junit.jupiter.api.Test;
55

6-
import java.io.IOException;
7-
86
import static org.junit.jupiter.api.Assertions.assertEquals;
9-
import static org.junit.jupiter.api.Assertions.assertThrows;
107

118
public class ReadingLevelUtilTest {
129

1310
@Test
1411
public void testPredictReadingLevel_Level1() {
1512

16-
String modelFilePath = "src/test/resources/ai/elimu/util/reading_level/model1.pmml";
17-
int chapterCount = 5;
18-
int paragraphCount = 20;
19-
int wordCount = 100;
13+
int chapterCount = 12;
14+
int paragraphCount = 18;
15+
int wordCount = 150;
2016

21-
ReadingLevel result = ReadingLevelUtil.predictReadingLevel(chapterCount, paragraphCount, wordCount, modelFilePath);
17+
ReadingLevel result = ReadingLevelUtil.predictReadingLevel(chapterCount, paragraphCount, wordCount);
2218
assertEquals(ReadingLevel.LEVEL1, result, "Expected ReadingLevel to be LEVEL1, but got: " + result);
2319

2420
}
2521

2622
@Test
2723
public void testPredictReadingLevel_Level2() {
2824

29-
String modelFilePath = "src/test/resources/ai/elimu/util/reading_level/model1.pmml";
30-
int chapterCount = 12;
31-
int paragraphCount = 22;
32-
int wordCount = 250;
25+
int chapterCount = 20;
26+
int paragraphCount = 30;
27+
int wordCount = 300;
3328

34-
ReadingLevel result = ReadingLevelUtil.predictReadingLevel(chapterCount, paragraphCount, wordCount, modelFilePath);
29+
ReadingLevel result = ReadingLevelUtil.predictReadingLevel(chapterCount, paragraphCount, wordCount);
3530
assertEquals(ReadingLevel.LEVEL2, result, "Expected ReadingLevel to be LEVEL2, but got: " + result);
3631

3732
}
3833

3934
@Test
4035
public void testPredictReadingLevel_Level3() {
4136

42-
String modelFilePath = "src/test/resources/ai/elimu/util/reading_level/model1.pmml";
43-
int chapterCount = 12;
44-
int paragraphCount = 25;
37+
int chapterCount = 25;
38+
int paragraphCount = 40;
4539
int wordCount = 350;
4640

47-
ReadingLevel result = ReadingLevelUtil.predictReadingLevel(chapterCount, paragraphCount, wordCount, modelFilePath);
41+
ReadingLevel result = ReadingLevelUtil.predictReadingLevel(chapterCount, paragraphCount, wordCount);
4842
assertEquals(ReadingLevel.LEVEL3, result, "Expected ReadingLevel to be LEVEL3, but got: " + result);
4943

5044
}
5145

5246
@Test
53-
public void testPredictReadingLevel_InvalidModelFile() {
47+
public void testPredictReadingLevel_Level4() {
48+
49+
int chapterCount = 15;
50+
int paragraphCount = 45;
51+
int wordCount = 559;
52+
53+
ReadingLevel result = ReadingLevelUtil.predictReadingLevel(chapterCount, paragraphCount, wordCount);
54+
assertEquals(ReadingLevel.LEVEL4, result, "Expected ReadingLevel to be LEVEL4, but got: " + result);
5455

55-
assertThrows(IOException.class, () -> {
56-
ReadingLevelUtil.predictReadingLevel(1, 1, 1, "invalidPath");
57-
}, "Expected IOException when loading an invalid model file path");
5856
}
5957
}

0 commit comments

Comments
 (0)