Kurulum
TurkPII, Docker imajı olarak dağıtılır ve müşterinin kendi sunucusunda (on-premise) çalışır.
CPU runtime v1.1.1 Kurulumu
docker pull bahadorr/turkpii:1.1.1
docker run --rm \
-e LICENSE_KEY="your-license-key" \
-p 8080:8080 \
bahadorr/turkpii:1.1.1
Opsiyonel benchmark / log hacmi kurulumu
Erişim loglarını kapatmak istediğiniz test ve benchmark koşullarında aşağıdaki opsiyonel değişkeni kullanabilirsiniz:
docker run --rm \
-e LICENSE_KEY="your-license-key" \
-e TURKPII_ACCESS_LOG=0 \
-p 8080:8080 \
bahadorr/turkpii:1.1.1
Mevcut public/customer release yalnızca CPU runtime ile yayınlanır. Performans sonuçları donanım, payload, concurrency ve lisans limitlerine göre değişir.
Deployment notu: TurkPII offline lisans doğrulamasını destekler. Docker imajı ve lisans bilgisi önceden sağlandığında, müşteri politikalarına bağlı olarak internet erişimi olmayan veya kısıtlı ağ ortamlarında çalıştırılabilir. Ağ davranışı müşteri tarafından firewall, IDS/IPS, SIEM, proxy ve network monitoring araçlarıyla doğrulanabilir.
Servisi Kontrol Etme
curl http://localhost:8080/health
Gerekli Ortam Değişkenleri
| Değişken | Zorunlu | Açıklama |
|---|---|---|
LICENSE_KEY | Evet | Müşteri için üretilmiş lisans anahtarı. Geçerli lisans olmadan servis başlamaz. |
TURKPII_ACCESS_LOG | Hayır | Erişim loglarını kapatmak için 0 olarak ayarlanabilir. Özellikle benchmark veya yüksek log hacmi istemeyen ortamlarda kullanışlıdır. |
Genel Bakış
TurkPII için müşteri odaklı HTTP API.
Aşağıdaki örnekler v1.1.1 CPU runtime release esas alınarak güncellendi. Doğrulama kanıtı: 372/372 pass, 0 fail. Yerel CPU benchmark kanıtı, 6-core Intel Core i5 test host uzerinde: 88792 successful request, 0 fail, best RPS 799.76.
TurkPII, konteyner başlangıcında geçerli bir LICENSE_KEY gerektirir. Benchmark sayıları evrensel üretim garantisi değildir; sonuçlar donanım, payload, concurrency ve lisans limitlerine göre değişir.
Endpointler
POST /mask, verilen metindeki kişisel verileri (PII) tespit edip maskeler.
POST /unmask, token yer tutucularından maskelenmiş metni yeniden oluşturur.
GET /health, servis durumunu döndürür.
GET /license/info, lisansa ait güvenli meta verileri ve çalışma zamanı durumunu döndürür.
Format
Belgelenen tüm istek ve yanıt örnekleri JSON formatındadır.
Örnek isteği tam olarak kopyalamak için her kod bloğundaki kopyala butonunu kullanın.
Aşağıdaki tablolar, kaynak dokümandaki alan adlarını, türleri ve açıklamaları eksiksiz korur.
/mask
Verilen metindeki kişisel verileri (PII) tespit edip maskeler.
İstek
{
"text": "Ahmet Yılmaz, TC: 10203040506, tel: 0532 123 45 67",
"options": {
"detect": ["TC", "IBAN", "CREDIT_CARD", "PASSPORT", "VIN", "IP", "PORT", "PHONE", "EMAIL", "NAME", "PERSON", "ADDRESS", "TAX", "PLATE", "AGE", "AGE_RANGE"],
"ner": true,
"min_confidence": 0.0,
"mode": "pseudonymize"
}
}
İstek alanları:
| Alan | Tür | Zorunlu | Açıklama |
|---|---|---|---|
text | string | Evet | PII taraması yapılacak metin. |
debug | boolean | Hayır | true olduğunda yanıta, eşleşme ayrıntılarını adli inceleme düzeyinde veren bir explanations dizisi eklenir. Canlı ortamda test edilmiştir. |
mask_policy | string | Hayır | Maskeleme politikası. Mevcut kodda desteklenen değerler valid_only, valid_and_suspicious, everything, all_structured_like ve compliance_strict değerleridir. Varsayılan değer valid_and_suspicious olarak kullanılır. |
options | object | Hayır | Tespit seçenekleri. |
options.detect | string[] | Hayır | Aranacak PII tipleri. Geçerli değerler TC, IBAN, CREDIT_CARD, PASSPORT, VIN, IP, PORT, PHONE, EMAIL, NAME, PERSON, ADDRESS, TAX, PLATE, AGE ve AGE_RANGE değerleridir. NAME ile PERSON aynı istekte birlikte kullanılmamalıdır; AGE ile AGE_RANGE de birlikte kullanılmamalıdır. |
options.ner | boolean | Hayır | Türkçe isim tespiti için NER katmanını etkinleştirir. Çalışan lisanslı serviste bu alan atlanırsa ner_enabled değeri false kalır; true olarak ayarlanırsa lisans ve çalışma zamanı izin verdiğinde NER etkinleşir. Canlı ortamda test edilmiştir. |
options.min_confidence | number | Hayır | Minimum güven eşiği. 0.0 değeri, güven skoruna göre filtreleme yapılmayacağı anlamına gelir. |
options.mode | string | Hayır | Maskeleme modu. pseudonymize varsayılandır ve geri döndürülebilir tokens haritası üretir. anonymize geri döndürülemezdir ve token map döndürmez. |
Mutual exclusion kuralı: NAME ile PERSON birlikte istenmemelidir. Aynı şekilde AGE ile AGE_RANGE de aynı istekte birlikte gönderilmemelidir.
Yanıt
Çalışan servisten alınmış canlı örnek:
{
"masked": "{{NAME_1}}, TC: {{TC_1}}, tel: {{PHONE_1}}",
"tokens": {
"NAME_1": "Ahmet Yılmaz",
"PHONE_1": "0532 123 45 67",
"TC_1": "10203040506"
},
"detected": [
{
"type": "NAME",
"family": "Person",
"semantic_class": "person",
"parser_context": "natural",
"assertion_scope": "sentence_scope",
"profile_used": "TurkishNativeProfile",
"primary_profile": "TurkishNativeProfile",
"contributing_profiles": [
"TurkishNativeProfile"
],
"policy_used": "valid_and_suspicious",
"masking_reason": "valid or suspicious entity under valid_and_suspicious policy",
"compliance_relevance": "medium",
"alert_severity": "low",
"value": "Ahmet Yılmaz",
"raw_value": "Ahmet Yılmaz",
"normalized_value": "Ahmet Yılmaz",
"canonical_value": "Ahmet Yılmaz",
"start": 0,
"end": 13,
"confidence": 0.7034956909518111,
"structural_score": 0.45,
"validation_score": 0.22,
"context_score": 0,
"pattern_score": 0.06,
"neighbor_score": 0,
"semantic_score": 0,
"relationship_score": 0,
"source": "ner.name",
"validation_state": "valid",
"reason": "ner_person",
"scores": {
"structural": 0.45,
"validation": 0.22,
"context": 0,
"pattern": 0.06,
"neighbor": 0,
"semantic": 0,
"relationship": 0,
"raw_total": 0.73,
"normalized": 0.7034956909518111
}
},
{
"type": "TC",
"family": "StructuredIdentifiers",
"semantic_class": "identifier",
"parser_context": "natural",
"field_anchor": "tc",
"ownership_reason": "label strongly indicates TC",
"assertion_scope": "sentence_scope",
"profile_used": "TurkishNativeProfile",
"primary_profile": "TurkishNativeProfile",
"contributing_profiles": [
"TurkishNativeProfile"
],
"policy_used": "valid_and_suspicious",
"masking_reason": "valid or suspicious entity under valid_and_suspicious policy",
"compliance_relevance": "high",
"alert_severity": "medium",
"value": "10203040506",
"raw_value": "10203040506",
"normalized_value": "10203040506",
"canonical_value": "10203040506",
"start": 19,
"end": 30,
"confidence": 0.7231218051243897,
"structural_score": 0.44,
"validation_score": -0.24,
"context_score": 0.16,
"pattern_score": 0.06,
"neighbor_score": 0.05,
"semantic_score": 0.28,
"relationship_score": 0,
"source": "regex.tc",
"validation_state": "suspicious",
"reason": "checksum10_failed",
"scores": {
"structural": 0.44,
"validation": -0.24,
"context": 0.16,
"pattern": 0.06,
"neighbor": 0.05,
"semantic": 0.28,
"relationship": 0,
"raw_total": 0.75,
"normalized": 0.7231218051243897
}
},
{
"type": "PHONE",
"family": "ContactInfo",
"semantic_class": "contact_info",
"parser_context": "natural",
"field_anchor": "tel",
"assertion_scope": "sentence_scope",
"profile_used": "TurkishNativeProfile",
"primary_profile": "TurkishNativeProfile",
"contributing_profiles": [
"TurkishNativeProfile"
],
"policy_used": "valid_and_suspicious",
"masking_reason": "valid or suspicious entity under valid_and_suspicious policy",
"compliance_relevance": "high",
"alert_severity": "high",
"value": "0532 123 45 67",
"raw_value": "0532 123 45 67",
"normalized_value": "0532 123 45 67",
"canonical_value": "5321234567",
"start": 37,
"end": 51,
"confidence": 0.8009113398157163,
"structural_score": 0.42,
"validation_score": 0.3,
"context_score": 0,
"pattern_score": 0.07,
"neighbor_score": 0.05,
"semantic_score": 0,
"relationship_score": 0,
"source": "regex.phone",
"validation_state": "valid",
"reason": "ok",
"scores": {
"structural": 0.42,
"validation": 0.3,
"context": 0,
"pattern": 0.07,
"neighbor": 0.05,
"semantic": 0,
"relationship": 0,
"raw_total": 0.8400000000000001,
"normalized": 0.8009113398157163
}
}
],
"summary": {
"requested_types": [
"TC",
"PHONE",
"EMAIL",
"IBAN",
"NAME",
"ADDRESS",
"TAX",
"PLATE"
],
"ner_enabled": true,
"detected_context": "natural",
"total_detected": 3,
"by_type": {
"NAME": 1,
"PHONE": 1,
"TC": 1
}
}
}
Yanıt alanları:
| Alan | Tür | Açıklama |
|---|---|---|
masked | string | Seçilen tespitlerin {{TOKEN}} yer tutucularıyla değiştirildiği özgün metin. |
tokens | object | Pseudonymize modunda token adı ile özgün değer arasındaki eşleme döner. Anonymize modunda bu nesne bulunmayabilir veya boş olabilir. |
detected | array | İstek için döndürülen kabul edilmiş tespitlerin listesi. |
detected[].type | string | TC, IBAN, CREDIT_CARD, PASSPORT, VIN, IP, PORT, PHONE, EMAIL, NAME, PERSON, ADDRESS, TAX, PLATE, AGE veya AGE_RANGE gibi PII kategorisi. |
detected[].family | string | Person, StructuredIdentifiers veya ContactInfo gibi daha geniş sınıflandırma ailesi. |
detected[].semantic_class | string | person, identifier veya contact_info gibi anlamsal etiket. |
detected[].parser_context | string | Girdiden çıkarılan bağlam; örneğin natural, json, xml, sql, logfmt, markdown, csv, chat, yaml veya ocr. |
detected[].field_anchor | string | Tanınan yakın alan etiketi; örneğin tc veya tel. |
detected[].value | string | Dışarı aktarılan tespit değeri. |
detected[].raw_value | string | Mevcutsa, özgün istek metninden alınan tam alt dize. |
detected[].normalized_value | string | Sunum amacıyla kullanılan normalize edilmiş biçim. |
detected[].canonical_value | string | Karşılaştırma veya tekilleştirme için kullanılan kanonikleştirilmiş biçim. |
detected[].start / detected[].end | number | Özgün UTF-8 istek metnindeki byte ofsetleri. |
detected[].confidence | number | 0.0 ile 1.0 arasında güven skoru. |
detected[].source | string | regex.tc, regex.phone veya ner.name gibi tespit kaynağı. |
detected[].validation_state | string | valid veya suspicious gibi doğrulama sonucu. |
detected[].reason | string | Tanıyıcı veya doğrulayıcıdan gelen kısa gerekçe; örneğin ok, ner_person veya checksum10_failed. |
detected[].structural_score ve ilgili skor alanları | number | Nihai güven skoruna katkı veren skor bileşenleri. |
detected[].scores | object | Normalize toplamı ve bileşen skorlarını içeren skor kırılım nesnesi. |
summary | object | İstek düzeyindeki özet bilgisi. |
summary.requested_types | string[] | İstek ayrıştırıldıktan sonra geçerli olan PII tipleri. |
summary.ner_enabled | boolean | Bu istek için NER yolunun gerçekten çalıştırılıp çalıştırılmadığını gösterir; çalıştıysa true olur. |
summary.detected_context | string | İstek için seçilen bağlam; örneğin natural veya ocr. |
summary.total_detected | number | detected içinde döndürülen tespit sayısı. |
summary.by_type | object | PII tipine göre adet dağılımı. |
explanations | array | Yalnızca debug=true olduğunda bulunur. Her adayın nasıl değerlendirildiğini anlatan açıklama nesnelerini içerir. Canlı ortamda test edilmiştir. |
debug ve mask_policy
Her iki alan da mevcut handler içinde uygulanmıştır ve canlı ortamda test edilmiştir.
debug=true olduğunda yanıt bir explanations dizisi içerir:
{
"masked": "TC kimlik numaram 34567890146.",
"tokens": {},
"detected": [
{
"type": "TC",
"validation_state": "suspicious",
"reason": "checksum10_failed"
}
],
"summary": {
"requested_types": ["TC"],
"ner_enabled": false,
"detected_context": "natural",
"total_detected": 1,
"by_type": {
"TC": 1
}
},
"explanations": [
{
"entity": "TC",
"validation_state": "suspicious",
"matched_by": "regex.tc",
"masking_applied": false,
"pipeline": [
"regex.tc matched",
"bounded candidate",
"TCValidator suspicious: checksum10_failed",
"mask policy skipped masking"
]
}
]
}
mask_policy, bir tespitin döndürülüp döndürülmeyeceğini değil, neyin maskeleneceğini değiştirir. Şüpheli bir TC adayı için canlı ortamda gözlenen davranış aşağıdadır:
Varsayılan politika (valid_and_suspicious), şüpheli adayı maskeler:
{
"masked": "TC kimlik numaram {{TC_1}}.",
"tokens": {
"TC_1": "34567890146"
},
"detected": [
{
"type": "TC",
"validation_state": "suspicious",
"reason": "checksum10_failed"
}
]
}
valid_only, aynı şüpheli tespiti maskelemeden bırakır; ancak yine de detected içinde döndürür:
{
"masked": "TC kimlik numaram 34567890146.",
"tokens": {},
"detected": [
{
"type": "TC",
"validation_state": "suspicious",
"reason": "checksum10_failed"
}
]
}
Lisans kısıtlarında görülebilen özet alanları
Mevcut kurumsal test lisansı belgelenen tüm tipleri ve bağlamları izinli hale getirdiği için, aşağıdaki özet alanları kodda doğrulandı ancak bu oturumda canlı bir istekle tetiklenmedi:
- summary.unlicensed_types_skipped
- summary.ner_requested_but_not_licensed
- summary.context_downgraded_to
- summary.reason
Mevcut kod yolundan alınan örnek şekil aşağıdaki gibidir:
{
"summary": {
"requested_types": ["NAME", "EMAIL"],
"ner_enabled": false,
"ner_requested_but_not_licensed": true,
"unlicensed_types_skipped": ["EMAIL"],
"detected_context": "ocr",
"context_downgraded_to": "natural",
"reason": "ocr not included in license"
}
}
/unmask
/mask tarafından döndürülen token eşlemesini kullanarak maskelenmiş metni yeniden oluşturur.
İstek
{
"masked": "{{NAME_1}} toplantıya katıldı",
"tokens": {
"NAME_1": "Ahmet Yılmaz"
}
}
İstek alanları:
| Alan | Tür | Zorunlu | Açıklama |
|---|---|---|---|
masked | string | Evet | {{TOKEN}} yer tutucuları içeren maskelenmiş metin. |
tokens | object | Hayır | /mask tarafından döndürülen token eşlemesi. Alan gönderilmezse veya boş bırakılırsa yanıt yer tutucuları olduğu gibi bırakır. Canlı ortamda test edilmiştir. |
Yanıt
Çalışan servisten alınmış canlı örnek:
{
"text": "Ahmet Yılmaz toplantıya katıldı"
}
Yanıt alanları:
| Alan | Tür | Açıklama |
|---|---|---|
text | string | Yer tutucular değiştirildikten sonra yeniden oluşturulan metin. |
/health
Temel servis durumunu döndürür.
İstek
Bu endpoint bir istek gövdesi kabul etmez.
İstek alanları:
| Alan | Tür | Zorunlu | Açıklama |
|---|---|---|---|
| Yok | - | - | İstek gövdesi yoktur. |
Yanıt
Çalışan servisten alınmış canlı örnek:
{
"status": "ok",
"version": "1.0.2"
}
Yanıt alanları:
| Alan | Tür | Açıklama |
|---|---|---|
status | string | Servis durumu. Gözlenen değer: ok. |
version | string | Uygulama sürüm bilgisi. Mevcut public/customer release örneğinde bu değer 1.0.2 olarak gösterilir. |
/license/info
Ham lisans token'ını açığa çıkarmadan güvenli lisans meta verilerini ve çalışma zamanı durumunu döndürür.
İstek
Bu endpoint bir istek gövdesi kabul etmez.
İstek alanları:
| Alan | Tür | Zorunlu | Açıklama |
|---|---|---|---|
| Yok | - | - | İstek gövdesi yoktur. |
Yanıt
Çalışan servisten alınmış canlı örnek:
{
"customer_name": "Evaluation Customer",
"days_remaining": 30,
"expires_at": "2026-08-12T00:00:00Z",
"features": {
"contexts": [
"natural",
"json",
"xml",
"sql",
"logfmt",
"markdown",
"csv",
"ocr",
"chat",
"yaml"
],
"detect_types": [
"TC",
"IBAN",
"CREDIT_CARD",
"PASSPORT",
"VIN",
"IP",
"PORT",
"PHONE",
"EMAIL",
"NAME",
"PERSON",
"ADDRESS",
"TAX",
"PLATE",
"AGE",
"AGE_RANGE"
],
"ner": true,
"ocr": true,
"anonymize": true,
"pseudonymize": true
},
"limits": {
"max_req_per_day": 50000,
"max_req_per_sec": 25
},
"runtime": {
"mode": "cpu",
"ner_available": true
},
"status": "valid",
"tier": "evaluation"
}
Yanıt alanları:
| Alan | Tür | Açıklama |
|---|---|---|
customer_name | string | Aktif lisanstaki müşteri adı. |
tier | string | Lisans seviyesi; örneğin starter, professional veya enterprise. |
expires_at | string | RFC 3339 formatındaki lisans bitiş zamanı. |
days_remaining | number | İstek anında lisans bitimine kalan tam gün sayısı. |
status | string | Endpoint tarafından döndürülen güncel lisans durumu. Canlı ortamda gözlenen değer valid olmuştur. Mevcut handler kodu, 30 gün veya daha az süre kaldığında ayrıca expiring_soon da döndürebilir. |
features | object | Aktif lisanstaki özellik bayrakları ve izin listeleri. |
features.ner | boolean | Lisansın NER tabanlı isim tespitine izin verip vermediğini gösterir. |
features.ocr | boolean | Lisansın OCR farkındalıklı işlemeye izin verip vermediğini gösterir. |
features.anonymize / features.pseudonymize | boolean | Lisansın ilgili maskeleme modlarına izin verip vermediğini gösterir. |
features.contexts | string[] | Aktif lisansın izin verdiği bağlamlar. |
features.detect_types | string[] | Aktif lisansın izin verdiği PII tipleri. |
limits | object | Aktif lisanstaki oran limiti bilgileri. |
limits.max_req_per_sec | number | İzin verilen saniye başına maksimum istek sayısı. |
limits.max_req_per_day | number or null | İsteğe bağlı günlük maksimum istek sayısı. null değeri günlük limit tanımlanmadığını gösterir. |
runtime | object | Çalışan sürecin canlı çalışma zamanı durumu. |
runtime.mode | string | Mevcut public/customer release için çalışma zamanı modu cpu olarak dokümante edilir. |
runtime.ner_available | boolean | NER modelinin başlangıçta başarıyla yüklenip yüklenmediğini ve isteklere hazır olup olmadığını gösterir; hazırsa true olur. |
runtime.mode ve runtime.ner_available, çalışma zamanı durumunu yansıtır. Mevcut release CPU-only olarak yayınlanır.
Hatalar
Kaynak referanstan alınan hata örnekleri, endpoint bölümleriyle aynı dokümantasyon düzeni kullanılarak aşağıda sunulmuştur.
Geçersiz veya eksik lisans (başlangıç düzeyi)
Bu, istek başına dönen bir HTTP hatası değildir. LICENSE_KEY eksik veya geçersizse konteyner başlayamaz ve bir log mesajıyla çıkar.
LICENSE_KEY olmadan imaj çalıştırılarak alınmış canlı örnek:
{"time":"2026-07-05T14:24:18.75247706Z","level":"ERROR","msg":"application init failed","error":"[LICENSE] invalid license: LICENSE_KEY is required"}
Bozuk istek gövdesi
Bozuk JSON ile POST /mask üzerinde canlı ortamda test edilmiştir.
HTTP durumu: 400 Bad Request
{
"error": "invalid request body"
}
Aynı istek ayrıştırma yolu POST /unmask için de kullanılır.
Bilinmeyen detect türü
Geçersiz bir detect türü gönderildiğinde servis geçerli tür listesini de döndürür.
HTTP durumu: 400 Bad Request
{
"error": "unknown PII type: NATIONAL_ID",
"valid_types": [
"TC",
"IBAN",
"CREDIT_CARD",
"PASSPORT",
"VIN",
"IP",
"PORT",
"PHONE",
"EMAIL",
"NAME",
"PERSON",
"ADDRESS",
"TAX",
"PLATE",
"AGE",
"AGE_RANGE"
]
}