File size: 3,681 Bytes
73a6a7e
ce2ce69
 
73a6a7e
 
ce2ce69
73a6a7e
ce2ce69
 
73a6a7e
ce2ce69
 
 
73a6a7e
ce2ce69
 
 
 
 
 
 
 
 
 
 
 
73a6a7e
ce2ce69
 
 
 
73a6a7e
ce2ce69
 
 
 
73a6a7e
ce2ce69
 
 
 
73a6a7e
ce2ce69
 
 
 
73a6a7e
ce2ce69
 
 
 
73a6a7e
ce2ce69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73a6a7e
ce2ce69
 
73a6a7e
ce2ce69
 
73a6a7e
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# app/services/readability.py
import textstat
import logging
from app.core.config import APP_NAME
from app.core.exceptions import ServiceError

logger = logging.getLogger(f"{APP_NAME}.services.readability")

class ReadabilityScorer:
    async def compute(self, text: str) -> dict:
        try:
            text = text.strip()
            if not text:
                raise ServiceError(status_code=400, detail="Input text is empty for readability scoring.")

            scores = {
                "flesch_reading_ease": textstat.flesch_reading_ease(text),
                "flesch_kincaid_grade": textstat.flesch_kincaid_grade(text),
                "gunning_fog_index": textstat.gunning_fog(text),
                "smog_index": textstat.smog_index(text),
                "coleman_liau_index": textstat.coleman_liau_index(text),
                "automated_readability_index": textstat.automated_readability_index(text),
            }

            friendly_scores = {
                "flesch_reading_ease": {
                    "score": round(scores["flesch_reading_ease"], 2),
                    "label": "Flesch Reading Ease",
                    "description": "Higher is easier. 60–70 is plain English; 90+ is very easy."
                },
                "flesch_kincaid_grade": {
                    "score": round(scores["flesch_kincaid_grade"], 2),
                    "label": "Flesch-Kincaid Grade Level",
                    "description": "U.S. school grade. 8.0 means an 8th grader can understand it."
                },
                "gunning_fog_index": {
                    "score": round(scores["gunning_fog_index"], 2),
                    "label": "Gunning Fog Index",
                    "description": "Estimates years of formal education needed to understand."
                },
                "smog_index": {
                    "score": round(scores["smog_index"], 2),
                    "label": "SMOG Index",
                    "description": "Also estimates required years of education."
                },
                "coleman_liau_index": {
                    "score": round(scores["coleman_liau_index"], 2),
                    "label": "Coleman-Liau Index",
                    "description": "Grade level based on characters, not syllables."
                },
                "automated_readability_index": {
                    "score": round(scores["automated_readability_index"], 2),
                    "label": "Automated Readability Index",
                    "description": "Grade level using word and sentence lengths."
                }
            }

            ease_score = scores["flesch_reading_ease"]
            if ease_score >= 90:
                summary = "Very easy to read. Easily understood by 11-year-olds."
            elif ease_score >= 70:
                summary = "Fairly easy. Conversational English for most people."
            elif ease_score >= 60:
                summary = "Plain English. Easily understood by 13–15-year-olds."
            elif ease_score >= 30:
                summary = "Fairly difficult. College-level reading."
            else:
                summary = "Very difficult. Best understood by university graduates."

            return {
                "readability_summary": summary,
                "scores": friendly_scores
            }

        except Exception as e:
            logger.error(f"Readability scoring error for text: '{text[:50]}...'", exc_info=True)
            raise ServiceError(status_code=500, detail="An internal error occurred during readability scoring.") from e

# You can continue pasting the rest of your services here for production hardening