From daf060829108b6fab9d690a4894e16cf10bb53c7 Mon Sep 17 00:00:00 2001 From: odaridavid Date: Fri, 22 Mar 2024 03:22:11 +0100 Subject: [PATCH 1/2] try out gemini --- app/build.gradle.kts | 3 +++ .../ui/home/AIOutfitRecommendation.kt | 26 +++++++++++++++++++ gradle/libs.versions.toml | 2 ++ 3 files changed, 31 insertions(+) create mode 100644 app/src/main/java/com/github/odaridavid/weatherapp/ui/home/AIOutfitRecommendation.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 475b410..336a071 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -227,6 +227,9 @@ dependencies { // About implementation(libs.about.lib.core) implementation(libs.about.lib.compose.ui) + + // AI + implementation(libs.gemini) } kapt { diff --git a/app/src/main/java/com/github/odaridavid/weatherapp/ui/home/AIOutfitRecommendation.kt b/app/src/main/java/com/github/odaridavid/weatherapp/ui/home/AIOutfitRecommendation.kt new file mode 100644 index 0000000..8e2c6cb --- /dev/null +++ b/app/src/main/java/com/github/odaridavid/weatherapp/ui/home/AIOutfitRecommendation.kt @@ -0,0 +1,26 @@ +package com.github.odaridavid.weatherapp.ui.home + +import com.github.odaridavid.weatherapp.BuildConfig +import com.google.ai.client.generativeai.GenerativeModel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import javax.inject.Inject + +class AIOutfitRecommendation @Inject constructor() { + + private val outfitsModel by lazy { + GenerativeModel( + modelName = "gemini-1.0-pro", + apiKey = BuildConfig.VERTEX_AI_API_KEY + ) + } + + suspend fun generateOutfitRecommendation(temperature: String): Flow { + // TODO implement for language changes + val prompt = "What would be a nice outfit for $temperature weather?" + return flowOf(outfitsModel.generateContent(prompt).text) + } + + +} + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f5c33a1..3cead5e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,6 +39,7 @@ androidx-test-runner = "1.5.2" androidx-test-rules = "1.5.0" core-ktx = "1.5.0" coroutines = "1.8.0" +gemini = "0.2.2" [libraries] activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" } @@ -89,6 +90,7 @@ about-lib-compose-ui = { module = "com.mikepenz:aboutlibraries-compose-m3", vers android-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test-runner" } android-test-rules = { module = "androidx.test:rules", version.ref = "androidx-test-rules" } test-core-ktx = { group = "androidx.test", name = "core-ktx", version.ref = "core-ktx" } +gemini = { module = "com.google.ai.client.generativeai:generativeai", version.ref = "gemini" } [plugins] com-android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" } From d8b50ce94a63e7d7447f0cfe23a3a09722cdcc7b Mon Sep 17 00:00:00 2001 From: odaridavid Date: Fri, 22 Mar 2024 18:47:29 +0100 Subject: [PATCH 2/2] try out open ai --- app/build.gradle.kts | 1 + .../OutfitRecommendationRecommenderGemini.kt} | 4 +- .../OutfitRecommendationRecommenderOpenAI.kt | 38 +++++++++++++++++++ .../weatherapp/ui/home/HomeScreen.kt | 9 +++++ .../weatherapp/ui/home/HomeViewModel.kt | 19 +++++++++- gradle/libs.versions.toml | 2 + 6 files changed, 70 insertions(+), 3 deletions(-) rename app/src/main/java/com/github/odaridavid/weatherapp/{ui/home/AIOutfitRecommendation.kt => data/ai/OutfitRecommendationRecommenderGemini.kt} (85%) create mode 100644 app/src/main/java/com/github/odaridavid/weatherapp/data/ai/OutfitRecommendationRecommenderOpenAI.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 336a071..0b33e97 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -230,6 +230,7 @@ dependencies { // AI implementation(libs.gemini) + implementation(libs.openai) } kapt { diff --git a/app/src/main/java/com/github/odaridavid/weatherapp/ui/home/AIOutfitRecommendation.kt b/app/src/main/java/com/github/odaridavid/weatherapp/data/ai/OutfitRecommendationRecommenderGemini.kt similarity index 85% rename from app/src/main/java/com/github/odaridavid/weatherapp/ui/home/AIOutfitRecommendation.kt rename to app/src/main/java/com/github/odaridavid/weatherapp/data/ai/OutfitRecommendationRecommenderGemini.kt index 8e2c6cb..b6572b6 100644 --- a/app/src/main/java/com/github/odaridavid/weatherapp/ui/home/AIOutfitRecommendation.kt +++ b/app/src/main/java/com/github/odaridavid/weatherapp/data/ai/OutfitRecommendationRecommenderGemini.kt @@ -1,4 +1,4 @@ -package com.github.odaridavid.weatherapp.ui.home +package com.github.odaridavid.weatherapp.data.ai import com.github.odaridavid.weatherapp.BuildConfig import com.google.ai.client.generativeai.GenerativeModel @@ -6,7 +6,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf import javax.inject.Inject -class AIOutfitRecommendation @Inject constructor() { +class OutfitRecommendationRecommenderGemini @Inject constructor() { private val outfitsModel by lazy { GenerativeModel( diff --git a/app/src/main/java/com/github/odaridavid/weatherapp/data/ai/OutfitRecommendationRecommenderOpenAI.kt b/app/src/main/java/com/github/odaridavid/weatherapp/data/ai/OutfitRecommendationRecommenderOpenAI.kt new file mode 100644 index 0000000..ee5af9f --- /dev/null +++ b/app/src/main/java/com/github/odaridavid/weatherapp/data/ai/OutfitRecommendationRecommenderOpenAI.kt @@ -0,0 +1,38 @@ +package com.github.odaridavid.weatherapp.data.ai + + +import com.aallam.openai.api.chat.ChatCompletionRequest +import com.aallam.openai.api.chat.ChatMessage +import com.aallam.openai.api.chat.ChatRole +import com.aallam.openai.api.model.ModelId +import com.aallam.openai.client.OpenAI +import com.github.odaridavid.weatherapp.BuildConfig +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import javax.inject.Inject + +class OutfitRecommendationRecommenderOpenAI @Inject constructor() { + + private val openAi by lazy { + OpenAI(token = BuildConfig.OPEN_AI_KEY) + } + + suspend fun generateOutfitRecommendation(temperature: String): Flow { + // TODO implement for language changes + val prompt = "What would be a nice outfit for $temperature weather?" + val chatCompletionRequest = ChatCompletionRequest( + model = ModelId("gpt-3.5-turbo"), + messages = listOf( + ChatMessage( + role = ChatRole.Assistant, + content = prompt + ) + ) + ) + val completion = openAi.chatCompletion(chatCompletionRequest) + + val response = completion.choices.first().message.content + return flowOf(response) + } + +} diff --git a/app/src/main/java/com/github/odaridavid/weatherapp/ui/home/HomeScreen.kt b/app/src/main/java/com/github/odaridavid/weatherapp/ui/home/HomeScreen.kt index 012f76f..ccf1d09 100644 --- a/app/src/main/java/com/github/odaridavid/weatherapp/ui/home/HomeScreen.kt +++ b/app/src/main/java/com/github/odaridavid/weatherapp/ui/home/HomeScreen.kt @@ -59,6 +59,15 @@ fun HomeScreen( if (state.errorMessageId != null) { ErrorScreen(state.errorMessageId, onTryAgainClicked) } else { + state.recommendation?.let { recommendation -> + MediumBody( + text = recommendation, + modifier = Modifier + .fillMaxWidth() + .padding(WeatherAppTheme.dimens.medium), + textAlign = TextAlign.Center + ) + } state.weather?.current?.let { currentWeather -> CurrentWeatherWidget(currentWeather = currentWeather) } ?: run { diff --git a/app/src/main/java/com/github/odaridavid/weatherapp/ui/home/HomeViewModel.kt b/app/src/main/java/com/github/odaridavid/weatherapp/ui/home/HomeViewModel.kt index ed79788..004c899 100644 --- a/app/src/main/java/com/github/odaridavid/weatherapp/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/github/odaridavid/weatherapp/ui/home/HomeViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.github.odaridavid.weatherapp.api.SettingsRepository import com.github.odaridavid.weatherapp.api.WeatherRepository +import com.github.odaridavid.weatherapp.data.ai.OutfitRecommendationRecommenderOpenAI import com.github.odaridavid.weatherapp.model.DefaultLocation import com.github.odaridavid.weatherapp.model.Result import com.github.odaridavid.weatherapp.model.SupportedLanguage @@ -14,6 +15,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import javax.inject.Inject @@ -21,7 +23,8 @@ import javax.inject.Inject @HiltViewModel class HomeViewModel @Inject constructor( private val weatherRepository: WeatherRepository, - private val settingsRepository: SettingsRepository + private val settingsRepository: SettingsRepository, + private val outfitRecommendationRecommenderOpenAI: OutfitRecommendationRecommenderOpenAI, ) : ViewModel() { private val _state = MutableStateFlow(HomeScreenViewState(isLoading = true)) @@ -70,6 +73,19 @@ class HomeViewModel @Inject constructor( when (result) { is Result.Success -> { val weatherData = result.data + viewModelScope.launch { + // TODO Do this someplace else? + val temperature = weatherData.current?.temperature.toString() + outfitRecommendationRecommenderOpenAI + .generateOutfitRecommendation(temperature = temperature) + .catch { e -> + e.printStackTrace() + } + .collect { recommendation -> + setState { copy(recommendation = recommendation) } + } + + } setState { copy( weather = weatherData, @@ -104,5 +120,6 @@ data class HomeScreenViewState( val language: SupportedLanguage = SupportedLanguage.ENGLISH, val weather: Weather? = null, val isLoading: Boolean = false, + val recommendation: String? = null, @StringRes val errorMessageId: Int? = null ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3cead5e..86391c5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -40,6 +40,7 @@ androidx-test-rules = "1.5.0" core-ktx = "1.5.0" coroutines = "1.8.0" gemini = "0.2.2" +openai = "3.7.0" [libraries] activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" } @@ -91,6 +92,7 @@ android-test-runner = { module = "androidx.test:runner", version.ref = "androidx android-test-rules = { module = "androidx.test:rules", version.ref = "androidx-test-rules" } test-core-ktx = { group = "androidx.test", name = "core-ktx", version.ref = "core-ktx" } gemini = { module = "com.google.ai.client.generativeai:generativeai", version.ref = "gemini" } +openai = { module = "com.aallam.openai:openai-client", version.ref = "openai" } [plugins] com-android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" }