2024.11.14
いまさらNode.jsを知ろう~環境構築も~
2024.06.24
開発環境・ツールFlutter + Geminiで簡単なアプリケーションを作ってみた
この記事では、以前にも記事を書いたFlutterと少し前に話題になった言語生成AIモデル、Geminiを使って簡単なアプリケーションを作成しようと思います。
完成イメージとしては、上記のようにメッセージをテキストフィールドに入力して「送信」ボタンを押下することでGeminiからのレスポンスを取得して表示させるチャットボットのようなものです。
2023年12月にGoogleから発表されたマルチモーダル生成AIです。
料金やモデルが適宜更新されているので、最新の情報は公式ドキュメントを参照してください。
APIキーの取得
まずGoogle AI StudioからAPIキーを取得します。
取得するにはGoogleアカウントが必要です。
Google AI Studioの「Create API Key」から簡単にAPIキーを取得できます。
Gemini APIを呼び出すまでにいくつかFlutter側で準備を施しておきましょう。
まず、プロジェクトの構造は以下のようになります。
gemini_app/
├ .env
├ pubspec.yaml
├ lib /
│ └ main.dart
│ └ controllers /
│ └ chat_controller.dart
│ └ models /
│ └ chat_message.dart
│ └ views /
│ └ chat_page.dart
├ その他ファイル
Flutterでは便利なパッケージがpub.devで公開されています。
今回は「google_generative_ai」というGoogleが公開しているパッケージを利用します。
まずpubspec.yamlファイルに以下を追加します。
pubspec.yamlはFlutterプロジェクトの管理ファイルで、アプリケーションの名前、説明、バージョン情報や、プロジェクトが依存するパッケージ情報を設定します。
パッケージのバージョンは適宜変更してください。
pubspec.yaml
dependencies:
google_generative_ai: ^0.3.1 //
flutter_dotenv: ^5.1.0 // .env使用に必要
最後に下記コマンドでパッケージをインストールします。
flutter pub get
今回はFlutterのオーソドックスな状態管理パターンであるStateful Widget Patternを使用し、APIキーは.envで管理します。今回は簡単化のために.envの詳しい説明は割愛します。
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:gemini_app/views/chat_page.dart';
Future<void> main() async { // エントリーポイント
WidgetsFlutterBinding.ensureInitialized();
await dotenv.load(fileName: ".env"); // .envを読み込む
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp( // ルートウィジェット
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const ChatPage(), // アプリのホームとしてChatPageを設定
);
}
}
chat_controller.dart
import 'dart:developer';
import 'package:flutter_dotenv/flutter_dotenv.dart'; // .envを利用するために必要なパッケージ
import 'package:google_generative_ai/google_generative_ai.dart'; //Geminiを利用するために必要なパッケージ
import '../models/chat_message.dart'; //チャットメッセージモデル
class ChatController {
late GenerativeModel _generativeModel;
final List<ChatMessage> _messages = []; //メッセージを格納する配列
ChatController() {
_initializeGenerativeModel();
}
void _initializeGenerativeModel() async {
try {
final apiKey = dotenv.env['API_KEY'];// apiキーをenvから取得
if (apiKey == null) {
print('API_KEY is not set in .env');
return;
}
_generativeModel = GenerativeModel(model: 'gemini-pro', apiKey: apiKey); // apiキーとモデルを指定してインスタンスを生成
} catch (e) {
print('Error initializing Generative Model: $e');
}
}
Future<void> onSendPressed(setState, textController) async { // 送信ボタン押下時のメソッド
final text = textController.text;
sendMessage(text); // コントローラーでメッセージを送信
setState(() {}); // UIを更新
await fetchMessage(text); // メッセージ取得
setState(() {}); // UIを更新
}
Future<void> sendMessage(String text) async { // メッセージ送信メソッド
if (text.isEmpty) {
return;
}
_messages.add(ChatMessage(sender: 'User', text: text)); // ユーザーのメッセージを追加
}
Future<void> fetchMessage(String text) async { // メッセージ受信メソッド
if (text.isEmpty) {
return;
}
try {
final response = await _generativeModel.generateContent([Content.text(text)]);
final geminiText = response.text ?? 'No response text';
_messages.add(ChatMessage(sender: 'Gemini', text: geminiText)); // Geminiからのメッセージを追加
} catch (e) {
print('Error generating response: $e');
}
}
List<ChatMessage> get messages => _messages; // メッセージのリストを取得
}
chat_page.dart
import 'package:flutter/material.dart';
import '../controllers/chat_controller.dart';
class ChatPage extends StatefulWidget {
const ChatPage({super.key});
@override
State<ChatPage> createState() => _ChatPageState();
}
class _ChatPageState extends State<ChatPage> {
final ChatController _chatController = ChatController();
final TextEditingController _textController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Chat with Gemini'),
),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: _chatController.messages.length,
itemBuilder: (context, index) {
final message = _chatController.messages[index];
return ListTile(
title: Text('${message.sender}: ${message.text}'),
);
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Expanded(
child: TextField( // メッセージ入力フィールド
controller: _textController,
decoration: const InputDecoration(
labelText: 'Type a message...',
),
),
),
IconButton( // 送信ボタン
icon: const Icon(Icons.send),
onPressed: ()=> _chatController.onSendPressed(setState, _textController),
),
],
),
),
],
),
);
}
}
chat_message.dart
class ChatMessage { //チャットメッセージモデル
final String sender;
final String text;
ChatMessage({required this.sender, required this.text});
}
今回は実行先プラットフォームをWindowsに指定して、Android Studioの「Run」ボタンをクリックして実行してみます。
冒頭で説明した簡易的なアプリケーションを作成することができました。
今回は、Geminiにリクエストを送信してレスポンスを表示させる簡単なアプリケーションを作成しました。DB等を利用すれば履歴を保存したり簡易的なチャットボットのような使い方も可能です。
また、今回作成したものは最低限なのでチャット風にするなどレイアウトを整えたりすると使いやすくなると思います。
最後に、たったこれだけで生成AIの導入ができてびっくりしているのが正直な所です。
みなさんもぜひ試してみてください。
【記事への感想募集中!】
記事への感想・ご意見がありましたら、ぜひフォームからご投稿ください!【テクノデジタルではエンジニア/デザイナーを積極採用中です!】
下記項目に1つでも当てはまる方は是非、詳細ページへ!Qangaroo(カンガルー)
【テクノデジタルのインフラサービス】
当社では、多数のサービスの開発実績を活かし、
アプリケーションのパフォーマンスを最大限に引き出すインフラ設計・構築を行います。
AWSなどへのクラウド移行、既存インフラの監視・運用保守も承りますので、ぜひご相談ください。
詳細は下記ページをご覧ください。
最近の記事
タグ検索