Laravel + ChatGPT 4 で特定のページが80%以上変更されたら通知する機能をつくる

こんにちは。フリーランス・コンサルタント&エンジニアの 九保すこひ です。

さてさて、この間オリエンタルラジオの中田あっちゃんが運営する「ユーチューブ大学」でChatGPT 4の動画を見たのですが、そこでちょっとドキッとする内容をおっしゃっていました。

それは、

Garbage In → Garbage Out(ゴミを入れたら、ゴミが出てくる)

つまり、入力するプロンプトが下手くそだとChatGPTから返ってくる答えも下手くそだよ、という意味です。

そして、さらにこの動画ではより良い結果をアウトプットするにはどうすればいいかを教えてくれたので、それを参考にしてChatGPT 4を使ってみることにしました。

なお、その動画へのリンクは私のブログを先に見てほしいので(きっともう帰ってこないので)最後に紹介します😂👍

そこで❗

今回は前から「できるけど、ちょっと面倒かな」と思っていた機能「特定のページが80%以上変更されたら通知する」機能を作ってみることにしました。

ぜひ何かの参考になりましたら嬉しいです。😄✨

「あっちゃんが ChatGPT 4
のことを ジピ亭四郎
と呼んでました(笑)」

開発環境: Laravel 10.x、ChatGPT 4

ChatGPTで全体の流れを確認する

では、まずはChatGPTに以下のように聞いてみました。

ChatGPT:
あなたは、優秀なLaravelエンジニアとして振る舞ってください。
Laravelを使って「特定のページが80%以上変更されたら通知する」という機能を実装するにはどうすればいいですか?

すると、以下のように手順を返してくれました。(詳しい部分の省略しています)

  1. 外部ページを取得するためのライブラリをインストール
  2. ページの変更を検出する機能を実装
  3. 通知機能を実装
  4. 定期的にページの変更をチェックするスケジューラを設定

では、手順に沿って作業を進めてみましょう❗

外部ページを取得するためのライブラリをインストール

ChatGPTはパッケージ「guzzlehttp/guzzle」をインストールするように言ってきます。

ただ、Laravel 10.xではインストールしたときにはすでにguzzlehttp/guzzleが存在しているのでここは不要です。(そして、Guzzleを利用したHttpクライアントクラスまであります)

ページの変更を検出する機能を実装

ChatGPTはページの変更をチェックする以下のクラスを提案してくれました。

// ⚠ このコードは正しくありません

use GuzzleHttp\Client;

class PageChangeDetector
{
    private $previousContent;
    private $currentContent;

    public function __construct($url)
    {
        $this->previousContent = $this->getContent($url);
    }

    private function getContent($url)
    {
        $client = new Client();
        $response = $client->get($url);
        return $response->getBody()->getContents();
    }

    public function isChanged($url, $threshold = 0.8)
    {
        $this->currentContent = $this->getContent($url);
        $similarity = similar_text($this->previousContent, $this->currentContent, $percent);
        $this->previousContent = $this->currentContent;
        return (1 - $percent / 100) >= $threshold;
    }
}

しかし、これはコードとしてはエラーは出ませんが論理的に正しくありません。

というのも、コンストラクタ内ではURLを使って前回のデータを取得するようになっていますが、isChanged()でもまた同じくURLを使ってデータを取得しています。

つまり、これだと数秒と経たずに変更チェックをすることになり、毎回「変更なし」という判断になる可能性大です。

そこで、新たな条件をつけてChatGPTに投げてみることにします。(なお、途中何回か試行錯誤したので「一番最初に使った」という文言を入れています

ChatGPTを使った開発で重要なのは、必ずコードを順にチェックしていくことですね😅)

ChatGPT:
一番最初に使った PageChangeDetectorクラスを使って以下のように修正してください。
・コンストラクタ内でgetContent()は使わずfetched_pagesテーブルからURLをキーにしてレコードを取得し、その中からcontentというデータを$this->previousContentに格納する
・isChanged内でもし$percentが$thresholdを超えていれば、次回のためにcontentの値を更新する

すると、以下のように修正してくれました。(なお、最初のコード開始部分と、ネームスペースは私がつけました)

Console/Commands/CheckPageChanges.php

<?php

namespace App\Utils;

use GuzzleHttp\Client;
use App\Models\FetchedPage;
use App\Mail\PageChangeNotification;
use Illuminate\Support\Facades\Mail;

class PageChangeDetector
{
    private $previousContent;
    private $currentContent;

    public function __construct($url)
    {
        $fetchedPage = FetchedPage::where('url', $url)->first();
        $this->previousContent = $fetchedPage ? $fetchedPage->content : null;
    }

    private function getContent($url)
    {
        $client = new Client();
        $response = $client->get($url);
        return (string) $response->getBody();
    }

