voice-mode 2.28.3__tar.gz → 2.30.0__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-2.28.3 → voice_mode-2.30.0}/CHANGELOG.md +26 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/PKG-INFO +6 -1
- {voice_mode-2.28.3 → voice_mode-2.30.0}/pyproject.toml +6 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/__version__.py +1 -1
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/cli.py +129 -34
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/converse.py +7 -8
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/whisper/model_install.py +99 -3
- {voice_mode-2.28.3 → voice_mode-2.30.0}/.gitignore +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/README.md +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/build_hooks.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/__init__.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/__main__.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/cli_commands/__init__.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/cli_commands/exchanges.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/config.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/conversation_logger.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/core.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/data/versions.json +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/exchanges/__init__.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/exchanges/conversations.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/exchanges/filters.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/exchanges/formatters.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/exchanges/models.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/exchanges/reader.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/exchanges/stats.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/README.md +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/app/api/connection-details/route.ts +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/app/favicon.ico +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/app/globals.css +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/app/layout.tsx +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/app/page.tsx +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/components/CloseIcon.tsx +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/components/NoAgentNotification.tsx +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/components/TranscriptionView.tsx +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/hooks/useCombinedTranscriptions.ts +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/hooks/useLocalMicTrack.ts +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/next-env.d.ts +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/next.config.mjs +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/package-lock.json +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/package.json +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/pnpm-lock.yaml +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/postcss.config.mjs +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/tailwind.config.ts +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/tsconfig.json +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/prompts/README.md +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/prompts/__init__.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/prompts/converse.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/prompts/release_notes.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/prompts/services.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/provider_discovery.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/providers.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/resources/__init__.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/resources/audio_files.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/resources/changelog.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/resources/configuration.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/resources/statistics.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/resources/version.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/resources/whisper_models.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/server.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/shared.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/simple_failover.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/statistics.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/streaming.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/launchd/com.voicemode.frontend.plist +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/launchd/com.voicemode.kokoro.plist +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/launchd/com.voicemode.livekit.plist +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/launchd/com.voicemode.whisper.plist +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/launchd/start-kokoro-with-health-check.sh +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/launchd/start-whisper-with-health-check.sh +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/systemd/voicemode-frontend.service +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/systemd/voicemode-kokoro.service +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/systemd/voicemode-livekit.service +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/systemd/voicemode-whisper.service +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/__init__.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/configuration_management.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/dependencies.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/devices.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/diagnostics.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/providers.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/service.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/kokoro/install.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/kokoro/uninstall.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/list_versions.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/livekit/__init__.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/livekit/frontend.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/livekit/install.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/livekit/production_server.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/livekit/uninstall.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/version_info.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/whisper/__init__.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/whisper/install.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/whisper/list_models.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/whisper/model_active.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/whisper/model_benchmark.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/whisper/model_remove.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/whisper/models.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/whisper/uninstall.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/statistics.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/voice_registry.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/utils/__init__.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/utils/audio_diagnostics.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/utils/event_logger.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/utils/ffmpeg_check.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/utils/format_migration.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/utils/gpu_detection.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/utils/migration_helpers.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/utils/services/common.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/utils/services/kokoro_helpers.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/utils/services/livekit_helpers.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/utils/services/whisper_helpers.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/utils/services/whisper_version.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/utils/version_helpers.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/version.py +0 -0
- {voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/voice_preferences.py +0 -0
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [2.30.0] - 2025-08-25
|
11
|
+
|
12
|
+
## [2.29.0] - 2025-08-25
|
13
|
+
|
14
|
+
### Added
|
15
|
+
- **CoreML acceleration support for Whisper on Apple Silicon**
|
16
|
+
- Added optional dependency group 'coreml' with PyTorch and CoreMLTools
|
17
|
+
- Enhanced whisper_model_install tool with install_torch and auto_confirm parameters
|
18
|
+
- Automatic detection of Apple Silicon Macs with CoreML acceleration offer
|
19
|
+
- User-friendly confirmation prompts for large (~2.5GB) PyTorch download
|
20
|
+
- Graceful fallback to Metal acceleration if CoreML requirements not met
|
21
|
+
- Clear instructions for enabling CoreML later if initially skipped
|
22
|
+
|
23
|
+
- **Beautiful installer experience**
|
24
|
+
- Added Voice Mode ASCII art in Claude Code orange color
|
25
|
+
- Enhanced preamble with clear value proposition and privacy messaging
|
26
|
+
- Early system detection with special recognition for Apple Silicon
|
27
|
+
- Professional presentation with centered text and visual hierarchy
|
28
|
+
|
29
|
+
### Fixed
|
30
|
+
- **Improved converse tool documentation**
|
31
|
+
- Simplified listen_duration parameter documentation
|
32
|
+
- Removed confusing duration recommendations that led to unnecessary overrides
|
33
|
+
- Clarified that silence detection handles timing well with sensible defaults
|
34
|
+
- Reduces cognitive load and prevents token waste from explicit duration settings
|
35
|
+
|
10
36
|
## [2.28.3] - 2025-08-24
|
11
37
|
|
12
38
|
### Fixed
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: voice-mode
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.30.0
|
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
|
@@ -39,6 +39,11 @@ Requires-Dist: simpleaudio
|
|
39
39
|
Requires-Dist: sounddevice
|
40
40
|
Requires-Dist: uv>=0.4.0
|
41
41
|
Requires-Dist: webrtcvad>=2.0.10
|
42
|
+
Provides-Extra: coreml
|
43
|
+
Requires-Dist: ane-transformers; extra == 'coreml'
|
44
|
+
Requires-Dist: coremltools>=7.0; extra == 'coreml'
|
45
|
+
Requires-Dist: torch>=2.0.0; extra == 'coreml'
|
46
|
+
Requires-Dist: transformers; extra == 'coreml'
|
42
47
|
Provides-Extra: dev
|
43
48
|
Requires-Dist: build>=1.0.0; extra == 'dev'
|
44
49
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
@@ -1694,18 +1694,89 @@ def version():
|
|
1694
1694
|
@click.help_option('-h', '--help')
|
1695
1695
|
@click.option('--force', is_flag=True, help='Force reinstall even if already up to date')
|
1696
1696
|
def update(force):
|
1697
|
-
"""Update Voice Mode to the latest version.
|
1697
|
+
"""Update Voice Mode to the latest version.
|
1698
|
+
|
1699
|
+
Automatically detects installation method (UV tool, UV pip, or regular pip)
|
1700
|
+
and uses the appropriate update command.
|
1701
|
+
"""
|
1698
1702
|
import subprocess
|
1699
1703
|
import requests
|
1704
|
+
from pathlib import Path
|
1700
1705
|
from importlib.metadata import version as get_version, PackageNotFoundError
|
1701
1706
|
|
1707
|
+
def detect_uv_tool_installation():
|
1708
|
+
"""Detect if running from a UV tool installation."""
|
1709
|
+
prefix_path = Path(sys.prefix).resolve()
|
1710
|
+
uv_tools_base = Path.home() / ".local" / "share" / "uv" / "tools"
|
1711
|
+
|
1712
|
+
# Check if sys.prefix is within UV tools directory
|
1713
|
+
if uv_tools_base in prefix_path.parents or prefix_path.parent == uv_tools_base:
|
1714
|
+
# Find the tool directory
|
1715
|
+
tool_dir = prefix_path if prefix_path.parent == uv_tools_base else None
|
1716
|
+
|
1717
|
+
if not tool_dir:
|
1718
|
+
for parent in prefix_path.parents:
|
1719
|
+
if parent.parent == uv_tools_base:
|
1720
|
+
tool_dir = parent
|
1721
|
+
break
|
1722
|
+
|
1723
|
+
if tool_dir:
|
1724
|
+
# Verify with uv-receipt.toml
|
1725
|
+
receipt_file = tool_dir / "uv-receipt.toml"
|
1726
|
+
if receipt_file.exists():
|
1727
|
+
# Parse tool name from receipt or use directory name
|
1728
|
+
try:
|
1729
|
+
with open(receipt_file) as f:
|
1730
|
+
content = f.read()
|
1731
|
+
import re
|
1732
|
+
match = re.search(r'name = "([^"]+)"', content)
|
1733
|
+
tool_name = match.group(1) if match else tool_dir.name
|
1734
|
+
return True, tool_name
|
1735
|
+
except Exception:
|
1736
|
+
return True, tool_dir.name
|
1737
|
+
|
1738
|
+
return False, None
|
1739
|
+
|
1740
|
+
def detect_uv_venv():
|
1741
|
+
"""Detect if running in a UV-managed virtual environment."""
|
1742
|
+
# Check if we're in a venv
|
1743
|
+
if sys.prefix == sys.base_prefix:
|
1744
|
+
return False
|
1745
|
+
|
1746
|
+
# Check for UV markers in pyvenv.cfg
|
1747
|
+
pyvenv_cfg = Path(sys.prefix) / "pyvenv.cfg"
|
1748
|
+
if pyvenv_cfg.exists():
|
1749
|
+
try:
|
1750
|
+
with open(pyvenv_cfg) as f:
|
1751
|
+
content = f.read()
|
1752
|
+
if "uv" in content.lower() or "managed by uv" in content:
|
1753
|
+
return True
|
1754
|
+
except Exception:
|
1755
|
+
pass
|
1756
|
+
|
1757
|
+
return False
|
1758
|
+
|
1759
|
+
def check_uv_available():
|
1760
|
+
"""Check if UV is available."""
|
1761
|
+
try:
|
1762
|
+
result = subprocess.run(
|
1763
|
+
["uv", "--version"],
|
1764
|
+
capture_output=True,
|
1765
|
+
text=True,
|
1766
|
+
timeout=2
|
1767
|
+
)
|
1768
|
+
return result.returncode == 0
|
1769
|
+
except (FileNotFoundError, subprocess.TimeoutExpired):
|
1770
|
+
return False
|
1771
|
+
|
1772
|
+
# Get current version
|
1702
1773
|
try:
|
1703
1774
|
current_version = get_version("voice-mode")
|
1704
1775
|
except PackageNotFoundError:
|
1705
1776
|
current_version = "development"
|
1706
1777
|
|
1778
|
+
# Check if update needed (unless forced)
|
1707
1779
|
if not force and current_version != "development":
|
1708
|
-
# Check if update is needed
|
1709
1780
|
try:
|
1710
1781
|
response = requests.get(
|
1711
1782
|
"https://pypi.org/pypi/voice-mode/json",
|
@@ -1717,58 +1788,82 @@ def update(force):
|
|
1717
1788
|
click.echo(f"Already running the latest version ({current_version})")
|
1718
1789
|
return
|
1719
1790
|
except (requests.RequestException, KeyError, ValueError):
|
1720
|
-
# Continue with update if we can't check
|
1721
|
-
pass
|
1791
|
+
pass # Continue with update if we can't check
|
1722
1792
|
|
1723
|
-
|
1793
|
+
# Detect installation method
|
1794
|
+
is_uv_tool, tool_name = detect_uv_tool_installation()
|
1724
1795
|
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1796
|
+
if is_uv_tool:
|
1797
|
+
# UV tool installation - use uv tool upgrade
|
1798
|
+
click.echo(f"Updating Voice Mode (UV tool: {tool_name})...")
|
1799
|
+
|
1728
1800
|
result = subprocess.run(
|
1729
|
-
["uv", "
|
1801
|
+
["uv", "tool", "upgrade", tool_name],
|
1730
1802
|
capture_output=True,
|
1731
|
-
text=True
|
1732
|
-
check=False
|
1803
|
+
text=True
|
1733
1804
|
)
|
1734
1805
|
|
1735
1806
|
if result.returncode == 0:
|
1736
|
-
|
1807
|
+
try:
|
1808
|
+
new_version = get_version("voice-mode")
|
1809
|
+
click.echo(f"✅ Successfully updated to version {new_version}")
|
1810
|
+
except PackageNotFoundError:
|
1811
|
+
click.echo("✅ Successfully updated Voice Mode")
|
1812
|
+
else:
|
1813
|
+
click.echo(f"❌ Update failed: {result.stderr}")
|
1814
|
+
click.echo(f"Try running manually: uv tool upgrade {tool_name}")
|
1815
|
+
|
1816
|
+
elif detect_uv_venv():
|
1817
|
+
# UV-managed virtual environment
|
1818
|
+
click.echo("Updating Voice Mode (UV virtual environment)...")
|
1819
|
+
|
1820
|
+
result = subprocess.run(
|
1821
|
+
["uv", "pip", "install", "--upgrade", "voice-mode"],
|
1822
|
+
capture_output=True,
|
1823
|
+
text=True
|
1824
|
+
)
|
1825
|
+
|
1826
|
+
if result.returncode == 0:
|
1827
|
+
try:
|
1828
|
+
new_version = get_version("voice-mode")
|
1829
|
+
click.echo(f"✅ Successfully updated to version {new_version}")
|
1830
|
+
except PackageNotFoundError:
|
1831
|
+
click.echo("✅ Successfully updated Voice Mode")
|
1832
|
+
else:
|
1833
|
+
click.echo(f"❌ Update failed: {result.stderr}")
|
1834
|
+
click.echo("Try running: uv pip install --upgrade voice-mode")
|
1835
|
+
|
1836
|
+
else:
|
1837
|
+
# Standard installation - try UV if available, else pip
|
1838
|
+
has_uv = check_uv_available()
|
1839
|
+
|
1840
|
+
if has_uv:
|
1841
|
+
click.echo("Updating Voice Mode (using UV)...")
|
1737
1842
|
result = subprocess.run(
|
1738
1843
|
["uv", "pip", "install", "--upgrade", "voice-mode"],
|
1739
1844
|
capture_output=True,
|
1740
1845
|
text=True
|
1741
1846
|
)
|
1742
|
-
if result.returncode == 0:
|
1743
|
-
# Get new version
|
1744
|
-
try:
|
1745
|
-
new_version = get_version("voice-mode")
|
1746
|
-
click.echo(f"✅ Successfully updated to version {new_version}")
|
1747
|
-
except PackageNotFoundError:
|
1748
|
-
click.echo("✅ Successfully updated Voice Mode")
|
1749
|
-
else:
|
1750
|
-
click.echo(f"❌ Update failed: {result.stderr}")
|
1751
|
-
click.echo("Try running: uv pip install --upgrade voice-mode")
|
1752
1847
|
else:
|
1753
|
-
|
1848
|
+
click.echo("Updating Voice Mode (using pip)...")
|
1754
1849
|
result = subprocess.run(
|
1755
1850
|
[sys.executable, "-m", "pip", "install", "--upgrade", "voice-mode"],
|
1756
1851
|
capture_output=True,
|
1757
1852
|
text=True
|
1758
1853
|
)
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
|
1854
|
+
|
1855
|
+
if result.returncode == 0:
|
1856
|
+
try:
|
1857
|
+
new_version = get_version("voice-mode")
|
1858
|
+
click.echo(f"✅ Successfully updated to version {new_version}")
|
1859
|
+
except PackageNotFoundError:
|
1860
|
+
click.echo("✅ Successfully updated Voice Mode")
|
1861
|
+
else:
|
1862
|
+
click.echo(f"❌ Update failed: {result.stderr}")
|
1863
|
+
if has_uv:
|
1864
|
+
click.echo("Try running: uv pip install --upgrade voice-mode")
|
1765
1865
|
else:
|
1766
|
-
click.echo(f"❌ Update failed: {result.stderr}")
|
1767
1866
|
click.echo("Try running: pip install --upgrade voice-mode")
|
1768
|
-
|
1769
|
-
except FileNotFoundError as e:
|
1770
|
-
click.echo(f"❌ Update failed: {e}")
|
1771
|
-
click.echo("Please install UV or pip and try again")
|
1772
1867
|
|
1773
1868
|
|
1774
1869
|
# Completions command
|
@@ -1351,14 +1351,13 @@ async def converse(
|
|
1351
1351
|
message: The message to speak
|
1352
1352
|
wait_for_response: Whether to listen for a response after speaking (default: True)
|
1353
1353
|
listen_duration: How long to listen for response in seconds (default: 120.0)
|
1354
|
-
|
1355
|
-
-
|
1356
|
-
|
1357
|
-
-
|
1358
|
-
-
|
1359
|
-
-
|
1360
|
-
|
1361
|
-
silence at the end than to cut off the user mid-sentence.
|
1354
|
+
The tool handles silence detection well and uses a sensible default.
|
1355
|
+
It's unusual to need to set the duration - only override if you have
|
1356
|
+
specific requirements such as:
|
1357
|
+
- Silence detection is disabled and you need a specific timeout
|
1358
|
+
- You know the response will be exceptionally long (>120s)
|
1359
|
+
- You're in a special mode that requires different timing
|
1360
|
+
In most cases, just let the default and silence detection handle it.
|
1362
1361
|
min_listen_duration: Minimum time to record before silence detection can stop (default: 2.0)
|
1363
1362
|
Useful for preventing premature cutoffs when users need thinking time.
|
1364
1363
|
Examples:
|
@@ -1,10 +1,13 @@
|
|
1
1
|
"""Download Whisper models with Core ML support."""
|
2
2
|
|
3
3
|
import os
|
4
|
+
import sys
|
4
5
|
import json
|
5
6
|
import logging
|
7
|
+
import platform
|
8
|
+
import subprocess
|
6
9
|
from pathlib import Path
|
7
|
-
from typing import Union, List
|
10
|
+
from typing import Union, List, Dict, Any
|
8
11
|
|
9
12
|
from voice_mode.server import mcp
|
10
13
|
from voice_mode.config import logger, MODELS_DIR
|
@@ -17,7 +20,9 @@ logger = logging.getLogger("voice-mode")
|
|
17
20
|
async def whisper_model_install(
|
18
21
|
model: Union[str, List[str]] = "large-v2",
|
19
22
|
force_download: Union[bool, str] = False,
|
20
|
-
skip_core_ml: Union[bool, str] = False
|
23
|
+
skip_core_ml: Union[bool, str] = False,
|
24
|
+
install_torch: Union[bool, str] = False,
|
25
|
+
auto_confirm: Union[bool, str] = False
|
21
26
|
) -> str:
|
22
27
|
"""Download Whisper model(s) with optional Core ML conversion.
|
23
28
|
|
@@ -31,6 +36,8 @@ async def whisper_model_install(
|
|
31
36
|
- "all" to download all available models
|
32
37
|
force_download: Re-download even if model exists (default: False)
|
33
38
|
skip_core_ml: Skip Core ML conversion on Apple Silicon (default: False)
|
39
|
+
install_torch: Install PyTorch for CoreML (adds ~2.5GB) (default: False)
|
40
|
+
auto_confirm: Skip all confirmation prompts (default: False)
|
34
41
|
|
35
42
|
Available models:
|
36
43
|
- tiny, tiny.en
|
@@ -77,6 +84,20 @@ async def whisper_model_install(
|
|
77
84
|
"error": "Whisper.cpp not installed. Please run whisper_install first."
|
78
85
|
}, indent=2)
|
79
86
|
|
87
|
+
# Handle CoreML dependencies if needed
|
88
|
+
coreml_status = await _handle_coreml_dependencies(
|
89
|
+
install_torch=install_torch,
|
90
|
+
auto_confirm=auto_confirm,
|
91
|
+
skip_core_ml=skip_core_ml
|
92
|
+
)
|
93
|
+
|
94
|
+
if not coreml_status["continue"]:
|
95
|
+
return json.dumps(coreml_status, indent=2)
|
96
|
+
|
97
|
+
# If CoreML deps were installed, skip_core_ml may have been updated
|
98
|
+
if coreml_status.get("coreml_deps_failed"):
|
99
|
+
skip_core_ml = True
|
100
|
+
|
80
101
|
# Parse model input
|
81
102
|
available_models = get_available_models()
|
82
103
|
|
@@ -200,4 +221,79 @@ async def whisper_model_install(
|
|
200
221
|
return json.dumps({
|
201
222
|
"success": False,
|
202
223
|
"error": str(e)
|
203
|
-
}, indent=2)
|
224
|
+
}, indent=2)
|
225
|
+
|
226
|
+
|
227
|
+
async def _handle_coreml_dependencies(
|
228
|
+
install_torch: bool = False,
|
229
|
+
auto_confirm: bool = False,
|
230
|
+
skip_core_ml: bool = False
|
231
|
+
) -> Dict[str, Any]:
|
232
|
+
"""Handle CoreML dependency installation for Apple Silicon Macs.
|
233
|
+
|
234
|
+
Returns:
|
235
|
+
Dict with 'continue' key indicating whether to proceed with model download
|
236
|
+
"""
|
237
|
+
# Check if we're on Apple Silicon Mac
|
238
|
+
if platform.system() != "Darwin" or platform.machine() != "arm64":
|
239
|
+
return {"continue": True}
|
240
|
+
|
241
|
+
# If skipping CoreML, no need to check dependencies
|
242
|
+
if skip_core_ml:
|
243
|
+
return {"continue": True}
|
244
|
+
|
245
|
+
# Check if torch is already installed
|
246
|
+
try:
|
247
|
+
import torch
|
248
|
+
logger.info("PyTorch already installed for CoreML support")
|
249
|
+
return {"continue": True}
|
250
|
+
except ImportError:
|
251
|
+
pass
|
252
|
+
|
253
|
+
# Check if user wants to install torch
|
254
|
+
if not install_torch and not auto_confirm:
|
255
|
+
return {
|
256
|
+
"continue": False,
|
257
|
+
"success": False,
|
258
|
+
"requires_confirmation": True,
|
259
|
+
"message": "CoreML requires PyTorch (~2.5GB). Rerun with install_torch=True to confirm.",
|
260
|
+
"recommendation": "Set install_torch=True for CoreML acceleration (2-3x faster)"
|
261
|
+
}
|
262
|
+
|
263
|
+
# Install CoreML dependencies
|
264
|
+
logger.info("Installing CoreML dependencies...")
|
265
|
+
|
266
|
+
try:
|
267
|
+
# Detect environment and install appropriately
|
268
|
+
packages = ["torch>=2.0.0", "coremltools>=7.0", "transformers", "ane-transformers"]
|
269
|
+
|
270
|
+
# Try UV first (most common)
|
271
|
+
if subprocess.run(["which", "uv"], capture_output=True).returncode == 0:
|
272
|
+
cmd = ["uv", "pip", "install"] + packages
|
273
|
+
logger.info("Installing via UV...")
|
274
|
+
else:
|
275
|
+
# Fallback to pip
|
276
|
+
cmd = [sys.executable, "-m", "pip", "install"] + packages
|
277
|
+
logger.info("Installing via pip...")
|
278
|
+
|
279
|
+
# Run installation
|
280
|
+
result = subprocess.run(cmd, capture_output=True, text=True)
|
281
|
+
|
282
|
+
if result.returncode == 0:
|
283
|
+
logger.info("CoreML dependencies installed successfully")
|
284
|
+
return {"continue": True, "coreml_deps_installed": True}
|
285
|
+
else:
|
286
|
+
logger.warning(f"Failed to install CoreML dependencies: {result.stderr}")
|
287
|
+
return {
|
288
|
+
"continue": True,
|
289
|
+
"coreml_deps_failed": True,
|
290
|
+
"warning": "CoreML dependencies installation failed. Models will use Metal acceleration."
|
291
|
+
}
|
292
|
+
|
293
|
+
except Exception as e:
|
294
|
+
logger.warning(f"Error installing CoreML dependencies: {e}")
|
295
|
+
return {
|
296
|
+
"continue": True,
|
297
|
+
"coreml_deps_failed": True,
|
298
|
+
"warning": f"CoreML setup error: {str(e)}. Models will use Metal acceleration."
|
299
|
+
}
|
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-2.28.3 → voice_mode-2.30.0}/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-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/components/NoAgentNotification.tsx
RENAMED
File without changes
|
{voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/frontend/components/TranscriptionView.tsx
RENAMED
File without changes
|
{voice_mode-2.28.3 → voice_mode-2.30.0}/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
|
{voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/launchd/com.voicemode.frontend.plist
RENAMED
File without changes
|
{voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/launchd/com.voicemode.kokoro.plist
RENAMED
File without changes
|
{voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/launchd/com.voicemode.livekit.plist
RENAMED
File without changes
|
{voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/launchd/com.voicemode.whisper.plist
RENAMED
File without changes
|
File without changes
|
File without changes
|
{voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/systemd/voicemode-frontend.service
RENAMED
File without changes
|
{voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/systemd/voicemode-kokoro.service
RENAMED
File without changes
|
{voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/templates/systemd/voicemode-livekit.service
RENAMED
File without changes
|
{voice_mode-2.28.3 → voice_mode-2.30.0}/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
|
{voice_mode-2.28.3 → voice_mode-2.30.0}/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
|
{voice_mode-2.28.3 → voice_mode-2.30.0}/voice_mode/tools/services/whisper/model_benchmark.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
|