AI-Powered Chat Application using Flutter and Google’s Gemini API

Haris Bin Nasir Avatar

·

·

The integration of AI capabilities within mobile applications offers a range of exciting opportunities. One such example is creating a chat app that leverages the power of Google’s Gemini API and Flutter. This tutorial will guide you through the process, from setting up the project to implementing functionalities for text and image-based interactions with the Gemini API.

In this tutorial, we will build a comprehensive AI-powered chat application using Flutter and Google’s Gemini API. We’ll cover everything from project setup to coding, ensuring a seamless experience for the end-user.

If you prefer watching a video tutorial here is a link to that.

Setting Up the Project

Adding Dependencies

To get started with the “gemini app flutter,” you need to add the relevant dependencies to your Flutter project. These include flutter_gemini, image_picker, and dash_chat_2 packages. These packages will facilitate communication with the Gemini API, media selection from the device gallery, and rendering the chat interface respectively.

  1. flutter_gemini: This package will enable us to interact with the Google Gemini API effortlessly. To get the dependency click here.
  2. image_picker: This package allows us to pick images from the device’s gallery. To get the dependency click here.
  3. dash_chat_2: This package provides a comprehensive UI for chat applications. To get the dependency click here.

Add the following dependencies in your pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  flutter_gemini: ^2.0.4
  image_picker: ^1.1.2
  dash_chat_2: ^0.0.21  

Run flutter pub get to get the dependencies.

flutter pub get

Getting the Gemini API Key

To interact with Google’s Gemini API, you need an API key. Here’s how to get it:

  • Google offers a generous free tier with unlimited requests, limited to 60 requests per minute. For more than 60 requests per minute, you might need to opt for a pay-as-you-go plan.

Steps to create an API key:

  • On the Google AI for Developers page, click on the “Learn more about the Gemini API” button.
  • Next, click on “Get API key in Google AI Studio”.
  • Click on the “Get API Key” button positioned on the top left of the screen
  • Click on the “Create API” button and select a project to generate an API.

Store the API key securely. Create a new file named constants.dart in your lib folder and add your API key:

const String GEMINI_API_KEY = 'your_api_key_here';

Initializing the Gemini Instance

After obtaining the API key, initialize the Gemini instance in the main file:

import 'package:flutter/material.dart';
import 'package:flutter_gemini/flutter_gemini.dart';
import 'constants.dart';

void main() {
  final gemini = Gemini.instance;
  gemini.init(apiKey: GEMINI_API_KEY);
  runApp(MyApp());
}

Ensure you import necessary packages and initialize the Gemini instance using the API key stored in constants.dart.

Creating the UI

Building the Home Page

Start by creating a stateful widget for the home page and setting up a basic scaffold structure.

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Gemini Chat")),
      body: buildUI(),
    );
  }

  Widget buildUI() {
    // UI building code will go here.
  }
}

Setting Up the App Bar

For a better user experience, configure the app bar with a custom title.

appBar: AppBar(
  title: Text("Gemini Chat"),
),

Rendering the DashChat Widget

Use the DashChat widget to implement the chat interface. Define the current user and the Gemini user for differentiation between sent and received messages.

import 'package:dash_chat_2/dash_chat_2.dart';

class _HomePageState extends State<HomePage> {
  final ChatUser currentUser = ChatUser(
    id: '0',
    firstName: 'User',
  );

  final ChatUser geminiUser = ChatUser(
    id: '1',
    firstName: 'Gemini',
    avatar: 'profile_image_url',
  );

  List<ChatMessage> messages = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Gemini Chat")),
      body: DashChat(
        currentUser: currentUser,
        onSend: sendMessage,
        messages: messages,
      ),
    );
  }

  void sendMessage(ChatMessage chatMessage) {
    // Logic for sending messages will go here.
  }
}

Implementing Text Chat

Handling Send Message Events

When the user sends a message, add their message to the chat and simultaneously send it to the Gemini API:

void sendMessage(ChatMessage chatMessage) {
  setState(() {
    messages.insert(0, chatMessage);
  });
  // Handle sending message to Gemini API
}

Streaming Gemini’s Response

To provide a seamless chat experience, handle real-time responses from the Gemini API:

