Skip to content

실시간 음성을 텍스트로 변환하기 ​

이 가이드에서는 실시간으로 음성을 텍스트로 변환하는 샘플 애플리케이션을 실행해볼 수 있습니다. 마이크를 통해 입력되는 음성이 즉시 텍스트로 변환되어 표시됩니다. 이 페이지의 예제는 Python을 사용하여 gRPC 양방향 스트리밍 기반의 음성 인식을 수행하는 예제이지만, gRPC를 지원하는 언어라면 각 언어의 클라이언트 라이브러리를 생성하여 사용할 수 있습니다.

1. 사전 요구 사항 ​

  • Python, gRPC에 대한 사전 지식 (grpc.io 참조)
  • 마이크가 연결된 기기
  • API 키 (API Console에서 발급 가능)

WARNING

  • 실시간 음성 인식은 현재 ‘한국어와 영어’만 지원합니다.
  • 한 요청 스트림당 최대 6시간까지 지원합니다.
  • 노래 음원 혹은 배경음악이 크게 들리는 오디오는 텍스트 변환을 지원하지 않습니다.

2. Protocol Buffer 파일 저장 ​

gRPC는 프로토콜 버퍼의 정의를 따라 통신합니다. Daglo Realtime STT에서 제공하는 Protocol Buffer는 다음과 같습니다. 다음 내용을 speech.proto 파일로 저장해 주세요.

protobuf
syntax = "proto3";

package dagloapis.speech.v1;

// 음성인식 API를 구현하는 서비스
service Speech {
  // 양방향 스트리밍 방식으로 음성 인식을 수행합니다. 오디오를 전송하는 동시에 결과를 수신합니다.
  rpc StreamingRecognize(stream StreamingRecognizeRequest)
      returns (stream StreamingRecognizeResponse) {}
}

// `StreamingRecognize` 메서드에서 클라이언트가 전송하는 최상위 메시지.
// `StreamingRecognizeRequest` 메시지는 두 종류가 있습니다.
// 첫 번째 메시지는 반드시 `config` 필드를 포함해야 하며 `audio_content`는 포함하지 않아야 합니다.
// 이후에 전송되는 모든 메시지는 `audio_content`를 포함해야 하며 `config`는 포함하지 않아야 합니다.
message StreamingRecognizeRequest {
  // 스트리밍 요청은 스트리밍 설정(config) 혹은 오디오 스트림입니다.
  oneof streaming_request {
    // 오디오 및 음성 인식 처리에 관한 설정 정보를 제공합니다.
    RecognitionConfig config = 1;

    // 오디오 스트림 데이터. 연속된 오디오 데이터 조각은 순차적으로 `StreamingRecognizeRequest` 메시지로 전송됩니다.
    // 오디오 소스는 `LINEAR16` 인코딩을 사용하여 캡처 및 전송되어야 합니다.
    // 샘플링 레이트는 `16000Hz`여야 합니다. 필요한 경우 오디오를 다시 샘플링하세요.
    // 모노(1 채널) 오디오만 지원됩니다.
    bytes audio_content = 2;
  }
}

// 요청을 처리하는 방법을 서버에 제공합니다.
message RecognitionConfig {
  // 제공할 오디오의 언어를 선택합니다.
  // 언어 코드는 [BCP-47](https://www.rfc-editor.org/rfc/bcp/bcp47.txt) 표준을 따릅니다.
  // 이 필드는 생략 가능하나, 생략하면 기본값인 "ko-KR"이 적용됩니다.
  // 지원되는 언어 코드(`mixed`의 경우 한글/영문 혼합을 의미합니다):
  // - ko-KR
  // - en-US
  // - mixed
  string language_code = 1;

  // `true`인 경우, 발화 도중의 임시 부분 결과를 즉시 반환하도록 합니다
  // (이러한 잠정 결과는 `is_final=false` 플래그로 표시됨).
  // `false`이거나 생략하면 `is_final=true`인 결과만 반환됩니다.
  bool interim_results = 2;

  // 생략하면 비활성화됩니다. 설정하면 단어 끝점이 지정된 시간(ms) 동안 갱신되지 않을 때
  // 쌓인 결과를 final로 반환합니다. 최소값은 `0`, 최대값은 `10000`(10초) 입니다.
  optional int32 max_silence_ms = 3;
}

// `StreamingRecognizeResponse`는 `StreamingRecognize`에 의해 클라이언트로 반환되는 유일한 메시지입니다. 
// 0개 이상의 `StreamingRecognizeResponse` 메시지가 클라이언트로 스트리밍됩니다.
// 각 응답에서는 `error` 또는 `result` 중 하나의 필드만 설정됩니다.
message StreamingRecognizeResponse {
  // 현재 처리 중인 오디오 부분에 해당하는 결과.
  StreamingRecognitionResult result = 1;

  // 스트림에 대한 전체 오디오 지속 시간(초).
  float total_duration = 2;
}

// 현재 처리 중인 오디오 부분에 해당하는 스트리밍 음성 인식 결과.
message StreamingRecognitionResult {
  // 사용자가 말한 단어를 나타내는 스크립트 텍스트.
  // 단어를 공백으로 구분하는 언어에서, 이 스크립트가 첫 번째 결과가 아닐 경우 앞에 공백이 포함될 수 있습니다. 
  // 각 결과를 연결하면 구분자 없이 전체 스크립트를 얻을 수 있습니다.
  string transcript = 1;

  // `false`인 경우, 이 `StreamingRecognitionResult`는 변경될 수 있는 잠정적인 결과를 나타냅니다.
  // `true`인 경우, 이전 시작점부터 하나의 완성된 발화 부분까지의 해당 오디오 부분에 대한 완성된 음성 인식 결과를 의미합니다.
  bool is_final = 2;
  
  // 음성에서 감지한 언어 코드입니다.
  string language_code = 3;
}

