その他

【Slack Bot】議事録や日報を「見る」から「聞く」へ! Slack Radio bot

その他
この記事は約15分で読めます。

はじめに

みなさんこんにちは。突然ですが、NotebookLMのStudio機能、使ってますか!?

Sign in - Google Accounts

この機能では、与えられたテキストやURLのソース全体を解析して、ラジオのような対話形式の音声でまとめていることについて解説をしてくれるというものです。初めて触った時は、AIでここまでできるの、すごいなと感じました。

でも、そこでこう感じたんです。社内で使っている連絡ツール(Slackやteamsなど)で、昨日の情報をラジオのようにまとめてくれたら便利じゃね!?って。会議やチャットで会話された出来事を、探しながら読むのではなく、まとめて音声ファイルにしてくれたら便利だなと感じたわけです。

そこで今回は、Slack上でそのようなツールを作ってみた!という内容になります。

今回の設計

今回の設計イメージです。

まず、Slack上では、テキストデータを引っ張ってくることと作成したラジオデータを投稿できるようにする必要があります。そこでは、Slack APIを使うことで、問題なさそうです。

Unlock your productivity potential with Slack Platform
Connect, simplify, and automate work.

続いて、引っ張ってきたテキストデータをラジオ風に要約する必要があります。そこでは、OpenAI APIで要約してもらうことにしましょう。

Just a moment...

テキストデータは、要約するだけでなく音声化(ラジオ風に仕上げる)必要があります。そこでは、今回はgTTS(Google Text-to-Speech)というGoogleの無料ツールを使いました。
作ってみて感じたことは、音声化する時はここにどれだけこだわるかで、クオリティが大きく変わってきます。つまり、お金をかければかけるほど、NotebookLMのような流暢なラジオが出来上がるわけですね。今回はお試しでの制作なので、無料で使用できるツールを使用しました。

Client Challenge

パーツごとに作ってみる

Slack API(Slack周りの作成)

まずは、Slack APIに登録をしていきます。

画面にアクセスして、左上のメニューバーにあるYour appsをクリックしましょう。

Your Appsの設定画面が出てきます。右上のCreate New Appをクリックしましょう。
(私の場合はすでに作ったものがあるので、作ったエージェントが表示されていますが、お気になさらず・・・。)

Create an app の画面が表示されるので、From scratchを選びます。

Name app & choose workspaceの画面が開きますので、それぞれ入力していきましょう。
App Nameには作りたいアプリの名前を入力しましょう。今回はradio-botとしました。Pick a workspace to develop your app in: には、アプリを追加するワークスペースを選びましょう。開発用のワークスペースがあるのであれば、そこで準備するのが一番いいです。入力が終わったら、右下のCreate App をクリックしましょう。

すると、Appが作成され、以下のような画面が表示されると思います。
左のバーで、Features > OAuth & Permissionsを選んでください。appの権限設定ができます。

OAuth & Permissionsの画面で下へスクロールしていくと、Scopesという項目があると思います。

ここで、Add an OAuth Scope から、botのできることを追加していきます。追加するスコープは、下の表の内容の通りです。

Scope 名用途
channels:historyパブリックチャンネルのメッセージを読み取る(投稿取得)
chat:writeBotがメッセージや投稿を送信する(要約投稿など)
files:write音声ファイルなどのファイルをSlackにアップロードする
channels:readチャンネルのメタ情報を取得(名前・IDなど)
users:read投稿者の名前などを表示するためのユーザー情報取得(任意)

以下の項目は、みなさんの作りたい環境に応じて追加してください。特に、プライベートチャンネルやDMの情報もラジオ化したい!という人には必要なScopesです。なくても作ることができます。

Scope 名用途
groups:historyプライベートチャンネルの履歴取得(プライベート対象の場合)
groups:readプライベートチャンネル情報の取得
mpim:historyマルチユーザーDMの履歴取得(特殊用途)
im:history通常DMの履歴取得

追加し終わりましたら、上の方へ戻ってOAuth Tokens から Install to [チャンネル名] のボタンをクリックしましょう。これを押し忘れると、いままでの作業が無駄になります・・・。
(私はすでに作成しているので少し表示が違いますが、クリックするとこのようになるはずです。)

すると、Tokenが発行されるはずです。そのうち、今回使うのは Bot User OAuth Token の方です。xoxb-から始まるTokenをコピーしてください。これでSlackAPIの準備はOKです!

コピーしたTokenは.envファイルなどに以下のように保存しておきましょう。また、ちょっと話はずれますが、今後のためにチャンネルIDも取得しておきましょう。チャンネルIDはチャンネルのURLを見るとわかります。

