OpenAI Realtime API

OpenAI가 실시간 API의 공개 베타 버전을 출시했습니다.

 

실시간이 아니면, 한 사람이 말하면 끝날 때까지 기다려야 합니다. 중간에 끼어들 수 없습니다. 사람은 말하면서 듣기도 할 수 있기 때문에 말하기와 듣기를 분리하면, 말하기와 듣기 전환에 지연이 발생한다고 느껴 답답해 합니다. 텍스트만 사용해서 대화할 땐 없던 답답함이 음성으로 대화하니 생기는 문제입니다.

OpenAI 실시간 API는 여러 사용 사례를 만들고 싶겠지만, 출현한 근본 이유가 음성 대화이니 음성 대화에 맞추어 사용 사례를  만드는 게 좋습니다.

실시간 다국어 통역을 지원한다는 시대에 다른 나라 말을 배울 필요가 있나?라고 할 수도 있지만, 아직은 못하는 것보다는 할 수 있는 게 좋은 거 같고. 학생들 입장에서는 대입에서 없어지지 않는 한, 영어는 할 수 밖에 없습니다. 어차피 배운다면 좀 오래된 세대와는 달, 말도 잘 하는 게 유리하겠죠?

그래서 “영어 말하기 투터”를 사용 사례로 만들기로 결정했습니다. 아직은 AIPilotSmarteasy의 어떤 버전에 포함해서 언제 릴리즈할지는 정하지 않았습니다.

먼저 실시간(Realtime API)가 무엇인지 알아보기 위해,  October 1, 2024일자 OpenAI 글을 읽어 보겠습니다.

타이틀은 “Introducing the Realtime API”이고, 부 타이틀은 “Developers can now build fast speech-to-speech experiences into their applications” 입니다.  타이틀만 봐도 OpenAI가 어떤 생각과 접근을 하고 있는 지 알 수 있습니다.

필요성은 speech-to-speech에서 나오지만,

포지셔닝은 realtime으로 하고, 지연 없음을 강조하고 싶다. 

 

OpenAI는 실시간 API 등장 전에도, 사용자의 음성을 텍스트로 변환하고, 생성형 AI 모델의 텍스트 응답을 음성으로 변환하는 방식으로 음성을 지원했습니다.

실시간 느낌을 주는 정도는 “음성에 대한 스트리밍”으로도 가능하지 않을까 생각하고 있었는데, 내부적으로는 어떻게 하는 지 모르겠지만 OpenAI는 분리된 모델 “gpt-4o-realtime-preview”을 제시합니다. 사람이 말하면, 그것을 텍스트로 변환(STT)하고, 그것을 LLM이 받아 텍스트를 생성하고, 텍스트를 음성으로 변환(TTS)해서 전달해주는 방식은 World’s Fastest Talking AI: Deepgram + Groq에서 보여줍니다.

이렇게 해서 말하기로 대화해도 만족할 수 있습니다. 하지만 아직도 상대의 말하기 중간에 끼어들지는 못합니다. OpenAI 실시간 음성지원의 특별함은 중간 끼어들기입니다. 이들이 생성형 모델을 만드는 기술 뿐만 아니라 소프트웨어 개발 기술에도 자신이 있기 때문에 이런 시도와 리딩을 할 수 있습니다.

이런 OpenAI의 모습을 보면서, OpenAI가 새로운 생성형 모델을 출시할 때 그것만으로 안 되는 영역을, 스타트업이 덥석 물었다가 후에 그들이 그 부분을 강화해 버리면 돈 없는 작은 기업은 그냥 주저 앉을 수 있으니 조심해야겠다는 생각도 듭니다. 생성형 모델을 공급하는  공급사들이 하나에만 집중하지 않고 실력있는 규모의 소프트웨어 개발 조직도 갖고 있다는 것을 잊지 말아야 합니다. 그래서 한 공급사에만 의존하면 안 되고 여러 공급사들을 섞어서 장점을 발휘할 수 있는 기술과 사용사례를 갖춰야 합니다.

 

OpenAI에서 실시간 API 발표 할 때, 이전에 지연을 경험했던 사람들은 환호를 합니다. 지연이 처음부터 없었다면 없을 환호가 지연을 경험하니 터져 나옵니다. 기술은 뒤로 놓고라도 의도 했던 의도하지 않았던 OpenAI의 발표나 발표시점을 보면 샘알트만의 타고난 경영 감각에 놀랍니다.

 

