Replace httpx with aiohttp
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
@@ -31,78 +32,79 @@ async def run_bot(webrtc_connection: SmallWebRTCConnection):
|
|||||||
|
|
||||||
remote_smart_turn_url = os.getenv("REMOTE_SMART_TURN_URL")
|
remote_smart_turn_url = os.getenv("REMOTE_SMART_TURN_URL")
|
||||||
|
|
||||||
transport = SmallWebRTCTransport(
|
async with aiohttp.ClientSession() as session:
|
||||||
webrtc_connection=webrtc_connection,
|
transport = SmallWebRTCTransport(
|
||||||
params=TransportParams(
|
webrtc_connection=webrtc_connection,
|
||||||
audio_in_enabled=True,
|
params=TransportParams(
|
||||||
audio_out_enabled=True,
|
audio_in_enabled=True,
|
||||||
vad_enabled=True,
|
audio_out_enabled=True,
|
||||||
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)),
|
vad_enabled=True,
|
||||||
vad_audio_passthrough=True,
|
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)),
|
||||||
turn_analyzer=SmartTurnAnalyzer(url=remote_smart_turn_url),
|
vad_audio_passthrough=True,
|
||||||
),
|
turn_analyzer=SmartTurnAnalyzer(url=remote_smart_turn_url, aiohttp_session=session),
|
||||||
)
|
),
|
||||||
|
)
|
||||||
|
|
||||||
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
|
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
|
||||||
|
|
||||||
tts = CartesiaTTSService(
|
tts = CartesiaTTSService(
|
||||||
api_key=os.getenv("CARTESIA_API_KEY"),
|
api_key=os.getenv("CARTESIA_API_KEY"),
|
||||||
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
|
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
|
||||||
)
|
)
|
||||||
|
|
||||||
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"))
|
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
|
||||||
messages = [
|
messages = [
|
||||||
{
|
{
|
||||||
"role": "system",
|
"role": "system",
|
||||||
"content": "You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. Your output will be converted to audio so don't include special characters in your answers. Respond to what the user said in a creative and helpful way.",
|
"content": "You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. Your output will be converted to audio so don't include special characters in your answers. Respond to what the user said in a creative and helpful way.",
|
||||||
},
|
},
|
||||||
]
|
|
||||||
|
|
||||||
context = OpenAILLMContext(messages)
|
|
||||||
context_aggregator = llm.create_context_aggregator(context)
|
|
||||||
|
|
||||||
pipeline = Pipeline(
|
|
||||||
[
|
|
||||||
transport.input(), # Transport user input
|
|
||||||
stt,
|
|
||||||
context_aggregator.user(), # User responses
|
|
||||||
llm, # LLM
|
|
||||||
tts, # TTS
|
|
||||||
transport.output(), # Transport bot output
|
|
||||||
context_aggregator.assistant(), # Assistant spoken responses
|
|
||||||
]
|
]
|
||||||
)
|
|
||||||
|
|
||||||
task = PipelineTask(
|
context = OpenAILLMContext(messages)
|
||||||
pipeline,
|
context_aggregator = llm.create_context_aggregator(context)
|
||||||
params=PipelineParams(
|
|
||||||
allow_interruptions=True,
|
|
||||||
enable_metrics=True,
|
|
||||||
enable_usage_metrics=True,
|
|
||||||
report_only_initial_ttfb=True,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
@transport.event_handler("on_client_connected")
|
pipeline = Pipeline(
|
||||||
async def on_client_connected(transport, client):
|
[
|
||||||
logger.info(f"Client connected")
|
transport.input(), # Transport user input
|
||||||
# Kick off the conversation.
|
stt,
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
context_aggregator.user(), # User responses
|
||||||
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
llm, # LLM
|
||||||
|
tts, # TTS
|
||||||
|
transport.output(), # Transport bot output
|
||||||
|
context_aggregator.assistant(), # Assistant spoken responses
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_client_disconnected")
|
task = PipelineTask(
|
||||||
async def on_client_disconnected(transport, client):
|
pipeline,
|
||||||
logger.info(f"Client disconnected")
|
params=PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_client_closed")
|
@transport.event_handler("on_client_connected")
|
||||||
async def on_client_closed(transport, client):
|
async def on_client_connected(transport, client):
|
||||||
logger.info(f"Client closed connection")
|
logger.info(f"Client connected")
|
||||||
await task.cancel()
|
# Kick off the conversation.
|
||||||
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
runner = PipelineRunner(handle_sigint=False)
|
@transport.event_handler("on_client_disconnected")
|
||||||
|
async def on_client_disconnected(transport, client):
|
||||||
|
logger.info(f"Client disconnected")
|
||||||
|
|
||||||
await runner.run(task)
|
@transport.event_handler("on_client_closed")
|
||||||
|
async def on_client_closed(transport, client):
|
||||||
|
logger.info(f"Client closed connection")
|
||||||
|
await task.cancel()
|
||||||
|
|
||||||
|
runner = PipelineRunner(handle_sigint=False)
|
||||||
|
|
||||||
|
await runner.run(task)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -5,10 +5,11 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import io
|
import io
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
import httpx
|
import aiohttp
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
@@ -16,19 +17,15 @@ from pipecat.audio.turn.base_smart_turn import BaseSmartTurn, SmartTurnTimeoutEx
|
|||||||
|
|
||||||
|
|
||||||
class SmartTurnAnalyzer(BaseSmartTurn):
|
class SmartTurnAnalyzer(BaseSmartTurn):
|
||||||
def __init__(self, url: str, **kwargs):
|
def __init__(self, url: str, aiohttp_session: aiohttp.ClientSession, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.remote_smart_turn_url = url
|
self.remote_smart_turn_url = url
|
||||||
|
self._aiohttp_session = aiohttp_session
|
||||||
|
|
||||||
if not self.remote_smart_turn_url:
|
if not self.remote_smart_turn_url:
|
||||||
logger.error("remote_smart_turn_url is not set.")
|
logger.error("remote_smart_turn_url is not set.")
|
||||||
raise Exception("remote_smart_turn_url must be provided.")
|
raise Exception("remote_smart_turn_url must be provided.")
|
||||||
|
|
||||||
self.client = httpx.AsyncClient(
|
|
||||||
headers={"Connection": "keep-alive"},
|
|
||||||
timeout=httpx.Timeout(self._params.stop_secs),
|
|
||||||
)
|
|
||||||
|
|
||||||
def _serialize_array(self, audio_array: np.ndarray) -> bytes:
|
def _serialize_array(self, audio_array: np.ndarray) -> bytes:
|
||||||
logger.trace("Serializing NumPy array to bytes...")
|
logger.trace("Serializing NumPy array to bytes...")
|
||||||
buffer = io.BytesIO()
|
buffer = io.BytesIO()
|
||||||
@@ -43,33 +40,36 @@ class SmartTurnAnalyzer(BaseSmartTurn):
|
|||||||
f"Sending {len(data_bytes)} bytes as raw body to {self.remote_smart_turn_url}..."
|
f"Sending {len(data_bytes)} bytes as raw body to {self.remote_smart_turn_url}..."
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
response = await self.client.post(
|
timeout = aiohttp.ClientTimeout(total=self._params.stop_secs)
|
||||||
self.remote_smart_turn_url,
|
|
||||||
content=data_bytes,
|
|
||||||
headers=headers,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.trace("\n--- Response ---")
|
async with self._aiohttp_session.post(
|
||||||
logger.trace(f"Status Code: {response.status_code}")
|
self.remote_smart_turn_url, data=data_bytes, headers=headers, timeout=timeout
|
||||||
|
) as response:
|
||||||
|
logger.trace("\n--- Response ---")
|
||||||
|
logger.trace(f"Status Code: {response.status}")
|
||||||
|
|
||||||
if response.is_success:
|
if response.status == 200:
|
||||||
try:
|
try:
|
||||||
json_data = response.json()
|
json_data = await response.json()
|
||||||
logger.trace("Response JSON:")
|
logger.trace("Response JSON:")
|
||||||
logger.trace(json_data)
|
logger.trace(json_data)
|
||||||
return json_data
|
return json_data
|
||||||
except httpx.DecodingError:
|
except aiohttp.ContentTypeError:
|
||||||
logger.trace("Response Content (non-JSON):")
|
# Non-JSON response
|
||||||
logger.trace(response.text)
|
text = await response.text()
|
||||||
else:
|
logger.trace("Response Content (non-JSON):")
|
||||||
logger.trace("Response Content (Error):")
|
logger.trace(text)
|
||||||
logger.trace(response.text)
|
raise Exception(f"Non-JSON response: {text}")
|
||||||
response.raise_for_status()
|
else:
|
||||||
|
error_text = await response.text()
|
||||||
|
logger.trace("Response Content (Error):")
|
||||||
|
logger.trace(error_text)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
except httpx.TimeoutException:
|
except asyncio.TimeoutError:
|
||||||
logger.error(f"Request timed out after {self._params.stop_secs} seconds")
|
logger.error(f"Request timed out after {self._params.stop_secs} seconds")
|
||||||
raise SmartTurnTimeoutException(f"Request exceeded {self._params.stop_secs} seconds.")
|
raise SmartTurnTimeoutException(f"Request exceeded {self._params.stop_secs} seconds.")
|
||||||
except httpx.RequestError as e:
|
except aiohttp.ClientError as e:
|
||||||
logger.error(f"Failed to send raw request to Daily Smart Turn: {e}")
|
logger.error(f"Failed to send raw request to Daily Smart Turn: {e}")
|
||||||
raise Exception("Failed to send raw request to Daily Smart Turn.")
|
raise Exception("Failed to send raw request to Daily Smart Turn.")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user