音声・テキストエージェントのワークフロー
文字起こし → 推論 → 音声応答のパイプラインをエンドツーエンドで構築します。
「音声・テキストエージェントのワークフロー」はCoddyKit上の無料AI Agentsレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Agents学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Agentsコースには全4レッスンが含まれています。
音声・テキストエージェントパイプラインの概要
音声・テキストエージェントパイプラインは、話し言葉と書き言葉の世界を相互に変換します。基本的な流れは、音声入力 → Whisperによる文字起こし → テキストエージェント → TTSによる音声出力です。これにより、音声アシスタント、通話分析、会議の要約、ハンズフリーインターフェースが実現します。
対応音声形式
OpenAI Whisperは、mp3、mp4、mpeg、mpga、m4a、wav、webmに対応しています。最大ファイルサイズは25 MBです。これより大きいファイルを送信する場合は、事前に音声を分割または圧縮する必要があります。
最高の文字起こし品質と最小のファイルサイズを実現するには、常に16 kHzのモノラルで録音または変換してください。
import os
SUPPORTED_FORMATS = {'.mp3', '.mp4', '.mpeg', '.mpga', '.m4a', '.wav', '.webm'}
MAX_FILE_SIZE_BYTES = 25 * 1024 * 1024 # 25 MB
def validate_audio_file(path: str) -> dict:
ext = os.path.splitext(path)[1].lower()
size = os.path.getsize(path) if os.path.exists(path) else 0
return {
'path': path,
'format_ok': ext in SUPPORTED_FORMATS,
'size_ok': size <= MAX_FILE_SIZE_BYTES,
'size_mb': round(size / 1024 / 1024, 2),
'extension': ext
}
# Usage:
info = validate_audio_file('meeting.wav')
print(info)Whisperによる音声の文字起こし
OpenAIのaudio.transcriptions.createエンドポイントはWhisperをラップしています。ファイルオブジェクトとモデル名を渡し、必要に応じて言語ヒント(処理が速くなり、誤検出を防げます)とプロンプト(ドメイン固有の用語に合わせて語彙をあらかじめ設定します)も指定します。
from openai import OpenAI
client = OpenAI(api_key='YOUR_OPENAI_API_KEY')
def transcribe_audio(
audio_path: str,
language: str = 'en',
prompt: str = ''
) -> str:
with open(audio_path, 'rb') as audio_file:
transcript = client.audio.transcriptions.create(
model='whisper-1',
file=audio_file,
language=language,
prompt=prompt, # e.g. 'Python, NestJS, TypeScript, API'
response_format='text'
)
return transcript
text = transcribe_audio('user_query.mp3', language='en',
prompt='Kubernetes, microservices, Docker')
print('Transcription:', text)タイムスタンプ付き文字起こし
会議の分析や話者分離を行う場合は、verbose_json形式を指定してください。これにより、単語単位またはセグメント単位のタイムスタンプが返されるため、参照や切り出しに必要な音声内の正確な時点を特定できます。
def transcribe_with_timestamps(audio_path: str) -> dict:
from openai import OpenAI
client = OpenAI(api_key='YOUR_OPENAI_API_KEY')
with open(audio_path, 'rb') as f:
result = client.audio.transcriptions.create(
model='whisper-1',
file=f,
response_format='verbose_json',
timestamp_granularities=['segment']
)
# result.segments: list of {start, end, text}
segments = [
{'start': s.start, 'end': s.end, 'text': s.text}
for s in result.segments
]
return {'full_text': result.text, 'segments': segments}
# Example output structure:
# {'full_text': 'Hello team...', 'segments': [{'start': 0.0, 'end': 2.3, 'text': 'Hello team'}]}テキストエージェントによる処理
文字起こし後、テキストは通常のテキストメッセージとしてLLMエージェントを通過します。コンテキストを設定するシステムプロンプトを含めてください。このテキストは発話から生成されたものなので、フィラーワードや不完全な文が含まれることを想定します。
import anthropic
VOICE_AGENT_SYSTEM = (
'You are a helpful voice assistant. The user\'s message was transcribed from speech '
'and may contain filler words ("um", "uh"), false starts, or incomplete sentences. '
'Interpret the intent charitably and respond concisely in 1-3 sentences. '
'Your response will be converted to speech, so avoid markdown, lists, or code blocks.'
)
def voice_agent_respond(transcription: str) -> str:
client = anthropic.Anthropic(api_key='YOUR_ANTHROPIC_API_KEY')
response = client.messages.create(
model='claude-opus-4-5',
max_tokens=256,
system=VOICE_AGENT_SYSTEM,
messages=[{'role': 'user', 'content': transcription}]
)
return response.content[0].textOpenAI TTSによるテキスト読み上げ
OpenAIのTTS APIを使用して、エージェントのテキスト応答を音声に戻します。音声(alloy、echo、fable、onyx、nova、shimmer)とモデル(速度重視のtts-1、品質重視のtts-1-hd)を選択してください。結果をmp3ファイルとして保存するか、直接ストリーミングします。
from openai import OpenAI
from pathlib import Path
client = OpenAI(api_key='YOUR_OPENAI_API_KEY')
def text_to_speech(
text: str,
output_path: str = 'response.mp3',
voice: str = 'nova',
model: str = 'tts-1'
) -> str:
response = client.audio.speech.create(
model=model,
voice=voice,
input=text,
response_format='mp3'
)
Path(output_path).write_bytes(response.content)
print(f'TTS audio saved to {output_path}')
return output_path
# Full pipeline:
tts_file = text_to_speech(
'The weather in London is currently 15 degrees and partly cloudy.',
voice='nova'
)音声出力のストリーミング
リアルタイムの音声応答では、完全なファイルの生成を待つのではなく、TTS音声をチャンク単位でストリーミングしてください。OpenAIのstream_to_fileヘルパーまたは手動のチャンク反復処理を使うと、残りの音声が生成中でも再生を開始できます。
from openai import OpenAI
client = OpenAI(api_key='YOUR_OPENAI_API_KEY')
def stream_tts_to_file(text: str, output_path: str):
# OpenAI SDK streams the audio response
with client.audio.speech.with_streaming_response.create(
model='tts-1',
voice='nova',
input=text,
response_format='mp3'
) as response:
response.stream_to_file(output_path)
print(f'Streamed to {output_path}')
def stream_tts_chunks(text: str):
"""Yield raw audio bytes for piping to an audio player."""
with client.audio.speech.with_streaming_response.create(
model='tts-1',
voice='nova',
input=text
) as response:
for chunk in response.iter_bytes(chunk_size=4096):
yield chunk # pipe to audio player or WebSocket長い音声ファイルの分割
25 MBを超える音声ファイルは、Whisperに送信する前に分割する必要があります。pydubライブラリを使用して時間間隔ごとに分割し、各チャンクを個別に処理してから、文字起こし結果を連結してください。
from pydub import AudioSegment
import os
def split_audio(
path: str,
chunk_minutes: int = 10
) -> list:
audio = AudioSegment.from_file(path)
chunk_ms = chunk_minutes * 60 * 1000
chunks = []
os.makedirs('audio_chunks', exist_ok=True)
for i, start in enumerate(range(0, len(audio), chunk_ms)):
chunk = audio[start:start + chunk_ms]
chunk_path = f'audio_chunks/chunk_{i:03d}.mp3'
chunk.export(chunk_path, format='mp3')
chunks.append(chunk_path)
return chunks
def transcribe_long_audio(path: str) -> str:
chunks = split_audio(path, chunk_minutes=10)
transcripts = []
for chunk_path in chunks:
text = transcribe_audio(chunk_path)
transcripts.append(text)
# Clean up chunks
for chunk_path in chunks:
os.remove(chunk_path)
return ' '.join(transcripts)リアルタイム音声パイプライン
リアルタイムパイプラインでは、マイク入力をチャンク単位で取得し、到着するたびに各チャンクをWhisperへ送信して、TTS出力をストリーミングで返します。これにより、ほぼリアルタイムの音声会話ループを実現できます。重要な課題は、各段階のレイテンシを管理することです。
import asyncio
import time
async def realtime_voice_loop(mic_stream, speaker_stream, client):
"""
mic_stream: async generator yielding audio bytes
speaker_stream: async callable accepting audio bytes
"""
buffer = b''
BUFFER_THRESHOLD = 50 * 1024 # ~3 seconds at 16kHz mono mp3
async for audio_chunk in mic_stream:
buffer += audio_chunk
if len(buffer) >= BUFFER_THRESHOLD:
t0 = time.time()
# Save buffer to temp file
with open('/tmp/voice_chunk.mp3', 'wb') as f:
f.write(buffer)
buffer = b''
# Transcribe
text = transcribe_audio('/tmp/voice_chunk.mp3')
print(f'Transcribed ({time.time()-t0:.1f}s): {text}')
# Agent response
reply = voice_agent_respond(text)
# TTS and stream to speaker
for audio_bytes in stream_tts_chunks(reply):
await speaker_stream(audio_bytes)言語検出と自動ルーティング
Whisperは発話された言語を自動的に検出します。検出された言語を使って、会話を適切なエージェントペルソナに振り分けたり、応答に使用するTTSの言語を設定したりできます。
def transcribe_and_detect_language(audio_path: str) -> dict:
from openai import OpenAI
client = OpenAI(api_key='YOUR_OPENAI_API_KEY')
with open(audio_path, 'rb') as f:
result = client.audio.transcriptions.create(
model='whisper-1',
file=f,
response_format='verbose_json'
)
return {
'text': result.text,
'language': result.language, # e.g. 'english', 'spanish'
'duration': result.duration
}
LANGUAGE_VOICE_MAP = {
'english': 'nova',
'spanish': 'alloy',
'french': 'echo',
'german': 'fable'
}
def respond_in_detected_language(audio_path: str) -> str:
info = transcribe_and_detect_language(audio_path)
voice = LANGUAGE_VOICE_MAP.get(info['language'], 'nova')
reply = voice_agent_respond(info['text'])
return text_to_speech(reply, voice=voice)背景ノイズと低品質音声への対処
低品質の音声は文字起こしの精度を低下させます。実践的な対策として、ノイズ低減(noisereduceライブラリ)で前処理を行う、Whisperのpromptにドメイン固有の語彙を追加する、文字起こしの信頼度を検証する、信頼度が低い場合は明確化を求める、といった方法があります。
def transcribe_with_quality_check(
audio_path: str,
min_confidence_words: int = 3
) -> dict:
from openai import OpenAI
import string
client = OpenAI(api_key='YOUR_OPENAI_API_KEY')
with open(audio_path, 'rb') as f:
result = client.audio.transcriptions.create(
model='whisper-1',
file=f,
response_format='verbose_json',
timestamp_granularities=['word']
)
# Word count as a basic quality proxy
words = result.text.translate(
str.maketrans('', '', string.punctuation)
).split()
quality_ok = len(words) >= min_confidence_words
return {
'text': result.text,
'word_count': len(words),
'quality_ok': quality_ok,
'fallback_message': None if quality_ok else 'I could not hear you clearly. Please repeat.'
}知識チェック
Whisperのpromptパラメーターは何をしますか?
振り返り:音声・テキストエージェントのワークフロー
すばらしいです!主なポイント:
- Whisper:mp3、wav、m4aなどに対応し、最大25 MB。大きなファイルはpydubで分割
- タイムスタンプ:
timestamp_granularitiesを指定したverbose_jsonでセグメントのタイミングを取得 - TTS:音声の選択肢があるOpenAI TTSを使用し、低レイテンシのためにチャンクをストリーミング
- 言語検出:Whisperが自動検出し、検出された言語に基づいて適切な音声やエージェントに振り分ける
- リアルタイムパイプライン:音声チャンクをバッファリング → 文字起こし → エージェント → TTSをストリーミング
次は、エージェントにおける動画理解です。フレーム抽出と時間的推論を扱います。
よくある質問
「音声・テキストエージェントのワークフロー」レッスンは無料ですか?
はい。「音声・テキストエージェントのワークフロー」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Agentsコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Agentsコースには全4レッスンが含まれています。
「音声・テキストエージェントのワークフロー」で何を学びますか?
文字起こし → 推論 → 音声応答のパイプラインをエンドツーエンドで構築します。 ブラウザで直接実行するハンズオンコードでAI Agentsを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Agentsを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Agentsは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「音声・テキストエージェントのワークフロー」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Agentsレッスンでコードを書いて実行できますか?
はい。すべてのAI Agentsレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- Claude Vision と GPT-4V による画像・テキストエージェント
- 音声・テキストエージェントのワークフロー
- エージェントにおける動画理解
- クロスモーダル推論のパターン