Talk to Me, TinyLLaMA: Build a Web Voice Assistant with Django

✨ Why Did We Edit chat.html Like This?

In our previous blog, our chatbot could only read text that we typed in manually.

But let’s be real β€”

If I can talk to Siri and Alexa, why not to my own bot? 😎

So in this blog, we upgraded chat.html to turn it into a mini voice assistant β€” both listener and speaker πŸŽ€πŸ—£οΈ


πŸ’‘ What We Added and Why:

βœ… 1. Mic Button with JavaScript

We created a cute little 🎀 button that floats at the bottom-right corner of the screen.

When clicked:

  • It starts listening to your voice using SpeechRecognition

  • Converts your speech to text

  • Puts it right into the input box like ✨magic✨

No typing needed!


βœ… 2. Text-to-Speech Response

After the bot replies, we added a script that:

  • Grabs the bot’s response from Django ({{ response }})

  • Uses speechSynthesis to speak it aloud

  • Now your bot can talk back to you like a real assistant πŸ§ πŸ’¬

  • Updated chat.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <title>Chatbot</title>
      <style>
      body {
          font-family: Arial, sans-serif;
          background-color: #f2f2f2;
          margin: 0;
          padding: 0;
          height: 100vh;
      }
    
      .robot-btn {
          position: fixed;
          bottom: 20px;
          right: 20px;
          background: #0d6efd;
          border: none;
          border-radius: 50%;
          width: 60px;
          height: 60px;
          cursor: pointer;
          font-size: 30px;
          color: white;
          box-shadow: 0 2px 8px rgba(0,0,0,0.3);
          z-index: 9999;
      }
    
      .chat-popup {
          position: fixed;
          bottom: 90px;
          right: 20px;
          width: 350px;
          max-width: 90%;
          background: white;
          border-radius: 10px;
          box-shadow: 0 0 10px rgba(0,0,0,0.3);
          display: none;
          flex-direction: column;
          overflow: hidden;
          z-index: 9998;
      }
    
      .header {
          background: #0d6efd;
          color: #fff;
          padding: 10px;
          text-align: center;
          font-weight: bold;
          position: relative;
      }
    
      .end-btn {
          position: absolute;
          top: 5px;
          right: 8px;
          background: transparent;
          border: none;
          font-size: 18px;
          color: white;
          cursor: pointer;
      }
    
      .chat-history {
          flex: 1;
          padding: 10px;
          max-height: 300px;
          overflow-y: auto;
      }
    
      .message {
          margin: 5px 0;
          display: flex;
      }
      .message.user {
          justify-content: flex-end;
      }
      .message.bot {
          justify-content: flex-start;
      }
      .bubble {
          max-width: 70%;
          padding: 8px 12px;
          border-radius: 15px;
          font-size: 14px;
          line-height: 1.4;
      }
      .message.user .bubble {
          background-color: #0d6efd;
          color: #fff;
          border-bottom-right-radius: 0;
      }
      .message.bot .bubble {
          background-color: #d9edf8;
          color: #333;
          border-bottom-left-radius: 0;
      }
    
      .input-area {
          display: flex;
          border-top: 1px solid #ccc;
      }
      .input-area input {
          flex: 1;
          padding: 10px;
          border: none;
          outline: none;
      }
      .input-area button {
          background: #0d6efd;
          color: white;
          border: none;
          padding: 0 15px;
          cursor: pointer;
          font-size: 18px;
      }
      .input-area button:hover {
          background: #0b5ed7;
      }
      </style>
      </head>
      <body>
    
      <!-- Floating Robot Button -->
      <button class="robot-btn">πŸ€–</button>
    
      <!-- Chat Popup -->
      <div class="chat-popup" id="chatPopup">
          <div class="header">
              Chat with the Bot
              <button class="end-btn" id="endBtn">❌</button>
          </div>
          <div class="chat-history" id="chatHistory">
              {% if question %}
              <div class="message user"><div class="bubble">{{ question }}</div></div>
              {% endif %}
              {% if response %}
              <div class="message bot"><div class="bubble">{{ response }}</div></div>
              {% endif %}
          </div>
          <form method="post" class="input-area">
              {% csrf_token %}
              <input type="text" name="question" placeholder="Type a message..." autocomplete="off" id="textInput">
              <button type="submit">✏️</button>
          </form>
      </div>
    
      <script>
      const robotBtn = document.querySelector('.robot-btn');
      const chatPopup = document.getElementById('chatPopup');
      const textInput = document.getElementById('textInput');
      const form = document.querySelector('form');
      const chatHistory = document.getElementById('chatHistory');
      const endBtn = document.getElementById('endBtn');
    
      let synth = window.speechSynthesis;
    
      // Show/hide chat popup
      robotBtn.addEventListener('click', (e) => {
          chatPopup.style.display = chatPopup.style.display === 'flex' ? 'none' : 'flex';
          e.stopPropagation(); 
      });
    
      // Close on outside click
      document.addEventListener('click', (e) => {
          if (!chatPopup.contains(e.target) && !robotBtn.contains(e.target)) {
              chatPopup.style.display = 'none';
          }
      });
    
      // End button click β€” also stop speech
      endBtn.addEventListener('click', () => {
          chatPopup.style.display = 'none';
          if (synth.speaking) {
              synth.cancel();  // πŸ›‘ Stop the bot from speaking
          }
      });
    
      // Add mic button
      const micBtn = document.createElement('button');
      micBtn.type = "button";
      micBtn.innerText = "🎀";
      micBtn.style.background = "#0d6efd";
      micBtn.style.color = "#fff";
      micBtn.style.border = "none";
      micBtn.style.cursor = "pointer";
      micBtn.style.fontSize = "18px";
      micBtn.style.marginLeft = "5px";
      form.appendChild(micBtn);
    
      let recognition;
      let voiceTimeout;
    
      micBtn.addEventListener('click', () => {
          if (!('webkitSpeechRecognition' in window)) {
              alert("Voice not supported 😒.");
              return;
          }
    
          recognition = new webkitSpeechRecognition();
          recognition.lang = "en-US";
          recognition.continuous = false;
          recognition.interimResults = false;
    
          recognition.start();
    
          recognition.onresult = function (event) {
              const transcript = event.results[0][0].transcript;
              textInput.value = transcript;
    
              if (voiceTimeout) clearTimeout(voiceTimeout);
              voiceTimeout = setTimeout(() => {
                  form.submit();
              }, 3000);
          };
    
          recognition.onerror = function (event) {
              alert("Speech error: " + event.error);
          };
      });
    
      // Bot speaks its response
      const botResponse = `{{ response|escapejs }}`;
      if (botResponse) {
          const utterance = new SpeechSynthesisUtterance(botResponse);
          utterance.lang = "en-US";
          synth.speak(utterance);
      }
      </script>
    
      </body>
      </html>
    

    🌈 Together, These Two Changes Make It...

    A real web-based voice assistant, built with
    ❀️ Django + πŸŽ™οΈ Web Speech API + πŸ¦™ LangChain + ✨ You!

    And the best part?
    Still no APIs, no fees, no tokens β€” it’s all local and yours πŸŽ€

  • Part 4 is gonna be extra magical β€” time to make your bot remember, personalize, and feel more like your own little assistant friend πŸŽ€πŸ§ 

0
Subscribe to my newsletter

Read articles from Sudharshini Jothikumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sudharshini Jothikumar
Sudharshini Jothikumar

I am Sudharshini, a dynamic force in the world of technology and creativity, currently pursuing my MSc in Software Systems. With a passion for problem-solving, I have not only honed my skills but emerged victorious in numerous hackathons, showcasing my prowess in the ever-evolving realm of software development. Beyond the lines of code, I am also a wordsmith, having penned and published two captivating books that reflect my diverse interests. My ability to weave narratives demonstrates a depth of creativity that extends beyond the digital domain. I am also a national-level champion in both Silambam and Adimurai, showcasing my physical prowess and discipline. Whether it's mastering the intricacies of software architecture or gracefully wielding traditional weapons, I embodied a perfect blend of the modern and the traditional. In a world where versatility is key, I stand out as a multifaceted individual, seamlessly navigating the realms of technology, literature, and martial arts with finesse. My journey is not just a narrative of achievements but a testament to the limitless possibilities that arise when one embraces a holistic approach to life.