[WIP] AWS Nova Sonic service - post-rebase, update examples to play nicely with recent pipecat changes

This commit is contained in:
Paul Kompfner
2025-05-06 21:19:16 -04:00
parent 35848d10b3
commit 5579145a06
2 changed files with 27 additions and 29 deletions

View File

@@ -4,6 +4,7 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import argparse
import asyncio import asyncio
import glob import glob
import json import json
@@ -22,6 +23,7 @@ from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.aws_nova_sonic.aws import AWSNovaSonicLLMService from pipecat.services.aws_nova_sonic.aws import AWSNovaSonicLLMService
from pipecat.services.llm_service import FunctionCallParams
from pipecat.transports.base_transport import TransportParams from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
@@ -31,21 +33,19 @@ load_dotenv(override=True)
BASE_FILENAME = "/tmp/pipecat_conversation_" BASE_FILENAME = "/tmp/pipecat_conversation_"
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(params: FunctionCallParams):
temperature = 75 if args["format"] == "fahrenheit" else 24 temperature = 75 if params.arguments["format"] == "fahrenheit" else 24
await result_callback( await params.result_callback(
{ {
"conditions": "nice", "conditions": "nice",
"temperature": temperature, "temperature": temperature,
"format": args["format"], "format": params.arguments["format"],
"timestamp": datetime.now().strftime("%Y%m%d_%H%M%S"), "timestamp": datetime.now().strftime("%Y%m%d_%H%M%S"),
} }
) )
async def get_saved_conversation_filenames( async def get_saved_conversation_filenames(params: FunctionCallParams):
function_name, tool_call_id, args, llm, context, result_callback
):
# Construct the full pattern including the BASE_FILENAME # Construct the full pattern including the BASE_FILENAME
full_pattern = f"{BASE_FILENAME}*.json" full_pattern = f"{BASE_FILENAME}*.json"
@@ -53,7 +53,7 @@ async def get_saved_conversation_filenames(
matching_files = glob.glob(full_pattern) matching_files = glob.glob(full_pattern)
logger.debug(f"matching files: {matching_files}") logger.debug(f"matching files: {matching_files}")
await result_callback({"filenames": matching_files}) await params.result_callback({"filenames": matching_files})
# async def get_saved_conversation_filenames( # async def get_saved_conversation_filenames(
@@ -69,26 +69,26 @@ async def get_saved_conversation_filenames(
# await result_callback({"filenames": matching_files}) # await result_callback({"filenames": matching_files})
async def save_conversation(function_name, tool_call_id, args, llm, context, result_callback): async def save_conversation(params: FunctionCallParams):
timestamp = datetime.now().strftime("%Y-%m-%d_%H:%M:%S") timestamp = datetime.now().strftime("%Y-%m-%d_%H:%M:%S")
filename = f"{BASE_FILENAME}{timestamp}.json" filename = f"{BASE_FILENAME}{timestamp}.json"
logger.debug( logger.debug(
f"writing conversation to {filename}\n{json.dumps(context.get_messages_for_persistent_storage(), indent=4)}" f"writing conversation to {filename}\n{json.dumps(params.context.get_messages_for_persistent_storage(), indent=4)}"
) )
try: try:
with open(filename, "w") as file: with open(filename, "w") as file:
messages = context.get_messages_for_persistent_storage() messages = params.context.get_messages_for_persistent_storage()
# remove the last message, which is the instruction we just gave to save the conversation # remove the last message, which is the instruction we just gave to save the conversation
messages.pop() messages.pop()
json.dump(messages, file, indent=2) json.dump(messages, file, indent=2)
await result_callback({"success": True}) await params.result_callback({"success": True})
except Exception as e: except Exception as e:
await result_callback({"success": False, "error": str(e)}) await params.result_callback({"success": False, "error": str(e)})
async def load_conversation(function_name, tool_call_id, args, llm, context, result_callback): async def load_conversation(params: FunctionCallParams):
async def _reset(): async def _reset():
filename = args["filename"] filename = params.arguments["filename"]
logger.debug(f"loading conversation from {filename}") logger.debug(f"loading conversation from {filename}")
try: try:
with open(filename, "r") as file: with open(filename, "r") as file:
@@ -99,11 +99,11 @@ async def load_conversation(function_name, tool_call_id, args, llm, context, res
"content": f"{AWSNovaSonicLLMService.AWAIT_TRIGGER_ASSISTANT_RESPONSE_INSTRUCTION}", "content": f"{AWSNovaSonicLLMService.AWAIT_TRIGGER_ASSISTANT_RESPONSE_INSTRUCTION}",
} }
) )
context.set_messages(messages) params.context.set_messages(messages)
await llm.reset_conversation() await params.llm.reset_conversation()
await llm.trigger_assistant_response() await params.llm.trigger_assistant_response()
except Exception as e: except Exception as e:
await result_callback({"success": False, "error": str(e)}) await params.result_callback({"success": False, "error": str(e)})
asyncio.create_task(_reset()) asyncio.create_task(_reset())
@@ -161,7 +161,7 @@ tools = ToolsSchema(
) )
async def run_bot(webrtc_connection: SmallWebRTCConnection): async def run_bot(webrtc_connection: SmallWebRTCConnection, _: argparse.Namespace):
logger.info(f"Starting bot") logger.info(f"Starting bot")
transport = SmallWebRTCTransport( transport = SmallWebRTCTransport(
@@ -169,9 +169,7 @@ async def run_bot(webrtc_connection: SmallWebRTCConnection):
params=TransportParams( params=TransportParams(
audio_in_enabled=True, audio_in_enabled=True,
audio_out_enabled=True, audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)), vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)),
vad_audio_passthrough=True,
), ),
) )

View File

@@ -4,6 +4,7 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import argparse
import os import os
from datetime import datetime from datetime import datetime
@@ -19,6 +20,7 @@ from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.aws_nova_sonic import AWSNovaSonicLLMService from pipecat.services.aws_nova_sonic import AWSNovaSonicLLMService
from pipecat.services.llm_service import FunctionCallParams
from pipecat.transports.base_transport import TransportParams from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
@@ -27,13 +29,13 @@ from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(params: FunctionCallParams):
temperature = 75 if args["format"] == "fahrenheit" else 24 temperature = 75 if params.arguments["format"] == "fahrenheit" else 24
await result_callback( await params.result_callback(
{ {
"conditions": "nice", "conditions": "nice",
"temperature": temperature, "temperature": temperature,
"format": args["format"], "format": params.arguments["format"],
"timestamp": datetime.now().strftime("%Y%m%d_%H%M%S"), "timestamp": datetime.now().strftime("%Y%m%d_%H%M%S"),
} }
) )
@@ -60,7 +62,7 @@ weather_function = FunctionSchema(
tools = ToolsSchema(standard_tools=[weather_function]) tools = ToolsSchema(standard_tools=[weather_function])
async def run_bot(webrtc_connection: SmallWebRTCConnection): async def run_bot(webrtc_connection: SmallWebRTCConnection, _: argparse.Namespace):
logger.info(f"Starting bot") logger.info(f"Starting bot")
# Initialize the SmallWebRTCTransport with the connection # Initialize the SmallWebRTCTransport with the connection
@@ -71,8 +73,6 @@ async def run_bot(webrtc_connection: SmallWebRTCConnection):
audio_in_sample_rate=16000, audio_in_sample_rate=16000,
audio_out_enabled=True, audio_out_enabled=True,
camera_in_enabled=False, camera_in_enabled=False,
vad_enabled=True,
vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)), vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)),
), ),
) )