안녕하세요, 코린이의 코딩 학습기 채니 입니다.
개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.
STT (Speech-To-Text) 기술을 사용해야하는 프로젝트가 생겨서 Google, Naver, Azure가 제공하는 STT 서비스를 기술 검토해보았다.
검토사항은 아래와 같다.
- 스트리밍 처리가 가능한가
- 한국어를 가장 잘 인식할 수 있는가
- 가격은 저렴한가
Naver Cloud (Clova)
- 한국어 / 영어 / 일본어 / 중국어 지원
- 인식 가능 시간
- 장문 인식: 최대 2시간 (sync), 최대 6시간 (Batch, async)
- 단문 인식: 최대 60초
- 인식 파일 크기
- 장문인식 : 최대 2GB (빌더), 최대 20GB (API)
- 단문인식 : 최대 10MB (빌더, API)
- Clova 공식 홈페이지
가격
서비스 중 이벤트 탐지 서비스는 박수나 음악 소리를 인식하는 기능이고, 이 외 서비스는 서비스명을 보면 유추할 수 있을 것이다.
실시간 음성 처리를 해야하므로 장문 인식 유형 & Basic 플랜 & 음성 인식 서비스만을 사용한다고 가정했을 때 가격은 아래와 같다.
- 1분: 20원
- 1시간: 1,200원
리소스 한도
별도 리소스 한도에 관한 정보를 찾지는 못했지만 chat streaming api 동시접속 에러 관련 아티클을 발견하였다.
"현재는 별도 유량을 제한하는 정책은 없으나, 장문 인식에서는 sync, async 두 가지 방식을 지원하고 있으며, 초당 10개 sync 요청 가능하며 Speech에서 처리 가능한 작업 수는 20개입니다.
따라서 초당 10개씩 2초 간 20개 작업 요청하는 경우 그 이후의 요청에 대해서는 지연/에러가 발생할 수 있습니다."
위 아티클과 답변을 토대로 이용량의 한도가 정해져있다는 것을 알 수 있다.
서비스 이용해보기
실시간 스트리밍의 경우, gRPC 방식을 통해서만 접근이 가능하다.
⭐️ gRPC 관련 아티클
https://chanychu.tistory.com/537
Anaconda 설치 및 설정 (이미 설치되어 있는 경우 생략 가능)
$ brew install --cask anaconda
$ /opt/homebrew/anaconda3/bin/conda init zsh
$ source ~/.zshrc
가상환경 생성
$ conda create -n naverCloudSttSample python=3.13
Protoc Compiler 설치 및 준비
$ pip install grpc-tools
$ touch nest.proto
nest.proto
파일 작성
syntax = "proto3";
option java_multiple_files = true;
package com.nbp.cdncp.nest.grpc.proto.v1;
enum RequestType {
CONFIG = 0;
DATA = 1;
}
message NestConfig {
string config = 1;
}
message NestData {
bytes chunk = 1;
string extra_contents = 2;
}
message NestRequest {
RequestType type = 1;
oneof part {
NestConfig config = 2;
NestData data = 3;
}
}
message NestResponse {
string contents = 1;
}
service NestService {
rpc recognize(stream NestRequest) returns (stream NestResponse){};
}
nest.proto
파일 컴파일 (gRPC 코드 생성)
$ python -m grpc_tools.protoc -I=. --python_out=. --grpc_python_out=. nest.proto
해당 과정을 거쳤다면 위와 같은 파일이 생성된 것을 확인할 수 있다.
패키지 설치
requirements.txt 파일 생성
grpcio==1.67.1
grpcio-tools==1.67.1
protobuf==5.28.3
PyAudio==0.2.14
setuptools==75.1.0
wheel==0.44.0
$ pip install -r requirements.txt
예제코드
import grpc
import json
import time
import threading
import nest_pb2
import nest_pb2_grpc
import pyaudio
CLIENT_SECRET = "YOUR SECRET KEY"
RATE = 16000
CHUNK_SIZE = 16000
THRESHOLD = 500
SILENCE_THRESHOLD = 4000
def get_microphone_stream():
audio = pyaudio.PyAudio()
try:
stream = audio.open(
format=pyaudio.paInt16,
channels=1,
rate=RATE,
input=True,
frames_per_buffer=CHUNK_SIZE
)
return stream
except OSError as error:
print(f"[WARNING]: Unable to access microphone. {error}")
def generate_requests():
# 초기 설정 요청: 음성 인식 설정
yield nest_pb2.NestRequest(
type=nest_pb2.RequestType.CONFIG,
config=nest_pb2.NestConfig(
config=json.dumps({"transcription": {"language": "ko"}, "semanticEpd": {"skipEmptyText": True}})
)
)
stream = get_microphone_stream()
if stream is None:
raise Exception("[ERROR]: Stream is None.")
def print_every_second():
current_time = time.strftime("%H:%M:%S", time.localtime())
print(f"1초마다 출력됩니다. 현재 시간: {current_time}")
threading.Timer(1, print_every_second).start()
print_every_second()
while True:
try:
chunk = stream.read(CHUNK_SIZE, exception_on_overflow=False)
yield nest_pb2.NestRequest(
type=nest_pb2.RequestType.DATA,
data=nest_pb2.NestData(
chunk=chunk,
extra_contents=json.dumps({"seqId": 0, "epFlag": False})
)
)
except Exception:
pass
def save_text_to_file(text):
if text.strip():
with open("transcription_output.txt", "a", encoding="utf-8") as file:
file.write(f"{text}\n")
def main():
# Clova Speech 서버에 대한 보안 gRPC 채널을 설정
channel = grpc.secure_channel(
"clovaspeech-gw.ncloud.com:50051",
grpc.ssl_channel_credentials()
)
stub = nest_pb2_grpc.NestServiceStub(channel) # NestService에 대한 stub 생성
metadata = (("authorization", f"Bearer {CLIENT_SECRET}"),) # 인증 토큰과 함께 메타데이터 설정
responses = stub.recognize(generate_requests(), metadata=metadata) # 생성된 요청으로 인식(recognize) 메서드 호출
try:
# 서버로부터 응답을 반복 처리
for response in responses:
response_data = json.loads(response.contents)
if 'transcription' in response_data:
transcription = response_data['transcription']
print(f"Transcript: {transcription['text']}")
save_text_to_file(transcription['text'])
except grpc.RpcError as e:
# gRPC 오류 처리
print(f"Error: {e.details()}")
finally:
channel.close() # 작업이 끝나면 채널 닫기
if __name__ == "__main__":
main()
공식 홈페이지의 실시간 스트리밍 인식 예제 코드를 참고하여 실시간으로 마이크에 말하는 음성에 대해 텍스트로 변환해주는 python 코드를 짜보았다.
요청 파라미터 공식 문서에서 필요한 파라미터를 찾아 추가하여 좀 더 세밀한 작업을 할 수 있게끔 처리할 수도 있다.
나는 아래와 같이 음성 인식 설정을 하였다.
인식하는 언어를 한국어로 설정 ("transcription": {"language": "ko"}
)
인식 결과가 없는 값에 대한 전송을 하지 않도록 ("semanticEpd": {"skipEmptyText": True}
) 설정
위 코드를 보면 알겠지만, nest_pb2.NestRequest
함수를
def generate_requests():
# 1. 초기 설정 요청: 음성 인식 설정
yield nest_pb2.NestRequest(
type=nest_pb2.RequestType.CONFIG,
config=nest_pb2.NestConfig(
config=json.dumps({"transcription": {"language": "ko"}, "semanticEpd": {"skipEmptyText": True, "usePeriodEpd": True, "useWordEpd": True, "durationThreshold": 4000}})
)
)
...
...
while True:
try:
chunk = stream.read(CHUNK_SIZE, exception_on_overflow=False)
# 2. 음성 인식 요청
yield nest_pb2.NestRequest(
type=nest_pb2.RequestType.DATA,
data=nest_pb2.NestData(
chunk=chunk,
extra_contents=json.dumps({"seqId": 0, "epFlag": False})
)
)
except Exception:
pass
1. 초기 설정 요청: 음성 인식 설정
과 2. 음성 인식 요청
시 사용하는 것을 확인할 수 있는데,
이 때 차이점은 type이 CONFIG이고, DATA인 것이다.
- CONFIG
"config에 정의한 설정으로 음성 인식을 해주세요"라고 요청
⭐️ 반드시recognize
함수(실시간 스트리밍 인식 API)를 처음 실행 시 전달해줘야 한다. - DATA
음성 인식하려는 chunk 데이터를 전달
위 코드에서도 CONFIG 설정을 먼저 한 후, 마이크 스트리밍 데이터를 CHUNK_SIZE만큼 잘라와 chunk 데이터를 넘겨주어 음성 인식 요청을 한다.
가장 중요한 Auth 설정은
def main():
...
...
metadata = (("authorization", f"Bearer {CLIENT_SECRET}"),) # 인증 토큰과 함께 메타데이터 설정
responses = stub.recognize(generate_requests(), metadata=metadata) # 생성된 요청으로 인식(recognize) 메서드 호출
recognize
함수 호출 시 metadata를 생성하여 같이 넘겨주어 처리해준다.
성능 테스트
샘플동영상을 10분 정도 틀어놓고 얼마나 잘 인식하는지 테스트 해보았다.
결과 값은 아래 파일을 참고하자!
(참고로 테스트를 할 때 durationThreshold: 4000
으로 설정하였다. - 4000초 뒤 문장을 끊게끔 설정)
성능도 괜찮았고, 가격도 적당한 편!
아마 Clova를 사용하지 않을까 싶다.
'AI' 카테고리의 다른 글
STT) Azure STT 기술 검토 (0) | 2024.12.10 |
---|---|
STT) Google Cloud STT 기술 검토 (0) | 2024.11.27 |