SLACK_BOT_TOKEN=xoxb-000・・・  # Bot User OAuth Token
CHANNEL_ID=CXXXX・・・       # チャンネルID

チャンネルIDは、チャンネルURL最後のCから始まる英数字
https://app.slack.com/client/T0000000000/C00000000000

Slackからテキストデータを引っ張ってくる

続いて、Slackのチャンネルからテキストデータを引っ張ってくることをします。
まずはお試しで、簡単なプログラムを使って最新のテキスト5件分を引っ張ってくるプログラムを作って実行してみましょう。以下のPythonのプログラムを使います。

import os
import requests
from dotenv import load_dotenv

load_dotenv()
SLACK_BOT_TOKEN = os.getenv("SLACK_BOT_TOKEN")
CHANNEL_ID = os.getenv("CHANNEL_ID")

url = "https://slack.com/api/conversations.history"
headers = {
    "Authorization": f"Bearer {SLACK_BOT_TOKEN}"
}
params = {
    "channel": CHANNEL_ID,
    "limit": 5  # 最新5件だけ取得
}

response = requests.get(url, headers=headers, params=params)
data = response.json()

for message in data.get("messages", []):
    print(f"[{message.get('ts')}] {message.get('text')}")

これを実行させると、画像のように最新の投稿を拾ってきます。Slackのチャンネルの様子も載せていますが、ちゃんと拾ってくることができていますね!
(私は実験で適当に投稿したメッセージやラジオ風にまとめた音声ファイルの投稿などが拾われました。)

上手く動作できているようです。それでは、今度は今日投稿されたテキストデータを全て引っ張ってくるプログラムを作ってみましょう。昨日投稿されたデータでもいいのですが、今日この記事を見て準備をしている人は、テストチャンネルには昨日の投稿などありませんからね・・・。

import os
from dotenv import load_dotenv
import requests
from datetime import datetime, timedelta, timezone

load_dotenv()
SLACK_BOT_TOKEN = os.getenv("SLACK_BOT_TOKEN")
CHANNEL_ID = os.getenv("CHANNEL_ID")

JST = timezone(timedelta(hours=9))
now = datetime.now(JST)

start_ts = now.replace(hour=0, minute=0, second=0, microsecond=0).timestamp()
end_ts = now.replace(hour=23, minute=59, second=59, microsecond=0).timestamp()

headers = {
    "Authorization": f"Bearer {SLACK_BOT_TOKEN}"
}

params = {
    "channel": CHANNEL_ID,
    "oldest": str(start_ts),
    "latest": str(end_ts),
    "inclusive": True,
    "limit": 100
}

response = requests.get("https://slack.com/api/conversations.history", headers=headers, params=params)
data = response.json()

print("API Response:", data)

if data.get("ok") and data.get("messages"):
    for msg in data["messages"]:
        print("📝 投稿:", msg.get("text"))
else:
    print("⚠️ メッセージが取得できませんでした。エラー内容:", data.get("error"))

これを実行してみると、画像のように、本日投稿されたSlackの内容が全て取得することができました。問題なく動作しているようです。chatGPTに適当に生成してもらったおにぎり制作プロジェクトの内容が全て取得されていますね笑

テキストを要約化

さて、次は引っ張ってきたテキストを要約して音声化します。

要約においては、AIの力を使いましょう。今回は、OpenAI APIを使って要約をしていきます。使用するモデルに関してですが、gpt-4oが一番コストパフォーマンスとして良さそうでした。

gpt-3.5-turboだと、昨日の振り返りとして聞くには中身が薄すぎ(15個のテキストに対して20~30秒程度でまとめてくれるが)で、gpt-4だと文章はしっかりし内容も良い(15個のテキストに対して1分30ほど)ですが動作に時間がかかり費用も高めです。4oはその中間をとってくれています。

import os
import requests
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()

# トークン読み込み
SLACK_BOT_TOKEN = os.getenv("SLACK_BOT_TOKEN")
CHANNEL_ID = os.getenv("CHANNEL_ID")
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

# ① Slackのメッセージ(仮の例。実際はSlack APIで取得)
messages = [
    "昨日、プロジェクトXの進捗確認を行いました。",
    "次回のミーティングは来週月曜10時です。",
    "バグ報告:ログイン画面でエラーが出ています。"
]

# ② 要約処理
def summarize_messages(messages):
    text = "\n".join(messages)
    print("🔍 GPTに渡す内容:\n", text)

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": "あなたはSlackの会話を要約する秘書です。簡潔に、敬語で、今日のラジオの冒頭挨拶のようにまとめてください。"},
            {"role": "user", "content": text}
        ],
        temperature=0.7
    )

    summary = response.choices[0].message.content
    print("📝 要約結果:\n", summary)
    return summary

