voice-mode 4.2.0__tar.gz → 4.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {voice_mode-4.2.0 → voice_mode-4.3.1}/CHANGELOG.md +8 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/PKG-INFO +1 -1
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/__version__.py +1 -1
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/cli.py +24 -6
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/cli_commands/hook.py +33 -21
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/config.py +89 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/.gitignore +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/README.md +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/build_hooks.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/pyproject.toml +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/__init__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/__main__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/cli_commands/__init__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/cli_commands/claude.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/cli_commands/exchanges.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/cli_commands/pronounce_commands.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/cli_commands/transcribe.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/conversation_logger.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/core.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/data/default_pronunciation.yaml +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/data/versions.json +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/exchanges/__init__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/exchanges/conversations.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/exchanges/filters.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/exchanges/formatters.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/exchanges/models.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/exchanges/reader.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/exchanges/stats.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/README.md +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/app/api/connection-details/route.ts +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/app/favicon.ico +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/app/globals.css +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/app/layout.tsx +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/app/page.tsx +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/components/CloseIcon.tsx +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/components/NoAgentNotification.tsx +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/components/TranscriptionView.tsx +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/hooks/useCombinedTranscriptions.ts +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/hooks/useLocalMicTrack.ts +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/next-env.d.ts +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/next.config.mjs +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/package-lock.json +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/package.json +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/pnpm-lock.yaml +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/postcss.config.mjs +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/tailwind.config.ts +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/tsconfig.json +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/prompts/README.md +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/prompts/__init__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/prompts/converse.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/prompts/release_notes.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/prompts/services.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/pronounce.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/provider_discovery.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/providers.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/resources/__init__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/resources/audio_files.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/resources/changelog.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/resources/configuration.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/resources/statistics.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/resources/version.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/resources/whisper_models.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/server.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/shared.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/simple_failover.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/statistics.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/streaming.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/__init__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/launchd/com.voicemode.frontend.plist +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/launchd/com.voicemode.kokoro.plist +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/launchd/com.voicemode.livekit.plist +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/launchd/com.voicemode.whisper.plist +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/launchd/start-kokoro-with-health-check.sh +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/launchd/start-whisper-with-health-check.sh +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/scripts/__init__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/scripts/start-whisper-server.sh +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/systemd/voicemode-frontend.service +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/systemd/voicemode-kokoro.service +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/systemd/voicemode-livekit.service +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/systemd/voicemode-whisper.service +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/__init__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/claude_thinking.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/configuration_management.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/converse.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/dependencies.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/devices.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/diagnostics.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/pronounce.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/providers.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/service.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/kokoro/install.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/kokoro/uninstall.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/list_versions.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/livekit/__init__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/livekit/frontend.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/livekit/install.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/livekit/production_server.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/livekit/uninstall.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/version_info.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/whisper/__init__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/whisper/install.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/whisper/list_models.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/whisper/model_active.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/whisper/model_benchmark.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/whisper/model_install.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/whisper/model_remove.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/whisper/models.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/whisper/uninstall.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/sound_fonts/__init__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/sound_fonts/audio_player.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/sound_fonts/hook_handler.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/sound_fonts/player.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/statistics.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/transcription/__init__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/transcription/backends.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/transcription/core.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/transcription/formats.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/transcription/types.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/voice_registry.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/__init__.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/audio_diagnostics.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/event_logger.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/ffmpeg_check.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/format_migration.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/gpu_detection.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/migration_helpers.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/services/common.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/services/coreml_setup.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/services/kokoro_helpers.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/services/livekit_helpers.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/services/whisper_helpers.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/services/whisper_version.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/utils/version_helpers.py +0 -0
- {voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/version.py +0 -0
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [4.3.1] - 2025-09-03
|
11
|
+
|
12
|
+
## [4.3.0] - 2025-09-03
|
13
|
+
|
10
14
|
## [4.2.0] - 2025-09-03
|
11
15
|
|
12
16
|
### Added
|
@@ -23,6 +27,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
23
27
|
- Claude Code integration via stdin-receiver for hook-based audio
|
24
28
|
- CLI command `play-sound` with theme, action, and sound selection
|
25
29
|
- Enhances user experience with auditory feedback during operations
|
30
|
+
- MP3 support added for 90% file size reduction over WAV
|
31
|
+
- Recursive directory copying for complete sound font structure
|
32
|
+
- Three Bears sound fonts for baby-bear, mama-bear, and papa-bear agents
|
33
|
+
- Sound fonts disabled by default (VOICEMODE_SOUNDFONTS_ENABLED=false)
|
26
34
|
|
27
35
|
- **🎭 Claude Code Deep Integration**
|
28
36
|
- Extract and analyze Claude's conversation logs in real-time
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: voice-mode
|
3
|
-
Version: 4.
|
3
|
+
Version: 4.3.1
|
4
4
|
Summary: VoiceMode - Voice interaction capabilities for AI assistants (formerly voice-mcp)
|
5
5
|
Project-URL: Homepage, https://github.com/mbailey/voicemode
|
6
6
|
Project-URL: Repository, https://github.com/mbailey/voicemode
|
@@ -57,6 +57,14 @@ def voice_mode() -> None:
|
|
57
57
|
voice_mode_main_cli()
|
58
58
|
|
59
59
|
|
60
|
+
# Audio group for audio-related commands
|
61
|
+
@voice_mode_main_cli.group()
|
62
|
+
@click.help_option('-h', '--help', help='Show this message and exit')
|
63
|
+
def audio():
|
64
|
+
"""Audio transcription and playback commands."""
|
65
|
+
pass
|
66
|
+
|
67
|
+
|
60
68
|
# Service group commands
|
61
69
|
@voice_mode_main_cli.group()
|
62
70
|
@click.help_option('-h', '--help', help='Show this message and exit')
|
@@ -1372,15 +1380,25 @@ cli.add_command(claude.claude_group)
|
|
1372
1380
|
|
1373
1381
|
# Add exchanges to main CLI
|
1374
1382
|
voice_mode_main_cli.add_command(exchanges_cmd.exchanges)
|
1375
|
-
voice_mode_main_cli.add_command(pronounce_commands.pronounce_group)
|
1376
1383
|
voice_mode_main_cli.add_command(claude.claude_group)
|
1377
1384
|
|
1378
|
-
#
|
1379
|
-
|
1385
|
+
# Note: We'll add these commands after the groups are defined
|
1386
|
+
# audio group will get transcribe and play commands
|
1387
|
+
# claude group will get hook command
|
1388
|
+
# config group will get pronounce command
|
1389
|
+
|
1390
|
+
|
1391
|
+
# Now add the subcommands to their respective groups
|
1392
|
+
# Add transcribe command to audio group
|
1393
|
+
transcribe_audio_cmd = transcribe_cmd.transcribe.commands['audio']
|
1394
|
+
transcribe_audio_cmd.name = 'transcribe'
|
1395
|
+
audio.add_command(transcribe_audio_cmd)
|
1380
1396
|
|
1381
|
-
# Add hook command
|
1382
|
-
|
1397
|
+
# Add hook command under claude group
|
1398
|
+
claude.claude_group.add_command(hook_cmd.hook)
|
1383
1399
|
|
1400
|
+
# Add pronounce under config group
|
1401
|
+
config.add_command(pronounce_commands.pronounce_group)
|
1384
1402
|
|
1385
1403
|
# Converse command - direct voice conversation from CLI
|
1386
1404
|
@voice_mode_main_cli.command()
|
@@ -1759,7 +1777,7 @@ def update(force):
|
|
1759
1777
|
|
1760
1778
|
|
1761
1779
|
# Sound Fonts command
|
1762
|
-
@
|
1780
|
+
@audio.command("play")
|
1763
1781
|
@click.help_option('-h', '--help')
|
1764
1782
|
@click.option('-t', '--tool', help='Tool name for direct command-line usage')
|
1765
1783
|
@click.option('-a', '--action', default='start', type=click.Choice(['start', 'end']), help='Action type')
|
@@ -86,25 +86,32 @@ def stdin_receiver(tool_name, action, subagent_type, event, debug):
|
|
86
86
|
print(f"[DEBUG] Processing: event={event_name}, tool={tool_name}, "
|
87
87
|
f"action={action}, subagent={subagent_type}", file=sys.stderr)
|
88
88
|
|
89
|
-
#
|
90
|
-
|
89
|
+
# Check if sound fonts are enabled
|
90
|
+
from voice_mode.config import SOUNDFONTS_ENABLED
|
91
91
|
|
92
|
-
if
|
92
|
+
if not SOUNDFONTS_ENABLED:
|
93
93
|
if debug:
|
94
|
-
print(f"[DEBUG]
|
95
|
-
|
96
|
-
# Play the sound
|
97
|
-
player = Player()
|
98
|
-
success = player.play(str(sound_file))
|
99
|
-
|
100
|
-
if debug:
|
101
|
-
if success:
|
102
|
-
print(f"[DEBUG] Sound played successfully", file=sys.stderr)
|
103
|
-
else:
|
104
|
-
print(f"[DEBUG] Failed to play sound", file=sys.stderr)
|
94
|
+
print(f"[DEBUG] Sound fonts are disabled (VOICEMODE_SOUNDFONTS_ENABLED=false)", file=sys.stderr)
|
105
95
|
else:
|
106
|
-
|
107
|
-
|
96
|
+
# Find sound file using filesystem conventions
|
97
|
+
sound_file = find_sound_file(event_name, tool_name, subagent_type)
|
98
|
+
|
99
|
+
if sound_file:
|
100
|
+
if debug:
|
101
|
+
print(f"[DEBUG] Found sound file: {sound_file}", file=sys.stderr)
|
102
|
+
|
103
|
+
# Play the sound
|
104
|
+
player = Player()
|
105
|
+
success = player.play(str(sound_file))
|
106
|
+
|
107
|
+
if debug:
|
108
|
+
if success:
|
109
|
+
print(f"[DEBUG] Sound played successfully", file=sys.stderr)
|
110
|
+
else:
|
111
|
+
print(f"[DEBUG] Failed to play sound", file=sys.stderr)
|
112
|
+
else:
|
113
|
+
if debug:
|
114
|
+
print(f"[DEBUG] No sound file found for this event", file=sys.stderr)
|
108
115
|
|
109
116
|
# Always exit 0 to not disrupt Claude Code
|
110
117
|
sys.exit(0)
|
@@ -114,11 +121,11 @@ def find_sound_file(event: str, tool: str, subagent: Optional[str] = None) -> Op
|
|
114
121
|
"""
|
115
122
|
Find sound file using filesystem conventions.
|
116
123
|
|
117
|
-
Tries paths in order:
|
118
|
-
1. Most specific: {event}/{tool}/subagent/{subagent}.wav (Task tool only)
|
119
|
-
2. Tool default: {event}/{tool}/default.wav
|
120
|
-
3. Event default: {event}/default.wav
|
121
|
-
4. Global fallback: fallback.wav
|
124
|
+
Tries paths in order (mp3 preferred over wav for size):
|
125
|
+
1. Most specific: {event}/{tool}/subagent/{subagent}.{mp3,wav} (Task tool only)
|
126
|
+
2. Tool default: {event}/{tool}/default.{mp3,wav}
|
127
|
+
3. Event default: {event}/default.{mp3,wav}
|
128
|
+
4. Global fallback: fallback.{mp3,wav}
|
122
129
|
|
123
130
|
Args:
|
124
131
|
event: Event name (PreToolUse, PostToolUse)
|
@@ -157,15 +164,20 @@ def find_sound_file(event: str, tool: str, subagent: Optional[str] = None) -> Op
|
|
157
164
|
|
158
165
|
# 1. Most specific: subagent sound (Task tool only)
|
159
166
|
if tool == 'task' and subagent:
|
167
|
+
# Try mp3 first (smaller), then wav
|
168
|
+
paths_to_try.append(base_path / event_dir / tool / 'subagent' / f'{subagent}.mp3')
|
160
169
|
paths_to_try.append(base_path / event_dir / tool / 'subagent' / f'{subagent}.wav')
|
161
170
|
|
162
171
|
# 2. Tool-specific default
|
172
|
+
paths_to_try.append(base_path / event_dir / tool / 'default.mp3')
|
163
173
|
paths_to_try.append(base_path / event_dir / tool / 'default.wav')
|
164
174
|
|
165
175
|
# 3. Event-level default
|
176
|
+
paths_to_try.append(base_path / event_dir / 'default.mp3')
|
166
177
|
paths_to_try.append(base_path / event_dir / 'default.wav')
|
167
178
|
|
168
179
|
# 4. Global fallback
|
180
|
+
paths_to_try.append(base_path / 'fallback.mp3')
|
169
181
|
paths_to_try.append(base_path / 'fallback.wav')
|
170
182
|
|
171
183
|
# Find first existing file
|
@@ -101,6 +101,9 @@ def load_voicemode_env():
|
|
101
101
|
# Enable audio feedback (true/false)
|
102
102
|
# VOICEMODE_AUDIO_FEEDBACK=true
|
103
103
|
|
104
|
+
# Enable sound fonts for tool use hooks (true/false)
|
105
|
+
# VOICEMODE_SOUNDFONTS_ENABLED=false
|
106
|
+
|
104
107
|
#############
|
105
108
|
# Provider Configuration
|
106
109
|
#############
|
@@ -371,6 +374,11 @@ FRONTEND_PORT = int(os.getenv("VOICEMODE_FRONTEND_PORT", "3000"))
|
|
371
374
|
# Auto-enable services after installation
|
372
375
|
SERVICE_AUTO_ENABLE = env_bool("VOICEMODE_SERVICE_AUTO_ENABLE", False)
|
373
376
|
|
377
|
+
# ==================== SOUND FONTS CONFIGURATION ====================
|
378
|
+
|
379
|
+
# Sound fonts are disabled by default to avoid annoying users with unexpected sounds
|
380
|
+
SOUNDFONTS_ENABLED = env_bool("VOICEMODE_SOUNDFONTS_ENABLED", False)
|
381
|
+
|
374
382
|
# ==================== AUDIO CONFIGURATION ====================
|
375
383
|
|
376
384
|
# Audio parameters
|
@@ -555,6 +563,87 @@ def initialize_directories():
|
|
555
563
|
# Create events log directory
|
556
564
|
if EVENT_LOG_ENABLED:
|
557
565
|
Path(EVENT_LOG_DIR).mkdir(parents=True, exist_ok=True)
|
566
|
+
|
567
|
+
# Initialize sound fonts if not present
|
568
|
+
initialize_soundfonts()
|
569
|
+
|
570
|
+
# ==================== SOUND FONTS INITIALIZATION ====================
|
571
|
+
|
572
|
+
def initialize_soundfonts():
|
573
|
+
"""Install default sound fonts from package data if not present."""
|
574
|
+
import shutil
|
575
|
+
import importlib.resources
|
576
|
+
|
577
|
+
soundfonts_dir = BASE_DIR / "soundfonts"
|
578
|
+
default_soundfont_dir = soundfonts_dir / "default"
|
579
|
+
current_symlink = soundfonts_dir / "current"
|
580
|
+
|
581
|
+
# Skip if soundfonts already exist (user has customized them)
|
582
|
+
if default_soundfont_dir.exists():
|
583
|
+
# Ensure symlink exists if directory exists
|
584
|
+
if not current_symlink.exists():
|
585
|
+
try:
|
586
|
+
current_symlink.symlink_to(default_soundfont_dir.resolve())
|
587
|
+
except OSError:
|
588
|
+
# Symlinks might not work on all systems
|
589
|
+
pass
|
590
|
+
return
|
591
|
+
|
592
|
+
try:
|
593
|
+
# Create soundfonts directory
|
594
|
+
soundfonts_dir.mkdir(exist_ok=True)
|
595
|
+
|
596
|
+
# Copy default soundfonts from package data
|
597
|
+
try:
|
598
|
+
# For Python 3.9+
|
599
|
+
from importlib.resources import files
|
600
|
+
package_soundfonts = files("voice_mode.data.soundfonts.default")
|
601
|
+
|
602
|
+
if package_soundfonts.is_dir():
|
603
|
+
# Create the default directory
|
604
|
+
default_soundfont_dir.mkdir(exist_ok=True)
|
605
|
+
|
606
|
+
# Recursively copy all files from package data
|
607
|
+
def copy_tree(src, dst):
|
608
|
+
"""Recursively copy directory tree from package data."""
|
609
|
+
dst.mkdir(exist_ok=True)
|
610
|
+
for item in src.iterdir():
|
611
|
+
if item.is_file():
|
612
|
+
target = dst / item.name
|
613
|
+
target.write_bytes(item.read_bytes())
|
614
|
+
elif item.is_dir():
|
615
|
+
copy_tree(item, dst / item.name)
|
616
|
+
|
617
|
+
# Copy entire tree structure
|
618
|
+
copy_tree(package_soundfonts, default_soundfont_dir)
|
619
|
+
except ImportError:
|
620
|
+
# Fallback for older Python versions
|
621
|
+
import pkg_resources
|
622
|
+
|
623
|
+
# Create the default directory
|
624
|
+
default_soundfont_dir.mkdir(exist_ok=True)
|
625
|
+
|
626
|
+
# List all resources in the soundfonts directory
|
627
|
+
resource_dir = "data/soundfonts/default"
|
628
|
+
if pkg_resources.resource_exists("voice_mode", resource_dir):
|
629
|
+
# This is a bit more complex with pkg_resources
|
630
|
+
# We'll need to manually copy the structure
|
631
|
+
pass
|
632
|
+
|
633
|
+
# Create symlink to current soundfont (points to default)
|
634
|
+
if default_soundfont_dir.exists() and not current_symlink.exists():
|
635
|
+
try:
|
636
|
+
current_symlink.symlink_to(default_soundfont_dir.resolve())
|
637
|
+
except OSError:
|
638
|
+
# Symlinks might not work on all systems (e.g., Windows without admin)
|
639
|
+
pass
|
640
|
+
|
641
|
+
except Exception as e:
|
642
|
+
# Don't fail initialization if soundfonts can't be installed
|
643
|
+
# They're optional and disabled by default
|
644
|
+
if DEBUG:
|
645
|
+
import logging
|
646
|
+
logging.getLogger("voicemode").debug(f"Could not initialize soundfonts: {e}")
|
558
647
|
|
559
648
|
# ==================== UTILITY FUNCTIONS ====================
|
560
649
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/app/api/connection-details/route.ts
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/components/NoAgentNotification.tsx
RENAMED
File without changes
|
File without changes
|
{voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/frontend/hooks/useCombinedTranscriptions.ts
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/launchd/com.voicemode.frontend.plist
RENAMED
File without changes
|
{voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/launchd/com.voicemode.kokoro.plist
RENAMED
File without changes
|
{voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/launchd/com.voicemode.livekit.plist
RENAMED
File without changes
|
{voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/launchd/com.voicemode.whisper.plist
RENAMED
File without changes
|
{voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/launchd/start-kokoro-with-health-check.sh
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/systemd/voicemode-frontend.service
RENAMED
File without changes
|
File without changes
|
{voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/systemd/voicemode-livekit.service
RENAMED
File without changes
|
{voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/templates/systemd/voicemode-whisper.service
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{voice_mode-4.2.0 → voice_mode-4.3.1}/voice_mode/tools/services/livekit/production_server.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|