텍스트로만 대화할 때만 생각하면, 토큰 비용이 꽤 높기 때문에 아직은 꼭 필요한 경우가 아니라면 사용에 주의해야 합니다.

  • 텍스트 입력 토큰은 1M당 $5, 출력 토큰은 1M당 $20
  • 오디오 입력은 1M 토큰당 $100, 출력은 1M 토큰당 $200입니다. 이는 대략적으로 오디오 입력 분당 $0.06, 오디오 출력 분당 $0.24가 된다고 합니다.

 

실시간 API에 대한 설명은 아래 링크를 참조합니다.

https://platform.openai.com/docs/guides/realtime

Realtime 문서 시작 부분의 다음 설명이 사실이라면 차별화입니다.

  • 음성을 텍스트로 변환하는 중간 단계 없이 바로 음성을 처리
  • 웃음, 속삭임, 어조 조절 등을 음성 표현으로 처리

 

물론 업무 생산성을 높이거나 새로운 업무 방식을 찾는 사람들 한테는 이런 차별화가 전혀 필요 없을 수도 있습니다. 그래서 더, 이에 맞는 유스케이스를 찾으려는 노력이 중요해 보입니다.

 

사람이 한 번의 말하기를 끝낸 것과 다시 시작하려는 것을 아는 것은 매우 중요합니다.

AI Pilot Smarteasy에서 음성 지원을 구현 할 때 사람의 말하기의 시작과 끝을 구현할 때 고려했던 것들이 생각납니다.

  • 사람이 말하기를 멈췄다는 것은 침묵이 어느 정도 이어질 때로 할 것인가?
  • 소음이 있는데 어느 정도 크기의 소리가 나면 소음이 아니라 말하기로 인정할 것인가?

OpenAI의 Realtime Audio API에서 Turn detection 관련 속성은 이를 위한 지원입니다.

음성활동 감지 – 임계값 Threshold – 기본 값 0.5

  • Threshold (임계값): 기본 값은 0.5로 설정되어 있습니다. 이 값은 음성으로 인식하는 민감도를 나타냅니다. 0.0에서 1.0 사이의 값을 가지며, 값이 낮을수록 작은 소리에도 반응합니다. 이 값이 필요한 이유로 주변에 소음이 있기 때문입니다. 소음이 사람 말하기보다 크다면 대응을 할 수 없겠지만 그렇지 않다면 소음은 무시할 수 있습니다. 어느 정도의 소음을 무시할 지는 사용자의 환경에 따라 달라질 수 있기 때문에 이 값은 상황에 따라 조정해야 합니다. 조용한 환경이라면 말하기를 작게, 시끄러운 환경이라면 말하기 크기해야 합니다. 결국 임계값을 설정한다는 것은 음성으로 감지해 줄 크기를 얼마나 할지를 결정하는 것, 즉 얼마나 말하기를 크게 할 것인지를 정하는 것입니다.
  • Prefix Padding (ms) (접두사 패딩): 기본 값은 300ms(밀리초)로 설정되어 있습니다. 이는 음성 감지 시작 시점 이전에 추가되는 시간입니다. 음성 감지가 시작되었다는 판단이 되었을 때, 이 시간 만큼 이전의 소리까지 포함한다는 것입니다. 이전 경험만으로는 이 값이 있을 때와 없을 때의 차이는 모르겠지만, 음성 시작 부분을 놓치지 않도록 한다고 합니다. 예를 들어, 누군가 말을 시작하기 직전에 약간의 소음이 있는 경우, 이 패딩을 통해 해당 소음과 함께 음성 시작 부분을 포함하여 캡처할 수 있습니다.
  • Silence Duration (ms) -200 (무음 지속 시간): 기본 값은 200ms로 설정되어 있습니다. 마우스나 키보드 같은 말하기를 끝냈다는 신호를 보낼 장치가 없는 환경이라면, 말하기로 말하기가 끝났다는 것을 표현해야 합니다. 사람의 대표적인 방법이 침묵입니다. 침묵은 말하기를 끝낸 것이 아니고 잠깐 멈춤인 경우도 있습니다. 그래서 말하기 끝남으로 인식할 수 있는 침묵의 길이가 필요합니다. 이것은 말하는 사람의 말하기 스타일이나 환경에 영향을 받기 때문에 설정 값을 맞춰나가는 노력이 필요합니다.

 

이런 내용을 볼 때, gpt-4o-realtime-preview 모델은 끼어들기에도 잘 대응하고, turn detection도 잘하는 훈련이 더해진 모델이겠구나라고 판단해 볼 수 있습니다. 

 

실시간 대화를 잘하려면 말하기와 듣기 채널이 분리 되어야 합니다. OpenAI API를 보면 이런 구현을 추가로 하고 있음을 알 수 있습니다.

