網頁設計實驗室

Web Design Laboratory

如何用 HTML CSS + JavaScript 建立免費的 Google Gemini API工作聊天機器人

Dec 19, 2024

↓程式碼演示在文章底部↓

取得免費的 Google Gemini API 金鑰

請造訪https://aistudio.google.com/app/apikey並建立新的 API 金鑰

建立工作聊天機器人的步驟

建立一個 index.html 文件。檔案名稱必須是index,副檔名是.html
建立一個 style.css 文件。檔案名稱必須是 style 且副檔名為 .css
建立一個 script.js 文件。檔案名稱必須是 script 且副檔名為 .js

將以下 HTML 程式碼新增至您的index.html檔案
 
        <html lang="en" dir="ltr">
        <head>
        <meta charset="utf-8">
        <title>Chatbot in JavaScript | CodingNepal</title>
        <link rel="stylesheet" href="style.css">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" />
    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@48,400,1,0" />
    <script src="script.js" defer></script>
    </head>
    <body>
    <button class="chatbot-toggler">
    <span class="material-symbols-rounded">mode_comment</span>
    <span class="material-symbols-outlined">close</span>
    </button>
    <div class="chatbot">
    <header>
    <h2>Chatbot</h2>
    <span class="close-btn material-symbols-outlined">close</span>
    </header>
    <ul class="chatbox">
    <li class="chat incoming">
    <span class="material-symbols-outlined">smart_toy</span>
    <p>Hi there <br>How can I help you today?</p>
    </li>
    </ul>
    <div class="chat-input">
    <textarea placeholder="Enter a message..." spellcheck="false" required></textarea>
    <span id="send-btn" class="material-symbols-rounded">send</span>
    </div>
    </div>
    </body>
    </html>

將以下 CSS 程式碼新增至您的檔案 style.css以設定登入表單的樣式

         /* Import Google font - Poppins */
          @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap');
          * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: "Poppins", sans-serif;
          }
          body {
            background: #E3F2FD;
          }
          .chatbot-toggler {
            position: fixed;
            bottom: 30px;
            right: 35px;
            outline: none;
            border: none;
            height: 50px;
            width: 50px;
            display: flex;
            cursor: pointer;
            align-items: center;
            justify-content: center;
            border-radius: 50%;
            background: #724ae8;
            transition: all 0.2s ease;
          }
          body.show-chatbot .chatbot-toggler {
            transform: rotate(90deg);
          }
          .chatbot-toggler span {
            color: #fff;
            position: absolute;
          }
          .chatbot-toggler span:last-child,
          body.show-chatbot .chatbot-toggler span:first-child  {
            opacity: 0;
          }
          body.show-chatbot .chatbot-toggler span:last-child {
            opacity: 1;
          }
          .chatbot {
            position: fixed;
            right: 35px;
            bottom: 90px;
            width: 420px;
            background: #fff;
            border-radius: 15px;
            overflow: hidden;
            opacity: 0;
            pointer-events: none;
            transform: scale(0.5);
            transform-origin: bottom right;
            box-shadow: 0 0 128px 0 rgba(0,0,0,0.1),
                        0 32px 64px -48px rgba(0,0,0,0.5);
            transition: all 0.1s ease;
          }
          body.show-chatbot .chatbot {
            opacity: 1;
            pointer-events: auto;
            transform: scale(1);
          }
          .chatbot header {
            padding: 16px 0;
            position: relative;
            text-align: center;
            color: #fff;
            background: #724ae8;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
          }
          .chatbot header span {
            position: absolute;
            right: 15px;
            top: 50%;
            display: none;
            cursor: pointer;
            transform: translateY(-50%);
          }
          header h2 {
            font-size: 1.4rem;
          }
          .chatbot .chatbox {
            overflow-y: auto;
            height: 510px;
            padding: 30px 20px 100px;
          }
          .chatbot :where(.chatbox, textarea)::-webkit-scrollbar {
            width: 6px;
          }
          .chatbot :where(.chatbox, textarea)::-webkit-scrollbar-track {
            background: #fff;
            border-radius: 25px;
          }
          .chatbot :where(.chatbox, textarea)::-webkit-scrollbar-thumb {
            background: #ccc;
            border-radius: 25px;
          }
          .chatbox .chat {
            display: flex;
            list-style: none;
          }
          .chatbox .outgoing {
            margin: 20px 0;
            justify-content: flex-end;
          }
          .chatbox .incoming span {
            width: 32px;
            height: 32px;
            color: #fff;
            cursor: default;
            text-align: center;
            line-height: 32px;
            align-self: flex-end;
            background: #724ae8;
            border-radius: 4px;
            margin: 0 10px 7px 0;
          }
          .chatbox .chat p {
            white-space: pre-wrap;
            padding: 12px 16px;
            border-radius: 10px 10px 0 10px;
            max-width: 75%;
            color: #fff;
            font-size: 0.95rem;
            background: #724ae8;
          }
          .chatbox .incoming p {
            border-radius: 10px 10px 10px 0;
          }
          .chatbox .chat p.error {
            color: #721c24;
            background: #f8d7da;
          }
          .chatbox .incoming p {
            color: #000;
            background: #f2f2f2;
          }
          .chatbot .chat-input {
            display: flex;
            gap: 5px;
            position: absolute;
            bottom: 0;
            width: 100%;
            background: #fff;
            padding: 3px 20px;
            border-top: 1px solid #ddd;
          }
          .chat-input textarea {
            height: 55px;
            width: 100%;
            border: none;
            outline: none;
            resize: none;
            max-height: 180px;
            padding: 15px 15px 15px 0;
            font-size: 0.95rem;
          }
          .chat-input span {
            align-self: flex-end;
            color: #724ae8;
            cursor: pointer;
            height: 55px;
            display: flex;
            align-items: center;
            visibility: hidden;
            font-size: 1.35rem;
          }
          .chat-input textarea:valid ~ span {
            visibility: visible;
          }
          @media (max-width: 490px) {
            .chatbot-toggler {
              right: 20px;
              bottom: 20px;
            }
            .chatbot {
              right: 0;
              bottom: 0;
              height: 100%;
              border-radius: 0;
              width: 100%;
            }
            .chatbot .chatbox {
              height: 90%;
              padding: 25px 15px 100px;
            }
            .chatbot .chat-input {
              padding: 5px 15px;
            }
            .chatbot header span {
              display: block;
            }
          }


