실시간 음성을 텍스트로 변환하기
이 가이드에서는 실시간으로 음성을 텍스트로 변환하는 샘플 애플리케이션을 실행해볼 수 있습니다. 마이크를 통해 입력되는 음성이 즉시 텍스트로 변환되어 표시됩니다. 이 페이지의 예제는 Python을 사용하여 gRPC 양방향 스트리밍 기반의 음성 인식을 수행하는 예제이지만, gRPC를 지원하는 언어라면 각 언어의 클라이언트 라이브러리를 생성하여 사용할 수 있습니다.
1. 사전 요구 사항
- Python, gRPC에 대한 사전 지식 (grpc.io 참조)
- 마이크가 연결된 기기
- API 키 (API Console에서 발급 가능)
WARNING
- 실시간 음성 인식은 현재 ‘한국어와 영어’만 지원합니다.
- 노래 음원 혹은 배경음악이 크게 들리는 오디오는 텍스트 변환을 지원하지 않습니다.
2. Protocol Buffer 파일 저장
gRPC는 프로토콜 버퍼의 정의를 따라 통신합니다. Daglo Realtime STT에서 제공하는 Protocol Buffer는 다음과 같습니다. 다음 내용을 speech.proto
파일로 저장해 주세요.
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"이 적용됩니다.
// 지원되는 언어 코드:
// - ko-KR
// - en-US
string language_code = 1;
// `true`인 경우, 발화 도중의 임시 부분 결과를 즉시 반환하도록 합니다
// (이러한 잠정 결과는 `is_final=false` 플래그로 표시됨).
// `false`이거나 생략하면 `is_final=true`인 결과만 반환됩니다.
bool interim_results = 2;
}
// `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;
}
3. 클라이언트 코드 작성
3-1. gRPC 및 Protobuf 라이브러리 설치
gRPC 클라이언트 생성 및 통신을 위해 필요한 라이브러리를 설치합니다.
pip install grpcio grpcio-tools
3-2. 오디오 입력 스트림 처리를 위한 라이브러리 설치
이 예제에서는 pyaudio
를 사용합니다. pyaudio
를 사용하기 위해서는 PortAudio라는 라이브러리가 필수적으로 설치되어 있어야 합니다. 플랫폼 별로 PortAudio를 설치한 뒤(pyaudio
패키지에 포함되어있을 수도 있음) pyaudio
패키지를 설치합니다.
pip install pyaudio
3-3. Protobuf 파일 컴파일
제공된 .proto
파일을 Python 코드로 컴파일해야 합니다. 다음 명령어를 실행하여 필요한 파일을 생성하세요.
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
와 같은 이름으로 저장하세요.
import argparse
import grpc
import speech_pb2
import speech_pb2_grpc
import pyaudio
import sys
# 오디오 스트림 설정
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):
"""
마이크 스트림에서 오디오 데이터를 읽어 스트리밍 요청을 생성하는 제너레이터 함수.
"""
# 첫 번째 요청: 설정(Config) 전송
config = speech_pb2.RecognitionConfig(
language_code=language_code,
interim_results=interim_results
)
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. 클라이언트 코드 실행
python client.py --server apis.daglo.ai --token $API_TOKEN
4. 문제 해결
- API Token이 올바르지 않은 경우, API Console에서 토큰이 유효한지 확인하세요.
- 음성 인식 품질이 좋지 않은 경우, 조용한 환경에서 다시 시도하거나 마이크 설정을 확인하세요.