Continuing the Compose Multiplatform Journey: Weather and AI at Your Fingertips

IN THIS ARTICLE:

SPREAD THE WORD:

7AM In The Morning

You hit snooze too many times.

Rain’s hammering down like the sky’s personally offended by your morning. Your smartwatch pings: “Grab the boots. Ditch the white shirt.”A buzz from your pocket: “Pack an umbrella – storms clearing by lunch.”

Magic? Nah, just what happens when your AI assistant actually pays attention to the world outside.

Introduction: Where We Left Off and Where We’re Heading Now

Last time, we talked big: the exciting vision of building a smart AI assistant using Compose Multiplatform (CMP). We explored CMP’s power to create stunning UIs  across Android, iOS, desktop, web, and even wearables, all from a single Kotlin codebase. The objective was clear: an intelligent companion, unified across devices, designed to simplify daily life.

Now comes the next step: making our assistant truly intelligent by connecting it to the real world. This is the first chapter in our “Foundation” series – where we’ll systematically build the core capabilities that transform a simple app into an intelligent companion.

Environmental Awareness: The Big Picture

A smart assistant should understand its environment – weather conditions, location context, calendar events, and personal preferences. This comprehensive awareness is what transforms a simple app into an intelligent companion.

Our Starting Point: Weather-Based Clothing Advice

For this implementation, we’re focusing on one specific but practical capability: intelligent clothing recommendations based on real-time weather data.

We’ll integrate weather APIs with Gemini AI to create an assistant that understands current conditions and suggests what to wear accordingly. It’s a focused approach that delivers immediate value while establishing the foundation for more sophisticated features.

Ready to make your assistant weather-smart? Let’s dive into the technical details.

Extended AI Assistant Architecture: Connecting to the Real World

Our initial AI assistant concept aimed for a robust core, focusing on future conversational abilities and consistent UI over all platforms. To fulfill its promise as an intelligent, anticipatory companion, it first needs to perceive and react to its environment. This is where we start building its “awareness.”

The goal for this stage of our assistant is practical yet powerful: imagine our future AI not just answering questions, but proactively telling you, based on the real weather outside, what outfit might be best for your day. This capability transforms a concept into a truly insightful and useful application.

To begin building this awareness, we’re focusing on two core architectural additions to our Compose Multiplatform project:

  1. The Weather API Network Module: This module will be our app’s “eyes” on the outside world. It’s designed to fetch up-to-the-minute weather conditions—like temperature, precipitation, and wind—from a chosen external weather service.
  2. The Gemini AI Integration Module: This is where the initial spark of our assistant’s “intelligence” will reside. We’ll feed the raw weather data into the Gemini AI model. Gemini will then process this information, combined with carefully crafted prompts, to generate natural language suggestions for appropriate attire.

The planned data flow for this new functionality is straightforward: our assistant first gets the user’s location (currently just a hardcoded value). This location then goes to the Weather API to retrieve current weather data. That weather data, along with specific instructions, is then sent to the Gemini AI. Gemini processes this input and returns smart clothing recommendations. Finally, these AI-generated suggestions are seamlessly displayed within our Compose Multiplatform UI. This structured approach is how we’re starting to build our intelligent assistant, one smart feature at a time.

Technical Deep Dive: Integrating the Weather API

To imbue our assistant with real-world awareness, our first step was to integrate a reliable weather data source. For this, we chose OpenWeatherMap due to its widespread adoption and straightforward API. Our objective was simple: fetch current weather conditions for a specified city.

To handle our network requests, we leveraged Ktor Client, a powerful and flexible HTTP client specifically designed for Kotlin Multiplatform. For deserializing the JSON responses into usable Kotlin objects, we opted for kotlinx.serialization, which integrates seamlessly with Ktor.

Our approach to fetching data involved a direct API call to OpenWeatherMap’s current weather endpoint. Here’s a simplified look at the request:

As you can see, we pass the city name (using the q parameter) and our weatherApiKey as essential parameters. The q parameter is a common convention in API design, serving as a shorthand for “query.” In this case, it tells the OpenWeatherMap API to search for weather data based on the city name we provide.

Upon receiving a successful response, OpenWeatherMap provides a JSON payload containing various weather details. To make this data easily accessible and type-safe in our Kotlin code, we defined several data classes using kotlinx.serialization annotations:

This clear data modeling allows us to easily extract essential information like temperature (temp), humidity (humidity), and the weather’s main condition (main) and description.

For handling the asynchronous nature of network calls, we embraced Kotlin Coroutines. Our loadWeather function demonstrates this, utilizing suspend fun within a viewModelScope.launch block. This approach allows us to perform long-running network operations without blocking the main thread, keeping our UI smooth and responsive.

Our UI state is managed using a MutableStateFlow that exposes an immutable StateFlow to the UI, ensuring a reactive and predictable data flow. We’ve defined a sealed class called WeatherUiState to represent the different stages of our data fetching process:

