0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Chat-GEMINI: Google Gemini AI を使用した Android チャット アプリの構築

Last updated at Posted at 2024-02-28

はじめに

はじめまして、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枚の画像あたりに料金が発生します。

image.png

新プロジェクトを作成

アプリ テンプレート: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 サンプル

かなりシンプルです…:blush:

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

gemini2.gif
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?