    public function isChanged($url, $threshold = 0.8)
    {
        $this->currentContent = $this->getContent($url);
        $similarity = similar_text($this->previousContent, $this->currentContent, $percent);
        $changeRate = (1 - $percent / 100);

        if ($changeRate >= $threshold) {
            // Send email notification
            $recipientEmail = 'example@example.com'; // Change this to the recipient's email address
            Mail::to($recipientEmail)->send(new PageChangeNotification($changeRate, $url));

            // Update the content in the database for the next check
            $fetchedPage = FetchedPage::where('url', $url)->first();
            if (!$fetchedPage) {
                $fetchedPage = new FetchedPage();
                $fetchedPage->url = $url;
            }
            $fetchedPage->content = $this->currentContent;
            $fetchedPage->save();

            return true;
        } else {
            return false;
        }
    }
}

正直なところ、このコードとしては以下の点が気になりますが間違いではないのでOKとします。

  • 直接 Guzzle を呼び出さなくても Laravel には(Guzzleを使った)Httpクライアントがあるので、そっちのほうがベター
  • FetchedPage でデータ取得して存在チェックしていますが、FirstOrNew() やFirstOrCreate() でショートカットできる
  • isChanged の return false に else は不要

(私、、、なんか意地悪な小姑みたいですかね…😂)

そして、モデル&マイグレーションをつくります。

php artisan make:model FetchedPage -m

すると、モデルとマイグレーションが作成されるので中身を次のように変更します。(これもChatGPTの指示です)

// 省略
    public function up()
    {
        Schema::create('fetched_pages', function (Blueprint $table) {
            $table->id();
            $table->string('url')->unique();
            $table->text('content');
            $table->timestamps();
        });
    }

// 省略

※ ちなみに細かいですが、ChatGPTCreateFetchedPagesTableというクラス名をつけていますが、Laravel 10.xでは無名クラスになっていますので、採用しませんでした。(やはり最新の情報には少し弱い部分があるようですね)

では、マイグレーション実行です。

php artisan migrate

すると実際のテーブルはこうなりました。

通知機能を実装

では通知機能ですが、回答は文章のみだったので、コードを出してもらえるように頼んでみます。

プロンプトは以下のとおりです。

ChatGPT: 
通知機能はMailableでメール送信できるようにしたいです。 
コードを書いてください。 

なお、メール送信する内容は変更率と対象となるURLへのリンクを含めてください。

すると、以下の手順を提案してくれました。

  1. Mailableクラスを作成
  2. Mailableクラスを編集して、メール内容を定義
  3. .envファイルを設定してメール送信の設定を行う
  4. 通知機能を実装

これも順に作業をしていきます。
まずは以下のコマンド実行です。

php artisan make:mail PageChangeNotification

すると、ファイルが作成されるので中身を次のように変更します。(なお、これは古い書き方です・・・が、間違いではないので採用しました👍)

Mail/PageChangeNotification.php

<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class PageChangeNotification extends Mailable
{
    use Queueable, SerializesModels;

    public $changeRate;
    public $url;

    public function __construct($changeRate, $url)
    {
        $this->changeRate = $changeRate;
        $this->url = $url;
    }

    public function build()
    {
        return $this->subject('Page Changed Notification')
            ->text('emails.page_change_notification')
            ->with([
                'changeRate' => $this->changeRate,
                'url' => $this->url,
            ]);
    }
}

text('emails.page_change_notification') の部分は当初マークダウンだったのですが、あとで変更しました。

そして、メールのビューです。
特に指定していなかったのでマークダウンとして提案されました。

が…以下のとおり英語でのメール内容でした。(Oh, my…)

@component('mail::message')
# Page Changed Notification

The target page has been changed by {{ $changeRate * 100 }}%.

@component('mail::button', ['url' => $url])
View Changed Page
@endcomponent

Thanks,

{{ config('app.name') }}
@endcomponent

それほど英語レベルが高くない私でも短いので問題ないですが、念のため日本語化してもらえるように頼んでみます。

ChatGPT:
先ほどのマークダウンのメール本文は英語でした。 
日本語に翻訳してください。

すると、このように変更してくれました。

@component('mail::message')
# ページ変更通知

対象ページの変更率が{{ $changeRate * 100 }}%です。

@component('mail::button', ['url' => $url])
変更されたページを表示
@endcomponent

ありがとうございます。

{{ config('app.name') }}
@endcomponent

これで、問題ないのですが開発に使っているMailCatcherがマークダウンに対応していないようだったので、さらに注文することにしました。

ChatGPT:
日本語化してもらったメール本文ですが、マークダウンには対応していないメールクライアントなので、テキスト形式に変更してください。

すると、最終的にこうなりました。

ページ変更通知
===================

対象ページの変更率が{{ $changeRate * 100 }}%です。

変更されたページを表示: {{ $url }}

ありがとうございます。
{{ config('app.name') }}

いいですね👍

定期的にページの変更をチェックするスケジューラを設定