3. 클라이언트 코드 작성 ​

3-1. gRPC 및 Protobuf 라이브러리 설치

gRPC 클라이언트 생성 및 통신을 위해 필요한 라이브러리를 설치합니다.

bash
pip install grpcio grpcio-tools

3-2. 오디오 입력 스트림 처리를 위한 라이브러리 설치

이 예제에서는 pyaudio를 사용합니다. pyaudio를 사용하기 위해서는 PortAudio라는 라이브러리가 필수적으로 설치되어 있어야 합니다. 플랫폼 별로 PortAudio를 설치한 뒤(pyaudio 패키지에 포함되어있을 수도 있음) pyaudio 패키지를 설치합니다.

bash
pip install pyaudio

3-3. Protobuf 파일 컴파일

제공된 .proto 파일을 Python 코드로 컴파일해야 합니다. 다음 명령어를 실행하여 필요한 파일을 생성하세요.

bash
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./speech.proto

위 명령어를 실행하면 speech_pb2.py 와 speech_pb2_grpc.py 파일이 생성됩니다. 이 파일들을 클라이언트 코드와 같은 디렉터리에 두세요.

3-4. 클라이언트 코드 작성

이제 gRPC 클라이언트를 사용하여 StreamingRecognize 메서드에 오디오 데이터를 스트리밍하는 코드를 작성할 수 있습니다. 다음 예제는 오디오 스트리밍 요청을 구성하고 서버로부터 결과를 받는 전체 과정을 보여줍니다. 다음 예제 코드를 client.py 와 같은 이름으로 저장하세요.

python
import argparse
import grpc
import speech_pb2
import speech_pb2_grpc
import pyaudio
import sys

# 오디오 스트림 설정 <CopyButton /><EmailFormButton />
SAMPLE_RATE = 16000
CHUNK = int(SAMPLE_RATE * 0.25) # 0.25초에 해당하는 프레임
CHANNELS = 1
FORMAT = pyaudio.paInt16

def generate_requests(audio_stream, language_code='ko-KR', interim_results=True, max_silence_ms=2500):
    """
    마이크 스트림에서 오디오 데이터를 읽어 스트리밍 요청을 생성하는 제너레이터 함수.
    """
    # 첫 번째 요청: 설정(Config) 전송
    config = speech_pb2.RecognitionConfig(
        language_code=language_code,
        interim_results=interim_results,
        max_silence_ms=max_silence_ms
    )
    yield speech_pb2.StreamingRecognizeRequest(config=config)

    # 이후 요청: 오디오 데이터 전송
    while True:
        try:
            # 오디오 스트림에서 데이터 읽기
            audio_chunk = audio_stream.read(CHUNK)
            if not audio_chunk:
                break
            yield speech_pb2.StreamingRecognizeRequest(audio_content=audio_chunk)
        except IOError as e:
            print(f"Error reading from audio stream: {e}", file=sys.stderr)
            break
            
    # 마지막 요청: 끝(EOS)을 나타내기 위해 빈 메시지를 전송
    yield speech_pb2.StreamingRecognizeRequest()

def run_streaming_recognition_from_mic(server_address, api_token):
    """
    마이크 입력을 사용하여 실시간 스트리밍 음성 인식을 실행하는 메인 함수.
    """
    # gRPC 채널 및 스텁 설정
    creds = grpc.ssl_channel_credentials()
    channel = grpc.secure_channel(server_address, creds)
    stub = speech_pb2_grpc.SpeechStub(channel)

    # API 인증을 위한 메타데이터(헤더)
    metadata = (
         ("authorization", f"Bearer {api_token}"),
    )

    # PyAudio 인스턴스 초기화
    audio = pyaudio.PyAudio()

    # 오디오 스트림 열기
    try:
        stream = audio.open(format=FORMAT,
                            channels=CHANNELS,
                            rate=SAMPLE_RATE,
                            input=True,
                            frames_per_buffer=CHUNK)

        print("마이크 녹음 및 스트리밍 시작. 'Ctrl+C'를 눌러 종료하세요.")
        
        # 요청과 응답을 양방향 스트리밍
        response_iterator = stub.StreamingRecognize(
            generate_requests(stream),
            metadata=metadata
        )
        
        # 응답을 처리하는 루프
        for response in response_iterator:
            if response.result:
                if response.result.is_final:
                    print(f"최종 결과: {response.result.transcript}")
                else:
                    print(f"부분 결과: {response.result.transcript}", end='\r')

    except grpc.RpcError as e:
        print(f"\ngRPC 오류 발생: {e.code()}, {e.details()}", file=sys.stderr)
    except KeyboardInterrupt:
        print("\n녹음을 중단하고 프로그램을 종료합니다.")
    finally:
        # 스트림 및 PyAudio 객체 정리
        if 'stream' in locals() and stream.is_active():
            stream.stop_stream()
            stream.close()
        audio.terminate()
        channel.close()

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="gRPC Speech Recognition Client")
    parser.add_argument(
        "--server",
        type=str,
        required=True,
        help="gRPC server address (e.g., apis.daglo.ai)",
    )
    parser.add_argument("--token", type=str, required=True, help="API Token")

    args = parser.parse_args()
    run_streaming_recognition_from_mic(args.server, args.token)

3-5. 클라이언트 코드 실행

bash
python client.py --server apis.daglo.ai --token $API_TOKEN

4. 문제 해결 ​

  • API Token이 올바르지 않은 경우, API Console에서 토큰이 유효한지 확인하세요.
  • 음성 인식 품질이 좋지 않은 경우, 조용한 환경에서 다시 시도하거나 마이크 설정을 확인하세요.