이 글에서는 OpenAI Realtime API를 사용해 대화 중단 기능을 구현하는 방법을 소개합니다.
구현에 대한 자세한 내용은 GitHub 저장소에서 확인할 수 있습니다.
이 구현은 Azure-Samples/aoai-realtime-audio-sdk의 코드를 기반으로 합니다. 코드에 대한 자세한 설명은 이 글에서 보실 수 있습니다.
이 구현에서는 오디오 입출력을 위해 로컬 PC의 마이크와 스피커를 사용합니다.
마이크에서 캡처한 오디오는 처리를 위해 OpenAI Realtime API 서버로 전송됩니다.
로컬 PC의 마이크에서 오디오를 캡처하기 위해 paudio 라이브러리의 스트림 기능을 사용합니다. 다음 코드는 오디오 입력용 스트림을 설정합니다.
p = pyaudio.PyAudio() input_default_input_index = p.get_default_input_device_info()['index'] input_stream = p.open( format=STREAM_FORMAT, channels=INPUT_CHANNELS, rate=INPUT_SAMPLE_RATE, input=True, output=False, frames_per_buffer=INPUT_CHUNK_SIZE, input_device_index=input_default_input_index, start=False, ) input_stream.start_stream()
오디오 캡처는 병렬 처리를 위해 threading.Thread를 사용하여 수행됩니다. 마이크에서 얻은 오디오 데이터는 base64 형식으로 인코딩되어 대기열에 저장됩니다.
def listen_audio(input_stream: pyaudio.Stream): while True: audio_data = input_stream.read(INPUT_CHUNK_SIZE, exception_on_overflow=False) if audio_data is None: continue base64_audio = base64.b64encode(audio_data).decode("utf-8") audio_input_queue.put(base64_audio) threading.Thread(target=listen_audio, args=(input_stream,), daemon=True).start()
큐에 저장된 base64 문자열은 "input_audio_buffer.append" 메시지로 OpenAI Realtime API 서버에 전송됩니다.
async def send_audio(client: RTLowLevelClient): while not client.closed: base64_audio = await asyncio.get_event_loop().run_in_executor(None, audio_input_queue.get) await client.send(InputAudioBufferAppendMessage(audio=base64_audio)) await asyncio.sleep(0)
오디오 재생은 OpenAI Realtime API 서버에서 수신한 오디오 데이터를 이용하여 로컬 PC의 스피커를 통해 수행됩니다.
오디오 데이터는 서버로부터 "response.audio.delta" 메시지로 수신됩니다. 수신된 데이터는 base64로 인코딩되므로 디코딩되어 큐에 저장되고 재생 가능한 형식으로 변환됩니다.
async def receive_messages(client: RTLowLevelClient): while True: message = await client.recv() if message is None: continue match message.type: case "response.audio.delta": audio_data = base64.b64decode(message.delta) for i in range(0, len(audio_data), OUTPUT_CHUNK_SIZE): audio_output_queue.put(audio_data[i:i+OUTPUT_CHUNK_SIZE]) await asyncio.sleep(0)
큐에 저장된 데이터는 병렬 처리를 통해 로컬 PC의 스피커를 통해 재생됩니다. 이 재생 프로세스에서는 threading.Thread를 사용하여 오디오 데이터가 실시간으로 원활하게 재생되도록 합니다.
def play_audio(output_stream: pyaudio.Stream): while True: audio_data = audio_output_queue.get() output_stream.write(audio_data) p = pyaudio.PyAudio() output_default_output_index = p.get_default_output_device_info()['index'] output_stream = p.open( format=STREAM_FORMAT, channels=OUTPUT_CHANNELS, rate=OUTPUT_SAMPLE_RATE, input=False, output=True, frames_per_buffer=OUTPUT_CHUNK_SIZE, output_device_index=output_default_output_index, start=False, ) output_stream.start_stream() threading.Thread(target=play_audio, args=(output_stream,), daemon=True).start()
OpenAI Realtime API는 서버 측에서 대화 세그먼트를 자동으로 감지합니다. 이를 통해 AI가 응답하는 동안에도 새로운 음성을 감지하고 실시간 응답을 생성할 수 있습니다.
그러나 로컬 PC에서 오디오를 재생할 때는 대화가 자연스럽게 중단되도록 진행 중인 오디오 재생을 중지하는 것이 중요합니다. 이 점은 주의가 필요합니다. 사용자 음성 감지는 OpenAI Realtime API 서버에서 "input_audio_buffer.speech_started" 메시지로 수신됩니다. 이 메시지를 수신하면 대기열에 저장된 오디오 데이터를 삭제하여 재생을 중지합니다.
async def receive_messages(client: RTLowLevelClient): while True: message = await client.recv() # print(f"{message=}") if message is None: continue match message.type: case "input_audio_buffer.speech_started": print("Input Audio Buffer Speech Started Message") print(f" Item Id: {message.item_id}") print(f" Audio Start [ms]: {message.audio_start_ms}") while not audio_output_queue.empty(): audio_output_queue.get()
오디오 출력의 경우 수정이 필요하지 않습니다. 앞서 설명한 코드에 설명된 대로 작동합니다.
이번에는 대화 중단을 위한 Python 구현을 소개했습니다.
저처럼 AI 음성을 효과적으로 중지하는 데 어려움을 겪고 있는 모든 분들에게 이 글이 도움이 되기를 바랍니다.
또한 스트림 인스턴스의 정의 및 구성은 오디오 재생 품질에 영향을 미칠 수 있습니다. 오디오 재생이 중단되는 경우 이러한 설정을 검토하면 상황을 개선하는 데 도움이 될 수 있습니다.
끝까지 읽어주셔서 감사합니다.
위 내용은 단계별 가이드: OpenAI Realtime API를 통한 중단 관리의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!