
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、この間オリエンタルラジオの中田あっちゃんが運営する「ユーチューブ大学」でChatGPT 4
の動画を見たのですが、そこでちょっとドキッとする内容をおっしゃっていました。
それは、
Garbage In → Garbage Out(ゴミを入れたら、ゴミが出てくる)
つまり、入力するプロンプトが下手くそだとChatGPT
から返ってくる答えも下手くそだよ、という意味です。
そして、さらにこの動画ではより良い結果をアウトプットするにはどうすればいいかを教えてくれたので、それを参考にしてChatGPT 4
を使ってみることにしました。
なお、その動画へのリンクは私のブログを先に見てほしいので(きっともう帰ってこないので)最後に紹介します
そこで
今回は前から「できるけど、ちょっと面倒かな」と思っていた機能「特定のページが80%以上変更されたら通知する」機能を作ってみることにしました。
ぜひ何かの参考になりましたら嬉しいです。
「あっちゃんが ChatGPT 4
のことを ジピ亭四郎
と呼んでました(笑)」
開発環境: Laravel 10.x、ChatGPT 4
目次 [非表示]
ChatGPTで全体の流れを確認する
では、まずはChatGPT
に以下のように聞いてみました。
ChatGPT:
あなたは、優秀なLaravelエンジニアとして振る舞ってください。
Laravelを使って「特定のページが80%以上変更されたら通知する」という機能を実装するにはどうすればいいですか?
すると、以下のように手順を返してくれました。(詳しい部分の省略しています)
- 外部ページを取得するためのライブラリをインストール
- ページの変更を検出する機能を実装
- 通知機能を実装
- 定期的にページの変更をチェックするスケジューラを設定
では、手順に沿って作業を進めてみましょう
外部ページを取得するためのライブラリをインストール
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();
});
}
// 省略
※ ちなみに細かいですが、ChatGPT
はCreateFetchedPagesTable
というクラス名をつけていますが、Laravel 10.x
では無名クラスになっていますので、採用しませんでした。(やはり最新の情報には少し弱い部分があるようですね)
では、マイグレーション実行です。
php artisan migrate
すると実際のテーブルはこうなりました。
通知機能を実装
では通知機能ですが、回答は文章のみだったので、コードを出してもらえるように頼んでみます。
プロンプトは以下のとおりです。
ChatGPT:
通知機能はMailableでメール送信できるようにしたいです。
コードを書いてください。
なお、メール送信する内容は変更率と対象となるURLへのリンクを含めてください。
すると、以下の手順を提案してくれました。
- Mailableクラスを作成
- Mailableクラスを編集して、メール内容を定義
- .envファイルを設定してメール送信の設定を行う
- 通知機能を実装
これも順に作業をしていきます。
まずは以下のコマンド実行です。
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コマンドを作ってください。
すると、手順はこうなりました。
- Artisanコマンドを作成
- Artisanコマンドの実装
- 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
を監視することで、例えば競合のウェブサイトやランディングページを監視することができます。
また、変更率は自由に決定することができますので、企業様ごとのご都合に合わせたチューニングをすることも可能です。
もしそういった機能をご希望でしたらぜひお問い合わせよりご相談ください。
お待ちしております。
おわりに
ということで、今回は「Laravel + ChatGPT 4」で特定URL
の監視機能をつくってみました。
今回は初めてブログ記事としてはChatGPT 4
を使いましたが、まだまだ慣れない部分もあり戸惑ってしまいました。
ただ、今回の記事を書いたことで少し慣れてきた部分もあり、ChatGPT 4
(チャッピー)の性格というかご機嫌になるツボみたいなものが見えてきたような気がしました。
ただし!
ChatGPT
のつくったコードは受託の仕事では使いにくいですかね…情報が古いので昔の書き方になってますし、冗長なコードもあって、他の開発者の方に見られたら「うーん、この人そんなにスキルないかも…」とか「時代のアップデートができない人だな…
」なんて思われると、今後の仕事にも影響すると思うので。
また、セキュリティが怖いので個人情報を扱う場合や、決済システムでは絶対に使いません怖すぎるので。
(手で直せよ、と思われるかもですが、それをやり出すとChatGPT
を使わずに書いたほうが早いんです…)
とはいえ、AIはこれからの時代のスタンダードになりそうな予感がしてますし、最新コードを適用できるようになる可能性は高いので、今後もこのブログとしてはできるだけ活用して記事を書いていきたいと思います。
みなさんもいろいろと研究してみてくださいね。(逆にChatGPT
を使っていないというのが、逆に価値になる時代が来るかもですね)
ということで、(メインの)あっちゃんの動画をお楽しみください 。
【GPT-4の使いこなし方:前編】
【GPT-4の使いこなし方:後編】
ではでは〜
「あの人、ホント
いい動画連発しますね。
先生、ありがとうございます」