# ③ Slackに投稿
def post_to_slack(text):
    url = "https://slack.com/api/chat.postMessage"
    headers = {"Authorization": f"Bearer {SLACK_BOT_TOKEN}"}
    payload = {
        "channel": CHANNEL_ID,
        "text": text
    }

    response = requests.post(url, headers=headers, json=payload)
    if response.status_code != 200 or not response.json().get('ok'):
        print("⚠️ 投稿に失敗しました:", response.json())
    else:
        print("✅ 投稿成功:", response.json()['message']['text'])

# 実行フロー
if __name__ == "__main__":
    summary = summarize_messages(messages)
    post_to_slack(summary)

これを実行すると、Slackへは以下のように投稿されました。

皆様、おはようございます。昨日はプロジェクトXの進行状況についての確認を行いました。また、次回のミーティングは来週の月曜日、午前10時に予定しております。さて、技術的なご報告として、ログイン画面で一部エラーが発生しているという情報が寄せられております。以上が本日の主な報告事項です。

要約したテキストを音声化

続いて、要約したテキストを音声化していきます。

音声化には、gTTSというツールを使います。これは、Googleの音声読み上げ機能をPythonから簡単に使えるようにしたライブラリです。日本を含む30カ国以上に対応しており、APIキーが不要で手軽に使えるところがいいですね。ただし、商用利用はNGのことがあるので、注意が必要です。

ちなみに、感情をつけて話させたり、本当の人間が喋るような形で読み上げさせたいのであれば、有料ツールでいいものもあります。それぞれのツールを表にまとめてくれたので(chatGPTが)、良ければ参考にしてください。

ツール精度・自然さコスト感日本語対応商用利用メモ
OpenAI TTS⭐⭐⭐⭐⭐安価〜中Proユーザー向け。最も自然。
ElevenLabs⭐⭐⭐⭐無料あり△(要確認)感情あり、英語が得意
CoeFont⭐⭐⭐⭐◎(要契約)ナレーションや広告向け
gTTS⭐⭐無料×(非公式)ライト用途には最適
pyttsx3無料△(OS依存)オフライン動作が強み
import os
from gtts import gTTS
from dotenv import load_dotenv
from slack_sdk import WebClient
import requests

# 環境変数の読み込み
load_dotenv()
SLACK_BOT_TOKEN = os.getenv("SLACK_BOT_TOKEN")
CHANNEL_ID = os.getenv("CHANNEL_ID")

# 要約されたテキスト(ダミー)
summary_text = """
おはようございます。昨日はプロジェクトXの進捗確認が行われました。
ログイン画面にバグが見つかり、対応が必要です。
次回のミーティングは来週月曜の10時です。
"""

# gTTSで音声ファイル作成
tts = gTTS(text=summary_text, lang='ja')
audio_filename = "summary.mp3"
tts.save(audio_filename)
print(f"✅ 音声ファイルを保存しました: {audio_filename}")

# Slackにファイル投稿 (multipart/form-data形式)
with open(audio_filename, "rb") as file:
    client = WebClient(token=SLACK_BOT_TOKEN)

try:
    response = client.files_upload_v2(
        channel=CHANNEL_ID,
        file=audio_filename,
        title="ラジオまとめ",
        initial_comment="🎧 今日の音声まとめです!"
    )
    print("✅ Slackに音声ファイルを投稿しました!")
except Exception as e:
    print("❌ エラーが発生しました:", str(e))

上記のプログラムを実行すると、このような形でラジオを作ってくれました。問題なくmp3で投稿されています!

実行させてみる

それでは上記コード4つで、それぞれ実行させたい機能が上手くいったので、1つにまとめて実行してみましょう。

chatGPTに適当にテキストを作ってもらい、それをコピペして投稿しました。

それではプログラムを実行します。すると、メッセージを取得し、要約、音声ファイルの作成まで、問題なく実行されていきました。

そして、ターミナルに投稿されたというメッセージと共に、Slackにも投稿されました。再生してみましたが、ちゃんとラジオの原稿のように読み上げられています。素晴らしい!

おわりに

今回は、Slack APIを使って昨日のチャット内容を要約してラジオのように音声化するツールを作ってみました。NotebookLMのstudio機能のようなものができました!

課題としては、投稿内容からしか要約が作れないので、返信や添付ファイルはまだ読み込めません。それも読み込めるようになったら、さらに素晴らしいですね。今後、アップデートできたらしていきたいと思います!

今回作ったプログラムは、GitHubに共有されていますので、良ければご覧ください!

GitHub - iwasakiterukazuimpl/Slack_radio-bot
Contribute to iwasakiterukazuimpl/Slack_radio-bot development by creating an account on GitHub.

今回もご覧いただき、ありがとうございました!