Krish-05 commited on
Commit
1096ecf
·
verified ·
1 Parent(s): bc08895

Update frontend/src/components/chat/ChatInputArea.jsx

Browse files
frontend/src/components/chat/ChatInputArea.jsx CHANGED
@@ -1,41 +1,59 @@
1
  import React, { useState, useEffect, useCallback } from 'react';
2
- import { VoiceVisualizer, useVoiceVisualizer } from 'react-voice-visualizer'; // Assuming these imports are correct
 
3
 
4
  const ChatInputArea = ({ onSendMessage, onSendVoiceMessage, isLoading }) => {
5
  const [message, setMessage] = useState('');
6
 
7
- // Configure useVoiceVisualizer with a specific MIME type for better compatibility
8
  const voiceVisualizerHook = useVoiceVisualizer({
9
  mediaRecorderOptions: { mimeType: 'audio/webm' },
10
- // You can add other options here, e.g., maxRecordingTime: 60000 (for 60 seconds)
11
  });
12
-
13
  const {
14
- startRecording,
15
- stopRecording,
16
  recordingBlob,
17
- isRecording,
18
- // You can also get other states if needed:
19
- // isStopped,
20
- // error,
21
  } = voiceVisualizerHook;
22
 
23
- // Logging for render phase (these will fire on every re-render)
24
- console.log('ChatInputArea render - isRecording:', isRecording);
25
- console.log('ChatInputArea render - recordingBlob (current state):', recordingBlob);
26
-
27
- // This useEffect will run whenever recordingBlob changes.
28
  useEffect(() => {
29
- // debugger; // Keep this for your testing, remove once it works
30
- console.log('ChatInputArea useEffect triggered. recordingBlob:', recordingBlob); // Log inside the effect
31
  if (recordingBlob) {
32
- console.log('ChatInputArea: recordingBlob IS present!', recordingBlob);
33
- onSendVoiceMessage(recordingBlob);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  } else {
35
- console.log('ChatInputArea: recordingBlob is NULL or UNDEFINED.');
 
 
 
 
 
36
  }
37
- }, [recordingBlob, onSendVoiceMessage]); // onSendVoiceMessage is stable due to useCallback in App.jsx
 
38
 
 
39
  const handleTextChange = useCallback((e) => {
40
  setMessage(e.target.value);
41
  }, []);
@@ -43,25 +61,83 @@ const ChatInputArea = ({ onSendMessage, onSendVoiceMessage, isLoading }) => {
43
  const handleSubmit = useCallback((e) => {
44
  e.preventDefault();
45
  if (message.trim()) {
 
46
  onSendMessage(message);
47
- setMessage('');
 
48
  }
49
- }, [message, onSendMessage]);
50
-
51
- const handleStartRecording = useCallback(() => {
52
- console.log("ChatInputArea: handleStartRecording called.");
53
- if (isLoading) return; // Prevent recording if an action is already in progress
54
- startRecording();
55
- // Note: isRecording here might not be immediately true due to async nature of startRecording
56
- console.log("ChatInputArea: Recording start function called. Current isRecording state:", isRecording);
57
- }, [isLoading, startRecording, isRecording]); // isRecording added to dependency array for accurate logging
58
-
59
- const handleStopRecording = useCallback(() => {
60
- console.log("ChatInputArea: handleStopRecording called.");
61
- stopRecording();
62
- // Note: isRecording here might not be immediately false due to async nature of stopRecording
63
- console.log("ChatInputArea: Recording stop function called. Current isRecording state:", isRecording);
64
- }, [stopRecording, isRecording]); // isRecording added to dependency array for accurate logging
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
  return (
67
  <div className="chat-input-area">
@@ -70,24 +146,24 @@ const ChatInputArea = ({ onSendMessage, onSendVoiceMessage, isLoading }) => {
70
  type="text"
71
  value={message}
72
  onChange={handleTextChange}
73
- placeholder={isRecording ? "Recording..." : (isLoading ? "Please wait..." : "Type your message or hold for voice...")}
74
- disabled={isLoading || isRecording}
75
  />
76
- <button type="submit" disabled={isLoading || isRecording || !message.trim()}>
77
  Send
78
  </button>
79
  <div className="voice-input-container">
80
  <button
81
  type="button"
82
- className={`voice-record-btn ${isRecording ? 'recording' : ''}`}
83
- onMouseDown={handleStartRecording}
84
- onMouseUp={handleStopRecording}
85
- onTouchStart={handleStartRecording}
86
- onTouchEnd={handleStopRecording}
87
  disabled={isLoading}
88
  title="Hold to record voice"
89
  >
90
- {isRecording ? (
91
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6 animate-pulse">
92
  <path d="M8.25 4.5a3.75 3.75 0 1 1 7.5 0v8.25a3.75 3.75 0 1 1-7.5 0V4.5Z" />
93
  <path d="M6 10.5a.75.75 0 0 1 .75.75v1.5a5.25 5.25 0 1 0 10.5 0v-1.5a.75.75 0 0 1 1.5 0v1.5a6.75 6.75 0 1 1-13.5 0v-1.5A.75.75 0 0 1 6 10.5Z" />
@@ -99,14 +175,14 @@ const ChatInputArea = ({ onSendMessage, onSendVoiceMessage, isLoading }) => {
99
  </svg>
100
  )}
101
  </button>
102
- {/* Only show visualizer if actively recording to save resources */}
103
- {isRecording && (
 
104
  <VoiceVisualizer
105
  className="sound-wave"
106
  mainBarColor="#4CAF50"
107
  secondaryBarColor="#81C784"
108
- hook={voiceVisualizerHook} // This needs to be 'controls' if the prop name is 'controls' in VoiceVisualizer
109
- // Optional: width="100%" height="50px"
110
  />
111
  )}
112
  </div>
 
1
  import React, { useState, useEffect, useCallback } from 'react';
2
+ import { VoiceVisualizer, useVoiceVisualizer } from 'react-voice-visualizer';
3
+ import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition';
4
 
5
  const ChatInputArea = ({ onSendMessage, onSendVoiceMessage, isLoading }) => {
6
  const [message, setMessage] = useState('');
7
 
8
+ // --- Voice Visualizer Setup (for recording/displaying audio waves if desired) ---
9
  const voiceVisualizerHook = useVoiceVisualizer({
10
  mediaRecorderOptions: { mimeType: 'audio/webm' },
 
11
  });
 
12
  const {
13
+ startRecording: startVoiceVisualizerRecording,
14
+ stopRecording: stopVoiceVisualizerRecording,
15
  recordingBlob,
16
+ isRecording: isVisualizerRecording,
 
 
 
17
  } = voiceVisualizerHook;
18
 
 
 
 
 
 
19
  useEffect(() => {
 
 
20
  if (recordingBlob) {
21
+ console.log('ChatInputArea: Voice Visualizer Recorded blob is: ', recordingBlob);
22
+ onSendVoiceMessage(recordingBlob); // Send the actual audio blob
23
+ }
24
+ }, [recordingBlob, onSendVoiceMessage]);
25
+
26
+
27
+ // --- Speech Recognition Setup ---
28
+ const {
29
+ transcript,
30
+ listening,
31
+ resetTranscript,
32
+ browserSupportsSpeechRecognition,
33
+ isMicrophoneAvailable
34
+ } = useSpeechRecognition();
35
+
36
+ // EFFECT TO DISPLAY TRANSCRIPT IN INPUT FIELD
37
+ useEffect(() => {
38
+ if (listening) {
39
+ // While listening, update the message state with the live transcript
40
+ setMessage(transcript);
41
+ } else if (transcript.trim() !== '') {
42
+ // Once listening stops and there's a final transcript, keep it in the message state
43
+ setMessage(transcript);
44
+ // We no longer send automatically here. The user will click "Send".
45
  } else {
46
+ // If listening stops and transcript is empty (e.g., no speech detected),
47
+ // ensure the input field doesn't get stuck with an old value.
48
+ // But only if we weren't already typing something else.
49
+ if (!transcript && !message) { // Only clear if transcript was truly empty and message wasn't user-typed
50
+ setMessage('');
51
+ }
52
  }
53
+ }, [transcript, listening, message]); // Include 'message' in dependencies to avoid stale closures if needed
54
+
55
 
56
+ // --- Handlers for Text Input ---
57
  const handleTextChange = useCallback((e) => {
58
  setMessage(e.target.value);
59
  }, []);
 
61
  const handleSubmit = useCallback((e) => {
62
  e.preventDefault();
63
  if (message.trim()) {
64
+ // Send the current content of the message state (which now includes transcript)
65
  onSendMessage(message);
66
+ setMessage(''); // Clear input after sending
67
+ resetTranscript(); // Also clear the internal transcript state
68
  }
69
+ }, [message, onSendMessage, resetTranscript]);
70
+
71
+
72
+ // --- Handlers for Voice Input ---
73
+ const handleStartVoiceInput = useCallback(() => {
74
+ if (isLoading) return;
75
+
76
+ // Clear previous transcript and message before starting new recognition
77
+ resetTranscript();
78
+ setMessage(''); // Clear the input field immediately
79
+ SpeechRecognition.startListening({ continuous: false, interimResults: true }); // Interim results for live preview
80
+
81
+ // Optional: Start visualizer if you want to record the audio blob as well
82
+ // startVoiceVisualizerRecording();
83
+
84
+ console.log("ChatInputArea: Voice input (SpeechRecognition) started.");
85
+ }, [isLoading, resetTranscript]); // Removed startVoiceVisualizerRecording for primary logic
86
+
87
+ const handleStopVoiceInput = useCallback(() => {
88
+ SpeechRecognition.stopListening();
89
+
90
+ // Optional: Stop visualizer if you started it
91
+ // stopVoiceVisualizerRecording();
92
+
93
+ console.log("ChatInputArea: Voice input (SpeechRecognition) stopped.");
94
+ }, []); // Removed stopVoiceVisualizerRecording for primary logic
95
+
96
+
97
+ // --- Render Logic ---
98
+ if (!browserSupportsSpeechRecognition) {
99
+ return (
100
+ <div className="chat-input-area">
101
+ <p className="browser-support-warning">
102
+ Voice input is not supported in this browser. Please use Chrome for best experience.
103
+ </p>
104
+ <form onSubmit={handleSubmit} className="chat-form">
105
+ <input
106
+ type="text"
107
+ value={message}
108
+ onChange={handleTextChange}
109
+ placeholder={isLoading ? "Please wait..." : "Type your message..."}
110
+ disabled={isLoading}
111
+ />
112
+ <button type="submit" disabled={isLoading || !message.trim()}>
113
+ Send
114
+ </button>
115
+ </form>
116
+ </div>
117
+ );
118
+ }
119
+
120
+ if (!isMicrophoneAvailable) {
121
+ return (
122
+ <div className="chat-input-area">
123
+ <p className="browser-support-warning">
124
+ Microphone access denied or unavailable. Please enable microphone permissions for voice input.
125
+ </p>
126
+ <form onSubmit={handleSubmit} className="chat-form">
127
+ <input
128
+ type="text"
129
+ value={message}
130
+ onChange={handleTextChange}
131
+ placeholder={isLoading ? "Please wait..." : "Type your message..."}
132
+ disabled={isLoading}
133
+ />
134
+ <button type="submit" disabled={isLoading || !message.trim()}>
135
+ Send
136
+ </button>
137
+ </form>
138
+ </div>
139
+ );
140
+ }
141
 
142
  return (
143
  <div className="chat-input-area">
 
146
  type="text"
147
  value={message}
148
  onChange={handleTextChange}
149
+ placeholder={listening ? "Listening..." : (isLoading ? "Please wait..." : "Type your message or hold for voice...")}
150
+ disabled={isLoading || listening} // Disable text input while listening via voice
151
  />
152
+ <button type="submit" disabled={isLoading || listening || !message.trim()}>
153
  Send
154
  </button>
155
  <div className="voice-input-container">
156
  <button
157
  type="button"
158
+ className={`voice-record-btn ${listening ? 'recording' : ''}`}
159
+ onMouseDown={handleStartVoiceInput}
160
+ onMouseUp={handleStopVoiceInput}
161
+ onTouchStart={handleStartVoiceInput}
162
+ onTouchEnd={handleStopVoiceInput}
163
  disabled={isLoading}
164
  title="Hold to record voice"
165
  >
166
+ {listening ? (
167
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6 animate-pulse">
168
  <path d="M8.25 4.5a3.75 3.75 0 1 1 7.5 0v8.25a3.75 3.75 0 1 1-7.5 0V4.5Z" />
169
  <path d="M6 10.5a.75.75 0 0 1 .75.75v1.5a5.25 5.25 0 1 0 10.5 0v-1.5a.75.75 0 0 1 1.5 0v1.5a6.75 6.75 0 1 1-13.5 0v-1.5A.75.75 0 0 1 6 10.5Z" />
 
175
  </svg>
176
  )}
177
  </button>
178
+
179
+ {/* Voice Visualizer remains optional */}
180
+ {isVisualizerRecording && (
181
  <VoiceVisualizer
182
  className="sound-wave"
183
  mainBarColor="#4CAF50"
184
  secondaryBarColor="#81C784"
185
+ controls={voiceVisualizerHook} // Corrected prop name
 
186
  />
187
  )}
188
  </div>