agentvibes 2.0.12 → 2.0.14

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.
Files changed (138) hide show
  1. package/.claude/commands/agent-vibes/bmad.md +0 -7
  2. package/.claude/github-star-reminder.txt +1 -1
  3. package/.claude/hooks/piper-installer.sh +7 -57
  4. package/.claude/hooks/play-tts-piper.sh +2 -10
  5. package/.claude/hooks/play-tts.sh +0 -31
  6. package/README.md +3 -3
  7. package/RELEASE_NOTES.md +44 -170
  8. package/package.json +1 -1
  9. package/src/installer.js +1 -112
  10. package/.claude/hooks/play-tts-local-wrapper.sh +0 -44
  11. package/.claude/hooks/play-tts-remote.sh +0 -81
  12. package/agentvibes.org/.claude/commands/agent-vibes/add.md +0 -21
  13. package/agentvibes.org/.claude/commands/agent-vibes/agent-vibes.md +0 -68
  14. package/agentvibes.org/.claude/commands/agent-vibes/commands.json +0 -53
  15. package/agentvibes.org/.claude/commands/agent-vibes/get.md +0 -9
  16. package/agentvibes.org/.claude/commands/agent-vibes/list.md +0 -13
  17. package/agentvibes.org/.claude/commands/agent-vibes/personality.md +0 -79
  18. package/agentvibes.org/.claude/commands/agent-vibes/preview.md +0 -16
  19. package/agentvibes.org/.claude/commands/agent-vibes/provider.md +0 -54
  20. package/agentvibes.org/.claude/commands/agent-vibes/replay.md +0 -19
  21. package/agentvibes.org/.claude/commands/agent-vibes/sample.md +0 -12
  22. package/agentvibes.org/.claude/commands/agent-vibes/sentiment.md +0 -52
  23. package/agentvibes.org/.claude/commands/agent-vibes/set-language.md +0 -47
  24. package/agentvibes.org/.claude/commands/agent-vibes/set-pretext.md +0 -65
  25. package/agentvibes.org/.claude/commands/agent-vibes/switch.md +0 -53
  26. package/agentvibes.org/.claude/commands/agent-vibes/update.md +0 -20
  27. package/agentvibes.org/.claude/commands/agent-vibes/version.md +0 -10
  28. package/agentvibes.org/.claude/commands/agent-vibes/whoami.md +0 -7
  29. package/agentvibes.org/.claude/hooks/bmad-voice-manager.sh +0 -278
  30. package/agentvibes.org/.claude/hooks/language-manager.sh +0 -190
  31. package/agentvibes.org/.claude/hooks/personality-manager.sh +0 -279
  32. package/agentvibes.org/.claude/hooks/piper-download-voices.sh +0 -133
  33. package/agentvibes.org/.claude/hooks/piper-voice-manager.sh +0 -227
  34. package/agentvibes.org/.claude/hooks/play-tts-elevenlabs.sh +0 -201
  35. package/agentvibes.org/.claude/hooks/play-tts-piper.sh +0 -175
  36. package/agentvibes.org/.claude/hooks/play-tts.sh +0 -138
  37. package/agentvibes.org/.claude/hooks/provider-commands.sh +0 -374
  38. package/agentvibes.org/.claude/hooks/provider-manager.sh +0 -196
  39. package/agentvibes.org/.claude/hooks/sentiment-manager.sh +0 -163
  40. package/agentvibes.org/.claude/hooks/voice-manager.sh +0 -349
  41. package/agentvibes.org/.claude/hooks/voices-config.sh +0 -33
  42. package/agentvibes.org/.claude/journal/2025-10-07.html +0 -373
  43. package/agentvibes.org/.claude/journal/index.html +0 -91
  44. package/agentvibes.org/.claude/output-styles/agent-vibes.md +0 -203
  45. package/agentvibes.org/.claude/personalities/angry.md +0 -16
  46. package/agentvibes.org/.claude/personalities/annoying.md +0 -16
  47. package/agentvibes.org/.claude/personalities/crass.md +0 -16
  48. package/agentvibes.org/.claude/personalities/dramatic.md +0 -16
  49. package/agentvibes.org/.claude/personalities/dry-humor.md +0 -52
  50. package/agentvibes.org/.claude/personalities/flirty.md +0 -22
  51. package/agentvibes.org/.claude/personalities/funny.md +0 -16
  52. package/agentvibes.org/.claude/personalities/grandpa.md +0 -34
  53. package/agentvibes.org/.claude/personalities/millennial.md +0 -16
  54. package/agentvibes.org/.claude/personalities/moody.md +0 -16
  55. package/agentvibes.org/.claude/personalities/normal.md +0 -18
  56. package/agentvibes.org/.claude/personalities/pirate.md +0 -16
  57. package/agentvibes.org/.claude/personalities/poetic.md +0 -16
  58. package/agentvibes.org/.claude/personalities/professional.md +0 -16
  59. package/agentvibes.org/.claude/personalities/robot.md +0 -16
  60. package/agentvibes.org/.claude/personalities/sarcastic.md +0 -40
  61. package/agentvibes.org/.claude/personalities/sassy.md +0 -16
  62. package/agentvibes.org/.claude/personalities/surfer-dude.md +0 -16
  63. package/agentvibes.org/.claude/personalities/zen.md +0 -16
  64. package/agentvibes.org/.mcp-minimal.json +0 -60
  65. package/agentvibes.org/CHANGELOG.md +0 -56
  66. package/agentvibes.org/README.md +0 -93
  67. package/agentvibes.org/app/(auth)/layout.tsx +0 -15
  68. package/agentvibes.org/app/(auth)/reset-password/page.tsx +0 -45
  69. package/agentvibes.org/app/(auth)/signin/page.tsx +0 -82
  70. package/agentvibes.org/app/(auth)/signup/page.tsx +0 -104
  71. package/agentvibes.org/app/(default)/layout.tsx +0 -31
  72. package/agentvibes.org/app/(default)/page.tsx +0 -20
  73. package/agentvibes.org/app/api/hello/route.ts +0 -3
  74. package/agentvibes.org/app/css/additional-styles/theme.css +0 -82
  75. package/agentvibes.org/app/css/additional-styles/utility-patterns.css +0 -55
  76. package/agentvibes.org/app/css/style.css +0 -100
  77. package/agentvibes.org/app/layout.tsx +0 -63
  78. package/agentvibes.org/components/cta.tsx +0 -58
  79. package/agentvibes.org/components/features.tsx +0 -256
  80. package/agentvibes.org/components/hero-home.tsx +0 -133
  81. package/agentvibes.org/components/modal-video.tsx +0 -137
  82. package/agentvibes.org/components/page-illustration.tsx +0 -55
  83. package/agentvibes.org/components/spotlight.tsx +0 -77
  84. package/agentvibes.org/components/testimonials.tsx +0 -282
  85. package/agentvibes.org/components/ui/footer.tsx +0 -82
  86. package/agentvibes.org/components/ui/header.tsx +0 -53
  87. package/agentvibes.org/components/ui/logo.tsx +0 -10
  88. package/agentvibes.org/components/workflows.tsx +0 -176
  89. package/agentvibes.org/next.config.js +0 -4
  90. package/agentvibes.org/package-lock.json +0 -1974
  91. package/agentvibes.org/package.json +0 -30
  92. package/agentvibes.org/pnpm-lock.yaml +0 -1141
  93. package/agentvibes.org/postcss.config.js +0 -5
  94. package/agentvibes.org/public/audio/02-sarcastic.mp3 +0 -0
  95. package/agentvibes.org/public/audio/03-angry.mp3 +0 -0
  96. package/agentvibes.org/public/audio/04-grandpa.mp3 +0 -0
  97. package/agentvibes.org/public/audio/05-sarcastic-example2.mp3 +0 -0
  98. package/agentvibes.org/public/audio/french-rachel.mp3 +0 -0
  99. package/agentvibes.org/public/audio/spanish-antoni.mp3 +0 -0
  100. package/agentvibes.org/public/favicon.ico +0 -0
  101. package/agentvibes.org/public/fonts/nacelle-italic.woff2 +0 -0
  102. package/agentvibes.org/public/fonts/nacelle-regular.woff2 +0 -0
  103. package/agentvibes.org/public/fonts/nacelle-semibold.woff2 +0 -0
  104. package/agentvibes.org/public/fonts/nacelle-semibolditalic.woff2 +0 -0
  105. package/agentvibes.org/public/images/blurred-shape-gray.svg +0 -1
  106. package/agentvibes.org/public/images/blurred-shape.svg +0 -1
  107. package/agentvibes.org/public/images/client-logo-01.svg +0 -1
  108. package/agentvibes.org/public/images/client-logo-02.svg +0 -1
  109. package/agentvibes.org/public/images/client-logo-03.svg +0 -1
  110. package/agentvibes.org/public/images/client-logo-04.svg +0 -1
  111. package/agentvibes.org/public/images/client-logo-05.svg +0 -1
  112. package/agentvibes.org/public/images/client-logo-06.svg +0 -1
  113. package/agentvibes.org/public/images/client-logo-07.svg +0 -1
  114. package/agentvibes.org/public/images/client-logo-08.svg +0 -1
  115. package/agentvibes.org/public/images/client-logo-09.svg +0 -1
  116. package/agentvibes.org/public/images/features.png +0 -0
  117. package/agentvibes.org/public/images/footer-illustration.svg +0 -1
  118. package/agentvibes.org/public/images/hero-image-01.jpg +0 -0
  119. package/agentvibes.org/public/images/logo.svg +0 -1
  120. package/agentvibes.org/public/images/page-illustration.svg +0 -1
  121. package/agentvibes.org/public/images/secondary-illustration.svg +0 -1
  122. package/agentvibes.org/public/images/testimonial-01.jpg +0 -0
  123. package/agentvibes.org/public/images/testimonial-02.jpg +0 -0
  124. package/agentvibes.org/public/images/testimonial-03.jpg +0 -0
  125. package/agentvibes.org/public/images/testimonial-04.jpg +0 -0
  126. package/agentvibes.org/public/images/testimonial-05.jpg +0 -0
  127. package/agentvibes.org/public/images/testimonial-06.jpg +0 -0
  128. package/agentvibes.org/public/images/testimonial-07.jpg +0 -0
  129. package/agentvibes.org/public/images/testimonial-08.jpg +0 -0
  130. package/agentvibes.org/public/images/testimonial-09.jpg +0 -0
  131. package/agentvibes.org/public/images/workflow-01.png +0 -0
  132. package/agentvibes.org/public/images/workflow-02.png +0 -0
  133. package/agentvibes.org/public/images/workflow-03.png +0 -0
  134. package/agentvibes.org/public/videos/video.mp4 +0 -0
  135. package/agentvibes.org/tsconfig.json +0 -28
  136. package/agentvibes.org/utils/useMasonry.tsx +0 -67
  137. package/agentvibes.org/utils/useMousePosition.tsx +0 -27
  138. package/docs/REMOTE_TTS_SETUP.md +0 -190
