『述べて作らず、信じて古を好む。
窃に我が老彭に比す』

論語より

【AI活用】ChatGPTの良さを引き出すコーディング

こんにちは、松井です。

最近は、AIを普段の開発で活用していこうと
色々試しております。

 

いままでも簡単なツールを作ることは試してきたのですが、
どうも、長期的に使うシステムの開発に

使うのは、なんか嫌だなーというマインドブロックがあり、
避けてきたところがあります。

 

とはいえ、

宮台真司さんも、

「何かを主張したいのなら、逆を学べ。」

と言っておりました。

 

例えば、日本文化・日本神道の良さを伝えるために、

キリスト教との比較を語るのなら、

キリスタン以上に、キリスト教のことを勉強・理解した上で、

語れよ。ということです。

 

 

ということで、

今回は、EC CUBEの定期商品の受注集計を

ChatGPTにお願いして作ってもらいました。

 

だいぶいい感じにできましたので、その報告です。

 

▼結果はこんな感じに!

 

ChatGPTには、こんな感じでお願いしました。

     $regularOrderRepository = $this->entityManager->getRepository(RegularOrder::class);

        $orders = $regularOrderRepository->getQueryBuilderBySearchDataForAdmin([])
            ->getQuery()
            ->getResult();

        foreach ($orders as $order) {
            echo "\n";
            echo "[" . $order->getId() . "]" . $order->getName01() . $order->getName02() . " / " . $order->getRegularStatus()->getName() . "\n";
            foreach ($order->getRegularShippings() as $shipping) {
                if($shipping->getNextDeliveryDate()){
                    echo $shipping->getNextDeliveryDate()->format("Y-m-d") . "\n";
                }
            }
            foreach ($order->getRegularOrderItems() as $orderItem) {
                if(!$orderItem->isProduct()) continue;
                echo "[" . $orderItem->getId() . "]" . $orderItem->getProductName() . ": " . $orderItem->getClassCategoryName1() . "/" . $orderItem->getClassCategoryName2(). "(" . $orderItem->getQuantity() . "コ)\n";
            }
        }

このソースをベースに、定期便商品の次回の出荷日ごとにどの商品が何個必要なのかを一覧にしたい。

出力は、2種類をテーブル形式でお願いしたい。

1つ目のテーブルは、定期便注文への全体の集計として、
ヘッダーは、商品名、規格名1、規格名2、次回お届け日、数量の5項目のテーブル。

2つ目のテーブルは、1つ目のテーブルへの詳細情報として、
商品名、規格名1、規格名2をタイトルとして、
ヘッダーは、行No、注文者名、数量、同じ次回お届け日の注文の有無

集計したい元データの取得方法は、
あらかじめ自分でコーディングしておいて、

集計処理部分だけ、実装をお願いするカタチでお願いしています。

 

▼ちなみに、ゴールイメージはこんな感じ。

 

これに対して返ってきたコードがこちら。

▼出力スクリプト(PHP)

$summary = []; // 集計用
$details = []; // 詳細用

foreach ($orders as $order) {
    $customerName = $order->getName01() . ' ' . $order->getName02();

    foreach ($order->getRegularShippings() as $shipping) {
        $nextDate = $shipping->getNextDeliveryDate();
        if (!$nextDate) {
            continue;
        }
        $nextDateStr = $nextDate->format('Y-m-d');

        foreach ($order->getRegularOrderItems() as $orderItem) {
            if (!$orderItem->isProduct()) {
                continue;
            }

            $productName = $orderItem->getProductName();
            $class1 = $orderItem->getClassCategoryName1();
            $class2 = $orderItem->getClassCategoryName2();
            $quantity = $orderItem->getQuantity();

            $key = md5($productName . $class1 . $class2 . $nextDateStr);

            // 集計表用
            if (!isset($summary[$key])) {
                $summary[$key] = [
                    'productName' => $productName,
                    'class1' => $class1,
                    'class2' => $class2,
                    'date' => $nextDateStr,
                    'quantity' => 0,
                ];
            }
            $summary[$key]['quantity'] += $quantity;

            // 詳細表用
            if (!isset($details[$key])) {
                $details[$key] = [];
            }

            // 同じお届け日の他の注文があるか確認
            $hasOtherSameDate = count($shipping->getRegularOrder()->getRegularShippings()) > 1;

            $details[$key][] = [
                'customerName' => $customerName,
                'quantity' => $quantity,
                'hasOtherSameDate' => $hasOtherSameDate,
            ];
        }
    }
}

▼出力①:全体集計テーブル

echo "\n=== 【出荷日別商品集計一覧】 ===\n";
printf("%-30s | %-10s | %-10s | %-12s | %-5s\n", "商品名", "規格1", "規格2", "次回お届け日", "数量");
echo str_repeat('-', 80) . "\n";

foreach ($summary as $row) {
    printf(
        "%-30s | %-10s | %-10s | %-12s | %-5d\n",
        $row['productName'],
        $row['class1'],
        $row['class2'],
        $row['date'],
        $row['quantity']
    );
}

▼出力②:各商品・規格ごとの詳細テーブル

echo "\n\n=== 【出荷日別商品詳細】 ===\n";

foreach ($details as $key => $entries) {
    $s = $summary[$key];

    echo "\n■ {$s['productName']}({$s['class1']}/{$s['class2']}) - 次回お届け日:{$s['date']}\n";
    printf("%-5s | %-20s | %-5s | %-20s\n", "No", "注文者名", "数量", "同日注文の有無");
    echo str_repeat('-', 60) . "\n";

    $i = 1;
    foreach ($entries as $entry) {
        printf(
            "%-5d | %-20s | %-5d | %-20s\n",
            $i++,
            $entry['customerName'],
            $entry['quantity'],
            $entry['hasOtherSameDate'] ? 'あり' : 'なし'
        );
    }
}

いいっすねぇ😊

ただ、ソート順が微妙だったので、再びこのようにお願い。

サマリーは、商品名・規格名1・規格名2でソートしてほしい

▼結果

// ソート処理:商品名 → 規格1 → 規格2
$summaryList = array_values($summary); // インデックス付きに変換

usort($summaryList, function ($a, $b) {
    return [$a['productName'], $a['class1'], $a['class2']]
         <=> [$b['productName'], $b['class1'], $b['class2']];
});

いい感じっすねえ。。

僕、PHPの配列ソートってどうやったらいいのか
よく分かっていないところあるので、助かります。

 

 

この後も、

 

「詳細の方も同じ並びルールにしてほしい」

 

「「同日注文の有無」の判定が間違ってます。

 detailsの中に、同じ注文者で、

 同じ次回お届け日の商品が2個以上ある場合は、有にしてほしい。」

 

「同じ注文者の判定は、$order->getCustomer()->getId()で

 取得した値をキーにやって欲しい。」

 

「この変更について、コミットメッセージを簡潔に1行で書いてもらってもいい?」

 

「仕様の追加をお願いしたい。

 - 集計対象から、$order->getRegularStatus()->getName()が
  継続でないものは除去。

 - 詳細情報に「定期継続状況」をヘッダーに追加して、
  $order->getRegularStatus()->getName()の値を表示してほしい。

  この時は、継続と継続以外の行も含めて表示してほしい。」

 

などとお願いして、だいぶ思った通りの形に仕上げてくれました。

 

 

 

前回の記事(他部署の新人教育をみて)にも書きましたが、

最近は、目の前のひとや物、道具のクセを知り、

手間ひま惜しまず、仲良くなっていくのを意識しています。

(他部署の上司から「辛抱強さがないね、ペラい」と、言われたので、、笑)

 

今回の件でいえば、

AIにはAIのクセがあり、

良さがあり、悪さがあって、それとどう付き合っていくのかが

AIの魅力を活かすことにも、殺すことにも繋がります。

 

いままで何度かAIでツールを作ってきて、

(こんな感じで。)

(こんな感じで。2)

AIに、データ集計の機能の実装をお願いした時は、

かなり正確に思い通りのものを仕上げてくれているように

感じました。

なので今回は、メインの開発でもデータ集計をお願いしてみました。

 

元データの取得は、

どのデータが集計されるのかは、

自分としてもちゃんと理解しておきたかったので、

自分でコーディングしました。

 

 

かなりいい感じに、AIちゃんが働いてくれました。(大助かり)

 

 

コンソールに期待通りに出力できたので、

あとは、画面表示(Twig)用に加工してもらったり、

CSV出力機能も作ってもらおうかな、と思ってます。

 

そういう基本機能の作成や、参考にしたいコードが明確にあるときは、

AIでのコーディングがかなり強いと思うので、

どうなるか楽しみです。

(まあダメな時は、自分でコーディングすればいいですし。)

 

 

単に、AIへの苦手意識で、線を引かず、

どういう付き合い方をしたら、いい関係を築けるのか?

もちろんそこでは、うまくいかない・思い通りにいかないことも

出てきますが、

その都度、擦り合わせていく中で、

よい付き合い方が、見つかっていくように思います。

 

 

では、今日はこの辺で。

ここまで読んでいただき、ありがとうございました!

 

 

松井