kakushi 隠し
Japanese PII masking for LLM pipelines. Strip personal names, company names, phone numbers, emails, amounts, and my-numbers from Japanese business text before it leaves your server. Restore them in the model reply.
Live demo on HuggingFace Spaces · 日本語の説明
Why
You want to send a Japanese email, meeting note, or invoice to OpenAI / Anthropic / Gemini for summarisation, rewriting, or QA. The text contains customer names (田中太郎), company names (株式会社山田商事), deal amounts (¥1,500,000), and contact details. You don't want those bytes leaving your server.
kakushi gives you a three-line workaround.
from kakushi import mask, unmask
masked, mapping = mask(
"田中太郎様、株式会社山田商事の件で¥1,500,000の見積書を tanaka@example.co.jp にお送りします",
dictionary={"株式会社山田商事": "取引先A"}, # optional — pin sensitive names
)
# masked → "<PERSON_1>様、取引先Aの件で<AMOUNT_1>の見積書を <EMAIL_1> にお送りします"
# mapping → in-memory only. Never persisted.
reply = call_openai(masked) # your LLM call here
final = unmask(reply, mapping) # placeholders → originals
Install
pip install kakushi # regex layer only — fast, no model download
pip install kakushi[ner] # + GiNZA Japanese NER (person / org / location)
What gets caught
Three layers, lowest priority first.
- GiNZA NER —
PERSON,ORG,LOCATIONfrom the Japanese spaCy pipeline. - Regex — phone, postal code, email, my-number, yen amount, IPv4, driver's license, credit card, URL, contract / order numbers, and Japanese company names with
株式会社/合同会社/(株)markers. - Company dictionary (optional) —
{"株式会社山田商事": "取引先A"}. Highest priority. The value can beNone, in which case kakushi auto-assigns<COMPANY_DICT_N>.
Overlapping spans are resolved with priority dict > regex > NER, with the longer span winning at the same priority.
Recall on synthetic corpus (100 cases, NER on)
| Entity | Recall |
|---|---|
| AMOUNT | 100% |
| 100% | |
| PERSON | 100% |
| PHONE | 100% |
| ORG | 92% |
| LOCATION | 60.9% |
| Overall | 95.7% |
Reproduce with python scripts/eval.py --n 100.
Known limitations
- Hiragana-leading company names (
株式会社さくら通信,合同会社みどり) are missed by the regex because including hiragana in the body would destroy the particle boundary. Register them via the company dictionary. - Compound place names like
京都府京都市are sometimes split by GiNZA. - My-number checksums are not validated yet. Any 12-digit
dddd-dddd-ddddpattern is matched. - The
mappingreturned frommask()is in-memory only. Do not serialize it, log it, or write it to disk. It contains the originals you just removed.
Try it without writing code
The HuggingFace Space lets you paste any Japanese text, optionally provide a company dictionary, and see exactly what would be sent to the LLM. Nothing is logged.
Project layout
kakushi/
├── src/kakushi/
│ ├── normalizer.py # NFKC + context-aware hyphen folding
│ ├── patterns.py # 12 regex patterns (PII + Japanese company names)
│ ├── ner.py # GiNZA wrapper (lazy load, optional)
│ ├── resolver.py # span overlap resolution
│ ├── masker.py # mask() / unmask() / company dictionary
│ ├── synth.py # synthetic business-text generator
│ └── types.py # EntityType, Match
├── tests/ # 70 cases, all green
├── scripts/eval.py # recall measurement on synthetic corpus
├── examples/openai_demo.py
└── space/ # HuggingFace Space app (Gradio)
License
MIT.
Metadata
Release files for kakushi 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| kakushi-0.1.1.tar.gz | 22.4 kB | Without provenance | Details for kakushi-0.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| kakushi-0.1.1-py3-none-any.whl | Python 3 | none | any | Details for kakushi-0.1.1-py3-none-any.whl |
Total release size: 37.5 kB
Release files / kakushi-0.1.1.tar.gz
| Download URL | kakushi-0.1.1.tar.gz |
|---|---|
| Size | 22.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
839ba1e94e7628f95bb029f44db7268ff4b0d11ef60d728cae667d7d516321ea
|
|
BLAKE2b-256 checksum How to use checksums |
01cd6a2f0f0e8c4c999aaf6d439ffd655ede3904a3032473de3882f7d052ac03
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Release files / kakushi-0.1.1-py3-none-any.whl
| Download URL | kakushi-0.1.1-py3-none-any.whl |
|---|---|
| Size | 15.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fa974cd787d31e54240182cf0bbf42ab62f78ce670015e14e9550d3fa3aaf65d
|
|
BLAKE2b-256 checksum How to use checksums |
8c77bc40b71d945227d58cf74f62312a946da6a3c2405da4a4461605aa62ae77
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Security for kakushi 0.1.1
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.