01. Speech-to-Text 직접 호출 v2
이 노트북은 TTS로 짧은 샘플 음성을 만든 뒤 STT API로 다시 전사합니다. 파일 객체가 client.audio.transcriptions.create(...)에 어떻게 전달되는지 직접 확인합니다.
# Colab 또는 로컬 노트북 실행 환경을 구분하기 위해 sys를 가져옵니다.
import sys
# 패키지 설치 명령을 현재 Python 커널에서 실행하기 위해 subprocess를 가져옵니다.
import subprocess
# 패키지 설치 여부를 확인하기 위해 importlib.util을 가져옵니다.
import importlib.util
# 환경 변수에서 API 키를 읽고 설정하기 위해 os를 가져옵니다.
import os
# API 키를 화면에 노출하지 않고 입력받기 위해 getpass를 가져옵니다.
import getpass
# .env 파일 위치를 다루기 위해 pathlib의 Path를 가져옵니다.
from pathlib import Path
# google.colab 모듈이 있으면 현재 런타임이 Google Colab이라고 판단합니다.
IN_COLAB = "google.colab" in sys.modules
# 노트북에서 사용하는 import 이름과 pip 패키지 이름을 짝지어 둡니다.
REQUIRED_PACKAGES = {
"openai": "openai>=2.26.0",
"dotenv": "python-dotenv>=1.2.2",
"pydantic": "pydantic>=2.11.0",
"PIL": "pillow>=12.1.1",
"requests": "requests>=2.32.5",
"numpy": "numpy>=2.3.3",
"websockets": "websockets>=15.0.1",
"websocket": "websocket-client>=1.8.0",
"nest_asyncio": "nest-asyncio>=1.6.0",
}
def ensure_package(import_name: str, package_name: str) -> None:
if importlib.util.find_spec(import_name) is not None:
return
subprocess.check_call(
[sys.executable, "-m", "pip", "install", "-q", package_name]
)
if IN_COLAB:
for import_name, package_name in REQUIRED_PACKAGES.items():
ensure_package(import_name, package_name)
from dotenv import load_dotenv
load_dotenv(Path.cwd() / ".env")
if not os.getenv("OPENAI_API_KEY"):
secret_key = None
try:
from google.colab import userdata
secret_key = userdata.get("OPENAI_API_KEY")
except Exception:
secret_key = None
if secret_key:
os.environ["OPENAI_API_KEY"] = secret_key
else:
entered_key = getpass.getpass("OPENAI_API_KEY를 입력하세요: ").strip()
if entered_key:
os.environ["OPENAI_API_KEY"] = entered_key
if not os.getenv("OPENAI_API_KEY"):
raise RuntimeError(
"OPENAI_API_KEY가 없습니다. Colab Secrets, 수동 입력, 또는 .env 파일로 설정해 주세요."
)
print(f"개발환경: {'Colab' if IN_COLAB else '로컬'}")
print("OPENAI_API_KEY 준비 완료")
개발환경: 로컬
OPENAI_API_KEY 준비 완료
실습 전에 보는 핵심 개념과 API
핵심 개념
- STT (Speech-to-Text, 음성-텍스트 변환)는 음성 파일을 텍스트로 바꾸는 작업입니다.
- 기본 전사는 결과를 문자열로 바로 받을 수 있고, 자세한 전사는 단어별 시간 정보와 세그먼트 정보를 포함한 구조화 응답으로 받을 수 있습니다.
- prompt를 함께 주면 전문 용어, 고유명사, 상품명처럼 틀리기 쉬운 단어를 더 잘 인식하도록 도울 수 있습니다.
API 소개
- client.audio.transcriptions.create(...)는 오디오 파일을 업로드해 텍스트 전사 결과를 받는 전용 API입니다.
- 이 노트북은 기본 전사와 JSON 전사를 비교해, 단순 결과와 구조화 결과가 어떻게 다른지 보여 줍니다.
API 호출부와 주요 매개변수
transcription = client.audio.transcriptions.create(
model="gpt-4o-mini-transcribe",
file=audio_file,
response_format="text",
)
json_result = client.audio.transcriptions.create(
model="gpt-4o-mini-transcribe",
file=audio_file,
response_format="json",
language="ko",
prompt="OpenAI API, 음성 인식, 교육 실습",
)
- model
- 보통 gpt-4o-mini-transcribe, gpt-4o-transcribe, whisper-1 같은 전사 모델을 넣습니다.
- 기본값: 실질적인 기본값이 없으므로 명시하는 것이 안전합니다.
- file
- 전사할 오디오 파일 객체입니다.
- MP3, WAV 같은 오디오 파일을 바이너리 모드로 열어 전달합니다.
- 기본값: 없습니다.
- response_format
- 자주 쓰는 값은 text, json, verbose_json, srt, vtt입니다.
- 학습용으로 가장 단순한 결과를 보려면 text, 구조화 필드 확인이 목적이면 json이나 verbose_json을 사용합니다.
- 기본값: 엔드포인트와 모델 조합에 따라 기대값이 달라질 수 있으므로 이 노트북처럼 명시하는 것이 가장 안전합니다.
- language
- ko, en, ja처럼 언어 코드를 미리 줄 수 있습니다.
- 다국어 오디오가 아니고 언어가 분명할 때 명시하면 전사 안정성을 높이는 데 도움이 됩니다.
- 기본값: 생략하면 모델이 자동 감지합니다.
- prompt
- 전문 용어, 고유명사, 도메인 맥락 같은 힌트를 넣습니다.
- 모델이 자주 틀리는 단어가 있을 때 특히 유용합니다.
- 기본값: 없습니다. 생략하면 힌트 없이 일반 전사로 진행합니다.
- timestamp_granularities
- 자세한 시간 정보를 받을 때는 보통 word, segment 같은 값을 사용합니다.
- 자막 생성이나 단어 단위 탐색이 필요할 때만 켜는 것이 일반적입니다.
- 기본값: 시간 정보가 필요한 경우에만 명시하는 선택 매개변수로 보는 편이 안전합니다.
요청/응답 필드에서 볼 것
- STT 실습에서는 요청에서 model, file, response_format, language, prompt를 먼저 읽고, 지금 호출이 단순 전사용인지 구조화 전사용인지 먼저 구분해 보세요.
- response_format="text" 결과는 먼저 화면에 그대로 출력해 보고, 저장한 텍스트 파일과 비교해 줄바꿈이나 후처리 차이가 없는지도 확인하면 좋습니다.
- json 또는 verbose_json 결과를 볼 때는 text를 먼저 확인한 뒤, 그다음 words[], segments[]처럼 세부 필드가 실제로 들어왔는지 순서대로 확인하는 것이 가장 빠릅니다.
- 전사 품질이 기대보다 낮으면 가장 먼저 language와 prompt를 다시 보고, 같은 오디오로 힌트 없이 실행한 결과와 나란히 비교해 보세요.
- 실습 로그에는 오디오 파일 경로, 사용 모델, 저장한 전사 파일 경로, 그리고 가능하면 usage나 응답 메타데이터를 함께 남겨 두면 모델을 바꿔 재실험하기 쉽습니다.
1단계. 실행 환경 준비
STT는 오디오 파일이 있어야 실습할 수 있습니다. 이 준비 셀은 저장 위치와 모델명을 먼저 확정합니다.
# 운영체제 환경 변수를 읽기 위해 os 모듈을 가져옵니다.
import os
# JSON 데이터를 저장하고 보기 좋게 출력하기 위해 json 모듈을 가져옵니다.
import json
# 오디오 base64 데이터를 다루기 위해 base64 모듈을 가져옵니다.
import base64
# 실행 시간을 측정하기 위해 time 모듈을 가져옵니다.
import time
# 비동기 Realtime 예제에서 이벤트 루프를 사용하기 위해 asyncio를 가져옵니다.
import asyncio
# 파일 경로를 안전하게 다루기 위해 Path를 가져옵니다.
from pathlib import Path
# .env 파일의 환경 변수를 읽기 위해 load_dotenv를 가져옵니다.
from dotenv import load_dotenv
# OpenAI API를 직접 호출하기 위해 OpenAI 클라이언트를 가져옵니다.
from openai import OpenAI
# 현재 실행 위치를 저장합니다.
CURRENT_DIR = Path.cwd()
# 루트에서 실행하는 경우 audio 트랙 폴더를 찾습니다.
if (CURRENT_DIR / "06.audio").exists():
# 워크스페이스 루트에서 실행 중이면 06.audio를 실습 루트로 사용합니다.
AUDIO_ROOT = CURRENT_DIR / "06.audio"
# 하위 폴더에서 실행하는 경우 경로 조각에서 06.audio를 찾습니다.
elif "06.audio" in [part for part in CURRENT_DIR.parts]:
# 06.audio까지의 경로를 복원합니다.
AUDIO_ROOT = Path(*CURRENT_DIR.parts[: CURRENT_DIR.parts.index("06.audio") + 1])
# 그 밖의 경우 상대 경로를 사용합니다.
else:
# 현재 위치 기준 06.audio를 실습 루트로 사용합니다.
AUDIO_ROOT = CURRENT_DIR / "06.audio"
# 워크스페이스 루트는 audio 트랙의 상위 폴더입니다.
WORKSPACE_ROOT = AUDIO_ROOT.parent
# v2 결과 저장 폴더를 정합니다.
OUTPUT_DIR = AUDIO_ROOT / "output" / "v2"
# 결과 저장 폴더를 생성합니다.
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
# 워크스페이스 루트의 .env 파일을 읽습니다.
load_dotenv(WORKSPACE_ROOT / ".env")
# API 키가 없으면 명확한 오류로 중단합니다.
if not os.getenv("OPENAI_API_KEY"):
# 교육생이 바로 확인할 수 있도록 환경 변수 이름을 알려 줍니다.
raise RuntimeError(
"OPENAI_API_KEY가 없습니다. 워크스페이스 루트의 .env 파일을 확인해 주세요."
)
# OpenAI API 클라이언트를 생성합니다.
client = OpenAI()
# 음성 인식 모델명을 환경 변수에서 읽습니다.
TRANSCRIBE_MODEL = os.getenv("OPENAI_TRANSCRIBE_MODEL", "gpt-4o-mini-transcribe")
# 음성 합성 모델명을 환경 변수에서 읽습니다.
TTS_MODEL = os.getenv("OPENAI_TTS_MODEL", "gpt-4o-mini-tts")
# 오디오 입출력 LLM 모델명을 환경 변수에서 읽습니다.
AUDIO_LLM_MODEL = os.getenv("OPENAI_AUDIO_LLM_MODEL", "gpt-audio-mini")
# Realtime API 모델명을 환경 변수에서 읽습니다.
REALTIME_MODEL = os.getenv("OPENAI_REALTIME_MODEL", "gpt-realtime-mini")
# 워크스페이스 기준 상대 경로를 반환하는 함수를 정의합니다.
def workspace_path(path: Path) -> str:
# 절대 경로를 워크스페이스 기준 / 구분 문자열로 변환합니다.
return path.resolve().relative_to(WORKSPACE_ROOT.resolve()).as_posix()
# 환경 정보를 출력합니다.
print(f"오디오 실습 폴더: {AUDIO_ROOT}")
# 결과 저장 폴더를 출력합니다.
print(f"결과 저장 폴더: {OUTPUT_DIR}")
# 사용할 음성 인식 모델을 출력합니다.
print(f"STT 모델: {TRANSCRIBE_MODEL}")
# 사용할 음성 합성 모델을 출력합니다.
print(f"TTS 모델: {TTS_MODEL}")
오디오 실습 폴더: c:\Users\USER\Desktop\AS.1.1\d02\06.audio
결과 저장 폴더: c:\Users\USER\Desktop\AS.1.1\d02\06.audio\output\v2
STT 모델: gpt-4o-mini-transcribe
TTS 모델: gpt-4o-mini-tts
2단계. 전사용 샘플 음성 만들기
마이크 녹음을 요구하면 실행 환경마다 실패할 수 있습니다. 그래서 TTS API로 짧은 샘플 MP3를 만들어 항상 같은 입력으로 STT를 검증합니다.
# 샘플 음성 파일 경로를 정합니다.
sample_audio_path = OUTPUT_DIR / "01-02_stt_sample.mp3"
# 샘플 음성으로 읽을 문장을 준비합니다.
sample_text = "안녕하세요. 이 파일은 OpenAI 음성 인식 API 실습을 위해 생성한 짧은 한국어 샘플입니다."
# TTS 스트리밍 응답을 열어 파일로 저장합니다.
with client.audio.speech.with_streaming_response.create(
# 음성 합성 모델을 지정합니다.
model=TTS_MODEL,
# 합성할 목소리를 지정합니다.
voice="alloy",
# 합성할 텍스트를 전달합니다.
input=sample_text,
# MP3 형식으로 결과를 받습니다.
response_format="mp3",
) as response:
# 스트리밍 응답을 MP3 파일로 저장합니다.
response.stream_to_file(sample_audio_path)
# 샘플 파일 위치를 출력합니다.
print(f"샘플 오디오 저장: {workspace_path(sample_audio_path)}")
# 파일 크기를 출력합니다.
print(f"샘플 크기: {sample_audio_path.stat().st_size} bytes")
샘플 오디오 저장: 06.audio/output/v2/01-02_stt_sample.mp3
샘플 크기: 125568 bytes
3단계. 기본 전사와 verbose JSON
기본 전사는 가장 단순한 텍스트 결과를 반환합니다. json 응답은 단순 문자열보다 구조화된 필드를 제공하므로 디버깅과 품질 확인에 유용합니다.
# 샘플 오디오 파일을 바이너리 읽기 모드로 엽니다.
with sample_audio_path.open("rb") as audio_file:
# 음성 인식 API를 직접 호출해 텍스트 형식 전사를 요청합니다.
transcript_text = client.audio.transcriptions.create(
# 음성 인식 모델을 지정합니다.
model=TRANSCRIBE_MODEL,
# 전사할 오디오 파일 객체를 전달합니다.
file=audio_file,
# 결과를 문자열로 받습니다.
response_format="text",
)
# 텍스트 전사 결과를 저장합니다.
(OUTPUT_DIR / "01-03_stt_basic_transcript.txt").write_text(
str(transcript_text) + "\n",
encoding="utf-8",
)
# 전사 결과를 출력합니다.
print(transcript_text)
# 샘플 오디오 파일을 다시 엽니다.
with sample_audio_path.open("rb") as audio_file:
# json 형식으로 구조화된 전사 결과를 요청합니다.
json_result = client.audio.transcriptions.create(
# 같은 음성 인식 모델을 사용합니다.
model=TRANSCRIBE_MODEL,
# 같은 오디오 파일을 전달합니다.
file=audio_file,
# 자세한 JSON 객체를 받습니다.
response_format="json",
# 한국어 오디오임을 힌트로 제공합니다.
language="ko",
# 도메인 단어를 prompt로 제공해 인식 맥락을 보강합니다.
prompt="OpenAI API, 음성 인식, 교육 실습",
)
# SDK 객체를 dict로 변환합니다.
json_data = (
json_result.model_dump() if hasattr(json_result, "model_dump") else dict(json_result)
)
# json 결과를 JSON 파일로 저장합니다.
(OUTPUT_DIR / "01-03_stt_json_transcript.json").write_text(
json.dumps(json_data, ensure_ascii=False, indent=2) + "\n",
encoding="utf-8",
)
# json 결과의 주요 키를 출력합니다.
print(f"json keys: {list(json_data.keys())}")
안녕하세요? 이 파일은 OpenAI 음성 인식 API 실습을 위해 생성한 짧은 한부어 샘플입니다.
json keys: ['text', 'logprobs', 'usage']'AI System > OpenAI API와 바이브 코딩으로 배우는 AI 서비스 개발' 카테고리의 다른 글
| d02 - 06. Audio - 03. audio in llm v2 (0) | 2026.06.02 |
|---|---|
| d02 - 06. Audio - 02.tts (0) | 2026.06.02 |
| d02 - 05. Image - 04. workflow (0) | 2026.06.02 |
| d02 - 05. Image - 03. analysis (0) | 2026.06.02 |
| d02 - 05. Image - 02. editing (0) | 2026.06.02 |