From 4b7228202993ece0d06a3b3c9eac95a4511b5403 Mon Sep 17 00:00:00 2001 From: marvin Date: Mon, 23 Feb 2026 10:48:57 +0000 Subject: [PATCH] Dateien nach "/" hochladen --- .env.example | 1 + generate_pii_texts.py | 149 ++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 2 + 3 files changed, 152 insertions(+) create mode 100644 .env.example create mode 100644 generate_pii_texts.py create mode 100644 requirements.txt diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..58f5e63 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +OPENAI_API_KEY=sk-.... \ No newline at end of file diff --git a/generate_pii_texts.py b/generate_pii_texts.py new file mode 100644 index 0000000..edabb90 --- /dev/null +++ b/generate_pii_texts.py @@ -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() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f219f28 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +openai +python-dotenv