mcpField
I
integrate-genui-firebase

integrate-genui-firebase

github.com/flutter開発1.8k82 回インストール2 週間前に更新
リポジトリ

integrate-genui-firebase について

既存の Flutter アプリに genui を追加し、Firebase AI Logic を使う基本的な会話エージェントを接続するスキルです。依存関係、コントローラー、イベント処理、画面表示を案内し、状態を持つウィジェットと入力 UI は事前確認を求めます。

主な機能

  1. 01Firebase 初期化と依存関係の確認
  2. 02genui の追加とログ設定
  3. 03会話・サーフェスコントローラーの接続
  4. 04Firebase AI Logic 経由のメッセージ送信
  5. 05会話イベント処理とサーフェス表示
  6. 06状態ウィジェットと入力 UI の事前確認

活用シーン

  1. 01Flutter のチャット画面への GenUI 組み込み
  2. 02チャットセッションと Firebase AI Logic の接続
  3. 03アプリ内でのエージェント提供 UI の表示

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/flutter/genui --skill integrate-genui-firebase

インストール後、Claude Code で/integrate-genui-firebaseを入力して読み込まれたか確認します。

詳細

GenUI を Firebase AI Logic と統合する

目標

genui パッケージを Flutter アプリに正常に統合し、Firebase AI Logic を使用する基本的な会話エージェントを設定します。このスキルでは、Firebase AI Logic の設定がプロジェクトですでに完了し、動作していることを前提とします。

手順

genui を統合して簡単な会話を開始するよう依頼された場合は、次の手順に従います。

  1. Firebase の設定を確認する: firebase_core と firebase_ai が pubspec.yaml に含まれていることを確認します。 main() 関数内で Firebase.initializeApp が呼び出されていることを確認します。

    WidgetsFlutterBinding.ensureInitialized();
    await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
    
  2. GenUI パッケージを追加する: pubspec.yaml の依存関係に genui を追加します。

  3. 必要なライブラリをインポートする: TextPart が他のパッケージと競合しないように genui をインポート時に非表示にし、その後エイリアスを付けて再度インポートします。

    import 'package:genui/genui.dart' hide TextPart;
    import 'package:genui/genui.dart' as genui;
    
  4. 基本的なロギングを設定する: main() 関数の冒頭で GenUI のロギングを設定します。

    configureLogging(
      logCallback: (level, msg) => debugPrint('GenUI $level: $msg'),
    );
    
  5. モデルとチャットセッションを作成する: 生成モデルを初期化し、チャットセッションを開始します。

    final model = FirebaseAI.googleAI().generativeModel(
      model: 'gemini-3-flash-preview',
    );
    final _chatSession = model.startChat();
    
  6. 対象の StatefulWidget を特定する: 不明な場合は処理を中断してユーザーに確認してください: この統合では、GenUI コントローラー(SurfaceController、A2uiTransportAdapter、Conversation)への参照を保持する StatefulWidget が必要です。アプリケーションで使用する StatefulWidget を特定してください。この状態を保持するウィジェットがわからない場合は、先に進む前にユーザーに確認してください。

  7. State 内で GenUI コントローラーを接続する: 特定した State クラス内で、SurfaceController、A2uiTransportAdapter、Conversation のインスタンスを作成します。

    final catalog = BasicCatalogItems.asCatalog(); // Optionally inject custom CatalogItems
    final _controller = SurfaceController(catalogs: [catalog]);
    final _transport = A2uiTransportAdapter(onSend: _sendAndReceive);
    final _conversation = Conversation(
      controller: _controller,
      transport: _transport,
    );
    
  8. _sendAndReceive メソッドを実装する: トランスポートアダプターからメッセージを受け取り、Firebase に送信し、AI の応答をトランスポートに返すメソッドを作成します。

    Future<void> _sendAndReceive(ChatMessage msg) async {
      final buffer = StringBuffer();
    
      for (final part in msg.parts) {
        if (part.isUiInteractionPart) {
          buffer.write(part.asUiInteractionPart!.interaction);
        } else if (part is genui.TextPart) {
          buffer.write(part.text);
        }
      }
    
      if (buffer.isEmpty) return;
    
      final text = buffer.toString();
      final response = await _chatSession.sendMessage(Content.text(text));
    
      if (response.text?.isNotEmpty ?? false) {
        _transport.addChunk(response.text!);
      }
    }
    
  9. Conversation イベントをリッスンする: DartDoc コメントで必要な動作を説明しながら、各イベントタイプに対応するスタブメソッドを State クラスに作成します。インターフェースの設計に応じて、エージェントから届く新しいサーフェスやテキストの処理方法は異なります。たとえば、会話型インターフェースでは、すべてをリストに追加して ListView に表示できます。一方、ヘッダーやフッターなど特定の場所に UI コンポーネントを表示するインターフェースでは、どのサーフェスをどこに表示するかを判断するために、システム指示でエージェントに指定したサーフェス ID を利用できます。

    /// Updates state to include the new [surfaceId] so a new `Surface` widget can be built.
    void _onSurfaceAdded(String surfaceId) {
      // TODO: Implement state update to add surfaceId
    }
    
    /// Updates state to remove the [surfaceId] so its `Surface` widget is no longer built.
    void _onSurfaceRemoved(String surfaceId) {
      // TODO: Implement state update to remove surfaceId
    }
    
    /// Handles displaying raw text content received from the AI to the user.
    void _onContentReceived(String text) {
      // TODO: Implement displaying the received text
    }
    
    /// Handles errors that occur during the conversation appropriately.
    void _onError(Object error) {
      // TODO: Implement error handling
    }
    

    _conversation.events をサブスクライブして UI サーフェスやチャットメッセージの到着を追跡し、適切なスタブメソッドに振り分けます。

    _conversation.events.listen((event) {
      switch (event) {
        case ConversationSurfaceAdded added:
          _onSurfaceAdded(added.surfaceId);
        case ConversationSurfaceRemoved removed:
          _onSurfaceRemoved(removed.surfaceId);
        case ConversationContentReceived content:
          _onContentReceived(content.text);
        case ConversationError error:
          _onError(error.error);
        default:
      }
    });
    
  10. システムプロンプトを初期化する: PromptBuilder を使って AI に基本的な指示を与え、システムメッセージとして送信します。

    final promptBuilder = PromptBuilder.chat(
      catalog: catalog,
      instructions: 'You are a helpful assistant. Respond to messages in a chatty way.',
    );
    _conversation.sendRequest(ChatMessage.system(promptBuilder.systemPrompt));
    
  11. サーフェスを表示する: Flutter の build() メソッドで、手順 9 で収集した surfaceIds を使用し、GenUI ウィジェットを描画する場所に Surface ウィジェットを配置します。

    Surface(surfaceContext: _controller.contextFor(surfaceId));
    
  12. ユーザー入力の設定について確認する: 処理を中断してユーザーに確認してください: ユーザー入力にどの UI 要素を使用するか、ユーザーに確認してください。TextField と ElevatedButton は適切なデフォルトの選択肢ですが、ユーザーが明確に希望を伝えない限り、それらのウィジェットを使うものと決めつけないでください。

制約

  • ユーザー入力に使う UI 要素を決めつけないでください。手順 12 を参照してください。
  • ウィジェットの dispose() メソッド内で GenUI コントローラー(_transport.dispose()、_controller.dispose())を適切にクリーンアップしてください。

コメント