Skip to content

Détection du processus de rédaction

Transformez les journaux de frappes de Potato en signalements vérifiables pour les réponses en texte libre collées, recopiées ou produites par une machine, avec des seuils que vous pouvez lire et remplacer.

La détection du processus de rédaction lit la dynamique de frappe captée par la journalisation des frappes et produit des signalements nommés, avec les preuves attachées, pour que vous puissiez voir quelles valeurs de caractéristiques ont déclenché chacun d'eux et écarter ceux avec lesquels vous n'êtes pas d'accord.

Elle demande Potato 2.7.2 ou une version ultérieure, et elle ne fonctionne que là où la journalisation des frappes est déjà active. Comme keystroke_logging.enabled vaut false par défaut, un projet qui ne l'a jamais activée n'a rien sur quoi détecter.

Avertissement : Les signalements sont des indices destinés à l'examen d'un humain. Ce ne sont pas des preuves de fraude, et ils ne doivent jamais être branchés sur un rejet automatique, une retenue de paiement ou l'exclusion d'un participant. Un dactylo rapide et fluide qui produit un premier jet propre ressemble vraiment à une transcription. Un annotateur sur téléphone ressemble vraiment à quelqu'un qui colle. Les règles ci-dessous sont conçues pour limiter ces collisions, et les collisions se produisent quand même. La section faux positifs fait partie de la fonctionnalité, ce n'est pas une clause de style.

Trois niveaux

NiveauDe quoi il s'agitDonnées étiquetées nécessaires ?Défaut
1. RèglesSix signalements nommés, à seuils explicites et preuves visiblesNonActivé
2. CalibrationSeuils réajustés sur les annotateurs de votre propre projetNonDésactivé
3. SuperviséUn classifieur que vous entraînez sur vos propres étiquettesOuiDésactivé

Aucun modèle pré-entraîné n'est livré avec Potato. Il n'y a pas de corpus étiqueté dans le dépôt, donc tout coefficient que nous livrerions arriverait avec un chiffre de validation que nous aurions inventé. Vous obtenez à la place six règles que vous pouvez lire et discuter. Si vous disposez de vraies étiquettes, le niveau 3 est la voie qui reproduit les exactitudes rapportées dans la littérature.

Niveau 1 : les règles

Chaque signalement renvoie les valeurs de caractéristiques qui l'ont déclenché, pour que vous puissiez défendre ou écarter chacun d'eux.

paste_dominant

Gravité : suspect. Se déclenche quand pasted_fraction >= 0.5, c'est-à-dire quand la moitié ou plus du texte final est arrivée par collage.

Neutralisé quand tous les collages ont été classés self (réorganisation de son propre brouillon) ou instance_text (citation du passage annoté).

silent_insertion

Gravité : suspect. Se déclenche quand external_insert_ratio >= 0.3, c'est-à-dire quand près d'un tiers des caractères insérés sont apparus sans frappe correspondante.

C'est le signal isolé le plus utile. Le collage, le remplissage automatique, la dictée et l'injection programmatique se manifestent tous ici, même quand l'événement de collage lui-même est supprimé par la page. C'est une opérationnalisation directe du « nombre de frappes anormalement bas au regard de la longueur de la réponse » d'Asher et al.

Neutralisé sur les claviers logiciels (virtual_keyboard) et pendant la composition IME, où keydown n'est pas émis de façon fiable et où chaque insertion paraîtrait sinon silencieuse. La règle utilise le ratio tenant compte de la source, donc citer légitimement ne compte pas.

transcription_rhythm

Gravité : review. Se déclenche quand les trois conditions suivantes tiennent :

  • iki_log_cv <= 0.06, un rythme de frappe métronomique
  • revision_ratio <= 0.02, pour ainsi dire aucune suppression
  • moins de 0,5 pause de 2 secondes ou plus par tranche de 100 caractères

Conjonctive à dessein. Chacune prise isolément a une lecture innocente. Ensemble, elles forment la signature de la recopie décrite par Crossley et al. : linéaire, par rafales, à faible variance.

