Dateien nach "/" hochladen
This commit is contained in:
1
.env.example
Normal file
1
.env.example
Normal file
@@ -0,0 +1 @@
|
|||||||
|
OPENAI_API_KEY=sk-....
|
||||||
149
generate_pii_texts.py
Normal file
149
generate_pii_texts.py
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
"""
|
||||||
|
Generiert synthetische deutsche Texte mit PII-Daten via OpenAI.
|
||||||
|
Speichert das Ergebnis als JSON.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
pip install openai python-dotenv
|
||||||
|
set OPENAI_API_KEY=sk-...
|
||||||
|
python generate_pii_texts.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
from pathlib import Path
|
||||||
|
from openai import OpenAI
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
SYSTEM_PROMPT = """\
|
||||||
|
Du bist ein Testdaten-Generator. Du erzeugst realistische deutsche Texte \
|
||||||
|
die personenbezogene Daten (PII) enthalten. Alle Daten sind FIKTIV.
|
||||||
|
|
||||||
|
Wichtig:
|
||||||
|
- Sei KREATIV bei den PII-Typen. Nicht nur Name+Email, sondern auch:
|
||||||
|
Geburtsdaten, Steuernummern, Kennzeichen, Kundennummern, IP-Adressen,
|
||||||
|
Benutzernamen, Bankverbindungen, Sozialversicherungsnummern, Adressen,
|
||||||
|
Telefonnummern, Kreditkarten, Personalausweisnummern, Reisepassnummern,
|
||||||
|
Führerscheinnummern, Krankenkassennummern, URLs mit PII-Parametern,
|
||||||
|
Geburtsorte, Nationalitäten, Religionszugehörigkeit usw.
|
||||||
|
- Baue EDGE CASES ein:
|
||||||
|
* PII in Tabellenform, Aufzählungen, Signaturen
|
||||||
|
* Abgekürzte Namen (M. Müller), Spitznamen, Doppelnamen
|
||||||
|
* Telefonnummern in verschiedenen Formaten (+49, 0049, 089/, mit/ohne Leerzeichen)
|
||||||
|
* Adressen in verschiedenen Formaten (mit/ohne Bundesland, Postfach, c/o)
|
||||||
|
* Teilweise geschwärzte Daten (DE** **** **** 1234 56)
|
||||||
|
* PII eingebettet in Code-Snippets, Log-Dateien, SQL-Queries
|
||||||
|
* PII in E-Mail-Headern, Chat-Verläufen
|
||||||
|
* Mehrere Personen im selben Text
|
||||||
|
* PII die sich über Zeilenumbrüche erstreckt
|
||||||
|
* Tippfehler in PII-nahen Kontexten
|
||||||
|
* IBANs/Kartennummern mit und ohne Leerzeichen
|
||||||
|
- Variiere die Textarten: Emails, Chatverläufe, Briefe, Logs, Formulare,
|
||||||
|
Berichte, Notizen, Protokolle, Tickets, Datenbankeinträge
|
||||||
|
"""
|
||||||
|
|
||||||
|
SCENARIOS = [
|
||||||
|
"Kundenanfrage per Email mit Signatur",
|
||||||
|
"IT-Support-Ticket mit Log-Auszügen",
|
||||||
|
"Internes Chat-Protokoll zwischen Kollegen",
|
||||||
|
"Behördliches Schreiben / Bescheid",
|
||||||
|
"Arztbrief mit Patientendaten",
|
||||||
|
"Polizeibericht / Unfallprotokoll",
|
||||||
|
"Bewerbung mit Lebenslauf-Auszügen",
|
||||||
|
"Bankmitteilung / Kontoeröffnung",
|
||||||
|
"Versicherungsmeldung / Schadensfall",
|
||||||
|
"Datenbankexport / CSV-artige Daten mit Kopfzeile",
|
||||||
|
"Handschriftliche Notiz (transkribiert) mit PII",
|
||||||
|
"Server-Logfile mit User-Daten und IPs",
|
||||||
|
"SQL-Query oder Code-Snippet mit hardkodierten PII",
|
||||||
|
"Meeting-Protokoll mit Teilnehmerliste",
|
||||||
|
"Mietvertrag / Wohnungsübergabe-Protokoll",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def generate(count=5, scenario=None, model="gpt-4o"):
|
||||||
|
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
scenario = scenario or random.choice(SCENARIOS)
|
||||||
|
|
||||||
|
user_prompt = f"""\
|
||||||
|
Generiere {count} verschiedene deutsche Texte (je 50-250 Wörter).
|
||||||
|
Szenario: {scenario}
|
||||||
|
|
||||||
|
Jeder Text soll VERSCHIEDENE PII-Typen enthalten – nicht immer die gleichen.
|
||||||
|
Baue bewusst Edge Cases und ungewöhnliche Formate ein.
|
||||||
|
|
||||||
|
Antwort als JSON:
|
||||||
|
{{
|
||||||
|
"samples": [
|
||||||
|
{{
|
||||||
|
"text": "...",
|
||||||
|
"pii_spans": [
|
||||||
|
{{"type": "PERSON", "value": "Max Müller", "start": 10, "end": 20}},
|
||||||
|
{{"type": "PHONE", "value": "+49 170 1234567", "start": 55, "end": 70}}
|
||||||
|
],
|
||||||
|
"scenario": "Kundenanfrage"
|
||||||
|
}}
|
||||||
|
]
|
||||||
|
}}
|
||||||
|
|
||||||
|
Regeln für pii_spans:
|
||||||
|
- type: freier String, z.B. PERSON, EMAIL, PHONE, IBAN, ADDRESS, DATE_OF_BIRTH,
|
||||||
|
LICENSE_PLATE, IP_ADDRESS, CREDIT_CARD, TAX_ID, SSN, ID_CARD, PASSPORT, URL, USERNAME, ...
|
||||||
|
- start/end: Zeichenpositionen im text (0-basiert). MÜSSEN exakt dem value entsprechen.
|
||||||
|
- JEDE PII im Text muss als span annotiert sein.
|
||||||
|
"""
|
||||||
|
|
||||||
|
print(f" → Generiere {count}x '{scenario}' ...")
|
||||||
|
|
||||||
|
resp = client.chat.completions.create(
|
||||||
|
model=model,
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": SYSTEM_PROMPT},
|
||||||
|
{"role": "user", "content": user_prompt},
|
||||||
|
],
|
||||||
|
temperature=1.0,
|
||||||
|
response_format={"type": "json_object"},
|
||||||
|
)
|
||||||
|
|
||||||
|
raw = json.loads(resp.choices[0].message.content or "{}")
|
||||||
|
samples = raw.get("samples", [])
|
||||||
|
|
||||||
|
# Fix offsets: LLMs liegen oft daneben bei start/end
|
||||||
|
for s in samples:
|
||||||
|
for span in s.get("pii_spans", []):
|
||||||
|
val = span.get("value", "")
|
||||||
|
idx = s["text"].find(val)
|
||||||
|
if idx != -1:
|
||||||
|
span["start"] = idx
|
||||||
|
span["end"] = idx + len(val)
|
||||||
|
|
||||||
|
return samples
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
total = 50
|
||||||
|
batch_size = 5
|
||||||
|
all_samples = []
|
||||||
|
|
||||||
|
print(f"Generiere {total} synthetische PII-Texte...\n")
|
||||||
|
|
||||||
|
for i in range(0, total, batch_size):
|
||||||
|
scenario = random.choice(SCENARIOS)
|
||||||
|
n = min(batch_size, total - i)
|
||||||
|
try:
|
||||||
|
batch = generate(count=n, scenario=scenario)
|
||||||
|
all_samples.extend(batch)
|
||||||
|
print(f" ✓ {len(all_samples)}/{total} fertig")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ✗ Fehler: {e}")
|
||||||
|
|
||||||
|
out = Path("output/synthetic_pii_data.json")
|
||||||
|
out.parent.mkdir(exist_ok=True)
|
||||||
|
out.write_text(json.dumps(all_samples, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||||
|
print(f"\n✅ {len(all_samples)} Texte gespeichert → {out}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
openai
|
||||||
|
python-dotenv
|
||||||
Reference in New Issue
Block a user