whisper-dictation/whisper_app/config.py

142 lines
4.9 KiB
Python

import json
import os
import sys
def _app_dir() -> str:
"""Root dir for config.json and vocabulary.json."""
if getattr(sys, "frozen", False):
return os.path.dirname(sys.executable)
# config.py lives at whisper_app/config.py → parent of parent = repo root
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATA_DIR = os.environ.get("WHISPER_DATA_DIR") or _app_dir()
_env_local = os.environ.get("WHISPER_LOCAL_DIR")
if _env_local:
_local_dir = _env_local
elif os.name == "nt":
_local_dir = os.path.join(os.environ.get("LOCALAPPDATA", DATA_DIR), "WhisperDictation")
else:
_local_dir = os.path.join(os.path.expanduser("~"), ".local", "share", "WhisperDictation")
CONFIG_FILE = os.path.join(DATA_DIR, "config.json")
CONFIG_LOCAL_FILE = os.path.join(_local_dir, "config_local.json")
VOCAB_FILE = os.path.join(DATA_DIR, "vocabulary.json")
DEFAULT_CONFIG = {
"hotkey": "ctrl+shift+space",
"model": "medium",
"device": "cuda",
"compute_type": "float16",
"language": "de",
"audio_device": None,
"sample_rate": 16000,
"vocab_path": "",
"model_dir": "",
"grammar_check": True,
"paste_delay_ms": 300,
"media_duck": True,
"duck_percent": 20,
}
MODELS = ["tiny", "base", "small", "medium", "large-v2", "large-v3"]
LANGUAGES = {"Deutsch": "de", "English": "en", "Français": "fr", "Español": "es",
"Italiano": "it", "Auto": None}
DEVICES = ["cuda", "cpu"]
COMPUTE_TYPES = {"float16 (GPU)": "float16", "int8 (CPU/GPU)": "int8", "float32": "float32"}
LOCAL_KEYS = {"audio_device", "device", "compute_type", "model"}
config: dict = {}
vocab: dict = {"words": [], "replacements": []}
def _resolve_vocab_file() -> None:
"""Set VOCAB_FILE from config['vocab_path'], falling back to DATA_DIR."""
global VOCAB_FILE
vp = config.get("vocab_path", "")
if vp:
VOCAB_FILE = vp if os.path.isabs(vp) else os.path.join(DATA_DIR, vp)
else:
VOCAB_FILE = os.path.join(DATA_DIR, "vocabulary.json")
def load_config() -> None:
global config
os.makedirs(_local_dir, exist_ok=True)
config = dict(DEFAULT_CONFIG)
if os.path.exists(CONFIG_FILE):
with open(CONFIG_FILE, encoding="utf-8") as f:
try:
config.update(json.load(f))
except json.JSONDecodeError:
print(f"Warning: could not parse {CONFIG_FILE}; using defaults")
config = dict(DEFAULT_CONFIG)
if os.path.exists(CONFIG_LOCAL_FILE):
with open(CONFIG_LOCAL_FILE, encoding="utf-8") as f:
try:
config.update(json.load(f))
except json.JSONDecodeError:
print(f"Warning: could not parse {CONFIG_LOCAL_FILE}; ignoring")
_resolve_vocab_file()
def save_config() -> None:
os.makedirs(os.path.dirname(CONFIG_FILE), exist_ok=True)
os.makedirs(os.path.dirname(CONFIG_LOCAL_FILE), exist_ok=True)
shared = {k: v for k, v in config.items() if k not in LOCAL_KEYS}
local = {k: v for k, v in config.items() if k in LOCAL_KEYS}
with open(CONFIG_FILE, "w", encoding="utf-8") as f:
json.dump(shared, f, indent=2)
with open(CONFIG_LOCAL_FILE, "w", encoding="utf-8") as f:
json.dump(local, f, indent=2)
_resolve_vocab_file()
def load_vocab() -> None:
global vocab
if os.path.exists(VOCAB_FILE):
with open(VOCAB_FILE, encoding="utf-8") as f:
try:
vocab = json.load(f)
except json.JSONDecodeError:
print(f"Warning: could not parse {VOCAB_FILE}; using empty vocab")
vocab = {"words": [], "replacements": []}
else:
vocab = {"words": [], "replacements": []}
def save_vocab() -> None:
os.makedirs(os.path.dirname(VOCAB_FILE), exist_ok=True)
with open(VOCAB_FILE, "w", encoding="utf-8") as f:
json.dump(vocab, f, indent=2, ensure_ascii=False)
def apply_vocab(text: str) -> str:
for r in vocab.get("replacements", []):
text = text.replace(r["from"], r["to"])
return text
_STYLE_HINTS = {
"de": "Hallo, wie geht es Ihnen? Ich arbeite an einem wichtigen Projekt. "
"Die Ergebnisse der Analyse zeigen deutliche Verbesserungen.",
"en": "Hello, how are you? I am working on an important project. "
"The analysis results show clear improvements.",
"fr": "Bonjour, comment allez-vous ? Je travaille sur un projet important. "
"Les résultats de l'analyse montrent des améliorations nettes.",
}
def get_initial_prompt() -> str:
parts = []
lang = config.get("language")
hint = _STYLE_HINTS.get(lang)
if hint:
parts.append(hint)
words = vocab.get("words", [])
if words:
parts.append(", ".join(words))
return " ".join(parts) if parts else ""