Files
smart-speaker/app/audio/sound_level.py

165 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Volume control module.
Regulates system volume on a scale from 1 to 10.
"""
# Модуль управления громкостью системы.
# Работает через различные системные утилиты в зависимости от ОС.
import subprocess
import re
import platform
from ..core.roman import replace_roman_numerals
# Карта для перевода слов в цифры ("пять" -> 5)
NUMBER_MAP = {
"один": 1,
"раз": 1,
"два": 2,
"три": 3,
"четыре": 4,
"пять": 5,
"шесть": 6,
"семь": 7,
"восемь": 8,
"девять": 9,
"десять": 10,
}
def _get_volume_command(level: int):
"""
Возвращает команду для изменения громкости в зависимости от ОС.
Args:
level: Уровень громкости (1-10)
Returns:
Список команд для выполнения или None, если команда не поддерживается
"""
percentage = level * 10
system = platform.system().lower()
if system == "linux":
# Проверяем доступность различных утилит
if _command_exists("pactl"):
# Используем PulseAudio (более современный подход)
return ["pactl", "set-sink-volume", "@DEFAULT_SINK@", f"{percentage}%"]
elif _command_exists("amixer"):
# Используем ALSA
return ["amixer", "-q", "sset", "Master", f"{percentage}%"]
else:
# Проверяем alsamixer
if _command_exists("alsamixer"):
return ["amixer", "-q", "sset", "Master", f"{percentage}%"]
elif system == "darwin": # macOS
return ["osascript", "-e", f"set volume output volume {percentage}"]
elif system == "windows":
# Для Windows используем PowerShell команду
# Это требует дополнительных библиотек, поэтому пока просто покажем сообщение
print("⚠️ Настройка громкости на Windows требует дополнительных библиотек")
return None
return None
def _command_exists(command):
"""
Проверяет, существует ли команда в системе.
Args:
command: Название команды
Returns:
True, если команда существует
"""
try:
result = subprocess.run(
["which", command],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=False,
)
return result.returncode == 0
except:
try:
# Альтернативная проверка для Windows
result = subprocess.run(
["where", command],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=False,
)
return result.returncode == 0
except:
return False
def set_volume(level: int) -> bool:
"""
Устанавливает системную громкость (шкала 1-10).
1 -> 10%
10 -> 100%
Args:
level: Число от 1 до 10.
Returns:
True, если успешно.
"""
if not isinstance(level, int):
print(
f"❌ Ошибка: Уровень громкости должен быть целым числом, получено {type(level)}"
)
return False
# Ограничение диапазона
if level < 1:
level = 1
elif level > 10:
level = 10
percentage = level * 10
# Получаем команду для текущей ОС
cmd = _get_volume_command(level)
if cmd is None:
print(f"Не найдена подходящая утилита для изменения громкости на вашей системе")
print(f"💡 Установите PulseAudio (pactl) или ALSA (amixer) для управления громкостью")
return False
try:
# Выполняем команду
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
print(f"🔊 Громкость установлена на {level} ({percentage}%)")
return True
except subprocess.CalledProcessError as e:
print(f"❌ Ошибка при установке громкости: {e}")
print(f"💡 Убедитесь, что у вас установлены и настроены аудио утилиты (pactl, amixer)")
return False
except Exception as e:
print(f"❌ Неизвестная ошибка громкости: {e}")
return False
def parse_volume_text(text: str) -> int | None:
"""
Пытается найти число громкости в тексте.
Понимает и цифры ("5"), и слова ("пять").
"""
text = replace_roman_numerals(text.lower())
# 1. Ищем цифры (1-10)
num_match = re.search(r"\b(10|[1-9])\b", text)
if num_match:
return int(num_match.group())
# 2. Ищем слова из словаря
for word, value in NUMBER_MAP.items():
if word in text:
return value
return None