202 lines
6.8 KiB
Bash
Executable File
202 lines
6.8 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# File: .claude/hooks/sentiment-manager.sh
|
|
#
|
|
# AgentVibes - Finally, your AI Agents can Talk Back! Text-to-Speech WITH personality for AI Assistants!
|
|
# Website: https://agentvibes.org
|
|
# Repository: https://github.com/paulpreibisch/AgentVibes
|
|
#
|
|
# Co-created by Paul Preibisch with Claude AI
|
|
# Copyright (c) 2025 Paul Preibisch
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
# DISCLAIMER: This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
# express or implied, including but not limited to the warranties of
|
|
# merchantability, fitness for a particular purpose and noninfringement.
|
|
# In no event shall the authors or copyright holders be liable for any claim,
|
|
# damages or other liability, whether in an action of contract, tort or
|
|
# otherwise, arising from, out of or in connection with the software or the
|
|
# use or other dealings in the software.
|
|
#
|
|
# ---
|
|
#
|
|
# @fileoverview Sentiment Manager - Applies personality styles to current voice without changing the voice itself
|
|
# @context Allows adding emotional/tonal layers (flirty, sarcastic, etc.) to any voice while preserving voice identity
|
|
# @architecture Reuses personality markdown files, stores sentiment separately from personality
|
|
# @dependencies .claude/personalities/*.md files, play-tts.sh for acknowledgment
|
|
# @entrypoints Called by /agent-vibes:sentiment slash command
|
|
# @patterns Personality/sentiment separation, state file management, random example selection
|
|
# @related personality-manager.sh, .claude/personalities/*.md, .claude/tts-sentiment.txt
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PERSONALITIES_DIR="$SCRIPT_DIR/../personalities"
|
|
|
|
# Project-local file first, global fallback
|
|
# Use logical path (not physical) to handle symlinked .claude directories
|
|
# Script is at .claude/hooks/sentiment-manager.sh, so .claude is ..
|
|
CLAUDE_DIR="$(cd "$SCRIPT_DIR/.." 2>/dev/null && pwd)"
|
|
|
|
# Check if we have a project-local .claude directory
|
|
if [[ -d "$CLAUDE_DIR" ]] && [[ "$CLAUDE_DIR" != "$HOME/.claude" ]]; then
|
|
SENTIMENT_FILE="$CLAUDE_DIR/tts-sentiment.txt"
|
|
else
|
|
SENTIMENT_FILE="$HOME/.claude/tts-sentiment.txt"
|
|
fi
|
|
|
|
# Function to get personality data from markdown file
|
|
get_personality_data() {
|
|
local personality="$1"
|
|
local field="$2"
|
|
local file="$PERSONALITIES_DIR/${personality}.md"
|
|
|
|
if [[ ! -f "$file" ]]; then
|
|
return 1
|
|
fi
|
|
|
|
case "$field" in
|
|
description)
|
|
grep "^description:" "$file" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Function to list all available personalities
|
|
list_personalities() {
|
|
if [[ -d "$PERSONALITIES_DIR" ]]; then
|
|
for file in "$PERSONALITIES_DIR"/*.md; do
|
|
if [[ -f "$file" ]]; then
|
|
basename "$file" .md
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
case "$1" in
|
|
list)
|
|
echo "🎭 Available Sentiments:"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
# Get current sentiment
|
|
CURRENT="none"
|
|
if [ -f "$SENTIMENT_FILE" ]; then
|
|
CURRENT=$(cat "$SENTIMENT_FILE")
|
|
fi
|
|
|
|
# List personalities from markdown files
|
|
echo "Available sentiment styles:"
|
|
for personality in $(list_personalities | sort); do
|
|
desc=$(get_personality_data "$personality" "description")
|
|
if [[ "$personality" == "$CURRENT" ]]; then
|
|
echo " ✓ $personality - $desc (current)"
|
|
else
|
|
echo " - $personality - $desc"
|
|
fi
|
|
done
|
|
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
echo "Usage: /agent-vibes:sentiment <name>"
|
|
echo " /agent-vibes:sentiment clear"
|
|
;;
|
|
|
|
set)
|
|
SENTIMENT="$2"
|
|
|
|
if [[ -z "$SENTIMENT" ]]; then
|
|
echo "❌ Please specify a sentiment name"
|
|
echo "Usage: $0 set <sentiment>"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if sentiment file exists
|
|
if [[ ! -f "$PERSONALITIES_DIR/${SENTIMENT}.md" ]]; then
|
|
echo "❌ Sentiment not found: $SENTIMENT"
|
|
echo ""
|
|
echo "Available sentiments:"
|
|
for p in $(list_personalities | sort); do
|
|
echo " • $p"
|
|
done
|
|
exit 1
|
|
fi
|
|
|
|
# Save the sentiment (but don't change personality or voice)
|
|
echo "$SENTIMENT" > "$SENTIMENT_FILE"
|
|
echo "🎭 Sentiment set to: $SENTIMENT"
|
|
echo "🎤 Voice remains unchanged"
|
|
echo ""
|
|
|
|
# Make a sentiment-appropriate remark with TTS
|
|
TTS_SCRIPT="$SCRIPT_DIR/play-tts.sh"
|
|
|
|
# Try to get acknowledgment from personality file (sentiments use same personality files)
|
|
PERSONALITY_FILE_PATH="$PERSONALITIES_DIR/${SENTIMENT}.md"
|
|
REMARK=""
|
|
|
|
if [[ -f "$PERSONALITY_FILE_PATH" ]]; then
|
|
# Extract example responses from personality file (lines starting with "- ")
|
|
mapfile -t EXAMPLES < <(grep '^- "' "$PERSONALITY_FILE_PATH" | sed 's/^- "//; s/"$//')
|
|
|
|
if [[ ${#EXAMPLES[@]} -gt 0 ]]; then
|
|
# Pick a random example
|
|
REMARK="${EXAMPLES[$RANDOM % ${#EXAMPLES[@]}]}"
|
|
fi
|
|
fi
|
|
|
|
# Fallback if no examples found
|
|
if [[ -z "$REMARK" ]]; then
|
|
REMARK="Sentiment set to ${SENTIMENT} while maintaining current voice"
|
|
fi
|
|
|
|
echo "💬 $REMARK"
|
|
"$TTS_SCRIPT" "$REMARK"
|
|
;;
|
|
|
|
get)
|
|
if [ -f "$SENTIMENT_FILE" ]; then
|
|
CURRENT=$(cat "$SENTIMENT_FILE")
|
|
echo "Current sentiment: $CURRENT"
|
|
|
|
desc=$(get_personality_data "$CURRENT" "description")
|
|
[[ -n "$desc" ]] && echo "Description: $desc"
|
|
else
|
|
echo "Current sentiment: none (voice personality only)"
|
|
fi
|
|
;;
|
|
|
|
clear)
|
|
rm -f "$SENTIMENT_FILE"
|
|
echo "🎭 Sentiment cleared - using voice personality only"
|
|
;;
|
|
|
|
*)
|
|
# If a single argument is provided and it's not a command, treat it as "set <sentiment>"
|
|
if [[ -n "$1" ]] && [[ -f "$PERSONALITIES_DIR/${1}.md" ]]; then
|
|
exec "$0" set "$1"
|
|
else
|
|
echo "AgentVibes Sentiment Manager"
|
|
echo ""
|
|
echo "Commands:"
|
|
echo " list - List all sentiments"
|
|
echo " set <name> - Set sentiment for current voice"
|
|
echo " get - Show current sentiment"
|
|
echo " clear - Clear sentiment"
|
|
echo ""
|
|
echo "Examples:"
|
|
echo " /agent-vibes:sentiment flirty # Add flirty style to current voice"
|
|
echo " /agent-vibes:sentiment sarcastic # Add sarcasm to current voice"
|
|
echo " /agent-vibes:sentiment clear # Remove sentiment"
|
|
fi
|
|
;;
|
|
esac
|