はじめに
皆さん、ごきげんよう!れぶです!
今回の記事では、ChatGPTと類似したComposeAI
というオープンソースアプリの解説をしていきます。
ぶっちゃけこのアプリを参考にすることで、ChatGPTのようなアプリをAndroidとiOS両方で作れてしまいます。なので、この記事ではComposeAIアプリの参考資料として技術的な概要を整理していきます。
約7分以内で読めます。それでは、参りましょう!!
この記事の対象者
以下二つに当てはまる方に特に読んで頂きたいです。
- ChatGPTのようなチャットボットアプリを、AndroidとiOS両方で同時に作りたい方
-
Kotlin
やKMM
に一通り精通してる方
Githubリポジトリ
設計概要
-
対応OS
- Android
- iOS
-
言語
- Kotlin
-
アーキテクチャ
- UI Layer/Data Layer
-
使用技術
- UI:
Compose Multiplatform
- ロジック:
KMM
- デザイン:
Material 3
- OpenAI APIクライアント:
openai-kotlin
- ナビゲーション:
Voyager
- DI:
Koin
- SQLiteデータベース:
SQLDelight
- キーと値のデータ保持:
Multiplatform Settings
- 画像表示:
ImageLoader
- リソース生成:
Libre
- ログ:
Napier
- BuildConfig:
BuildKonfig
- Firebase:
Analytics
/Crashlytics
- 広告:
AdMob
- UI:
-
機能
- オンボーディング画面の表示
- プロンプトの入力
- プロンプトに対する回答の生成
- プロンプトに対する回答のコピー
- プロンプトに対する回答のシェア
- スレッドのタイトルの表示
- スレッドの追加・選択・更新
- Firebase連携
- コインによる広告収益
-
画面
- オンボーディング
- チャット
- スレッド管理ドロワー
フォルダ構造
今回はロジックやUIが共通化されているshared/scr
フォルダ内(一部省く)に絞って説明します。
commonMain
commonMain/kotlin
フォルダ(ファイル)名 | 主な内容 |
---|---|
analytics | Firebase Analytics関連の処理やデータを定義 |
data | ・アプリ内で扱うローカルとリモートのデータ関連 ・DB操作/API通信処理を行うRepositoryを定義 |
di | Koinライブラリによるモジュール定義 |
expect | expectを付与したメソッドやプロパティを定義 |
extendedspans | 表示するテキストの特定の部分における描画や動作方法を定義 |
markdown | 出力結果をマークダウン形式で表現するためのデータや表示方法を定義 |
model | アプリで扱うデータ構造を定義 |
ui | オンボーディング画面/チャット画面を構成するUI(Composable関数)を定義 |
util | expectを付与したユーティリティメソッドを定義 |
App.kt | アプリのメインエントリーポイントとなるUI(Composable関数)を定義 |
AppScreenModel.kt | ・画面(App.kt)の状態を管理 ・ユーザーの選択に基づいて適切な画面を表示 |
commonMain/sqldelight
-
SQLDelight
ライブラリ関連 - チャットとチャットメッセージのデータを操作するSQLを定義
androidMain/kotlin
- Android固有の実装を記述
- commonMain/kotlin/のフォルダと対応
- main.android.kt
- commonMain/kotlin/App.ktで定義した
Composable関数
を呼び出し - システムUIの初期設定
- commonMain/kotlin/App.ktで定義した
iosMain/kotlin
- iOS固有の実装を記述
- commonMain/kotlin/のフォルダと対応
- main.ios.kt
- commonMain/kotlin/App.ktで定義した
Composable関数
を呼び出し -
ComposeUIViewController
でUIKitやSwiftUI製のUIをComposeに変換
- commonMain/kotlin/App.ktで定義した
- NapierProxy.kt
- iOS専用の
Napier
を使用したログ設定
- iOS専用の
API処理
openai-kotlin
を使用してAPIを叩くことで、AIモデルによる文章生成等を可能にしています。その応答結果をSQLDelight
によってDB管理するのが、このチャットボットアプリの基本構造になっています。
例えば、以下のメソッドは指定されたチャット(スレッド)に対して適切なタイトルを生成します。openAI.chatCompletion(request)
でAPIに対してチャットの完了リクエストを送信します。これにより、AIモデルからの応答が得られます。
suspend fun generateTitleFromChat(
chatId: String,
): Result<String> = suspendRunCatching(defaultDispatcher) {
val instruction = ChatMessage(
role = ChatRole.System,
content = "What would be a short and relevant title for this chat? You must strictly answer with only the title, no other text is allowed.",
)
val messages = chatMessageQueries.getChatMessagesWithChatId(chatId)
.executeAsList()
.map(ChatMessageEntity::asModel)
val request = ChatCompletionRequest(
model = ModelId("gpt-3.5-turbo"),
messages = messages + instruction,
)
val response = openAI.chatCompletion(request)
response.choices.first().message?.content ?: "?"
}
また、以下の処理はユーザーが入力したメッセージをAPIに送信し、それに対するAIモデルからの応答を取得して、逐次データベースに保存しています。chatCompletions()
を呼び出すことで、Flow
型のデータを受け取ることができます。
// Create request to OpenAI
val request = ChatCompletionRequest(
model = ModelId("gpt-3.5-turbo"),
messages = messagesToSend,
)
// Get assistant response
var assistantMessage = ""
Try {
// Sending request to OpenAI
openAI.chatCompletions(request).collect { chunk ->
chunk.choices.first().delta?.content?.let {
assistantMessage += it
chatMessageQueries.updateChatMessageContent(
id = assistantMessageId,
content = assistantMessage,
)
}
}
...
}
おわりに
今回はComposeAI
というChatGPT類似アプリに関して、技術的な概要を設計・フォルダ構成・API処理の観点からまとめていきました。
今回紹介したアプリの設計やコードを参考にすることで、ChatGPTのようなアプリをAndroidとiOS両方に対応して作れます。また、KotlinによるOpenAI APIの扱い方も参考になるかと思います。
この記事がAndroid開発者/iOS開発者にとって少しでも役立つと嬉しいです。ありがとうございました。
参考サイト