Detect PII in text, substitute it with stable sentinels (<PERSON_1>,
<EMAIL_2>, ...), send the redacted text to any LLM, and restore the
originals on the way back, including in streamed responses. The package
is framework-agnostic and ships a drop-in openai client wrapper for
zero-effort integration.
See the monorepo README for the cross-language overview and architecture.
Install
uv add gheim # core: pairs with a RemoteDetector or GHEIM_API_KEY
uv add "gheim[local]" # + torch and transformers for on-device detection
uv add "gheim[openai]" # + drop-in OpenAI client
uv add "gheim[local,openai]" # both
Model choice
LocalDetector runs a token-classification model in process. The
package's default model is
joelbarmettler/gheim-ch-560m
— a 560M xlm-roberta-large fine-tune optimised for Swiss-market PII
(test strict F1 0.910, char F1 0.946 on Swiss text, see
MODEL_CARD.md).
Any HuggingFace token-classification model that emits the same 33-class
BIOES schema can be substituted via the model_id constructor arg.
| Model | Best for | Parameters | Notes |
|---|---|---|---|
joelbarmettler/gheim-ch-560m (default) |
Production / commercial. Swiss court / parliament / web text with CH-format account numbers (IBAN, AHV, VAT-CHE) | 560M | Apache 2.0. Test strict F1 0.910, char F1 0.946. |
joelbarmettler/gheim-ch-560m-research |
Research / non-commercial. Stronger cross-domain transfer on Swiss-news text (swissner PER char F1 0.90 vs 0.70 on the default) | 560M | CC BY-NC-SA 4.0 + Reuters research-only rider. In-distribution numbers identical to the default. |
openai/privacy-filter |
English-first or general use, long-context (up to 128k tokens) | 1.4B (50M active, MoE) | Apache 2.0. Wider language coverage, larger weights. |
from gheim import LocalDetector
# Default — Swiss-tuned, 560M, Apache 2.0:
det = LocalDetector()
# Stronger cross-domain transfer (research, non-commercial):
det = LocalDetector(model_id="joelbarmettler/gheim-ch-560m-research")
# Alternative for English or general use:
det = LocalDetector(model_id="openai/privacy-filter")
Drop-in OpenAI client
from gheim.openai import OpenAI
client = OpenAI() # same constructor args as openai.OpenAI
r = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hi, my name is Joel"}],
)
# r.choices[0].message.content contains "Joel".
# OpenAI only ever saw "<PERSON_1>".
Custom endpoint or key (e.g. OpenRouter, local vLLM):
client = OpenAI(api_key="sk-or-...", base_url="https://openrouter.ai/api/v1")
Streaming:
stream = client.chat.completions.create(..., stream=True)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="", flush=True)
Async:
from gheim.openai import AsyncOpenAI
client = AsyncOpenAI()
r = await client.chat.completions.create(...)
Per-call overrides:
from gheim import Session
session = Session() # reuse across calls for multi-turn coherent sentinels
r = client.chat.completions.create(
model="gpt-4o",
messages=[...],
gheim_session=session, # or gheim_detector=...
)
Framework-agnostic
from gheim import Session, LocalDetector, anonymize_text, deanonymize_text
session = Session(detector=LocalDetector()) # gheim-ch-560m by default
clean = anonymize_text("Hi, my name is Joel", session)
# ... call any LLM with clean ...
final = deanonymize_text(response_text, session)
Streaming deanonymizer:
from gheim import deanonymize_stream
for chunk in deanonymize_stream(my_chunk_iterator, session):
print(chunk, end="", flush=True)
Chat-message helpers:
from gheim import anonymize_messages
redacted = anonymize_messages(messages, session) # preserves role, name, tool_call_id
Wrapped endpoints
The drop-in OpenAI / AsyncOpenAI clients automatically protect every
text-carrying endpoint: chat.completions, responses, completions (legacy),
embeddings, moderations, audio.speech, audio.transcriptions,
audio.translations, images.generate, images.edit. Tool-call arguments and
SSE delta chunks are restored on the way back. See the
monorepo README for the full
coverage matrix and the embeddings caveat.
Strict mode
gheim_strict=True (default) raises RuntimeError if you call an unwrapped
endpoint (beta.assistants, batches, files, uploads, fine_tuning,
vector_stores). The error message names client.raw.<path> as the documented
escape hatch.
client = OpenAI(gheim_strict=False) # downgrade to one-time warnings
client.raw.beta.assistants.create(...) # always works regardless of strict mode
Detector backends
import torch
from gheim import LocalDetector, RemoteDetector, default_detector
# Local inference. Weights download to the HF cache on first use.
# `model_id` defaults to "joelbarmettler/gheim-ch-560m"; pass
# `dtype=torch.bfloat16` for half-precision GPU inference.
det = LocalDetector(device="auto", dtype=torch.bfloat16)
# Remote inference against your own gheim-server or api.gheim.ch.
det = RemoteDetector(base_url="http://your-host:8080", api_key="...")
# default_detector() picks remote if GHEIM_API_KEY is set, else local.
det = default_detector()
Composite detector (recommended for production)
For categories where structure is verifiable by checksum (CH-IBAN, AHV,
VAT-CHE, credit cards, common token formats) the package ships a regex
catalogue under gheim.detectors.composite that pairs with the model
detector. The composite detector applies regex first, masks matched
spans, then runs the model on the remainder. This pushes effective
recall on account_number, private_phone, and private_url close
to 1.0 with high precision; the underlying ML model handles person
names, addresses, and dates.
Consulting
gheim is built and maintained by Souverana, a Swiss AI consulting business helping companies build secure, privacy-first AI systems — on-premise LLM deployments, PII/data-protection engineering, and Swiss-market NLP. If you need help integrating gheim or building compliant AI, get in touch at souverana.ch.
License
Apache 2.0. Bundled model weights are inherited from the upstream license of the model you select.
Metadata
Release files for gheim 0.1.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gheim-0.1.7.tar.gz | 42.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gheim-0.1.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 96.6 kB
Release files / gheim-0.1.7.tar.gz
| Download URL | gheim-0.1.7.tar.gz |
|---|---|
| Size | 42.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
38d795a32d92558888de6fb1856b249fb1237018d896333594e54f55418d0262
|
|
BLAKE2b-256 checksum How to use checksums |
04b4f2e9fb38b91fbdd7e27a9e92c8412e3fa7131448ca9dce82154493a7c0af
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 11, 2026.
Transparency logRelease files / gheim-0.1.7-py3-none-any.whl
| Download URL | gheim-0.1.7-py3-none-any.whl |
|---|---|
| Size | 54.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9375f6fd2f742d62faad0281f3b48ef95bdd52a0df3e92ccacb8b67dd038b241
|
|
BLAKE2b-256 checksum How to use checksums |
998b78c55f450d33cd69434d5fa43b0b9f05d1670c32ac02b2b3dbb1836a97d7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 11, 2026.
Transparency log