agentvibes 4.2.0 → 4.4.1
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.
- package/.agentvibes/bmad/bmad-voices.md +69 -69
- package/.agentvibes/config.json +12 -0
- package/.claude/activation-instructions +54 -54
- package/.claude/audio/tracks/README.md +52 -52
- package/.claude/commands/agent-vibes/add.md +21 -21
- package/.claude/commands/agent-vibes/agent-vibes.md +101 -101
- package/.claude/commands/agent-vibes/agent.md +79 -79
- package/.claude/commands/agent-vibes/background-music.md +111 -111
- package/.claude/commands/agent-vibes/bmad.md +198 -198
- package/.claude/commands/agent-vibes/clean.md +18 -18
- package/.claude/commands/agent-vibes/cleanup.md +18 -18
- package/.claude/commands/agent-vibes/commands.json +145 -145
- package/.claude/commands/agent-vibes/effects.md +97 -97
- package/.claude/commands/agent-vibes/get.md +9 -9
- package/.claude/commands/agent-vibes/hide.md +91 -91
- package/.claude/commands/agent-vibes/language.md +23 -23
- package/.claude/commands/agent-vibes/learn.md +67 -67
- package/.claude/commands/agent-vibes/list.md +13 -13
- package/.claude/commands/agent-vibes/mute.md +37 -37
- package/.claude/commands/agent-vibes/preview.md +17 -17
- package/.claude/commands/agent-vibes/provider.md +68 -68
- package/.claude/commands/agent-vibes/replay-target.md +14 -14
- package/.claude/commands/agent-vibes/sample.md +12 -12
- package/.claude/commands/agent-vibes/set-favorite-voice.md +84 -84
- package/.claude/commands/agent-vibes/set-pretext.md +65 -65
- package/.claude/commands/agent-vibes/set-speed.md +41 -41
- package/.claude/commands/agent-vibes/show.md +84 -84
- package/.claude/commands/agent-vibes/switch.md +87 -87
- package/.claude/commands/agent-vibes/target-voice.md +26 -26
- package/.claude/commands/agent-vibes/target.md +30 -30
- package/.claude/commands/agent-vibes/translate.md +68 -68
- package/.claude/commands/agent-vibes/unmute.md +45 -45
- package/.claude/commands/agent-vibes/verbosity.md +89 -89
- package/.claude/commands/agent-vibes/whoami.md +7 -7
- package/.claude/commands/agent-vibes-bmad-voices.md +117 -117
- package/.claude/commands/agent-vibes-rdp.md +24 -24
- package/.claude/config/agentvibes.json +1 -0
- package/.claude/config/audio-effects.cfg +2 -2
- package/.claude/config/audio-effects.cfg.sample +52 -52
- package/.claude/config/background-music-volume.txt +1 -0
- package/.claude/config/intro-text.txt +1 -0
- package/.claude/config/piper-speech-rate.txt +4 -0
- package/.claude/config/piper-target-speech-rate.txt +1 -0
- package/.claude/config/reverb-level.txt +1 -0
- package/.claude/config/tts-speech-rate.txt +4 -0
- package/.claude/config/tts-target-speech-rate.txt +1 -0
- package/.claude/docs/TERMUX_SETUP.md +408 -408
- package/.claude/github-star-reminder.txt +1 -1
- package/.claude/hooks/README-TTS-QUEUE.md +135 -135
- package/.claude/hooks/audio-cache-utils.sh +246 -246
- package/.claude/hooks/audio-processor.sh +433 -433
- package/.claude/hooks/background-music-manager.sh +404 -404
- package/.claude/hooks/bmad-speak-enhanced.sh +165 -165
- package/.claude/hooks/bmad-speak.sh +269 -269
- package/.claude/hooks/bmad-tts-injector.sh +568 -568
- package/.claude/hooks/bmad-voice-manager.sh +928 -928
- package/.claude/hooks/clawdbot-receiver-SECURE.sh +129 -129
- package/.claude/hooks/clawdbot-receiver.sh +107 -107
- package/.claude/hooks/clean-audio-cache.sh +22 -22
- package/.claude/hooks/cleanup-cache.sh +106 -106
- package/.claude/hooks/configure-rdp-mode.sh +137 -137
- package/.claude/hooks/download-extra-voices.sh +244 -244
- package/.claude/hooks/effects-manager.sh +268 -268
- package/.claude/hooks/github-star-reminder.sh +154 -154
- package/.claude/hooks/language-manager.sh +362 -362
- package/.claude/hooks/learn-manager.sh +492 -492
- package/.claude/hooks/macos-voice-manager.sh +205 -205
- package/.claude/hooks/migrate-background-music.sh +125 -125
- package/.claude/hooks/migrate-to-agentvibes.sh +161 -161
- package/.claude/hooks/optimize-background-music.sh +87 -87
- package/.claude/hooks/path-resolver.sh +60 -60
- package/.claude/hooks/personality-manager.sh +448 -448
- package/.claude/hooks/piper-download-voices.sh +225 -225
- package/.claude/hooks/piper-installer.sh +292 -292
- package/.claude/hooks/piper-multispeaker-registry.sh +171 -171
- package/.claude/hooks/piper-voice-manager.sh +24 -3
- package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +90 -90
- package/.claude/hooks/play-tts-enhanced.sh +105 -105
- package/.claude/hooks/play-tts-macos.sh +368 -368
- package/.claude/hooks/play-tts-piper.sh +679 -679
- package/.claude/hooks/play-tts-soprano.sh +356 -356
- package/.claude/hooks/play-tts-ssh-remote.sh +167 -167
- package/.claude/hooks/play-tts-termux-ssh.sh +169 -169
- package/.claude/hooks/play-tts.sh +301 -301
- package/.claude/hooks/prepare-release.sh +54 -54
- package/.claude/hooks/provider-commands.sh +617 -617
- package/.claude/hooks/provider-manager.sh +399 -399
- package/.claude/hooks/replay-target-audio.sh +95 -95
- package/.claude/hooks/requirements.txt +6 -6
- package/.claude/hooks/sentiment-manager.sh +201 -201
- package/.claude/hooks/session-start-tts.sh +81 -81
- package/.claude/hooks/soprano-gradio-synth.py +139 -139
- package/.claude/hooks/speed-manager.sh +291 -291
- package/.claude/hooks/stop-tts.sh +84 -84
- package/.claude/hooks/termux-installer.sh +261 -261
- package/.claude/hooks/translate-manager.sh +341 -341
- package/.claude/hooks/translator.py +237 -237
- package/.claude/hooks/tts-queue-worker.sh +145 -145
- package/.claude/hooks/tts-queue.sh +165 -165
- package/.claude/hooks/verbosity-manager.sh +178 -178
- package/.claude/hooks/voice-manager.sh +548 -548
- package/.claude/hooks-windows/audio-cache-utils.ps1 +119 -119
- package/.claude/hooks-windows/background-music-manager.ps1 +348 -0
- package/.claude/hooks-windows/clean-audio-cache.ps1 +53 -0
- package/.claude/hooks-windows/download-extra-voices.ps1 +185 -0
- package/.claude/hooks-windows/effects-manager.ps1 +294 -0
- package/.claude/hooks-windows/language-manager.ps1 +193 -0
- package/.claude/hooks-windows/learn-manager.ps1 +241 -0
- package/.claude/hooks-windows/personality-manager.ps1 +266 -0
- package/.claude/hooks-windows/play-tts-piper.ps1 +209 -0
- package/.claude/hooks-windows/play-tts-sapi.ps1 +108 -0
- package/.claude/hooks-windows/play-tts-soprano.ps1 +159 -158
- package/.claude/hooks-windows/play-tts-windows-piper.ps1 +50 -5
- package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -108
- package/.claude/hooks-windows/play-tts.ps1 +344 -266
- package/.claude/hooks-windows/provider-manager.ps1 +29 -10
- package/.claude/hooks-windows/session-start-tts.ps1 +124 -124
- package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
- package/.claude/hooks-windows/speed-manager.ps1 +166 -0
- package/.claude/hooks-windows/verbosity-manager.ps1 +119 -0
- package/.claude/hooks-windows/voice-manager-windows.ps1 +92 -8
- package/.claude/output-styles/agent-vibes.md +202 -202
- package/.claude/personalities/angry.md +14 -14
- package/.claude/personalities/annoying.md +14 -14
- package/.claude/personalities/crass.md +14 -14
- package/.claude/personalities/dramatic.md +14 -14
- package/.claude/personalities/dry-humor.md +50 -50
- package/.claude/personalities/flirty.md +20 -20
- package/.claude/personalities/funny.md +14 -14
- package/.claude/personalities/grandpa.md +32 -32
- package/.claude/personalities/millennial.md +14 -14
- package/.claude/personalities/moody.md +14 -14
- package/.claude/personalities/normal.md +16 -16
- package/.claude/personalities/pirate.md +14 -14
- package/.claude/personalities/poetic.md +14 -14
- package/.claude/personalities/professional.md +14 -14
- package/.claude/personalities/rapper.md +55 -55
- package/.claude/personalities/robot.md +14 -14
- package/.claude/personalities/sarcastic.md +38 -38
- package/.claude/personalities/sassy.md +14 -14
- package/.claude/personalities/surfer-dude.md +14 -14
- package/.claude/personalities/zen.md +14 -14
- package/.claude/settings.json +15 -15
- package/.claude/verbosity.txt +1 -1
- package/.clawdbot/README.md +105 -105
- package/.clawdbot/skill/SKILL.md +241 -241
- package/.mcp.json +12 -0
- package/CLAUDE.md +170 -170
- package/README.md +2029 -2007
- package/RELEASE_NOTES.md +1310 -1203
- package/WINDOWS-SETUP.md +208 -208
- package/bin/agent-vibes +39 -39
- package/bin/agentvibes-voice-browser.js +1840 -1840
- package/bin/agentvibes.js +48 -2
- package/bin/mcp-server.js +121 -121
- package/bin/mcp-server.sh +206 -206
- package/bin/test-bmad-pr +78 -78
- package/mcp-server/QUICK_START.md +203 -203
- package/mcp-server/README.md +345 -345
- package/mcp-server/WINDOWS_SETUP.md +260 -260
- package/mcp-server/docs/troubleshooting-audio.md +313 -313
- package/mcp-server/examples/claude_desktop_config.json +11 -11
- package/mcp-server/examples/claude_desktop_config_piper.json +9 -9
- package/mcp-server/examples/custom_instructions.md +169 -169
- package/mcp-server/install-deps.js +130 -130
- package/mcp-server/pyproject.toml +52 -52
- package/mcp-server/requirements.txt +2 -2
- package/mcp-server/server.py +1465 -1453
- package/mcp-server/test_server.py +395 -395
- package/mcp-server/test_windows_script_parity.py +336 -0
- package/package.json +110 -110
- package/setup-windows.ps1 +815 -815
- package/src/bmad-detector.js +71 -71
- package/src/cli/list-personalities.js +110 -110
- package/src/cli/list-voices.js +114 -114
- package/src/commands/bmad-voices.js +394 -394
- package/src/commands/install-mcp.js +476 -476
- package/src/console/app.js +824 -824
- package/src/console/audio-env.js +20 -1
- package/src/console/brand-colors.js +13 -13
- package/src/console/constants/personalities.js +44 -44
- package/src/console/footer-config.js +50 -50
- package/src/console/modals/modal-overlay.js +247 -247
- package/src/console/navigation.js +62 -62
- package/src/console/tabs/agents-tab.js +1684 -1516
- package/src/console/tabs/help-tab.js +261 -261
- package/src/console/tabs/install-tab.js +1007 -991
- package/src/console/tabs/music-tab.js +22 -8
- package/src/console/tabs/placeholder-tab.js +53 -53
- package/src/console/tabs/readme-tab.js +267 -267
- package/src/console/tabs/receiver-tab.js +1472 -1212
- package/src/console/tabs/settings-tab.js +208 -84
- package/src/console/tabs/voices-tab.js +100 -21
- package/src/console/widgets/destroy-list.js +25 -25
- package/src/console/widgets/format-utils.js +89 -89
- package/src/console/widgets/notice.js +55 -55
- package/src/console/widgets/personality-picker.js +185 -185
- package/src/console/widgets/reverb-picker.js +94 -94
- package/src/console/widgets/track-picker.js +285 -285
- package/src/installer/music-file-input.js +304 -304
- package/src/installer.js +5895 -5829
- package/src/services/agent-voice-store.js +423 -423
- package/src/services/config-service.js +264 -264
- package/src/services/navigation-service.js +123 -123
- package/src/services/provider-service.js +143 -132
- package/src/services/verbosity-service.js +157 -157
- package/src/utils/audio-duration-validator.js +298 -298
- package/src/utils/audio-format-validator.js +277 -277
- package/src/utils/dependency-checker.js +469 -466
- package/src/utils/file-ownership-verifier.js +358 -358
- package/src/utils/list-formatter.js +194 -194
- package/src/utils/music-file-validator.js +285 -285
- package/src/utils/preview-list-prompt.js +136 -136
- package/src/utils/provider-validator.js +96 -12
- package/src/utils/secure-music-storage.js +412 -412
- package/templates/agentvibes-receiver.sh +482 -482
- package/templates/audio/welcome-music.mp3 +0 -0
- package/voice-assignments.json +8244 -8244
- package/.claude/config/background-music-position.txt +0 -1
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#
|
|
2
|
+
# File: .claude/hooks-windows/play-tts-windows-piper.ps1
|
|
3
|
+
#
|
|
4
|
+
# AgentVibes - Windows Piper TTS Provider
|
|
5
|
+
# High-quality neural TTS using Piper.exe
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
param(
|
|
9
|
+
[Parameter(Mandatory = $true)]
|
|
10
|
+
[string]$Text,
|
|
11
|
+
|
|
12
|
+
[Parameter(Mandatory = $false)]
|
|
13
|
+
[string]$VoiceOverride
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# Configuration paths
|
|
17
|
+
$ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
18
|
+
$ProjectClaudeDir = Join-Path (Split-Path -Parent (Split-Path -Parent $ScriptPath)) ".claude"
|
|
19
|
+
|
|
20
|
+
if (Test-Path $ProjectClaudeDir) {
|
|
21
|
+
$ClaudeDir = $ProjectClaudeDir
|
|
22
|
+
} else {
|
|
23
|
+
$ClaudeDir = "$env:USERPROFILE\.claude"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Audio cache and voice config use project-local .claude
|
|
27
|
+
$AudioDir = "$ClaudeDir\audio"
|
|
28
|
+
# Try provider-specific file first, then generic tts-voice.txt (set by TUI)
|
|
29
|
+
$VoiceFile = "$ClaudeDir\tts-voice-piper.txt"
|
|
30
|
+
if (-not (Test-Path $VoiceFile)) {
|
|
31
|
+
$VoiceFile = "$ClaudeDir\tts-voice.txt"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Voices and Piper binary are global (shared across projects, ~100MB+)
|
|
35
|
+
$UserClaudeDir = "$env:USERPROFILE\.claude"
|
|
36
|
+
$VoicesDir = "$UserClaudeDir\piper-voices"
|
|
37
|
+
# Try standard install location first, then fall back to PATH
|
|
38
|
+
$PiperExe = "$env:LOCALAPPDATA\Programs\Piper\piper.exe"
|
|
39
|
+
if (-not (Test-Path $PiperExe)) {
|
|
40
|
+
$found = Get-Command piper.exe -ErrorAction SilentlyContinue
|
|
41
|
+
if (-not $found) {
|
|
42
|
+
# PATH may be stale (SSH sessions inherit minimal PATH); refresh from registry
|
|
43
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
44
|
+
$found = Get-Command piper.exe -ErrorAction SilentlyContinue
|
|
45
|
+
}
|
|
46
|
+
if ($found) { $PiperExe = $found.Source }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# Ensure directories exist
|
|
50
|
+
foreach ($dir in @($AudioDir, $VoicesDir)) {
|
|
51
|
+
if (-not (Test-Path $dir)) {
|
|
52
|
+
New-Item -ItemType Directory -Path $dir -Force | Out-Null
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# Check if Piper is installed
|
|
57
|
+
if (-not (Test-Path $PiperExe)) {
|
|
58
|
+
Write-Host "[ERROR] Piper not found at: $PiperExe" -ForegroundColor Red
|
|
59
|
+
Write-Host "Run: .\setup-windows.ps1 to install Piper" -ForegroundColor Yellow
|
|
60
|
+
exit 1
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# Determine voice to use
|
|
64
|
+
$VoiceName = ""
|
|
65
|
+
|
|
66
|
+
if ($VoiceOverride) {
|
|
67
|
+
$VoiceName = $VoiceOverride
|
|
68
|
+
}
|
|
69
|
+
elseif (Test-Path $VoiceFile) {
|
|
70
|
+
$VoiceName = (Get-Content $VoiceFile -Raw).Trim()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Strip display name suffix (e.g. "en_US-libritts-high::Bella-9" -> "en_US-libritts-high")
|
|
74
|
+
# and extract speaker ID if present (works for both override and file)
|
|
75
|
+
if ($VoiceName -match '::') {
|
|
76
|
+
$parts = $VoiceName -split '::'
|
|
77
|
+
$VoiceName = $parts[0]
|
|
78
|
+
if ($parts.Length -ge 2 -and $parts[1] -match '-(\d+)$') {
|
|
79
|
+
$env:PIPER_SPEAKER = $Matches[1]
|
|
80
|
+
} else {
|
|
81
|
+
Remove-Item env:PIPER_SPEAKER -ErrorAction SilentlyContinue
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
# No multi-speaker syntax — clear any stale speaker env var
|
|
85
|
+
Remove-Item env:PIPER_SPEAKER -ErrorAction SilentlyContinue
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# Default voice if not specified
|
|
89
|
+
# Prefer en_US-lessac-medium (bundled/commonly installed) over en_US-ryan-high
|
|
90
|
+
if (-not $VoiceName) {
|
|
91
|
+
$UserClaudePiperDir = "$env:USERPROFILE\.claude\piper-voices"
|
|
92
|
+
if (Test-Path "$UserClaudePiperDir\en_US-lessac-medium.onnx") {
|
|
93
|
+
$VoiceName = "en_US-lessac-medium"
|
|
94
|
+
} elseif (Test-Path "$UserClaudePiperDir\en_US-ryan-high.onnx") {
|
|
95
|
+
$VoiceName = "en_US-ryan-high"
|
|
96
|
+
} else {
|
|
97
|
+
# Fallback: use first available .onnx file, or default name for auto-download
|
|
98
|
+
$firstVoice = Get-ChildItem -Path $UserClaudePiperDir -Filter "*.onnx" -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
99
|
+
if ($firstVoice) {
|
|
100
|
+
$VoiceName = $firstVoice.BaseName
|
|
101
|
+
} else {
|
|
102
|
+
$VoiceName = "en_US-lessac-medium"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# Security: Validate voice name to prevent path traversal
|
|
108
|
+
# Only allow alphanumeric, underscore, hyphen, and period
|
|
109
|
+
if ($VoiceName -notmatch '^[a-zA-Z0-9_\-\.]+$') {
|
|
110
|
+
Write-Host "[ERROR] Invalid voice name: $VoiceName" -ForegroundColor Red
|
|
111
|
+
exit 1
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# Resolve voice model path and validate it stays within VoicesDir
|
|
115
|
+
$VoiceModelFile = [System.IO.Path]::GetFullPath("$VoicesDir\$VoiceName.onnx")
|
|
116
|
+
$VoiceJsonFile = [System.IO.Path]::GetFullPath("$VoicesDir\$VoiceName.onnx.json")
|
|
117
|
+
$ResolvedVoicesDir = [System.IO.Path]::GetFullPath($VoicesDir)
|
|
118
|
+
if (-not $VoiceModelFile.StartsWith($ResolvedVoicesDir)) {
|
|
119
|
+
Write-Host "[ERROR] Voice path outside voices directory" -ForegroundColor Red
|
|
120
|
+
exit 1
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
# Check if voice model exists, download if missing
|
|
124
|
+
if (-not (Test-Path $VoiceModelFile)) {
|
|
125
|
+
Write-Host "[DOWNLOAD] Voice model: $VoiceName" -ForegroundColor Yellow
|
|
126
|
+
|
|
127
|
+
# Try to download from Hugging Face
|
|
128
|
+
# Voice name format: {lang}_{region}-{speaker}-{quality}
|
|
129
|
+
# HF path format: {lang}/{lang}_{region}/{speaker}/{quality}/{voicename}.onnx
|
|
130
|
+
try {
|
|
131
|
+
# Parse voice name to build correct HF path
|
|
132
|
+
# e.g. en_US-ryan-high -> en/en_US/ryan/high/en_US-ryan-high.onnx
|
|
133
|
+
if ($VoiceName -match '^([a-z]{2})_([A-Z]{2})-([a-zA-Z0-9_]+)-([a-z]+)$') {
|
|
134
|
+
$Lang = $Matches[1]
|
|
135
|
+
$LangRegion = "$($Matches[1])_$($Matches[2])"
|
|
136
|
+
$Speaker = $Matches[3]
|
|
137
|
+
$Quality = $Matches[4]
|
|
138
|
+
$HFBase = "https://huggingface.co/rhasspy/piper-voices/resolve/main/$Lang/$LangRegion/$Speaker/$Quality"
|
|
139
|
+
} else {
|
|
140
|
+
# Fallback for non-standard voice names
|
|
141
|
+
$HFBase = "https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/ryan/high"
|
|
142
|
+
}
|
|
143
|
+
$ModelUrl = "$HFBase/$VoiceName.onnx"
|
|
144
|
+
$JsonUrl = "$HFBase/$VoiceName.onnx.json"
|
|
145
|
+
|
|
146
|
+
Write-Host " Downloading model..." -ForegroundColor Cyan
|
|
147
|
+
Invoke-WebRequest -Uri $ModelUrl -OutFile $VoiceModelFile -ErrorAction Stop
|
|
148
|
+
Write-Host " Downloading config..." -ForegroundColor Cyan
|
|
149
|
+
Invoke-WebRequest -Uri $JsonUrl -OutFile $VoiceJsonFile -ErrorAction Stop
|
|
150
|
+
Write-Host "[OK] Voice model downloaded" -ForegroundColor Green
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
Write-Host "[ERROR] Failed to download voice model: $_" -ForegroundColor Red
|
|
154
|
+
Write-Host "Make sure you have internet connection" -ForegroundColor Yellow
|
|
155
|
+
exit 1
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# Sanitize text for speech - strip only dangerous shell metacharacters
|
|
160
|
+
$Text = $Text -replace '\\', ' '
|
|
161
|
+
$Text = $Text -replace '[{}<>|`~^;]', ''
|
|
162
|
+
$Text = $Text -replace '\s+', ' '
|
|
163
|
+
$Text = $Text.Trim()
|
|
164
|
+
|
|
165
|
+
# Create audio file path
|
|
166
|
+
$Timestamp = Get-Date -Format 'yyyyMMdd-HHmmss-ffff'
|
|
167
|
+
$AudioFile = "$AudioDir\tts-$Timestamp.wav"
|
|
168
|
+
|
|
169
|
+
# Synthesize with Piper
|
|
170
|
+
try {
|
|
171
|
+
Write-Host "[SYNTH] Synthesizing with Piper..." -ForegroundColor Cyan
|
|
172
|
+
|
|
173
|
+
# Run Piper with text input
|
|
174
|
+
# Add --speaker for multi-speaker models (e.g. libritts-high with speaker 9)
|
|
175
|
+
$piperArgs = @("--model", $VoiceModelFile, "--output-file", $AudioFile)
|
|
176
|
+
if ($env:PIPER_SPEAKER) {
|
|
177
|
+
$piperArgs += @("--speaker", $env:PIPER_SPEAKER)
|
|
178
|
+
}
|
|
179
|
+
$Text | & $PiperExe @piperArgs 2>$null
|
|
180
|
+
|
|
181
|
+
if (-not (Test-Path $AudioFile)) {
|
|
182
|
+
Write-Host "[ERROR] Piper synthesis failed" -ForegroundColor Red
|
|
183
|
+
exit 1
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
# Display results
|
|
187
|
+
Write-Host "[OK] Saved to: $AudioFile" -ForegroundColor Green
|
|
188
|
+
Write-Host "[VOICE] Voice used: $VoiceName (Piper)" -ForegroundColor Green
|
|
189
|
+
|
|
190
|
+
# Play the audio using built-in Windows audio player (skip if AGENTVIBES_NO_PLAY is set)
|
|
191
|
+
if (-not $env:AGENTVIBES_NO_PLAY) {
|
|
192
|
+
$player = $null
|
|
193
|
+
try {
|
|
194
|
+
$player = New-Object System.Media.SoundPlayer $AudioFile
|
|
195
|
+
$player.PlaySync()
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
Write-Host "[WARNING] Could not play audio (SoundPlayer unavailable)" -ForegroundColor Yellow
|
|
199
|
+
Write-Host "Audio saved to: $AudioFile" -ForegroundColor Gray
|
|
200
|
+
}
|
|
201
|
+
finally {
|
|
202
|
+
if ($player) { $player.Dispose() }
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
Write-Host "[ERROR] Error running Piper: $_" -ForegroundColor Red
|
|
208
|
+
exit 1
|
|
209
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#
|
|
2
|
+
# File: .claude/hooks-windows/play-tts-windows-sapi.ps1
|
|
3
|
+
#
|
|
4
|
+
# AgentVibes - Windows SAPI TTS Provider (Zero Dependencies)
|
|
5
|
+
# Uses built-in Windows System.Speech API
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
param(
|
|
9
|
+
[Parameter(Mandatory = $true)]
|
|
10
|
+
[string]$Text,
|
|
11
|
+
|
|
12
|
+
[Parameter(Mandatory = $false)]
|
|
13
|
+
[string]$VoiceOverride
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# Configuration paths
|
|
17
|
+
$ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
18
|
+
$ProjectClaudeDir = Join-Path (Split-Path -Parent (Split-Path -Parent $ScriptPath)) ".claude"
|
|
19
|
+
|
|
20
|
+
if (Test-Path $ProjectClaudeDir) {
|
|
21
|
+
$ClaudeDir = $ProjectClaudeDir
|
|
22
|
+
} else {
|
|
23
|
+
$ClaudeDir = "$env:USERPROFILE\.claude"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
$AudioDir = "$ClaudeDir\audio"
|
|
27
|
+
$VoiceFile = "$ClaudeDir\tts-voice-sapi.txt"
|
|
28
|
+
|
|
29
|
+
# Ensure directories exist
|
|
30
|
+
if (-not (Test-Path $AudioDir)) {
|
|
31
|
+
New-Item -ItemType Directory -Path $AudioDir -Force | Out-Null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Load System.Speech assembly
|
|
35
|
+
try {
|
|
36
|
+
Add-Type -AssemblyName System.Speech
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
Write-Host "[ERROR] System.Speech assembly not available" -ForegroundColor Red
|
|
40
|
+
exit 1
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Determine voice to use
|
|
44
|
+
$VoiceName = ""
|
|
45
|
+
|
|
46
|
+
if ($VoiceOverride) {
|
|
47
|
+
$VoiceName = $VoiceOverride
|
|
48
|
+
}
|
|
49
|
+
elseif (Test-Path $VoiceFile) {
|
|
50
|
+
$VoiceName = (Get-Content $VoiceFile -Raw).Trim()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# Initialize speech synthesizer
|
|
54
|
+
$synth = New-Object System.Speech.Synthesis.SpeechSynthesizer
|
|
55
|
+
|
|
56
|
+
# Set voice if specified
|
|
57
|
+
if ($VoiceName) {
|
|
58
|
+
try {
|
|
59
|
+
$synth.SelectVoice($VoiceName)
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
Write-Host "[WARNING] Voice '$VoiceName' not found, using default" -ForegroundColor Yellow
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Sanitize text for speech - strip only dangerous shell metacharacters and SSML tags
|
|
67
|
+
$Text = $Text -replace '\\', ' '
|
|
68
|
+
$Text = $Text -replace '[{}<>|`~^;]', ''
|
|
69
|
+
$Text = $Text -replace '&[a-zA-Z]+;', ''
|
|
70
|
+
$Text = $Text -replace '\s+', ' '
|
|
71
|
+
$Text = $Text.Trim()
|
|
72
|
+
|
|
73
|
+
# Get actual voice name (after selection or default)
|
|
74
|
+
$ActualVoice = $synth.Voice.Name
|
|
75
|
+
|
|
76
|
+
# Create audio file path
|
|
77
|
+
$Timestamp = Get-Date -Format 'yyyyMMdd-HHmmss-ffff'
|
|
78
|
+
$AudioFile = "$AudioDir\tts-$Timestamp.wav"
|
|
79
|
+
|
|
80
|
+
# Save to WAV file with proper resource cleanup
|
|
81
|
+
$player = $null
|
|
82
|
+
try {
|
|
83
|
+
$synth.SetOutputToWaveFile($AudioFile)
|
|
84
|
+
$synth.Speak($Text)
|
|
85
|
+
|
|
86
|
+
# Display results
|
|
87
|
+
Write-Host "[OK] Saved to: $AudioFile" -ForegroundColor Green
|
|
88
|
+
Write-Host "[VOICE] Voice used: $ActualVoice (Windows SAPI)" -ForegroundColor Green
|
|
89
|
+
|
|
90
|
+
# Play the audio using built-in Windows audio player (skip if AGENTVIBES_NO_PLAY is set)
|
|
91
|
+
if (-not $env:AGENTVIBES_NO_PLAY) {
|
|
92
|
+
try {
|
|
93
|
+
$player = New-Object System.Media.SoundPlayer $AudioFile
|
|
94
|
+
$player.PlaySync()
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
Write-Host "[WARNING] Could not play audio (SoundPlayer unavailable)" -ForegroundColor Yellow
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
Write-Host "[ERROR] Error synthesizing speech: $_" -ForegroundColor Red
|
|
103
|
+
exit 1
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
if ($synth) { $synth.Dispose() }
|
|
107
|
+
if ($player) { $player.Dispose() }
|
|
108
|
+
}
|
|
@@ -1,158 +1,159 @@
|
|
|
1
|
-
#
|
|
2
|
-
# File: .claude/hooks-windows/play-tts-soprano.ps1
|
|
3
|
-
#
|
|
4
|
-
# AgentVibes - Soprano TTS Provider for Windows
|
|
5
|
-
# Ultra-fast neural TTS via Soprano (80M params)
|
|
6
|
-
#
|
|
7
|
-
# Supports three modes (auto-detected in priority order):
|
|
8
|
-
# 1. WebUI mode: Gradio WebUI running (soprano-webui), uses Python helper
|
|
9
|
-
# 2. API mode: OpenAI-compatible server, uses Invoke-RestMethod
|
|
10
|
-
# 3. CLI mode: Direct soprano command (reloads model each call, slowest)
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
param(
|
|
14
|
-
[Parameter(Mandatory = $true, Position = 0)]
|
|
15
|
-
[string]$Text,
|
|
16
|
-
|
|
17
|
-
[Parameter(Mandatory = $false, Position = 1)]
|
|
18
|
-
[string]$VoiceOverride # Ignored - Soprano has a single voice
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
$ErrorActionPreference = "Stop"
|
|
22
|
-
|
|
23
|
-
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
24
|
-
# Validate port is numeric to prevent injection
|
|
25
|
-
$SopranoPort = "7860"
|
|
26
|
-
if ($env:SOPRANO_PORT -and $env:SOPRANO_PORT -match '^\d+$') {
|
|
27
|
-
$portNum = [int]$env:SOPRANO_PORT
|
|
28
|
-
if ($portNum -gt 0 -and $portNum -le 65535) {
|
|
29
|
-
$SopranoPort = $env:SOPRANO_PORT
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
$SopranoDevice = if ($env:SOPRANO_DEVICE) { $env:SOPRANO_DEVICE } else { "auto" }
|
|
33
|
-
|
|
34
|
-
# Sanitize text for TTS - strip shell metacharacters
|
|
35
|
-
|
|
36
|
-
$Text = $Text
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
$
|
|
57
|
-
$
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
$
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
$
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
$
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
Write-Host ""
|
|
130
|
-
Write-Host "
|
|
131
|
-
Write-Host "
|
|
132
|
-
Write-Host ""
|
|
133
|
-
Write-Host "
|
|
134
|
-
Write-Host "Start
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
$player.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
Write-Host "
|
|
1
|
+
#
|
|
2
|
+
# File: .claude/hooks-windows/play-tts-soprano.ps1
|
|
3
|
+
#
|
|
4
|
+
# AgentVibes - Soprano TTS Provider for Windows
|
|
5
|
+
# Ultra-fast neural TTS via Soprano (80M params)
|
|
6
|
+
#
|
|
7
|
+
# Supports three modes (auto-detected in priority order):
|
|
8
|
+
# 1. WebUI mode: Gradio WebUI running (soprano-webui), uses Python helper
|
|
9
|
+
# 2. API mode: OpenAI-compatible server, uses Invoke-RestMethod
|
|
10
|
+
# 3. CLI mode: Direct soprano command (reloads model each call, slowest)
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
param(
|
|
14
|
+
[Parameter(Mandatory = $true, Position = 0)]
|
|
15
|
+
[string]$Text,
|
|
16
|
+
|
|
17
|
+
[Parameter(Mandatory = $false, Position = 1)]
|
|
18
|
+
[string]$VoiceOverride # Ignored - Soprano has a single voice
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
$ErrorActionPreference = "Stop"
|
|
22
|
+
|
|
23
|
+
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
24
|
+
# Validate port is numeric to prevent injection
|
|
25
|
+
$SopranoPort = "7860"
|
|
26
|
+
if ($env:SOPRANO_PORT -and $env:SOPRANO_PORT -match '^\d+$') {
|
|
27
|
+
$portNum = [int]$env:SOPRANO_PORT
|
|
28
|
+
if ($portNum -gt 0 -and $portNum -le 65535) {
|
|
29
|
+
$SopranoPort = $env:SOPRANO_PORT
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
$SopranoDevice = if ($env:SOPRANO_DEVICE) { $env:SOPRANO_DEVICE } else { "auto" }
|
|
33
|
+
|
|
34
|
+
# Sanitize text for TTS - strip only dangerous shell metacharacters
|
|
35
|
+
# Keep $, parens, quotes — these are harmless for TTS text piped to stdin
|
|
36
|
+
$Text = $Text -replace '[\\`{}<>|~^;]', '' -replace '\s+', ' '
|
|
37
|
+
$Text = $Text.Trim()
|
|
38
|
+
|
|
39
|
+
if (-not $Text) {
|
|
40
|
+
Write-Host "Usage: play-tts-soprano.ps1 'text to speak' [voice_override]"
|
|
41
|
+
exit 1
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Determine audio directory
|
|
45
|
+
$ProjectClaudeDir = Join-Path (Split-Path -Parent (Split-Path -Parent $ScriptDir)) ".claude"
|
|
46
|
+
if (Test-Path $ProjectClaudeDir) {
|
|
47
|
+
$AudioDir = Join-Path $ProjectClaudeDir "audio"
|
|
48
|
+
} else {
|
|
49
|
+
$AudioDir = "$env:USERPROFILE\.claude\audio"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (-not (Test-Path $AudioDir)) {
|
|
53
|
+
New-Item -ItemType Directory -Path $AudioDir -Force | Out-Null
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
|
57
|
+
$random = Get-Random -Maximum 9999
|
|
58
|
+
$TempFile = Join-Path $AudioDir "tts-$timestamp-$random.wav"
|
|
59
|
+
|
|
60
|
+
# Check WebUI server
|
|
61
|
+
function Test-WebUI {
|
|
62
|
+
try {
|
|
63
|
+
$null = Invoke-WebRequest -Uri "http://127.0.0.1:${SopranoPort}/gradio_api/info" -TimeoutSec 2 -UseBasicParsing -ErrorAction Stop
|
|
64
|
+
return $true
|
|
65
|
+
} catch {
|
|
66
|
+
try {
|
|
67
|
+
$null = Invoke-WebRequest -Uri "http://127.0.0.1:${SopranoPort}/info" -TimeoutSec 2 -UseBasicParsing -ErrorAction Stop
|
|
68
|
+
return $true
|
|
69
|
+
} catch {
|
|
70
|
+
return $false
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# Check API server
|
|
76
|
+
function Test-APIServer {
|
|
77
|
+
try {
|
|
78
|
+
$body = '{"input":"test"}'
|
|
79
|
+
$null = Invoke-RestMethod -Uri "http://127.0.0.1:${SopranoPort}/v1/audio/speech" `
|
|
80
|
+
-Method POST -ContentType "application/json" -Body $body -TimeoutSec 2 -ErrorAction Stop
|
|
81
|
+
return $true
|
|
82
|
+
} catch {
|
|
83
|
+
return $false
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Check CLI availability
|
|
88
|
+
function Test-SopranoCLI {
|
|
89
|
+
try {
|
|
90
|
+
$null = Get-Command soprano -ErrorAction Stop
|
|
91
|
+
return $true
|
|
92
|
+
} catch {
|
|
93
|
+
return $false
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# Synthesize speech
|
|
98
|
+
$SynthMode = ""
|
|
99
|
+
|
|
100
|
+
if (Test-WebUI) {
|
|
101
|
+
# Gradio WebUI mode - use Python helper for SSE protocol
|
|
102
|
+
$SynthMode = "webui"
|
|
103
|
+
$pythonHelper = Join-Path $ScriptDir "soprano-gradio-synth.py"
|
|
104
|
+
if (Test-Path $pythonHelper) {
|
|
105
|
+
& python $pythonHelper $Text $TempFile $SopranoPort 2>$null
|
|
106
|
+
} else {
|
|
107
|
+
Write-Host "[ERROR] soprano-gradio-synth.py not found" -ForegroundColor Red
|
|
108
|
+
exit 1
|
|
109
|
+
}
|
|
110
|
+
} elseif (Test-APIServer) {
|
|
111
|
+
# OpenAI-compatible API mode
|
|
112
|
+
$SynthMode = "api"
|
|
113
|
+
# Build JSON safely using ConvertTo-Json to avoid injection
|
|
114
|
+
$bodyObj = @{ input = $Text }
|
|
115
|
+
$body = $bodyObj | ConvertTo-Json -Compress
|
|
116
|
+
try {
|
|
117
|
+
Invoke-RestMethod -Uri "http://127.0.0.1:${SopranoPort}/v1/audio/speech" `
|
|
118
|
+
-Method POST -ContentType "application/json" -Body $body `
|
|
119
|
+
-OutFile $TempFile -ErrorAction Stop
|
|
120
|
+
} catch {
|
|
121
|
+
Write-Host "[ERROR] API synthesis failed: $_" -ForegroundColor Red
|
|
122
|
+
exit 4
|
|
123
|
+
}
|
|
124
|
+
} elseif (Test-SopranoCLI) {
|
|
125
|
+
# CLI fallback - reloads model each call (slowest)
|
|
126
|
+
$SynthMode = "cli"
|
|
127
|
+
& soprano $Text -o $TempFile -d $SopranoDevice 2>$null
|
|
128
|
+
} else {
|
|
129
|
+
Write-Host "[ERROR] Soprano TTS not installed and no server running on port $SopranoPort" -ForegroundColor Red
|
|
130
|
+
Write-Host ""
|
|
131
|
+
Write-Host "Install: pip install soprano-tts" -ForegroundColor Yellow
|
|
132
|
+
Write-Host " (GPU): pip install soprano-tts[lmdeploy]" -ForegroundColor Yellow
|
|
133
|
+
Write-Host ""
|
|
134
|
+
Write-Host "Start WebUI: soprano-webui" -ForegroundColor Yellow
|
|
135
|
+
Write-Host "Start API: uvicorn soprano.server:app --host 127.0.0.1 --port $SopranoPort" -ForegroundColor Yellow
|
|
136
|
+
exit 2
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
# Verify output
|
|
140
|
+
if (-not (Test-Path $TempFile) -or (Get-Item $TempFile).Length -eq 0) {
|
|
141
|
+
Write-Host "[ERROR] Failed to synthesize speech with Soprano ($SynthMode mode)" -ForegroundColor Red
|
|
142
|
+
exit 4
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
# Play audio with proper resource cleanup (skip if AGENTVIBES_NO_PLAY is set)
|
|
146
|
+
if (-not $env:AGENTVIBES_NO_PLAY) {
|
|
147
|
+
$player = $null
|
|
148
|
+
try {
|
|
149
|
+
$player = New-Object System.Media.SoundPlayer $TempFile
|
|
150
|
+
$player.PlaySync()
|
|
151
|
+
} catch {
|
|
152
|
+
Write-Host "[ERROR] Audio playback failed: $_" -ForegroundColor Red
|
|
153
|
+
} finally {
|
|
154
|
+
if ($player) { $player.Dispose() }
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
Write-Host "Saved to: $TempFile"
|
|
159
|
+
Write-Host "Voice: Soprano-1.1-80M (Soprano TTS, $SynthMode mode)"
|