結論から言うと、GASとスプレッドシートを使えば、サーバー代完全無料で「特定の言葉にだけ反応するBot」は作れます。 「おはよう」には挨拶を、「推しの名前」には尊い語りを。あなたの会話に合わせて成長するBotを、コピペだけで実装してみましょう。
そもそも、どうやって「言葉」を判断しているの?
Bot作りで一番楽しいのが、言葉の「判定ロジック」です。今回はスプレッドシートを使って、以下の2つのパターンを使い分けられる高機能なBotを作ります。
| 判定モード | 仕組み (プログラム) | 特徴 | 使用例 |
| 完全一致 | === (イコール) | 一言一句合っていないと反応しない | 合言葉、コマンド、パスワード |
| 部分一致 | includes (含む) | 文中にキーワードが含まれていれば反応する | 会話、挨拶、推し語り |
例えばキーワードが**「犬」**の場合:
- 完全一致: 「犬」→ ⭕️反応 / 「犬が好き」→ ❌無視
- 部分一致: 「犬」→ ⭕️反応 / 「犬が好き」→ ⭕️反応
これを使い分けることで、「会話に自然に割り込むBot」や「特定のコマンドだけ聞くBot」を自由に作れます。
ステップ1:スプレッドシートを「Botの脳(辞書)」にする
まずはBotが覚える言葉のリストを作ります。コードを書き換えるのではなく、シートに行を追加するだけで言葉を増やせるのが最大のメリットです。
- Googleスプレッドシートを新規作成します。
- シート名(画面下のタブ)を「Dictionary」に変更します。
- 1行目に見出しを作り、2行目以降にデータを入力します。
【シートの入力例】
| A列 (Keyword) | B列 (Response) | C列 (Mode) | |
| 1 | 言葉 | 返信 | モード |
| 2 | おはよう | おはようございます! | exact |
| 3 | 猫 | ニャー🐱 | exact |
| 4 | ラーメン | 今日のご飯はラーメンですか? | partial |
- exact: 完全一致させたい時に入力
- partial: 部分一致(〜を含む)させたい時に入力(空欄でもOK)
ステップ2:GASで「定期見回りシステム」を作る
GASは通常、自分から動くことができません。そこで**「1分に1回、Discordを見に行く」**という仕組み(ポーリング)を作ります。
- スプレッドシートのメニューから [拡張機能] → [Apps Script] を開きます。
- エディタのコードを全て消して、以下のコードを丸ごとコピペしてください。
- コード上部の
DISCORD_TOKENとCHANNEL_IDを自分のものに書き換えます。
※注意: Bot Tokenの取得方法やDeveloper Portalでの設定(Message Content IntentをONにする等)は、Bot作成の基本手順通りに行っておいてください。
【コピペ用】特定の単語反応Bot 全コード
JavaScript
/**
* 特定の単語に反応するDiscord Bot (GAS版)
* * 機能:
* 1. Discordの特定チャンネルのメッセージを定期的に取得
* 2. スプレッドシートの「辞書」と照らし合わせる
* 3. マッチしたら返信する
*/
// --- 設定エリア ---
// ※本来はスクリプトプロパティ推奨ですが、初心者向けに直接記述式にしています
const DISCORD_TOKEN = 'ここにBotトークンを貼り付け';
const CHANNEL_ID = 'ここにチャンネルIDを貼り付け';
const SHEET_NAME = 'Dictionary';
/**
* メイン関数 (これをトリガーで1分ごとに実行)
*/
function main() {
// 1. メッセージを取得
const messages = fetchMessages();
if (!messages || messages.length === 0) return;
// 2. 辞書データを取得
const dictionary = getDictionary();
// 3. 処理済みチェック用のキャッシュ
const cache = CacheService.getScriptCache();
// 新しいメッセージから順にチェック
for (const msg of messages) {
// Bot自身の発言は無視(無限ループ防止)
if (msg.author.bot) continue;
// 既に返信済みなら無視(キャッシュ確認)
if (cache.get(msg.id)) continue;
const content = msg.content;
let replyText = null;
// 辞書と照合
for (const row of dictionary) {
const keyword = row.keyword;
const response = row.response;
const mode = row.mode; // 'exact' か 'partial'
if (mode === 'exact') {
// 完全一致判定 (前後の空白は無視)
if (content.trim() === keyword) {
replyText = response;
break; // マッチしたらループを抜ける
}
} else {
// 部分一致判定
if (content.includes(keyword)) {
replyText = response;
break;
}
}
}
// 返信対象が見つかった場合
if (replyText) {
sendDiscordMessage(replyText, msg.id); // メンション付きで返信
// 二重返信防止のためキャッシュに保存 (有効期限10分)
cache.put(msg.id, 'done', 600);
// 1回の実行で1件返信したら終了する(スパム防止)
break;
}
}
}
/**
* スプレッドシートから辞書データを取得
*/
function getDictionary() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);
if (!sheet || sheet.getLastRow() < 2) return [];
// A列:キーワード, B列:返信, C列:モード
const data = sheet.getRange(2, 1, sheet.getLastRow() - 1, 3).getValues();
return data.map(row => ({
keyword: row[0].toString(),
response: row[1].toString(),
mode: row[2].toString().toLowerCase() || 'partial'
})).filter(item => item.keyword !== '');
}
/**
* Discord API: メッセージ取得
*/
function fetchMessages() {
const url = `https://discord.com/api/v10/channels/${CHANNEL_ID}/messages?limit=10`;
const options = {
method: 'get',
headers: { 'Authorization': `Bot ${DISCORD_TOKEN}` },
muteHttpExceptions: true
};
try {
const res = UrlFetchApp.fetch(url, options);
if (res.getResponseCode() === 200) {
return JSON.parse(res.getContentText());
}
} catch (e) {
console.error('メッセージ取得失敗:', e);
}
return [];
}
/**
* Discord API: メッセージ送信 (Reply形式)
*/
function sendDiscordMessage(text, replyMessageId) {
const url = `https://discord.com/api/v10/channels/${CHANNEL_ID}/messages`;
const payload = {
content: text,
message_reference: { message_id: replyMessageId }
};
const options = {
method: 'post',
headers: {
'Authorization': `Bot ${DISCORD_TOKEN}`,
'Content-Type': 'application/json'
},
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
try {
UrlFetchApp.fetch(url, options);
console.log(`返信しました: ${text}`);
} catch (e) {
console.error(`送信エラー: ${e.toString()}`);
}
}
ステップ3:自動実行(トリガー)のセット
最後に「1分ごとに見回りに行く」設定をします。
- 左メニューの [トリガー] (時計アイコン) をクリック。
- 右下の [トリガーを追加] をクリック。
- 以下のように設定して保存します。
- 実行する関数:
main - イベントのソース: 時間主導型
- 時間ベースのトリガーのタイプ: 分ベースのタイマー
- 間隔: 1分おき
- 実行する関数:
これで完了です!Discordで辞書に登録した言葉を呟いてみましょう。Botが巡回してきたタイミング(最大1分後)に返信が来ます。
トラブルシューティング(動かない時は?)
Q. Botが反応しません(エラーも出ない)。
A. 「Message Content Intent」 がOFFになっていませんか?
Developer Portalの「Bot」ページにあるこのスイッチをONにしないと、Botはメッセージの中身が空っぽに見えてしまい、反応できません。
Q. 「自分(Bot)」の発言にまた反応して無限ループします。
A. コード内の if (msg.author.bot) continue; という行がその防止策です。この行を消さないように注意してください。
Q. 少し反応が遅いです。
A. GASのトリガー実行は「1分に1回」なので、タイミングによっては最大1分のラグがあります。これは「サーバー代無料」の対価として、のんびり待ちましょう。