
이번에는 텍스트를 TTS(Text To Speech, 텍스트 음성 변환) 로 읽어주는 앱을 만들어봅니다.
책 내용을 귀로 들으며 복습할 수 있는 "Python 오디오북 앱" 입니다.
이 앱을 만들면서 Python에서 가장 중요한 에러 처리 패턴인 try-except 구문을 자연스럽게 익혀봅시다.
Google의 TTS API를 Python에서 사용하기 위해 gTTS 라이브러리를 설치합니다.
pip install gTTS
💡 gTTS의 한국어 지원
gTTS는lang='ko'를 지정하면 한국어 음성으로 읽어줍니다.
⚠️ 주의: gTTS는 텍스트를 읽어주기 위해 인터넷 연결이 필요합니다.
오프라인 환경에서는 동작하지 않습니다. 이것이 바로 이번에는 try-except 구문이 등장하는 이유입니다.
아래 코드를 text_reading.py 라는 이름으로 저장하세요.
import streamlit as st
from gtts import gTTS
st.markdown("## Python 오디오북")
st.markdown("책의 '시작하며'를 소리 내어 읽습니다.")
# 읽어주고 싶은 텍스트를 변수에 저장 (트리플 따옴표 """로 여러 줄의 문자열을 다룰 수 있다)
text_to_read = """
이 책는, 파이썬을 배우기 시작했지만, 막상 코딩을 하려고 하면 머릿속이 하얘지는 사람들을 위해 쓰였습니다.
또한, 빨리 실용적인 앱을 만들고 싶다는 마음에 깊이 공감하는 내용으로 구성되어 있습니다.
"""
st.markdown(text_to_read) # 읽어줄 텍스트를 브라우저에 표시한다
# -----------------------------------------------------------------
# 통신 에러에 대비하여, try 블록이 실패해도 자기 자신에게 실패했다는 것을 알린다
# -----------------------------------------------------------------
try:
# 【시도하는 처리】여기서부터
# Google 서버에 텍스트를 보내서, 음성 데이터를 생성
tts = gTTS(text=text_to_read, lang='ko')
# 음성 데이터를 voice.mp3 로 저장
tts.save("voice.mp3")
# 저장된 음성 데이터를 브라우저에서 재생할 수 있도록 한다
st.audio("voice.mp3")
st.success("음성 생성이 완료되었습니다! 재생 버튼을 눌러보세요.")
# 【시도하는 처리】여기까지
except Exception as e:
# 【에러 발생 시의 처리】
# 위의 "시도하는 처리"의 어딘가에서 에러가 발생하면, 이 부분이 실행된다
st.warning("음성 생성에 실패했습니다. 인터넷 연결 상태나, 코드에 오류가 없는지 확인해주세요.")
# 기동 명령어:
# streamlit run text_reading.py
# 종료:
# Ctrl + C
streamlit run text_reading.py
브라우저가 열리면 텍스트와 함께 오디오 플레이어가 표시됩니다.
재생 버튼을 누르면 한국어 음성으로 텍스트를 읽어줍니다.
종료는 터미널에서 Ctrl + C.
from gtts import gTTS
gTTS는 Google Text-to-Speech의 약자입니다.
Google의 TTS 서버에 텍스트를 보내면, MP3 형식의 음성 파일로 변환해서 돌려줍니다.
tts = gTTS(text="안녕하세요", lang='ko') # 한국어 음성 생성
tts.save("voice.mp3") # MP3 파일로 저장
주요 lang 코드:
| 언어 | lang 코드 |
|---|---|
| 한국어 | 'ko' |
| 영어 | 'en' |
| 일본어 | 'ja' |
| 중국어(간체) | 'zh-CN' |
""")로 여러 줄 문자열 다루기text_to_read = """
이 책는, 파이썬을 배우기 시작했지만, 막상 코딩을 하려고 하면 머릿속이 하얘지는 사람들을 위해 쓰였습니다.
또한, 빨리 실용적인 앱을 만들고 싶다는 마음에 깊이 공감하는 내용으로 구성되어 있습니다.
"""
text_to_read: 읽어줄 텍스트를 저장하는 변수입니다."""): 줄바꿈이 포함된 여러 줄의 문자열을 그대로 저장할 수 있습니다.\n을 반복해서 쓰지 않아도 되므로, 긴 텍스트를 다룰 때 편리합니다."(일반 따옴표) vs """(트리플 따옴표) 비교:
# 일반 따옴표: 한 줄만 가능
text = "첫 번째 줄\n두 번째 줄\n세 번째 줄"
# 트리플 따옴표: 여러 줄을 그대로 쓸 수 있다 (읽기 쉬움)
text = """
첫 번째 줄
두 번째 줄
세 번째 줄
"""
트리플 따옴표 + f-string 조합:
트리플 따옴표와 f-string을 함께 쓰면, 변수를 포함한 긴 텍스트를 깔끔하게 만들 수 있습니다.
programing_language = "Python"
text_to_read = f"""
{programing_language}은, 초보자에게 친화적인 프로그래밍 언어입니다.
많은 사람들이 배우기 쉽다고 느끼고 있습니다.
{programing_language}을 사용하여, 다양한 앱을 만들 수 있습니다.
"""
이번 코드의 핵심은 바로 try-except 구문입니다.
try:
# 시도하는 처리 (에러가 날 수 있는 처리)
except Exception as e:
# 에러가 발생했을 때의 처리
gTTS는 Google 서버와 통신해서 음성을 생성합니다.
이 과정에서 다음과 같은 상황이 발생하면 에러(예외)가 일어납니다.
try-except 없이 에러가 발생하면 프로그램이 즉시 중단(크래시) 됩니다.
사용자 입장에서는 빨간 에러 메시지만 보이고 아무것도 할 수 없게 됩니다.
try-except를 사용하면:
try:
tts = gTTS(text=text_to_read, lang='ko') # ← 여기서 에러 발생 가정
tts.save("voice.mp3") # ← 실행되지 않고 건너뜀
st.audio("voice.mp3") # ← 실행되지 않고 건너뜀
st.success("음성 생성 완료!") # ← 실행되지 않고 건너뜀
except Exception as e:
# 에러가 발생하면 여기로 점프한다
st.warning("음성 생성에 실패했습니다. 인터넷 연결 상태나, 코드에 오류가 없는지 확인해주세요.")
# 프로그램은 크래시하지 않고 계속 실행된다
프로그램이 크래시하는 대신 친절한 안내 메시지를 표시하고 계속 실행됩니다.
실제로 자주 발생하는 오탈자 실수 예시입니다.
tts.save("vice.mp3") # ❌ 오탈자: voice → vice
st.audio("voice.mp3") # ← 저장된 파일 이름과 다름 → 에러 발생
| 상황 | try-except 없음 | try-except 있음 |
|---|---|---|
| 프로그램 동작 | 즉시 크래시 | 계속 실행됨 |
| 사용자에게 표시되는 것 | 빨간 에러 스택 트레이스 | 친절한 경고 메시지 |
| 디버깅 | 어디서 에러가 났는지 파악 어려움 | 무엇이 문제인지 안내 가능 |
프로그램 시작
↓
try 블록 진입
↓
에러 발생?
├── NO → try 블록 끝까지 정상 실행 → except 블록은 건너뜀
└── YES → 에러 발생 지점에서 즉시 중단 → except 블록으로 점프
핵심: 에러가 없으면 except 블록은 절대 실행되지 않습니다.
에러가 발생한 순간, try 블록의 나머지는 건너뛰고 except 블록이 실행됩니다.
| 용도 | 예시 |
|---|---|
| 네트워크 통신 | gTTS, requests, OpenAI API 호출 |
| 파일 읽기/쓰기 | CSV 파일 없을 때, 저장 공간 부족 |
| 사용자 입력 | 숫자 입력란에 문자를 넣었을 때 |
| 데이터 파싱 | JSON 형식이 깨졌을 때 |
as e — 에러 상세 정보 활용하기except Exception as e:
st.warning("음성 생성에 실패했습니다. ...")
as e는 발생한 에러 객체를 변수 e에 저장하는 구문입니다.
현재 코드에서는 e를 사용하지 않지만, 필요에 따라 에러 내용을 표시할 수 있습니다.
except Exception as e:
st.warning("음성 생성에 실패했습니다.")
st.error(str(e)) # 에러 메시지를 빨간색으로 표시
print(f"에러 상세: {e}") # 터미널에도 출력 (디버깅용)
개발 중:
st.error(str(e))를 추가하면 어디서 에러가 났는지 바로 파악할 수 있어 디버깅에 유용합니다.
배포 후: 에러 상세를 그대로 사용자에게 보여주면 보안상 위험할 수 있으므로, 친절한 안내 메시지만 표시하는 것이 좋습니다.
이번 코드에서 st.success()와 st.warning()이 새로 등장했습니다.
st.success("음성 생성이 완료되었습니다! 재생 버튼을 눌러보세요.")
st.warning("음성 생성에 실패했습니다. ...")
Streamlit은 상황에 따라 다른 색깔의 알림 박스를 표시하는 함수를 제공합니다.
| 함수 | 색깔 | 용도 |
|---|---|---|
st.success(msg) | 🟢 초록 | 성공 메시지 |
st.warning(msg) | 🟡 노랑 | 경고 메시지 |
st.error(msg) | 🔴 빨강 | 에러 메시지 |
st.info(msg) | 🔵 파랑 | 안내 메시지 |
text_to_read 변수의 내용을 바꾸면, 무엇이든 음성으로 변환할 수 있습니다.
# 예시 1: 영어 학습 — 영어로 읽어주기
text_to_read = "Python is a versatile programming language."
tts = gTTS(text=text_to_read, lang='en')
# 예시 2: 뉴스 기사 요약 음성화 (AI 분석 결과와 조합)
text_to_read = f"""
오늘의 주요 뉴스입니다.
AI 기술이 빠르게 발전하면서, 많은 기업들이 Python 기반의 AI 솔루션을 도입하고 있습니다.
"""
tts = gTTS(text=text_to_read, lang='ko')
# 예시 3: Gemini AI 답변을 음성으로 읽어주기 (제2부 코드와 조합)
# response = gemini.invoke(prompt)
# tts = gTTS(text=response.content, lang='ko')
©2024-2026 MDRULES.dev, Hand-crafted & made with Jaewoo Kim.
이메일문의: jaewoo@mdrules.dev
AI강의/개발/기술자문, AI 업무 자동화 컨설팅 문의: https://talk.naver.com/ct/w5umt5
AI 프롬프트 및 워크플로우 설계 대행: https://mdrules.dev
제2부에서 만든 CSV 분석 결과를 음성으로 읽어주는 앱도 같은 방식으로 만들 수 있습니다.
response.content(AI 분석 텍스트)를 gTTS에 넘기면 됩니다.
| 개념 | 한 줄 요약 |
|---|---|
| gTTS | Google TTS API로 텍스트를 MP3 음성 파일로 변환하는 라이브러리 |
lang='ko' | 한국어 음성으로 읽어주도록 지정하는 옵션 |
트리플 따옴표(""") | 여러 줄에 걸친 문자열을 다루는 구문 |
| try 블록 | 에러가 날 수 있는 처리를 감싸는 "시도" 영역 (정상계) |
| except 블록 | 에러 발생 시 실행되는 "대응" 영역 (이상계) |
as e | 발생한 에러 객체를 변수에 저장하여 상세 정보 활용 |
st.success() / st.warning() | 성공/경고를 색깔 박스로 표시하는 Streamlit 함수 |
tts.save() | 음성 데이터를 MP3 파일로 저장하는 메서드 |
st.audio() | 저장된 MP3 파일을 브라우저에서 재생하는 Streamlit 함수 |
📌 try-except의 핵심 원칙
- 에러가 없으면 →
try블록만 실행,except블록은 건너뜀- 에러가 발생하면 →
try블록 중단 후except블록으로 즉시 점프- 인터넷 통신, 파일 입출력, 외부 API 호출이 있는 곳에는 항상 try-except를 고려하자