Entièrement ignorée pour les réponses de moins de 80 caractères ou 40 frappes, où il n'y a pas de rythme dont parler.

offscreen_composition

Gravité : suspect. Se déclenche quand une insertion importante d'origine externe (80 caractères ou plus) suit immédiatement une absence de 10 secondes ou plus hors de la page. C'est le motif « passé sur ChatGPT, revenu, collé ».

Neutralisé quand la source de l'insertion était le passage ou le texte de l'annotateur lui-même, car s'éloigner puis citer le passage est un comportement ordinaire.

implausible_speed

Gravité : review. Se déclenche au-delà de 900 caractères par minute (environ 180 wpm) tenus sur toute une réponse.

synthetic_input

Gravité : suspect. Se déclenche sur tout événement avec isTrusted === false, le navigateur signalant que la saisie a été produite par un script et non par une personne. L'automatisation de navigateur, les scripts injectés et certains outils d'accessibilité produisent ce cas.

Niveaux de verdict

NiveauSignification
okAucun signalement déclenché
reviewAu moins un signalement de gravité review
suspectAu moins un signalement de gravité suspect

Remplacer les seuils

yaml
keystroke_logging:
  detection:
    thresholds:
      paste_dominant.pasted_fraction: 0.4
      silent_insertion.ratio: 0.25
      transcription_rhythm.iki_log_cv: 0.05
      transcription_rhythm.revision_ratio: 0.02
      transcription_rhythm.pause_2s_per_100_chars: 0.5
      offscreen_composition.blur_ms: 15000
      offscreen_composition.insert_chars: 100
      implausible_speed.chars_per_min: 1000

Les seuils sont évalués côté serveur et ne sont jamais envoyés au navigateur. Les publier indiquerait à un annotateur exactement à quelle lenteur coller pour rester sous le signalement.

Niveau 2 : calibration sur le projet

Les caractéristiques de frappe varient beaucoup selon la tâche de rédaction (Conijn et al. 2019), et des seuils fixes sur une grandeur distribuée en mélange sont biaisés (Roeser et al. 2021). Une coupure qui convient à une justification d'une phrase est fausse pour un essai de cinq paragraphes.

La calibration place chaque seuil à un percentile de queue des sessions de votre propre projet.

bash
# Inspect the fit without saving it
python -m potato.typing_detect calibrate config.yaml --dry-run
 
# Save it
python -m potato.typing_detect calibrate config.yaml
yaml
keystroke_logging:
  detection:
    calibrate: true    # use the saved fit

La calibration demande au moins 30 sessions exploitables (80 caractères ou plus, hors mobile). En dessous, elle renvoie insufficient_data et les valeurs par défaut restent en vigueur.

Avertissement : Une coupure par percentile est une définition relative de la valeur aberrante. Par construction, elle signale à peu près tail_fraction (5 % par défaut) des sessions, même dans une population où personne ne fait rien de mal. Elle indique où regarder en premier. Ce n'est pas une preuve. Les seuils calibrés sont en outre bornés à 3× les valeurs par défaut intégrées, pour qu'une population homogène ne puisse pas tirer une coupure jusqu'à sa propre médiane et se mettre à signaler des annotateurs honnêtes.

Un thresholds: explicite l'emporte toujours sur une valeur calibrée, qui l'emporte toujours sur la valeur par défaut intégrée.

Niveau 3 : classifieur supervisé

Si vous disposez de sessions étiquetées, entraînez un vrai modèle :

python
from potato import typing_store
from potato.typing_detect import fit_supervised
 
rows = typing_store.feature_matrix(task_dir, project)
labels = [...]   # 1 = non-composed, 0 = composed
 
result = fit_supervised(rows, labels, model="random_forest")
print(result["cv_accuracy_mean"], result["feature_importances"])

Nécessite scikit-learn, importé à la demande et qui n'est pas une dépendance de Potato.

Obtenir des étiquettes sans étude externe

