Bedrock Realtime API
Bedrock Realtime API
Amazon Bedrock의 Nova Sonic 모델은 음성 대화를 위한 실시간 양방향 오디오 스트리밍을 지원해요. 이 튜토리얼은 LiteLLM Proxy에서의 사용법을 보여줘요.
출처: 문서
본문
개요 (Overview)
Amazon Bedrock의 Nova Sonic 모델은 음성 대화를 위한 실시간 양방향 오디오 스트리밍을 지원해요.
설정 (Setup)
1. LiteLLM Proxy 구성
config.yaml 파일 생성:
model_list:
- model_name: "bedrock-sonic"
litellm_params:
model: bedrock/amazon.nova-sonic-v1:0
aws_region_name: us-east-1 # or your preferred region
model_info:
mode: realtime
2. LiteLLM Proxy 시작
litellm --config config.yaml
기본 텍스트 상호작용 (Basic Text Interaction)
import asyncio
import websockets
import json
LITELLM_API_KEY = "sk-<your-litellm-api-key>" # Your LiteLLM API key
LITELLM_URL = 'ws://localhost:4000/v1/realtime?model=bedrock-sonic'
async def test_text_conversation():
async with websockets.connect(
LITELLM_URL,
additional_headers={
"Authorization": f"Bearer {LITELLM_API_KEY}"
}
) as ws:
# Wait for session.created
response = await ws.recv()
print(f"Connected: {json.loads(response)['type']}")
# Configure session
session_update = {
"type": "session.update",
"session": {
"instructions": "You are a helpful assistant.",
"modalities": ["text"],
"temperature": 0.8
}
}
await ws.send(json.dumps(session_update))
# Send a message
message = {
"type": "conversation.item.create",
"item": {
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "Hello!"}]
}
}
await ws.send(json.dumps(message))
# Trigger response
await ws.send(json.dumps({"type": "response.create"}))
# Listen for response
while True:
response = await ws.recv()
event = json.loads(response)
if event['type'] == 'response.text.delta':
print(event['delta'], end='', flush=True)
elif event['type'] == 'response.done':
print("\n✓ Complete")
break
if __name__ == "__main__":
asyncio.run(test_text_conversation())
음성 대화 오디오 스트리밍 (Audio Streaming with Voice Conversation)
import asyncio
import websockets
import json
import base64
import pyaudio
LITELLM_API_KEY = "sk-<your-litellm-api-key>"
LITELLM_URL = 'ws://localhost:4000/v1/realtime?model=bedrock-sonic'
# Audio configuration
INPUT_RATE = 16000 # Nova Sonic expects 16kHz input
OUTPUT_RATE = 24000 # Nova Sonic outputs 24kHz
CHUNK = 1024
async def audio_conversation():
# Initialize PyAudio
p = pyaudio.PyAudio()
# Input stream (microphone)
input_stream = p.open(
format=pyaudio.paInt16,
channels=1,
rate=INPUT_RATE,
input=True,
frames_per_buffer=CHUNK
)
# Output stream (speakers)
output_stream = p.open(
format=pyaudio.paInt16,
channels=1,
rate=OUTPUT_RATE,
output=True,
frames_per_buffer=CHUNK
)
async with websockets.connect(
LITELLM_URL,
additional_headers={"Authorization": f"Bearer {LITELLM_API_KEY}"}
) as ws:
# Wait for session.created
await ws.recv()
print("✓ Connected")
# Configure session with audio
session_update = {
"type": "session.update",
"session": {
"instructions": "You are a friendly voice assistant.",
"modalities": ["text", "audio"],
"voice": "matthew",
"input_audio_format": "pcm16",
"output_audio_format": "pcm16"
}
}
await ws.send(json.dumps(session_update))
print("🎤 Speak into your microphone...")
async def send_audio():
"""Capture and send audio from microphone"""
while True:
audio_data = input_stream.read(CHUNK, exception_on_overflow=False)
audio_b64 = base64.b64encode(audio_data).decode('utf-8')
await ws.send(json.dumps({
"type": "input_audio_buffer.append",
"audio": audio_b64
}))
await asyncio.sleep(0.01)
async def receive_audio():
"""Receive and play audio responses"""
while True:
response = await ws.recv()
event = json.loads(response)
if event['type'] == 'response.audio.delta':
audio_b64 = event.get('delta', '')
if audio_b64:
audio_bytes = base64.b64decode(audio_b64)
output_stream.write(audio_bytes)
elif event['type'] == 'response.text.delta':
print(event['delta'], end='', flush=True)
elif event['type'] == 'response.done':
print("\n✓ Response complete")
도구/함수 호출 사용 (Using Tools/Function Calling)
import asyncio
import websockets
import json
from datetime import datetime
LITELLM_API_KEY = "sk-<your-litellm-api-key>"
LITELLM_URL = 'ws://localhost:4000/v1/realtime?model=bedrock-sonic'
# Define tools
TOOLS = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name"
}
},
"required": ["location"]
}
}
}
]
def get_weather(location: str) -> dict:
"""Simulated weather function"""
return {
"location": location,
"temperature": 72,
"conditions": "sunny"
}
async def conversation_with_tools():
async with websockets.connect(
LITELLM_URL,
additional_headers={"Authorization": f"Bearer {LITELLM_API_KEY}"}
) as ws:
# Wait for session.created
await ws.recv()
# Configure session with tools
session_update = {
"type": "session.update",
"session": {
"instructions": "You are a helpful assistant with access to tools.",
"modalities": ["text"],
"tools": TOOLS
}
}
await ws.send(json.dumps(session_update))
# Send a message that requires a tool
message = {
"type": "conversation.item.create",
"item": {
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "What's the weather in San Francisco?"}]
}
}
await ws.send(json.dumps(message))
await ws.send(json.dumps({"type": "response.create"}))
# Handle responses and tool calls
while True:
response = await ws.recv()
event = json.loads(response)
if event['type'] == 'response.text.delta':
print(event['delta'], end='', flush=True)
elif event['type'] == 'response.function_call_arguments.done':
# Execute the tool
function_name = event['name']
arguments = json.loads(event['arguments'])
print(f"\n🔧 Calling {function_name}({arguments})")
result = get_weather(**arguments)
# Send tool result back
tool_result = {
"type": "conversation.item.create",
"item": {
"type": "function_call_output",
"call_id": event['call_id'],
"output": json.dumps(result)
}
}
await ws.send(json.dumps(tool_result))
설정 옵션 (Configuration Options)
음성 옵션 (Voice Options)
사용 가능한 음성: matthew, joanna, ruth, stephen, gregory, amy
오디오 형식 (Audio Formats)
- 입력: 16kHz PCM16 (mono)
- 출력: 24kHz PCM16 (mono)
Modalities
["text"]- 텍스트만["audio"]- 오디오만["text", "audio"]- 텍스트와 오디오 모두
예시 테스트 스크립트 (Example Test Scripts)
LiteLLM 리포지토리에서 완전한 동작 예제를 확인할 수 있어요:
- 기본 오디오 스트리밍: test_bedrock_realtime_client.py
- 간단한 텍스트 테스트: test_bedrock_realtime_simple.py
- Tool calling: test_bedrock_realtime_tools.py
요구사항 (Requirements)
uv add litellm websockets pyaudio
AWS 설정 (AWS Configuration)
AWS 자격 증명이 구성되어 있는지 확인하세요:
export AWS_ACCESS_KEY_ID=your_access_key
export AWS_SECRET_ACCESS_KEY=your_secret_key
export AWS_REGION_NAME=us-east-1
또는 AWS CLI 설정 사용:
aws configure
문제 해결 (Troubleshooting)
연결 문제
- LiteLLM proxy가 올바른 포트에서 실행 중인지 확인
- AWS 자격 증명이 올바르게 구성되었는지 확인
- Bedrock 모델이 해당 지역에 사용 가능한지 확인
오디오 문제
- PyAudio가 제대로 설치되었는지 확인
- 마이크/스피커 권한 확인
- 올바른 샘플 레이트 확인 (16kHz 입력, 24kHz 출력)
Tool Calling 문제
- session.update에서 도구가 올바르게 정의되었는지 확인
- tool 결과가 올바른 call_id로 다시 전송되는지 확인
- tool 결과가 나온 후 response.create가 전송되는지 확인