Initial commit
This commit is contained in:
17
.claude-plugin/plugin.json
Normal file
17
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "takushi-notifier",
|
||||||
|
"description": "Claude Assistantの応答を音声で読み上げるプラグイン(Style-Bert-VITS2対応)",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": {
|
||||||
|
"name": "Yuri"
|
||||||
|
},
|
||||||
|
"skills": [
|
||||||
|
"./skills"
|
||||||
|
],
|
||||||
|
"commands": [
|
||||||
|
"./commands"
|
||||||
|
],
|
||||||
|
"hooks": [
|
||||||
|
"./hooks"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# takushi-notifier
|
||||||
|
|
||||||
|
Claude Assistantの応答を音声で読み上げるプラグイン(Style-Bert-VITS2対応)
|
||||||
51
commands/project_name.md
Normal file
51
commands/project_name.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
description: "現在のプロジェクトに名前を設定する"
|
||||||
|
argument-hint: [project_name]
|
||||||
|
---
|
||||||
|
|
||||||
|
# エージェント向け指示
|
||||||
|
|
||||||
|
引数がある場合は現在の作業ディレクトリにプロジェクト名を設定し、引数がない場合は現在設定されているプロジェクト名を表示してください。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# プロジェクト名設定(引数がある場合)
|
||||||
|
bash "${CLAUDE_PLUGIN_ROOT}/hooks/project_manager.sh" set "$(pwd)" "[project_name]"
|
||||||
|
|
||||||
|
# 現在のプロジェクト名取得(引数がない場合)
|
||||||
|
bash "${CLAUDE_PLUGIN_ROOT}/hooks/project_manager.sh" get "$(pwd)"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ユーザー向け使用方法
|
||||||
|
|
||||||
|
## 概要
|
||||||
|
現在のプロジェクトに名前を設定します。設定した名前は通知時に読み上げられます。
|
||||||
|
|
||||||
|
## 使用例
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# プロジェクト名を設定
|
||||||
|
/project_name TakushiNotifier
|
||||||
|
|
||||||
|
# 現在のプロジェクト名を確認
|
||||||
|
/project_name
|
||||||
|
```
|
||||||
|
|
||||||
|
## 引数
|
||||||
|
|
||||||
|
- `project_name` (オプション): プロジェクトに付ける名前(文字列)
|
||||||
|
- 省略時: 現在のプロジェクト名を表示
|
||||||
|
|
||||||
|
## 動作
|
||||||
|
|
||||||
|
プロジェクト名が設定されている場合、通知時に読み上げるテキストの先頭に「{プロジェクト名}です。」が追加されます。
|
||||||
|
|
||||||
|
**例:**
|
||||||
|
- プロジェクト名: `InfoComposer`
|
||||||
|
- 元のメッセージ: `処理が完了しました。`
|
||||||
|
- 読み上げ: `InfoComposerです。処理が完了しました。`
|
||||||
|
|
||||||
|
## 設定保存
|
||||||
|
|
||||||
|
設定は `~/.config/takushi_notifier/project_names.conf` に保存され、プロジェクトパスごとに管理されます。
|
||||||
45
commands/volume.md
Normal file
45
commands/volume.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
description: "Takushi音量を0-100の範囲で設定する"
|
||||||
|
argument-hint: [volume]
|
||||||
|
---
|
||||||
|
|
||||||
|
# エージェント向け指示
|
||||||
|
|
||||||
|
引数がある場合は音量を設定し、引数がない場合は現在の音量を表示してください。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 音量設定(引数がある場合)
|
||||||
|
bash "${CLAUDE_PLUGIN_ROOT}/hooks/volume_manager.sh" set [volume]
|
||||||
|
|
||||||
|
# 現在の音量取得(引数がない場合)
|
||||||
|
bash "${CLAUDE_PLUGIN_ROOT}/hooks/volume_manager.sh" get
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ユーザー向け使用方法
|
||||||
|
|
||||||
|
## 概要
|
||||||
|
Takushi(Text-to-Speech)の音量を0-100の範囲で設定します。
|
||||||
|
|
||||||
|
## 使用例
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 音量を75%に設定
|
||||||
|
/volume 75
|
||||||
|
|
||||||
|
# 現在の音量を確認
|
||||||
|
/volume
|
||||||
|
```
|
||||||
|
|
||||||
|
## 引数
|
||||||
|
|
||||||
|
- `volume` (オプション): 音量レベル(0-100の整数)
|
||||||
|
- 0: 無音
|
||||||
|
- 50: 中間音量
|
||||||
|
- 100: 最大音量
|
||||||
|
- 省略時: 現在の音量を表示
|
||||||
|
|
||||||
|
## 設定保存
|
||||||
|
|
||||||
|
設定は `~/.config/takushi_notifier/volume.conf` に保存されます。
|
||||||
81
hooks/generate_message.sh
Executable file
81
hooks/generate_message.sh
Executable file
@@ -0,0 +1,81 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# メッセージ生成スクリプト
|
||||||
|
|
||||||
|
# プラグインのディレクトリを取得
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
HOOKS_DIR="$SCRIPT_DIR"
|
||||||
|
NOTIFY_LOG_PATH="$HOOKS_DIR/notify.log"
|
||||||
|
|
||||||
|
# 標準入力からメッセージ要約を取得
|
||||||
|
SUMMARY=$(cat)
|
||||||
|
|
||||||
|
EXISTING_EXAMPLES=$(cat <<'EOT'
|
||||||
|
- 対応を完了しました。
|
||||||
|
- 修正を反映しました。
|
||||||
|
- 最終確認をお願いします。
|
||||||
|
- 確認事項があります。
|
||||||
|
- 次の点についてご確認ください。
|
||||||
|
- ご回答をお願いします。
|
||||||
|
- 追加の情報が必要です。
|
||||||
|
- ご指示をお願いします。
|
||||||
|
- ご確認ください。
|
||||||
|
- 以上です。
|
||||||
|
EOT
|
||||||
|
)
|
||||||
|
|
||||||
|
# 直近10件のログを取得
|
||||||
|
RECENT_LOGS=""
|
||||||
|
if [ -f "$NOTIFY_LOG_PATH" ]; then
|
||||||
|
RECENT_LOGS=$(tail -n 10 "$NOTIFY_LOG_PATH" | cut -d'|' -f2)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Claude APIへのプロンプトを作成
|
||||||
|
PROMPT="あなたは無個性で中立的なアシスタントです。以下のタスク要約に対し、
|
||||||
|
感情やキャラクター性を排した、簡潔で平易な敬体のメッセージを50文字以内で生成してください。
|
||||||
|
|
||||||
|
前提: これはAgentからユーザーへの切り替え時の発言です(質問がある時または対応完了時)。
|
||||||
|
|
||||||
|
タスク要約: $SUMMARY
|
||||||
|
|
||||||
|
【必須要件】
|
||||||
|
- 無個性・中立。感情やキャラクター性を出さない。
|
||||||
|
- です/ます調。過度に仰々しい敬語や比喩は避ける。
|
||||||
|
- 記号・絵文字・感嘆符を使わない。平易な語彙を用いる。
|
||||||
|
- 着手・開始・実行・進める等の未来時制の表現は使わない。
|
||||||
|
- 成果の報告または質問の提示に限定する。
|
||||||
|
|
||||||
|
【重複回避】
|
||||||
|
- 最近の発言(下記)と同義反復や語句の重複を避ける。
|
||||||
|
$RECENT_LOGS
|
||||||
|
|
||||||
|
【発言パターン例】
|
||||||
|
$EXISTING_EXAMPLES
|
||||||
|
|
||||||
|
【出力形式】
|
||||||
|
- 何をしたかが具体的にわかるよう、端的に記載する(前後の解説・記号・引用符なし)。"
|
||||||
|
|
||||||
|
# フォールバック文言の判定(質問/確認が含まれるかで出し分け)
|
||||||
|
if echo "$SUMMARY" | grep -Eq '[\??]|質問|確認|教えて|不明点|ご回答'; then
|
||||||
|
FALLBACK_MESSAGE="ご確認をお願いします。"
|
||||||
|
else
|
||||||
|
FALLBACK_MESSAGE="対応を完了しました。"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Claude CLIコマンドを使用してメッセージ生成
|
||||||
|
if command -v claude >/dev/null 2>&1; then
|
||||||
|
# プロンプトを直接パイプで渡す
|
||||||
|
RESPONSE=$(echo "$PROMPT" | claude -p - 2>/dev/null)
|
||||||
|
# レスポンスが取得できた場合
|
||||||
|
if [ -n "$RESPONSE" ] && [ "$RESPONSE" != "" ]; then
|
||||||
|
echo "$RESPONSE" | head -n 2
|
||||||
|
else
|
||||||
|
# Claude CLIが失敗した場合のフォールバック
|
||||||
|
echo "$FALLBACK_MESSAGE"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Claude CLIが利用できない場合のフォールバック
|
||||||
|
echo "$FALLBACK_MESSAGE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
15
hooks/hooks.json
Normal file
15
hooks/hooks.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"hooks": {
|
||||||
|
"Stop": [
|
||||||
|
{
|
||||||
|
"matcher": "",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/notify.sh"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
90
hooks/notify.sh
Executable file
90
hooks/notify.sh
Executable file
@@ -0,0 +1,90 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 音声通知スクリプト
|
||||||
|
# 最後のメッセージを取得し、要約してメッセージを読み上げ
|
||||||
|
|
||||||
|
# 標準入力からJSONを読み取る
|
||||||
|
INPUT=$(cat)
|
||||||
|
|
||||||
|
# プラグインのディレクトリを取得
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PLUGIN_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
|
HOOKS_DIR="$SCRIPT_DIR"
|
||||||
|
NOTIFY_LOG_PATH="$HOOKS_DIR/notify.log"
|
||||||
|
|
||||||
|
# ログディレクトリの作成
|
||||||
|
mkdir -p "$HOOKS_DIR"
|
||||||
|
|
||||||
|
# トランスクリプトを処理(.jsonl形式に対応)
|
||||||
|
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path')
|
||||||
|
if [ -f "$TRANSCRIPT_PATH" ]; then
|
||||||
|
# 最後のアシスタントメッセージのみを取得(全文)
|
||||||
|
TEMP_FILE=$(mktemp)
|
||||||
|
|
||||||
|
if command -v tail >/dev/null 2>&1; then
|
||||||
|
tail -r "$TRANSCRIPT_PATH" > "$TEMP_FILE"
|
||||||
|
|
||||||
|
LAST_MESSAGE=""
|
||||||
|
while IFS= read -r line; do
|
||||||
|
# JSON形式の妥当性をチェック
|
||||||
|
if echo "$line" | jq -e . >/dev/null 2>&1; then
|
||||||
|
if echo "$line" | jq -e '.type == "assistant"' >/dev/null 2>&1; then
|
||||||
|
LAST_MESSAGE=$(echo "$line" | jq -r '.message.content[]? | select(.type == "text") | .text' 2>/dev/null)
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < "$TEMP_FILE"
|
||||||
|
|
||||||
|
rm -f "$TEMP_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# メッセージが取得できた場合の処理
|
||||||
|
if [ -n "$LAST_MESSAGE" ]; then
|
||||||
|
# 最後のメッセージの1行目を取得(最大100文字)
|
||||||
|
MESSAGE=$(echo "$LAST_MESSAGE" | head -n 1 | head -c 100 | sed 's/[[:space:]]*$//')
|
||||||
|
|
||||||
|
# メッセージが空の場合はデフォルト文例
|
||||||
|
if [ -z "$MESSAGE" ]; then
|
||||||
|
MESSAGE="処理が完了しました。"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# プロジェクト名を取得して追加
|
||||||
|
PROJECT_PATH=$(echo "$INPUT" | jq -r '.cwd // empty')
|
||||||
|
if [ -n "$PROJECT_PATH" ]; then
|
||||||
|
PROJECT_MANAGER="$HOOKS_DIR/project_manager.sh"
|
||||||
|
if [ -f "$PROJECT_MANAGER" ]; then
|
||||||
|
PROJECT_NAME=$(bash "$PROJECT_MANAGER" get "$PROJECT_PATH" 2>/dev/null || echo "")
|
||||||
|
if [ -n "$PROJECT_NAME" ]; then
|
||||||
|
MESSAGE="${PROJECT_NAME}のたくしです。${MESSAGE}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 通知実行
|
||||||
|
# terminal-notifier使用(Macネイティブ通知)
|
||||||
|
if command -v terminal-notifier >/dev/null 2>&1; then
|
||||||
|
terminal-notifier -message "$MESSAGE" -title "Assistant" >/dev/null 2>&1 &
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 音声出力(Style-Bert-VITS2)
|
||||||
|
TTS_SCRIPT="$HOOKS_DIR/tts_bert_vits.sh"
|
||||||
|
if [ -f "$TTS_SCRIPT" ]; then
|
||||||
|
nohup bash "$TTS_SCRIPT" "$MESSAGE" >/dev/null 2>&1 &
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ログ保存(タイムスタンプ|発言のみ、改行除去)
|
||||||
|
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
CLEAN_MESSAGE=$(echo "$MESSAGE" | tr -d '\n\r' | sed 's/[[:space:]]\+/ /g' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||||
|
echo "$TIMESTAMP|$CLEAN_MESSAGE" >> "$NOTIFY_LOG_PATH"
|
||||||
|
|
||||||
|
# ログを10件までに制限
|
||||||
|
if [ -f "$NOTIFY_LOG_PATH" ]; then
|
||||||
|
TEMP_LOG=$(mktemp)
|
||||||
|
tail -n 10 "$NOTIFY_LOG_PATH" > "$TEMP_LOG"
|
||||||
|
mv "$TEMP_LOG" "$NOTIFY_LOG_PATH"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo '{"decision": "approve"}'
|
||||||
|
exit 0
|
||||||
126
hooks/project_manager.sh
Executable file
126
hooks/project_manager.sh
Executable file
@@ -0,0 +1,126 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Takushiプロジェクト名管理スクリプト
|
||||||
|
# 使用方法: ./project_manager.sh [action] [args...]
|
||||||
|
# action: set, get, init
|
||||||
|
|
||||||
|
CONFIG_DIR="$HOME/.config/takushi_notifier"
|
||||||
|
PROJECT_NAMES_FILE="$CONFIG_DIR/project_names.conf"
|
||||||
|
|
||||||
|
# 設定ディレクトリの作成
|
||||||
|
init_config() {
|
||||||
|
mkdir -p "$CONFIG_DIR"
|
||||||
|
if [ ! -f "$PROJECT_NAMES_FILE" ]; then
|
||||||
|
touch "$PROJECT_NAMES_FILE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# プロジェクト名設定
|
||||||
|
set_project_name() {
|
||||||
|
local project_path="$1"
|
||||||
|
local project_name="$2"
|
||||||
|
|
||||||
|
# 引数チェック
|
||||||
|
if [ -z "$project_path" ] || [ -z "$project_name" ]; then
|
||||||
|
echo "エラー: プロジェクトパスと名前を指定してください"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
init_config
|
||||||
|
|
||||||
|
# 一時ファイルを作成
|
||||||
|
local temp_file=$(mktemp)
|
||||||
|
local var_name="PROJECT_NAME_${project_path//\//_}"
|
||||||
|
local updated=false
|
||||||
|
|
||||||
|
# 設定ファイルを読み込み、該当行を更新
|
||||||
|
if [ -f "$PROJECT_NAMES_FILE" ]; then
|
||||||
|
while IFS= read -r line; do
|
||||||
|
if [[ "$line" =~ ^${var_name}= ]]; then
|
||||||
|
echo "${var_name}=\"$project_name\"" >> "$temp_file"
|
||||||
|
updated=true
|
||||||
|
else
|
||||||
|
echo "$line" >> "$temp_file"
|
||||||
|
fi
|
||||||
|
done < "$PROJECT_NAMES_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 新規追加の場合
|
||||||
|
if [ "$updated" = false ]; then
|
||||||
|
echo "${var_name}=\"$project_name\"" >> "$temp_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 一時ファイルで設定ファイルを上書き
|
||||||
|
mv "$temp_file" "$PROJECT_NAMES_FILE"
|
||||||
|
|
||||||
|
echo "プロジェクト「${project_name}」を設定しました (パス: ${project_path})"
|
||||||
|
}
|
||||||
|
|
||||||
|
# プロジェクト名取得
|
||||||
|
get_project_name() {
|
||||||
|
local project_path="$1"
|
||||||
|
|
||||||
|
if [ -z "$project_path" ]; then
|
||||||
|
echo "エラー: プロジェクトパスを指定してください"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
init_config
|
||||||
|
|
||||||
|
if [ -f "$PROJECT_NAMES_FILE" ]; then
|
||||||
|
local current_path="$project_path"
|
||||||
|
|
||||||
|
# 現在のパスから親階層まで順に探索
|
||||||
|
while [ -n "$current_path" ]; do
|
||||||
|
local var_name="PROJECT_NAME_${current_path//\//_}"
|
||||||
|
local project_name=$(grep "^${var_name}=" "$PROJECT_NAMES_FILE" | cut -d'=' -f2- | tr -d '"')
|
||||||
|
|
||||||
|
if [ -n "$project_name" ]; then
|
||||||
|
echo "$project_name"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 親ディレクトリに移動
|
||||||
|
if [ "$current_path" = "/" ] || [ "$current_path" = "." ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
current_path=$(dirname "$current_path")
|
||||||
|
if [ "$current_path" = "." ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# メイン処理
|
||||||
|
case "${1:-get}" in
|
||||||
|
"set")
|
||||||
|
if [ -z "$2" ] || [ -z "$3" ]; then
|
||||||
|
echo "エラー: プロジェクトパスと名前を指定してください"
|
||||||
|
echo "使用方法: $0 set [path] [name]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
set_project_name "$2" "$3"
|
||||||
|
;;
|
||||||
|
"get")
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
echo "エラー: プロジェクトパスを指定してください"
|
||||||
|
echo "使用方法: $0 get [path]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
get_project_name "$2"
|
||||||
|
;;
|
||||||
|
"init")
|
||||||
|
init_config
|
||||||
|
echo "設定ディレクトリを初期化しました: $CONFIG_DIR"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "使用方法: $0 [set|get|init] [args...]"
|
||||||
|
echo " set [path] [name] : プロジェクト名を設定"
|
||||||
|
echo " get [path] : プロジェクト名を取得"
|
||||||
|
echo " init : 設定ディレクトリを初期化"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
107
hooks/tts_bert_vits.sh
Executable file
107
hooks/tts_bert_vits.sh
Executable file
@@ -0,0 +1,107 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Style-Bert-VITS2 音声合成スクリプト
|
||||||
|
# 使用方法: ./tts_bert_vits.sh "読み上げたいテキスト"
|
||||||
|
|
||||||
|
# API認証情報
|
||||||
|
CF_ACCESS_CLIENT_ID="78daf18f4b82f77f12a0bfec004ab4ce.access"
|
||||||
|
CF_ACCESS_CLIENT_SECRET="cded896f04ee01c47f5098cebcd3118ed09ad1bc3666f1d59cc5912b2e724020"
|
||||||
|
API_BASE_URL="https://bert-vits-web.vildas.org"
|
||||||
|
|
||||||
|
# モデル設定(固定)
|
||||||
|
MODEL_NAME="izawa_toiyomi"
|
||||||
|
MODEL_FILE="model_assets/izawa_toiyomi/izawa_toiyomi_e100_s5000.safetensors"
|
||||||
|
|
||||||
|
# 設定ファイルの読み込み
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
# グローバル設定ファイルを読み込み
|
||||||
|
GLOBAL_CONFIG="$HOME/.config/takushi_notifier/volume.conf"
|
||||||
|
|
||||||
|
# グローバル設定ファイルが存在する場合は読み込み
|
||||||
|
if [ -f "$GLOBAL_CONFIG" ]; then
|
||||||
|
. "$GLOBAL_CONFIG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 音量設定(設定ファイルで AFPLAY_VOLUME を 0.0〜1.0 で指定可能。)
|
||||||
|
AFPLAY_VOLUME="${AFPLAY_VOLUME:-1.0}"
|
||||||
|
|
||||||
|
# 引数チェック
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo "エラー: テキストを指定してください"
|
||||||
|
echo "使用方法: $0 \"読み上げたいテキスト\""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TEXT="$1"
|
||||||
|
SAVE_FILE="${2:-}" # 第2引数で出力ファイル名を指定可能(省略時は一時ファイル)
|
||||||
|
|
||||||
|
# 出力ファイルの設定
|
||||||
|
if [ -z "$SAVE_FILE" ]; then
|
||||||
|
# ファイル名が指定されていない場合は一時ファイルを使用(macOS対応)
|
||||||
|
OUTPUT_FILE=$(mktemp).wav
|
||||||
|
if [ $? -ne 0 ] || [ -z "$OUTPUT_FILE" ]; then
|
||||||
|
echo "エラー: 一時ファイルの作成に失敗しました"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
TEMP_FILE=true
|
||||||
|
else
|
||||||
|
OUTPUT_FILE="$SAVE_FILE"
|
||||||
|
TEMP_FILE=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 1. G2P処理でmoraToneListを取得
|
||||||
|
G2P_RESULT=$(curl -s -X POST "${API_BASE_URL}/api/g2p" \
|
||||||
|
-H "CF-Access-Client-Id: ${CF_ACCESS_CLIENT_ID}" \
|
||||||
|
-H "CF-Access-Client-Secret: ${CF_ACCESS_CLIENT_SECRET}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"text\": \"${TEXT}\"}")
|
||||||
|
|
||||||
|
# エラーチェック
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "エラー: G2P処理に失敗しました"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. 音声合成
|
||||||
|
SYNTHESIS_JSON=$(cat <<EOF
|
||||||
|
{
|
||||||
|
"model": "${MODEL_NAME}",
|
||||||
|
"modelFile": "${MODEL_FILE}",
|
||||||
|
"text": "${TEXT}",
|
||||||
|
"moraToneList": ${G2P_RESULT}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
# 音声合成リクエスト
|
||||||
|
HTTP_STATUS=$(curl -s -X POST "${API_BASE_URL}/api/synthesis" \
|
||||||
|
-H "CF-Access-Client-Id: ${CF_ACCESS_CLIENT_ID}" \
|
||||||
|
-H "CF-Access-Client-Secret: ${CF_ACCESS_CLIENT_SECRET}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Accept: audio/wav" \
|
||||||
|
-d "${SYNTHESIS_JSON}" \
|
||||||
|
--output "${OUTPUT_FILE}" \
|
||||||
|
-w "%{http_code}")
|
||||||
|
|
||||||
|
# HTTPステータスコードチェック
|
||||||
|
if [ -n "$HTTP_STATUS" ] && [ "$HTTP_STATUS" -eq 200 ]; then
|
||||||
|
if [ -f "${OUTPUT_FILE}" ]; then
|
||||||
|
if [ "$TEMP_FILE" = true ]; then
|
||||||
|
# 一時ファイルの場合は自動再生して削除
|
||||||
|
afplay -v "${AFPLAY_VOLUME}" "${OUTPUT_FILE}"
|
||||||
|
rm "${OUTPUT_FILE}"
|
||||||
|
else
|
||||||
|
# ファイル保存の場合
|
||||||
|
echo "ファイル: ${OUTPUT_FILE}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "エラー: 音声合成に失敗しました (HTTPステータス: ${HTTP_STATUS})"
|
||||||
|
if [ -f "${OUTPUT_FILE}" ]; then
|
||||||
|
echo "エラー内容:"
|
||||||
|
cat "${OUTPUT_FILE}"
|
||||||
|
rm "${OUTPUT_FILE}"
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
85
hooks/volume_manager.sh
Executable file
85
hooks/volume_manager.sh
Executable file
@@ -0,0 +1,85 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Takushi音量管理スクリプト
|
||||||
|
# 使用方法: ./volume_manager.sh [action] [args...]
|
||||||
|
# action: set, get, init
|
||||||
|
|
||||||
|
CONFIG_DIR="$HOME/.config/takushi_notifier"
|
||||||
|
CONFIG_FILE="$CONFIG_DIR/volume.conf"
|
||||||
|
DEFAULT_VOLUME=50
|
||||||
|
|
||||||
|
# 設定ディレクトリの作成
|
||||||
|
init_config() {
|
||||||
|
mkdir -p "$CONFIG_DIR"
|
||||||
|
if [ ! -f "$CONFIG_FILE" ]; then
|
||||||
|
echo "AFPLAY_VOLUME=0.5" > "$CONFIG_FILE"
|
||||||
|
echo "VOLUME_PERCENT=$DEFAULT_VOLUME" >> "$CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 音量設定(0-100を0.0-1.0に変換)
|
||||||
|
set_volume() {
|
||||||
|
local volume_percent="$1"
|
||||||
|
|
||||||
|
# 引数チェック
|
||||||
|
if ! [[ "$volume_percent" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "エラー: 音量は0-100の整数で指定してください"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$volume_percent" -lt 0 ] || [ "$volume_percent" -gt 100 ]; then
|
||||||
|
echo "エラー: 音量は0-100の範囲で指定してください"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 0-100を0.0-1.0に変換
|
||||||
|
local volume_float=$(echo "scale=2; $volume_percent / 100" | bc -l)
|
||||||
|
|
||||||
|
# 設定ファイルを更新
|
||||||
|
init_config
|
||||||
|
cat > "$CONFIG_FILE" << EOF
|
||||||
|
AFPLAY_VOLUME=$volume_float
|
||||||
|
VOLUME_PERCENT=$volume_percent
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Takushi音量を${volume_percent}%に設定しました (afplay: ${volume_float})"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 現在の音量取得
|
||||||
|
get_volume() {
|
||||||
|
init_config
|
||||||
|
if [ -f "$CONFIG_FILE" ]; then
|
||||||
|
source "$CONFIG_FILE"
|
||||||
|
echo "現在のTakushi音量: ${VOLUME_PERCENT}% (afplay: ${AFPLAY_VOLUME})"
|
||||||
|
else
|
||||||
|
echo "設定ファイルが見つかりません。初期化します..."
|
||||||
|
init_config
|
||||||
|
echo "現在のTakushi音量: ${DEFAULT_VOLUME}% (afplay: 0.5)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# メイン処理
|
||||||
|
case "${1:-get}" in
|
||||||
|
"set")
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
echo "エラー: 音量を指定してください"
|
||||||
|
echo "使用方法: $0 set [0-100]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
set_volume "$2"
|
||||||
|
;;
|
||||||
|
"get")
|
||||||
|
get_volume
|
||||||
|
;;
|
||||||
|
"init")
|
||||||
|
init_config
|
||||||
|
echo "設定ディレクトリを初期化しました: $CONFIG_DIR"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "使用方法: $0 [set|get|init] [volume]"
|
||||||
|
echo " set [0-100] : 音量を設定"
|
||||||
|
echo " get : 現在の音量を表示"
|
||||||
|
echo " init : 設定ディレクトリを初期化"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
77
plugin.lock.json
Normal file
77
plugin.lock.json
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||||
|
"pluginId": "gh:Baton8/TakushiNotifier:",
|
||||||
|
"normalized": {
|
||||||
|
"repo": null,
|
||||||
|
"ref": "refs/tags/v20251128.0",
|
||||||
|
"commit": "9d714c426edc813540942df2e77f080226ebfb55",
|
||||||
|
"treeHash": "eba7010f547c846e44250bc53c66282055258ed391d7fc3498aaa813d830b72b",
|
||||||
|
"generatedAt": "2025-11-28T10:09:57.127461Z",
|
||||||
|
"toolVersion": "publish_plugins.py@0.2.0"
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||||
|
"branch": "master",
|
||||||
|
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||||
|
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||||
|
},
|
||||||
|
"manifest": {
|
||||||
|
"name": "takushi-notifier",
|
||||||
|
"description": "Claude Assistantの応答を音声で読み上げるプラグイン(Style-Bert-VITS2対応)",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"sha256": "441e798aed35ed069950be361ffef7ed0759b81ad844e9e9a86001958ed43bfb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/tts_bert_vits.sh",
|
||||||
|
"sha256": "d7f0e178fdad527b359716c28db5fe78cf7425cd54f50062cefe6cbf3a05a3cc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/project_manager.sh",
|
||||||
|
"sha256": "388a6311af6cff1e8966f3357fe4689a70f6f1a81c2bc107ef0a550226b32f36"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/generate_message.sh",
|
||||||
|
"sha256": "2ca89bb4821c2f455d5dca411ae5bfd548dfe915e76f04fc9d49407e68ed6cb6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/hooks.json",
|
||||||
|
"sha256": "93cd760da216581490d8b2d0547fa2326a33a67149408d881db972638dec1039"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/volume_manager.sh",
|
||||||
|
"sha256": "32b85aa3eeff9a41aa225f50a699bf653df4564c54dabe87c04ee362b627e2e2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/notify.sh",
|
||||||
|
"sha256": "184d4f5bde3eee9f9ae9b9cc93471b39c4fa50f9161e8d3b6148e860d30a59af"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": ".claude-plugin/plugin.json",
|
||||||
|
"sha256": "83f1141f242789a8777158e2f722daad1e11a620511f549fa88c711c169e258a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/volume.md",
|
||||||
|
"sha256": "6e6c7ab3fae2fba204e59b6df855f8f81e02b3a741876d403a591496377cecde"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/project_name.md",
|
||||||
|
"sha256": "3812393341bb68ac23259a556787f7f6e7758fe73a8b8d1db80bb812fcf60ed6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/takushi-notification/SKILL.md",
|
||||||
|
"sha256": "65da5988c108770fffef0eb4ef6c3571c7a90766fdaa03be185a5757f3028ff6"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dirSha256": "eba7010f547c846e44250bc53c66282055258ed391d7fc3498aaa813d830b72b"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"scannedAt": null,
|
||||||
|
"scannerVersion": null,
|
||||||
|
"flags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
39
skills/takushi-notification/SKILL.md
Normal file
39
skills/takushi-notification/SKILL.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
description: "Takushi通知機能の設定と使用方法を提供するスキル"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Takushi通知スキル
|
||||||
|
|
||||||
|
このスキルは、Claude Assistantの応答を音声で読み上げる機能を提供します。
|
||||||
|
|
||||||
|
## 機能
|
||||||
|
|
||||||
|
- Assistantの応答を自動的に音声で読み上げ
|
||||||
|
- Style-Bert-VITS2を使用した高品質な音声合成
|
||||||
|
- メッセージの要約と動的生成
|
||||||
|
- 通知ログの管理
|
||||||
|
|
||||||
|
## 設定
|
||||||
|
|
||||||
|
### 音量設定
|
||||||
|
`/volume`コマンドで音量を調整できます:
|
||||||
|
```
|
||||||
|
/volume 50 # 50%の音量に設定
|
||||||
|
```
|
||||||
|
|
||||||
|
### API設定
|
||||||
|
`hooks/tts_bert_vits.sh`ファイル内で以下の設定を確認してください:
|
||||||
|
- CF_ACCESS_CLIENT_ID
|
||||||
|
- CF_ACCESS_CLIENT_SECRET
|
||||||
|
- API_BASE_URL
|
||||||
|
- MODEL_NAME
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
プラグインをインストールすると、Assistantの応答が自動的に音声で読み上げられます。
|
||||||
|
|
||||||
|
## トラブルシューティング
|
||||||
|
|
||||||
|
- 音声が再生されない場合は、macOSの音量設定を確認してください
|
||||||
|
- APIエラーが発生する場合は、認証情報を確認してください
|
||||||
|
- ログは`hooks/notify.log`に保存されます
|
||||||
Reference in New Issue
Block a user