uninstall.pyā¢8.39 kB
"""Uninstall tool for Whisper STT service."""
import os
import shutil
import subprocess
import platform
import logging
from pathlib import Path
from typing import Dict, Any, Union
from voice_mode.server import mcp
from voice_mode.config import BASE_DIR
from voice_mode.utils.services.common import find_process_by_port
logger = logging.getLogger("voicemode")
@mcp.tool()
async def whisper_uninstall(
remove_models: Union[bool, str] = False,
remove_all_data: Union[bool, str] = False
) -> Dict[str, Any]:
"""Uninstall whisper.cpp and optionally remove models and data.
This tool will:
1. Stop any running Whisper service
2. Remove service configurations (launchd/systemd)
3. Remove the whisper.cpp installation
4. Optionally remove downloaded models
5. Optionally remove all Whisper-related data
Args:
remove_models: Also remove downloaded Whisper models (default: False)
remove_all_data: Remove all Whisper data including logs and transcriptions (default: False)
Returns:
Dictionary with uninstall status and details
"""
system = platform.system()
removed_items = []
errors = []
try:
# 1. Stop any running Whisper service
logger.info("Checking for running Whisper service...")
proc = find_process_by_port(2022)
if proc:
try:
logger.info(f"Stopping Whisper service (PID: {proc.pid})...")
proc.terminate()
proc.wait(timeout=5)
removed_items.append("Stopped running Whisper service")
except Exception as e:
logger.warning(f"Failed to stop Whisper service: {e}")
# 2. Remove service configurations
if system == "Darwin":
# Remove launchd plist files (check both old and new names)
plist_names = [
"com.voicemode.whisper.plist",
"com.voicemode.whisper-server.plist" # Old name for compatibility
]
for plist_name in plist_names:
plist_path = Path.home() / "Library" / "LaunchAgents" / plist_name
if plist_path.exists():
try:
# Unload if loaded
subprocess.run(
["launchctl", "unload", str(plist_path)],
capture_output=True
)
# Remove file
plist_path.unlink()
removed_items.append(f"Removed launchd configuration: {plist_name}")
logger.info(f"Removed {plist_path}")
except Exception as e:
errors.append(f"Failed to remove {plist_path}: {e}")
elif system == "Linux":
# Remove systemd service files
service_names = [
"voicemode-whisper.service",
"whisper-server.service" # Old name for compatibility
]
systemd_user_dir = Path.home() / ".config" / "systemd" / "user"
for service_name in service_names:
service_path = systemd_user_dir / service_name
if service_path.exists():
try:
# Stop and disable service
subprocess.run(
["systemctl", "--user", "stop", service_name],
capture_output=True,
stderr=subprocess.DEVNULL
)
subprocess.run(
["systemctl", "--user", "disable", service_name],
capture_output=True,
stderr=subprocess.DEVNULL
)
# Remove file
service_path.unlink()
# Reload systemd
subprocess.run(["systemctl", "--user", "daemon-reload"], check=True)
removed_items.append(f"Removed systemd service: {service_name}")
logger.info(f"Removed {service_path}")
except Exception as e:
errors.append(f"Failed to remove {service_path}: {e}")
# 3. Remove whisper.cpp installation
# Check new location first, then legacy location
whisper_dirs = [
BASE_DIR / "services" / "whisper", # New location
BASE_DIR / "whisper.cpp" # Legacy location
]
for whisper_dir in whisper_dirs:
if whisper_dir.exists():
try:
shutil.rmtree(whisper_dir)
removed_items.append(f"Removed whisper.cpp installation: {whisper_dir}")
logger.info(f"Removed {whisper_dir}")
except Exception as e:
errors.append(f"Failed to remove {whisper_dir}: {e}")
# 4. Optionally remove models
if remove_models:
models_dir = BASE_DIR / "models" / "whisper"
if models_dir.exists():
try:
shutil.rmtree(models_dir)
removed_items.append(f"Removed Whisper models: {models_dir}")
logger.info(f"Removed {models_dir}")
except Exception as e:
errors.append(f"Failed to remove {models_dir}: {e}")
# 5. Optionally remove all data
if remove_all_data:
# Remove logs
log_files = [
BASE_DIR / "logs" / "whisper" / "whisper.out.log", # New location
BASE_DIR / "logs" / "whisper" / "whisper.err.log", # New location
BASE_DIR / "logs" / "whisper.out.log", # Legacy location
BASE_DIR / "logs" / "whisper.err.log", # Legacy location
BASE_DIR / "whisper-server.log",
BASE_DIR / "whisper-server.stdout.log",
BASE_DIR / "whisper-server.stderr.log",
BASE_DIR / "whisper-server.error.log"
]
# Also remove the whisper logs directory if empty
whisper_log_dir = BASE_DIR / "logs" / "whisper"
for log_file in log_files:
if log_file.exists():
try:
log_file.unlink()
removed_items.append(f"Removed log file: {log_file.name}")
except Exception as e:
errors.append(f"Failed to remove {log_file}: {e}")
# Remove any whisper-specific transcriptions
transcriptions_dir = BASE_DIR / "transcriptions"
if transcriptions_dir.exists():
for file in transcriptions_dir.glob("whisper_*.txt"):
try:
file.unlink()
removed_items.append(f"Removed transcription: {file.name}")
except Exception as e:
errors.append(f"Failed to remove {file}: {e}")
# Prepare response
success = len(errors) == 0
if success:
message = "Whisper has been successfully uninstalled"
if remove_models:
message += " (including models)"
if remove_all_data:
message += " (including all data)"
else:
message = "Whisper uninstall completed with some errors"
return {
"success": success,
"message": message,
"removed_items": removed_items,
"errors": errors,
"summary": {
"items_removed": len(removed_items),
"errors_encountered": len(errors)
}
}
except Exception as e:
logger.error(f"Unexpected error during Whisper uninstall: {e}")
return {
"success": False,
"message": f"Failed to uninstall Whisper: {str(e)}",
"removed_items": removed_items,
"errors": errors + [str(e)],
"summary": {
"items_removed": len(removed_items),
"errors_encountered": len(errors) + 1
}
}