Async tasks for handling audio saving and inference
()
| 344 | log("info", "connection closed") |
| 345 | |
| 346 | async def save_audio_loop(): |
| 347 | """Async tasks for handling audio saving and inference""" |
| 348 | nonlocal all_recorded_pcm, turn_counter, messages, audio_list, audio_buffer_list, audio_buffer_lock, all_generated_audio, reset_first_frame, reset_send_state, this_uuid, tts_offset, cur_audio_tokens, opus_reader, accumulate_tts_tokens |
| 349 | |
| 350 | current_generation = { |
| 351 | 'streamer': None, |
| 352 | 'accumulated_text': '', |
| 353 | 'generation_thread': None, |
| 354 | 'is_generating': False, |
| 355 | 'interrupt': False |
| 356 | } |
| 357 | |
| 358 | while True: |
| 359 | if close: |
| 360 | return |
| 361 | try: |
| 362 | signal_type, _ = await asyncio.wait_for(save_audio_queue.get(), timeout=0.1) |
| 363 | |
| 364 | if signal_type == 'pause': |
| 365 | # save audio and model inference |
| 366 | if all_recorded_pcm is not None and len(all_recorded_pcm) > 0: |
| 367 | timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") |
| 368 | filename = f"{client_id}_turn{turn_counter}_input.wav" |
| 369 | filepath = os.path.join(self.output_dir, "input", filename) |
| 370 | |
| 371 | audio_duration = len(all_recorded_pcm) / self.sample_rate |
| 372 | |
| 373 | # resampling |
| 374 | if self.sample_rate != self.model_manager.target_sample_rate: |
| 375 | audio_tensor = torch.from_numpy(all_recorded_pcm).unsqueeze(0) |
| 376 | resampler = torchaudio.transforms.Resample( |
| 377 | self.sample_rate, |
| 378 | self.model_manager.target_sample_rate |
| 379 | ) |
| 380 | audio_tensor = resampler(audio_tensor) |
| 381 | audio_for_model = audio_tensor.squeeze(0).numpy() |
| 382 | else: |
| 383 | audio_for_model = all_recorded_pcm |
| 384 | |
| 385 | audio_tensor = torch.from_numpy(audio_for_model).unsqueeze(0) |
| 386 | torchaudio.save(filepath, audio_tensor, self.model_manager.target_sample_rate) |
| 387 | log("info", f"Saved audio to {filepath}, length: {audio_duration:.2f}s") |
| 388 | |
| 389 | # Prepare conversation messages |
| 390 | if len(messages) == 0: |
| 391 | messages = [{"role": "system", "content": session_system_prompt}] |
| 392 | |
| 393 | max_messages = 1 + MAX_HISTORY_TURNS * 2 # 1 for system prompt |
| 394 | if len(messages) >= max_messages: |
| 395 | messages_to_remove = len(messages) - max_messages + 2 |
| 396 | if messages_to_remove > 0: |
| 397 | user_messages_removed = sum(1 for m in messages[1:1+messages_to_remove] if m['role'] == 'user') |
| 398 | messages = [messages[0]] + messages[1+messages_to_remove:] |
| 399 | audio_list = audio_list[user_messages_removed:] |
| 400 | log("info", f"Trimmed history: removed {messages_to_remove} messages, {user_messages_removed} audio items") |
| 401 | |
| 402 | message_item = {"role": "user", "content": self.template} |
| 403 | audio_tokens = self.APAD_TOKEN * int(math.ceil(audio_duration * self.token_fps)) |
nothing calls this directly
no test coverage detected