目次
Polly v2.0 完全ガイド(Machine Learning & AI)
概要
Amazon Polly は、テキストを自然な人間らしい音声に変換するテキスト音声合成(TTS: Text-to-Speech)サービスです。Neural TTS(ニューラルネットワークベース)・Standard(統計的合成)・Long-form(長文最適化)・Generative(生成型)の 4 つのエンジンで、60 以上の言語と 100 以上のボイスキャラクターをサポートします。SSML による細かい音声制御(速度・ピッチ・強調)、Newscaster スタイル、Speech Marks による字幕同期、リアルタイム・非同期処理に対応し、アクセシビリティ・オーディオブック・IVR・ゲーム・IoT デバイス向け音声化を実現します。
課題と特徴
従来型 TTS の課題
- ロボット的な音声: 従来の連結型 TTS では不自然な音声品質
- 発音・速度・ポーズの制御が難しい: 細かい音声制御が手作業
- 多言語・多ボイス対応の複雑さ: 言語ごとの音声エンジン構築が必要
- スケーリングの困難: 大量音声生成のインフラ構築コスト高
Polly の特徴
| 特徴 | 効果 |
|---|---|
| Neural TTS | 深層学習で人間らしい自然な音声 |
| 100+ ボイス | 多様なキャラクター・言語対応 |
| SSML サポート | 発音・速度・ピッチ・感情を細かく制御 |
| Speech Marks | 音声同期・字幕タイミング出力 |
| Newscaster スタイル | ニュース向けの定型読上げ |
| Long-form エンジン | 長文コンテンツ対応・イントネーション自動調整 |
| Generative Voice | AI 生成音声(実験的) |
| 音声キャッシング | 同じ音声の再利用でコスト削減 |
| 60+ 言語対応 | グローバル対応 |
アーキテクチャ
graph TB
subgraph Input["入力"]
A["テキスト(API)"]
B["SSML(タグ付き)"]
end
subgraph Processing["音声合成処理"]
C["言語検出"]
D["エンジン選択<br/>Neural/Standard/Long-form"]
E["SSML 解析"]
F["発音・速度制御"]
G["音声生成"]
end
subgraph Output["出力"]
I["MP3/PCM/OGG"]
J["Speech Marks<br/>タイミング情報"]
end
A --> C
B --> C
C --> D
D --> E
E --> F
F --> G
G --> I
G --> J
コアコンポーネント
1. Standard TTS(基本合成)
import boto3
polly = boto3.client('polly', region_name='ap-northeast-1')
# シンプルな音声合成
response = polly.synthesize_speech(
Text='こんにちは。Amazon Polly のデモです。',
Engine='standard', # standard/neural/long-form
LanguageCode='ja-JP',
OutputFormat='mp3', # mp3/pcm/ogg_vorbis
VoiceId='Tomoko', # 女性音声
SampleRateHz='8000' # 8000/16000/22050
)
# 音声ファイルをダウンロード
with open('output.mp3', 'wb') as f:
f.write(response['AudioStream'].read())
2. Neural TTS(ニューラルネットワーク)
# より自然な音声品質
response = polly.synthesize_speech(
Text='このサービスは素晴らしいです。強くお勧めします。',
Engine='neural', # Neural TTS
VoiceId='Kazuha', # 日本語 Neural 音声
OutputFormat='mp3'
)
3. Long-form TTS(長文対応)
# 長いテキストで自然なイントネーション
long_text = """
電子商取引の発展に伴い、多くの企業がグローバルな市場に進出しています。
特にアジア太平洋地域では、デジタルトランスフォーメーションが急速に進んでいます。
クラウドコンピューティング技術の活用により、企業の競争力が大幅に向上しています。
"""
response = polly.synthesize_speech(
Text=long_text,
Engine='long-form', # Long-form TTS
VoiceId='Tomoko',
OutputFormat='mp3'
)
4. SSML(音声制御)
# SSML で細かい音声制御
ssml_text = """
<speak>
<prosody rate="slow">ゆっくり話します。</prosody>
<break time="1s"/>
<prosody volume="loud">大きく話します。</prosody>
<break time="500ms"/>
<prosody pitch="high">高い声で話します。</prosody>
<break time="500ms"/>
<emphasis level="strong">重要な部分</emphasis>です。
<prosody rate="fast">速く話します。</prosody>
</speak>
"""
response = polly.synthesize_speech(
Text=ssml_text,
Engine='neural',
LanguageCode='ja-JP',
OutputFormat='mp3',
TextType='ssml' # 'text' or 'ssml'
)
5. Speech Marks(字幕同期情報)
# 音声との同期タイミング情報を取得
response = polly.synthesize_speech(
Text='これはテストです。',
Engine='neural',
VoiceId='Kazuha',
OutputFormat='json', # json で Speech Marks 取得
SpeechMarkTypes=['word', 'sentence', 'viseme'], # 単語/文/視覚音素
IncludeExternalPlaylist=True
)
# 出力例
"""
{
"time": 0,
"type": "sentence",
"start": 0,
"end": 9,
"value": "これはテストです。"
}
{
"time": 100,
"type": "word",
"start": 0,
"end": 2,
"value": "これは"
}
"""
6. 非同期タスク処理(長文・大量)
# 1500 文字超は非同期処理
response = polly.start_speech_synthesis_task(
Text='長いテキストコンテンツ...',
Engine='long-form',
VoiceId='Tomoko',
LanguageCode='ja-JP',
OutputFormat='mp3',
OutputS3BucketName='my-bucket',
OutputS3KeyPrefix='synthesized-speech/',
SnsTopicArn='arn:aws:sns:ap-northeast-1:123456789:polly-complete'
)
task_id = response['SynthesisTask']['TaskId']
# タスク完了を確認
while True:
result = polly.get_speech_synthesis_task(TaskId=task_id)
if result['SynthesisTask']['TaskStatus'] == 'Completed':
print(f"✓ 音声合成完了")
print(f"出力URI: {result['SynthesisTask']['OutputUri']}")
break
7. Newscaster スタイル(ニュース読上げ)
# ニュース記事向けの定型読上げ
news_text = """
本日、新型技術が発表されました。
この技術は業界に革命をもたらす見通しです。
詳しくは公式サイトをご覧ください。
"""
response = polly.synthesize_speech(
Text=news_text,
Engine='neural',
VoiceId='Mizuki', # Newscaster 対応音声
LanguageCode='ja-JP',
OutputFormat='mp3',
SpeechMarkTypes=['sentence']
)
8. 言語別音声一覧
# 利用可能な音声を取得
response = polly.describe_voices(LanguageCode='ja-JP')
for voice in response['Voices']:
print(f"""
音声名: {voice['Name']}
性別: {voice['Gender']}
言語: {voice['LanguageName']}
エンジン対応: {voice['SupportedEngines']}
""")
# 出力例
"""
音声名: Kazuha
性別: Female
言語: Japanese
エンジン対応: ['neural', 'standard']
"""
主要ユースケース
1. アクセシビリティ機能(視覚障害者向け)
import boto3
class AccessibleWebContent:
def __init__(self):
self.polly = boto3.client('polly')
self.s3 = boto3.client('s3')
def make_webpage_accessible(self, webpage_html, webpage_id):
"""Web サイトをアクセシブルにするため音声化"""
# HTML からテキスト抽出
from bs4 import BeautifulSoup
soup = BeautifulSoup(webpage_html, 'html.parser')
text_content = soup.get_text()
# Polly で音声化
response = self.polly.start_speech_synthesis_task(
Text=text_content,
Engine='neural',
VoiceId='Kazuha',
LanguageCode='ja-JP',
OutputFormat='mp3',
OutputS3BucketName='my-bucket',
OutputS3KeyPrefix=f'accessible-audio/{webpage_id}/'
)
# Speech Marks で字幕同期情報取得
marks_response = self.polly.synthesize_speech(
Text=text_content,
Engine='neural',
VoiceId='Kazuha',
OutputFormat='json',
TextType='text',
SpeechMarkTypes=['word', 'sentence']
)
return {
'audio_uri': response['SynthesisTask']['OutputUri'],
'speech_marks': marks_response['AudioStream'].read()
}
2. オーディオブック・ポッドキャスト生成
class AudiobookGenerator:
def __init__(self):
self.polly = boto3.client('polly')
self.dynamodb = boto3.resource('dynamodb')
self.books_table = self.dynamodb.Table('Books')
def generate_audiobook(self, book_id, book_content, target_language='ja'):
"""テキスト本からオーディオブックを自動生成"""
# 章ごとに分割
chapters = self._split_into_chapters(book_content)
chapter_audios = []
for chapter_num, chapter_text in enumerate(chapters):
# 長文用 Long-form エンジン
response = self.polly.start_speech_synthesis_task(
Text=chapter_text,
Engine='long-form',
VoiceId='Kazuha',
LanguageCode=f'{target_language}-JP',
OutputFormat='mp3',
OutputS3BucketName='audiobooks-bucket',
OutputS3KeyPrefix=f'{book_id}/chapter-{chapter_num+1}/'
)
chapter_audios.append({
'chapter': chapter_num + 1,
'task_id': response['SynthesisTask']['TaskId'],
'status': 'processing'
})
# DynamoDB に保存
self.books_table.update_item(
Key={'book_id': book_id},
UpdateExpression='SET audio_chapters = :chapters, audiobook_status = :status',
ExpressionAttributeValues={
':chapters': chapter_audios,
':status': 'audio_generating'
}
)
return chapter_audios
3. IVR(音声自動応答)システム
import asyncio
import boto3
class IVRSystem:
def __init__(self):
self.polly = boto3.client('polly')
self.connect = boto3.client('connect')
def generate_ivr_prompts(self):
"""コールセンター IVR プロンプトの動的生成"""
prompts = {
'welcome': 'いらっしゃいませ。お電話ありがとうございます。',
'queue_time': 'ただいま 3 名様が対応中です。お待ち時間は約 2 分です。',
'transfer': 'サポート部門にお繋ぎいたします。',
'goodbye': 'ご利用ありがとうございました。'
}
for prompt_key, prompt_text in prompts.items():
# リアルタイムで SSML 含む動的メッセージ生成可能
ssml_text = f"""
<speak>
<prosody rate="medium" pitch="0%">
{prompt_text}
</prosody>
</speak>
"""
response = self.polly.synthesize_speech(
Text=ssml_text,
Engine='neural',
VoiceId='Tomoko',
OutputFormat='pcm', # PCM で低遅延
SampleRateHz='8000', # 8kHz で電話品質
TextType='ssml'
)
# Lambda を通じて Amazon Connect に返す
yield {
'prompt_key': prompt_key,
'audio_stream': response['AudioStream'].read()
}
4. ゲーム・キャラクター音声
class GameCharacterVoices:
def __init__(self):
self.polly = boto3.client('polly')
def generate_game_dialogue(self, character_name, dialogue_text, character_emotion='neutral'):
"""ゲームキャラクターの音声セリフを生成"""
# キャラクターごとの音声・感情スタイル設定
voice_config = {
'princess': {'voice': 'Mizuki', 'rate': 'medium', 'pitch': '+10%'},
'villain': {'voice': 'Tomoko', 'rate': 'slow', 'pitch': '-5%'},
'hero': {'voice': 'Kazuha', 'rate': 'medium', 'pitch': '+5%'},
}
config = voice_config.get(character_name, {})
# SSML で感情表現
emotion_mapping = {
'happy': '<prosody rate="fast" pitch="+15%">',
'sad': '<prosody rate="slow" pitch="-10%">',
'angry': '<prosody rate="fast" volume="loud">',
'neutral': '<prosody rate="medium">',
}
ssml_text = f"""
<speak>
{emotion_mapping.get(character_emotion, emotion_mapping['neutral'])}
{dialogue_text}
</prosody>
</speak>
"""
response = self.polly.synthesize_speech(
Text=ssml_text,
Engine='neural',
VoiceId=config.get('voice', 'Kazuha'),
OutputFormat='ogg_vorbis', # ゲームエンジン互換
TextType='ssml'
)
return response['AudioStream'].read()
5. 多言語教育コンテンツ
class LanguageLearningContent:
def __init__(self):
self.polly = boto3.client('polly')
def generate_pronunciation_examples(self, word, languages=['en', 'ja', 'es', 'fr']):
"""学習者向けに複数言語の発音例を生成"""
pronunciations = {}
for language in languages:
# 言語ごとの音声で発音確認
language_code = self._get_language_code(language)
response = self.polly.synthesize_speech(
Text=word,
Engine='neural',
LanguageCode=language_code,
OutputFormat='mp3'
)
pronunciations[language] = response['AudioStream'].read()
return pronunciations
def _get_language_code(self, lang_code):
mapping = {
'en': 'en-US',
'ja': 'ja-JP',
'es': 'es-ES',
'fr': 'fr-FR',
}
return mapping.get(lang_code, 'en-US')
6. IoT デバイス音声通知
import boto3
def iot_device_notification(device_id, message, device_language='ja'):
"""IoT デバイスに音声で通知を配信"""
polly = boto3.client('polly')
iot_data = boto3.client('iot-data')
# Polly で音声生成(低遅延は PCM 8kHz)
response = polly.synthesize_speech(
Text=message,
Engine='standard', # 速度重視
VoiceId='Tomoko' if device_language == 'ja' else 'Joanna',
OutputFormat='pcm',
SampleRateHz='8000' # IoT デバイス用
)
# IoT デバイスに音声データを送信
iot_data.publish(
topic=f'devices/{device_id}/audio-notification',
qos=1,
payload=response['AudioStream'].read()
)
7. 映像字幕の音声付与
from moviepy.editor import VideoFileClip, CompositeAudioFileClip
def add_voiceover_to_video(video_path, subtitle_text, output_path):
"""ビデオに音声付きナレーション追加"""
polly = boto3.client('polly')
# Polly で音声ナレーション生成
response = polly.synthesize_speech(
Text=subtitle_text,
Engine='neural',
VoiceId='Kazuha',
OutputFormat='mp3'
)
# 音声をファイルに保存
import tempfile
with tempfile.NamedTemporaryFile(suffix='.mp3', delete=False) as f:
f.write(response['AudioStream'].read())
audio_file = f.name
# MoviePy でビデオに音声合成
video = VideoFileClip(video_path)
from pydub import AudioSegment
audio = AudioSegment.from_mp3(audio_file)
# 字幕・音声合成してビデオ出力
# ...処理省略
8. 通知・アラート音声化
class AlertVoiceNotifier:
def __init__(self):
self.polly = boto3.client('polly')
self.sns = boto3.client('sns')
def send_voice_alert(self, alert_type, alert_message):
"""アラートを音声で通知"""
# アラートタイプに応じた音声スタイル
alert_styles = {
'critical': {
'text': f'<speak><prosody volume="loud" rate="fast">{alert_message}</prosody></speak>',
'engine': 'neural'
},
'warning': {
'text': f'<speak><prosody rate="medium">{alert_message}</prosody></speak>',
'engine': 'standard'
},
'info': {
'text': alert_message,
'engine': 'standard'
}
}
style = alert_styles.get(alert_type, alert_styles['info'])
response = self.polly.synthesize_speech(
Text=style['text'],
Engine=style['engine'],
VoiceId='Tomoko',
OutputFormat='mp3',
TextType='ssml' if 'speak' in style['text'] else 'text'
)
# SNS で音声メッセージ配信
self.sns.publish(
TopicArn='arn:aws:sns:ap-northeast-1:123456789:alerts',
Message='Voice alert',
MessageStructure='json',
MessageAttributes={
'audio_content': {
'DataType': 'Binary',
'StringValue': response['AudioStream'].read().hex()
}
}
)
9. リアルタイムカスタマー対応(Lex 統合)
import boto3
class LexVoiceBot:
def __init__(self):
self.polly = boto3.client('polly')
self.lex = boto3.client('lex-runtime')
async def voice_chat(self, user_input, session_id):
"""Lex + Polly でボイスチャット実現"""
# Step 1: Lex で自然言語理解
lex_response = self.lex.post_text(
botName='MyBot',
botAlias='PROD',
userId=session_id,
inputText=user_input
)
bot_response = lex_response['message']
# Step 2: Polly でボット応答を音声化
polly_response = self.polly.synthesize_speech(
Text=bot_response,
Engine='neural',
VoiceId='Kazuha',
OutputFormat='mp3'
)
return {
'text_response': bot_response,
'audio_response': polly_response['AudioStream'].read()
}
10. マルチモーダル学習教材
class InteractiveEducationPlatform:
def __init__(self):
self.polly = boto3.client('polly')
self.rekognition = boto3.client('rekognition')
def generate_interactive_lesson(self, lesson_content, images):
"""画像 + テキスト + 音声の統合学習教材"""
lesson_data = {}
for section_id, (text, image) in enumerate(zip(lesson_content, images)):
# Step 1: 画像を Rekognition で分析
image_labels = self.rekognition.detect_labels(Image={'S3Object': image})
# Step 2: テキストに画像情報を組み込み
enhanced_text = f"""
{text}
この画像には以下の要素が含まれています:
{', '.join([label['Name'] for label in image_labels['Labels'][:3]])}
"""
# Step 3: Polly で音声化
audio_response = self.polly.synthesize_speech(
Text=enhanced_text,
Engine='long-form',
VoiceId='Kazuha',
OutputFormat='mp3'
)
lesson_data[f'section_{section_id}'] = {
'text': enhanced_text,
'image': image,
'audio': audio_response['AudioStream'].read(),
'labels': image_labels['Labels']
}
return lesson_data
設定・操作の具体例
CLI 例(5+)
1. シンプルな音声合成
aws polly synthesize-speech \
--text 'こんにちは。テストです。' \
--voice-id 'Kazuha' \
--engine 'neural' \
--language-code 'ja-JP' \
--output-format 'mp3' \
--region 'ap-northeast-1' \
output.mp3
2. SSML で音声制御
aws polly synthesize-speech \
--text '<speak><prosody rate="slow">ゆっくり</prosody> <break time="1s"/> <prosody pitch="+10%">高い声</prosody></speak>' \
--text-type 'ssml' \
--voice-id 'Tomoko' \
--engine 'neural' \
--output-format 'mp3' \
--region 'ap-northeast-1' \
output.mp3
3. Speech Marks 取得
aws polly synthesize-speech \
--text 'これはテストです。' \
--voice-id 'Kazuha' \
--engine 'neural' \
--output-format 'json' \
--speech-mark-types 'word' 'sentence' \
--region 'ap-northeast-1' \
output.json
4. 非同期タスク開始
aws polly start-speech-synthesis-task \
--text 'これは長いテキストです。非同期で処理されます。' \
--engine 'long-form' \
--voice-id 'Kazuha' \
--language-code 'ja-JP' \
--output-format 'mp3' \
--output-s3-bucket-name 'my-bucket' \
--output-s3-key-prefix 'synthesized/' \
--region 'ap-northeast-1'
5. 利用可能な音声一覧
aws polly describe-voices \
--language-code 'ja-JP' \
--region 'ap-northeast-1' \
--query 'Voices[*].[Name,Gender,SupportedEngines]' \
--output table
SDK 例(5+)
1. Python: SSML + Speech Marks
import boto3
import json
polly = boto3.client('polly')
ssml = """
<speak>
<p>段落1です。</p>
<p>段落2です。</p>
</speak>
"""
response = polly.synthesize_speech(
Text=ssml,
TextType='ssml',
Engine='neural',
VoiceId='Kazuha',
OutputFormat='json',
SpeechMarkTypes=['sentence', 'word', 'viseme'],
LanguageCode='ja-JP'
)
# Speech Marks を JSON で出力
marks_data = response['AudioStream'].read()
print(json.loads(marks_data))
2. JavaScript: 非同期処理
const AWS = require('aws-sdk');
const polly = new AWS.Polly({ region: 'ap-northeast-1' });
async function generateAudiobook(bookText) {
const params = {
Text: bookText,
Engine: 'long-form',
VoiceId: 'Kazuha',
LanguageCode: 'ja-JP',
OutputFormat: 'mp3',
OutputS3BucketName: 'my-bucket',
OutputS3KeyPrefix: 'audiobooks/',
SnsTopicArn: 'arn:aws:sns:ap-northeast-1:123456789:polly-complete'
};
try {
const result = await polly.startSpeechSynthesisTask(params).promise();
console.log(`Task started: ${result.SynthesisTask.TaskId}`);
console.log(`Status: ${result.SynthesisTask.TaskStatus}`);
} catch (error) {
console.error('Error:', error);
}
}
3. Go: 複数ボイスで生成
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/polly"
)
func synthesizeMultipleVoices(text string, voices []string) {
sess := session.Must(session.NewSession(&aws.Config{
Region: aws.String("ap-northeast-1"),
}))
svc := polly.New(sess)
for _, voiceId := range voices {
result, _ := svc.SynthesizeSpeech(&polly.SynthesizeSpeechInput{
Text: aws.String(text),
VoiceId: aws.String(voiceId),
Engine: aws.String("neural"),
OutputFormat: aws.String("mp3"),
})
fmt.Printf("Generated audio for voice: %s\n", voiceId)
// 音声ファイルに保存
}
}
4. Java: PCM 形式で IVR 最適化
import software.amazon.awssdk.services.polly.PollyClient;
import software.amazon.awssdk.services.polly.model.*;
public class IVRPromptGenerator {
public static void main(String[] args) {
PollyClient pollyClient = PollyClient.builder()
.region(Region.AP_NORTHEAST_1)
.build();
SynthesizeSpeechRequest request = SynthesizeSpeechRequest.builder()
.text("お電話ありがとうございます。")
.voiceId("Tomoko")
.engine(Engine.NEURAL)
.outputFormat(OutputFormat.PCM)
.sampleRateHz("8000") // 電話品質
.build();
SynthesizeSpeechResponse response = pollyClient.synthesizeSpeech(request);
// PCM データを処理
pollyClient.close();
}
}
5. C#: 非同期タスク管理
using Amazon;
using Amazon.Polly;
using Amazon.Polly.Model;
using System;
using System.Threading.Tasks;
class AudiobookGenerator {
static async Task Main() {
var client = new AmazonPollyClient(RegionEndpoint.APNortheast1);
var request = new StartSpeechSynthesisTaskRequest {
Text = "長いテキストのオーディオブック生成...",
Engine = Engine.LongForm,
VoiceId = "Kazuha",
LanguageCode = "ja-JP",
OutputFormat = OutputFormat.Mp3,
OutputS3BucketName = "my-bucket",
OutputS3KeyPrefix = "audiobooks/",
SnsTopicArn = "arn:aws:sns:ap-northeast-1:123456789:polly"
};
var response = await client.StartSpeechSynthesisTaskAsync(request);
Console.WriteLine({{CONTENT}}quot;Task ID: {response.SynthesisTask.TaskId}");
Console.WriteLine({{CONTENT}}quot;Status: {response.SynthesisTask.TaskStatus}");
}
}
IaC 例(5+)
1. CloudFormation: Polly 用 IAM ロール
Resources:
PollyRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: polly.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: PollyS3Access
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:PutObject
Resource: 'arn:aws:s3:::my-bucket/*'
PollyOutputBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: polly-output-${AWS::AccountId}
2. Terraform: SNS トピック統合
resource "aws_s3_bucket" "polly_output" {
bucket = "polly-output-${data.aws_caller_identity.current.account_id}"
}
resource "aws_sns_topic" "polly_completion" {
name = "polly-task-completion"
}
resource "aws_sns_topic_subscription" "polly_webhook" {
topic_arn = aws_sns_topic.polly_completion.arn
protocol = "https"
endpoint = "https://example.com/polly-webhook"
}
resource "aws_iam_role" "polly_async_role" {
name = "polly-async-task-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "polly.amazonaws.com"
}
}]
})
}
3. CDK (Python): オーディオブック生成パイプライン
from aws_cdk import (
aws_s3 as s3,
aws_lambda as lambda_,
aws_sns as sns,
aws_iam as iam,
core
)
class PollyAudiobookStack(core.Stack):
def __init__(self, scope: core.Construct, id: str, **kwargs):
super().__init__(scope, id, **kwargs)
# S3 バケット
output_bucket = s3.Bucket(self, "AudiobookOutput")
# SNS トピック
completion_topic = sns.Topic(
self, "PollyCompletion",
display_name="Polly Task Completion"
)
# Lambda: Polly タスク監視
monitor_function = lambda_.Function(
self, "PollyMonitor",
runtime=lambda_.Runtime.PYTHON_3_11,
code=lambda_.Code.from_asset("lambda"),
handler="monitor.handler",
environment={
"SNS_TOPIC": completion_topic.topic_arn,
"OUTPUT_BUCKET": output_bucket.bucket_name
}
)
4. CloudFormation: Lambda + Polly 統合
Resources:
PollyLambdaFunction:
Type: AWS::Lambda::Function
Properties:
Runtime: python3.11
Handler: index.handler
Role: !GetAtt LambdaRole.Arn
Code:
ZipFile: |
import boto3
polly = boto3.client('polly')
def handler(event, context):
response = polly.synthesize_speech(
Text='Lambda から Polly へのテスト',
VoiceId='Kazuha',
Engine='neural',
OutputFormat='mp3'
)
return {'statusCode': 200}
LambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
5. Terraform: Lambda + EventBridge トリガー
resource "aws_lambda_function" "polly_tts" {
filename = "polly_lambda.zip"
function_name = "text-to-speech-processor"
role = aws_iam_role.lambda_role.arn
handler = "index.handler"
runtime = "python3.11"
timeout = 300
}
resource "aws_events_rule" "text_upload" {
name = "detect-text-file-upload"
event_pattern = jsonencode({
source = ["aws.s3"]
detail = {
bucket = {
name = ["text-input-bucket"]
}
}
})
}
resource "aws_events_target" "polly_target" {
rule = aws_events_rule.text_upload.name
arn = aws_lambda_function.polly_tts.arn
}
比較表
| 特性 | Polly | ElevenLabs | Google TTS | Azure Speech | OpenAI TTS | Murf | WellSaid |
|---|---|---|---|---|---|---|---|
| 言語対応 | 60+ | 29 | 100+ | 200+ | 26 | 20+ | 10+ |
| ボイス数 | 100+ | 1000+ | 140+ | 200+ | 6 | 130+ | 270+ |
| Neural/生成 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| SSML制御 | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ |
| Speech Marks | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ |
| 非同期処理 | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| IVR最適化 | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
| 無料枠 | 100万文字/月 | 10,000文字 | 無し | 50万文字/月 | 無し | トライアル | トライアル |
| 料金 | $4/100万文字 | $5-30/100万文字 | $5-16/100万文字 | $4-16/100万文字 | $0.015/1k入力 | $10+/月 | 要相談 |
ベストプラクティス
✅ すべき事
- エンジン選択: リアルタイム IVR は Standard、オーディオブックは Long-form
- SSML 活用: 速度・ピッチ・感情を細かく制御
- Speech Marks 取得: 字幕同期が必要な場合は必須
- キャッシング活用: 同じテキスト・ボイスの再生成は避ける
- 音声フォーマット最適化: IVR は PCM 8kHz、ストリーミングは MP3
- エラーハンドリング: 合成失敗時のフォールバック
- CloudWatch 監視: 非同期タスク完了を SNS で追跡
- 多言語テスト: 言語ごとに音声品質を確認
- アクセシビリティ: 視覚障害者向けに常に音声オプション提供
❌ してはいけない事
- リアルタイムで Long-form 使用: レイテンシー増大・コスト増加
- SSML なしで速度制御: CLI パラメータでは速度制御不可
- 大量テキストをリアルタイム API で: 非同期タスク (start_speech_synthesis_task) を使用
- 出力フォーマット誤選択: オーディオブックを PCM で生成しない
- 言語コード未指定: 言語自動検出は精度が低い
- Speech Marks なしで字幕作成: タイミング情報がないと字幕がずれる
- キャッシング無視: 同じテキストを何度も合成しない
- SampleRateHz 無視: デバイスに合った SampleRate を指定
- エラーログなし: 失敗理由が分からない
トラブルシューティング
| 症状 | 原因 | 解決策 |
|---|---|---|
| 「InvalidParameterException」エラー | ボイス/言語コード不正 | 公式サイトでサポート言語・ボイス確認 |
| 音声品質が不自然 | エンジン選択誤り | Neural エンジン使用、SSML で調整 |
| Speech Marks タイムスタンプ不正 | 出力フォーマット誤り | –output-format を json に設定 |
| 非同期タスク失敗 | S3 権限不足 | IAM ロールに S3 FullAccess 確認 |
| IVR 音声が遅い | レイテンシー高い | OutputFormat を PCM、SampleRateHz を 8000 に |
| SSML が反映されない | TextType が ‘text’ | –text-type を ‘ssml’ に設定 |
| 言語サポート外エラー | 言語コード未対応 | 言語サポート一覧確認 |
| キャッシング参照エラー | 音声ファイル不在 | CloudFront キャッシュを確認 |
| SSML フォーマットエラー | XML が不正 | SSML バリデータで確認 |
| コスト急増 | 無駄な再生成 | キャッシング実装・不要テキスト削除 |
2025-2026最新動向
1. Generative Voice(生成型音声)
- 新規ボイス合成・個性的な音声生成
- ブランド固有音声の自動生成
2. Real-time TTS Streaming
- WebSocket での低遅延音声ストリーミング
- ライブ翻訳・ライブ字幕対応
3. Emotion-Aware TTS
- テキスト内容に応じた自動感情制御
- マーケティング・コンテンツの最適化
4. Multi-Speaker Synthesis
- 複数キャラクターが対話する音声生成
- ドラマ・ポッドキャスト制作の自動化
5. Custom Voice Training
- 企業ブランド音声の学習・生成
- ボイスアクターの再現
学習リソース・参考文献
公式ドキュメント(8+)
- Amazon Polly Developer Guide
- Supported Languages & Voices
- SSML Reference
- Speech Marks
- API Reference
- Pricing
- Asynchronous Processing
- Security & Compliance
OSS・ベンダー リソース(5+)
- pyttsx3 - Offline TTS
- gTTS - Google Text-to-Speech
- ElevenLabs Python SDK
- Mozilla TTS
- Tacotron 2 - Open-source TTS
実装例・チェックリスト
まとめ
Polly は 「テキストを自然な音声に変換する TTS サービス」。Neural・Long-form・Generative 4 つのエンジンで 60+ 言語・100+ ボイスに対応し、SSML・Speech Marks で細かい制御が可能。IVR・オーディオブック・アクセシビリティ・ゲーム・IoT の音声化基盤として、Transcribe・Translate・Comprehend と組み合わせた完全な多言語音声パイプラインを構築できます。
最終更新:2026-04-26 バージョン:v2.0