Currently, the error handling is a basic catch block that updates the _uiState to Error. In future iterations, we’ll refine this to provide more granular error messages and specific handling for different failure scenarios, such as network timeouts or API key issues. This setup efficiently fetches and processes weather data, preparing it for the next crucial step: feeding it into our Gemini AI for intelligent suggestions.

Technical Deep Dive: Intelligent Wardrobe with Gemini AI

With weather data now flowing into our application, the next crucial step is to infuse intelligence: leveraging Gemini AI to translate raw meteorological figures into practical, personalized clothing advice. 

For this, we decided to interact directly with the Gemini API endpoints, specifically utilizing the gemini-1.5-flash model for its balance of speed and capability.

Our setup points to the Google Generative Language API’s base URL:

The core of our AI integration lies in “prompt engineering” – crafting the perfect input for Gemini to generate relevant suggestions. We designed a clear and concise prompt that sets Gemini’s role and provides it with the necessary weather context. Here’s a look at our prompt structure:

This prompt explicitly tells Gemini to act as a personal stylist, feeds it the city, temperature, and weather description, and then requests a single, practical clothing suggestion.

The API call itself is handled by a suspend fun that constructs the request body, sends it via our Ktor client, and processes the response:

We utilize kotlinx.serialization to model Gemini’s complex JSON response into clear Kotlin data classes:

After successfully making the API call, we extract the generated text from the response.candidates list. For now, we simply display the text provided by Gemini directly to the user, showcasing its immediate suggestion. Our WeatherUiState.Success(val geminiResult: String) will hold this generated advice, ready for presentation.

While our current error handling for AI calls is basic – a simple fallback message if a response isn’t generated – this setup effectively brings the power of Gemini AI into our Compose Multiplatform application, transforming raw weather data into intelligent, actionable fashion advice. This marks a significant leap towards our truly smart AI assistant.

Architectural Considerations and Development Challenges

Building our AI assistant on Compose Multiplatform necessitates solid architectural decisions. We’ve adopted an MVVM (Model-View-ViewModel) pattern underpinned by a Clean Architecture approach. This is evident in our WeatherViewModel, which manages the UI state (via StateFlow) and delegates complex logic to Use Cases (GetWeatherUseCase, GetDressingAdviceUseCase) residing in our domain layer. This separation ensures testable and maintainable code.

For asynchronous operations (weather and Gemini AI API calls), Kotlin Coroutines are essential. We use viewModelScope.launch to run these tasks in the background, keeping the UI fluid and responsive.

Error handling is an ongoing challenge. While we currently use a generic catch (e: Exception) to update WeatherUiState.Error, our layered architecture allows for future refinement. We can introduce more granular error types (e.g., NetworkError, CityNotFound, GeminiContentBlocked) from the data layer to the domain and then to the ViewModel, providing more precise user feedback.

Regarding optimization and performance, while not yet fully implemented, caching for weather data and rate-limiting for both APIs (OpenWeatherMap and Gemini) are crucial long-term. Our repository layer structure facilitates these strategies.

Testing is significantly simplified by our architecture. Unit-tests are easy to write for use-cases, mappers, and ViewModel logic, ensuring reliability.

These architectural considerations guide our project’s development, transforming the AI assistant vision into a robust and scalable application across multiple platforms.

Conclusion: The Next Steps in Your Smart Journey

We’ve just taken significant strides in transforming our AI assistant vision into a tangible reality. By successfully integrating a Weather API and Gemini AI, we’ve built the foundation for an assistant that’s not only conversational, but also keenly aware of its user’s immediate environment. This isn’t just about showing the weather; it’s about delivering contextually intelligent advice, all delivered seamlessly across any device thanks to Compose Multiplatform.

This phase of development vividly demonstrates CMP’s power beyond just UI. It showcases its capability to build complex, data-driven applications that integrate external services and advanced AI models effectively. We’re seeing our initial dream take shape, proving how shared logic genuinely accelerates development for intelligent, multiplatform experiences.

What’s next for our AI assistant? The possibilities are immense. We’re already envisioning:

  • Calendar Integration: Advising not just on weather, but on outfits suitable for specific events.
  • Learning Preferences: Allowing the AI to learn individual style choices for even more personalized suggestions.
  • Proactive Notifications: Imagine our assistant prompting you to grab an umbrella before the first drop of rain.

We’ve only scratched the surface of what’s possible, and honestly, that’s the exciting part. Our adventure with Compose Multiplatform and AI is just getting started, and we’d love for you to join us on this journey. Go ahead, play around with the code, break things, fix them, and see what cool stuff you can build. These powerful technologies are just waiting for someone like you to turn them into something amazing. Happy coding!

Be the first one to learn about new Victory openings.

Subscribe to our newsletter and keep up with the new career opportunities in our evergreen engineering square. We promise to send only relevant information, no fluff included.

Interested in more?
Here are some of our moments.

Shopping Basket