無料で ChatGPT に URL を渡して内容を読んでもらう

以前書いた通り、家族の LINE グループから ChatGPT を利用できるようにしています。

ChatGPT API を使って LINE ボットを作成した
少し前ですが ChatGPT API が公開されました。 以前から ChatGPT をいい感じに使いたいな〜と思っていて、ちょうど実家に帰った際に最近の AI は凄いぜ!的な話をしており、LINE の家族グループに「ボットくん」として参加させてみることを思い立ったというのがやってみた経緯です。 大まかな構成 使用する主要な各サービスは以下です。 * LINE Messaging API * API Gateway * Lambda * DynamoDB * ChatGPT API ざっくりとした図ではこんな感じ。 LINE の Messaging API を使用すること…

今回、このボットに URL を渡すと内容を読んでくれる機能を追加しました。

なるべく課金しない方法を探す

ChatGPT は URL へアクセスすることはできませんが、ChatGPT Plus に課金することでプラグインを使えるようになり、URL へアクセスするプラグインを入れることでコンテンツを取得することが可能になります。

ただ月額 $20 とそれなりにするので、無料でできる方法を探してみます (もっと使用頻度増えたら課金したいと思っている)。

考えた方法

要はアクセス先のコンテンツを ChatGPT に渡せられれば良いので、ChatGPT へメッセージを送る前に URL 先のコンテンツを取得して、ペイロードに含めれば良さそうです。

こんな流れなイメージ。

  1. URL を含むメッセージを LINE から受け取る。
  2. URL を抽出してアクセスし、コンテンツを取得。
  3. ChatGPT へ送るメッセージにコンテンツを追加する。
  4. ChatGPT へメッセージを送信。

例えば、以下のメッセージが LINE から送られてくるとします。

ボットくん
以下の記事を要約して。
https://blog.lorentzca.me/creating-a-line-bot-using-the-chatgpt-api/

なるべく短く要約して。

URL が含まれているのでコンテンツを取得し、最終的に ChatGPT へ送られるメッセージは以下のようになります。

ボットくん
以下の記事を要約して。
https://blog.lorentzca.me/creating-a-line-bot-using-the-chatgpt-api/

なるべく短く要約して。
以下はこの URL の内容です。
少し前ですが ChatGPT API が公開されました。

以前から ChatGPT をいい感じに使いたいな〜と思っていて、ちょうど実家に帰った際に最近の AI は凄いぜ!的な話をしており、LINE の家族グループに「ボットくん」として参加させてみることを思い立ったというのがやってみた経緯です。

大まかな構成

…

「以下はこの URL の内容です。」からが追加したメッセージです。普通に URL を渡すだけだと「URL へはアクセスできません」的なことを言われるので、「以下はこの URL の内容です。」と枕詞を置くことで自然な流れでコンテンツを渡そうという魂胆です。

実装

まず URL を含んでいるかを判定します。含まれていなければそのまま処理を継続し、含まれている場合は URL を抽出してコンテンツを取得します。mssage はLINE から送られてきたメッセージが入っています。

    # URL 有無の判定。
    if 'http://' in message or 'https://' in message:
        print('URL が含まれています。')
        # url 部分のみを抽出。
        urls = get_website_contents.extract_urls(message)

get_website_contents.extract_urls() の実装は以下です。URLExtract というまんまなライブラリがあるので使わせてもらっています。cache_dir='/tmp' 部分は重要です。URLExtract はキャッシュ用のディレクトリを作成しようとしますが、Lambda 関数で動作させる場合、パーミッションのエラーが発生します。キャッシュディレクトリに関数で利用可能な /tmp ディレクトリを指定することで回避できます。

def extract_urls(message):
    extractor = URLExtract(cache_dir='/tmp')
    urls = extractor.find_urls(message)
    return urls

URL を抽出したら、コンテンツを取得して message に追加します。URL が一つの場合のみ処理を行うようにしています。複数 URL 渡して ChatGPT に比較してもらう、というように使うのも面白そうですがまずは単純な状態で試したいので。なので if len(urls) == 1 の条件を入れて urls[0] で一つだけ取り出して渡しています。

    if 'http://' in message or 'https://' in message:
        print('URL が含まれています。')
        urls = get_website_contents.extract_urls(message)

        # URL が一つの場合は、コンテンツを取得して message に追加。
        if len(urls) == 1:
            contents = get_website_contents.get_website_contents(urls[0])
            message = f"""{message}
以下はこの URL の内容です。
{contents}"""

get_website_contents.get_website_contents() の実装は以下です。

def get_website_contents(url):
    response = requests.get(url)
    if response.status_code == 200:
        soup = BeautifulSoup(response.content, 'html.parser')
        body_content = soup.body
        if body_content:
            return body_content.get_text()
        else:
            return 'コンテンツがありませんでした。'
    else:
        return f'コンテンツの取得に失敗しました。ステータスコードは {response.status_code} です。'

URL が複数ある場合は注意を返答して会話を終わらせています。

    if 'http://' in message or 'https://' in message:
        print('URL が含まれています。')
        urls = get_website_contents.extract_urls(message)

        if len(urls) == 1:
            contents = get_website_contents.get_website_contents(urls[0])
            message = f"""{message}
以下はこの URL の内容です。
{contents}"""

       # URL が一つ以外の場合は注意を返答する。
        else:
            line_api.reply_message_for_line(
                reply_token, '会話に含める URL は一つのみ記載してください。')

            return {
                'statusCode': 200,
                'body': json.dumps({'message': 'success'})
            }

早速動かしてみます。

動作イメージ

良い感じに動作しました! 🎉

英語の記事もいい感じに日本語で要約してくれる様子。
アクセス時にエラーとなった場合も良い感じに返してくれる。

エラーの場合は以下のようなメッセージを送ることになるのでどうなるかな〜と思っていましたが、予想以上にいい感じに解釈して伝えてくれていますね…! 🙏

ボットくん
以下の記事を要約して。
https://sp.m.jiji.com/english/show/hogehoge
以下はこの URL の内容です。
コンテンツの取得に失敗しました。ステータスコードは 404 です。

賢い!

感想

思ったよりあっさり実現できた。だいたい何を送りつけてもいい感じにやってくれる (ように見えるだけの場合もありますが) ChatGPT, 生成系 AI は本当に驚きますねぇ…。

URL を渡すのはボットくんを作成してからずっとやろうと思っていたことでしたので、これでより家族 LINE が使いやすくなると良いな〜。