La phase de formation de Potato peut les produire pour vous. Demandez aux annotateurs de recopier un passage fourni en guise d'échauffement. Leurs sessions de recopie sont de véritables exemples de transcription et leurs réponses normales des exemples de rédaction, ce qui vous donne un jeu étiqueté issu de votre propre projet, sur votre propre tâche, avec vos propres annotateurs. C'est ainsi que Crossley et al. ont constitué leur corpus, et l'exemple de calibration le met en place de bout en bout.

Faux positifs

Le mode de défaillance de cette fonctionnalité, c'est d'accuser un annotateur honnête. Voici les cas qui ressemblent légitimement aux motifs décrits plus haut.

SituationRègle à laquelle cela ressembleComment Potato le traite
Citer le passage annotépaste_dominant, silent_insertion, offscreen_compositionNeutralisé via paste_source: instance_text
Déplacer son propre brouillonLes mêmesNeutralisé via paste_source: self
Taper sur un téléphone ou une tablettesilent_insertionNeutralisé via virtual_keyboard
Saisie non latine via un IMEsilent_insertionNeutralisé via composition_events
Dactylo rapide et fluide, jet propretranscription_rhythm, implausible_speedRègles conjonctives ; review et non suspect ; calibration
Réponses très courtestranscription_rhythmIgnorées en dessous de 80 caractères / 40 frappes
Dictée ou reconnaissance vocalesilent_insertionNon traité. Sera signalé. Excluez ces annotateurs ou relevez le seuil.
Lecteurs d'écran et certaines technologies d'assistancesynthetic_inputPas entièrement traité. Certains outils produisent des événements non fiables.
Correction automatique sur mobilesilent_insertionEn partie. insertReplacementText compte comme externe.
Extensions de navigateur, par exemple les correcteurs grammaticauxsilent_insertion, synthetic_inputNon traité. Sera signalé.

Les quatre derniers cas sont de vraies limites, pas des oublis. Si votre panel comprend des personnes qui dictent, qui utilisent des technologies d'assistance ou des extensions d'aide à la rédaction, retirez ces règles de vos critères d'examen ou traitez chaque signalement comme une invitation à interroger l'annotateur plutôt qu'à agir.

Accessibilité

synthetic_input s'appuie sur isTrusted, que certaines technologies d'assistance déclenchent aussi. Signaler un annotateur en situation de handicap parce qu'il utilise les outils dont il a besoin pour travailler est un résultat inacceptable.

Cette règle n'a pas de seuil, donc il n'existe aucune valeur à régler pour la rendre inatteignable. Si votre étude est ouverte aux personnes qui utilisent des technologies d'assistance, retirez synthetic_input des critères d'examen que vous rédigez, ou désactivez complètement la détection et analysez vous-même les caractéristiques exportées :

yaml
keystroke_logging:
  enabled: true
  detection:
    enabled: false

Les règles à seuil peuvent être rendues inatteignables en fixant une coupure absurde, par exemple implausible_speed.chars_per_min: 1000000.

Intervention en temps réel

yaml
keystroke_logging:
  detection:
    on_external_insert: flag   # allow | warn | block | flag
ValeurComportement
allowNe rien faire au-delà de l'enregistrement
warnAvis non bloquant sur collage externe, mais pas sur les auto-citations ni les citations du passage
blockEmpêche le collage et le dépôt dans les champs instrumentés
flagPar défaut. Enregistre en silence ; vous déciderez plus tard

block est un instrument grossier. Il bloque aussi les citations légitimes, et un participant déterminé peut retaper le texte. Utiliser flag puis relire vaut en général mieux.

Tableau de bord d'administration

Le panneau Processus de rédaction, sous l'onglet Comportemental du tableau de bord d'administration, affiche les médianes par annotateur, les taux de collage, les taux d'insertion silencieuse et chaque session signalée avec ses preuves.

Il rapporte writing_process_risk, la part des sessions d'un utilisateur ayant déclenché chaque signalement, pondérée vers les signaux dont l'explication innocente est la moins probable. C'est une aide au classement, délibérément tenue à l'écart du suspicion_score existant pour qu'aucun des deux nombres ne modifie en silence le sens de l'autre.

