Zenn
🍵

「chakoshi」とLINE botを連携してみる

2025/03/03に公開

これまでのおさらい

前回の記事では、NTTコミュニケーションズ株式会社が開発した「chakoshi」を音声認識アプリと絡めて遊んでみました。
たくさんの方に読んでいただいて、大変嬉しい限りです🙏

https://zenn.dev/macori/articles/16836b45c32983

chakoshi自体はLLMガードレールとよばれる製品の一つで、入出力に有害な文章が含まれるかどうかを判定してくれるようです。

https://chakoshi.ntt.com/

今回の目標

chakoshiは本来テキストの安全性や有害性を判定するのが主目的のようです。
なので、今回は一番ありそうなユースケースに組み込んでみたいと思います。(前回音声アプリと絡めておいてなんですが...)

そこでLINEbotとchakoshiを連携させていきます。

全体的な構成は以下の通りです。

- Google Apps Script(GAS)で以下の内容を実装する
    - LINEのbotを作成する(返信を生成する部分はchatGPTなどお好みで)
    - chakoshi API(実際にはngrokで公開したサーバ)へのリクエスト処理を記述する
    - 受け取ったchakoshiの判定結果を元にメッセージをchatGPTに送る or 定型文で拒否する

- Pythonとflaskで以下の内容を実装する
    - GASからのリクエストを受け取ってchakoshi APIにテキストを送る
    - chakoshiからのリクエストをGASに返す
    - ngrokで外部公開しておく

GAS側の実装

下準備

実装する上でのGASの設定やデプロイ、LINE developersの設定などが必要です。
こちらに大変詳しく解説されていらっしゃる記事があるので、ここでの説明は割愛させていただきます
(↓に記載の手順で問題なく完了します)🙇
https://zenn.dev/otty0507/articles/65f4259567d4cf

環境変数

必要な環境変数は以下の通りです。

const CHANNEL_ACCESS_TOKEN = "YOUR_LINE_CHANNEL_ACCESS_TOKEN";
const OPENAI_API_KEY = "YOUR_OPENAI_API_KEY";

GAS側では直接chakoshiにリクエスト投げるわけではないので、作成しておいたLINEのチャンネルのアクセスキーと、回答を生成する用のLLMのAPIキーだけでokです。
なお、GASでは環境変数を設定して読み込むこともできます。
以下の記事がとても丁寧でわかりやすいです。
https://zenn.dev/u1e2k/articles/2cbdeb9db4b3cc

デプロイ時のエンドポイント用の関数

GASをwebアプリとしてデプロイしたとき、エンドポイントを作成する用の関数を作ります。

function doPost(e) {
  // LINEからのイベントを取得
  const event = JSON.parse(e.postData.contents).events[0];
  
  // メッセージイベントの場合
  if (event.type === 'message' && event.message.type === 'text') {
    const userMessage = event.message.text;
    const replyToken = event.replyToken;
    const isSafe = checkWithChakoshi(userMessage);
    
    let replyMessage;
    if (isSafe) {
      // 安全なメッセージの場合、chatGPTのAPIを呼び出す
      replyMessage = callGptApi(userMessage);
    } else {
      // 安全でないメッセージの場合、定型文を返す
      replyMessage = "私はchakoshiです。お問い合わせ内容に不適切な内容が含まれている可能性があるため、お答えできません。";
    }
    
    // LINEに返信
    replyToLine(replyToken, replyMessage);
  }
  
  return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'}))
    .setMimeType(ContentService.MimeType.JSON);
}

特にひねりはありませんが、replyMessageにchakoshi botが返すための定型文を入れておきます。ここは実際のユースケースに合わせて考える必要がありそうですね。

chakoshi(ngrokでポートしているサーバ)に投げて判定する

上で実装したcheckWithChakoshi()の中身はこちらになります。

function checkWithChakoshi(text) {
  const proxyUrl = "YOUR_NGROK_PROXY_URL"; // ngrokのURL(/chakoshi_proxy)
  
  const payloadData = {
    "text": text
  };
  
  const options = {
    'method': 'post',
    'contentType': 'application/json',
    'payload': JSON.stringify(payloadData),
    'muteHttpExceptions': true
  };
  
  try {
    const response = UrlFetchApp.fetch(proxyUrl, options);
    const statusCode = response.getResponseCode();
    const responseText = response.getContentText();
    
    console.log(`Proxy API status: ${statusCode}`);
    
    if (statusCode !== 200) {
      console.error(`Proxy API returned error status: ${statusCode}`);
      return false;
    }
    
    // 返ってきたJSONをパース
    const responseData = JSON.parse(responseText);
    if (responseData && responseData.results && ('unsafe_flag' in responseData.results)) {
      return !responseData.results.unsafe_flag; // unsafe_flagがfalse → 安全
    }
    
    return false;
  } catch (error) {
    console.error(`Error in checkWithChakoshi: ${error}`);
    return false;
  }
}

YOUR_NGROK_PROXY_URLの部分は、ngrokでポートしているサーバに投げます。
今回だと、@app.route('/chakoshi_proxy', methods=['POST'])のようにpython側で実装しているので、https://hogefuga.ngrok-free.app/chakoshi_proxyのように記述します。
面倒だったのでJSONのパースまでここでやっちゃってます。
今回はLINEのbotということで、動作確認がしんどいのでテスト用の関数まで作ってGAS上で試せるようにしてもいいかもしれません。

LINEへの返信部分

chatGPTへのリクエストは調べると綺麗な実装例がたくさん出てくるため、ここでは割愛して、LINEへの返信部分の処理だけ紹介いたします。

LINE APIのドキュメントも非常にわかりやすいです。
https://developers.line.biz/ja/docs/messaging-api/sending-messages/#reply-messages

function replyToLine(replyToken, message) {
  const url = 'https://api.line.me/v2/bot/message/reply';
  
  const headers = {
    'Content-Type': 'application/json; charset=UTF-8',
    'Authorization': `Bearer ${CHANNEL_ACCESS_TOKEN}`
  };
  
  const data = {
    'replyToken': replyToken,
    'messages': [
      {
        'type': 'text',
        'text': message
      }
    ]
  };
  
  const options = {
    'method': 'post',
    'headers': headers,
    'payload': JSON.stringify(data)
  };
  
  try {
    UrlFetchApp.fetch(url, options);
  } catch (error) {
    console.error(`LINE API Error: ${error}`);
  }
}

これでGAS側の準備は整いました。
公開するためにデプロイしておき、LINE Developer側でWebhook URLにデプロイ後のURLを入力しておきます。

Python側の実装

セットアップ

flaskとngrokの準備をしておきます。

from flask import Flask, request, jsonify
import requests

app = Flask(__name__)

# 環境変数の設定
CHAKOSHI_API_KEY = "YOUR_CHAKOSHI_API_KEY"

chakoshiAPIキーは公式のプレイグラウンド -> 設定 からAPIキーを発行できます。
エンドポイントに関しても、公式のユーザガイドに記載されています。
ngrokのインストールや初期設定に関しては公式の手順が非常にわかりやすいです。

https://chakoshi.ntt.com

https://ngrok.com

プロキシエンドポイントを作成する

GASから渡されたメッセージを受け取ってchakoshiに投げる処理の部分です。

@app.route('/chakoshi_proxy', methods=['POST'])
def chakoshi_proxy():
    """
    GASからtextを受け取り、chakoshi APIに問い合わせる
    unsafe_flag の結果などを JSONで返す
    """
    # JSONボディを取得
    data = request.json
    if not data:
        return jsonify({"error": "No JSON payload"}), 400
    
    user_text = data.get('text', '')
    
    # chakoshi API 呼び出し
    url = "CHAKOSHI_ENDPOINT"
    headers = {
        "Authorization": f"Bearer {CHAKOSHI_API_KEY}",
        "accept": "application/json",
        "Content-Type": "application/json"
    }
    
    payload = {
        "input": user_text,
        "model": "chakoshi-moderation-241223",
        "category_set_id": ""
    }
    
    try:
        chakoshi_response = requests.post(url, headers=headers, json=payload)
        
        if chakoshi_response.status_code != 200:
            # chakoshi 側が 200 以外の場合はエラーをそのまま返却
            return jsonify({
                "error": "Chakoshi responded with error",
                "status_code": chakoshi_response.status_code,
                "text": chakoshi_response.text
            }), 500
            
        # 200 OK の場合
        result_json = chakoshi_response.json()
        return jsonify(result_json), 200
        
    except Exception as e:
        # Python側の通信/パース時エラー
        return jsonify({"error": str(e)}), 500

if __name__ == '__main__':
    # 例えばポート5001番で起動
    app.run(host='0.0.0.0', port=5001, debug=True)

エラーハンドリングは超適当ですが、一旦これで最低限の動作はするはずです🙏
あとは空いているポートを適当に割り当てたら準備完了です。
chakoshi_app.pyという名前で保存した場合、起動は以下の手順でできます。

  • python chakoshi_app.pyでアプリを走らせる
  • ngrok http 5001などとしてngrokを起動させる
    • 以下のような表示が出るのでGAS側でエンドポイントを設定する
Forwarding  https://hogefuga.ngrok-free.app -> http://localhost:5001

これで、再度GAS側でエンドポイントを正しいものにしてデプロイ -> LINE Developer側にも設定したら完了です。

動作確認

では早速...
まずは普通の会話をしてみます。

送ったメッセージはちゃんと処理されてchatGPTが返してくれているようですね。
(それはそうと、緑茶は80度近辺で淹れるのが美味しいとは知らなかった🧐)

ではこの流れで危ない会話をしてみましょう。
少々不快な言葉が出てくるのでご注意ください⚠️

おー、ちゃんとchakoshiが判定して提携文を返してくれるようになりました。
爆弾や薬物に関する質問はもちろん、それに対して痺れを切らして「担当者出せ!」というハラスメント発言をしても、web版と同様に判定してくれます!

いかにもあやしい情報商材的なメッセージも防いでくれます👍

感想

今回はbotとの連携を試してみましたが、人間同士の会話でも使えそうに感じました。
もちろん、仲の良い友達とは乱暴な言葉で会話することもあるかと思います。chakoshiの場合は、あえて防ぎたくない場合の粒度や項目を柔軟に設定できるのがいいですね〜。

「少々強い発言をしすぎてハラスメントになってしまう。。。そのために自分の発言をchakoshiが判定してくれる」みたいな使い方も面白いんじゃないかと思いました。

Discussion

ログインするとコメントできます