Skip to content

Improve Ghost ingest language detection - #3

Merged
maquchizi merged 5 commits into
pesacheckfrom
improve-ghost-ingest-language-detection
Aug 10, 2026
Merged

Improve Ghost ingest language detection#3
maquchizi merged 5 commits into
pesacheckfrom
improve-ghost-ingest-language-detection

Conversation

@maquchizi

@maquchizi maquchizi commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Ghost ingest assigned the wrong language to two of the six languages PesaCheck
    publishes in. _guess_language only ever returned am, fr or en, so Somali
    and Afaan Oromo both landed as English — 92% accurate overall on the 50-post
    reference export, but 0% on those two. Kiswahili was never detected at all.
  • Language is now resolved from the post's language tag (English, Afaan Oromo,
    ...), which is editorial metadata and therefore authoritative. Posts predating
    that tagging convention fall back to a text classifier closed over just these six
    languages: Ethiopic script share for Amharic, calibrated function-word coverage
    for the Latin-script five.
  • The classifier is purpose-built rather than delegating to langdetect, which has
    no Afaan Oromo model and labels it Somali (both Cushitic, both using the
    doubled-vowel Latin orthography) and raises outright on Amharic. langdetect is
    dropped as a dependency.
  • Unrelated: the last commit is a repo-wide Black pass over 7 files (scripts/,
    settings.py, medium_parser.py, and others). Verified formatting-only — AST
    identical before and after for every file. Worth reviewing separately from, or
    splitting out of, the ingest change.

Test plan

  • 25 unit tests for the detector: tag matching, script detection, each of the
    six languages, and the cases where it declines to guess.
  • 100% on the 50-post reference export (ops/local/ingest/ghost) via the tag
    path, and 100% again with the language tag stripped to exercise the text path.
  • Country tags adjacent to language tags don't collide — French/France,
    Somali/Somalia, English/Ethiopia.
  • A quoted Amharic phrase inside an English article no longer relabels it
    Amharic; embedded English quotes don't flip Somali or Oromo articles.

Pure formatting ahead of the language-detection work, so that the
functional diff which follows is readable rather than buried in
reflowed decorators and call sites.

black at its default line length (88) plus import sorting; no
behaviour change. Verified by comparing the AST of each module before
and after, ignoring import order.
@maquchizi
maquchizi force-pushed the improve-ghost-ingest-language-detection branch from 88c0f81 to 69934bb Compare August 10, 2026 10:25
Superdesk needs an ISO 639-1 code on every ingested item, and PesaCheck
publishes in English, Kiswahili, French, Somali, Afaan Oromo and
Amharic. Add a self-contained detector with two strategies:

- detect_language_from_tags: recent posts carry an explicit language tag
  ("English", "Afaan Oromo", ...). This is editorial metadata, so it is
  authoritative and tried first. Matching is exact on the normalised
  name or slug so a language is never confused with the country tag
  beside it, which PesaCheck always sets: French/France,
  Somali/Somalia. Where two language tags appear the lowest sort_order
  wins, matching Ghost's primary tag.
- detect_language_from_text: for posts predating that convention.
  Ethiopic script share identifies Amharic; the Latin-script languages
  are separated by calibrated function-word coverage.

The classifier is deliberately closed over just these six languages
rather than delegating to a general-purpose detector. langdetect has no
model for Afaan Oromo and labels it Somali (both Cushitic, both using
the doubled-vowel Latin orthography), and it raises outright on
Amharic. Scoring only what we publish removes the failure mode where an
article is lost to a seventh language that was never an option.

Marker lists and the per-language coverage constants were built and
measured against the 50-post reference export in ops/local/ingest/ghost.
Bare "Oromo" is deliberately not accepted as a language tag: it is an
ethnonym first and a plausible topic tag on an English article, and
Oromo prose is recognised well by the text path, so an unmatched tag
degrades safely.

The module imports only the standard library. It deliberately lives in
pesacheck/ rather than pesacheck/ingest/: the ingest package's __init__
eagerly imports the parsers, which pull in superdesk.io and the native
libmagic dependency, so placing it there would mean this pure-stdlib
logic -- and its tests -- could not be imported without the whole
Superdesk stack.
Replace _guess_language, which only ever returned am, fr or en. Somali
and Afaan Oromo both collapsed to English: langdetect was consulted but
its result was trusted only for en/fr, and it has no Oromo model
regardless. Measured against the 50-post reference export that was 92%
overall but 0% on Somali and Oromo.

_parse_language now resolves in three steps: Ghost's locale (normalised,
so en-US becomes en), then the post's language tag, then the new text
classifier. Tag records carry their slug so either the display name or
the slug can name the language.

Detection runs on Ghost's plaintext rendering rather than body_html, so
markup no longer dilutes the word counts, and falls back to html when a
post has no plaintext.

Also coerce a null sort_order on tags: the existing sort would have
raised TypeError comparing None to int, and sort_order now decides which
language tag wins.

Both paths reach 100% on the reference export -- via tags, and via text
with the language tag stripped to simulate the older untagged posts.
langdetect was added as a direct requirement solely for Ghost ingest
language detection, which no longer uses it. Nothing else in the tree
imports it.

six stays in requirements.txt: it is still required by flask-oidc-ex,
oauth2client and python-dateutil.
@maquchizi
maquchizi force-pushed the improve-ghost-ingest-language-detection branch from 695c5be to 53108d4 Compare August 10, 2026 11:08
@maquchizi
maquchizi merged commit 5c65122 into pesacheck Aug 10, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant