@thorikiriのてょりっき

@thorikiriの技術ネタや本を読んだブログです

Geminiを用いたAI駆動開発(7) 〜MT形式インポートとデータ取得の勘所〜

※この本文はGeminiに書かせています。記載内容はおおむね事実と思われますが、誤りが含まれている可能性が大きいです。

前回までのあらすじ

GitHubリポジトリをGeminiに連携させ、プロジェクトのディレクトリ構造や型定義を前提としたコード生成が可能になった。これにより、ブログ詳細画面(ダッシュボード)の基礎と、Zod/Drizzleを用いた型安全なデータ取得エンドポイントの実装を完了した。

MT形式ファイルのインポート実装

過去記事の資産を活用するため、Movable Type(MT)形式のテキストファイルをアップロードし、パースしてデータベースに一括登録する機能を実装した。 1. パーサーの実装: server/utils に、MT形式特有のセパレータ(-------------)を解析し、記事タイトルや本文、作成日時を抽出するロジックを構築。 2. 一括登録API: readMultipartFormData を用いてファイルを受け取り、Drizzleのトランザクション処理を用いて posts テーブルへ一括保存するエンドポイントを作成。 3. UIの実装: UButton と隠し input 要素を組み合わせ、ファイル選択ダイアログを呼び出す操作系を構築した。

直面した課題:APIの使い分けとUIの整合性

開発の過程で、Nuxt特有のデータ取得手法における混乱が生じた。 * useFetch$fetch の混同: ページ初期表示用の useFetch と、イベント駆動で動作する $fetch は役割が異なる。インポート完了後に画面を更新するためには、useFetch が提供する refresh 関数を適切に呼び出す必要があった。コピペで動作することもあるが、内部的な挙動(リアクティビティの有無など)を理解していないと、意図した画面更新が行われないケースに直面した。 * UI実装の揺れ: 長時間のチャットによるコンテキストの引き継ぎの影響か、Nuxt UI v4の仕様(スロット名の変更など)に適合しない古い形式のコードが提案される場面があった。

AIによるパーサー実装の恩恵

特筆すべき点として、MT形式のパーサー実装が極めて容易であったことが挙げられる。開発者はMT形式の具体的な内部仕様を詳細に把握していなかったが、Geminiに「MT形式をパースしてほしい」と指示を出すだけで、セパレータや各項目の抽出ロジックが即座に生成された。

細かい不具合が内在している可能性はあるが、少なくとも現状のテストデータにおいては問題なく動作している。仕様を深く調べ学習するコストをスキップして、実用的なロジックを手にできる点は、AI駆動開発の大きな強みであると感じた。

まとめ

GitHub連携により開発スピードは加速したが、AIが提案する「似て非なるAPI」の使い分けや、UIライブラリのバージョン差異については、開発者がドキュメントを確認し、内容を正しく理解した上で採否を判断する必要がある。一方で、フォーマット解析のようなドメイン知識が必要な実装においては、AIの提案が開発コストを大幅に削減してくれることを再認識した。

Geminiを用いたAI駆動開発(6) 〜GitHub連携と詳細画面への遷移〜

※この本文はGeminiに書かせています。記載内容はおおむね事実と思われますが、誤りが含まれている可能性が大きいです。

前回までのあらすじ

これまでに、Nuxt 4 と Drizzle ORM を用いたプロジェクトの土台を作成し、ブログ情報の基本的な CRUD 操作を実装した。また、Gemini API との連携を見据えた DB スキーマの定義や、Nuxt UI v4 を用いた一覧画面のプロトタイプ構築を行ってきた。

GitHub連携によるコンテキストの共有

今回は、開発環境の GitHub リポジトリを Gemini に連携させた。これにより、既存のディレクトリ構造や型定義を前提としたコード生成が可能になった。具体的には、shared/types に定義した Zod スキーマを介して、サーバー(Nitro)とフロントエンド(Vue)で型安全なデータ通信を行うためのエンドポイントとインターフェースを整備した。

ブログ詳細画面の実装

ブログ一覧の各カードから、特定のブログの詳細を確認できる「ダッシュボード画面」への遷移を実装した。

  1. pages/blogs/[id].vue の作成:タブ切り替えにより、記事一覧、ネタ帳、AI設定を管理できる画面を構成した。
  2. データ取得ロジックの構築server/api/blogs/[id].get.ts において、Drizzle で必要なカラムのみを SELECT し、Zod スキーマでパースして返却する堅牢なロジックを実装した。
  3. 遷移機能の付与BlogCard コンポーネントにおいて、UCard をクリックすることで詳細画面へ遷移する動線を作成した。

発生した問題と解決

実装後の動作確認において、カード内に配置した「外部リンク」ボタンや「削除」ボタンが正常に機能しない問題が発生した。カード全体をリンクにしたことで、子要素であるボタンのクリックイベントが親要素にバブリング(伝播)し、ボタン固有の処理よりも先にページ遷移が発火してしまうことが原因である。

この問題に対し、ボタン要素に @click.stop 修飾子を付与することでイベントの伝播を阻止した。また、HTMLの仕様として <a> タグの入れ子(リンクの中にリンクを置くこと)を避けるため、CSSの stretched link パターンを適用した。具体的には、カード内に絶対位置指定した「全体リンク」を配置し、ボタン要素はそれよりも高い z-index を持つレイヤーに配置することで、カード全体のクリック判定とボタンの独立した操作性を両立させた。

実装コードのイメージ:

<ULink :to="`/blogs/${id}`" class="after:absolute after:inset-0" />

<UButton @click.stop="onDelete" class="relative z-10" />

AIは効率的なコードを提案したが、こうした UI 上の基本的なイベント制御や、アクセシビリティに関わる構造上の注意点については、開発者が実際に操作して指摘するまで考慮されないという課題が浮き彫りになった。

Geminiを用いたAI駆動開発(番外編2) 〜有料版への移行と、連携機能の検証〜

※この本文はGeminiに書かせています。記載内容はおおむね事実と思われますが、誤りが含まれている可能性が大きいです。

1. 開発環境のアップデート:Gemini 有料版の導入

第2章の開始にあたり、Geminiを有料版(Gemini Advanced)へ移行しました。目的は、より高度な推論能力の活用と、プロジェクト専用のカスタマイズ機能(Gem)を利用することです。

2. Gemの定義とコンテキストの引き継ぎ

有料版の機能である「Gem」を利用し、本プロジェクト専属のエンジニアとしてAIを定義しました。 新チャットへの移行に際しては、これまでの開発経緯や設計上の意思決定をまとめたドキュメントを旧チャットから抽出し、それを新環境に適用。これまでの議論の文脈を維持したまま、開発を継続できる状態を整えました。

3. GitHub連携の現状と課題

今回のアップデートにおける主要な検証項目の一つが、GitHubリポジトリとの直接連携でした。 リポジトリをAIに読み込ませることで、コードベース全体を俯瞰した提案を期待していましたが、現時点ではシステム側の動作が不安定であり、正常にファイルを読み取れない状況が続いています。

4. 回避策の検討と「待機」の選択

AIからは、ソースコードを直接チャットへアップロードして共有する代替案が示されました。しかし、今回はこの方法を見送ることにしました。

その理由は、「手動共有した知識」と「GitHub連携によって得た知識」が混在すると、連携機能自体の実用性や精度を正確に評価できなくなるためです。ツールが本来持つポテンシャルを正しく検証することを優先し、連携機能が安定するまで次の実装工程を保留するという判断を下しました。

5. 今後の予定

当面は、連携機能の回復を確認しつつ、並行して進めるべき設計業務に注力します。 環境が整い次第、当初の計画通り「Gemini API連携」へと進む予定です。

Geminiを用いたAI駆動開発(番外編1) 〜5日間の軌跡と、次なるステージへの「環境進化」〜

※この本文はGeminiに書かせています。記載内容はおおむね事実と思われますが、誤りが含まれている可能性が大きいです。

1. 5日間のダイジェスト:AIと共に歩んだ基盤構築

この5日間、Geminiと共にシステムの土台を作り上げてきました。 Nuxt 4 / Nuxt UI v4 という最新鋭の環境に対し、AIは時に迷いながらも、対話を通じて正確なコードを導き出してきました。

  • 第1回〜第2回: データベース(Turso/Drizzle)連携とユーザー基盤の構築
  • 第3回〜第4回: Nuxt UI v4によるモダンな画面設計と、AI生成によるブランドデザイン
  • 第5回: ブラウザ標準を脱却した、ユーザー体験(UX)の磨き上げ

2. 方針転換:構築中システムのベールを脱ぐ

これまで、構築しているシステムの詳細についてはあえて伏せてきましたが、基盤が整った今、その正体を明かす時が来ました。

私たちが作っているのは、「AIを活用した記事作成支援システム」です。 単なるテキストエディタではなく、複数のブログメディアを効率的に管理し、AIと対話しながら記事の構成案、執筆、校正をワンストップで行うためのツールを目指しています。これからの記事では、この具体的な機能実装にフォーカスしていきます。

3. AI駆動開発の核心:「再考してください」が未来を創る

開発中、AIが「構造上の制約で実装できない」と回答する場面がありました。しかし、そこで諦めずに「再考してください」と粘り強く促すことで、AIは解決策を自ら編み出し、限界を突破しました。 AIの回答を鵜呑みにせず、共に最適解を探る。これこそが、真のAI駆動開発です。

4. 次なる進化:Geminiプランのアップデート

記事作成の核となるロジックを実装する次なるフェーズに向け、環境を大幅にアップデートします。

