業務自動化で脱・手作業!一人事務のDX活用術 | RPA・自動化ツール

業務自動化で脱・手作業!一人事務のDX活用ブログ|RPA・自動化ツールで業務をもっとラクに、もっとスマートに

Slackのネガティブ発言を自動検知して上司に通知する方法【ChatGPT×GASで簡単導入】

Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

Slackなどのビジネスチャットツールを日常業務に活用している企業も多いと思います。
気軽に情報共有できる便利な反面、「感情の見えにくさ」や「誤爆のリスク」に悩まされるケースも少なくありません。

たとえば

  • お客様や取引先からの不満がSlack上に投稿されていたが、上司が気づくのが遅れた

  • 社内のメンバーが、静かな怒りやストレスを投稿していたが、気づかないまま放置されていた

  • 社内の愚痴やネガティブな発言を、うっかり取引先チャットに誤爆してしまった

実際、私自身も取引先の部下がSlack上で上層部への不満を投稿していたにも関わらず、上層部がしばらく気が付いていなかったという場面に立ち会ったことがあります。

投稿は全社に筒抜けの状態だったにも関わらず、誰も指摘せずスルーされていたことに驚くと同時に、「Slack上の空気」は意外と見落とされやすいものなのだと痛感しました。このように、Slackは便利である一方で、こうしたリスク管理の穴になりがちな側面もあるのです。


ChatGPTとGASで、Slackの“空気”を見える化

そこで今回は、ChatGPT APIGoogle Apps Script(GAS)を活用して、Slack上の発言を感情分析し、ネガティブ度が高ければメールで通知する仕組みを構築してみました。

実際のログ分析結果を見てみましょう。


発言例①(丁寧だけど心の中は…)

Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

▼メールでの通知内容

Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

このように、文面は丁寧でも「退職も考えています」というキーワードがAIによって適切に評価され、上司に通知されます。


発言例②(ストレートな怒り)

ユーザー:うざ。ふざけんなよ。

Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

こちらはストレートな怒りの発露。このレベルの内容であれば誤爆の可能性の方が高そうですが、ネガティブ度:9、不適切・攻撃性あり と分析され、即時通知が送信されました。


発言例③(会話の流れの中で怒りを検知)

Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

1つ前の「再考いただければ~」までは未通知、見積もりの内容について不満や不安があることは伝わっているものの、この段階ではネガティブ度は6となり、ギリギリ未通知。

追随の「おかしいですよね?」の内容について通知がきています。

Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

取引先が静かに怒っていることをすぐに察知でき、対策を講じることができます。


導入方法は?

Slackから取得した発言をGASで読み込み、ChatGPT APIに感情分析を依頼、
ネガティブ度が高ければメールで通知、というシンプルな流れです。

🔧 必要な準備

  1. Slack API  でAppを作成

    Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

    Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

    Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

    Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

  2. サイドバーのOAuth & Permissions から以下のスコープを設定:
    channels:history(パブリックチャンネル)
    groups:history(プライベートチャンネル)
    im:history(DMの履歴)
    channels:read(チャンネル情報)
    users:read(ユーザー名取得)

    Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

  3.  Botを作成

    Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】


    Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

  4. Bot Tokenを取得

    Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

  5. ChatGPT API Keyを取得

    keiridx.net

  6. Google Apps Script(GAS)にコードを記述 ※当ブログの一番下に記載しています。

  7. トリガーで定期実行!

    keiridx.net


実際どう使う?

人事部・総務部で従業員のメンタルヘルスケアの一環として導入したり、
プロジェクト単位で「Slackの空気が荒れていないか」を可視化するダッシュボードと連携したり、様々な場面で活用可能です。

「何も起こらない」が一番ですが、“もしも”に気づける体制があるだけで、組織の安心感はグッと高まります。


まとめ:Slackの“感情”にもセンサーを

Slackは、便利さとリスクが背中合わせのツールです。
ChatGPTとGASを活用すれば、そうした見えにくい“感情の揺らぎ”を可視化し、
早期対応につなげることが可能になります。

「AIによるネガティブ検知」は、組織の安全管理にもつながる第一歩。
ぜひ一度、実験的にでも導入してみてはいかがでしょうか。

【関連リンク】

▼人事評価AIで新入社員の離職率を下げる方法

keiridx.net

GoogleドライブとSlack連携でファイル通知を自動化

keiridx.net

▼GASとChatGPTの連携でさらなるカスタマイズをしたい方はこちらの書籍もおすすめです。

Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

Google Apps Script × ChatGPTのツボとコツがゼッタイにわかる本

新品価格
¥1,960から
(2025/4/5 11:45時点)

▼ 役に立ったらブックマークお願いします!

Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】

Slackのネガティブ発言を感情分析で自動検知して上司に通知する方法【ChatGPT×Google Apps script(GAS)で簡単導入】
人気ブログランキング

 

