Last active
May 1, 2025 08:45
-
-
Save knishioka/43fcd9bc840499e46e6dcd117c07aaeb to your computer and use it in GitHub Desktop.
自然言語でのタスク入力をパースし、Claude 3.7 Sonnet APIを使用してタスクの詳細(サマリー、説明、期限)を分析・抽出した後、適切なプロパティを持つNotion databaseに新しいエントリを作成するAlfred workflowスクリプト。完了時には通知と効果音も含まれています。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# 今日の日付を取得 | |
TODAY=$(date +"%Y-%m-%d") | |
# タスク内容 | |
TASK_DESCRIPTION="{query}" | |
# システムメッセージを変数として定義 | |
SYSTEM_MESSAGE='あなたはタスク分析の専門家です。 | |
ユーザーが送信したタスクから以下の情報を抽出し、構造化されたJSONとして返してください: | |
1. タスクの要約 | |
2. 実行すべきアクションの説明 | |
3. 期限 | |
期限は「due_date」フィールドとしてISO形式(YYYY-MM-DD)で返してください。 | |
タスク内に相対的な日付表現(例:「3日後」「来週の金曜日」)がある場合は、 | |
ユーザーが提供した現在の日付を基準として計算してください。 | |
期限が明示されていない場合は、due_dateフィールドを空の文字列("")と設定してください。' | |
# リクエストデータをファイルとして作成 | |
ANTHROPIC_REQUEST_FILE=/tmp/alfred-wf_anthropic-request.json | |
cat > $ANTHROPIC_REQUEST_FILE << EOF | |
{ | |
"model": "claude-3-7-sonnet-20250219", | |
"max_tokens": 2048, | |
"messages": [ | |
{ | |
"role": "user", | |
"content": "今日の日付は${TODAY}です。以下のタスクから、タスクのサマリー、必要なアクション、期限を抽出してください。タスク:${TASK_DESCRIPTION}" | |
} | |
], | |
"system": $(jq -Rs . <<< "${SYSTEM_MESSAGE}"), | |
"tools": [ | |
{ | |
"name": "task_analyzer", | |
"description": "タスクを分析し、サマリー、アクションの説明、期限を抽出する", | |
"input_schema": { | |
"type": "object", | |
"properties": { | |
"summary": { | |
"type": "string", | |
"description": "タスクの簡潔な要約" | |
}, | |
"description": { | |
"type": "string", | |
"description": "タスクを完了するために必要なアクションの詳細説明" | |
}, | |
"due_date": { | |
"type": "string", | |
"description": "タスクの期限をISO形式(YYYY-MM-DD)で表示。期限が未指定の場合は今日の日付に合わせる" | |
} | |
}, | |
"required": ["summary", "description", "due_date"] | |
} | |
} | |
] | |
} | |
EOF | |
# 作成したJSONファイルの内容を確認(デバッグ用) | |
echo "送信するJSONデータ:" >&2 | |
cat $ANTHROPIC_REQUEST_FILE >&2 | |
CLAUDE_RESPONSE=/tmp/alfred-wf_anthropic-response.json | |
# Claudeがタスク内容を生成 | |
curl -s https://api.anthropic.com/v1/messages \ | |
-H "x-api-key: $ANTHROPIC_API_KEY" \ | |
-H "anthropic-version: 2023-06-01" \ | |
-H "content-type: application/json" \ | |
-d @$ANTHROPIC_REQUEST_FILE > $CLAUDE_RESPONSE | |
# エラーチェック関数 | |
check_error() { | |
local response_file="$1" | |
# ファイルからレスポンスを読み込む | |
local response=$(cat "$response_file") | |
# オーバーロードエラーの検出 | |
if [[ "$response" == *"overloaded_error"* ]]; then | |
terminal-notifier -title "API エラー" -message "サーバーが過負荷状態です。後で再試行してください。" -sound default | |
echo "エラー: サーバーが過負荷状態です。後で再試行してください。" >&2 | |
exit 1 | |
fi | |
# その他のエラー検出 | |
if [[ "$response" == *"\"error\":"* ]]; then | |
error_message=$(echo "$response" | grep -o '"message":"[^"]*"' | cut -d'"' -f4) | |
terminal-notifier -title "API エラー" -message "エラーが発生しました: $error_message" -sound default | |
echo "エラー: $error_message" >&2 | |
exit 1 | |
fi | |
} | |
# レスポンスからエラーをチェック | |
check_error $CLAUDE_RESPONSE >&2 | |
# レスポンス全体を表示(デバッグ用) | |
echo "APIレスポンス:" >&2 | |
cat $CLAUDE_RESPONSE >&2 | |
# jqを使ってレスポンスから必要な情報を抽出 | |
SUMMARY=$(cat $CLAUDE_RESPONSE | jq -r '.content[] | select(.type=="tool_use").input.summary') | |
DESCRIPTION=$(cat $CLAUDE_RESPONSE | jq -r '.content[] | select(.type=="tool_use").input.description') | |
# 期限が空または取得できなかった場合は本日の日付で埋める | |
DUE_DATE=$(cat $CLAUDE_RESPONSE | jq -r '.content[] | select(.type=="tool_use").input.due_date') | |
if [ -z "$DUE_DATE" ] || [ "$DUE_DATE" = "取得失敗" ]; then | |
DUE_DATE="$TODAY" | |
echo "期限が特定できなかったため、本日の日付($TODAY)を設定しました。" >&2 | |
fi | |
# 結果を表示 | |
echo "サマリー: $SUMMARY" >&2 | |
echo "説明: $DESCRIPTION" >&2 | |
echo "期限: $DUE_DATE" >&2 | |
# 最終的な結果をJSONとして出力 | |
JSON_RESULT=$(cat <<EOF | |
{ | |
"summary": "$SUMMARY", | |
"description": "$DESCRIPTION", | |
"due_date": "$DUE_DATE" | |
} | |
EOF | |
) | |
echo "最終結果(JSON):" >&2 | |
echo "$JSON_RESULT" | jq . >&2 | |
# notionにタスクを登録 | |
NOTION_RESPONSE=/tmp/alfred-wf_notion-response.json | |
NOTION_REQUEST_FILE=/tmp/alfred-wf_notion-request.json | |
cat > $NOTION_REQUEST_FILE << EOF | |
{ | |
"parent": { | |
"database_id": "${DATABASE_ID}" | |
}, | |
"properties": { | |
"Name": { | |
"title": [ | |
{ | |
"text": { | |
"content": "${SUMMARY}" | |
} | |
} | |
] | |
}, | |
"Due Date": { | |
"type": "date", | |
"date": { | |
"start": "${DUE_DATE}" | |
} | |
}, | |
"Priority": { | |
"type": "select", | |
"select": { | |
"name": "Middle" | |
} | |
} | |
}, | |
"children": [ | |
{ | |
"object": "block", | |
"type": "paragraph", | |
"paragraph": { | |
"rich_text": [ | |
{ | |
"type": "text", | |
"text": { | |
"content": "${DESCRIPTION}" | |
} | |
} | |
] | |
} | |
} | |
] | |
} | |
EOF | |
curl -s -X POST "https://api.notion.com/v1/pages" \ | |
-H "Authorization: Bearer ${NOTION_TOKEN}" \ | |
-H 'Content-Type: application/json' \ | |
-H 'Notion-Version: 2022-06-28' \ | |
-d @$NOTION_REQUEST_FILE > $NOTION_RESPONSE 2>/tmp/notion_debug.log | |
# NotionのページIDを取得 | |
PAGE_ID=$(cat $NOTION_RESPONSE | jq -r '.id') | |
# NotionのページURLを作成 | |
NOTION_URL="notion://www.notion.so/${PAGE_ID//-/}" | |
# terminal-notifierで通知 | |
terminal-notifier -title "Notion Task追加" -subtitle "$SUMMARY" -message "\[期限: $DUE_DATE] ${DESCRIPTION}" -open "$NOTION_URL" -sound "Glass" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment