Build your chatbot with the power of Gemini API using Django

Feb. 18, 2024


0
14 min read
2.23K

In today's digital age, chatbots have become an indispensable tool for businesses to engage with their customers and automate various tasks. With the advancement of natural language processing (NLP) technologies, it's now easier than ever to create your chatbot using powerful APIs like Gemini.

Gemini is an open-source NLP API that provides a robust set of features for building intelligent chatbot experiences. In this article, we'll guide you through the step-by-step process of creating a custom chatbot using Gemini and Django, a popular Python web framework.

Prerequisites

Before diving into the development process, you need to have a basic understanding of Python and some experience with web development. Additionally, it is recommended to have a development environment set up, including Python, pip, and a text editor or IDE.

Step 1: Install Django & Google Generativeai

The first step in building a chatbot with Django is to install the framework and install Google Generativeai. You can do this by using the pip package manager with the following command:

pip install Django

pip install google-generativeai

Step 2: Create a Django Project

Once you have installed Django & Google Generativeai, you can create a new project by using the following command:

django-admin startproject chatbot

This will create a new directory called chatbot that contains the basic structure of your Django project.

Step 3: Create a Django App

A Django project can consist of multiple apps, each of which can handle a specific functionality of the website. To create a new app, navigate to the project directory and run the following command:

python manage.py startapp chat_app

This will create a new directory with the same name as your app, containing all the necessary files to run a Django app. Your structure will look like this:

├── chat_app
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── chatbot
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-310.pyc
│   │   └── settings.cpython-310.pyc
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py

 Step 4: Add your app to the project's settings

Your project directory will have a settings.py file, open it and mention the app like this:

# Application definition

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "chat_app",
]

LOGIN_URL = "/admin/login/"

In this Django application, the INSTALLED_APPS variable defines the list of Django applications that are installed and available for use in the project. Each application listed here can contain models, views, templates, and other components specific to its functionality.

Additionally, the LOGIN_URL setting specifies the URL where users should be redirected if they are not logged in and try to access a view that requires authentication. In this case, it's set to "/admin/login/", meaning unauthorized users will be redirected to the admin login page if they attempt to access a protected view.

Step 5: Define Models

Models are the backbone of a Django website, representing the data that will be stored in the database. To define models, open the models.py file in your app directory and add the following code:

from django.db import models
from django.contrib.auth.models import User

# Create your models here.


class ChatBot(models.Model):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="GeminiUser", null=True
    )
    text_input = models.CharField(max_length=500)
    gemini_output = models.TextField(null=True, blank=True)
    date = models.DateTimeField(auto_now_add=True, blank=True, null=True)

    def __str__(self):
        return self.text_input

Here I have created only 4 fields, which you can add as per your requirement.

Step 6: Migrate the Database

Once you have defined your models, you need to create the database tables to store the data. You can do this by running the following command:

python manage.py makemigrations
python manage.py migrate

You should also create a superuser because we will only allow logged-in users to do this.

python manage.py createsuperuser

Step 7: Create Views

Views handle the logic of the chatbot and render the template, which is the HTML file that displays the content to the user. To create views, open the views.py file in your app directory and add the following code:

from django.shortcuts import render, reverse
from django.contrib.auth.decorators import login_required
from .models import ChatBot
from django.http import HttpResponseRedirect, JsonResponse
import google.generativeai as genai

# Create your views here.
# add here to your generated API key
genai.configure(api_key="YourAPI-Key")


@login_required
def ask_question(request):
    if request.method == "POST":
        text = request.POST.get("text")
        model = genai.GenerativeModel("gemini-pro")
        chat = model.start_chat()
        response = chat.send_message(text)
        user = request.user
        ChatBot.objects.create(text_input=text, gemini_output=response.text, user=user)
        # Extract necessary data from response
        response_data = {
            "text": response.text,  # Assuming response.text contains the relevant response data
            # Add other relevant data from response if needed
        }
        return JsonResponse({"data": response_data})
    else:
        return HttpResponseRedirect(
            reverse("chat")
        )  # Redirect to chat page for GET requests


@login_required
def chat(request):
    user = request.user
    chats = ChatBot.objects.filter(user=user)
    return render(request, "chat_bot.html", {"chats": chats})

Here is the summary of this code:

  1. Imports: The code imports necessary modules from Django, including shortcuts for rendering templates and reversing URLs, decorators for handling user authentication, and the ChatBot model representing chat interactions. Additionally, it imports the genai module to access the Google Generative AI API.

  2. Google Generative AI Configuration: The API key required to access the Google Generative AI API is configured using the genai module. Click here to generate your API key.

  3. ask_question View: This view is decorated with @login_required, ensuring that only authenticated users can access it. It handles both GET and POST requests. Upon receiving a POST request, the view extracts the user's input text, interacts with the Generative AI model to obtain a response, saves the input, output, and user information in the database using the ChatBot model, and returns the response data as a JSON object. In the case of a GET request, the user is redirected to the chat page.

  4. chat View: Similarly decorated with @login_required, this view retrieves all previous chat interactions associated with the current authenticated user from the database using the ChatBot model. It then renders these interactions within a template named "chat_bot.html" for the user to view.

  5. Template: The "chat_bot.html" template is responsible for presenting the user's past interactions with the chatbot in a visually intuitive and user-friendly manner, likely displaying the user's input along with the corresponding responses from the Generative AI model.

Step 8: Create Templates

We will create a template. To create this, we will create a folder named templates inside the directory of our chat_app. We will name it chat_bot.html which we have also mentioned in our views.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ChatBot</title>
    <!-- Font Awesome -->
<link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"
rel="stylesheet"
/>
<!-- Google Fonts -->
<link
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
rel="stylesheet"
/>
<!-- MDB -->
<link
href="https://cdnjs.cloudflare.com/ajax/libs/mdb-ui-kit/7.1.0/mdb.min.css"
rel="stylesheet"
/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.4.0/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.4.0/highlight.min.js"></script>
</head>
<body>

<style>
body {
    background-image: url("https://espere.in/static/images/chat.png");
    background-position: center center;
	background-repeat:  no-repeat;
	background-attachment: fixed;
	background-size:  cover;
    background-color: rgba(161, 161, 161, 0.108);
  }


#chat4 .form-control {
    border-color: transparent;
}

#chat4 .form-control:focus {
    border-color: transparent;
    box-shadow: inset 0px 0px 0px 1px transparent;
}

.divider:after,
.divider:before {
    content: "";
    flex: 1;
    height: 1px;
    background: #eee;
}
#scroll::-webkit-scrollbar{
    background-color: rgba(0, 0, 0, 0.108); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(5px);
    width: 0px;
    height: 0px;
    color: #eee;
}

pre::-webkit-scrollbar{
    background-color: rgba(0, 0, 0, 0.108); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(5px);
    width: 0px;
    height: 0px;
}

div {
    position: relative; /* Set position to relative for the container */
}

pre {
     overflow-x: scroll; /* Enable horizontal scrolling */
    width: 68vw;
  /* white-space: pre-wrap; Preserve line breaks */
}

pre button {
    position: absolute;
    top: 1px;
    left: calc(68vw - 2rem); /* Adjust the position of the button */
    font-size: 0.9rem;
    padding: 0.5rem; /* Changed to a positive value */
    background-color: rgb(50, 50, 50);
    border-radius: 50px;
    border: none;
}

.form{
    width: 100%;
}
#questionInput{
    background-color: rgba(253, 253, 253, 0.532); 
    -webkit-backdrop-filter: blur(8px); 
    backdrop-filter: blur(5px);
    border: 2px solid rgb(255, 255, 255);
    border-radius: 45px;
    height: 40px;
}

.tooltip-inner {
    background-color: rgb(100, 100, 100);
    border-radius: 2px;
    position: relative;
    padding: 2px 10px;
    font-size: small;
}

.tooltip-inner::before {
    content: "";
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%);
    border-width: 6px;
    border-style: solid;
    border-color: transparent transparent rgb(100, 100, 100) transparent;
}
#scroll {
        margin: 4px, 4px;
        padding: 4px;
        width: 100%;
        height: 57.0vh;
        overflow-x: auto;
        /* overflow-y: auto; */
        text-align: justify;
        /* border: 1px solid rgb(14, 119, 163); */
        border-radius: 3px;
    }
    #scroll::-webkit-scrollbar {
    width: 5px;
    height: 0px;
    }

    /* Track */
    #scroll::-webkit-scrollbar-track {
    box-shadow: inset 0 0 7px rgb(219, 219, 219);
    border-radius: 10px;
    }

    /* Handle */
    #scroll::-webkit-scrollbar-track {
    box-shadow: inset 0 0 7px rgb(255, 255, 255); 
    border-radius: 10px;
    }

    /* Handle */
    #scroll::-webkit-scrollbar-thumb {
    background: rgb(215, 215, 215); 
    border-radius: 10px;
    }

    /* Handle on hover */
    #scroll::-webkit-scrollbar-thumb:hover {
    background: rgb(159, 159, 159); 
    }
    pre {
            /* background-color: #dcdcdc; */
            padding: 1em;
            width: 100%;
            overflow-x: auto;
            border-radius: 5px;
            border: 1px solid #ddd;
        }

        code {
            font-family: 'Courier New', Courier, monospace;
            font-size: 14px;
        }
        .loader-container {
  display: flex;
  justify-content: center;
  align-items: center;
  margin-top: 5px;
  margin-bottom: 10px;
}
.loader {
  width: 120px;
  height: 20px;
  -webkit-mask: linear-gradient(90deg,#000 70%,#0000 0) left/20% 100%;
  background:
   linear-gradient(#000 0 0) left -25% top 0 /20% 100% no-repeat
   rgb(226, 229, 205);
  animation: l7 1s infinite steps(6);
}
@keyframes l7 {
    100% {background-position: right -25% top 0}
}00% {background-position: 0 0}
}
</style>
  
<div class="container">
    <div class="row">
    <div style="border-radius: 5px; background-color: rgba(161, 161, 161, 0.108); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(5px);" class="modal-content con mt-4 mb-4">
        <div style="background-color: rgba(161, 161, 161, 0.108); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(5px); border-radius: 5px 5px 0px 0px;" class="modal-header text-white shadow-5">
          <div class="my-3">
            <a class="text-dark" href="javascript:history.back()"><i type="button" data-mdb-dismiss="modal" style="font-size: 18px;" class="fas fa-arrow-left"></i></a>
            <img class="ms-2" src="https://espere.in/static/images/newlogo.png" alt="Header Image" style="border-radius: 50%; max-height: 35px; max-width: 50px;">
            <span class="ms-1 text-dark">ChatBot</span>
          </div>
          <a data-mdb-placement="bottom" data-mdb-toggle="tooltip" title="Reload" class="text-dark" href="{% url 'chat' %}"><i type="button" data-mdb-dismiss="modal" style="font-size: 18px;" class="fas fa-arrows-rotate"></i></a>
      </div>
        <div style="background-color: rgba(161, 161, 161, 0.108); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(5px);" class="modal-body">
          <div style="background-color: transparent;" id="chat4">
            <div id="scroll" class="card-body my-3" data-mdb-perfect-scrollbar="true"
              style="position: relative; height: 66vh">
              {% if chats %}
            {% for chat in chats %}
            <div id="chatCard">
                <div  class="d-flex flex-row justify-content-end mb-3">
                    <div>
                        <div style="background-color: #1b1b1b8e; font-size: smaller; border-radius: 20px 0px 20px 20px;" class="small p-2 me-2 mb-1 text-white ms-auto">{{ chat.text_input }}</div>
                    </div>
                    <img class="rounded-circle mb-1" src="https://espere.in/static/images/profile.webp"
                         alt="avatar 1" style="width: 40px; height: 100%;">
                </div>
                <div id="response_data" class="d-flex flex-row justify-content-start mb-3">
                    <img src="https://espere.in/static/images/newlogo.png"
                         alt="avatar 1" style="width:  40px; height: 100%;">
                    <div>
                        <div id="chatArea" class="small p-2 ms-2 mb-1 me-auto text-dark" style="background-color: #ffffffb8; font-size: smaller; border-radius: 0px 20px 20px 20px;">{{ chat.gemini_output | safe }}</div>
                    </div>
                </div>
              </div>
            {% endfor %}
              {% endif %}
            </div>
            <div class="loader-container">
              <div style="color: #242424b1;" class="d-flex align-items-center me-3" id="loading">
              </div>
            </div>
            <div class="card-footer text-muted d-flex justify-content-start align-items-center p-3">
              <img class="rounded-circle" src="https://espere.in/static/images/profile.webp"
                alt="avatar 3" style="width: 40px; height: 100%;">
                <form class="form" onsubmit="askQuestion(event)">
                    <input class="form-control ms-2" type="text" id="userText" name="text" placeholder="Ask your question">
                </form>                
              <span id="submitBtn" style="background-color: rgba(253, 253, 253, 0.532); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(5px)" type="submit" class="ms-3 link-danger btn btn-floating" href=""><i class="fas fa-paper-plane"></i></span>
            </div>
          </div>
        </div>
      </div>
</div>
</div>

<!-- MDB -->
<script
  type="text/javascript"
  src="https://cdnjs.cloudflare.com/ajax/libs/mdb-ui-kit/7.1.0/mdb.umd.min.js"
></script>
<!-- jquery -->
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/markdown-it/dist/markdown-it.min.js"></script>
     
<script>
    let chatCard = document.querySelector('#scroll');
    chatCard.scrollTop = chatCard.scrollHeight;

    document.addEventListener('DOMContentLoaded', function(){
        document.querySelector('#submitBtn').addEventListener('click', () => chat_ajax());
    });

    function myFunction() {
        document.getElementById("userText").disabled = true;
        document.querySelector('#userText').setAttribute('placeholder', 'Please wait, your result will come soon...');
    }
    function enableUserText() {
    // Enable the input field
    document.getElementById("userText").disabled = false;
    document.querySelector('#userText').setAttribute('placeholder', 'Ask your question');
}


    function chat_ajax() {
        const md = new markdownit({ html: true });
        let text = document.querySelector('#userText').value;
        let html = md.renderInline(text);
        let chatCard = document.querySelector('#scroll');
        
        // Append user's message to chat card
        chatCard.innerHTML += `
            <div class="d-flex flex-row justify-content-end mb-3">
                <div>
                    <div style="background-color: #1b1b1b8e; font-size: smaller; border-radius: 20px 0px 20px 20px;" class="small p-2 me-2 mb-1 text-white ms-auto">${text}</div>
                </div>
                <img class="rounded-circle mb-1" src="https://espere.in/static/images/profile.webp" alt="avatar 1" style="width: 40px; height: 100%;">
            </div>
        `;
        chatCard.scrollTop = chatCard.scrollHeight;
        console.log(text);

        document.querySelector('#userText').value = null;

        var loading = document.querySelector('#loading');
        myFunction();
        loading.innerHTML = `
            <div class="loader">
            </div>
        `;
        chatCard.scrollTop = chatCard.scrollHeight;
        $.ajax({
            type: 'POST',
            url: '/ask_question/',
            data: {
                'text': text,
                csrfmiddlewaretoken: '{{ csrf_token }}',
            },
            success: function(res) {
              var response = md.render(res.data.text); // Render Markdown content
              var chatCard = document.getElementById('scroll');
              var typingSpeed = 15; // Set the typing speed in milliseconds
              // Create response_data div
              var responseDataDiv = document.createElement('div');
              responseDataDiv.id = 'response_data';
              responseDataDiv.classList.add('d-flex', 'flex-row', 'justify-content-start', 'mb-3');
              chatCard.appendChild(responseDataDiv);
              
              // Create avatar image
              var avatarImg = document.createElement('img');
              avatarImg.src = "https://espere.in/static/images/newlogo.png";
              avatarImg.alt = "avatar 1";
              avatarImg.style.width = '40px';
              avatarImg.style.height = '100%';
              responseDataDiv.appendChild(avatarImg);
              
              // Create chatArea div
              var chatAreaDiv = document.createElement('div');
              chatAreaDiv.id = 'chatArea';
              chatAreaDiv.classList.add('small', 'p-2', 'ms-2', 'mb-1', 'me-auto', 'text-dark');
              chatAreaDiv.style.backgroundColor = '#ffffffb8';
              chatAreaDiv.style.fontSize = 'smaller';
              chatAreaDiv.style.borderRadius = '0px 20px 20px 20px';
              chatAreaDiv.innerHTML = response;
              responseDataDiv.appendChild(chatAreaDiv);
              // chatAreaDiv.innerHTML += response
              loading.innerHTML = '';
              chatCard.scrollTop = chatCard.scrollHeight;
              enableUserText();

          },


            error: function() {
                console.log("There was an error!");
            }
        });
    }
</script>

</body>
</html>

You can adjust it as per your requirement, I have designed it just basic, I am not good at JavaScript, but you can do it as per your requirement.

Step 9: Configure URLs

URLs define the mapping between the web address and the view that should be displayed. To configure URLs, you have to create a file named urls.py in chat_app and add your URLs inside it.

from django.urls import path
from . import views

urlpatterns = [
    path("", views.chat, name="chat"),
    path("ask_question/", views.ask_question, name="ask_question"),
]

You have to include this urls file in your base urls file which you will find in your project's directory.

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("chat_app.urls")), # include this
]

 This is the structure of the entire project:

├── chat_app
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-310.pyc
│   │   ├── admin.cpython-310.pyc
│   │   ├── apps.cpython-310.pyc
│   │   ├── models.cpython-310.pyc
│   │   ├── urls.cpython-310.pyc
│   │   └── views.cpython-310.pyc
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       ├── 0001_initial.cpython-310.pyc
│   │       └── __init__.cpython-310.pyc
│   ├── models.py
│   ├── templates
│   │   ├── chat_bot.html
│   │   └── chat_bot1.html
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── chatbot
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-310.pyc
│   │   ├── settings.cpython-310.pyc
│   │   ├── urls.cpython-310.pyc
│   │   └── wsgi.cpython-310.pyc
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── db.sqlite3
└── manage.py

Step 10: Run the Development Server

Finally, you can run the development server by running the following command in your terminal:

python manage.py runserver

Once the server is running, you can visit "http://127.0.0.1:8000/" in your web browser to view your chatbot application. You can make changes to the code and the changes will be automatically reflected on the website when you refresh the page.

Conclusion

In conclusion, developing your chatbot using the Gemini API in Django can be an exciting and rewarding endeavour. By leveraging the power of generative AI technology provided by the Gemini API, you can create a conversational interface that interacts with users naturally and intelligently.

Throughout this article, we have explored the process of integrating the Gemini API into a Django application to build a chatbot. We started by setting up the necessary environment and configuring the Gemini API with your API key. Then, we implemented views in Django to handle user input, interact with the Gemini AI model, and store chat interactions in the database.

By following the steps outlined in this article, you can create a robust chatbot application that offers users a seamless conversational experience. Furthermore, you have the flexibility to customize and expand the functionality of your chatbot to suit your specific requirements and preferences.

Overall, building a chatbot using the Gemini API in Django opens up a world of possibilities for enhancing user engagement, automating tasks, and providing personalized experiences. With the right approach and creativity, you can develop a sophisticated chatbot that adds value to your Django application and delights your users.

django Google API Assistant Gemini ChatBot Appreciate you stopping by my post! 😊

Add a comment


Note: If you use these tags, write your text inside the HTML tag.
Login Required
Author's profile
Profile Image

Abdulla Fajal

Django Developer

With 'espere.in' under my care, I, Abdulla Fajal, graciously invite your insights and suggestions, as we endeavour to craft an exquisite online experience together.