@@ -1,201 +0,0 @@
1
- #!/bin/bash
2
- #
3
- # @fileoverview ElevenLabs TTS Provider Implementation
4
- # @context Provider-specific implementation for ElevenLabs API integration
5
- # @architecture Part of multi-provider TTS system - implements provider interface
6
- # @dependencies Requires ELEVENLABS_API_KEY, curl, ffmpeg, paplay/aplay/mpg123, jq
7
- # @entrypoints Called by play-tts.sh router with ($1=text, $2=voice_name)
8
- # @patterns Follows provider contract: accept text/voice, output audio file path
9
- # @related play-tts.sh, provider-manager.sh, GitHub Issue #25
10
- #
11
-
12
- # Fix locale warnings
13
- export LC_ALL=C
14
-
15
- TEXT="$1"
16
- VOICE_OVERRIDE="$2" # Optional: voice name or direct voice ID
17
- API_KEY="${ELEVENLABS_API_KEY}"
18
-
19
- # Check for project-local pretext configuration
20
- CONFIG_DIR="${CLAUDE_PROJECT_DIR:-.}/.claude/config"
21
- CONFIG_FILE="$CONFIG_DIR/agentvibes.json"
22
-
23
- if [[ -f "$CONFIG_FILE" ]] && command -v jq &> /dev/null; then
24
- PRETEXT=$(jq -r '.pretext // empty' "$CONFIG_FILE" 2>/dev/null)
25
- if [[ -n "$PRETEXT" ]]; then
26
- TEXT="$PRETEXT: $TEXT"
27
- fi
28
- fi
29
-
30
- # Limit text length to prevent API issues (max 500 chars for safety)
31
- if [ ${#TEXT} -gt 500 ]; then
32
- TEXT="${TEXT:0:497}..."
33
- echo "⚠️ Text truncated to 500 characters for API safety"
34
- fi
35
-
36
- # Source the single voice configuration file
37
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
38
- source "$SCRIPT_DIR/voices-config.sh"
39
- source "$SCRIPT_DIR/language-manager.sh"
40
-
41
- # @function determine_voice_and_language
42
- # @intent Resolve voice name/ID and language for multilingual support
43
- # @why Supports both voice names and direct IDs, plus language-specific voices
44
- # @param $VOICE_OVERRIDE {string} Voice name or ID (optional)
45
- # @returns Sets $VOICE_ID and $LANGUAGE_CODE global variables
46
- # @sideeffects None
47
- # @edgecases Handles unknown voices, falls back to default
48
- VOICE_ID=""
49
- LANGUAGE_CODE="en" # Default to English
50
-
51
- # Get current language setting
52
- CURRENT_LANGUAGE=$(get_current_language)
53
-
54
- # Get language code for API
55
- LANGUAGE_CODE=$(get_language_code_for_name "$CURRENT_LANGUAGE")
56
- [[ -z "$LANGUAGE_CODE" ]] && LANGUAGE_CODE="en"
57
-
58
- if [[ -n "$VOICE_OVERRIDE" ]]; then
59
- # Check if override is a voice name (lookup in mapping)
60
- if [[ -n "${VOICES[$VOICE_OVERRIDE]}" ]]; then
61
- VOICE_ID="${VOICES[$VOICE_OVERRIDE]}"
62
- echo "🎤 Using voice: $VOICE_OVERRIDE (session-specific)"
63
- # Check if override looks like a voice ID (alphanumeric string ~20 chars)
64
- elif [[ "$VOICE_OVERRIDE" =~ ^[a-zA-Z0-9]{15,30}$ ]]; then
65
- VOICE_ID="$VOICE_OVERRIDE"
66
- echo "🎤 Using custom voice ID (session-specific)"
67
- else
68
- echo "⚠️ Unknown voice '$VOICE_OVERRIDE', trying language-specific voice"
69
- fi
70
- fi
71
-
72
- # If no override or invalid override, use language-specific voice
73
- if [[ -z "$VOICE_ID" ]]; then
74
- # Try to get voice for current language
75
- LANG_VOICE=$(get_voice_for_language "$CURRENT_LANGUAGE" "elevenlabs" 2>/dev/null)
76
-
77
- if [[ -n "$LANG_VOICE" ]] && [[ -n "${VOICES[$LANG_VOICE]}" ]]; then
78
- VOICE_ID="${VOICES[$LANG_VOICE]}"
79
- echo "🌍 Using $CURRENT_LANGUAGE voice: $LANG_VOICE"
80
- else
81
- # Fall back to voice manager
82
- VOICE_MANAGER_SCRIPT="$(dirname "$0")/voice-manager.sh"
83
- if [[ -f "$VOICE_MANAGER_SCRIPT" ]]; then
84
- VOICE_NAME=$("$VOICE_MANAGER_SCRIPT" get)
85
- VOICE_ID="${VOICES[$VOICE_NAME]}"
86
- fi
87
-
88
- # Final fallback to default
89
- if [[ -z "$VOICE_ID" ]]; then
90
- echo "⚠️ No voice configured, using default"
91
- VOICE_ID="${VOICES[Aria]}"
92
- fi
93
- fi
94
- fi
95
-
96
- # @function validate_inputs
97
- # @intent Check required parameters and API key
98
- # @why Fail fast with clear errors if inputs missing
99
- # @exitcode 1=missing text, 2=missing API key
100
- if [ -z "$TEXT" ]; then
101
- echo "Usage: $0 \"text to speak\" [voice_name_or_id]"
102
- exit 1
103
- fi
104
-
105
- if [ -z "$API_KEY" ]; then
106
- echo "Error: ELEVENLABS_API_KEY not set"
107
- echo "Set your API key: export ELEVENLABS_API_KEY=your_key_here"
108
- exit 2
109
- fi
110
-
111
- # @function determine_audio_directory
112
- # @intent Find appropriate directory for audio file storage
113
- # @why Supports project-local and global storage
114
- # @returns Sets $AUDIO_DIR global variable
115
- # @sideeffects None
116
- # @edgecases Handles missing directories, creates if needed
117
- # AI NOTE: Check project dir first, then search up tree, finally fall back to global
118
- if [[ -n "$CLAUDE_PROJECT_DIR" ]]; then
119
- AUDIO_DIR="$CLAUDE_PROJECT_DIR/.claude/audio"
120
- else
121
- # Fallback: try to find .claude directory in current path
122
- CURRENT_DIR="$PWD"
123
- while [[ "$CURRENT_DIR" != "/" ]]; do
124
- if [[ -d "$CURRENT_DIR/.claude" ]]; then
125
- AUDIO_DIR="$CURRENT_DIR/.claude/audio"
126
- break
127
- fi
128
- CURRENT_DIR=$(dirname "$CURRENT_DIR")
129
- done
130
- # Final fallback to global if no project .claude found
131
- if [[ -z "$AUDIO_DIR" ]]; then
132
- AUDIO_DIR="$HOME/.claude/audio"
133
- fi
134
- fi
135
-
136
- mkdir -p "$AUDIO_DIR"
137
- TEMP_FILE="$AUDIO_DIR/tts-$(date +%s).mp3"
138
-
139
- # @function synthesize_with_elevenlabs
140
- # @intent Call ElevenLabs API to generate speech
141
- # @why Encapsulates API call with error handling
142
- # @param Uses globals: $TEXT, $VOICE_ID, $API_KEY
143
- # @returns Creates audio file at $TEMP_FILE
144
- # @exitcode 0=success, 3=API error
145
- # @sideeffects Creates MP3 file in audio directory
146
- # @edgecases Handles network failures, API errors, rate limiting
147
- # Choose model based on language
148
- if [[ "$LANGUAGE_CODE" == "en" ]]; then
149
- MODEL_ID="eleven_monolingual_v1"
150
- else
151
- MODEL_ID="eleven_multilingual_v2"
152
- fi
153
-
154
- curl -s -X POST "https://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}" \
155
- -H "xi-api-key: ${API_KEY}" \
156
- -H "Content-Type: application/json" \
157
- -d "{\"text\":\"${TEXT}\",\"model_id\":\"${MODEL_ID}\",\"language_code\":\"${LANGUAGE_CODE}\",\"voice_settings\":{\"stability\":0.5,\"similarity_boost\":0.75}}" \
158
- -o "${TEMP_FILE}"
159
-
160
- # @function add_silence_padding
161
- # @intent Add silence to beginning of audio to prevent WSL static
162
- # @why WSL audio subsystem cuts off first ~200ms, causing static/clipping
163
- # @param Uses global: $TEMP_FILE
164
- # @returns Updates $TEMP_FILE to padded version
165
- # @sideeffects Modifies audio file, removes original
166
- # @edgecases Gracefully falls back to unpadded if ffmpeg unavailable
167
- # Add silence padding to prevent WSL audio static
168
- if [ -f "${TEMP_FILE}" ]; then
169
- # Check if ffmpeg is available for adding padding
170
- if command -v ffmpeg &> /dev/null; then
171
- PADDED_FILE="$AUDIO_DIR/tts-padded-$(date +%s).mp3"
172
- # Add 200ms of silence at the beginning to prevent static
173
- ffmpeg -f lavfi -i anullsrc=r=44100:cl=stereo:d=0.2 -i "${TEMP_FILE}" \
174
- -filter_complex "[0:a][1:a]concat=n=2:v=0:a=1[out]" \
175
- -map "[out]" -y "${PADDED_FILE}" 2>/dev/null
176
-
177
- if [ -f "${PADDED_FILE}" ]; then
178
- # Use padded file and clean up original
179
- rm -f "${TEMP_FILE}"
180
- TEMP_FILE="${PADDED_FILE}"
181
- fi
182
- # If padding failed, just use original file
183
- fi
184
-
185
- # @function play_audio
186
- # @intent Play generated audio file using available player
187
- # @why Support multiple audio players (paplay, aplay, mpg123)
188
- # @param Uses global: $TEMP_FILE
189
- # @sideeffects Plays audio in background
190
- # @edgecases Falls through players until one works
191
- # Play audio (WSL/Linux) in background to avoid blocking
192
- (paplay "${TEMP_FILE}" 2>/dev/null || aplay "${TEMP_FILE}" 2>/dev/null || mpg123 "${TEMP_FILE}" 2>/dev/null) &
193
-
194
- # Keep temp files for later review - cleaned up weekly by cron
195
- echo "🎵 Saved to: ${TEMP_FILE}"
196
- echo "🎤 Voice used: ${VOICE_NAME} (${VOICE_ID})"
197
- else
198
- echo "❌ Failed to generate audio - API may be unavailable"
199
- echo "Check your API key and network connection"
200
- exit 3
201
- fi
@@ -1,175 +0,0 @@
1
- #!/bin/bash
2
- #
3
- # @fileoverview Piper TTS Provider Implementation
4
- # @context Free, offline neural TTS for WSL/Linux
5
- # @architecture Implements provider contract for Piper binary
6
- # @dependencies piper (pipx), piper-voice-manager.sh, mpv/aplay
7
- # @entrypoints Called by play-tts.sh router
8
- # @patterns Provider contract: text/voice → audio file path
9
- # @related play-tts.sh, piper-voice-manager.sh, GitHub Issue #25
10
- #
11
-
12
- # Fix locale warnings
13
- export LC_ALL=C
14
-
15
- TEXT="$1"
16
- VOICE_OVERRIDE="$2" # Optional: voice model name
17
-
18
- # Source voice manager and language manager
19
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20
- source "$SCRIPT_DIR/piper-voice-manager.sh"
21
- source "$SCRIPT_DIR/language-manager.sh"
22
-
23
- # Default voice for Piper
24
- DEFAULT_VOICE="en_US-lessac-medium"
25
-
26
- # @function determine_voice_model
27
- # @intent Resolve voice name to Piper model name with language support
28
- # @why Support voice override, language-specific voices, and default fallback
29
- # @param Uses global: $VOICE_OVERRIDE
30
- # @returns Sets $VOICE_MODEL global variable
31
- # @sideeffects None
32
- VOICE_MODEL=""
33
-
34
- # Get current language setting
35
- CURRENT_LANGUAGE=$(get_current_language)
36
-
37
- if [[ -n "$VOICE_OVERRIDE" ]]; then
38
- # Use override if provided
39
- VOICE_MODEL="$VOICE_OVERRIDE"
40
- echo "🎤 Using voice: $VOICE_OVERRIDE (session-specific)"
41
- else
42
- # Try to get language-specific voice
43
- LANG_VOICE=$(get_voice_for_language "$CURRENT_LANGUAGE" "piper" 2>/dev/null)
44
-
45
- if [[ -n "$LANG_VOICE" ]]; then
46
- VOICE_MODEL="$LANG_VOICE"
47
- echo "🌍 Using $CURRENT_LANGUAGE voice: $LANG_VOICE (Piper)"
48
- else
49
- # Use default voice
50
- VOICE_MODEL="$DEFAULT_VOICE"
51
- fi
52
- fi
53
-
54
- # @function validate_inputs
55
- # @intent Check required parameters
56
- # @why Fail fast with clear errors if inputs missing
57
- # @exitcode 1=missing text, 2=missing piper binary
58
- if [[ -z "$TEXT" ]]; then
59
- echo "Usage: $0 \"text to speak\" [voice_model_name]"
60
- exit 1
61
- fi
62
-
63
- # Check if Piper is installed
64
- if ! command -v piper &> /dev/null; then
65
- echo "❌ Error: Piper TTS not installed"
66
- echo "Install with: pipx install piper-tts"
67
- echo "Or run: .claude/hooks/piper-installer.sh"
68
- exit 2
69
- fi
70
-
71
- # @function ensure_voice_downloaded
72
- # @intent Download voice model if not cached
73
- # @why Provide seamless experience with automatic downloads
74
- # @param Uses global: $VOICE_MODEL
75
- # @sideeffects Downloads voice model files
76
- # @edgecases Prompts user for consent before downloading
77
- if ! verify_voice "$VOICE_MODEL"; then
78
- echo "📥 Voice model not found: $VOICE_MODEL"
79
- echo " File size: ~25MB"
80
- echo " Preview: https://huggingface.co/rhasspy/piper-voices"
81
- echo ""
82
- read -p " Download this voice model? [y/N]: " -n 1 -r
83
- echo
84
-
85
- if [[ $REPLY =~ ^[Yy]$ ]]; then
86
- if ! download_voice "$VOICE_MODEL"; then
87
- echo "❌ Failed to download voice model"
88
- echo "Fix: Download manually or choose different voice"
89
- exit 3
90
- fi
91
- else
92
- echo "❌ Voice download cancelled"
93
- exit 3
94
- fi
95
- fi
96
-
97
- # Get voice model path
98
- VOICE_PATH=$(get_voice_path "$VOICE_MODEL")
99
- if [[ $? -ne 0 ]]; then
100
- echo "❌ Voice model path not found: $VOICE_MODEL"
101
- exit 3
102
- fi
103
-
104
- # @function determine_audio_directory
105
- # @intent Find appropriate directory for audio file storage
106
- # @why Supports project-local and global storage
107
- # @returns Sets $AUDIO_DIR global variable
108
- if [[ -n "$CLAUDE_PROJECT_DIR" ]]; then
109
- AUDIO_DIR="$CLAUDE_PROJECT_DIR/.claude/audio"
110
- else
111
- # Fallback: try to find .claude directory in current path
112
- CURRENT_DIR="$PWD"
113
- while [[ "$CURRENT_DIR" != "/" ]]; do
114
- if [[ -d "$CURRENT_DIR/.claude" ]]; then
115
- AUDIO_DIR="$CURRENT_DIR/.claude/audio"
116
- break
117
- fi
118
- CURRENT_DIR=$(dirname "$CURRENT_DIR")
119
- done
120
- # Final fallback to global if no project .claude found
121
- if [[ -z "$AUDIO_DIR" ]]; then
122
- AUDIO_DIR="$HOME/.claude/audio"
123
- fi
124
- fi
125
-
126
- mkdir -p "$AUDIO_DIR"
127
- TEMP_FILE="$AUDIO_DIR/tts-$(date +%s).wav"
128
-
129
- # @function synthesize_with_piper
130
- # @intent Generate speech using Piper TTS
131
- # @why Provides free, offline TTS alternative
132
- # @param Uses globals: $TEXT, $VOICE_PATH
133
- # @returns Creates WAV file at $TEMP_FILE
134
- # @exitcode 0=success, 4=synthesis error
135
- # @sideeffects Creates audio file
136
- # @edgecases Handles piper errors, invalid models
137
- echo "$TEXT" | piper --model "$VOICE_PATH" --output_file "$TEMP_FILE" 2>/dev/null
138
-
139
- if [[ ! -f "$TEMP_FILE" ]] || [[ ! -s "$TEMP_FILE" ]]; then
140
- echo "❌ Failed to synthesize speech with Piper"
141
- echo "Voice model: $VOICE_MODEL"
142
- echo "Check that voice model is valid"
143
- exit 4
144
- fi
145
-
146
- # @function add_silence_padding
147
- # @intent Add silence to prevent WSL audio static
148
- # @why WSL audio subsystem cuts off first ~200ms
149
- # @param Uses global: $TEMP_FILE
150
- # @returns Updates $TEMP_FILE to padded version
151
- # @sideeffects Modifies audio file
152
- # AI NOTE: Use ffmpeg if available, otherwise skip padding (degraded experience)
153
- if command -v ffmpeg &> /dev/null; then
154
- PADDED_FILE="$AUDIO_DIR/tts-padded-$(date +%s).wav"
155
- # Add 200ms of silence at the beginning
156
- ffmpeg -f lavfi -i anullsrc=r=44100:cl=stereo:d=0.2 -i "$TEMP_FILE" \
157
- -filter_complex "[0:a][1:a]concat=n=2:v=0:a=1[out]" \
158
- -map "[out]" -y "$PADDED_FILE" 2>/dev/null
159
-
160
- if [[ -f "$PADDED_FILE" ]]; then
161
- rm -f "$TEMP_FILE"
162
- TEMP_FILE="$PADDED_FILE"
163
- fi
164
- fi
165
-
166
- # @function play_audio
167
- # @intent Play generated audio using available player
168
- # @why Support multiple audio players
169
- # @param Uses global: $TEMP_FILE
170
- # @sideeffects Plays audio in background
171
- # Play audio (WSL/Linux) in background
172
- (mpv "$TEMP_FILE" 2>/dev/null || aplay "$TEMP_FILE" 2>/dev/null || paplay "$TEMP_FILE" 2>/dev/null) &
173
-
174
- echo "🎵 Saved to: $TEMP_FILE"
175
- echo "🎤 Voice used: $VOICE_MODEL (Piper TTS)"
@@ -1,138 +0,0 @@
1
- #!/bin/bash
2
- # Quick TTS playback script with session-specific voice support
3
- # Usage: play-tts.sh "Text to speak" [voice_name_or_id]
4
- #
5
- # Examples:
6
- # play-tts.sh "Hello world" # Uses default voice from voice manager
7
- # play-tts.sh "Hello world" "Sarah" # Uses Sarah voice by name
8
- # play-tts.sh "Hello world" "KTPVrSVAEUSJRClDzBw7" # Uses voice by direct ID
9
- #
10
- # This allows different sessions to use different voices for easy identification!
11
-
12
- # Fix locale warnings
13
- export LC_ALL=C
14
-
15
- TEXT="$1"
16
- VOICE_OVERRIDE="$2" # Optional: voice name or direct voice ID
17
- API_KEY="${ELEVENLABS_API_KEY}"
18
-
19
- # Check for project-local pretext configuration
20
- CONFIG_DIR="${CLAUDE_PROJECT_DIR:-.}/.claude/config"
21
- CONFIG_FILE="$CONFIG_DIR/agentvibes.json"
22
-
23
- if [[ -f "$CONFIG_FILE" ]] && command -v jq &> /dev/null; then
24
- PRETEXT=$(jq -r '.pretext // empty' "$CONFIG_FILE" 2>/dev/null)
25
- if [[ -n "$PRETEXT" ]]; then
26
- TEXT="$PRETEXT: $TEXT"
27
- fi
28
- fi
29
-
30
- # Limit text length to prevent API issues (max 500 chars for safety)
31
- if [ ${#TEXT} -gt 500 ]; then
32
- TEXT="${TEXT:0:497}..."
33
- echo "⚠️ Text truncated to 500 characters for API safety"
34
- fi
35
-
36
- # Source the single voice configuration file
37
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
38
- source "$SCRIPT_DIR/voices-config.sh"
39
-
40
- # Determine which voice to use
41
- VOICE_ID=""
42
-
43
- if [[ -n "$VOICE_OVERRIDE" ]]; then
44
- # Check if override is a voice name (lookup in mapping)
45
- if [[ -n "${VOICES[$VOICE_OVERRIDE]}" ]]; then
46
- VOICE_ID="${VOICES[$VOICE_OVERRIDE]}"
47
- echo "🎤 Using voice: $VOICE_OVERRIDE (session-specific)"
48
- # Check if override looks like a voice ID (alphanumeric string ~20 chars)
49
- elif [[ "$VOICE_OVERRIDE" =~ ^[a-zA-Z0-9]{15,30}$ ]]; then
50
- VOICE_ID="$VOICE_OVERRIDE"
51
- echo "🎤 Using custom voice ID (session-specific)"
52
- else
53
- echo "⚠️ Unknown voice '$VOICE_OVERRIDE', using default"
54
- fi
55
- fi
56
-
57
- # If no override or invalid override, use default from voice manager
58
- if [[ -z "$VOICE_ID" ]]; then
59
- VOICE_MANAGER_SCRIPT="$(dirname "$0")/voice-manager.sh"
60
- if [[ -f "$VOICE_MANAGER_SCRIPT" ]]; then
61
- VOICE_NAME=$("$VOICE_MANAGER_SCRIPT" get)
62
- VOICE_ID="${VOICES[$VOICE_NAME]}"
63
- fi
64
-
65
- # Final fallback to Cowboy Bob default
66
- if [[ -z "$VOICE_ID" ]]; then
67
- echo "⚠️ No voice configured, using Cowboy Bob default"
68
- VOICE_ID="${VOICES[Cowboy Bob]}"
69
- fi
70
- fi
71
-
72
- if [ -z "$TEXT" ]; then
73
- echo "Usage: $0 \"text to speak\""
74
- exit 1
75
- fi
76
-
77
- if [ -z "$API_KEY" ]; then
78
- echo "Error: ELEVENLABS_API_KEY not set"
79
- exit 1
80
- fi
81
-
82
- # Create audio file in project-local storage
83
- # Use project directory if available, otherwise fall back to global
84
- if [[ -n "$CLAUDE_PROJECT_DIR" ]]; then
85
- AUDIO_DIR="$CLAUDE_PROJECT_DIR/.claude/audio"
86
- else
87
- # Fallback: try to find .claude directory in current path
88
- CURRENT_DIR="$PWD"
89
- while [[ "$CURRENT_DIR" != "/" ]]; do
90
- if [[ -d "$CURRENT_DIR/.claude" ]]; then
91
- AUDIO_DIR="$CURRENT_DIR/.claude/audio"
92
- break
93
- fi
94
- CURRENT_DIR=$(dirname "$CURRENT_DIR")
95
- done
96
- # Final fallback to global if no project .claude found
97
- if [[ -z "$AUDIO_DIR" ]]; then
98
- AUDIO_DIR="$HOME/.claude/audio"
99
- fi
100
- fi
101
-
102
- mkdir -p "$AUDIO_DIR"
103
- TEMP_FILE="$AUDIO_DIR/tts-$(date +%s).mp3"
104
-
105
- # Generate audio
106
- curl -s -X POST "https://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}" \
107
- -H "xi-api-key: ${API_KEY}" \
108
- -H "Content-Type: application/json" \
109
- -d "{\"text\":\"${TEXT}\",\"model_id\":\"eleven_monolingual_v1\",\"voice_settings\":{\"stability\":0.5,\"similarity_boost\":0.75}}" \
110
- -o "${TEMP_FILE}"
111
-
112
- # Add silence padding to prevent WSL audio static
113
- if [ -f "${TEMP_FILE}" ]; then
114
- # Check if ffmpeg is available for adding padding
115
- if command -v ffmpeg &> /dev/null; then
116
- PADDED_FILE="$AUDIO_DIR/tts-padded-$(date +%s).mp3"
117
- # Add 200ms of silence at the beginning to prevent static
118
- ffmpeg -f lavfi -i anullsrc=r=44100:cl=stereo:d=0.2 -i "${TEMP_FILE}" \
119
- -filter_complex "[0:a][1:a]concat=n=2:v=0:a=1[out]" \
120
- -map "[out]" -y "${PADDED_FILE}" 2>/dev/null
121
-
122
- if [ -f "${PADDED_FILE}" ]; then
123
- # Use padded file and clean up original
124
- rm -f "${TEMP_FILE}"
125
- TEMP_FILE="${PADDED_FILE}"
126
- fi
127
- # If padding failed, just use original file
128
- fi
129
-
130
- # Play audio (WSL/Linux) in background to avoid blocking
131
- (paplay "${TEMP_FILE}" 2>/dev/null || aplay "${TEMP_FILE}" 2>/dev/null || mpg123 "${TEMP_FILE}" 2>/dev/null) &
132
- # Keep temp files for later review - cleaned up weekly by cron
133
- echo "🎵 Saved to: ${TEMP_FILE}"
134
- echo "🎤 Voice used: ${VOICE_NAME} (${VOICE_ID})"
135
- else
136
- echo "Failed to generate audio"
137
- exit 1
138
- fi