import { useState, useEffect, useRef } from 'react'; const BACKEND_URL = import.meta.env.VITE_BACKEND_URL || (import.meta.env.DEV ? 'http://localhost:8000' : ''); export default function BriefPanel({ briefText }) { const [displayedText, setDisplayedText] = useState(''); const [isPlaying, setIsPlaying] = useState(false); const [isLoading, setIsLoading] = useState(false); const audioRef = useRef(null); useEffect(() => { if (!briefText) { setDisplayedText(''); return; } // Typewriter effect setDisplayedText(''); let i = 0; const interval = setInterval(() => { if (i < briefText.length) { setDisplayedText(briefText.slice(0, i + 1)); i++; } else { clearInterval(interval); } }, 12); // Auto-launch TTS in parallel (async () => { setIsLoading(true); try { const res = await fetch(`${BACKEND_URL}/api/tts`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: briefText }), }); if (!res.ok) throw new Error('TTS failed'); const blob = await res.blob(); const url = URL.createObjectURL(blob); const audio = new Audio(url); audioRef.current = audio; audio.onended = () => { setIsPlaying(false); URL.revokeObjectURL(url); }; setIsPlaying(true); await audio.play(); } catch (err) { console.error('TTS auto-play error:', err); } finally { setIsLoading(false); } })(); return () => clearInterval(interval); }, [briefText]); const handleSpeak = async () => { if (isPlaying) { if (audioRef.current) { audioRef.current.pause(); audioRef.current.currentTime = 0; } setIsPlaying(false); return; } setIsLoading(true); try { const res = await fetch(`${BACKEND_URL}/api/tts`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: briefText }), }); if (!res.ok) throw new Error('TTS failed'); const blob = await res.blob(); const url = URL.createObjectURL(blob); const audio = new Audio(url); audioRef.current = audio; audio.onended = () => { setIsPlaying(false); URL.revokeObjectURL(url); }; setIsPlaying(true); await audio.play(); } catch (err) { console.error('TTS error:', err); } finally { setIsLoading(false); } }; if (!briefText) { return null; } return (