iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
Build on Google AI

用 Google AI 打造「因材施教」的個人化 AI 虛擬助教系列 第 10 篇

Day 10 |【別讓 AI 裝死!】 在 MVP 階段加入 AI 思考載入動畫與防呆設計

  • 分享至 

  • xImage
  •  

【今日開發目標】

前幾天我們已經把前端介面和後端 API 串起來了。然而,今天實際測試聊天功能時發現一個滿小、但其實滿影響使用體驗的問題,就是當學生按下發送後,Gemini 還需要一點時間思考,如果這段時間畫面完全沒反應,使用者會以為卡住了,然後又手很癢一直狂按送出,這樣除了造成伺服器重複請求,使用上也會有點不太安心。所以今天的目標就是先把這個等待期間的 UX 做好:加入 AI 思考中的 loading 狀態,同時把輸入框和送出按鈕暫時鎖住,避免使用者重複操作。

【Google AI 工具實作過程】

  1. 鎖定前端互動(防呆設計):
    • 當學生按下發送或按下 Enter 鍵時,前端 JavaScript 會立即將輸入框(chatInput)與發送按鈕(sendButton)設為禁用狀態(disabled = true),避免使用者重複發送請求。
  2. 動態插入載入氣泡:
    • 在等待非同步 fetch() 回應的空檔,動態在對話容器底部插入一段帶有跳動點點動畫的提示氣泡(loadingBubbleHtml),讓學生清楚知道 Professor Spark 正在思考。
  3. 接收回應與狀態恢復:
    • 當 Gemini API 順利回傳結構化 JSON 資料後,自動移除載入氣泡,將 AI 的引導回覆渲染上畫面,並解除按鈕與輸入框的鎖定。
  4. 實作與測試截圖:

https://ithelp.ithome.com.tw/upload/images/20260919/20183764ybQwz6Qz1N.png

https://ithelp.ithome.com.tw/upload/images/20260919/20183764cW61LPR87W.png

【核心 Code / Prompt 展示】

以下是我們在前端 JavaScript 中實作非同步載入與防呆的核心程式碼:

JavaScript

// 整合非同步請求、載入動畫與防呆機制的的核心函式
const sendMessage = async (message) => {
  if (!message.trim()) return;

  // 1. 動態追加使用者訊息到對話區塊
  chatContainer.innerHTML += studentBubbleHtml(message);
  scrollToBottom();

  // 2. 清空輸入框與鎖定按鈕(防呆機制,避免重複點擊)
  chatInput.value = '';
  chatInput.disabled = true;
  sendButton.disabled = true;
  sendButton.classList.add('opacity-50', 'cursor-not-allowed');

  // 3. 顯示帶有跳動點點的載入氣泡
  chatContainer.innerHTML += loadingBubbleHtml();
  scrollToBottom();

  try {
    // 4. 發送請求至後端 API
    const response = await fetch('/api/chat', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ message: message })
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();

    // 5. 移除 loading 氣泡
    const loadingBubble = document.getElementById('loading-bubble');
    if (loadingBubble) {
      loadingBubble.remove();
    }

    // 6. 追加助教回應與延伸提問
    chatContainer.innerHTML += aiBubbleHtml(data.reply, data.suggested_questions);
    scrollToBottom();

  } catch (error) {
    console.error('Fetch error:', error);
    const loadingBubble = document.getElementById('loading-bubble');
    if (loadingBubble) {
      loadingBubble.innerHTML = aiBubbleHtml("抱歉,我現在連線有點問題,請稍後再試一次。");
    }
  } finally {
    // 7. 解除防呆:恢復輸入框與按鈕狀態,讓學生可以繼續對話
    chatInput.disabled = false;
    sendButton.disabled = false;
    sendButton.classList.remove('opacity-50', 'cursor-not-allowed');
    chatInput.focus();
  }
};

【未來教育反思】

做 AI 產品不一定只是把模型接起來就結束了。
一開始我們比較在意 Gemini 能不能正常回覆、Prompt 要怎麼寫、API 能不能成功串接,但實際測試之後才發現,使用者在等待的這幾秒其實也很重要。

如果學生按下送出之後,畫面完全沒有反應,他其實不知道現在到底是在處理、還是壞掉了。甚至可能因為以為沒送出去,就再按一次。

所以這次我們加上 loading 動畫,並且在請求送出後先把輸入框和按鈕鎖住。這些功能本身不難,但做完之後,整個對話流程就順很多。

我覺得這也是這次比較有趣的地方:AI 功能本身很重要,但實際使用起來的感受也不能忽略。尤其是教育類產品,學生本來就可能是在不太會的時候來問問題,如果介面又讓他搞不清楚發生什麼事,反而會增加他的焦慮感。

【明日預告】

明天我們將進入全新階段,體驗 Antigravity CLI,在終端機裡召喚 AI 結對工程師來幫我們掃描並優化專案程式碼!


上一篇
Day 09|【前後端串接】將 Python API 與 Stitch 前端介面串接實戰與除錯血淚史
下一篇
Day 11|【Antigravity】不用切視窗,直接在終端機叫 AI 寫 Code
系列文
用 Google AI 打造「因材施教」的個人化 AI 虛擬助教 共 22 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言