More pep8 fixes. A tiny bit of refactoring.
This commit is contained in:
@ -1,9 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import subprocess
|
||||
import importlib.util
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
from fenrirscreenreader.core import debug
|
||||
|
||||
|
||||
@ -27,11 +28,12 @@ class DynamicVoiceCommand:
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
f"Testing voice {
|
||||
self.voice} from {
|
||||
self.module}. Please wait.",
|
||||
interrupt=True)
|
||||
interrupt=True,
|
||||
)
|
||||
|
||||
# Brief pause before testing to avoid speech overlap
|
||||
time.sleep(0.5)
|
||||
@ -39,45 +41,57 @@ class DynamicVoiceCommand:
|
||||
# Test voice
|
||||
testResult, errorMsg = self.test_voice()
|
||||
if testResult:
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
"Voice test completed successfully. Navigate to Apply Tested Voice to use this voice.",
|
||||
interrupt=False,
|
||||
flush=False)
|
||||
flush=False,
|
||||
)
|
||||
|
||||
# Store for confirmation (use same variables as
|
||||
# apply_tested_voice.py)
|
||||
self.env['commandBuffer']['lastTestedModule'] = self.module
|
||||
self.env['commandBuffer']['lastTestedVoice'] = self.voice
|
||||
self.env['commandBuffer']['pendingVoiceModule'] = self.module
|
||||
self.env['commandBuffer']['pendingVoiceVoice'] = self.voice
|
||||
self.env['commandBuffer']['voiceTestCompleted'] = True
|
||||
self.env["commandBuffer"]["lastTestedModule"] = self.module
|
||||
self.env["commandBuffer"]["lastTestedVoice"] = self.voice
|
||||
self.env["commandBuffer"]["pendingVoiceModule"] = self.module
|
||||
self.env["commandBuffer"]["pendingVoiceVoice"] = self.voice
|
||||
self.env["commandBuffer"]["voiceTestCompleted"] = True
|
||||
else:
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
f"Voice test failed: {errorMsg}", interrupt=False, flush=False)
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
f"Voice test failed: {errorMsg}",
|
||||
interrupt=False,
|
||||
flush=False,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
f"Voice selection error: {str(e)}", interrupt=False, flush=False)
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
f"Voice selection error: {str(e)}",
|
||||
interrupt=False,
|
||||
flush=False,
|
||||
)
|
||||
|
||||
def test_voice(self):
|
||||
"""Test voice with spd-say"""
|
||||
try:
|
||||
cmd = [
|
||||
'spd-say',
|
||||
'-C',
|
||||
'-w',
|
||||
'-o',
|
||||
"spd-say",
|
||||
"-C",
|
||||
"-w",
|
||||
"-o",
|
||||
self.module,
|
||||
'-y',
|
||||
"-y",
|
||||
self.voice,
|
||||
self.testMessage]
|
||||
self.testMessage,
|
||||
]
|
||||
result = subprocess.run(
|
||||
cmd, timeout=8, capture_output=True, text=True)
|
||||
cmd, timeout=8, capture_output=True, text=True
|
||||
)
|
||||
if result.returncode == 0:
|
||||
return True, "Voice test successful"
|
||||
else:
|
||||
error_msg = result.stderr.strip(
|
||||
) if result.stderr else f"Command failed with return code {result.returncode}"
|
||||
error_msg = (
|
||||
result.stderr.strip()
|
||||
if result.stderr
|
||||
else f"Command failed with return code {result.returncode}"
|
||||
)
|
||||
return False, error_msg
|
||||
except subprocess.TimeoutExpired:
|
||||
return False, "Voice test timed out"
|
||||
@ -105,47 +119,55 @@ class DynamicApplyVoiceCommand:
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
if not self.env['commandBuffer'].get('voiceTestCompleted', False):
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
"No voice has been tested yet", interrupt=True)
|
||||
if not self.env["commandBuffer"].get("voiceTestCompleted", False):
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
"No voice has been tested yet", interrupt=True
|
||||
)
|
||||
return
|
||||
|
||||
module = self.env['commandBuffer']['pendingVoiceModule']
|
||||
voice = self.env['commandBuffer']['pendingVoiceVoice']
|
||||
module = self.env["commandBuffer"]["pendingVoiceModule"]
|
||||
voice = self.env["commandBuffer"]["pendingVoiceVoice"]
|
||||
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
f"Applying {voice} from {module}", interrupt=True)
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
f"Applying {voice} from {module}", interrupt=True
|
||||
)
|
||||
|
||||
# Debug: Show current settings
|
||||
settings_manager = self.env['runtime']['SettingsManager']
|
||||
current_module = settings_manager.get_setting('speech', 'module')
|
||||
current_voice = settings_manager.get_setting('speech', 'voice')
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
f"Current: {current_voice} from {current_module}", interrupt=False, flush=False)
|
||||
settings_manager = self.env["runtime"]["SettingsManager"]
|
||||
current_module = settings_manager.get_setting("speech", "module")
|
||||
current_voice = settings_manager.get_setting("speech", "voice")
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
f"Current: {current_voice} from {current_module}",
|
||||
interrupt=False,
|
||||
flush=False,
|
||||
)
|
||||
|
||||
# Apply to runtime settings with fallback
|
||||
settings_manager = self.env['runtime']['SettingsManager']
|
||||
settings_manager = self.env["runtime"]["SettingsManager"]
|
||||
|
||||
# Store old values for safety
|
||||
old_driver = settings_manager.get_setting('speech', 'driver')
|
||||
old_module = settings_manager.get_setting('speech', 'module')
|
||||
old_voice = settings_manager.get_setting('speech', 'voice')
|
||||
old_driver = settings_manager.get_setting("speech", "driver")
|
||||
old_module = settings_manager.get_setting("speech", "module")
|
||||
old_voice = settings_manager.get_setting("speech", "voice")
|
||||
|
||||
try:
|
||||
# Apply new settings to runtime only (use set_setting to update
|
||||
# settingArgDict)
|
||||
settings_manager.set_setting('speech', 'driver', 'speechdDriver')
|
||||
settings_manager.set_setting('speech', 'module', module)
|
||||
settings_manager.set_setting('speech', 'voice', voice)
|
||||
settings_manager.set_setting(
|
||||
"speech", "driver", "speechdDriver"
|
||||
)
|
||||
settings_manager.set_setting("speech", "module", module)
|
||||
settings_manager.set_setting("speech", "voice", voice)
|
||||
|
||||
# Apply settings to speech driver directly
|
||||
if 'SpeechDriver' in self.env['runtime']:
|
||||
SpeechDriver = self.env['runtime']['SpeechDriver']
|
||||
if "SpeechDriver" in self.env["runtime"]:
|
||||
SpeechDriver = self.env["runtime"]["SpeechDriver"]
|
||||
|
||||
# Get current module to see if we're changing modules
|
||||
current_module = settings_manager.get_setting(
|
||||
'speech', 'module')
|
||||
module_changing = (current_module != module)
|
||||
"speech", "module"
|
||||
)
|
||||
module_changing = current_module != module
|
||||
|
||||
# Set module and voice on driver instance first
|
||||
SpeechDriver.set_module(module)
|
||||
@ -154,61 +176,75 @@ class DynamicApplyVoiceCommand:
|
||||
if module_changing:
|
||||
# Module change requires reinitializing the speech
|
||||
# driver
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
f"Switching from {current_module} to {module} module", interrupt=True)
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
f"Switching from {current_module} to {module} module",
|
||||
interrupt=True,
|
||||
)
|
||||
SpeechDriver.shutdown()
|
||||
SpeechDriver.initialize(self.env)
|
||||
# Re-set after initialization
|
||||
SpeechDriver.set_module(module)
|
||||
SpeechDriver.set_voice(voice)
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
"Speech driver reinitialized", interrupt=True)
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
"Speech driver reinitialized", interrupt=True
|
||||
)
|
||||
|
||||
# Debug: verify what was actually set
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
f"Speech driver now has module: {
|
||||
SpeechDriver.module}, voice: {
|
||||
SpeechDriver.voice}", interrupt=True)
|
||||
SpeechDriver.voice}",
|
||||
interrupt=True,
|
||||
)
|
||||
|
||||
# Force application by speaking a test message
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
"Voice applied successfully! You should hear this in the new voice.", interrupt=True)
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
"Voice applied successfully! You should hear this in the new voice.",
|
||||
interrupt=True,
|
||||
)
|
||||
|
||||
# Brief pause then more speech to test
|
||||
time.sleep(1)
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
"Use save settings to make permanent", interrupt=True)
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
"Use save settings to make permanent", interrupt=True
|
||||
)
|
||||
|
||||
# Clear pending state
|
||||
self.env['commandBuffer']['voiceTestCompleted'] = False
|
||||
self.env["commandBuffer"]["voiceTestCompleted"] = False
|
||||
|
||||
# Exit vmenu after successful application
|
||||
self.env['runtime']['VmenuManager'].set_active(False)
|
||||
self.env["runtime"]["VmenuManager"].set_active(False)
|
||||
|
||||
except Exception as e:
|
||||
# Revert on failure
|
||||
settings_manager.settings['speech']['driver'] = old_driver
|
||||
settings_manager.settings['speech']['module'] = old_module
|
||||
settings_manager.settings['speech']['voice'] = old_voice
|
||||
settings_manager.settings["speech"]["driver"] = old_driver
|
||||
settings_manager.settings["speech"]["module"] = old_module
|
||||
settings_manager.settings["speech"]["voice"] = old_voice
|
||||
|
||||
# Try to reinitialize with old settings
|
||||
if 'SpeechDriver' in self.env['runtime']:
|
||||
if "SpeechDriver" in self.env["runtime"]:
|
||||
try:
|
||||
SpeechDriver = self.env['runtime']['SpeechDriver']
|
||||
SpeechDriver = self.env["runtime"]["SpeechDriver"]
|
||||
SpeechDriver.shutdown()
|
||||
SpeechDriver.initialize(self.env)
|
||||
except Exception as e:
|
||||
self.env['runtime']['DebugManager'].write_debug_out(
|
||||
'dynamicVoiceMenu: Error reinitializing speech driver: ' + str(e),
|
||||
debug.DebugLevel.ERROR)
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
"dynamicVoiceMenu: Error reinitializing speech driver: "
|
||||
+ str(e),
|
||||
debug.DebugLevel.ERROR,
|
||||
)
|
||||
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
f"Failed to apply voice, reverted: {
|
||||
str(e)}", interrupt=False, flush=False)
|
||||
str(e)}",
|
||||
interrupt=False,
|
||||
flush=False,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
f"Apply voice error: {str(e)}", interrupt=False, flush=False)
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
f"Apply voice error: {str(e)}", interrupt=False, flush=False
|
||||
)
|
||||
|
||||
def set_callback(self, callback):
|
||||
pass
|
||||
@ -229,10 +265,12 @@ def add_dynamic_voice_menus(VmenuManager):
|
||||
|
||||
# Add apply voice command
|
||||
apply_command = DynamicApplyVoiceCommand(env)
|
||||
voice_browser_menu['Apply Tested Voice Action'] = apply_command
|
||||
voice_browser_menu["Apply Tested Voice Action"] = apply_command
|
||||
|
||||
# Add modules as submenus
|
||||
for module in modules[:8]: # Limit to 8 modules to keep menu manageable
|
||||
for module in modules[
|
||||
:8
|
||||
]: # Limit to 8 modules to keep menu manageable
|
||||
module_menu = {}
|
||||
|
||||
# Get voices for this module
|
||||
@ -244,40 +282,50 @@ def add_dynamic_voice_menus(VmenuManager):
|
||||
voice_command = DynamicVoiceCommand(module, voice, env)
|
||||
module_menu[f"{voice} Action"] = voice_command
|
||||
else:
|
||||
module_menu['No voices available Action'] = create_info_command(
|
||||
f"No voices found for {module}", env)
|
||||
module_menu["No voices available Action"] = (
|
||||
create_info_command(f"No voices found for {module}", env)
|
||||
)
|
||||
|
||||
voice_browser_menu[f"{module} Menu"] = module_menu
|
||||
|
||||
# Add to main menu dict
|
||||
VmenuManager.menuDict['Voice Browser Menu'] = voice_browser_menu
|
||||
VmenuManager.menuDict["Voice Browser Menu"] = voice_browser_menu
|
||||
|
||||
except Exception as e:
|
||||
# Use debug manager instead of print for error logging
|
||||
if 'DebugManager' in env['runtime']:
|
||||
env['runtime']['DebugManager'].write_debug_out(
|
||||
if "DebugManager" in env["runtime"]:
|
||||
env["runtime"]["DebugManager"].write_debug_out(
|
||||
f"Error creating dynamic voice menus: {e}",
|
||||
debug.DebugLevel.ERROR)
|
||||
debug.DebugLevel.ERROR,
|
||||
)
|
||||
else:
|
||||
print(f"Error creating dynamic voice menus: {e}")
|
||||
|
||||
|
||||
def create_info_command(message, env):
|
||||
"""Create a simple info command"""
|
||||
|
||||
class InfoCommand:
|
||||
def __init__(self, message, env):
|
||||
self.message = message
|
||||
self.env = env
|
||||
|
||||
def initialize(self, environment): pass
|
||||
def shutdown(self): pass
|
||||
def get_description(self): return self.message
|
||||
def initialize(self, environment):
|
||||
pass
|
||||
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
def get_description(self):
|
||||
return self.message
|
||||
|
||||
def run(self):
|
||||
self.env['runtime']['OutputManager'].present_text(
|
||||
self.message, interrupt=True)
|
||||
self.env["runtime"]["OutputManager"].present_text(
|
||||
self.message, interrupt=True
|
||||
)
|
||||
|
||||
def set_callback(self, callback): pass
|
||||
def set_callback(self, callback):
|
||||
pass
|
||||
|
||||
return InfoCommand(message, env)
|
||||
|
||||
@ -286,9 +334,10 @@ def get_speechd_modules():
|
||||
"""Get available speech modules"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['spd-say', '-O'], capture_output=True, text=True, timeout=5)
|
||||
["spd-say", "-O"], capture_output=True, text=True, timeout=5
|
||||
)
|
||||
if result.returncode == 0:
|
||||
lines = result.stdout.strip().split('\n')
|
||||
lines = result.stdout.strip().split("\n")
|
||||
return [line.strip() for line in lines[1:] if line.strip()]
|
||||
except Exception:
|
||||
pass
|
||||
@ -299,14 +348,18 @@ def get_module_voices(module):
|
||||
"""Get voices for a module"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['spd-say', '-o', module, '-L'], capture_output=True, text=True, timeout=8)
|
||||
["spd-say", "-o", module, "-L"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=8,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
lines = result.stdout.strip().split('\n')
|
||||
lines = result.stdout.strip().split("\n")
|
||||
voices = []
|
||||
for line in lines[1:]:
|
||||
if not line.strip():
|
||||
continue
|
||||
if module.lower() == 'espeak-ng':
|
||||
if module.lower() == "espeak-ng":
|
||||
voice = process_espeak_voice(line)
|
||||
if voice:
|
||||
voices.append(voice)
|
||||
@ -326,6 +379,10 @@ def process_espeak_voice(voiceLine):
|
||||
return None
|
||||
lang_code = parts[-2].lower()
|
||||
variant = parts[-1].lower()
|
||||
return f"{lang_code}+{variant}" if variant and variant != 'none' else lang_code
|
||||
return (
|
||||
f"{lang_code}+{variant}"
|
||||
if variant and variant != "none"
|
||||
else lang_code
|
||||
)
|
||||
except Exception:
|
||||
return None
|
||||
|
Reference in New Issue
Block a user