Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,12 @@ WATERMARKS_SERVER_API_KEY=
# WATERMARKS_SERVER_VERSION=

# ─── Vendor text-watermark detection ────────────────────────────
# Optional Google Gemini API key. When set, the service can run Google's
# official SynthID-text watermark detector via POST /detect and the
# detect_before / detect_after clean options. Env only — never on argv.
# Privacy: text is sent to Google only when this key is configured.
# Optional Google Gemini API key. Env only — never on argv. The Gemini
# SynthID-text detector is currently DISABLED: the generateContent API
# exposes no DETECT_TEXT_WATERMARK task type, so /capabilities always
# reports text_detectors.gemini-synthid-text as false and setting this key
# enables nothing today. Kept so the wiring is ready if the task type ships;
# text would then be sent to Google only when this key is configured.
# WATERMARKS_GEMINI_API_KEY=
# WATERMARKS_GEMINI_MODEL=gemini-2.5-flash
# WATERMARKS_GEMINI_TIMEOUT=30
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

<p align="center">
<a href="https://pypi.org/project/watermark-remover/"><img alt="PyPI" src="https://img.shields.io/pypi/v/watermark-remover?logo=pypi&logoColor=white&label=pypi&color=e8a33d&labelColor=0f1110"></a>
<a href="https://pepy.tech/project/watermark-remover"><img alt="Downloads" src="https://img.shields.io/pepy/dt/watermark-remover?logo=python&logoColor=white&label=downloads&color=e8a33d&labelColor=0f1110"></a>
<a href="https://pypi.org/project/watermark-remover/"><img alt="Python 3.10+" src="https://img.shields.io/badge/python-3.10%2B-e8a33d?logo=python&logoColor=white&labelColor=0f1110"></a>
<a href="https://github.com/PyModel/watermark-remover/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/PyModel/watermark-remover/actions/workflows/ci.yml/badge.svg"></a>
<a href="https://github.com/PyModel/watermark-remover/releases/latest"><img alt="Release" src="https://img.shields.io/github/v/release/PyModel/watermark-remover?sort=semver&display_name=tag&label=release&color=e8a33d&labelColor=0f1110"></a>
<a href="https://github.com/PyModel/watermark-remover/stargazers"><img alt="Stars" src="https://img.shields.io/github/stars/PyModel/watermark-remover?label=stars&color=e8a33d&labelColor=0f1110"></a>
<a href="https://github.com/PyModel/watermark-remover/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
<a href="https://hits.sh/github.com/PyModel/watermark-remover/"><img alt="Visitors" src="https://hits.sh/github.com/PyModel/watermark-remover.svg?label=visitors&color=e8a33d&labelColor=0f1110"></a>
<a href="https://pypi.org/project/watermark-remover/"><img alt="Python 3.10+" src="https://img.shields.io/badge/python-3.10%2B-30363d?logo=python&logoColor=white&labelColor=0f1110"></a>
<a href="https://pepy.tech/project/watermark-remover"><img alt="Downloads" src="https://img.shields.io/pepy/dt/watermark-remover?logo=python&logoColor=white&label=downloads&color=30363d&labelColor=0f1110"></a>
<a href="https://github.com/PyModel/watermark-remover/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/PyModel/watermark-remover/ci.yml?logo=github&logoColor=white&label=ci&labelColor=0f1110"></a>
<a href="https://github.com/PyModel/watermark-remover/stargazers"><img alt="Stars" src="https://img.shields.io/github/stars/PyModel/watermark-remover?logo=github&logoColor=white&label=stars&color=30363d&labelColor=0f1110"></a>
<a href="https://github.com/PyModel/watermark-remover/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-30363d?labelColor=0f1110"></a>
<a href="https://hits.sh/github.com/PyModel/watermark-remover/"><img alt="Visitors" src="https://hits.sh/github.com/PyModel/watermark-remover.svg?label=visitors&color=30363d&labelColor=0f1110"></a>
</p>

