mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-07-04 13:03:13 +02:00
refactor(linux_configuration): fix ruff violations in digital wellbeing and transcription scripts
- Add type annotations and docstrings to focus_mode_daemon.py, transcribe_fw.py, transcribe_helpers.py - Use logging module instead of print - Fix bare except clauses with specific exception types
This commit is contained in:
parent
0460f3fac6
commit
4d3da460fc
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Focus Mode Daemon - Steam/Browser Mutual Exclusion
|
||||
"""Focus Mode Daemon - Steam/Browser Mutual Exclusion.
|
||||
|
||||
This daemon monitors running processes and enforces mutual exclusion between
|
||||
Steam (gaming) and web browsers. Whichever starts first "wins" and the other
|
||||
@ -8,17 +8,27 @@ category is blocked/killed.
|
||||
Run as a systemd user service for continuous monitoring.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
import os
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
from datetime import datetime, timezone
|
||||
import logging
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from types import FrameType
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Configuration
|
||||
STATE_DIR = (
|
||||
Path(os.environ.get("XDG_STATE_HOME", Path.home() / ".local/state")) / "focus-mode"
|
||||
Path.home() / ".local" / "state" / "focus-mode"
|
||||
)
|
||||
LOG_FILE = STATE_DIR / "focus-mode.log"
|
||||
POLL_INTERVAL = 2 # seconds between process checks
|
||||
@ -75,36 +85,44 @@ IGNORE_PATTERNS = frozenset(
|
||||
|
||||
def log(message: str) -> None:
|
||||
"""Log message with timestamp."""
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
timestamp = datetime.now(tz=timezone.utc).strftime(
|
||||
"%Y-%m-%d %H:%M:%S"
|
||||
)
|
||||
log_line = f"{timestamp} - {message}"
|
||||
print(log_line)
|
||||
try:
|
||||
logger.info("%s", log_line)
|
||||
with contextlib.suppress(OSError):
|
||||
STATE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
with open(LOG_FILE, "a") as f:
|
||||
with LOG_FILE.open("a") as f:
|
||||
f.write(log_line + "\n")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def notify(title: str, message: str, urgency: str = "normal") -> None:
|
||||
def notify(
|
||||
title: str, message: str, urgency: str = "normal"
|
||||
) -> None:
|
||||
"""Send desktop notification."""
|
||||
try:
|
||||
notify_send = shutil.which("notify-send")
|
||||
if notify_send is None:
|
||||
return
|
||||
with contextlib.suppress(
|
||||
OSError, subprocess.SubprocessError
|
||||
):
|
||||
subprocess.run(
|
||||
["notify-send", "-u", urgency, title, message],
|
||||
[notify_send, "-u", urgency, title, message],
|
||||
capture_output=True,
|
||||
timeout=5,
|
||||
check=False,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def get_running_processes() -> set[str]:
|
||||
"""Get set of currently running process names."""
|
||||
processes = set()
|
||||
processes: set[str] = set()
|
||||
ps_bin = shutil.which("ps")
|
||||
if ps_bin is None:
|
||||
return processes
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["ps", "-eo", "comm="],
|
||||
[ps_bin, "-eo", "comm="],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10,
|
||||
@ -115,18 +133,16 @@ def get_running_processes() -> set[str]:
|
||||
proc_name = line.strip().lower()
|
||||
if proc_name:
|
||||
processes.add(proc_name)
|
||||
except Exception as e:
|
||||
log(f"Error getting processes: {e}")
|
||||
except (OSError, subprocess.SubprocessError) as exc:
|
||||
log(f"Error getting processes: {exc}")
|
||||
return processes
|
||||
|
||||
|
||||
def is_steam_running(processes: set[str]) -> bool:
|
||||
"""Check if Steam or any Steam game is running."""
|
||||
for proc in processes:
|
||||
# Check for Steam main processes
|
||||
if proc in STEAM_PATTERNS:
|
||||
return True
|
||||
# Check for Steam games (have steam_app_ prefix)
|
||||
if proc.startswith(STEAM_GAME_PREFIX):
|
||||
return True
|
||||
return False
|
||||
@ -135,129 +151,181 @@ def is_steam_running(processes: set[str]) -> bool:
|
||||
def is_browser_running(processes: set[str]) -> bool:
|
||||
"""Check if any browser is running."""
|
||||
for proc in processes:
|
||||
# Skip Electron apps and ignored patterns
|
||||
if proc in ELECTRON_IGNORE:
|
||||
continue
|
||||
if any(ign in proc for ign in IGNORE_PATTERNS):
|
||||
continue
|
||||
# Use exact match to avoid false positives from Electron apps
|
||||
if proc in BROWSER_PATTERNS:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _run_pkill(
|
||||
pattern: str, *, force: bool = False
|
||||
) -> None:
|
||||
"""Run pkill with the given pattern."""
|
||||
pkill_bin = shutil.which("pkill")
|
||||
if pkill_bin is None:
|
||||
return
|
||||
cmd = [pkill_bin]
|
||||
if force:
|
||||
cmd.append("-9")
|
||||
cmd.extend(["-f", pattern])
|
||||
with contextlib.suppress(
|
||||
OSError, subprocess.SubprocessError
|
||||
):
|
||||
subprocess.run(
|
||||
cmd, capture_output=True, timeout=5, check=False
|
||||
)
|
||||
|
||||
|
||||
def kill_steam() -> None:
|
||||
"""Kill all Steam-related processes."""
|
||||
log("Killing Steam processes...")
|
||||
notify("🎮 Gaming Blocked", "Browser is active. Closing Steam.", "critical")
|
||||
notify(
|
||||
"\U0001f3ae Gaming Blocked",
|
||||
"Browser is active. Closing Steam.",
|
||||
"critical",
|
||||
)
|
||||
|
||||
try:
|
||||
# First try graceful shutdown
|
||||
subprocess.run(
|
||||
["pkill", "-f", "steam"], capture_output=True, timeout=5, check=False
|
||||
)
|
||||
time.sleep(2)
|
||||
|
||||
# Force kill if still running
|
||||
subprocess.run(
|
||||
["pkill", "-9", "-f", "steam"], capture_output=True, timeout=5, check=False
|
||||
)
|
||||
except Exception as e:
|
||||
log(f"Error killing Steam: {e}")
|
||||
_run_pkill("steam")
|
||||
time.sleep(2)
|
||||
_run_pkill("steam", force=True)
|
||||
|
||||
|
||||
def kill_browsers() -> None:
|
||||
"""Kill all browser processes."""
|
||||
log("Killing browser processes...")
|
||||
notify("🌐 Browsers Blocked", "Steam is active. Closing browsers.", "critical")
|
||||
notify(
|
||||
"\U0001f310 Browsers Blocked",
|
||||
"Steam is active. Closing browsers.",
|
||||
"critical",
|
||||
)
|
||||
|
||||
for browser in BROWSER_PATTERNS:
|
||||
try:
|
||||
subprocess.run(
|
||||
["pkill", "-f", browser], capture_output=True, timeout=5, check=False
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
_run_pkill(browser)
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
# Force kill if still running
|
||||
for browser in BROWSER_PATTERNS:
|
||||
try:
|
||||
subprocess.run(
|
||||
["pkill", "-9", "-f", browser],
|
||||
capture_output=True,
|
||||
timeout=5,
|
||||
check=False,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
_run_pkill(browser, force=True)
|
||||
|
||||
|
||||
class FocusMode:
|
||||
"""Tracks current focus mode and enforces mutual exclusion."""
|
||||
|
||||
def __init__(self):
|
||||
self.current_mode: str | None = None # "gaming" or "browsing" or None
|
||||
def __init__(self) -> None:
|
||||
"""Initialize focus mode as inactive."""
|
||||
self.current_mode: str | None = None
|
||||
self.mode_start_time: datetime | None = None
|
||||
|
||||
def _enter_mode(
|
||||
self, mode: str, msg: str, notification: str
|
||||
) -> None:
|
||||
"""Enter a new focus mode."""
|
||||
log(msg)
|
||||
self.current_mode = mode
|
||||
self.mode_start_time = datetime.now(tz=timezone.utc)
|
||||
notify(*notification.split("|", 1))
|
||||
|
||||
def _handle_no_mode(
|
||||
self,
|
||||
*,
|
||||
steam_running: bool,
|
||||
browser_running: bool,
|
||||
) -> None:
|
||||
"""Handle updates when no mode is active."""
|
||||
if steam_running and browser_running:
|
||||
log(
|
||||
"Both Steam and browsers detected at "
|
||||
"startup - entering GAMING mode"
|
||||
)
|
||||
self.current_mode = "gaming"
|
||||
self.mode_start_time = datetime.now(
|
||||
tz=timezone.utc
|
||||
)
|
||||
kill_browsers()
|
||||
elif steam_running:
|
||||
self._enter_mode(
|
||||
"gaming",
|
||||
"Steam detected - entering GAMING mode",
|
||||
"\U0001f3ae Gaming Mode|"
|
||||
"Steam detected. Browsers are now blocked.",
|
||||
)
|
||||
elif browser_running:
|
||||
self._enter_mode(
|
||||
"browsing",
|
||||
"Browser detected - entering BROWSING mode",
|
||||
"\U0001f310 Browsing Mode|"
|
||||
"Browser detected. Steam is now blocked.",
|
||||
)
|
||||
|
||||
def _handle_gaming(
|
||||
self,
|
||||
*,
|
||||
steam_running: bool,
|
||||
browser_running: bool,
|
||||
) -> None:
|
||||
"""Handle updates in gaming mode."""
|
||||
if not steam_running:
|
||||
log("Steam closed - exiting GAMING mode")
|
||||
self.current_mode = None
|
||||
self.mode_start_time = None
|
||||
notify(
|
||||
"\U0001f3ae Gaming Mode Ended",
|
||||
"You can now use browsers.",
|
||||
"normal",
|
||||
)
|
||||
elif browser_running:
|
||||
log(
|
||||
"Browser detected during GAMING mode "
|
||||
"- killing browsers"
|
||||
)
|
||||
kill_browsers()
|
||||
|
||||
def _handle_browsing(
|
||||
self,
|
||||
*,
|
||||
steam_running: bool,
|
||||
browser_running: bool,
|
||||
) -> None:
|
||||
"""Handle updates in browsing mode."""
|
||||
if not browser_running:
|
||||
log("Browsers closed - exiting BROWSING mode")
|
||||
self.current_mode = None
|
||||
self.mode_start_time = None
|
||||
notify(
|
||||
"\U0001f310 Browsing Mode Ended",
|
||||
"You can now use Steam.",
|
||||
"normal",
|
||||
)
|
||||
elif steam_running:
|
||||
log(
|
||||
"Steam detected during BROWSING mode "
|
||||
"- killing Steam"
|
||||
)
|
||||
kill_steam()
|
||||
|
||||
def update(self, processes: set[str]) -> None:
|
||||
"""Update focus mode based on running processes."""
|
||||
steam_running = is_steam_running(processes)
|
||||
browser_running = is_browser_running(processes)
|
||||
|
||||
if self.current_mode is None:
|
||||
# No mode set yet - first to start wins
|
||||
if steam_running and browser_running:
|
||||
# Both running at startup - prefer gaming mode (close browsers)
|
||||
log(
|
||||
"Both Steam and browsers detected at startup - entering GAMING mode"
|
||||
)
|
||||
self.current_mode = "gaming"
|
||||
self.mode_start_time = datetime.now()
|
||||
kill_browsers()
|
||||
elif steam_running:
|
||||
log("Steam detected - entering GAMING mode")
|
||||
self.current_mode = "gaming"
|
||||
self.mode_start_time = datetime.now()
|
||||
notify(
|
||||
"🎮 Gaming Mode",
|
||||
"Steam detected. Browsers are now blocked.",
|
||||
"normal",
|
||||
)
|
||||
elif browser_running:
|
||||
log("Browser detected - entering BROWSING mode")
|
||||
self.current_mode = "browsing"
|
||||
self.mode_start_time = datetime.now()
|
||||
notify(
|
||||
"🌐 Browsing Mode",
|
||||
"Browser detected. Steam is now blocked.",
|
||||
"normal",
|
||||
)
|
||||
|
||||
self._handle_no_mode(
|
||||
steam_running=steam_running,
|
||||
browser_running=browser_running,
|
||||
)
|
||||
elif self.current_mode == "gaming":
|
||||
if not steam_running:
|
||||
# Steam closed - exit gaming mode
|
||||
log("Steam closed - exiting GAMING mode")
|
||||
self.current_mode = None
|
||||
self.mode_start_time = None
|
||||
notify("🎮 Gaming Mode Ended", "You can now use browsers.", "normal")
|
||||
elif browser_running:
|
||||
# Browser started while in gaming mode - kill it
|
||||
log("Browser detected during GAMING mode - killing browsers")
|
||||
kill_browsers()
|
||||
|
||||
self._handle_gaming(
|
||||
steam_running=steam_running,
|
||||
browser_running=browser_running,
|
||||
)
|
||||
elif self.current_mode == "browsing":
|
||||
if not browser_running:
|
||||
# Browsers closed - exit browsing mode
|
||||
log("Browsers closed - exiting BROWSING mode")
|
||||
self.current_mode = None
|
||||
self.mode_start_time = None
|
||||
notify("🌐 Browsing Mode Ended", "You can now use Steam.", "normal")
|
||||
elif steam_running:
|
||||
# Steam started while in browsing mode - kill it
|
||||
log("Steam detected during BROWSING mode - killing Steam")
|
||||
kill_steam()
|
||||
self._handle_browsing(
|
||||
steam_running=steam_running,
|
||||
browser_running=browser_running,
|
||||
)
|
||||
|
||||
def get_status(self) -> str:
|
||||
"""Get current status string."""
|
||||
@ -266,33 +334,47 @@ class FocusMode:
|
||||
|
||||
duration = ""
|
||||
if self.mode_start_time:
|
||||
elapsed = datetime.now() - self.mode_start_time
|
||||
elapsed = (
|
||||
datetime.now(tz=timezone.utc)
|
||||
- self.mode_start_time
|
||||
)
|
||||
minutes = int(elapsed.total_seconds() // 60)
|
||||
duration = f" (active for {minutes}m)"
|
||||
|
||||
if self.current_mode == "gaming":
|
||||
return f"🎮 GAMING mode{duration} - browsers blocked"
|
||||
return f"🌐 BROWSING mode{duration} - Steam blocked"
|
||||
return (
|
||||
f"\U0001f3ae GAMING mode{duration}"
|
||||
" - browsers blocked"
|
||||
)
|
||||
return (
|
||||
f"\U0001f310 BROWSING mode{duration}"
|
||||
" - Steam blocked"
|
||||
)
|
||||
|
||||
|
||||
def write_status(focus: FocusMode) -> None:
|
||||
"""Write current status to state file for external queries."""
|
||||
try:
|
||||
with contextlib.suppress(OSError):
|
||||
STATE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
status_file = STATE_DIR / "status"
|
||||
with open(status_file, "w") as f:
|
||||
with status_file.open("w") as f:
|
||||
f.write(focus.get_status() + "\n")
|
||||
f.write(f"mode={focus.current_mode or 'none'}\n")
|
||||
except Exception:
|
||||
pass
|
||||
f.write(
|
||||
f"mode={focus.current_mode or 'none'}\n"
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
"""Main daemon loop."""
|
||||
def main() -> None:
|
||||
"""Run the main daemon loop."""
|
||||
logging.basicConfig(
|
||||
format="%(message)s", level=logging.INFO
|
||||
)
|
||||
log("Focus Mode Daemon starting...")
|
||||
|
||||
# Setup signal handlers
|
||||
def handle_signal(signum, frame):
|
||||
def handle_signal(
|
||||
signum: int, _frame: FrameType | None
|
||||
) -> None:
|
||||
"""Handle termination signals."""
|
||||
log(f"Received signal {signum} - shutting down")
|
||||
sys.exit(0)
|
||||
|
||||
@ -306,8 +388,11 @@ def main():
|
||||
processes = get_running_processes()
|
||||
focus.update(processes)
|
||||
write_status(focus)
|
||||
except Exception as e:
|
||||
log(f"Error in main loop: {e}")
|
||||
except (
|
||||
OSError,
|
||||
subprocess.SubprocessError,
|
||||
) as exc:
|
||||
log(f"Error in main loop: {exc}")
|
||||
|
||||
time.sleep(POLL_INTERVAL)
|
||||
|
||||
|
||||
@ -0,0 +1 @@
|
||||
"""Transcription and helper tools for testsAndMisc bash scripts."""
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,31 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Helper utilities for transcribe.sh - replaces inline Python snippets."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import array
|
||||
import importlib
|
||||
import logging
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
from typing import TYPE_CHECKING
|
||||
import wave
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import types
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _try_import(name: str) -> types.ModuleType | None:
|
||||
"""Attempt to import a module, returning None on failure."""
|
||||
try:
|
||||
return importlib.import_module(name)
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
|
||||
def get_python_version() -> str:
|
||||
"""Return Python major.minor version string."""
|
||||
@ -16,42 +34,36 @@ def get_python_version() -> str:
|
||||
|
||||
def check_faster_whisper() -> bool:
|
||||
"""Check if faster_whisper is importable. Exit 7 if not."""
|
||||
try:
|
||||
import faster_whisper # noqa: F401
|
||||
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
return _try_import("faster_whisper") is not None
|
||||
|
||||
|
||||
def check_diarization_deps() -> bool:
|
||||
"""Check if diarization dependencies are available. Returns False with warning if missing."""
|
||||
try:
|
||||
import soundfile # noqa: F401
|
||||
import speechbrain # noqa: F401
|
||||
import torch # noqa: F401
|
||||
"""Check if diarization dependencies are available.
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(
|
||||
f"[WARN] Diarization deps missing offline ({e}); speaker labels will be skipped."
|
||||
Returns False with warning if missing.
|
||||
"""
|
||||
_sf = _try_import("soundfile")
|
||||
_sb = _try_import("speechbrain")
|
||||
_torch = _try_import("torch")
|
||||
if _sf is None or _sb is None or _torch is None:
|
||||
logger.warning(
|
||||
"Diarization deps missing offline; "
|
||||
"speaker labels will be skipped.",
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def check_ctranslate2() -> bool:
|
||||
"""Check if ctranslate2 is importable."""
|
||||
try:
|
||||
import ctranslate2 # noqa: F401
|
||||
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
return _try_import("ctranslate2") is not None
|
||||
|
||||
|
||||
def print_deps_installed():
|
||||
def print_deps_installed() -> None:
|
||||
"""Print confirmation that Python dependencies are installed."""
|
||||
print(f"[PY] Python {sys.version.split()[0]} dependencies installed.")
|
||||
logger.info(
|
||||
"Python %s dependencies installed.", sys.version.split()[0]
|
||||
)
|
||||
|
||||
|
||||
def generate_sine_wav(
|
||||
@ -84,7 +96,12 @@ def generate_sine_wav(
|
||||
min(
|
||||
1.0,
|
||||
amplitude
|
||||
* math.sin(2 * math.pi * frequency * (i / sample_rate)),
|
||||
* math.sin(
|
||||
2
|
||||
* math.pi
|
||||
* frequency
|
||||
* (i / sample_rate)
|
||||
),
|
||||
),
|
||||
)
|
||||
* 32767
|
||||
@ -97,10 +114,11 @@ def generate_sine_wav(
|
||||
wf.setsampwidth(2)
|
||||
wf.setframerate(sample_rate)
|
||||
wf.writeframes(data.tobytes())
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Failed to generate WAV: {e}", file=sys.stderr)
|
||||
except OSError:
|
||||
logger.exception("Failed to generate WAV")
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def prepare_model(model_name: str, model_dir: str) -> bool:
|
||||
@ -113,35 +131,40 @@ def prepare_model(model_name: str, model_dir: str) -> bool:
|
||||
Returns:
|
||||
True on success, False on failure
|
||||
"""
|
||||
try:
|
||||
from faster_whisper import WhisperModel
|
||||
|
||||
# Enable HuggingFace Hub progress bars for model download
|
||||
try:
|
||||
from huggingface_hub import logging as hf_logging
|
||||
|
||||
hf_logging.set_verbosity_info()
|
||||
import huggingface_hub
|
||||
|
||||
huggingface_hub.constants.HF_HUB_DISABLE_PROGRESS_BARS = False
|
||||
os.environ["HF_HUB_DISABLE_PROGRESS_BARS"] = "0"
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
print(f"[PY] Preparing model '{model_name}' into {model_dir}")
|
||||
print(
|
||||
"[INFO] Downloading model files (progress bar should appear below)...",
|
||||
flush=True,
|
||||
)
|
||||
WhisperModel(
|
||||
model_name, device="cpu", compute_type="int8", download_root=model_dir
|
||||
)
|
||||
print("[PY] Model prepared.")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Failed to prepare model: {e}", file=sys.stderr)
|
||||
fw = _try_import("faster_whisper")
|
||||
if fw is None:
|
||||
logger.error("faster_whisper is not installed")
|
||||
return False
|
||||
|
||||
try:
|
||||
hf_logging = _try_import("huggingface_hub.logging")
|
||||
if hf_logging is not None:
|
||||
hf_logging.set_verbosity_info()
|
||||
hh = _try_import("huggingface_hub")
|
||||
if hh is not None:
|
||||
hh.constants.HF_HUB_DISABLE_PROGRESS_BARS = False
|
||||
os.environ["HF_HUB_DISABLE_PROGRESS_BARS"] = "0"
|
||||
|
||||
logger.info(
|
||||
"Preparing model '%s' into %s", model_name, model_dir
|
||||
)
|
||||
logger.info(
|
||||
"Downloading model files "
|
||||
"(progress bar should appear below)...",
|
||||
)
|
||||
fw.WhisperModel(
|
||||
model_name,
|
||||
device="cpu",
|
||||
compute_type="int8",
|
||||
download_root=model_dir,
|
||||
)
|
||||
logger.info("Model prepared.")
|
||||
except (OSError, RuntimeError):
|
||||
logger.exception("Failed to prepare model")
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def test_cuda() -> bool:
|
||||
"""Test CUDA initialization with faster-whisper.
|
||||
@ -149,30 +172,96 @@ def test_cuda() -> bool:
|
||||
Returns:
|
||||
True if CUDA works, False otherwise
|
||||
"""
|
||||
try:
|
||||
from faster_whisper import WhisperModel
|
||||
|
||||
WhisperModel("tiny", device="cuda", compute_type="float16")
|
||||
print("[PY] CUDA test init succeeded.")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"[ERROR] CUDA test failed: {e}", file=sys.stderr)
|
||||
fw = _try_import("faster_whisper")
|
||||
if fw is None:
|
||||
logger.error("faster_whisper is not installed")
|
||||
return False
|
||||
|
||||
try:
|
||||
fw.WhisperModel(
|
||||
"tiny", device="cuda", compute_type="float16"
|
||||
)
|
||||
logger.info("CUDA test init succeeded.")
|
||||
except (OSError, RuntimeError):
|
||||
logger.exception("CUDA test failed")
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def _handle_python_version() -> None:
|
||||
"""Handle python-version command."""
|
||||
logger.info("%s", get_python_version())
|
||||
|
||||
|
||||
def _handle_check_faster_whisper() -> None:
|
||||
"""Handle check-faster-whisper command."""
|
||||
if not check_faster_whisper():
|
||||
logger.error(
|
||||
"Python dependency 'faster_whisper' not found in "
|
||||
"offline mode. Run with --online to install.",
|
||||
)
|
||||
sys.exit(7)
|
||||
|
||||
|
||||
def _handle_check_diarization() -> None:
|
||||
"""Handle check-diarization command."""
|
||||
check_diarization_deps()
|
||||
|
||||
|
||||
def _handle_check_ctranslate2() -> None:
|
||||
"""Handle check-ctranslate2 command."""
|
||||
if not check_ctranslate2():
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def _handle_deps_installed() -> None:
|
||||
"""Handle deps-installed command."""
|
||||
print_deps_installed()
|
||||
|
||||
|
||||
def _handle_generate_wav(args: argparse.Namespace) -> None:
|
||||
"""Handle generate-wav command."""
|
||||
if not args.file:
|
||||
logger.error("--file is required for generate-wav")
|
||||
sys.exit(2)
|
||||
if not generate_sine_wav(args.file):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def _handle_prepare_model(args: argparse.Namespace) -> None:
|
||||
"""Handle prepare-model command."""
|
||||
if not args.model or not args.model_dir:
|
||||
logger.error(
|
||||
"--model and --model-dir are required for prepare-model",
|
||||
)
|
||||
sys.exit(2)
|
||||
if not prepare_model(args.model, args.model_dir):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def _handle_test_cuda() -> None:
|
||||
"""Handle test-cuda command."""
|
||||
if not test_cuda():
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Parse arguments and dispatch helper commands."""
|
||||
logging.basicConfig(format="%(message)s", level=logging.INFO)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Helper utilities for transcribe.sh",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Commands:
|
||||
python-version Print Python major.minor version
|
||||
check-faster-whisper Check if faster_whisper is installed (exit 7 if not)
|
||||
check-faster-whisper Check if faster_whisper is installed
|
||||
check-diarization Check diarization deps (warn if missing)
|
||||
check-ctranslate2 Check if ctranslate2 is installed (exit 1 if not)
|
||||
deps-installed Print deps installed confirmation message
|
||||
generate-wav FILE Generate a 3s 1kHz sine wave WAV file
|
||||
prepare-model Download model for offline use (requires --model and --model-dir)
|
||||
check-ctranslate2 Check if ctranslate2 is installed
|
||||
deps-installed Print deps installed confirmation
|
||||
generate-wav FILE Generate a 3s 1kHz sine wave WAV
|
||||
prepare-model Download model for offline use
|
||||
test-cuda Test CUDA initialization
|
||||
""",
|
||||
)
|
||||
@ -190,46 +279,32 @@ Commands:
|
||||
],
|
||||
help="Command to run",
|
||||
)
|
||||
parser.add_argument("--file", help="Output file path (for generate-wav)")
|
||||
parser.add_argument("--model", help="Model name (for prepare-model)")
|
||||
parser.add_argument("--model-dir", help="Model directory (for prepare-model)")
|
||||
parser.add_argument(
|
||||
"--file", help="Output file path (for generate-wav)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--model", help="Model name (for prepare-model)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--model-dir", help="Model directory (for prepare-model)"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.command == "python-version":
|
||||
print(get_python_version())
|
||||
elif args.command == "check-faster-whisper":
|
||||
if not check_faster_whisper():
|
||||
print(
|
||||
"Python dependency 'faster_whisper' not found in offline mode. Run with --online to install.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(7)
|
||||
elif args.command == "check-diarization":
|
||||
check_diarization_deps()
|
||||
elif args.command == "check-ctranslate2":
|
||||
if not check_ctranslate2():
|
||||
sys.exit(1)
|
||||
elif args.command == "deps-installed":
|
||||
print_deps_installed()
|
||||
elif args.command == "generate-wav":
|
||||
if not args.file:
|
||||
print("--file is required for generate-wav", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
if not generate_sine_wav(args.file):
|
||||
sys.exit(1)
|
||||
elif args.command == "prepare-model":
|
||||
if not args.model or not args.model_dir:
|
||||
print(
|
||||
"--model and --model-dir are required for prepare-model",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(2)
|
||||
if not prepare_model(args.model, args.model_dir):
|
||||
sys.exit(1)
|
||||
elif args.command == "test-cuda":
|
||||
if not test_cuda():
|
||||
sys.exit(1)
|
||||
dispatch: dict[str, object] = {
|
||||
"python-version": _handle_python_version,
|
||||
"check-faster-whisper": _handle_check_faster_whisper,
|
||||
"check-diarization": _handle_check_diarization,
|
||||
"check-ctranslate2": _handle_check_ctranslate2,
|
||||
"deps-installed": _handle_deps_installed,
|
||||
"generate-wav": lambda: _handle_generate_wav(args),
|
||||
"prepare-model": lambda: _handle_prepare_model(args),
|
||||
"test-cuda": _handle_test_cuda,
|
||||
}
|
||||
|
||||
handler = dispatch.get(args.command)
|
||||
if handler is not None and callable(handler):
|
||||
handler()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Loading…
Reference in New Issue
Block a user