Kon's DX Lab - Case Study

Day 94|ChatGPT×VPSの実用例:問い合わせ対応Bot

Published on 2025-07-04

🔬 Case Study Summary
Problem

(ここに課題を記述)

Result

(ここに具体的な成果を記述)


Tech & Process

(ここに採用技術とプロセスを記述) コードを詳しく見る »

こんにちは、こんです🦊

Slackに集まる「あれって何だっけ?」「これ教えて!」
……気づいたら、いつも自分ばっかり答えてる気がしませんか?

今回は、そんな小さな「質問ラッシュ」を自分のVPS×ChatGPTでサクッと肩代わりさせちゃおう、という実験です。

✅ VPS上のFlaskでSlackイベントをキャッチ
✅ ChatGPTで回答を作って自動返信
✅ しかもちゃんと「誰でも送れる脆弱Bot」にはしない安全設計!

「Bot作るって難しそう…」と思うかもしれませんが、
作ってみると案外「お?動いたぞ!」って嬉しくなるはず。

今回のゴールは、
あなたのVPSを “24時間働く小さなカスタマーサポート” にすること

一緒に、Slackの横にあなた専用のChatGPT秘書を作ってみましょう🦊✨


1. 導入:この記事でできるようになること

今回は Slack + ChatGPT の組み合わせで、
「よくある問い合わせに自動で答えてくれるBot」
自分のVPS上で安全に動かす方法を一緒にやってみます。

✅ Flask で Slack イベントを受け取る
✅ OpenAI API(最新v1)で ChatGPT から答えを生成する
✅ 安心のリクエスト署名チェック付き
✅ 将来の拡張を見据えた nginx リバースプロキシ構成

💡 なぜやるの?
Slackで同じ質問が何度も来る → Botが代わりに対応
VPSだからAPIキー管理も自由、コストも低い
自分だけの自動化が学べる → 他のサービス応用にも使える


2. 背景・基礎知識

🔹 なぜ「署名チェック」が必要なの?

Slackは、あなたのFlaskに届いたリクエストが本当にSlackから来たものか
を証明する仕組みとして Signing Secret を使います。

これを検証しないと、誰でもリクエストを送れてしまう ので要注意です!

🔹 なぜ非同期レスポンスが必要なの?

Slackには「3秒ルール」があります。
/events に対して3秒以内に 200 OK を返さないと再送やエラー扱いになります。

なので、
1️⃣ イベントを受けたら即 OK を返す
2️⃣ 応答生成&返信は別スレッドでやる

これがベターです!

🔹 OpenAI API v1.x での書き方

OpenAIのPythonクライアントは v1.x で OpenAI クラス経由に変わりました。
古い .ChatCompletion.create は将来的に非推奨です。


3. 実践パート

✅ ステップ1|Slack App作成+キー準備

  • Slack App作成 → Event Subscription 有効化

  • Signing Secret を控える

  • Bot Token を控える

  • OpenAI APIキー を控える

.env に保管:

SLACK_BOT_TOKEN=xoxb-...
SLACK_SIGNING_SECRET=xxxx
OPENAI_API_KEY=sk-xxxx

✅ ステップ2|Flaskサーバー

import os, time, hmac, hashlib, threading
from flask import Flask, request, make_response
from slack_sdk import WebClient
from openai import OpenAI

# .env をロードする場合
from dotenv import load_dotenv
load_dotenv()

app = Flask(__name__)
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
slack_client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])
SIGNING_SECRET = os.environ["SLACK_SIGNING_SECRET"]

def verify_slack_request(req):
    timestamp = req.headers['X-Slack-Request-Timestamp']
    if abs(time.time() - int(timestamp)) > 60 * 5:
        return False
    sig_basestring = f"v0:{timestamp}:{req.get_data(as_text=True)}"
    my_sig = 'v0=' + hmac.new(
        SIGNING_SECRET.encode(),
        sig_basestring.encode(),
        hashlib.sha256
    ).hexdigest()
    slack_sig = req.headers['X-Slack-Signature']
    return hmac.compare_digest(my_sig, slack_sig)

def handle_event(text, channel):
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": text}]
    )
    answer = response.choices[0].message.content
    slack_client.chat_postMessage(channel=channel, text=answer)

@app.route("/slack/events", methods=["POST"])
def slack_events():
    if not verify_slack_request(request):
        return make_response("Invalid signature", 403)

    data = request.json
    if "challenge" in data:
        return make_response(data["challenge"], 200, {"content_type": "application/json"})

    if "event" in data:
        event = data["event"]
        if event.get("type") == "message" and not event.get("bot_id"):
            text = event.get("text")
            channel = event.get("channel")
            threading.Thread(target=handle_event, args=(text, channel)).start()

    return "OK"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

✅ ステップ3|nginx 設定

location /slack/ {
    proxy_pass http://localhost:5000/slack/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # WebSocket対応などの将来拡張用
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

4. つまずきポイントと対処法(FAQ)


5. まとめと次回予告

今回は、以下をやりました。

✅ VPSで ChatGPT×Slackの安全な問い合わせBot を作る手順
✅ リクエスト署名、非同期処理、v1 API対応などの最新ポイント

次は、永続化(DBログ)+複数Bot管理 をやってみます🦊

#openAI #API #API #Flask