| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- # -*- coding: utf-8 -*-
- """
- Hunspell-Korrekturschicht.
- Woerterbuch-basierte Korrektur (~6ms/Wort).
- """
- from pathlib import Path
- from trixy_core.stt.layers.base import CorrectionLayer
- from trixy_core.utils.debug import pdebug, pwarn
- try:
- import hunspell
- _HAS_HUNSPELL = True
- except ImportError:
- _HAS_HUNSPELL = False
- class HunspellLayer(CorrectionLayer):
- """Hunspell woerterbuch-basierte Korrektur."""
- NAME = "hunspell"
- def __init__(self) -> None:
- self._hobj: "hunspell.HunSpell | None" = None
- self._protected_words: set[str] = set()
- def is_available(self) -> bool:
- """Prueft ob pyhunspell installiert ist."""
- return _HAS_HUNSPELL
- def initialize(self, config: dict, language: str, protected_words: list[str]) -> bool:
- """Laedt Hunspell-Woerterbuch."""
- if not _HAS_HUNSPELL:
- return False
- dict_path = config.get("hunspell_dict_path", f"/usr/share/hunspell/{language}_DE")
- # Hunspell braucht .dic und .aff Dateien
- dic_file = Path(f"{dict_path}.dic")
- aff_file = Path(f"{dict_path}.aff")
- if not dic_file.exists() or not aff_file.exists():
- pdebug(f"[Hunspell] Woerterbuch nicht gefunden: {dict_path}")
- return False
- try:
- self._hobj = hunspell.HunSpell(str(aff_file), str(dic_file))
- self._protected_words = {w.lower() for w in protected_words}
- # Geschuetzte Woerter zum Woerterbuch hinzufuegen
- for word in protected_words:
- self._hobj.add(word)
- pdebug(f"[Hunspell] Woerterbuch geladen: {dict_path}")
- return True
- except Exception as e:
- pwarn(f"[Hunspell] Initialisierung fehlgeschlagen: {e}")
- self._hobj = None
- return False
- def correct(self, text: str) -> str:
- """Prueft jedes Wort einzeln und schlaegt Korrekturen vor."""
- if not self._hobj or not text.strip():
- return text
- try:
- words = text.split()
- corrected_words = []
- changed = False
- for word in words:
- # Geschuetzte Woerter ueberspringen
- if word.lower() in self._protected_words:
- corrected_words.append(word)
- continue
- # Wort pruefen (Satzzeichen entfernen fuer Pruefung)
- clean_word = word.strip(".,!?;:\"'()")
- if not clean_word:
- corrected_words.append(word)
- continue
- if self._hobj.spell(clean_word):
- # Wort ist korrekt
- corrected_words.append(word)
- else:
- # Wort ist falsch — Vorschlaege holen
- suggestions = self._hobj.suggest(clean_word)
- if suggestions:
- # Ersten Vorschlag verwenden (bester Match)
- suggestion = suggestions[0]
- # Satzzeichen beibehalten
- prefix = word[:len(word) - len(word.lstrip(".,!?;:\"'()"))] if word != word.lstrip(".,!?;:\"'()") else ""
- suffix = word[len(word.rstrip(".,!?;:\"'()")):] if word != word.rstrip(".,!?;:\"'()") else ""
- corrected_words.append(f"{prefix}{suggestion}{suffix}")
- changed = True
- else:
- corrected_words.append(word)
- if changed:
- result = " ".join(corrected_words)
- pdebug(f"[Hunspell] '{text}' → '{result}'")
- return result
- return text
- except Exception as e:
- pdebug(f"[Hunspell] Fehler bei Korrektur: {e}")
- return text
- def shutdown(self) -> None:
- """Gibt Ressourcen frei."""
- self._hobj = None
|