l’Almanet doLys Gnu/Linux – Open Source – Entreprises › Forums › L’almanet doLys Open Source › [Tuto] Watermarks IA : nettoyer les filigranes et réécrire localement un texte avec Ollama
Mots-clés : Arch Linux, caractères Unicode invisibles, confidentialité, docker, EndeavourOS, filigranes IA, Gemma, linux, LLM local, Ministral, nettoyage document IA, nettoyage métadonnées, Ollama, paraphrase locale, Qwen, réécriture locale, suppression watermark, tokens IA, watermark statistique, watermark texte IA, watermarks IA, watermarks-remover, xfce, YAD
- This topic is empty.
- AuteurArticles
- août 20, 2026 à 6:58 pm #13338
Le terme watermark signifie littéralement filigrane.
Dans un document classique, un filigrane peut être visible, comme un texte ou un logo placé en arrière-plan d’une page. Dans le contexte des contenus générés par IA, le mot watermark peut désigner des mécanismes beaucoup moins visibles.
On peut notamment rencontrer :
- des caractères Unicode invisibles ou inhabituels ;
- des métadonnées ajoutées au fichier ;
- des informations de provenance ;
- des structures particulières dans le document ;
- des signaux statistiques intégrés à la génération même du texte, par exemple dans la succession et le choix des tokens.
Ces différents mécanismes sont souvent regroupés sous le terme de watermarks IA, ou filigranes IA en français, même s’ils ne ressemblent pas nécessairement à un filigrane graphique traditionnel.
Le but de ce tutoriel est donc de disposer de deux outils distincts :
wr-clean fichier.mdpour nettoyer les filigranes ou marques déterministes que l’on peut directement retirer du fichier, et :
wr-rewrite-guipour effectuer une véritable réécriture locale avec Ollama lorsqu’on souhaite également perturber un éventuel watermark statistique lié au choix des tokens.
Il est important de distinguer ces deux familles.
Un caractère Unicode invisible ou une métadonnée peut être détecté puis supprimé sans toucher au texte lui-même.
Un watermark statistique fonctionne différemment. Il peut être lié à la manière dont le modèle choisit successivement ses mots ou ses tokens. Dans ce cas, il n’existe pas nécessairement une chaîne cachée qu’il suffirait d’effacer. Il faut modifier suffisamment la formulation du texte pour produire une nouvelle succession de tokens.
C’est précisément la différence entre le nettoyage effectué par
wr-cleanet la réécriture effectuée avec Ollama.Tout le traitement présenté ici reste local sur la machine.
1. Principe de l’installation
Nous allons utiliser :
- Docker ;
- Ollama ;
- le projet
watermarks-remover; curletjq;- YAD pour l’interface graphique ;
- deux petits wrappers placés dans
~/.local/bin.
L’installation finale sera organisée ainsi :
~/.local/bin/ ├── wr-clean └── wr-rewrite-gui ~/Bureau/ └── wr-rewrite.desktopLe nettoyage déterministe sera réalisé par
watermarks-removerdans Docker.La réécriture sera réalisée directement par Ollama installé sur la machine.
2. Installer les dépendances sous EndeavourOS
Sous EndeavourOS ou Arch Linux :
sudo pacman -S --needed \ git \ docker \ docker-compose \ python \ curl \ jq \ yad \ ollamaOn active Docker :
sudo systemctl enable --now dockerEt Ollama :
sudo systemctl enable --now ollamaPour pouvoir utiliser Docker sans
sudo:sudo usermod -aG docker "$USER"Il faut ensuite fermer puis rouvrir la session utilisateur pour que le nouveau groupe soit pris en compte.
On peut vérifier :
docker --version ollama --version3. Récupérer le projet watermarks-remover
Créons un emplacement propre pour les sources :
mkdir -p ~/.local/src cd ~/.local/srcPuis clonons le dépôt :
git clone https://github.com/guillaumemeyer/watermarks-remover.gitOn obtient :
~/.local/src/watermarks-remover/Pour mettre le dépôt à jour plus tard :
cd ~/.local/src/watermarks-remover git pullLe projet contient notamment des scripts destinés à inspecter, nettoyer et réécrire les fichiers.
Dans l’image Docker utilisée ici, on retrouve par exemple :
/app/scripts/inspect_file.py /app/scripts/clean_file.py /app/scripts/rewrite_text.py4. Installer watermarks-remover avec Docker
On récupère l’image :
docker pull ghcr.io/guillaumemeyer/watermarks-remover:latestPuis on crée le conteneur en exposant son API uniquement en local :
docker run -d \ --name watermarks-remover \ --restart unless-stopped \ -p 127.0.0.1:8765:8765 \ ghcr.io/guillaumemeyer/watermarks-remover:latestVérification :
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Ports}}'On doit obtenir une ligne proche de :
watermarks-remover ghcr.io/guillaumemeyer/watermarks-remover:latest 127.0.0.1:8765->8765/tcpQuelques commandes utiles :
docker stop watermarks-remover docker start watermarks-remover docker logs watermarks-removerPour mettre l’image à jour :
docker pull ghcr.io/guillaumemeyer/watermarks-remover:latest5. Créer la commande wr-clean
Nous allons placer le script dans :
~/.local/bin/wr-cleanCréation :
mkdir -p ~/.local/bin cat > ~/.local/bin/wr-clean <<'EOF' #!/usr/bin/env bash # wr-clean : nettoie un fichier via watermarks-remover set -euo pipefail API="http://127.0.0.1:8765/clean" if [[ $# -lt 1 ]]; then echo "Usage: wr-clean <fichier> [fichier_sortie]" echo echo "Exemples :" echo " wr-clean draft.md" echo " wr-clean photo.png photo.cleaned.png" echo " wr-clean notes.docx notes.propre.docx" exit 1 fi INPUT="$1" if [[ ! -f "$INPUT" ]]; then echo "Erreur : $INPUT n'existe pas" exit 1 fi if [[ $# -ge 2 ]]; then OUTPUT="$2" elif [[ "$INPUT" == *.* ]]; then OUTPUT="${INPUT%.*}.cleaned.${INPUT##*.}" else OUTPUT="${INPUT}.cleaned" fi echo "→ Nettoyage de $INPUT ..." PAYLOAD=$( jq -n \ --arg file "$(base64 -w0 "$INPUT")" \ --arg name "$(basename "$INPUT")" \ '{file:$file, name:$name}' ) RESULT=$( curl -sS \ -X POST "$API" \ -H 'Content-Type: application/json' \ -d "$PAYLOAD" ) if printf '%s' "$RESULT" | jq -e '.ok == true' >/dev/null; then printf '%s' "$RESULT" | jq -r '.cleaned' | base64 -d > "$OUTPUT" echo "✓ Fichier nettoyé → $OUTPUT" else echo "Erreur :" printf '%s' "$RESULT" | jq . exit 1 fi EOF chmod +x ~/.local/bin/wr-cleanVérifions que le script est bien trouvé :
command -v wr-cleanOn doit normalement obtenir quelque chose comme :
/home/utilisateur/.local/bin/wr-clean6. Utiliser wr-clean
Pour un fichier Markdown :
wr-clean document.mdLe script crée automatiquement :
document.cleaned.mdOn peut également préciser le nom de sortie :
wr-clean document.md document.propre.mdAvec une image :
wr-clean photo.pngAvec un document Word :
wr-clean notes.docx notes.propre.docxLe fichier original reste intact.
Un point important : le message :
✓ Fichier nettoyésignifie que le traitement s’est correctement déroulé.
Cela ne signifie pas nécessairement que quelque chose a effectivement été supprimé.
Pour vérifier si le fichier a été modifié :
cmp -s document.md document.cleaned.md \ && echo "Fichiers identiques" \ || echo "Le fichier a été modifié"Si les deux fichiers sont identiques, cela signifie simplement que le nettoyage déterministe n’a trouvé aucune marque à retirer.
7. Pourquoi wr-clean ne suffit pas toujours
Un watermark statistique n’est pas nécessairement stocké dans un caractère caché ou dans une métadonnée.
Il peut résulter du choix probabiliste des tokens effectué pendant la génération.
Imaginons qu’un modèle dispose de plusieurs mots possibles pour continuer une phrase.
Un mécanisme de watermark peut favoriser certaines familles de tokens plutôt que d’autres selon une règle déterminée pendant la génération.
Le texte reste parfaitement lisible.
Il n’y a alors aucun caractère particulier à supprimer.
Pour perturber ce type de signal, l’une des approches possibles consiste à produire une nouvelle formulation du texte avec un autre modèle.
C’est le rôle de notre seconde commande.
8. Installer les modèles Ollama
Sur une machine équipée de 16 Go de RAM, trois modèles raisonnables peuvent être utilisés :
ollama pull qwen3.5:9b ollama pull ministral-3:8b ollama pull gemma4:12bOn vérifie :
ollama listDans mes essais sur un Ryzen 5 5600H avec 16 Go de RAM :
qwen3.5:9b environ 59 secondes ministral-3:8b environ 66 secondes gemma4:12b environ 4 min 24 spour une petite réécriture réalisée avec un modèle chargé à froid.
qwen3.5:9bconstitue donc ici le meilleur compromis entre qualité et vitesse.9. Tester Ollama directement
On peut créer un petit texte de test :
cat >/tmp/rewrite-test.txt <<'EOF' Réécris ce texte en français naturel en modifiant nettement la formulation, l'ordre des propositions et les connecteurs, sans modifier les informations. Réponds uniquement avec le texte réécrit. Je tiens d'abord à saluer la qualité de votre synthèse. Elle est claire, documentée, et les questions que vous posez sont bien posées. EOFPuis tester Qwen :
time curl -s http://127.0.0.1:11434/api/chat \ -H 'Content-Type: application/json' \ -d "$(jq -n \ --arg model 'qwen3.5:9b' \ --arg prompt "$(cat /tmp/rewrite-test.txt)" \ '{ model:$model, messages:[{role:"user",content:$prompt}], think:false, stream:false, keep_alive:0 }')" \ | jq -r '.message.content'Deux options importantes apparaissent ici :
"think": falseet :
"keep_alive": 0think:falsedésactive le raisonnement lorsque le modèle le prend en charge.Pour une simple réécriture, cela évite de perdre du temps dans une phase de raisonnement inutile.
keep_alive:0demande à Ollama de décharger le modèle une fois le traitement terminé.C’est pratique sur une machine disposant de 16 Go de RAM.
10. Créer l’interface graphique wr-rewrite-gui
On place là encore le script dans :
~/.local/bin/Création :
cat > ~/.local/bin/wr-rewrite-gui <<'EOF' #!/usr/bin/env bash set -u TITLE="Watermark Rewriter" OLLAMA_URL="http://127.0.0.1:11434" LOGFILE="$HOME/.local/state/wr-rewrite.log" mkdir -p "$(dirname "$LOGFILE")" log() { echo "[wr-rewrite] $(date '+%Y-%m-%d %H:%M:%S') $*" \ >> "$LOGFILE" 2>/dev/null || true } error_box() { yad \ --error \ --center \ --width=600 \ --title="$TITLE" \ --text="$1" } for cmd in yad curl jq; do command -v "$cmd" >/dev/null 2>&1 || { echo "$cmd est requis" exit 1 } done if ! curl -sf "$OLLAMA_URL/api/tags" >/dev/null 2>&1; then error_box "Ollama ne répond pas sur $OLLAMA_URL" exit 1 fi CHOICE=$( yad \ --title="$TITLE" \ --center \ --width=720 \ --height=430 \ --form \ --separator="|" \ --text="<big><b>Réécriture locale</b></big> Réécriture via Ollama avec raisonnement désactivé." \ --field="Fichier:FL" "$HOME/Bureau/" \ --field="Modèle:CB" \ "qwen3.5:9b!ministral-3:8b!gemma4:12b" \ --field="Méthode:CB" \ "paraphrase!humanize" \ --field="Température:NUM" \ "0.7!0.1..1.2!0.1" \ --button="Annuler":1 \ --button="Réécrire":0 ) [ $? -ne 0 ] && exit 0 IFS='|' read -r INPUT MODEL STRENGTH TEMPERATURE _ <<< "$CHOICE" if [ ! -f "$INPUT" ]; then error_box "Fichier introuvable : $INPUT" exit 1 fi case "$STRENGTH" in paraphrase) INSTRUCTION="Réécris le texte suivant en français naturel en utilisant une formulation nettement différente au niveau lexical et syntaxique. Modifie l'ordre des propositions lorsque cela reste naturel, varie les connecteurs, la longueur des phrases et les tournures. Préserve strictement tous les faits, nombres, noms, dates, références et affirmations. N'ajoute ni ne retire aucune information. Réponds uniquement avec le texte réécrit." ;; humanize) INSTRUCTION="Réécris le texte suivant comme s'il avait été rédigé naturellement à partir de zéro. Varie le rythme, la longueur des phrases, les formulations et les transitions. Préserve strictement tous les faits, nombres, noms, dates, références et affirmations. N'ajoute ni ne retire aucune information. Réponds uniquement avec le texte réécrit." ;; esac if [[ "$INPUT" == *.* ]]; then OUTPUT="${INPUT%.*}.rewritten.${INPUT##*.}" else OUTPUT="${INPUT}.rewritten" fi PROMPT="$INSTRUCTION --- $(cat "$INPUT")" log "input=$INPUT model=$MODEL strength=$STRENGTH output=$OUTPUT" TMP_RESPONSE=$(mktemp) TMP_ERROR=$(mktemp) START=$(date +%s) ( echo "10" echo "# Chargement de $MODEL..." curl -sS \ --max-time 1800 \ "$OLLAMA_URL/api/chat" \ -H 'Content-Type: application/json' \ -d "$( jq -n \ --arg model "$MODEL" \ --arg prompt "$PROMPT" \ --argjson temperature "$TEMPERATURE" \ '{ model: $model, messages: [ { role: "user", content: $prompt } ], think: false, stream: false, keep_alive: 0, options: { temperature: $temperature } }' )" \ > "$TMP_RESPONSE" \ 2> "$TMP_ERROR" if [ $? -ne 0 ]; then echo "FAIL" > "${TMP_RESPONSE}.status" exit fi echo "85" echo "# Écriture du résultat..." jq -r '.message.content // empty' "$TMP_RESPONSE" > "$OUTPUT" if [ ! -s "$OUTPUT" ]; then echo "FAIL" > "${TMP_RESPONSE}.status" exit fi echo "OK" > "${TMP_RESPONSE}.status" echo "100" echo "# Terminé" ) | yad \ --progress \ --title="$TITLE" \ --center \ --width=520 \ --auto-close \ --no-buttons \ --text="Réécriture en cours..." END=$(date +%s) DURATION=$((END - START)) STATUS=$(cat "${TMP_RESPONSE}.status" 2>/dev/null || echo FAIL) if [ "$STATUS" != "OK" ]; then ERR=$(cat "$TMP_ERROR" 2>/dev/null) error_box "La réécriture a échoué. ${ERR:-Réponse Ollama invalide.}" rm -f \ "$TMP_RESPONSE" \ "$TMP_ERROR" \ "${TMP_RESPONSE}.status" exit 1 fi rm -f \ "$TMP_RESPONSE" \ "$TMP_ERROR" \ "${TMP_RESPONSE}.status" MIN=$((DURATION / 60)) SEC=$((DURATION % 60)) yad \ --title="$TITLE" \ --center \ --width=620 \ --text="<big><b>Réécriture terminée</b></big> <b>Modèle :</b> $MODEL <b>Méthode :</b> $STRENGTH <b>Durée :</b> ${MIN} min ${SEC} s <b>Sortie :</b> $OUTPUT" \ --button="Ouvrir le dossier":2 \ --button="Ouvrir le fichier":3 \ --button="Fermer":0 case $? in 2) xdg-open "$(dirname "$OUTPUT")" >/dev/null 2>&1 & ;; 3) xdg-open "$OUTPUT" >/dev/null 2>&1 & ;; esac exit 0 EOF chmod +x ~/.local/bin/wr-rewrite-guiOn peut lancer directement l’interface :
wr-rewrite-gui11. Ce que propose l’interface
La fenêtre permet de sélectionner :
Fichier Modèle Méthode TempératureLes modèles disponibles dans notre configuration sont :
qwen3.5:9b ministral-3:8b gemma4:12bDeux modes sont proposés :
paraphrase humanizeLe mode
paraphrasecherche surtout à modifier fortement le vocabulaire et la structure syntaxique.Le mode
humanizeprivilégie une rédaction plus naturelle et moins mécanique.Le fichier original n’est jamais écrasé.
Par exemple :
document.mdproduira :
document.rewritten.md12. Ajouter un lanceur XFCE sur le Bureau
Pour éviter de lancer la commande depuis un terminal, on peut créer un raccourci sur le Bureau.
Sur une installation française d’XFCE :
cat > ~/Bureau/wr-rewrite.desktop <<EOF [Desktop Entry] Version=1.0 Type=Application Name=Watermark Rewriter Comment=Réécriture locale via Ollama Exec=$HOME/.local/bin/wr-rewrite-gui Icon=accessories-text-editor Terminal=false Categories=Utility; StartupNotify=true EOF chmod +x ~/Bureau/wr-rewrite.desktopOn obtient alors une icône :
Watermark Rewriterdirectement sur le Bureau.
XFCE peut demander d’autoriser le lanceur lors de sa première utilisation.
13. Organisation finale
L’installation ressemble finalement à ceci :
~/.local/src/ └── watermarks-remover/ ~/.local/bin/ ├── wr-clean └── wr-rewrite-gui ~/Bureau/ └── wr-rewrite.desktopAvec côté services :
Docker └── watermarks-remover └── 127.0.0.1:8765et :
Ollama ├── qwen3.5:9b ├── ministral-3:8b └── gemma4:12b14. Les deux opérations en pratique
Pour nettoyer les marques directement présentes dans le fichier :
wr-clean document.mdRésultat :
document.cleaned.mdPour effectuer une véritable réécriture :
wr-rewrite-guiRésultat :
document.rewritten.mdLes deux opérations sont donc différentes :
document.md | +--> wr-clean | | | +--> document.cleaned.md | +--> wr-rewrite-gui | +--> Ollama | +--> document.rewritten.md15. Nettoyer également le texte après réécriture
On peut aller un peu plus loin.
Après une réécriture par Ollama :
document.rewritten.mdon peut repasser le résultat dans
wr-clean:wr-clean document.rewritten.mdCela produit :
document.rewritten.cleaned.mdLa chaîne complète devient alors :
texte original | v réécriture Ollama | v nouvelle succession de tokens | v nettoyage déterministe | v fichier finalCela permet de combiner les deux approches sans les confondre.
16. Vérifier la mémoire utilisée par Ollama
Pour savoir si un modèle est actuellement chargé :
ollama psGrâce à :
"keep_alive": 0le modèle doit normalement être déchargé à la fin de la réécriture.
On peut également arrêter manuellement un modèle :
ollama stop qwen3.5:9b17. Nettoyer sa bibliothèque Ollama
Avec 16 Go de RAM, il est inutile d’accumuler de nombreux gros modèles ayant le même usage.
Lister les modèles :
ollama listSupprimer un modèle :
ollama rm nom-du-modelePar exemple :
ollama rm ancien-modele:7bLes modèles peuvent être retéléchargés plus tard avec :
ollama pull nom-du-modele18. Limites à garder en tête
Il faut distinguer une suppression déterministe d’une tentative de perturbation statistique.
Avec un caractère Unicode invisible, on peut généralement dire précisément :
ce caractère était présentpuis :
il a été suppriméAvec un watermark statistique propriétaire, la situation est différente.
Si l’algorithme de détection, les paramètres ou les clés ne sont pas publics, on ne dispose pas forcément d’un moyen de mesurer directement le signal avant et après la réécriture.
La réécriture doit donc être comprise comme une méthode de modification profonde de la succession des tokens, pas comme une certification universelle.
19. Pourquoi faire tout cela en local ?
L’intérêt principal de cette installation est aussi ailleurs.
Un document potentiellement confidentiel reste sur l’ordinateur :
document | +--> Docker local | +--> Ollama localIl n’est pas nécessaire de l’envoyer vers un site de paraphrase ou un service de nettoyage en ligne.
On garde également :
- le fichier original ;
- le contrôle sur le modèle utilisé ;
- le contrôle sur la température ;
- les logs locaux ;
- la possibilité d’inspecter les scripts ;
- une séparation claire entre nettoyage et réécriture.
Conclusion
Les watermarks IA, ou filigranes IA, ne désignent pas une seule technologie.
Certains sont directement présents dans les fichiers et peuvent être nettoyés de manière déterministe.
D’autres peuvent être liés à la façon dont un modèle génère successivement ses tokens.
Dans notre installation :
wr-cleans’occupe du premier cas, tandis que :
wr-rewrite-guiutilise un autre modèle local pour produire une nouvelle rédaction.
Avec Docker, Ollama et deux petits scripts dans
~/.local/bin, on obtient ainsi une chaîne de traitement locale, relativement simple à utiliser et entièrement sous notre contrôle.Un jeune site que j'aime bien, la ferrari du T-shirt ...bio en plus : GoudronBlanc
- AuteurArticles
- Vous devez être connecté pour répondre à ce sujet.