void sendMessage(ChatMessage chatMessage) {
  setState(() {
    messages.insert(0, chatMessage);
  });

  try {
    final responseStream = gemini.streamGenerateContent(
      text: chatMessage.text,
    );

    responseStream.listen((event) {
      if (messages.first.user.id == geminiUser.id) {
        setState(() {
          messages.first.text += event.content.parts.fold(
            '',
            (previousValue, element) => previousValue + element.text,
          );
        });
      } else {
        setState(() {
          messages.insert(0, ChatMessage(
            text: event.content.parts.fold(
              '',
              (previousValue, element) => previousValue + element.text,
            ),
            user: geminiUser,
          ));
        });
      }
    });
  } catch (error) {
    print("Error in streaming response: $error");
  }
}

Implementing Image Chat

Adding an Image Picker Button

Modify the input options to include an image picker button, allowing users to pick an image from their gallery:

DashChat(
  currentUser: currentUser,
  onSend: sendMessage,
  messages: messages,
  inputOptions: InputOptions(
    trailing: [
      IconButton(
        icon: Icon(Icons.image),
        onPressed: sendMediaMessage,
      ),
    ],
  ),
)

Implementing the Send Media Message Function

Define a function to handle picking an image and sending it as a message:

Future<void> sendMediaMessage() async {
  final ImagePicker _picker = ImagePicker();
  final XFile? file = await _picker.pickImage(source: ImageSource.gallery);

  if (file != null) {
    final message = ChatMessage(
      user: currentUser,
      createdAt: DateTime.now(),
      text: "Describe this picture",
      medias: [
        ChatMedia(
          url: file.path,
          type: MediaType.image,
        )
      ],
    );

    sendMessage(message);
  }
}

Sending the Image to Gemini API

Extend the sendMessage method to handle image messages and pass the image bytes to the Gemini API:

void sendMessage(ChatMessage chatMessage) {
  setState(() {
    messages.insert(0, chatMessage);
  });

  if (chatMessage.medias.isNotEmpty) {
    final List<int> imageBytes = File(chatMessage.medias.first.url!).readAsBytesSync();

    final responseStream = gemini.streamGenerateContent(
      text: chatMessage.text,
      images: [imageBytes],
    );

    responseStream.listen((event) {
      // Handle response from Gemini API
    });
  } else {
    final responseStream = gemini.streamGenerateContent(
      text: chatMessage.text,
    );

    responseStream.listen((event) {
      // Handle response from Gemini API
    });
  }
}

Handling Errors and Exceptions

Implement error handling to ensure your application runs smoothly despite any potential API issues:

void sendMessage(ChatMessage chatMessage) {
  setState(() {
    messages.insert(0, chatMessage);
  });

  try {
    // Existing API call logic
  } catch (error) {
    print("Error occurred: $error");
  }
}

Testing the Application

Testing with Text Prompts

Ensure that text-based interactions with the Gemini API work as expected. Send various queries and verify the responses are accurate and real-time.

Testing with Image Prompts

Check the application’s ability to handle image-based queries. Pick images and observe whether the Gemini API can accurately describe the images.

Limitations of the Gemini API

Understand that the Gemini API has a knowledge cutoff of April 2023. It cannot provide real-time information beyond this date.

Finalizing the Application

Checking for Any Remaining Issues

Before concluding, test the application thoroughly to identify any remaining issues. Address any bugs or performance issues to ensure a polished final product.

Potential Improvements and Future Features

Consider implementing additional features to enhance the user experience. Potential improvements include:

  • Adding support for voice queries.
  • Implementing user authentication.
  • Enhancing error handling with user-friendly messages.

Resources and Further Reading

Here are some official documentation and resources for further reading:

By following this comprehensive guide, you will have a functional AI-powered chat application using Flutter and Google’s Gemini API. This application demonstrates the potential for integrating AI capabilities into mobile apps, paving the way for more innovative and interactive user experiences.

Get Source Code for free:

Conclusion

Congratulations! By following this guide, you’ve built a fully functional AI-powered chat app using Flutter and Google’s Gemini API. This project not only highlights the exciting possibilities of integrating AI into mobile apps but also demonstrates how you can create a more engaging and interactive user experience.

With features like text and image-based interactions, your app can handle a variety of user inputs, providing real-time responses and making the chat experience feel more dynamic and personalized. This is just the beginning—there are plenty of opportunities to further enhance your app, whether by adding voice queries, improving error handling, or incorporating user authentication.

This journey into AI-powered mobile development opens up a world of innovative possibilities. Keep experimenting and pushing the boundaries of what your app can do.

Happy coding!

Leave a Reply

Your email address will not be published. Required fields are marked *