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
| Niveau | De quoi il s'agit | Données étiquetées nécessaires ? | Défaut |
|---|---|---|---|
| 1. Règles | Six signalements nommés, à seuils explicites et preuves visibles | Non | Activé |
| 2. Calibration | Seuils réajustés sur les annotateurs de votre propre projet | Non | Désactivé |
| 3. Supervisé | Un classifieur que vous entraînez sur vos propres étiquettes | Oui | Dé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étronomiquerevision_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
| Niveau | Signification |
|---|---|
ok | Aucun signalement déclenché |
review | Au moins un signalement de gravité review |
suspect | Au moins un signalement de gravité suspect |
Remplacer les seuils
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: 1000Les 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.
# 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.yamlkeystroke_logging:
detection:
calibrate: true # use the saved fitLa 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 :
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.
| Situation | Règle à laquelle cela ressemble | Comment Potato le traite |
|---|---|---|
| Citer le passage annoté | paste_dominant, silent_insertion, offscreen_composition | Neutralisé via paste_source: instance_text |
| Déplacer son propre brouillon | Les mêmes | Neutralisé via paste_source: self |
| Taper sur un téléphone ou une tablette | silent_insertion | Neutralisé via virtual_keyboard |
| Saisie non latine via un IME | silent_insertion | Neutralisé via composition_events |
| Dactylo rapide et fluide, jet propre | transcription_rhythm, implausible_speed | Règles conjonctives ; review et non suspect ; calibration |
| Réponses très courtes | transcription_rhythm | Ignorées en dessous de 80 caractères / 40 frappes |
| Dictée ou reconnaissance vocale | silent_insertion | Non traité. Sera signalé. Excluez ces annotateurs ou relevez le seuil. |
| Lecteurs d'écran et certaines technologies d'assistance | synthetic_input | Pas entièrement traité. Certains outils produisent des événements non fiables. |
| Correction automatique sur mobile | silent_insertion | En partie. insertReplacementText compte comme externe. |
| Extensions de navigateur, par exemple les correcteurs grammaticaux | silent_insertion, synthetic_input | Non 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 :
keystroke_logging:
enabled: true
detection:
enabled: falseLes 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
keystroke_logging:
detection:
on_external_insert: flag # allow | warn | block | flag| Valeur | Comportement |
|---|---|
allow | Ne rien faire au-delà de l'enregistrement |
warn | Avis non bloquant sur collage externe, mais pas sur les auto-citations ni les citations du passage |
block | Empêche le collage et le dépôt dans les champs instrumentés |
flag | Par 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- Journalisation des frappes - ce qui est capté et comment
- Éthique de la journalisation des frappes - IRB, consentement, droits des participants
- Contrôle de la qualité - contrôles d'attention et étalons
- Tableau de bord d'administration - le panneau Processus de rédaction
Pour les détails d'implémentation, consultez la documentation source.