<GAS Code>

const SLACK_TOKEN = "****************************"; // ← Slack botトーク
const CHANNEL_ID = "*************"; // ← チャンネルID
const OPENAI_API_KEY = "**************"; // ← chatGPT API
const RECIPIENT_EMAIL = "(ここにあなたのメールアドレス)";

function getSlackMessagesWithReplies() {
  const now = new Date();
  const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
  const oldest = Math.floor(yesterday.getTime() / 1000);
  const latest = Math.floor(now.getTime() / 1000);

  const url = `https://slack.com/api/conversations.history?channel=${CHANNEL_ID}&oldest=${oldest}&latest=${latest}&limit=100`;
  const options = {
    method: "get",
    headers: {
      Authorization: `Bearer ${SLACK_TOKEN}`,
    },
    muteHttpExceptions: true,
  };

  const response = UrlFetchApp.fetch(url, options);
  const json = JSON.parse(response.getContentText());

  if (!json.ok) {
    Logger.log("Slack APIエラー: " + json.error);
    return ;
  }

  const messagesWithReplies = ;

  json.messages.forEach(msg => {
    messagesWithReplies.push(msg);
    if (msg.thread_ts && msg.thread_ts === msg.ts) {
      const replies = getThreadReplies(msg.thread_ts);
      messagesWithReplies.push(...replies);
    }
  });

  return messagesWithReplies;
}

function getThreadReplies(threadTs) {
  const url = `https://slack.com/api/conversations.replies?channel=${CHANNEL_ID}&ts=${threadTs}`;
  const options = {
    method: "get",
    headers: {
      Authorization: `Bearer ${SLACK_TOKEN}`
    }
  };
  const response = UrlFetchApp.fetch(url, options);
  const json = JSON.parse(response.getContentText());

  if (json.ok) {
    return json.messages.slice(1); // 親メッセージを除外
  } else {
    Logger.log("返信の取得に失敗: " + json.error);
    return [];
  }
}

function getUserName(userId) {
  const url = `https://slack.com/api/users.info?user=${userId}`;
  const options = {
    method: "get",
    headers: {
      Authorization: `Bearer ${SLACK_TOKEN}`
    }
  };
  const response = UrlFetchApp.fetch(url, options);
  const json = JSON.parse(response.getContentText());

  Logger.log(`ユーザーID: ${userId}`);
  Logger.log(`ユーザー情報: ${JSON.stringify(json)}`);

  if (json.ok) {
    return json.user.real_name || json.user.name;
  } else {
    return userId;
  }
}

function analyzeSlackMessages() {
  const messages = getSlackMessagesWithReplies();
  if (!messages || messages.length === 0) {
    Logger.log("投稿がありません");
    return;
  }

  messages.forEach*1 {

      MailApp.sendEmail(RECIPIENT_EMAIL, "⚠ ネガティブ投稿を検知しました", ...);
        `⚠ ネガティブ投稿を検知しました!\n\n投稿者:${userName}\n時刻 :${ts}\n内容 :「${text}」\n\n分析結果:\n${result}`);
    }
  });
}

function callChatGPT(prompt) {
  const payload = {
    model: "gpt-4o",
    messages: [
      { role: "system", content: "あなたはビジネスチャットの感情分析を行う専門AIです。" },
      { role: "user", content: prompt }
    ],
    temperature: 0.4,
    max_tokens: 300
  };

  const options = {
    method: "post",
    headers: {
      Authorization: `Bearer ${OPENAI_API_KEY}`,
      "Content-Type": "application/json"
    },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };

  const response = UrlFetchApp.fetch(url, options);
  const json = JSON.parse(response.getContentText());

  if (json.choices && json.choices.length > 0) {
    return json.choices[0].message.content.trim();
  } else {
    return "分析できませんでした。";
  }
}

*1:msg, index) => {

    const text = msg.text;
    const userId = msg.user || "BOT";
    const userName = getUserName(userId);
    const ts = new Date(parseFloat(msg.ts) * 1000).toLocaleString("ja-JP");

    const prompt = `以下のSlack発言に含まれる感情を分析してください。\n\n発言:「${text}」\n\n1. ネガティブ度(10段階)\n2. 怒り・ストレス・苛立ちの兆候(ある・ない)\n3. 言葉づかいに不適切・失礼・攻撃性があるか(ある・ない)\n4. 投稿者の感情状態について一言アドバイス`;

    const result = callChatGPT(prompt);
    Logger.log(`【${index + 1}${userName}${ts})\n${text}\n>>> 分析結果:\n${result}\n---`);

    if (result.includes("ネガティブ度(10段階):7") ||
        result.includes("ネガティブ度(10段階):8") ||
        result.includes("ネガティブ度(10段階):9") ||
        result.includes("ネガティブ度(10段階):10"