Skip to content

GradeBuilderSL/prosemeter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

prosemeter

CI License: MIT Python 3.10–3.13

A ruler for prose texture in Russian, English, Spanish and Italian. Pure stdlib, zero dependencies.

prosemeter measures the surface texture of a text — sentence rhythm, punctuation habits, lexical texture, voice — and hands you a flat dict of numbers. That's the whole product.

It is explicitly not an AI detector and not a quality metric: it describes, it does not pass judgment. Some of the features it reports (filler density, contrast frames, opener repetition) happen to be popular tells of generated or padded prose, but prosemeter attaches no verdict to any value. What counts as "too much" depends on your corpus, your genre and your taste — that's your call, on your data.

Install

pip install prosemeter

Usage

from prosemeter import profile

text = (
    "The kettle clicked off and the kitchen went quiet. I had been rewriting "
    "the same paragraph for an hour, and it still read like a brochure. So I "
    "did what editors do: cut the openers, moved the numbers up front, and "
    "read it aloud. Better. Not perfect, but better."
)

print(profile(text))          # lang="auto" detects English here
print(profile(text, lang="en"))  # or say it explicitly

Real output (English adds five extra keys on top of the common core):

{
  "words": 49, "sentences": 5,
  "mean_sentence_len": 9.8, "cv_sentence_len": 0.69,
  "pct_short": 0.4, "pct_long": 0.0, "staccato_share": 0.4,
  "anaphora_top_share": 0.2,
  "dash_per_100w": 0.0, "guillemet_per_100w": 0.0, "questions_per_sent": 0.0,
  "contrast_frames_per_100w": 0.0,
  "address_per_1k": 0.0, "first_person_per_1k": 40.8,
  "digit_density_per_1k": 0.0,
  "filler_per_100w": 0.0, "nominal_per_100w": 0.0,
  "mean_word_len": 4.14, "ttr": 0.8,
  "syllables_per_word": 1.33, "flesch_reading_ease": 84.7,
  "polysyllable_per_100w": 0.0, "passive_per_100sent": 0.0,
  "ly_adverbs_per_100w": 0.0
}

The public API is three names: profile(text, lang="auto"), SUPPORTED_LANGS (("ru", "en", "es", "it")) and __version__. lang="auto" uses a cheap script/function-word heuristic that is reliable on a paragraph of ordinary prose; pass the language explicitly for short fragments or mixed-language text.

Features

Counts are ints; every other value is a rate, so profiles of texts of different lengths are comparable. Rates are per word (per_100w / per_1k), per sentence (per_sent / per_100sent) or a share in 0..1.

Key What it measures Languages
words Word count. all
sentences Sentence count (regex splitter — see Honest limits). all
mean_sentence_len Mean sentence length in words. all
cv_sentence_len Coefficient of variation (std/mean) of sentence length — the classic dispersion measure used as a rhythm signal. Metronomic prose sits low; prose alternating long and short sentences sits higher. all
pct_short Share of sentences with ≤ 6 words. all
pct_long Share of sentences with ≥ 25 words. all
staccato_share Share of stub sentences (≤ 4 words) — the "Short. Punchy. Fragments." register. all
anaphora_top_share Opener repetition: share of sentences beginning with the single most frequent opening word ("This… This… This…"). English baselines are naturally noisy (articles, pronouns). all
dash_per_100w Em/en dashes (plus the spaced hyphen used as a dash) per 100 words. Dash-for-everything punctuation vs. dash-as-rare-accent. all
guillemet_per_100w Guillemets («») per 100 words — quote/dialogue-heavy vs. plain expository prose. all
questions_per_sent Question marks per sentence — rhetorical-question density. all
contrast_frames_per_100w Density of the "it's not X, it's Y" contrast frame (per-language patterns). One is rhetoric; a high rate is a texture of its own. all
address_per_1k Second-person reader-address words per 1000 words. all
first_person_per_1k First-person words per 1000 words — personal voice. all
digit_density_per_1k Numeric tokens per 1000 words — concreteness of the text's factual grounding. all
filler_per_100w Hits from a per-language filler/officialese phrase list per 100 words ("it is important to note", «важно отметить», "cabe destacar", "va sottolineato"). The Russian list follows the officialese-hunting tradition of Nora Gal. all
nominal_per_100w Abstract nominalizations per 100 words, matched by derivational suffix ("-tion", "-ность", "-ción", "-zione") — Helen Sword's "zombie nouns", Nora Gal's hidden verbs. all
mean_word_len Mean word length in characters. all
ttr Type-token ratio — lexical diversity. Length-sensitive: only compare texts of similar length. all
syllables_per_word Mean syllables per word (heuristic counter). en
flesch_reading_ease Flesch Reading Ease (Rudolf Flesch, 1948): higher = plainer. en
polysyllable_per_100w Words with ≥ 4 syllables per 100 words. en
passive_per_100sent Passive constructions ("to be" + past participle, regex approximation) per 100 sentences — the Orwell / Strunk & White signal. en
ly_adverbs_per_100w -ly adverbs per 100 words — the modifier crutch Stephen King warns about. en

Honest limits

Tokenization is regex-only: sentences split on runs of .!?, words on per-language character classes. Abbreviations, decimals and ellipses can over- or under-split. Over a paragraph or an article these errors average out; do not trust the numbers on a single sentence, and do not compare ttr across texts of very different lengths.

Scope is frozen

This package does one thing: it measures. Bug reports (wrong counts, crash on valid input, broken language detection) are very welcome. Feature requests — new languages, new metrics, verdicts of any kind — are out of scope for now.

Built to power Laspi

Laspi

prosemeter is the measuring half of the writing engine behind Laspi — an AI social media manager for small businesses. You record one short voice note a week; Laspi turns it into a week of ready-to-publish posts — captions written natively per network, images and short videos — in English, Spanish, Russian or Italian. These metrics are part of how Laspi keeps that writing sounding human.

The measuring is open source. The writing is the product: try a free week at laspi.pro — no card needed.

License

MIT © 2026 GradeBuilder S.L.

About

A dependency-free ruler for prose texture in Russian, English, Spanish and Italian. Measures rhythm, punctuation and voice; passes no judgment.

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages