85.1.28. pepsi-stage-detect-language

detect the human language of a message body

Section du manuel:

1

85.1.28.1.1. Nom

pepsi-stage-detect-language - l’étape de détection de langue du pipeline Pepsi.

85.1.28.1.2. Synopsis

pepsi-stage-detect-language [GLOBAL-OPTIONS] worker

85.1.28.1.3. Description

pepsi-stage-detect-language est un programme d’étape exécuté par pepsi-dispatch(1) comme un worker persistant lisant les identifiants de message sur l’entrée standard. Il charge la ligne pepsi.workqueue correspondante (refusant d’agir si son status n’est pas running), lit sa section [stage-<stage>], identifie la ou les langues humaines utilisées dans le corps du message, et les note sous state.language avant de faire avancer le message vers NEXT_STAGE. Cette étape ne supprime, ne fait rebondir ni ne met jamais un message en pause, et elle préserve le reste de state.

L’étape extrait le texte de corps en ligne du message avec un analyseur MIME complet (logique partagée dans pepsi-common) : les parties text/plain sont prises verbatim et les parties text/html sont réduites en texte brut, chacune décodée depuis son encodage de transfert de contenu et son jeu de caractères déclaré vers UTF-8. Les pièces jointes (y compris les pièces jointes texte) sont ignorées, tout comme les corps chiffrés ou autrement opaques (par exemple multipart/encrypted ou application/pkcs7-mime), qui ne portent aucun texte lisible. Pour un multipart/alternative, l’alternative en texte brut est préférée à celle en HTML — sauf lorsque cette alternative en texte brut se révèle ne contenir aucune prose, la forme que produit un expéditeur de masse lorsqu’il met deux URL nues là où devrait être le message ; la partie HTML sœur est alors utilisée à la place.

85.1.28.1.3.1. Filtrage de la prose

Le texte extrait est ensuite réduit à la part qui en est de la prose, et seule celle-ci est classifiée. Un détecteur statistique modélise la façon dont les humains écrivent des mots, et un corps d’e-mail est plein de choses qui ne sont pas des mots : URL, adresses, clés base64, enregistrements DNS, identifiants hexadécimaux. Sans filtrage, un corps majoritairement fait de texte machine est classifié à partir de ce texte machine : une notification d’enregistrement DNS ou un corps de spam fait de deux URL nues reçoit un verdict assuré pour une langue que personne n’y a écrite, même lorsque chaque mot qu’un humain y a écrit est anglais.

Deux filtres s’exécutent, dans cet ordre :

  • les jetons qui ne peuvent pas être des mots sont écartés — tout ce qui contient @, une barre oblique ou une barre oblique inverse, ou un point interne, tout ce qui commence par http ou www., tout ce qui comporte moins de la moitié de lettres, tout ce qui contient un chiffre, tout ce qui dépasse 30 caractères, et tout ce dont la capitalisation change à l’intérieur du mot (CamelCase, base64) ;

  • les lignes auxquelles il reste moins de 15 lettres, ou dans lesquelles les lettres ne sont pas majoritaires, sont écartées — ce que le premier filtre laisse d’un vidage DNS ou d’un tableau est une dispersion de noms de champs nus, ce qui n’est de la prose dans aucune langue.

Les règles connaissent les écritures qui ne séparent pas les mots par des espaces (han, kana, hangul, thaï, khmer, lao, birman, tibétain) : là, une proposition entière arrive comme un seul jeton, de sorte que les règles de longueur, de chiffres, de point et de capitalisation ne lui sont pas appliquées, et que les lignes sont jugées au nombre de lettres qu’elles contiennent plutôt qu’au nombre de mots. Sans cela, un message chinois ou thaï serait supprimé dans son intégralité.

85.1.28.1.3.2. Classification

La prose restante est classifiée avec le détecteur statistique lingua, construit à partir des langues candidates nommées par l’option LANGUAGES. Le détecteur produit une probabilité pour chaque langue candidate ; les au plus trois langues les plus probables dont la probabilité est d’au moins 5 % sont enregistrées.

Au plus les 20 000 premiers caractères de cette prose sont classifiés. Le détecteur note chaque langue candidate sur l’ensemble du texte : son coût est donc la longueur du texte multipliée par le nombre de langues candidates — et avec LANGUAGES = * elles sont 75, face à une limite de taille de message qui se mesure en mégaoctets. Une langue se décide sur les premiers kilo-octets ; classifier le reste d’un long message ne ferait qu’occuper le worker. Il n’y a pas d’option pour cela : c’est une borne sur le travail, pas une politique.

Si le message n’a pas de texte en ligne exploitable, si rien de ce texte n’est de la prose, ou s’il y a trop peu de prose (moins de 20 caractères) pour classifier de façon fiable, l’étape saute la classification : le message avance inchangé, sans clé language ajoutée. Ne rien noter est délibéré — un corps qui n’est que des URL n’a pas de langue, et en deviner une à partir d’un fragment d’URL est la façon dont un message finit étiqueté avec assurance dans une langue dans laquelle personne ne l’a écrit.

85.1.28.1.4. Format de sortie

