Prathmesh0001/interview-system
0
1"""
2Audio Handler Module
3Manages speech recognition (STT) and text-to-speech (TTS) functionality
4"""
5
6import speech_recognition as sr
7import pyttsx3
8from gtts import gTTS
9import os
10import tempfile
11from typing import Optional, Tuple
12import time
13
14
15class AudioHandler:
16 """Handle audio input/output for interview system"""
17
18 def __init__(self, use_gtts: bool = False):
19 """
20 Initialize audio handler
21
22 Args:
23 use_gtts: Use Google TTS instead of pyttsx3
24 """
25 self.recognizer = sr.Recognizer()
26 self.use_gtts = use_gtts
27
28 # Initialize TTS engine
29 if not use_gtts:
30 try:
31 self.tts_engine = pyttsx3.init()
32 self.tts_engine.setProperty('rate', 150) # Speed of speech
33 self.tts_engine.setProperty('volume', 0.9) # Volume (0.0 to 1.0)
34 except Exception as e:
35 print(f"Error initializing pyttsx3: {e}")
36 print("Falling back to gTTS")
37 self.use_gtts = True
38
39 def speak(self, text: str) -> bool:
40 """
41 Convert text to speech and play it
42
43 Args:
44 text: Text to speak
45
46 Returns:
47 True if successful, False otherwise
48 """
49 try:
50 if self.use_gtts:
51 return self._speak_gtts(text)
52 else:
53 return self._speak_pyttsx3(text)
54 except Exception as e:
55 print(f"Error in text-to-speech: {e}")
56 return False
57
58 def _speak_pyttsx3(self, text: str) -> bool:
59 """Speak using pyttsx3 (offline)"""
60 try:
61 self.tts_engine.say(text)
62 self.tts_engine.runAndWait()
63 return True
64 except Exception as e:
65 print(f"pyttsx3 error: {e}")
66 return False
67
68 def _speak_gtts(self, text: str) -> bool:
69 """Speak using Google TTS (online)"""
70 try:
71 tts = gTTS(text=text, lang='en', slow=False)
72
73 # Create temporary file
74 with tempfile.NamedTemporaryFile(delete=False, suffix='.mp3') as fp:
75 temp_file = fp.name
76 tts.save(temp_file)
77
78 # Play the audio file (platform-dependent)
79 if os.name == 'posix': # Linux/Mac
80 os.system(f'mpg123 -q {temp_file} 2>/dev/null || afplay {temp_file} 2>/dev/null')
81 else: # Windows
82 os.system(f'start {temp_file}')
83
84 time.sleep(0.5)
85
86 # Clean up
87 try:
88 os.remove(temp_file)
89 except:
90 pass
91
92 return True
93 except Exception as e:
94 print(f"gTTS error: {e}")
95 return False
96
97 def listen(self, timeout: int = 120, phrase_time_limit: int = 120) -> Tuple[Optional[str], dict]:
98 """
99 Listen to microphone and convert speech to text
100
101 Args:
102 timeout: Maximum time to wait for phrase start
103 phrase_time_limit: Maximum time for phrase
104
105 Returns:
106 Tuple of (transcribed text or None, audio analysis dict)
107 """
108 audio_analysis = {
109 'duration': 0,
110 'confidence': 0,
111 'error': None
112 }
113
114 try:
115 with sr.Microphone() as source:
116 print("๐ค Listening... (speak now)")
117
118 # Adjust for ambient noise
119 self.recognizer.adjust_for_ambient_noise(source, duration=1)
120
121 # Record audio
122 start_time = time.time()
123 audio = self.recognizer.listen(
124 source,
125 timeout=timeout,
126 phrase_time_limit=phrase_time_limit
127 )
128 audio_analysis['duration'] = time.time() - start_time
129
130 print("๐ Processing your response...")
131
132 # Recognize speech using Google Speech Recognition
133 text = self.recognizer.recognize_google(audio)
134 audio_analysis['confidence'] = 0.85 # Google doesn't provide confidence
135
136 return text, audio_analysis
137
138 except sr.WaitTimeoutError:
139 audio_analysis['error'] = 'timeout'
140 print("โฑ๏ธ No speech detected within timeout period")
141 return None, audio_analysis
142
143 except sr.UnknownValueError:
144 audio_analysis['error'] = 'unclear'
145 print("โ Could not understand the audio")
146 return None, audio_analysis
147
148 except sr.RequestError as e:
149 audio_analysis['error'] = 'service_error'
150 print(f"โ Could not request results from speech recognition service: {e}")
151 return None, audio_analysis
152
153 except Exception as e:
154 audio_analysis['error'] = str(e)
155 print(f"โ Error during speech recognition: {e}")
156 return None, audio_analysis
157
158 def analyze_voice_features(self, audio_data, text: str) -> dict:
159 """
160 Analyze voice features from audio
161
162 Args:
163 audio_data: Audio data from speech recognition
164 text: Transcribed text
165
166 Returns:
167 Dictionary with voice analysis metrics
168 """
169 # Basic analysis based on transcribed text
170 analysis = {
171 'word_count': len(text.split()),
172 'speaking_rate': 0, # Words per minute
173 'volume_level': 'medium', # Would need audio processing for actual value
174 'clarity_score': 0.7 # Default placeholder
175 }
176
177 # Estimate speaking rate if we have duration
178 # This is a simplified version - would need actual audio processing for accuracy
179 if hasattr(audio_data, 'duration'):
180 duration_minutes = audio_data.duration / 60
181 if duration_minutes > 0:
182 analysis['speaking_rate'] = analysis['word_count'] / duration_minutes
183
184 # Assess clarity based on word count and sentence structure
185 if analysis['word_count'] > 30:
186 analysis['clarity_score'] = 0.8
187 if analysis['word_count'] > 50:
188 analysis['clarity_score'] = 0.85
189
190 return analysis
191
192 def test_audio_setup(self) -> dict:
193 """
194 Test audio input/output setup
195
196 Returns:
197 Dictionary with test results
198 """
199 results = {
200 'microphone': False,
201 'speakers': False,
202 'speech_recognition': False
203 }
204
205 # Test speakers
206 print("\nTesting speakers...")
207 try:
208 self.speak("Testing audio output. Can you hear this?")
209 results['speakers'] = True
210 print("โ
Speakers working")
211 except Exception as e:
212 print(f"โ Speaker test failed: {e}")
213
214 # Test microphone
215 print("\nTesting microphone...")
216 try:
217 with sr.Microphone() as source:
218 self.recognizer.adjust_for_ambient_noise(source, duration=1)
219 results['microphone'] = True
220 print("โ
Microphone detected")
221 except Exception as e:
222 print(f"โ Microphone test failed: {e}")
223
224 # Test speech recognition
225 if results['microphone']:
226 print("\nTesting speech recognition...")
227 print("Please say: 'This is a test'")
228 try:
229 text, _ = self.listen(timeout=10, phrase_time_limit=10)
230 if text:
231 results['speech_recognition'] = True
232 print(f"โ
Recognized: {text}")
233 except Exception as e:
234 print(f"โ Speech recognition test failed: {e}")
235
236 return results
237
238
239if __name__ == "__main__":
240 # Test the audio handler
241 print("Audio Handler Module - Test Mode")
242 print("=" * 50)
243
244 handler = AudioHandler()
245
246 # Run audio setup test
247 test_results = handler.test_audio_setup()
248
249 print("\n" + "=" * 50)
250 print("Test Results:")
251 for component, status in test_results.items():
252 status_symbol = "โ
" if status else "โ"
253 print(f"{status_symbol} {component.replace('_', ' ').title()}: {'Working' if status else 'Failed'}")