私が当初から期待していたこと(基本戦略)

  • 精度の底上げ: 複雑な記事生成ロジックをミスなく出力する知能の強化。
  • Gem(カスタムAI)の活用: 「記事作成支援専用エンジン」としてAIをチューニング。
  • GitHub連携: コード全体をAIが把握し、リポジトリ単位での改善提案。

Geminiからの提案で気づいた「さらなる可能性」

  • 長大なコンテキスト(1.5 Pro): プロジェクト全ファイルを読み込ませた、ファイル間の依存関係を考慮した議論。
  • マルチモーダル・デバッグ: UIのキャプチャ画像による、視覚的なフィードバックと修正。
  • システムプロンプトの固定: 開発規約を徹底させ、回答のブレを最小限に抑制。

5. まとめと第2章への展望

家を建てるための更地を整え、基礎を打つ時期は終わりました。 これからは、アップデートした最強のAI環境と共に、システムの核心である「AI執筆支援エンジン」の本格実装へと突入します。

「AIに作ってもらう」から「AIと一つのチームになる」へ。 次回の第2章スタートを、ぜひ楽しみにしていてください。

Geminiを用いたAI駆動開発(5) 〜AIの誤解を乗り越えて。Nuxt UI v4の実装と、AIとの対話のコツ〜

※この本文はGeminiに書かせています。記載内容はおおむね事実と思われますが、誤りが含まれている可能性が大きいです。

前回までのあらすじ

前回(第4回)は、Geminiを駆使してキャラクター制作やバナー整備を行いました。今回は、システムの操作感をより「Webアプリ」らしくするため、ブラウザ標準のダイアログをモダンなUIに置き換えていきます。

1. 今回の目標:最新ライブラリへのAI対応

これまでデータの削除確認には window.confirm を使用していましたが、これを Nuxt UI v4UModalUNotifications に置き換えます。

ここでのポイントは、AI(Gemini)が最新ライブラリの破壊的変更をどこまで正確に把握できるかという点です。Nuxt UI v4はv3から大きく仕様が変わっていますが、AIは時として古い情報を「もっともらしく」提示することがあります。

2. 削除確認のモダン化:AIとの試行錯誤

当初、Geminiは従来の v-model を使った実装を提案しましたが、実際には表示が消えないなどの問題が発生しました。そこでAIと対話を重ね、v4固有の v-model:open#content スロットの仕様を「再発見」させていきました。

<script setup lang="ts">
const isConfirmOpen = ref(false)

const handleDeleteConfirm = () => {
  // 削除イベントの発行
  isConfirmOpen.value = false
}
</script>

<template>
  <UButton
    icon="i-lucide-trash-2"
    color="error"
    variant="ghost"
    @click="isConfirmOpen = true"
  />

  <UModal v-model:open="isConfirmOpen" title="データの削除">
    <template #content>
      <div class="p-4">
        <p class="text-sm text-neutral-500 mb-6">
          このデータを削除してもよろしいですか?
        </p>
        <div class="flex justify-end gap-3">
          <UButton label="キャンセル" color="neutral" variant="ghost" @click="isConfirmOpen = false" />
          <UButton label="削除する" color="error" @click="handleDeleteConfirm" />
        </div>
      </div>
    </template>
  </UModal>
</template>

3. トースト通知の導入:UNotifications

成功・失敗のフィードバックも useToast() に置き換えました。これもAIに「Nuxt Layout構成の場合の最適な配置」を検討させ、app.vueUApp 直下に置く構成に辿り着きました。

const toast = useToast()

// 成功時の例
toast.add({
  title: '処理完了',
  description: 'データを正常に保存しました。',
  color: 'success',
  icon: 'i-lucide-check-circle'
})

4. エピソード:AIの「できない」は「できる」の始まり

今回の開発で最も印象的だったのは、このブログ用マークダウンの出力プロセスでした。

マークダウン内にコードブロックが含まれる場合、AI(Gemini)は当初「構造上の制約(入れ子問題)で、マークダウン形式のままコードブロックを出力することはできない」と回答しました。しかし、こちらから「再考してください」と粘り強く要求したところ、AIは「外側を4つのバッククォートで囲む」という解決策を自ら編み出し、見事に期待通りの出力を行いました。

AI駆動開発において、AIの最初の回答が「限界」ではありません。適切なフィードバックと再考の促しによって、AIが自身の制約を超えた回答を出してくる。これこそがAIと共に開発する醍醐味だと感じた一幕でした。

5. まとめ

  • 最新技術への追従: AIは古い情報に引っ張られることもあるが、対話で修正可能。
  • UXの向上: Nuxt UI v4による一貫性のあるフィードバックの実装。
  • AIとの向き合い方: 「できない」と言われても諦めずに再考を促すことが重要。

これで、操作感とAIとの連携、両面において一歩前進しました。

Geminiの教科書

Geminiの教科書

Amazon