Browse Source

STT-Varianten Augmentation: Fragewort-Fehler im Training

Vosk verschluckt oft das erste Wort nach dem Wakeword:
"was kommt auf RTL" → "kommt auf RTL" oder "das kommt auf RTL"

Der DataGenerator erzeugt jetzt automatisch fuer jeden Satz
der mit einem Fragewort beginnt (was/wer/wann/wie/wo/welche)
zwei zusaetzliche Trainings-Varianten:
- Fragewort fehlt: "kommt auf RTL"
- Fragewort verwechselt: "das kommt auf RTL" (was→das, wann→dann, etc.)

Betrifft ALLE Intents automatisch — kein manuelles Pflegen
pro Plugin noetig. Keine Auswirkung auf Follow-Up Dialoge
da die Varianten nur beim Training erzeugt werden, nicht zur
Laufzeit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
patrick 2 months ago
parent
commit
f7339c34b0
1 changed files with 75 additions and 0 deletions
  1. 75 0
      trixy_core/trainer/core/intent/data_generator.py

+ 75 - 0
trixy_core/trainer/core/intent/data_generator.py

@@ -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