Quickstart

Realtime API를 사용하려면 서버 기반으로 구현해야 합니다.

빠른 테스트를 위해서는 콘솔 데모를 활용할 수 있지만, 실제 서비스 구축 시에는 프론트엔드에서 직접 사용하는 것보다 LiveKit, Twilio, Agora 등의 파트너사의 통합 솔루션을 고려하는 것이 좋다고 합니다.

 

Realtime API는 WebSocket을 통해 통신하는 상태 저장(stateful) 및 이벤트 기반  API입니다.

  • url: wss://api.openai.com/v1/realtime (wss 프로토콜 사용)
    • 쿼리 매개변수: ?model=gpt-4o-realtime-preview-2024-10-01 (사용할 모델 지정)
  • headers:
    • Authorization: Bearer YOUR_API_KEY (API 키를 Bearer 토큰 형식으로 전달)
    • OpenAI-Beta: realtime=v1  (베타 버전임을 명시)
  • 서버에서 발생하는 이벤트 –  이벤트 이름, openai-dotnet 이벤트
    • session.created – 새로운 연결이 설정되어 세션이 생성될 때, ConversationSessionStartedUpdate
    • session.updated – 세션이 업데이트될 때, ConversationSessionConfiguredUpdate
    • conversation.created – 세션이 만들어지자마자 대화가 시작될 준비가 되었을 때
    • conversation.item
      • .created, ConversationItemAcknowledgedUpdate
      • .deleted, ConversationItemDeletedUpdate
      • .input_audio_transcription
        • .completed, ConversationInputTranscriptionFinishedUpdate
          • 입력 오디오의 음성-텍스트 변환이 활성화되어 있고 변환이 성공했을 때.  즉, 사용자가 음성 입력을 하고 이 음성이 성공적으로 텍스트로 변환되었을 때
        • .failed, ConversationInputTranscriptionFailedUpdate
        • .truncated, ConversationItemTruncatedUpdate
          • 클라이언트에서 이전 assistant의 오디오 메시지 항목을 잘랐을 때. 즉, 클라이언트가 assitant가 전달한 오디오 메시지의 일부분을 삭제하거나 줄였을 때, 이 작업이 완료되었음을 서버에 알리는 역할을 합니다. 이를 통해 서버는 변경된 오디오 메시지 상태를 인지하고 관리할 수 있습니다.
      • input_audio_buffer
        • .committed, ConversationInputAudioBufferCommittedUpdate
          • 음성 입력이 완료되어 처리될 준비가 되었을 때. 클라이언트가 직접 입력을 완료했거나, 서버가 음성 활동이 끝났다고 판단했을 때
        • .cleared, ConversationInputAudioBufferClearedUpdate
          • 클라이언트에서 입력 오디오 버퍼를 지웠을 때. 즉, 사용자가 음성 입력을 취소하거나 삭제했을 때 발생하며, 서버는 이 이벤트를 통해 오디오 버퍼를 비우고 관련된 처리를 중단할 수 있습니다.
        • .speech_started, ConversationInputSpeechStartedUpdate
        • .speech_stopped, ConversationInputSpeechFinishedUpdate
      • response
        • .created, ConversationResponseStartedUpdate
        • .done, ConversationResponseFinishedUpdate
        • .output_item
          • .added, ConversationItemStartedUpdate
          • .done, ConversationItemFinishedUpdate
            • 스트리밍을 마칠 때, 응답이 interrupted, incomplete, or cancelled 될 때.
        • content_part
          • .added, ConversationContentPartStartedUpdate
          • .done, ConversationContentPartFinishedUpdate
        • .text
          • .delta, ConversationTextDeltaUpdate
          • .done, ConversationTextDoneUpdate
        • .audio_transcript
          • .delta, ConversationOutputTranscriptionDeltaUpdate
          • .done, ConversationOutputTranscriptionFinishedUpdate
        • .audio
          • .delta, ConversationAudioDeltaUpdate
          • .done, ConversationAudioDoneUpdate
        • function_call_arguments
          • .delta, ConversationFunctionCallArgumentsDeltaUpdate
          • .done, ConversationFunctionCallArgumentsDoneUpdate
        • rate_limits.updated, ConversationRateLimitsUpdatedUpdate
    • error, ConversationErrorUpdate
  • 클라이언트에서 발생할 수 있는 이벤트
About the Author
(주)뉴테크프라임 대표 김현남입니다. 저에 대해 좀 더 알기를 원하시는 분은 아래 링크를 참조하세요. http://www.umlcert.com/kimhn/

Leave a Reply

*