state.language est une chaîne dans la syntaxe d’un en-tête HTTP Accept-Language : une liste séparée par des virgules d’éléments code;q=quality, ordonnés du plus au moins probable. Chaque code est le code ISO 639-1 de la langue et chaque quality est sa probabilité de détection dans la plage 0–1 (les zéros finaux supprimés, de sorte qu’une langue unique certaine s’affiche q=1). Par exemple, un message majoritairement en anglais avec un peu d’allemand pourrait être enregistré comme

en;q=1, de;q=0.45

Le détecteur est coûteux à construire : chaque processus worker le construit donc une fois (par ensemble distinct de langues candidates) et le réutilise pour chaque message. Il est construit à la pleine précision de lingua ; le mode basse précision de la bibliothèque n’est délibérément pas utilisé. Ce mode court-circuite — il renvoie une langue avec la probabilité 1 dès qu’exactement une candidate possède un n-gramme apparaissant quelque part dans le texte, sans examiner le reste — de sorte qu’une seule adresse dans une ligne d’attribution citée, ou une clé base64, peut décider de la langue de kilo-octets de prose. Sur de la prose filtrée, il n’est pas moins coûteux non plus : la recherche de raccourci est payée puis jetée, et il précharge des modèles de comptage de n-grammes supplémentaires : il n’apporte donc rien.

85.1.28.1.5. Configuration

Les options résident dans la propre section [stage-<name>] de l’étape (PROGRAM = pepsi-stage-detect-language) : un NEXT_STAGE et l’ensemble de langues candidates LANGUAGES. Elles sont documentées dans pepsi.conf(5).

85.1.28.1.6. État

Entrées : aucune depuis state ; l’étape lit le corps du message stocké.

Sorties : lorsqu’au moins une langue est détectée, l’étape fusionne language (la chaîne de style Accept-Language) dans state et avance — une seule mise à jour qui déplace la ligne vers NEXT_STAGE et fusionne la clé ; sinon state est laissé intact et la ligne avance simplement. La disposition de l’état est décrite dans pepsi.state(7).

Transitions : avance toujours vers NEXT_STAGE, qu’une langue ait été détectée ou non. Il n’y a pas de branche ; l’étape ne met jamais en pause, n’échoue jamais, ne scinde jamais et ne termine jamais. Un message dont le contenu fait paniquer le classifieur est avancé sans langue, avec un avertissement dans le journal : le réessayer ne ferait que provoquer une nouvelle panique, et rien en aval n’exige de langue.

85.1.28.1.7. Commandes

worker

Exécuté comme un worker persistant de pepsi-dispatch(1), lisant les identifiants de message sur l’entrée standard.

85.1.28.1.8. Options globales

-c FILE, –config FILE

Lit la configuration depuis FILE au lieu de parcourir les emplacements par défaut.

-L LOGLEVEL, –log LOGLEVEL

Règle la verbosité de journalisation (par défaut info).

-v, –verbose

Affiche les messages de journal de toutes les sources.

-h, –help ; -V, –version

Affiche un résumé d’utilisation / la version et quitte.

85.1.28.1.9. Code de sortie

0

Le message a été traité (avancé, avec ou sans langue enregistrée).

1

Une erreur s’est produite (message introuvable ou non running, ou un paramètre par adresse qui casse la section de l’étape — un code LANGUAGES invalide, par exemple). La raison est écrite dans le journal.

Une défaillance de l’hôte (la base de données, un modèle ou un helper inutilisable) n’est pas signalée comme un échec : le message est mis en pause et réessayé, comme le décrit Erreurs d’étape dans pepsi-dispatch(1). Une section qui ne s’analyse pas fait refuser au worker de démarrer (statut 78) au lieu de faire échouer chaque message tour à tour. Il en va de même d’un NEXT_STAGE manquant.

85.1.28.1.10. Diagnostic et ajustement

pepsi-detect-language(1) est le pendant hors-ligne de cette étape : le même exécutable sous un second nom, qui classifie un message lu depuis un fichier ou l’entrée standard et n’imprime que ce que cette étape aurait noté, sans approcher la base de données. Utilisez-le pour reproduire une erreur de classification à partir d’un message sauvegardé (--explain montre le texte extrait, la prose restant après filtrage, et la confiance de chaque candidate) et pour essayer des ensembles de candidates avant d’en configurer un (--languages).

85.1.28.1.11. Exemples

Classifier un message à la main (l’identifiant doit nommer une ligne running)

echo 42 | pepsi-stage-detect-language -c /etc/pepsi/pepsi.conf worker

Une section de pipeline qui étiquette la langue du corps avant la vérification de liste blanche

[stage-detect-language]
PROGRAM = pepsi-stage-detect-language
NEXT_STAGE = check-whitelist
LANGUAGES = en de fr es

85.1.28.1.12. Voir aussi

pepsi-detect-language(1), pepsi-config(1), pepsi-stage-check-whitelist(1), pepsi-dispatch(1), pepsi.conf(5), pepsi.state(7), pepsi-setup(1)

85.1.28.1.13. Bogues

Signalez les bogues au gestionnaire de tickets de Pepsi.