This commit is contained in:
dingfeng.wong
2025-07-23 12:36:34 +08:00
parent 6e2bda5cfb
commit 30cdcd8fba
6 changed files with 1451 additions and 14 deletions
+1
View File
@@ -27,3 +27,4 @@ wheels/
/Users/wongdingfeng/.config/tooling/.env /Users/wongdingfeng/.config/tooling/.env
/Users/wongdingfeng/.config/tooling/.DS_Store /Users/wongdingfeng/.config/tooling/.DS_Store
/Users/wongdingfeng/.config/tooling/Thumbs.db /Users/wongdingfeng/.config/tooling/Thumbs.db
uv.lock
+2 -1
View File
@@ -13,8 +13,9 @@ dependencies = [
"python-doctr>=0.8.0", "python-doctr>=0.8.0",
"typer>=0.12.0", "typer>=0.12.0",
"rich>=13.0.0", "rich>=13.0.0",
"realtimestt>=0.3.104",
"rumps>=0.4.0", "rumps>=0.4.0",
"realtimestt>=0.3.104",
"pyautogui>=0.9.54",
] ]
[project.optional-dependencies] [project.optional-dependencies]
+1408
View File
File diff suppressed because it is too large Load Diff
+19 -13
View File
@@ -28,6 +28,12 @@ try:
except ImportError: except ImportError:
RUMPS_AVAILABLE = False RUMPS_AVAILABLE = False
try:
import pyautogui
PYAUTOGUI_AVAILABLE = True
except ImportError:
PYAUTOGUI_AVAILABLE = False
# Create STT app that can be imported as a subcommand # Create STT app that can be imported as a subcommand
stt_app = typer.Typer( stt_app = typer.Typer(
name="stt", name="stt",
@@ -111,7 +117,7 @@ if RUMPS_AVAILABLE:
self.language = "" self.language = ""
self.realtime = True self.realtime = True
self.sensitivity = 0.6 self.sensitivity = 0.6
self.device = "auto" self.device = "mps"
self.wakeword_backend = "openwakeword" self.wakeword_backend = "openwakeword"
self.save_to_file = None self.save_to_file = None
@@ -189,14 +195,14 @@ if RUMPS_AVAILABLE:
self.wake_word = sender.title self.wake_word = sender.title
self.set_current_wake_word() self.set_current_wake_word()
if self.is_running: if self.is_running:
rumps.notification("STT Settings", "Wake Word Changed", f"Restart STT to use '{self.wake_word}'") rumps.notification("STT Settings", "Wake Word Changed", f"Restart STT to use '{self.wake_word}'", sound=False)
def set_model(self, sender): def set_model(self, sender):
"""Set the model from menu selection.""" """Set the model from menu selection."""
self.model = sender.title self.model = sender.title
self.set_current_model() self.set_current_model()
if self.is_running: if self.is_running:
rumps.notification("STT Settings", "Model Changed", f"Restart STT to use '{self.model}' model") rumps.notification("STT Settings", "Model Changed", f"Restart STT to use '{self.model}' model", sound=False)
def start_stt(self, _): def start_stt(self, _):
"""Start STT functionality.""" """Start STT functionality."""
@@ -229,9 +235,9 @@ if RUMPS_AVAILABLE:
# Configure recorder # Configure recorder
recorder_config = { recorder_config = {
"model": self.model, "model": self.model,
"wake_words": self.wake_word, # "wake_words": self.wake_word,
"wakeword_backend": self.wakeword_backend, # "wakeword_backend": self.wakeword_backend,
"wake_words_sensitivity": self.sensitivity, # "wake_words_sensitivity": self.sensitivity,
"device": self.device, "device": self.device,
"on_recording_start": self.on_recording_start, "on_recording_start": self.on_recording_start,
"on_recording_stop": self.on_recording_stop, "on_recording_stop": self.on_recording_stop,
@@ -260,7 +266,7 @@ if RUMPS_AVAILABLE:
self.transcription_thread.start() self.transcription_thread.start()
self.update_menu_states() self.update_menu_states()
rumps.notification("STT Started", f"Wake word: {self.wake_word}", f"Model: {self.model} | Device: {self.device}") rumps.notification("STT Started", f"Wake word: {self.wake_word}", f"Model: {self.model} | Device: {self.device}", sound=False)
except Exception as e: except Exception as e:
rumps.alert("STT Error", f"Failed to start STT: {str(e)}") rumps.alert("STT Error", f"Failed to start STT: {str(e)}")
@@ -288,7 +294,7 @@ if RUMPS_AVAILABLE:
self.output_file = None self.output_file = None
self.update_menu_states() self.update_menu_states()
rumps.notification("STT Stopped", "Speech-to-text has been stopped", "") rumps.notification("STT Stopped", "Speech-to-text has been stopped", "", sound=False)
def pause_stt(self, _): def pause_stt(self, _):
"""Pause STT functionality.""" """Pause STT functionality."""
@@ -297,7 +303,7 @@ if RUMPS_AVAILABLE:
self.is_paused = True self.is_paused = True
self.update_menu_states() self.update_menu_states()
rumps.notification("STT Paused", "Speech recognition paused", "Resume from menu") rumps.notification("STT Paused", "Speech recognition paused", "Resume from menu", sound=False)
def resume_stt(self, _): def resume_stt(self, _):
"""Resume STT functionality.""" """Resume STT functionality."""
@@ -306,7 +312,7 @@ if RUMPS_AVAILABLE:
self.is_paused = False self.is_paused = False
self.update_menu_states() self.update_menu_states()
rumps.notification("STT Resumed", "Speech recognition resumed", f"Listening for '{self.wake_word}'") rumps.notification("STT Resumed", "Speech recognition resumed", f"Listening for '{self.wake_word}'", sound=False)
def transcription_loop(self): def transcription_loop(self):
"""Main transcription loop running in background thread.""" """Main transcription loop running in background thread."""
@@ -337,8 +343,8 @@ if RUMPS_AVAILABLE:
"""Handle completed transcriptions.""" """Handle completed transcriptions."""
if text.strip(): if text.strip():
# Show notification with transcription # Show notification with transcription
rumps.notification("Transcription", "Speech detected:", text[:100] + ("..." if len(text) > 100 else "")) rumps.notification("Transcription", "Speech detected:", text[:100] + ("..." if len(text) > 100 else ""), sound=False)
pyautogui.typewrite(text + " ")
# Save to file if specified # Save to file if specified
if self.output_file: if self.output_file:
timestamp = datetime.datetime.now().strftime("%H:%M:%S") timestamp = datetime.datetime.now().strftime("%H:%M:%S")
@@ -395,7 +401,7 @@ if RUMPS_AVAILABLE:
if response.clicked and response.text: if response.clicked and response.text:
self.save_to_file = Path.home() / "Documents" / response.text self.save_to_file = Path.home() / "Documents" / response.text
rumps.notification("File Set", "Transcriptions will be saved to:", str(self.save_to_file)) rumps.notification("File Set", "Transcriptions will be saved to:", str(self.save_to_file), sound=False)
except Exception as e: except Exception as e:
rumps.alert("Error", f"Could not set output file: {e}") rumps.alert("Error", f"Could not set output file: {e}")
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env python3
"""
Simple RealtimeSTT Test Script
Test wake word detection and transcription functionality
without the complexity of threading and status bar apps.
"""
from RealtimeSTT import AudioToTextRecorder
def process_text(text):
print(text)
if __name__ == '__main__':
print("Wait until it says 'speak now'")
recorder = AudioToTextRecorder()
while True:
recorder.text(process_text)
Generated
+2
View File
@@ -6257,6 +6257,7 @@ source = { editable = "." }
dependencies = [ dependencies = [
{ name = "pillow", version = "11.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" }, { name = "pillow", version = "11.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
{ name = "pillow", version = "11.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13'" }, { name = "pillow", version = "11.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13'" },
{ name = "pyautogui" },
{ name = "pyperclip" }, { name = "pyperclip" },
{ name = "python-doctr" }, { name = "python-doctr" },
{ name = "realtimestt" }, { name = "realtimestt" },
@@ -6292,6 +6293,7 @@ requires-dist = [
{ name = "mss", marker = "extra == 'screenshot-all'", specifier = ">=7.0.0" }, { name = "mss", marker = "extra == 'screenshot-all'", specifier = ">=7.0.0" },
{ name = "mss", marker = "extra == 'screenshot-fast'", specifier = ">=7.0.0" }, { name = "mss", marker = "extra == 'screenshot-fast'", specifier = ">=7.0.0" },
{ name = "pillow", specifier = ">=11.1.0" }, { name = "pillow", specifier = ">=11.1.0" },
{ name = "pyautogui", specifier = ">=0.9.54" },
{ name = "pyautogui", marker = "extra == 'screenshot-all'", specifier = ">=0.9.54" }, { name = "pyautogui", marker = "extra == 'screenshot-all'", specifier = ">=0.9.54" },
{ name = "pyautogui", marker = "extra == 'screenshot-full'", specifier = ">=0.9.54" }, { name = "pyautogui", marker = "extra == 'screenshot-full'", specifier = ">=0.9.54" },
{ name = "pyperclip", specifier = ">=1.9.0" }, { name = "pyperclip", specifier = ">=1.9.0" },