본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2026. 2. 2. · 4 Views
Voice Design 마스터하기
OpenAI의 음성 생성 API에서 Voice Design 기능을 활용하여 원하는 목소리를 자유롭게 디자인하는 방법을 알아봅니다. 텍스트 명령으로 음색, 감정, 말투를 제어하는 실전 기법을 다룹니다.
목차
1. 도입: 상상을 음성으로
김개발 씨는 교육용 앱을 개발하는 스타트업에서 일하고 있습니다. 어느 날 기획팀에서 요청이 들어왔습니다.
"아이들을 위한 동화 낭독 기능을 추가해주세요. 근데 목소리가 따뜻하고 다정해야 해요." 기존 TTS로는 딱딱한 기계음밖에 나오지 않아 고민에 빠졌습니다.
Voice Design은 텍스트 명령어로 원하는 목소리를 설계하는 기술입니다. 마치 성우에게 "좀 더 밝게, 조금 천천히 읽어주세요"라고 주문하는 것처럼, AI에게 음성의 특성을 자연어로 지시할 수 있습니다.
이 기능을 활용하면 프로젝트마다 맞춤형 목소리를 만들어낼 수 있습니다.
다음 코드를 살펴봅시다.
from openai import OpenAI
client = OpenAI()
# Voice Design의 핵심: instruct 파라미터로 목소리 특성 지정
response = client.audio.speech.create(
model="gpt-4o-mini-tts", # Voice Design 지원 모델
voice="coral", # 기본 음색 선택
input="안녕하세요, 오늘 동화를 들려드릴게요.",
# 핵심: 원하는 목소리 스타일을 자연어로 설명
instructions="따뜻하고 다정한 어조로, 아이에게 동화를 읽어주는 것처럼 천천히 말해주세요."
)
# 생성된 음성을 파일로 저장
response.stream_to_file("story_voice.mp3")
김개발 씨는 입사 6개월 차 백엔드 개발자입니다. 평소 API 연동에는 자신이 있었지만, 오늘 받은 요청은 조금 특별했습니다.
"동화 낭독 기능인데요, 목소리가 기계 같으면 안 돼요. 아이들이 들어도 편안하게 느껴야 해요." 기존에 사용하던 TTS 서비스로 테스트해봤지만 결과는 실망스러웠습니다.
분명 한국어를 잘 읽어주긴 하는데, 어딘가 차갑고 딱딱한 느낌이었습니다. 아이들에게 동화를 읽어주는 목소리와는 거리가 멀었습니다.
그때 선배 박시니어 씨가 다가왔습니다. "Voice Design이라는 기능 들어봤어요?
목소리를 텍스트로 디자인할 수 있어요." Voice Design이란 정확히 무엇일까요? 쉽게 비유하자면, 성우 오디션장에서 감독이 주문하는 것과 같습니다.
"좀 더 밝게요", "천천히 읽어주세요", "슬픈 감정을 담아서요"라고 말하면 성우가 그에 맞게 연기하듯, AI에게도 같은 방식으로 지시할 수 있습니다. 기존 TTS는 미리 녹음된 음성 데이터를 조합하는 방식이었습니다.
속도나 높낮이 정도는 조절할 수 있었지만, 감정이나 분위기까지 바꾸기는 어려웠습니다. 뉴스 아나운서 톤과 동화 구연 톤을 같은 엔진에서 구현하기란 거의 불가능했습니다.
Voice Design은 이런 한계를 뛰어넘습니다. instructions 파라미터에 원하는 목소리 특성을 자연어로 설명하기만 하면 됩니다.
"따뜻하게", "신나게", "차분하게"와 같은 형용사부터 "노인이 손자에게 이야기하듯이"와 같은 구체적인 상황 설정까지 가능합니다. 위 코드를 살펴보겠습니다.
먼저 gpt-4o-mini-tts 모델을 지정합니다. 이 모델이 Voice Design을 지원하는 핵심 모델입니다.
그 다음 voice 파라미터로 기본 음색을 선택합니다. coral 외에도 alloy, echo, fable, onyx, nova, shimmer 등 다양한 옵션이 있습니다.
가장 중요한 부분은 instructions 파라미터입니다. 여기에 원하는 목소리 스타일을 상세히 설명합니다.
이 설명이 구체적일수록 원하는 결과물에 가까워집니다. 실제 현업에서는 다양한 상황에 활용됩니다.
교육 앱에서는 친근한 선생님 목소리로, 명상 앱에서는 차분하고 안정적인 목소리로, 게임에서는 캐릭터별 개성 있는 목소리로 설정할 수 있습니다. 다시 김개발 씨 이야기로 돌아가 봅시다.
박시니어 씨의 조언대로 Voice Design을 적용해보니, 정말 동화책을 읽어주는 것 같은 따뜻한 목소리가 나왔습니다. 기획팀도 매우 만족했습니다.
실전 팁
💡 - instructions는 한국어로 작성해도 잘 동작하지만, 영어가 더 정교한 제어가 가능합니다
- 기본 voice 선택이 결과물에 큰 영향을 주므로, 여러 voice를 테스트해보세요
2. generate voice design 함수 구조
김개발 씨가 Voice Design을 프로젝트에 적용하려고 보니, 매번 같은 코드를 반복 작성하게 되었습니다. "이걸 함수로 만들어서 재사용하면 좋겠는데..." 어떻게 구조화하면 효율적으로 관리할 수 있을까요?
generate_voice_design 함수는 Voice Design API 호출을 캡슐화한 유틸리티 함수입니다. 마치 커피 머신에 원두 종류와 농도만 선택하면 커피가 나오는 것처럼, 텍스트와 스타일만 넣으면 원하는 음성이 생성됩니다.
이렇게 함수화하면 프로젝트 전반에서 일관된 방식으로 음성을 생성할 수 있습니다.
다음 코드를 살펴봅시다.
from openai import OpenAI
from pathlib import Path
def generate_voice_design(
text: str,
instructions: str,
voice: str = "coral",
output_path: str = "output.mp3"
) -> Path:
"""Voice Design을 활용한 음성 생성 함수"""
client = OpenAI()
# API 호출: 핵심 파라미터 4가지
response = client.audio.speech.create(
model="gpt-4o-mini-tts", # 필수: Voice Design 지원 모델
voice=voice, # 기본 음색 선택
input=text, # 읽을 텍스트
instructions=instructions # 목소리 스타일 지시
)
# 파일로 저장 후 경로 반환
output_file = Path(output_path)
response.stream_to_file(output_file)
return output_file
김개발 씨는 동화 낭독 기능을 완성한 후 뿌듯한 마음으로 퇴근했습니다. 그런데 다음 날, 새로운 요청이 들어왔습니다.
"명상 가이드 음성도 추가해주세요. 그리고 알림 메시지 음성도요." 코드를 보니 문제가 보였습니다.
동화 낭독용 코드를 복사해서 붙여넣고, instructions만 바꿔야 했습니다. 비슷한 코드가 여러 곳에 흩어지면 나중에 유지보수가 어려워질 것이 뻔했습니다.
이럴 때 필요한 것이 바로 함수화입니다. 공통된 로직을 하나의 함수로 묶어두면, 어디서든 같은 방식으로 호출할 수 있습니다.
마치 주방에 만능 요리 도구가 있는 것처럼, 재료만 바꿔 넣으면 다양한 요리를 만들 수 있습니다. generate_voice_design 함수의 구조를 살펴보겠습니다.
이 함수는 네 개의 파라미터를 받습니다. 첫 번째는 text입니다.
음성으로 변환할 텍스트 내용을 담습니다. 동화 내용이 될 수도 있고, 명상 가이드 멘트가 될 수도 있습니다.
두 번째는 instructions입니다. 앞서 배운 것처럼, 원하는 목소리 스타일을 자연어로 설명합니다.
이 부분이 Voice Design의 핵심입니다. 세 번째는 voice입니다.
기본 음색을 선택하는 파라미터로, 기본값으로 coral을 지정해두었습니다. 필요에 따라 alloy, nova 등 다른 옵션으로 바꿀 수 있습니다.
네 번째는 output_path입니다. 생성된 음성 파일을 저장할 경로입니다.
기본값은 output.mp3이지만, 상황에 맞게 다른 이름을 지정할 수 있습니다. 함수 내부에서는 OpenAI 클라이언트를 생성하고, audio.speech.create 메서드를 호출합니다.
여기서 model 파라미터에 gpt-4o-mini-tts를 지정하는 것이 중요합니다. 이 모델만 Voice Design을 지원합니다.
반환값으로 Path 객체를 돌려주도록 설계했습니다. 이렇게 하면 호출하는 쪽에서 파일 경로를 활용해 추가 작업을 할 수 있습니다.
예를 들어 생성된 파일을 클라우드에 업로드하거나, 다른 처리를 거칠 수 있습니다. 타입 힌트를 추가한 것도 눈여겨볼 부분입니다.
text: str, instructions: str처럼 각 파라미터의 타입을 명시해두면, IDE에서 자동 완성 지원을 받을 수 있고 실수를 줄일 수 있습니다. 이제 김개발 씨는 동화, 명상, 알림 등 어떤 유형의 음성이 필요하든 이 함수 하나로 처리할 수 있게 되었습니다.
코드도 깔끔해지고 유지보수도 훨씬 쉬워졌습니다.
실전 팁
💡 - 타입 힌트를 추가하면 IDE 지원을 받을 수 있고 코드 가독성도 높아집니다
- 반환값으로 Path 객체를 사용하면 파일 경로 처리가 편리해집니다
3. 효과적인 instruct 작성법
김개발 씨가 여러 스타일의 음성을 만들어보던 중, 이상한 점을 발견했습니다. 분명 같은 voice를 사용했는데, instructions를 어떻게 쓰느냐에 따라 결과물이 천차만별이었습니다.
"대체 어떻게 써야 원하는 목소리가 나올까요?"
instructions 작성은 마치 좋은 그림을 그리기 위한 스케치와 같습니다. 막연히 "예쁘게 그려줘"라고 하면 결과를 예측하기 어렵지만, "파란 하늘 아래 빨간 지붕의 작은 집을 그려줘"라고 하면 원하는 그림에 가까워집니다.
구체적이고 명확한 지시가 좋은 결과를 만들어냅니다.
다음 코드를 살펴봅시다.
# 나쁜 예: 모호한 지시
bad_instruction = "좋게 읽어주세요"
# 좋은 예: 구체적인 지시
good_instruction = """
- 톤: 따뜻하고 친근한 중저음
- 속도: 보통보다 약간 느리게, 문장 사이에 자연스러운 쉼
- 감정: 아이를 재우는 엄마처럼 부드럽고 안정적인 느낌
- 발음: 또박또박 명확하게, 특히 의성어는 살짝 과장해서
"""
# 실제 적용 예시
response = client.audio.speech.create(
model="gpt-4o-mini-tts",
voice="nova",
input="옛날 옛적에, 깊은 숲 속에 작은 토끼가 살았어요.",
instructions=good_instruction
)
박시니어 씨가 김개발 씨의 코드를 보다가 한 가지 조언을 해주었습니다. "instructions가 너무 짧아요.
좀 더 구체적으로 써보는 게 어때요?" 처음에 김개발 씨는 "친절하게 읽어주세요"라고만 작성했습니다. 결과물이 나쁘지는 않았지만, 뭔가 아쉬웠습니다.
정확히 어떤 점이 문제인지 파악하기도 어려웠습니다. 좋은 instructions를 작성하는 핵심은 구체성입니다.
"좋게"나 "예쁘게" 같은 추상적인 표현 대신, 정확히 어떤 특성을 원하는지 설명해야 합니다. 첫 번째로 톤을 명시합니다.
"따뜻한", "차분한", "밝은", "무거운" 같은 형용사로 전반적인 분위기를 설정합니다. "중저음", "고음" 같은 음역대 정보를 추가하면 더 좋습니다.
두 번째로 속도를 지정합니다. "빠르게", "천천히" 뿐만 아니라 "문장 사이에 2초 정도 쉬어주세요"처럼 구체적인 수치를 넣을 수도 있습니다.
쉼의 위치와 길이가 전체 느낌을 크게 좌우합니다. 세 번째로 감정을 설명합니다.
단순히 "기쁘게"보다는 "오랜만에 친구를 만난 것처럼 반갑게"라고 쓰면 AI가 더 정확하게 이해합니다. 상황을 설정해주는 것이 효과적입니다.
네 번째로 발음에 대한 지시를 추가합니다. "또박또박", "자연스럽게", "특정 단어 강조" 같은 세부 사항이 여기에 해당합니다.
의성어나 의태어를 어떻게 처리할지도 명시할 수 있습니다. 위 코드에서 good_instruction을 보면, 네 가지 요소가 모두 포함되어 있습니다.
톤은 "따뜻하고 친근한 중저음", 속도는 "보통보다 약간 느리게", 감정은 "아이를 재우는 엄마처럼", 발음은 "또박또박 명확하게"로 지정했습니다. 이렇게 구조화해서 작성하면 두 가지 장점이 있습니다.
먼저 결과물이 예측 가능해집니다. 어떤 부분이 마음에 안 들면 해당 요소만 수정하면 됩니다.
또한 팀원들과 공유하기도 편해집니다. "감정 부분만 바꿔보자"처럼 명확하게 소통할 수 있습니다.
김개발 씨는 박시니어 씨의 조언대로 instructions를 다시 작성했습니다. 결과물이 훨씬 좋아졌고, 무엇보다 수정이 필요할 때 어디를 고쳐야 하는지 명확해졌습니다.
실전 팁
💡 - 톤, 속도, 감정, 발음 네 가지 요소를 나누어 작성하면 관리가 편합니다
- 추상적인 형용사보다 구체적인 상황 비유가 더 효과적입니다
4. 음색, 감정, 운율 제어
김개발 씨가 드디어 동화 낭독 기능을 완성했습니다. 그런데 QA 팀에서 피드백이 왔습니다.
"대화 장면에서 캐릭터마다 목소리가 달라지면 좋겠어요. 토끼는 귀엽게, 늑대는 무섭게요." 한 문장 안에서도 감정이 바뀌어야 하는 상황, 어떻게 해결할 수 있을까요?
음색, 감정, 운율은 목소리를 입체적으로 만드는 세 가지 축입니다. 음색은 목소리의 기본 색깔이고, 감정은 그 순간의 마음 상태이며, 운율은 말의 리듬과 높낮이입니다.
마치 노래에서 음정, 박자, 감정이 어우러져 감동을 주듯, 이 세 요소가 조화롭게 어우러질 때 생생한 목소리가 탄생합니다.
다음 코드를 살펴봅시다.
# 캐릭터별 음성 디자인 예시
character_voices = {
"토끼": {
"voice": "shimmer", # 높고 맑은 기본 음색
"instructions": """
- 음색: 맑고 높은 톤, 살짝 콧소리가 섞인 느낌
- 감정: 순수하고 호기심 가득한, 가끔 겁먹은 듯
- 운율: 문장 끝을 살짝 올리며, 빠르고 경쾌하게
"""
},
"늑대": {
"voice": "onyx", # 낮고 굵은 기본 음색
"instructions": """
- 음색: 낮고 굵은 저음, 약간 거친 질감
- 감정: 위협적이고 교활한, 여유로운 자신감
- 운율: 느리고 무겁게, 중요한 단어에서 끊어 읽기
"""
}
}
# 캐릭터 대사 생성
def speak_as_character(character: str, line: str):
config = character_voices[character]
return generate_voice_design(
text=line,
voice=config["voice"],
instructions=config["instructions"]
)
동화 속에는 다양한 캐릭터가 등장합니다. 순수한 토끼, 무서운 늑대, 지혜로운 올빼미.
이들이 같은 목소리로 말한다면 얼마나 밋밋할까요? 성우들이 여러 역할을 연기하듯, AI도 캐릭터마다 다른 목소리를 낼 수 있어야 합니다.
먼저 음색에 대해 알아봅시다. 음색은 목소리의 기본 재질입니다.
피아노와 바이올린이 같은 음을 연주해도 다르게 들리는 것처럼, 사람마다 목소리의 기본 재질이 다릅니다. Voice Design에서는 voice 파라미터로 기본 음색을 선택합니다.
shimmer는 밝고 맑은 느낌이고, onyx는 낮고 깊은 느낌입니다. 캐릭터의 성격에 맞는 기본 음색을 먼저 선택하는 것이 좋습니다.
다음으로 감정입니다. 같은 대사라도 기쁠 때와 슬플 때 전혀 다르게 들립니다.
instructions에서 감정 상태를 명시하면 AI가 그에 맞게 표현해줍니다. 감정을 지정할 때는 단순한 형용사보다 상황 설명이 효과적입니다.
"기쁘게"보다는 "오랜만에 보고 싶던 친구를 만난 것처럼 반갑게"라고 쓰면 AI가 더 잘 이해합니다. 복합적인 감정도 표현할 수 있습니다.
"겉으로는 침착하지만 속으로는 불안한"처럼 말이죠. 마지막으로 운율입니다.
운율은 말의 리듬과 높낮이를 뜻합니다. 문장 끝을 올리는지 내리는지, 어디서 끊어 읽는지, 어떤 단어를 강조하는지가 모두 운율에 해당합니다.
위 코드를 보면, 토끼는 "문장 끝을 살짝 올리며, 빠르고 경쾌하게"라고 지정했습니다. 반면 늑대는 "느리고 무겁게, 중요한 단어에서 끊어 읽기"라고 설정했습니다.
같은 대사를 해도 완전히 다른 느낌이 납니다. character_voices 딕셔너리로 캐릭터별 설정을 관리하면 편리합니다.
새 캐릭터가 추가되면 딕셔너리에 항목만 추가하면 됩니다. 코드를 수정할 필요 없이 설정만 바꾸면 되니까요.
speak_as_character 함수는 캐릭터 이름과 대사만 받아서 적절한 목소리로 음성을 생성합니다. 동화 낭독 시스템에서 이 함수를 호출하면, 대사에 맞는 캐릭터 음성이 자동으로 적용됩니다.
김개발 씨는 이 구조를 적용해서 동화책의 모든 캐릭터에 개성 있는 목소리를 부여했습니다. QA 팀도, 기획팀도, 무엇보다 앱을 사용하는 아이들이 좋아했습니다.
실전 팁
💡 - 음색(voice)은 변경이 어려우니 캐릭터 성격에 맞는 것을 먼저 신중히 선택하세요
- 감정은 상황 설명으로, 운율은 읽기 방식으로 구체화하면 효과적입니다
5. 언어별 디자인 팁
회사에서 해외 진출을 결정했습니다. 김개발 씨에게 새로운 미션이 떨어졌습니다.
"일본어랑 영어 버전도 만들어주세요." 같은 instructions를 그대로 번역해서 쓰면 될까요? 언어마다 특성이 다른데, 어떻게 접근해야 할까요?
언어별 Voice Design은 각 언어의 고유한 특성을 이해하고 그에 맞게 지시를 조정하는 것입니다. 한국어는 존댓말과 반말의 차이가 크고, 영어는 강세와 리듬이 중요하며, 일본어는 경어 체계가 복잡합니다.
마치 같은 요리라도 나라마다 양념이 다르듯, 같은 감정 표현도 언어마다 다르게 접근해야 합니다.
다음 코드를 살펴봅시다.
# 언어별 Voice Design 설정 예시
language_configs = {
"ko": {
"voice": "nova",
"instructions": """
- 한국어 특성: 존댓말 사용, 어미 변화에 감정 담기
- 운율: 문장 끝 억양 자연스럽게, '요' 어미는 부드럽게
- 특별 지시: 의성어/의태어는 실감나게 표현
"""
},
"en": {
"voice": "alloy",
"instructions": """
- English specifics: Clear stress patterns on key words
- Rhythm: Natural pauses between clauses
- Special: Emphasize action words, soften articles
"""
},
"ja": {
"voice": "shimmer",
"instructions": """
- 日本語の特性: 丁寧語を使用、語尾を柔らかく
- リズム: 自然な間を取り、抑揚は控えめに
- 特別指示: 擬音語・擬態語は表情豊かに
"""
}
}
def generate_multilingual_voice(text: str, lang: str):
config = language_configs[lang]
return generate_voice_design(text, config["instructions"], config["voice"])
한국어, 영어, 일본어. 세 언어는 완전히 다른 특성을 가지고 있습니다.
같은 "안녕하세요"라도 한국어는 어미에 감정이 실리고, 영어는 억양에, 일본어는 경어 수준에 뉘앙스가 담깁니다. 먼저 한국어의 특성을 살펴봅시다.
한국어에서 가장 중요한 것은 존댓말과 반말의 구분입니다. 같은 내용이라도 "했어요"와 "했다"는 전혀 다른 느낌을 줍니다.
instructions에 어떤 화계를 사용할지 명시하는 것이 좋습니다. 한국어는 문장 끝 어미에 감정이 많이 실립니다.
"그랬어요"를 길게 늘이면 아쉬움이 느껴지고, 짧게 끊으면 단호해집니다. 어미 처리 방법을 구체적으로 지시하면 원하는 감정을 더 잘 표현할 수 있습니다.
또한 한국어에는 풍부한 의성어와 의태어가 있습니다. "주룩주룩", "반짝반짝" 같은 표현은 어떻게 읽느냐에 따라 생동감이 달라집니다.
이런 표현을 어떻게 처리할지 명시해두면 좋습니다. 다음으로 영어입니다.
영어에서 가장 중요한 것은 강세입니다. 어떤 단어를 강조하느냐에 따라 의미가 달라지기도 합니다.
"I didn't say he stole the money"는 어디에 강세를 주느냐에 따라 일곱 가지 다른 의미가 됩니다. 영어는 리듬도 중요합니다.
강세와 비강세가 규칙적으로 반복되는 것이 자연스럽습니다. 너무 평탄하게 읽으면 기계적으로 들립니다.
관사(a, the)나 전치사는 약하게, 명사와 동사는 강하게 처리하면 자연스럽습니다. 마지막으로 일본어입니다.
일본어의 경어 체계는 한국어보다도 복잡합니다. 존경어, 겸양어, 정중어가 세분화되어 있고, 상황에 따라 적절히 사용해야 합니다.
일본어는 한국어나 영어에 비해 억양 변화가 적습니다. 너무 감정을 과하게 표현하면 부자연스럽게 들릴 수 있습니다.
"控えめに(절제하여)"라고 지시하는 것이 좋습니다. 코드에서 language_configs 딕셔너리는 언어별로 다른 설정을 관리합니다.
각 언어에 적합한 기본 voice도 다르게 선택했습니다. 한국어는 nova, 영어는 alloy, 일본어는 shimmer가 비교적 자연스럽게 들립니다.
김개발 씨는 언어별 설정을 적용한 후, 각 나라의 네이티브 스피커에게 검토를 받았습니다. 미세한 조정이 필요한 부분이 있었지만, 기본적인 방향은 맞았다는 피드백을 받았습니다.
실전 팁
💡 - 각 언어의 네이티브 스피커에게 결과물 검토를 받는 것이 가장 확실합니다
- instructions는 해당 언어로 작성하는 것이 더 정교한 제어가 가능합니다
6. 실전: 캐릭터 음성 디자인하기
드디어 마지막 관문입니다. 김개발 씨는 이제까지 배운 모든 것을 종합해서 완성도 높은 캐릭터 음성 시스템을 만들어야 합니다.
여러 캐릭터가 등장하는 동화를 자동으로 낭독하는 시스템, 어떻게 설계하면 좋을까요?
캐릭터 음성 시스템은 지금까지 배운 모든 기법을 통합한 실전 애플리케이션입니다. 캐릭터 정의, 대사 파싱, 음성 생성, 파일 관리까지 전체 파이프라인을 구축합니다.
마치 애니메이션 더빙 스튜디오에서 각 성우가 맡은 캐릭터를 연기하듯, AI가 각 캐릭터에 맞는 목소리로 대사를 읽어줍니다.
다음 코드를 살펴봅시다.
from dataclasses import dataclass
from typing import List
import re
@dataclass
class Character:
name: str
voice: str
instructions: str
@dataclass
class DialogueLine:
character: str
text: str
class StoryNarrator:
def __init__(self):
self.characters = {}
# 기본 나레이터 설정
self.narrator = Character(
name="나레이터",
voice="nova",
instructions="차분하고 안정적인 어조로, 동화를 들려주듯 읽어주세요."
)
def add_character(self, character: Character):
"""캐릭터 등록"""
self.characters[character.name] = character
def parse_script(self, script: str) -> List[DialogueLine]:
"""대본 파싱: [캐릭터] 대사 형식"""
lines = []
for line in script.strip().split('\n'):
match = re.match(r'\[(.+?)\]\s*(.+)', line)
if match:
lines.append(DialogueLine(match.group(1), match.group(2)))
elif line.strip():
lines.append(DialogueLine("나레이터", line))
return lines
def generate_story_audio(self, script: str, output_dir: str = "./audio"):
"""전체 스토리 음성 생성"""
lines = self.parse_script(script)
for i, line in enumerate(lines):
char = self.characters.get(line.character, self.narrator)
generate_voice_design(
text=line.text,
instructions=char.instructions,
voice=char.voice,
output_path=f"{output_dir}/line_{i:03d}.mp3"
)
지금까지 배운 모든 것을 종합할 시간입니다. 개별 기능들을 하나의 완성된 시스템으로 엮어보겠습니다.
먼저 데이터 구조를 설계합니다. Python의 dataclass를 활용하면 깔끔하게 정의할 수 있습니다.
Character 클래스는 캐릭터 이름, 기본 음색, 스타일 지시를 담습니다. DialogueLine 클래스는 누가 무슨 말을 하는지 표현합니다.
핵심이 되는 StoryNarrator 클래스를 살펴봅시다. 이 클래스가 전체 시스템의 중심입니다.
init 메서드에서는 캐릭터 딕셔너리와 기본 나레이터를 초기화합니다. 나레이터는 대사가 아닌 서술 부분을 담당합니다.
"옛날 옛적에 깊은 숲속에..."와 같은 부분이죠. add_character 메서드로 캐릭터를 등록합니다.
토끼, 늑대, 올빼미 등 동화에 등장하는 캐릭터들을 미리 정의해둡니다. 각 캐릭터마다 앞서 배운 음색, 감정, 운율 설정을 포함합니다.
parse_script 메서드는 대본을 분석합니다. "[토끼] 안녕하세요!"처럼 대괄호 안에 캐릭터 이름이 있으면 해당 캐릭터의 대사로, 그렇지 않으면 나레이터의 서술로 처리합니다.
정규표현식을 사용해서 패턴을 인식합니다. generate_story_audio 메서드가 실제 음성을 생성합니다.
파싱된 대사 목록을 순회하면서, 각 줄에 맞는 캐릭터를 찾고, 해당 캐릭터의 설정으로 음성을 생성합니다. 파일 이름에 순번을 붙여서 나중에 순서대로 이어붙일 수 있게 합니다.
실제 사용 예시를 생각해봅시다. 먼저 StoryNarrator 인스턴스를 생성하고, 토끼와 늑대 캐릭터를 등록합니다.
그 다음 대본을 문자열로 준비해서 generate_story_audio 메서드에 전달합니다. 이 시스템의 장점은 확장성입니다.
새로운 캐릭터가 필요하면 add_character로 추가하기만 하면 됩니다. 다른 동화에도 같은 캐릭터를 재사용할 수 있습니다.
캐릭터 설정을 JSON 파일로 분리하면 비개발자도 수정할 수 있습니다. 또한 유지보수가 쉽습니다.
토끼 목소리를 조금 더 높게 하고 싶다면, 해당 캐릭터의 instructions만 수정하면 됩니다. 전체 코드를 건드릴 필요가 없습니다.
김개발 씨는 이 시스템을 완성하고 나서 뿌듯함을 느꼈습니다. 처음에는 막막했던 Voice Design이 이제는 자유자재로 다룰 수 있는 도구가 되었습니다.
박시니어 씨도 흐뭇하게 지켜보며 말했습니다. "이제 진짜 개발자가 됐네요."
실전 팁
💡 - 캐릭터 설정을 외부 파일(JSON, YAML)로 분리하면 비개발자도 수정할 수 있습니다
- 생성된 음성 파일을 ffmpeg로 이어붙여 하나의 오디오북으로 만들 수 있습니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
vLLM 통합 완벽 가이드
대규모 언어 모델 추론을 획기적으로 가속화하는 vLLM의 설치부터 실전 서비스 구축까지 다룹니다. PagedAttention과 연속 배칭 기술로 GPU 메모리를 효율적으로 활용하는 방법을 배웁니다.
Web UI Demo 구축 완벽 가이드
Gradio를 활용하여 머신러닝 모델과 AI 서비스를 위한 웹 인터페이스를 구축하는 방법을 다룹니다. 코드 몇 줄만으로 전문적인 데모 페이지를 만들고 배포하는 과정을 초급자도 쉽게 따라할 수 있도록 설명합니다.
Sandboxing & Execution Control 완벽 가이드
AI 에이전트가 코드를 실행할 때 반드시 필요한 보안 기술인 샌드박싱과 실행 제어에 대해 알아봅니다. 격리된 환경에서 안전하게 코드를 실행하고, 악성 동작을 탐지하는 방법을 단계별로 설명합니다.
Voice Design then Clone 워크플로우 완벽 가이드
AI 음성 합성에서 일관된 캐릭터 음성을 만드는 Voice Design then Clone 워크플로우를 설명합니다. 참조 음성 생성부터 재사용 가능한 캐릭터 구축까지 실무 활용법을 다룹니다.
Tool Use 완벽 가이드 - Shell, Browser, DB 실전 활용
AI 에이전트가 외부 도구를 활용하여 셸 명령어 실행, 브라우저 자동화, 데이터베이스 접근 등을 수행하는 방법을 배웁니다. 실무에서 바로 적용할 수 있는 패턴과 베스트 프랙티스를 담았습니다.