|
|
@@ -291,6 +291,10 @@ class DataGenerator:
|
|
|
filler_samples = self._inject_fillers(samples, rng, filler_variants)
|
|
|
samples.extend(filler_samples)
|
|
|
|
|
|
+ # 3b. Fragewort-Augmentation (Vosk verschluckt oft das erste Wort)
|
|
|
+ stt_variants = self._generate_stt_variants(samples)
|
|
|
+ samples.extend(stt_variants)
|
|
|
+
|
|
|
# 4. Augmentation falls noetig
|
|
|
if len(samples) < target_samples:
|
|
|
augmented = self._augment(
|
|
|
@@ -695,6 +699,77 @@ class DataGenerator:
|
|
|
|
|
|
return result
|
|
|
|
|
|
+ # === STT-Varianten (Fragewort-Augmentation) ===
|
|
|
+
|
|
|
+ # Typische STT-Fehler am Satzanfang:
|
|
|
+ # Vosk verschluckt/verstaemmelt das erste Wort nach dem Wakeword
|
|
|
+ _STT_QUESTION_WORDS = {"was", "wer", "wann", "wie", "wo", "welche", "welcher", "welches"}
|
|
|
+ _STT_CONFUSIONS = {
|
|
|
+ "was": ["das", ""], # "was kommt" → "das kommt" oder "kommt"
|
|
|
+ "wer": ["der", ""], # "wer ist" → "der ist" oder "ist"
|
|
|
+ "wann": ["dann", ""], # "wann kommt" → "dann kommt" oder "kommt"
|
|
|
+ "wie": ["die", ""], # "wie wird" → "die wird" oder "wird"
|
|
|
+ "wo": ["so", ""], # "wo ist" → "so ist" oder "ist"
|
|
|
+ "welche": ["solche", ""], # "welche" → "solche" oder weggelassen
|
|
|
+ "welcher": ["solcher", ""],
|
|
|
+ "welches": ["solches", ""],
|
|
|
+ }
|
|
|
+
|
|
|
+ def _generate_stt_variants(
|
|
|
+ self, samples: list[TrainingSample],
|
|
|
+ ) -> list[TrainingSample]:
|
|
|
+ """
|
|
|
+ Erzeugt Varianten fuer typische STT-Fehler am Satzanfang.
|
|
|
+
|
|
|
+ Vosk verschluckt oder verstaemmelt oft das erste Wort nach
|
|
|
+ dem Wakeword. Diese Methode erzeugt fuer jeden Satz der mit
|
|
|
+ einem Fragewort beginnt Varianten ohne/mit falschem Fragewort.
|
|
|
+
|
|
|
+ Beispiel:
|
|
|
+ "was kommt heute auf RTL" erzeugt:
|
|
|
+ - "kommt heute auf RTL" (Fragewort fehlt)
|
|
|
+ - "das kommt heute auf RTL" (Fragewort verwechselt)
|
|
|
+
|
|
|
+ Wird nicht auf Filler/Augmented Samples angewendet.
|
|
|
+ """
|
|
|
+ result: list[TrainingSample] = []
|
|
|
+ seen = {s.text.lower() for s in samples}
|
|
|
+
|
|
|
+ for sample in samples:
|
|
|
+ if sample.source not in ("example", "pattern"):
|
|
|
+ continue
|
|
|
+
|
|
|
+ words = sample.text.split()
|
|
|
+ if len(words) < 3:
|
|
|
+ continue
|
|
|
+
|
|
|
+ first_lower = words[0].lower()
|
|
|
+ if first_lower not in self._STT_QUESTION_WORDS:
|
|
|
+ continue
|
|
|
+
|
|
|
+ confusions = self._STT_CONFUSIONS.get(first_lower, [])
|
|
|
+ for replacement in confusions:
|
|
|
+ if replacement:
|
|
|
+ # Fragewort ersetzen: "was kommt" → "das kommt"
|
|
|
+ variant = replacement + " " + " ".join(words[1:])
|
|
|
+ else:
|
|
|
+ # Fragewort weglassen: "was kommt" → "kommt"
|
|
|
+ variant = " ".join(words[1:])
|
|
|
+
|
|
|
+ variant = variant.strip()
|
|
|
+ if variant.lower() not in seen and variant:
|
|
|
+ seen.add(variant.lower())
|
|
|
+ result.append(TrainingSample(
|
|
|
+ text=variant,
|
|
|
+ intent=sample.intent,
|
|
|
+ slots=dict(sample.slots),
|
|
|
+ source="stt_variant",
|
|
|
+ ))
|
|
|
+
|
|
|
+ if result:
|
|
|
+ pdebug(f"STT-Varianten: {len(result)} erzeugt")
|
|
|
+ return result
|
|
|
+
|
|
|
# === Augmentation ===
|
|
|
|
|
|
# Prefixe und Suffixe fuer natuerliche Varianten
|