將以下 JavaScript 程式碼新增至您的檔案script.js以啟用表單驗證

                         const chatbotToggler = document.querySelector(".chatbot-toggler");
            const closeBtn = document.querySelector(".close-btn");
            const chatbox = document.querySelector(".chatbox");
            const chatInput = document.querySelector(".chat-input textarea");
            const sendChatBtn = document.querySelector(".chat-input span");
            let userMessage = null; // Variable to store user's message
            const inputInitHeight = chatInput.scrollHeight;
            // API configuration
            const API_KEY = "PASTE-YOUR-API-KEY"; // Your API key here
            const API_URL = `https://generativelanguage.googleapis.com/v1/models/gemini-1.5-pro:generateContent?key=${API_KEY}`;
            const createChatLi = (message, className) => {
              // Create a chat <li> element with passed message and className
              const chatLi = document.createElement("li");
              chatLi.classList.add("chat", `${className}`);
              let chatContent = className === "outgoing" ? `<p></p>` : `<span class="material-symbols-outlined">smart_toy</span><p></p>`;
              chatLi.innerHTML = chatContent;
              chatLi.querySelector("p").textContent = message;
              return chatLi; // return chat <li> element
            }
            const generateResponse = async (chatElement) => {
              const messageElement = chatElement.querySelector("p");
              // Define the properties and message for the API request
              const requestOptions = {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ 
                  contents: [{ 
                    role: "user", 
                    parts: [{ text: userMessage }] 
                  }] 
                }),
              }
              // Send POST request to API, get response and set the reponse as paragraph text
              try {
                const response = await fetch(API_URL, requestOptions);
                const data = await response.json();
                if (!response.ok) throw new Error(data.error.message);
                
                // Get the API response text and update the message element
                messageElement.textContent = data.candidates[0].content.parts[0].text.replace(/\*\*(.*?)\*\*/g, '$1');
              } catch (error) {
                // Handle error
                messageElement.classList.add("error");
                messageElement.textContent = error.message;
              } finally {
                chatbox.scrollTo(0, chatbox.scrollHeight);
              }
            }
            const handleChat = () => {
              userMessage = chatInput.value.trim(); // Get user entered message and remove extra whitespace
              if (!userMessage) return;
              // Clear the input textarea and set its height to default
              chatInput.value = "";
              chatInput.style.height = `${inputInitHeight}px`;
              // Append the user's message to the chatbox
              chatbox.appendChild(createChatLi(userMessage, "outgoing"));
              chatbox.scrollTo(0, chatbox.scrollHeight);
              setTimeout(() => {
                // Display "Thinking..." message while waiting for the response
                const incomingChatLi = createChatLi("Thinking...", "incoming");
                chatbox.appendChild(incomingChatLi);
                chatbox.scrollTo(0, chatbox.scrollHeight);
                generateResponse(incomingChatLi);
              }, 600);
            }
            chatInput.addEventListener("input", () => {
              // Adjust the height of the input textarea based on its content
              chatInput.style.height = `${inputInitHeight}px`;
              chatInput.style.height = `${chatInput.scrollHeight}px`;
            });
            chatInput.addEventListener("keydown", (e) => {
              // If Enter key is pressed without Shift key and the window 
              // width is greater than 800px, handle the chat
              if (e.key === "Enter" && !e.shiftKey && window.innerWidth > 800) {
                e.preventDefault();
                handleChat();
              }
            });
            sendChatBtn.addEventListener("click", handleChat);
            closeBtn.addEventListener("click", () => document.body.classList.remove("show-chatbot"));
            chatbotToggler.addEventListener("click", () => document.body.classList.toggle("show-chatbot"));


我在這邊線上演示

See the Pen Untitled by 周平(瑪雅網路科技) (@vzhzchpn-the-vuer) on CodePen.

CodePen 官網: https://codepen.io/