Tools for finding and removing AI provenance signals from files you own. Four channels are covered: hidden Unicode in text, statistical token watermarks, visible marks burned into images, and metadata such as C2PA, EXIF, and XMP.
Expand Down Expand Up @@ -296,7 +296,8 @@ Best-effort pixel-domain removal is opt-in on image cleans: `--remove-synthid` (
Optional, stdlib-first, fail-soft:

- `score_stylometry.py` — zero-LLM stylometry (burstiness, MATTR, AI-phrase density) with confidence bands and `--explain`.
- `text_detectors.py` / `detect_text_watermark.py` — Gemini's official SynthID-text detector (needs `WATERMARKS_GEMINI_API_KEY`; env only) and a MarkLLM research harness (same-scheme-config only, not a vendor oracle). Claude detection is reserved but unavailable until a public API ships.
- `text_detectors.py` / `detect_text_watermark.py` — a MarkLLM research harness (same-scheme-config only, not a vendor oracle). Both vendor detectors are reserved but unavailable, and `/capabilities` always reports them `false`: Gemini's official SynthID-text detector is wired for `WATERMARKS_GEMINI_API_KEY` (env only) but the Gemini API exposes no `DETECT_TEXT_WATERMARK` task type, and Claude detection waits on a public API.
- MarkLLM detection reports a document-level `verdict` (`DETECTED`, `NOT_DETECTED`, `INCONCLUSIVE`, `UNSUPPORTED`, `ERROR`) alongside the raw `detector_verdict`. Only a below-threshold score with a confirmed key/provenance match and enough scored tokens reads as `NOT_DETECTED`; unknown provenance, a near-threshold score, or a short sample produces `INCONCLUSIVE`. An unsupported scheme produces `UNSUPPORTED`, and a detector result that cannot be scored produces `ERROR`. Provenance comes from the `<output>.wm.json` sidecar the `watermark` subcommand writes, or from an operator `--key-id` assertion.
- `inspect_text.py --stylometry` and `rewrite_text.py` MarkLLM before/after hooks.

```bash
Expand Down
4 changes: 2 additions & 2 deletions compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ services:
environment:
# Empty by default (no auth). Set to require `Authorization: Bearer <key>`.
WATERMARKS_SERVER_API_KEY: ${WATERMARKS_SERVER_API_KEY:-}
# Optional Gemini API key enabling vendor SynthID-text watermark
# detection via /detect and detect_before/after (see .env.example).
# Optional Gemini API key. The vendor SynthID-text detector is
# currently disabled and this key enables nothing (see .env.example).
WATERMARKS_GEMINI_API_KEY: ${WATERMARKS_GEMINI_API_KEY:-}
WATERMARKS_GEMINI_MODEL: ${WATERMARKS_GEMINI_MODEL:-}
# Optional SynthID image scorer sidecar (heavy profile).
Expand Down
26 changes: 19 additions & 7 deletions skills/remove-ai-marks/references/service-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ field and writes it to the output path itself.
| GET | `/health` | — | `{"ok": true, "version": ...}` |
| GET | `/capabilities` | — | optional tools / backends present |
| GET | `/openapi.json` | — | dynamically generated OpenAPI 3.0.3 spec |
| POST | `/inspect` | `{"file": "<base64>", "name": "notes.md"}` | `{"ok", "kind", "suspicious", "report"}` |
| POST | `/inspect` | `{"file": "<base64>", "name": "notes.md", "detect": true}` | `{"ok", "kind", "suspicious", "detection_status", "report"}` |
| POST | `/detect` | `{"file": "<base64>", "name": "notes.txt"}` | `{"ok", "kind", "detections": [...]}` |
| POST | `/clean` | `{"file": "<base64>", "name": "notes.md", "options": {...}}` | `{"ok", "kind", "cleaned": "<base64>", "report"}` |

Expand All @@ -61,6 +61,15 @@ unrecognized formats answer `kind: "unknown"` (`/inspect`) or 400 (`/clean`).
When writing a temp file for pasted text, keep a known extension (`.txt` /
`.md`) in the `name` you send.

For `/inspect`, `detection_status` is `DETECTED`, `INCONCLUSIVE`,
`NOT_DETECTED`, or `NOT_RUN`. `INCONCLUSIVE` means an available detector ran but
could not rule out a watermark; it sets `suspicious: true` conservatively but is
not a confirmed detection. A configured detector that ran and failed (timeout,
crash, unreadable output) also aggregates to `INCONCLUSIVE`, never `NOT_RUN`.
`NOT_RUN` means detection was not requested or no detector was configured.
Pass `"detect": true` only with consent when a configured vendor detector may
send text to its provider.

The machine-readable contract lives at `$WM/openapi.json` — plug it into any
OpenAPI tooling instead of hand-rolling clients.

Expand Down Expand Up @@ -92,15 +101,18 @@ default unless the user asked in-place) and summarize `report` honestly.

## Watermark detection before/after (when configured)

When `/capabilities` reports a vendor detector (`text_detectors.gemini-synthid-text`)
or an image scorer (`scorers.synthid_http` / `scorers.synthid`), measure the
When `/capabilities` reports a text detector (`text_detectors.markllm`) or an
image scorer (`scorers.synthid_http` / `scorers.synthid`), measure the
result by detecting before and after cleaning — either `POST /detect` or fold
it into the clean with `{"options": {"detect_before": true, "detect_after": true}}`
(returns `text_detectors.before/after` for text or `synthid_before/after` for
images). Vendor detection sends text to the configured provider (Gemini) —
only use it with user consent, and report the vendor's verdict honestly
(Gemini = Google's official SynthID-text detector; MarkLLM is same-config-only
research; Claude's detector is not public yet).
images). MarkLLM is same-config-only research, not a vendor oracle; report its
verdict honestly.

No vendor text detector is reachable today: `text_detectors.gemini-synthid-text`
and `text_detectors.claude-text` always report `false` in `/capabilities` (see
the detector list in the README). If one does become available, it sends text
to that provider — only use it with explicit user consent.

## Aggregate audits (directories / websites)

Expand Down
Loading