TL;DR
Discord の絵文字リアクションを承認トリガーに、毎日の note 投稿を自動化するシステムを Python × Claude API で実装できます。所要時間は 1~2 時間。エンジニアでなくても指示を出せば Claude Code が基本構造を生成してくれます。
背景:なぜ「全自動」ではなく「人間承認フロー」か
毎日の note 投稿を完全自動化したいというニーズはよくあります。しかし、実装の観点から見ると「AI が完全に任せるのは品質リスク」という問題があります。
生成 AI は優秀ですが、毎日同じプロンプトで出力すると:
- トーンの微妙なぶれ
- ネタの重複・使い尽くし
- 業界トレンドの反映漏れ
こうしたズレが月に数度発生し、投稿後の修正・削除コストが発生します。
最適な運用は「AI が 80%やって、人間が 20%の確認」。毎朝 Discord で生成記事を目視し、絵文字(✅ or ❌)をポチするだけで、ブランド品質を保ちながら投稿を自動化できます。
システム全体設計
このシステムは 4 つのコンポーネントで構成されます。
[定時実行] 毎朝8時
↓
[1] トピック提案AI(過去記事を分析、テーマ3案を提示)
↓
[2] 本文執筆AI(選定テーマで記事本体を生成)
↓ Discord に投稿
[3] 人間の目視と絵文字承認(✅ で確定、❌ で下書き保存)
↓
[4] note 自動投稿 + エラー通知
各ステップは Python スクリプトと Discord API、note API で連携します。
実装手順
ステップ 1:環境セットアップ
必要な環境変数を .env に設定します。
# .env
DISCORD_BOT_TOKEN=your_bot_token_here
DISCORD_CHANNEL_ID=your_channel_id
NOTE_API_KEY=your_note_api_key
CLAUDE_API_KEY=your_claude_api_key
bot token は Discord Developer Portal から取得します。サーバー内で bot に「メッセージ送信」「リアクション読み取り」権限を付与してください。
ステップ 2:トピック提案スクリプト
毎朝、過去の note タイトルを分析してテーマ案を生成します。
import os
import csv
from datetime import datetime
from anthropic import Anthropic
def load_past_titles(csv_path: str) -> list[str]:
"""CSVから過去記事タイトルを読み込む"""
titles = []
with open(csv_path, 'r', encoding='utf-8') as f:
reader = csv.reader(f)
next(reader) # ヘッダースキップ
titles = [row[0] for row in reader]
return titles
def generate_topic_proposals(titles: list[str]) -> str:
"""Claude APIで今日のテーマ案を3つ生成"""
client = Anthropic()
past_titles_text = '\n'.join(f"- {t}" for t in titles[-20:])
message = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=500,
messages=[
{
"role": "user",
"content": f"""以下は過去20件のnote記事タイトルです。
{past_titles_text}
このテーマ群を踏まえて、今日のnote記事として提案できるテーマを3つ、順番に提示してください。
各テーマは1行で、端的に書いてください。重複のない、読者に有益なテーマを心がけてください。"""
}
]
)
return message.content[0].text
def post_to_discord(content: str):
"""Discord に投稿"""
import discord
from discord.ext import commands
bot = commands.Bot(command_prefix='!')
@bot.event
async def on_ready():
channel = bot.get_channel(int(os.getenv('DISCORD_CHANNEL_ID')))
await channel.send(f"📝 【今日のテーマ案】\n\n{content}")
await bot.close()
bot.run(os.getenv('DISCORD_BOT_TOKEN'))
if __name__ == '__main__':
titles = load_past_titles('past_notes.csv')
proposals = generate_topic_proposals(titles)
print(proposals)
post_to_discord(proposals)
ステップ 3:本文執筆スクリプト
Discord でトピック案に対してリアクション(例:📝)が付いたら、本体を生成します。
from anthropic import Anthropic
import json
def generate_article(topic: str, past_articles: list[dict]) -> str:
"""選定テーマで記事本文を生成"""
client = Anthropic()
# 過去記事の文体を学習
past_text = '\n---\n'.join(
f"タイトル: {a['title']}\n本文:\n{a['body'][:500]}..."
for a in past_articles[-5:]
)
message = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=2000,
messages=[
{
"role": "user",
"content": f"""以下は私の過去のnote記事のサンプルです。これらから文体・トーン・構成パターンを学んでください。
{past_text}
---
今日のテーマ: {topic}
このテーマで、1200~1500文字程度のnote記事本文を書いてください。
上記の過去記事と同じ文体・トーン・深さで、読者にとって有益で実践的な内容をお願いします。"""
}
]
)
return message.content[0].text
def save_article_for_approval(topic: str, body: str, message_id: str):
"""Discord 承認待ちの記事を JSON で保存"""
article = {
"message_id": message_id,
"topic": topic,
"body": body,
"status": "pending_approval",
"created_at": datetime.now().isoformat()
}
with open(f'pending_{message_id}.json', 'w', encoding='utf-8') as f:
json.dump(article, f, ensure_ascii=False, indent=2)
ステップ 4:承認検知と自動投稿
Discord の絵文字リアクション(✅)を監視し、note に自動投稿します。
import discord
from discord.ext import commands
import aiohttp
class ApprovalBot(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.Cog.listener()
async def on_reaction_add(self, reaction, user):
"""✅ リアクションを検知して自動投稿"""
if user.bot or str(reaction.emoji) != '✅':
return
# pending ファイルを検索
message_id = reaction.message.id
article_file = f'pending_{message_id}.json'
try:
with open(article_file, 'r', encoding='utf-8') as f:
article = json.load(f)
# note API で投稿
await post_to_note(article['topic'], article['body'])
# 投稿完了を Discord に報告
await reaction.message.channel.send(
f"✅ 投稿完了: {article['topic']}"
)
# pending ファイルを削除
os.remove(article_file)
except FileNotFoundError:
await reaction.message.channel.send(
"❌ 承認対象の記事が見つかりません"
)
async def post_to_note(title: str, body: str):
"""note API で投稿"""
headers = {
"Authorization": f"Bearer {os.getenv('NOTE_API_KEY')}",
"Content-Type": "application/json"
}
payload = {
"title": title,
"body": body,
"published": True
}
async with aiohttp.ClientSession() as session:
async with session.post(
"https://note.com/api/v2/notes",
json=payload,
headers=headers
) as resp:
if resp.status != 201:
raise Exception(f"note API error: {resp.status}")
ステップ 5:エラー通知
各ステップで例外が発生したら、自動で通知します。
async def send_error_notification(error_type: str, detail: str):
"""#エラー通知 チャンネルにエラーをレポート"""
error_channel = bot.get_channel(int(os.getenv('ERROR_CHANNEL_ID')))
await error_channel.send(
f"⚠️ エラー発生\n"
f"**種類**: {error_type}\n"
f"**詳細**: {detail}\n"
f"**時刻**: {datetime.now().strftime('%H:%M:%S')}"
)
# 各スクリプトで try-except でラップ
try:
proposals = generate_topic_proposals(titles)
post_to_discord(proposals)
except Exception as e:
send_error_notification("トピック提案エラー", str(e))
つまづきやすいポイントと対処法
絵文字リアクション検知が失敗する
原因: emoji の Unicode や Discord のキャッシュ問題。
対処:
# リアクション検知をデバッグ
@commands.Cog.listener()
async def on_reaction_add(self, reaction, user):
print(f"リアクション: {reaction.emoji} (タイプ: {type(reaction.emoji)})")
print(f"比較: {str(reaction.emoji)} == ✅ ? {str(reaction.emoji) == '✅'}")
print() で実際に来ているリアクションを確認し、条件式に合わせてください。
note API の認証エラー
原因: トークンの有効期限切れ、スコープ不足。
対処: note API ドキュメントで「投稿作成」のスコープが含まれているか確認。トークン再発行も検討してください。
スケジュール実行されない
原因: ローカル環境でのスクリプト実行は、PC シャットダウンで停止。
対処: GitHub Actions、AWS Lambda、Google Cloud Functions などのサーバーレス環境で「毎朝 8 時に実行」を設定します。
# .github/workflows/schedule.yml
name: Daily Topic Proposal
on:
schedule:
- cron: '0 8 * * *' # 毎日 8:00 UTC
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run topic proposal
env:
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
CLAUDE_API_KEY: ${{ secrets.CLAUDE_API_KEY }}
run: python scripts/daily_topic.py
まとめ
Discord と Claude API を組み合わせることで、非エンジニアでも段階的に自動化システムを構築できます。
- トピック提案:過去記事の分析で毎日のネタ出しを自動化
- 本文生成:文体を学習した AI が記事を作成
- 人間承認:絵文字ポチで品質を保証
- 自動投稿:note API で確定内容を投稿
最初は「Discord に記事を投稿する」だけで始めて、安定してから「自動投稿」に進める段階的なアプローチが失敗を減らします。
さらに詳しい実装手順は note で公開中
この記事では実装の要点のみ紹介しました。完全なスクリプト・プロンプト全文・運用ノウハウは以下の note で公開しています。