Fondements de recherche

Chaque citation ci-dessous est vérifiée dans le registre Crossref ou DataCite.

Crossley, Tian, Choi, Holmes et Morris (2024) ont recueilli 500 essais argumentatifs, les ont fait recopier par d'autres participants, et ont séparé l'authentique du recopié avec 99 % d'exactitude au moyen d'une forêt aléatoire (96 à 98 % pour les autres modèles). Leurs familles de caractéristiques sont celles que Potato capte : temps de pause avant les phrases et les mots, nombre d'insertions et de suppressions, rapports produit/processus, rafales, révision et variance du processus. Leur résultat est la cible de conception. L'écriture authentique montre des pauses plus longues, davantage d'insertions et de suppressions, et une variance plus grande ; la transcription est linéaire et procède par rafales.

Deane, Zhang, Hao et Li, et séparément Zhang, Feng, He, Li et Zhu, confirment de façon indépendante la séparation entre recopie et écriture naturelle, les seconds avec un modèle d'apprentissage profond. Asher, Gold, Chen et Carvalho traitent le cas propre au crowdsourcing : un outil de frappe sur Prolific qui signale les participants qui collent dans les champs de réponse ou dont le nombre de frappes est anormalement bas au regard de la longueur de leur réponse.

Pour les mesures de processus sous-jacentes, voir Leijten et Van Waes (Inputlog) pour les mesures de journal standard, Chenoweth et Hayes pour la notion de rafale, Conijn, Roeser et van Zaanen pour la dépendance des caractéristiques de frappe à la tâche, et Roeser, De Maeyer, Leijten et Van Waes pour les raisons du biais des seuils de pause fixes.

Références

  1. Crossley, S., Tian, Y., Choi, J. S., Holmes, L., & Morris, W. (2024). Plagiarism Detection Using Keystroke Logs. EDM 2024 (Short Papers). doi:10.5281/zenodo.12729864
  2. Deane, P., Zhang, M., Hao, J., & Li, C. Using Keystroke Dynamics to Detect Nonoriginal Text. Journal of Educational Measurement, 63(1). doi:10.1111/jedm.12431
  3. Asher, M. W., Gold, G., Chen, E., & Carvalho, P. F. (2026). Chatbots Are Undermining Crowdsourced Research in the Behavioral Sciences: Detecting Artificial Intelligence-Assisted Cheating With a Keystroke-Based Tool. Advances in Methods and Practices in Psychological Science, 9(1). doi:10.1177/25152459261424723
  4. Zhang, M., Feng, L., He, X., Li, C., & Zhu, M. (2026). Disentangling copy typing and natural writing behaviors using keystroke logs and deep learning model. Assessing Writing. doi:10.1016/j.asw.2026.101070
  5. Leijten, M., & Van Waes, L. (2013). Keystroke Logging in Writing Research: Using Inputlog to Analyze and Visualize Writing Processes. Written Communication, 30(3), 358-392. doi:10.1177/0741088313491692
  6. Chenoweth, N. A., & Hayes, J. R. (2001). Fluency in Writing: Generating Text in L1 and L2. Written Communication, 18(1), 80-98. doi:10.1177/0741088301018001004
  7. Conijn, R., Roeser, J., & van Zaanen, M. (2019). Understanding the keystroke log: the effect of writing task on keystroke features. Reading and Writing, 32(9), 2353-2374. doi:10.1007/s11145-019-09953-8
  8. Roeser, J., De Maeyer, S., Leijten, M., & Van Waes, L. (2021). Modelling typing disfluencies as finite mixture process. Reading and Writing. doi:10.1007/s11145-021-10203-z
  9. Lee, M., Liang, P., & Yang, Q. (2022). CoAuthor: Designing a Human-AI Collaborative Writing Dataset for Exploring Language Model Capabilities. CHI 2022. doi:10.1145/3491102.3502030

Pour aller plus loin

Pour les détails d'implémentation, consultez la documentation source.