はじめに
はじめまして、Hridoy Chandra Das(リド)(@ihridoydas)です。Google Gemini AI Model を使用してAndroidの簡単なアプリケーションを作成する方法を学びたいと思います。
Androidアプリのアーキテクチャ(MVVM)を使用したGemini AI搭載のAIチャットボットの構築方法について、丁寧にご紹介いたします。
Gemini AI モデルとは
Google Gemini AI モデルは、Googleが開発した自然言語処理のための先進的なモデルです。Geminiは、大規模なデータセットを用いて訓練され、人間のような文章を生成することができます。Geminiは、様々なタスクに応用できる汎用的なモデルであり、チャットボット、テキスト生成、質問応答システムなどのアプリケーションに使用されています。「Gemini」は、当社の1.0 Proモデルを特に調整したバージョンと共に、現在40以上の言語で利用可能であり、230以上の国と地域で利用できます。
日本語で質問すれば日本語で答えてくれます。
Gemini Proの価格設定
現在、開発者はGoogle AI Studioを通じて、最大60リクエスト/分まで無料でGemini ProとGemini Pro Visionにアクセスできます。これにより、ほとんどのアプリ開発ニーズに適しています。Vertex AIの開発者は、来年初めの一般提供まで、同じモデルと同じレート制限で、無料で試すことができます。その後、Google AI StudioとVertex AIの両方で、1,000文字または1枚の画像あたりに料金が発生します。新プロジェクトを作成
アプリ テンプレート:BaseTemplateAndroidApp を使用して新しいプロジェクトを作成しました。
PackageStructure.md
# パッケージ構造
com.hridoy.chatgemini # ルートパッケージ
|
├── common # 共通パッケージ~すべての重要なコンポーネントとユーティリティ
| └── utils # ユーティリティクラス / Kotlin拡張
|
├── data # データ処理用
| └── ChatData # APIキーの提供と画像付きおよび画像なしのチャット応答の取得
|
├── domain # ドメイン
│ └── model # モデル(チャット)
│ └── Chat # チャットデータクラス
|
├── navigation # ナビゲーション
|
├── presentation # UI / View、state、およびeventレイヤー
| ├── event # イベント
| ├── screens # すべての画面がここに配置されます
│ ├── state # UIの状態
│ └── viewmodel # ビューモデル
|
├── theme # プロジェクトのテーマ
|
├── BaseApp # プロジェクトベースアプリケーションクラス
└── MainActivity # メインアクティビティ
プロジェクトに使うデペンデンシーライブラリー:
build.gradle.kts
// Gemini AI
implementation("com.google.ai.client.generativeai:generativeai:0.2.0")
implementation("io.coil-kt:coil-compose:2.5.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
implementation("androidx.compose.material:material-icons-extended:1.6.1")
以下のリンクから取得したAPIキーを使用してください:
https://aistudio.google.com/app/prompts/new_chat
このAPIキーを使用することで、プロジェクトがGemini AIと通信できるようになります。
プロジェクトを構築するには、local.properties
ファイルに次の行を追加する必要があります:
local.properties
API_KEY=YOUR_API_KEY
Chat データクラスを作成
Chat.kt
/**
* Chat data class
*
* @param prompt: String
* @param bitmap: Bitmap?
* @param isFromUser: Boolean
*/
data class Chat(
val prompt: String,
val bitmap: Bitmap?,
val isFromUser: Boolean,
)
データレスポンスの取得
警告
今日は例外処理を改善しませんでしたが必要であれば、これを処理してください。
ChatData.kt
object ChatData {
// Provide your API key here(local.properties) -> API_KEY=YOUR_API_KEY
val api_key = BuildConfig.API_KEY //You can use directly
//画像なしで応答を取得する
suspend fun getResponse(prompt: String): Chat {
val generativeModel = GenerativeModel(
modelName = "gemini-pro",
apiKey = api_key,
)
try {
val response = withContext(Dispatchers.IO) {
generativeModel.generateContent(prompt)
}
return Chat(
prompt = response.text ?: "error",
bitmap = null,
isFromUser = false,
)
} catch (e: Exception) {
return Chat(
prompt = e.message ?: "error",
bitmap = null,
isFromUser = false,
)
}
}
/**
* Get response with image
*
* @param prompt: String
* @param bitmap: Bitmap
* @return Chat
*/
//画像付きのレスポンスを取得する
suspend fun getResponseWithImage(
prompt: String,
bitmap: Bitmap,
): Chat {
val generativeModel = GenerativeModel(
modelName = "gemini-pro-vision",
apiKey = api_key,
)
try {
val inputContent = content {
image(bitmap)
text(prompt)
}
val response = withContext(Dispatchers.IO) {
generativeModel.generateContent(inputContent)
}
return Chat(
prompt = response.text ?: "error",
bitmap = null,
isFromUser = false,
)
} catch (e: Exception) {
return Chat(
prompt = e.message ?: "error",
bitmap = null,
isFromUser = false,
)
}
}
}
UIイベントを作成
ChatUiEvent.kt
/**
* Chat UI event
*/
sealed class ChatUiEvent {
data class UpdatePrompt(val newPrompt: String) : ChatUiEvent()
data class SendPrompt(
val prompt: String,
val bitmap: Bitmap?,
) : ChatUiEvent()
// show indicator
data object ShowIndicator : ChatUiEvent()
}
UI State(状態管理)
ChatState.kt
/**
* Chat state class
*
* @param chatList: MutableList<Chat>
* @param prompt: String
* @param bitmap: Bitmap?
* @param showIndicator: Boolean
*/
data class ChatState(
val chatList: MutableList<Chat> = mutableListOf(),
var prompt: String = "",
val bitmap: Bitmap? = null,
val showIndicator: Boolean = false,
)
viewModel
このデモンストレーションでは、画像なしと画像付きの応答を取得する方法を使用します。ChatViewModel.kt
/**
* Chat view model
*/
class ChatViewModel : ViewModel() {
private val _chatState = MutableStateFlow(ChatState())
val chatState = _chatState.asStateFlow()
/**
* Handle chat UI event
*
* @param event: ChatUiEvent
*/
fun onEvent(event: ChatUiEvent) {
when (event) {
is ChatUiEvent.SendPrompt -> {
if (event.prompt.isNotEmpty()) {
addPrompt(event.prompt, event.bitmap)
// Trigger the loading indicator when sending prompt
showIndicator()
if (event.bitmap != null) {
getResponseWithImage(event.prompt, event.bitmap)
} else {
getResponse(event.prompt)
}
}
}
is ChatUiEvent.UpdatePrompt -> {
_chatState.update {
it.copy(prompt = event.newPrompt)
}
}
is ChatUiEvent.ShowIndicator -> {
showIndicator()
}
}
}
/**
* Add prompt
*
* @param prompt: String
* @param bitmap: Bitmap?
*/
private fun addPrompt(
prompt: String,
bitmap: Bitmap?,
) {
// Add prompt to chat list
_chatState.update {
it.copy(
chatList = it.chatList.toMutableList().apply {
add(0, Chat(prompt, bitmap, true))
},
prompt = "",
bitmap = null,
)
}
}
/**
* Get response
*
* @param prompt: String
*/
private fun getResponse(prompt: String) {
viewModelScope.launch {
val chat = ChatData.getResponse(prompt)
_chatState.update {
it.copy(
chatList = it.chatList.toMutableList().apply {
add(0, chat)
},
// Hide loading indicator after response
showIndicator = false,
)
}
}
}
/**
* Get response with image
*
* @param prompt: String
* @param bitmap: Bitmap
*/
private fun getResponseWithImage(
prompt: String,
bitmap: Bitmap,
) {
viewModelScope.launch {
val chat = ChatData.getResponseWithImage(prompt, bitmap)
_chatState.update {
it.copy(
chatList = it.chatList.toMutableList().apply {
add(0, chat)
},
// Hide loading indicator after response
showIndicator = false,
)
}
}
}
/**
* Show indicator
*/
private fun showIndicator() {
// Show loading indicator
_chatState.update {
it.copy(showIndicator = true)
}
}
}
Chat Screen UI作成
Jetpack Composeを使用してビューを作成しました。以下のGitHub Gistをご覧ください。
結果: GitHub サンプル
かなりシンプルです…
以上、最後までお読みいただきありがとうございました。