(self)
| 206 | self.chunk_position = 0 |
| 207 | |
| 208 | async def run(self) -> None: |
| 209 | print("Connecting, may take a few seconds...") |
| 210 | |
| 211 | # Initialize audio player with callback |
| 212 | chunk_size = int(SAMPLE_RATE * CHUNK_LENGTH_S) |
| 213 | self.audio_player = sd.OutputStream( |
| 214 | channels=CHANNELS, |
| 215 | samplerate=SAMPLE_RATE, |
| 216 | dtype=FORMAT, |
| 217 | callback=self._output_callback, |
| 218 | blocksize=chunk_size, # Match our chunk timing for better alignment |
| 219 | ) |
| 220 | self.audio_player.start() |
| 221 | |
| 222 | try: |
| 223 | runner = RealtimeRunner(agent) |
| 224 | # Attach playback tracker and enable server‑side interruptions + auto response. |
| 225 | model_config: RealtimeModelConfig = { |
| 226 | "playback_tracker": self.playback_tracker, |
| 227 | "initial_model_settings": { |
| 228 | "model_name": "gpt-realtime-2", |
| 229 | "turn_detection": { |
| 230 | "type": "semantic_vad", |
| 231 | "interrupt_response": True, |
| 232 | "create_response": True, |
| 233 | }, |
| 234 | }, |
| 235 | } |
| 236 | async with await runner.run(model_config=model_config) as session: |
| 237 | self.session = session |
| 238 | print("Connected. Starting audio recording...") |
| 239 | |
| 240 | # Start audio recording |
| 241 | await self.start_audio_recording() |
| 242 | print("Audio recording started. You can start speaking - expect lots of logs!") |
| 243 | |
| 244 | # Process session events |
| 245 | async for event in session: |
| 246 | await self._on_event(event) |
| 247 | |
| 248 | finally: |
| 249 | # Clean up audio player |
| 250 | if self.audio_player and self.audio_player.active: |
| 251 | self.audio_player.stop() |
| 252 | if self.audio_player: |
| 253 | self.audio_player.close() |
| 254 | |
| 255 | print("Session ended") |
| 256 | |
| 257 | async def start_audio_recording(self) -> None: |
| 258 | """Start recording audio from the microphone.""" |
no test coverage detected