もちろんページのチェックはスケジューラを使ってもいいのですが、今回はcronを使って実行したいので、独自のArtisanコマンドをつくるよう頼んでみます。

ChatGPT:
今回はスケジューラは使わず、cronを使ってタイマー実行します。
そのため、独自のArtisanコマンドを作ってください。

すると、手順はこうなりました。

  1. Artisanコマンドを作成
  2. Artisanコマンドの実装
  3. cronでタイマー実行を設定

では、提案されたコマンドを実行します。

php artisan make:command CheckPageChanges

すると、コマンドファイルが作成されるので、中身を以下のようにするよう言われます。

ただ、これも正しくありませんでした。

// ⚠ 注意: これは正しくありません

use Illuminate\Console\Command;
use App\Services\PageChangeDetector;

class CheckPageChanges extends Command
{
    protected $signature = 'page:check-changes {url}';

    protected $description = 'Check if a specific page has changed more than 80% and send a notification if it has';

    public function handle()
    {
        $url = $this->argument('url');
        $detector = new PageChangeDetector();
        
        if ($detector->isChanged($url)) {
            $this->info('The page has changed more than 80%. A notification has been sent.');
        } else {
            $this->info('The page has not changed more than 80%. No notification has been sent.');
        }
    }
}

・・・とはいっても、今回はPageChangeDetectorのネームスペースが違う(これは私の判断でUtilsフォルダに入れたのでChatGPTは悪くありません!)が違うだけでした。

use App\Services\PageChangeDetector;

↓↓↓

use App\Utils\PageChangeDetector;

これで作業は完了です。
お疲れ様でした(ChatGPT=チャッピーくんも😄✨)

テストしてみる

では、実際にテストしてみましょう❗

まず、mailcatcherを起動して、以下のコマンドで独自Artisanコマンドを呼び出してみます。

php artisan page:check-changes https://example.com

すると・・・・・・

以下のようなメッセージが表示されました。(通知を送ったよ!という意味になってます)

The page has changed more than 80%. A notification has been sent.

そこで、mailcatcherを見てみると・・・・・

はい❗
指示通り、変更率とURLがリンクとして入っています。

成功です😄✨

では、続いてデータベースの方も見ておきましょう。

はい❗
こちらもきちんとデータが登録されています。

ではこの状態でもう一度コマンドを実行するとどうなるでしょうか・・・・・・

The page has not changed more than 80%. No notification has been sent.

80%以上の変更はありませんでした。
と返ってきました。

これも成功です。

では、最後にわざとDB内のデータを半分以上削ってから保存し、その状態でもう一回コマンドを実行してみましょう。

うまくいくでしょうか・・・・・・

はい❗
うまくパーセンテージが変更になったものが通知されました。

すべて成功です😄✨

企業様へのご提案

今回のように特定のURLを監視することで、例えば競合のウェブサイトやランディングページを監視することができます。

また、変更率は自由に決定することができますので、企業様ごとのご都合に合わせたチューニングをすることも可能です。

もしそういった機能をご希望でしたらぜひお問い合わせよりご相談ください。

お待ちしております。😄✨

開発のご依頼お待ちしております
開発のご依頼はこちらから: お問い合わせ
どうぞよろしくお願いいたします! by 九保すこひ

おわりに

ということで、今回は「Laravel + ChatGPT 4」で特定URLの監視機能をつくってみました。

今回は初めてブログ記事としてはChatGPT 4を使いましたが、まだまだ慣れない部分もあり戸惑ってしまいました。

ただ、今回の記事を書いたことで少し慣れてきた部分もあり、ChatGPT 4(チャッピー)の性格というかご機嫌になるツボみたいなものが見えてきたような気がしました。

ただし!

ChatGPTのつくったコードは受託の仕事では使いにくいですかね…情報が古いので昔の書き方になってますし、冗長なコードもあって、他の開発者の方に見られたら「うーん、この人そんなにスキルないかも…😢」とか「時代のアップデートができない人だな…😫」なんて思われると、今後の仕事にも影響すると思うので。

また、セキュリティが怖いので個人情報を扱う場合や、決済システムでは絶対に使いません❗怖すぎるので。

(手で直せよ、と思われるかもですが、それをやり出すとChatGPTを使わずに書いたほうが早いんです…)

とはいえ、AIはこれからの時代のスタンダードになりそうな予感がしてますし、最新コードを適用できるようになる可能性は高いので、今後もこのブログとしてはできるだけ活用して記事を書いていきたいと思います。

みなさんもいろいろと研究してみてくださいね。(逆にChatGPTを使っていないというのが、逆に価値になる時代が来るかもですね)

ということで、(メインの😂)あっちゃんの動画をお楽しみください 。

【GPT-4の使いこなし方:前編】

【GPT-4の使いこなし方:後編】

ではでは〜❗

「あの人、ホント
いい動画連発しますね。
先生、ありがとうございます❗」

このエントリーをはてなブックマークに追加       follow us in feedly