Flutterでのアプリ開発について

ソリューション事業部の松井です。

普段は主にバックエンド開発を担当していますが、
次の案件でFlutterを用いたアプリ開発をすることになったため、勉強がてら簡単なアプリを作ってみようと思いました。
今回の記事では、その時のアプリ開発についてご紹介したいと思います。

アプリのテーマ

まず、何を作ろうか考えたのですが、
簡単に作れるもの×話題性のあるもの = GPT系のアプリ
と安直に出たので、OpenAI APIを用いたアプリを作ってみることにしました。

今回リリースしたものがこちらになります。
play.google.com
GPT3をベースにしたおじさんが話し相手になってくれるアプリです。
高度な技術を無駄遣いしているようですが、あまり気にしないことにします。

恥ずかしながら、学生時代に友人と開発している時にはフロントエンドに全く触れさせてもらえない程デザインセンスがありませんでした。
しかし、一人でアプリを作るとなるとデザイン面とも向き合わなければなりません。
そこで、今回は有志の方が公開してくださっているライブラリの力を全力で頼ることにしました。

開発環境・使用ライブラリ

[✓] Flutter (Channel stable, 3.13.0, on Ubuntu 22.04.3 LTS 5.15.90.1-microsoft-standard-WSL2, locale ja_JP.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
[✓] Chrome - develop for the web
[✓] Linux toolchain - develop for Linux desktop
[!] Android Studio (not installed)
[✓] Connected device (3 available)
[✓] Network resources

実装

Chat(
  messages: _messages,
  user: _user,
  onSendPressed: _handleSendPressed,
  l10n: const ChatL10nEn(
  emptyChatPlaceholder: 'メッセージがありません。\nおじさんに話しかけてみましょう。',
  inputPlaceholder: 'おじさんに話しかける
),

以上のコードを追加してあげるだけでチャット画面のデザインは完成しました。
有志の方には感謝です。

このままでは返信してくれるおじさんがいないので一人で話し続けてしまうことになります。
まず、OpenAIのAPIを使っておじさんとメッセージのやり取りを出来るようにします。

    // メッセージを送信
    final request = ChatCompleteText(
      messages: messages,
      maxToken: 1000,
      model: GptTurboChatModel()
    );
    // おじさんからの返信を受け取り
    final response = await openAI.onChatCompletion(request: request);
    for (var element in response!.choices) {
      _addMessage(element);
    }
  }

以上でおじさんとチャットが出来るようになりました。

チャットが出来るようになったのは良いですが、おじさんが返信してくれるまでの待ち時間は暇になってしまいます。
ChatGPTと同じ様にリアルタイムで文字が追加されるようにしていきましょう。
リアルタイムで表示する技術はSSE(Server-Sent Events)といったものを使用しているそうです。
こちらに関してもchat_gpt_sdkが対応しているそうなので変更していきます。

final openAI = OpenAI.instance.build(
  token: dotenv.get('OPENAI_API_KEY'),
  baseOption: HttpSetup(receiveTimeout: const Duration(seconds: 30)),
  enableLog: true,
);
openAI.onChatCompletionSSE(request: request).transform(StreamTransformer.fromHandlers(handleError: (error, stackTrace, sink) {
        // エラー処理
    })).listen((it) {
    var content = (it as ChatResponseSSE).choices?.last.message?.content;
    if (content != null) {
      if (content == '') content = ' ';
        responseMessageText += content;
        final response = responseMessage.copyWith(text: responseMessageText);
        _addResponseMessage(response);
      }
    }, onDone: () {
      _changeStatus(types.Status.sent);
});

以上で実装が出来ました。

余談ですが、今回copyWithを使ってチャットを上書きしていますが
使わずに上書きをするとおじさんが荒ぶります。

この原因が分からず色々試行錯誤をしていた所、issueに似たような問題が上がっていたためこちらを参考にして解決することが出来ました。
How to update text message status? · Issue #130 · flyerhq/flutter_chat_ui · GitHub

GooglePlayに公開

GooglePlayConsoleに登録 -> アプリアップロード -> 審査 -> 完了
と順調に出来ると思っていたのですが、

  • 本人確認の為に必要なマイナンバーカードが期限切れで市役所に受け取り
  • アプリリリースの為に必要なストア掲載情報の入力
  • アプリの署名設定

など詰まる点が幾つもあり、開発よりもリリース作業の方が面倒でしたが、4日間の審査期間を経てめでたく公開されました。

まとめ

今まで食わず嫌いでアプリを触ることはなかったのですが、環境さえ作ってしまえば気軽に開発できる分野なのだと感じました。
簡単なものとはいえ、自分の作ったものを公開することでプログラマとして一歩成長出来たと実感しています。

引き続きこれからも、様々な分野に挑戦を続けて行こうと思います。

最後までお読みいただきありがとうございました。


現在アドグローブでは、さまざまなポジションで一緒に働く仲間を募集しています。
詳細については下記からご確認ください。みなさまからのご応募お待ちしております。
hrmos.co