From 5c99615edf373bef3b50c1c188064ca7979864fc Mon Sep 17 00:00:00 2001 From: Srayash Date: Wed, 30 Oct 2024 00:03:08 +0530 Subject: [PATCH] UI changes: add loading animation while audio response is being fetched --- frontend/src/assets/Loading.svg | 3 ++ .../src/components/TextToSpeechButton.tsx | 37 ++++++++++++------- 2 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 frontend/src/assets/Loading.svg diff --git a/frontend/src/assets/Loading.svg b/frontend/src/assets/Loading.svg new file mode 100644 index 00000000..84a604f9 --- /dev/null +++ b/frontend/src/assets/Loading.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/components/TextToSpeechButton.tsx b/frontend/src/components/TextToSpeechButton.tsx index b5402469..2cb9e8f8 100644 --- a/frontend/src/components/TextToSpeechButton.tsx +++ b/frontend/src/components/TextToSpeechButton.tsx @@ -1,6 +1,7 @@ import { useState, useRef } from 'react'; import Speaker from '../assets/speaker.svg?react'; import Stopspeech from '../assets/stopspeech.svg?react'; +import LoadingIcon from '../assets/Loading.svg?react'; // Add a loading icon SVG here const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com'; export default function SpeakButton({ @@ -13,12 +14,13 @@ export default function SpeakButton({ colorDark?: string; }) { const [isSpeaking, setIsSpeaking] = useState(false); + const [isLoading, setIsLoading] = useState(false); const [isSpeakHovered, setIsSpeakHovered] = useState(false); - const audioRef = useRef(null); // Reference to the audio object + const audioRef = useRef(null); const handleSpeakClick = async () => { if (isSpeaking) { - // Stop audio if currently playing and reset the state + // Stop audio if it's currently playing audioRef.current?.pause(); audioRef.current = null; setIsSpeaking(false); @@ -26,9 +28,9 @@ export default function SpeakButton({ } try { - setIsSpeaking(true); + // Set loading state and initiate TTS request + setIsLoading(true); - // Make a POST request to the /api/tts endpoint const response = await fetch(apiHost + '/api/tts', { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -38,22 +40,27 @@ export default function SpeakButton({ const data = await response.json(); if (data.success && data.audio_base64) { + // Create and play the audio const audio = new Audio(`data:audio/mp3;base64,${data.audio_base64}`); - audioRef.current = audio; // Store the audio object in ref for later control - audio.play(); + audioRef.current = audio; - // Reset state when audio ends - audio.onended = () => { - setIsSpeaking(false); - audioRef.current = null; - }; + audio.play().then(() => { + setIsSpeaking(true); + setIsLoading(false); + + // Reset when audio ends + audio.onended = () => { + setIsSpeaking(false); + audioRef.current = null; + }; + }); } else { console.error('Failed to retrieve audio.'); - setIsSpeaking(false); + setIsLoading(false); } } catch (error) { console.error('Error fetching audio from TTS endpoint', error); - setIsSpeaking(false); + setIsLoading(false); } }; @@ -65,7 +72,9 @@ export default function SpeakButton({ : `bg-[${colorLight ? colorLight : '#FFFFFF'}] dark:bg-[${colorDark ? colorDark : 'transparent'}]` }`} > - {isSpeaking ? ( + {isLoading ? ( + + ) : isSpeaking ? (