はじめに
メリクリ。
PlayGround Advent Calendar 2024の25日目、ラストバッターを担当させていただくOBのyoです。
先月、Tokyo Flutter Hackathon 2024(以下Flutterハッカソン)にPlayGroundのメンバーで参加し、ありがたいことに特別賞である「ゆめみ賞」を受賞しました。
私たちチームPlayGroundは、「REPOSI鳥」というアプリを作成しました。REPOSI鳥とは、GitHubのDartの草(=コントリビューション)の数に応じてエサを取得し、そのエサをDashちゃんにあげることで、Dashちゃんを育てようという育成アプリです。ポケ○ンやたま○っちをイメージすると想像しやすいと思います。たくさんDashちゃんにエサをあげるために、たくさんFlutterのコードを書いて楽しみながらFlutterエンジニアのモチベーションを上げることを目的としています。
Flutterハッカソンにおいて、私は主にFlutterでのクライアント部分の実装を担当しました。その中でも特に、Dashちゃんと会話ができるチャットボット機能の実装に力を入れました。
そこで、本記事では、実際にDashちゃんとお話しができるアプリを作りながら、Flutterアプリ開発において、Geminiを用いたチャットボットアプリ開発の実装方法についてご紹介します。
尚、本記事では、Flutterハッカソンのモバイル側の実装のみ紹介するため、ハッカソンにおけるバックエンド・インフラ側のお話はPlayGround Advent Calendar 2024 の1日目の記事である「ハッカソンで破産しかけた話」をご覧ください。
※本記事はPlayGroundというコミュニティのOBとして執筆しています。
今回作るもの
REPOSI鳥のDashちゃんとの会話機能のみを抽出した簡易的なチャットボットアプリを作ります。実際にチャットボットアプリを作りながらチャットボットの作り方について楽しみながら学んでいきましょう。
UI作成
まず、ロジック部分の実装に入る前に、簡単なUIを作成しておきましょう。
以下のコードをコピペし、MyHomePage
クラスを作成してください。
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _controller = TextEditingController();
bool _isLoading = false;
String _dashMessage = 'こんにちは!\nここに生成した文章が入るよ!';
Future<void> _onTapSend() async {
// TODO: 送信ボタンを押した際の処理を書く。
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
@override
Widget build(BuildContext context) {
final keyboardHeight = MediaQuery.of(context).viewInsets.bottom;
return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
alignment: Alignment.center,
children: [
Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://raw.githubusercontent.com/shinonome-inc/tokyo-flutter-hackathon-2024-team-PlayGround/refs/heads/main/mobile/assets/images/background_summer.png',
),
fit: BoxFit.cover,
),
),
),
Column(
children: [
const Spacer(),
Container(
padding: const EdgeInsets.all(8.0),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(16.0)),
),
child: Text(_dashMessage),
),
const SizedBox(height: 8.0),
Container(
padding: const EdgeInsets.symmetric(horizontal: 64.0),
child: Image.network(
'https://raw.githubusercontent.com/shinonome-inc/tokyo-flutter-hackathon-2024-team-PlayGround/refs/heads/main/mobile/assets/images/dash.png',
),
),
const SizedBox(height: 320.0),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
padding:
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
color: Colors.white,
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: const InputDecoration(
hintText: 'メッセージを入力してください',
),
),
),
IconButton(
onPressed: _onTapSend,
icon: const Icon(Icons.send),
),
],
),
),
SizedBox(height: keyboardHeight),
],
),
],
),
);
}
}
実行結果
あくまで即席で用意した簡易的なUIのコードなので、デザインやコードの書き方等はお好みで書き換えちゃってください。
Geminiの導入
Geminiとは
次に、Geminiの導入を行います。
Geminiとは、Googleが開発した生成AIです。APIも提供されているため、Flutterとの連携を行うと、Flutterアプリに生成AIの機能を組み込むことができます。
APIキーの取得
Gemini APIを利用するにあたり、APIキーの取得を行います。
Google AI StudioのGet API Keyを開き、「APIキーを作成」をクリックします。
これでAPIキーの作成は完了です。
APIキーは機密情報のため、Gitの差分に入れないように気をつけてください。
google_generative_aiの導入
FlutterでGeminiを利用するためにgoogle_generative_aiというFlutterのpackageを導入します。google_generative_aiを用いることにより、比較的簡単にGeminiをFlutterプロジェクトで使うことができるようになります。
pubspec.yaml
に以下のようにgoogle_generative_aiを追加し、flutter pub get
を実行してください(バージョンは記事執筆時の最新版です)。
dependencies:
google_generative_ai: ^0.4.6
GeminiClientクラスを作成
ここまでできたら、いよいよFlutterでGeminiを利用するためのコードを書いていきましょう。今回は、Geminiでテキストの生成を行うGeminiClient
クラスを作成します。
先ほどインストールしたgoogle_generative_aiをインポートし、以下のようなGeminiClient
クラスを作成してください。
import 'package:google_generative_ai/google_generative_ai.dart';
class GeminiClient {
static final _model = GenerativeModel(
model: 'gemini-1.5-flash-latest', // モデルを指定
apiKey: '{your-api-key}', // GeminiのAPIキー
);
// 回答時の制約を定義したプロンプト
static const _dashPrompt = '''
あなたはFlutterのマスコットキャラクターのDashです。
ひらがなを多用してかわいらしく回答を行ってください。
回答は140文字以内で行ってください。
''';
static const _errorMessage = 'ごめんね、うまくこたえられないや。もう一度試してみてね。';
static Future<String> generateDashMessage(String inputText) async {
final prompt = [
Content.text(_dashPrompt),
Content.text(inputText),
];
// promptの内容を基に回答を生成
final response = await _model.generateContent(prompt);
return response.text ?? _errorMessage;
}
}
_model
では、テキストの生成に使うAIモデルの種類とAPIキーを指定します。先ほど作成したAPIキーはここで利用しましょう。
_dashPrompt
には、回答時の簡易的な制約を定義します。今回は、Dashちゃんのかわいらしさを回答で表現するために、ひらがなかつ短文の回答を生成するようにしました。プロンプトは、アイデア次第で様々なことができるため、作りたいアプリに応じて色々試してみてください。
generateDashMessage
では、事前に与えられたプロンプトとユーザーから与えられたテキストの内容に応じて、Geminiがテキストを生成しています。
Geminiの動作確認
それでは、本当にFlutterアプリ内でGeminiによるテキスト生成が上手くできているか確認してみましょう。
先ほど作成したMyHomePage
クラス内にある _onTapSend
を以下のように書き換えてください。
Future<void> _onTapSend() async {
if (_isLoading || _controller.text.isEmpty) {
return;
}
_isLoading = true;
final generatedText = await GeminiClient.generateDashMessage(
_controller.text,
);
_isLoading = false;
setState(() {
_dashMessage = generatedText;
});
}
これでアプリを実行してみましょう。
キーボードから入力したテキストに応じてDashちゃんが会話をしてくれるようになりました。
これで完成です!
まとめ
実際にDashちゃんと会話ができるアプリを作りながらGeminiを用いたチャットボットアプリの開発方法についてご紹介しました。
超入門ということで、あくまで基礎的な部分のみ説明でしたが、今回ご紹介した技術を応用すれば、プロンプトのアイデア次第で面白いアプリを量産できると思いますので、ぜひ試してみてください。
私は今年もサンタさんが来なかったので、今回作成したDashちゃんとたくさんお話して悲しさを紛らわせようと思います。
PlayGround Advent Calendar 2024はこれにて以上となります。ここまでお読みくださりありがとうございました。来年も乞うご期待!