import React, { useState, useEffect, useRef, useCallback } from 'react'; import { BrowserRouter as Router, Routes, Route, Navigate, Link, useNavigate } from 'react-router-dom'; import { useReactMediaRecorder } from "react-media-recorder"; import './App.css'; // Your existing App.css import chatbotLogo from './assets/chatbot.png'; // Import the logo // Mock user object for demonstration. In your real app, this comes from Firebase. const mockUser = { isLoggedIn: true, }; // ================================================================================= // Chat Components (ChatPage and ChatInput) // ================================================================================= const ChatInput = ({ onSendMessage, isLoading, setInputText, inputText }) => { const { status, startRecording, stopRecording, mediaBlobUrl } = useReactMediaRecorder({ audio: true, mimeType: "audio/webm", // Explicitly set mimetype }); const [isTranscribing, setIsTranscribing] = useState(false); const isRecording = status === "recording"; // This effect handles the recorded audio blob useEffect(() => { // When a blob URL is available and recording has stopped if (mediaBlobUrl && status === 'stopped') { const transcribeAudio = async () => { setIsTranscribing(true); try { // Fetch the audio blob from its URL const audioBlob = await fetch(mediaBlobUrl).then((res) => res.blob()); // Create a FormData object to send the file const formData = new FormData(); formData.append("audio_file", audioBlob, "recording.webm"); // Send the audio to the backend transcription endpoint const response = await fetch("/api/transcribe-audio", { method: "POST", body: formData, }); if (!response.ok) { throw new Error("Transcription failed"); } const result = await response.json(); setInputText(result.transcription); // Set the input field with the transcribed text } catch (error) { console.error("Error transcribing audio:", error); alert("Could not transcribe audio. Please try again."); } finally { setIsTranscribing(false); } }; transcribeAudio(); } }, [mediaBlobUrl, status, setInputText]); const handleTextChange = (e) => { setInputText(e.target.value); }; const handleSubmit = (e) => { e.preventDefault(); if (inputText.trim()) { onSendMessage(inputText); setInputText(''); } }; const getPlaceholderText = () => { if (isRecording) return "Recording..."; if (isTranscribing) return "Transcribing..."; return "Type or hold the mic to talk..."; }; return (
{/* Voice Input Button */} {/* Text Send Button */}
); }; const ChatPage = () => { const [chatHistory, setChatHistory] = useState([]); const [isSending, setIsSending] = useState(false); const [inputText, setInputText] = useState(""); // State for the input field const chatEndRef = useRef(null); useEffect(() => { chatEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [chatHistory]); const handleSendMessage = useCallback(async (prompt) => { if (!prompt.trim() || isSending) return; const userMessage = { role: 'user', message: prompt }; // Add user message and a temporary placeholder for the bot's response setChatHistory(prev => [...prev, userMessage, { role: 'assistant', message: '...' }]); setIsSending(true); try { const response = await fetch('/api/ask', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: prompt }), }); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let fullResponse = ''; while (true) { const { value, done } = await reader.read(); if (done) break; const chunk = decoder.decode(value, { stream: true }); const events = chunk.split('\n\n'); for (const event of events) { if (event.startsWith('data:')) { const dataStr = event.substring(5).trim(); if (dataStr) { try { const dataObj = JSON.parse(dataStr); if (dataObj.token) { fullResponse += dataObj.token; // Update the last message in history with the streaming content setChatHistory(prev => { const newHistory = [...prev]; newHistory[newHistory.length - 1] = { role: 'assistant', message: fullResponse + '▌' }; return newHistory; }); } } catch (e) { console.error("Error parsing stream data:", e); } } } } } // Final update to remove the cursor setChatHistory(prev => { const newHistory = [...prev]; newHistory[newHistory.length - 1] = { role: 'assistant', message: fullResponse }; return newHistory; }); } catch (error) { console.error("Error fetching AI response:", error); setChatHistory(prev => { const newHistory = [...prev]; newHistory[newHistory.length - 1] = { role: 'assistant', message: "Sorry, I couldn't get a response. Please try again." }; return newHistory; }); } finally { setIsSending(false); } }, [isSending]); return (
{chatHistory.length === 0 ? (

Dobby is here to help!

Start the conversation by typing or using your voice.

) : ( chatHistory.map((chat, index) => (
{chat.role === 'assistant' ? ( Dobby ) : '👤'}
{chat.message}
)) )}
); }; // ================================================================================= // Auth Components (Login and SignUp) // ================================================================================= const AuthForm = ({ isLogin = false }) => { const navigate = useNavigate(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(''); const handleSubmit = (e) => { e.preventDefault(); setError(''); if (!email || !password) { setError('Please fill in all fields.'); return; } // In a real app, you'd integrate with Firebase or your backend for authentication // For this mock, we just set isLoggedIn to true mockUser.isLoggedIn = true; navigate('/chat'); }; return (

{isLogin ? 'Log In' : 'Sign Up'}

setEmail(e.target.value)} required />
setPassword(e.target.value)} required />
{error &&

{error}

}
{isLogin ? (

Don't have an account? Sign Up

) : (

Already have an account? Log In

)}
); }; const Login = () => ; const SignUp = () => ; // ================================================================================= // Header and Main App Component // ================================================================================= const Header = ({ user }) => { const navigate = useNavigate(); const handleLogout = () => { mockUser.isLoggedIn = false; navigate('/login'); }; return (
{/* Changed order: Dobby text first, then logo */}
Dobby GUVI Assistant
Dobby Logo
); }; function App() { const [user] = useState(mockUser); return (
} /> } /> : } /> : } />
); } export default App;