diff --git a/examples/foundational/40-aws-nova-sonic.py b/examples/foundational/40-aws-nova-sonic.py index ed329e281..0033fe6bb 100644 --- a/examples/foundational/40-aws-nova-sonic.py +++ b/examples/foundational/40-aws-nova-sonic.py @@ -91,14 +91,14 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): logger.info(f"Starting bot") # Specify initial system instruction. - # HACK: note that, for now, we need to inject a special bit of text into this instruction to - # allow the first assistant response to be programmatically triggered (which happens in the - # on_client_connected handler, below) system_instruction = ( "You are a friendly assistant. The user and you will engage in a spoken dialog exchanging " "the transcripts of a natural real-time conversation. Keep your responses short, generally " - "two or three sentences for chatty scenarios. " - f"{AWSNovaSonicLLMService.AWAIT_TRIGGER_ASSISTANT_RESPONSE_INSTRUCTION}" + "two or three sentences for chatty scenarios." + # HACK: if using the older Nova Sonic (pre-2) model, note that you need to inject a special + # bit of text into this instruction to allow the first assistant response to be + # programmatically triggered (which happens in the on_client_connected handler) + # f"{AWSNovaSonicLLMService.AWAIT_TRIGGER_ASSISTANT_RESPONSE_INSTRUCTION}" ) # Create the AWS Nova Sonic LLM service @@ -167,10 +167,10 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): logger.info(f"Client connected") # Kick off the conversation. await task.queue_frames([LLMRunFrame()]) - # HACK: for now, we need this special way of triggering the first assistant response in AWS - # Nova Sonic. Note that this trigger requires a special corresponding bit of text in the - # system instruction. In the future, simply queueing the context frame should be sufficient. - await llm.trigger_assistant_response() + # HACK: if using the older Nova Sonic (pre-2) model, you need this special way of + # triggering the first assistant response. Note that this trigger requires a special + # corresponding bit of text in the system instruction. + # await llm.trigger_assistant_response() # Handle client disconnection events @transport.event_handler("on_client_disconnected") diff --git a/src/pipecat/services/aws/nova_sonic/llm.py b/src/pipecat/services/aws/nova_sonic/llm.py index 641f126e5..25f32e819 100644 --- a/src/pipecat/services/aws/nova_sonic/llm.py +++ b/src/pipecat/services/aws/nova_sonic/llm.py @@ -618,10 +618,18 @@ class AWSNovaSonicLLMService(LLMService): ) return BedrockRuntimeClient(config=config) + def _is_first_generation_sonic_model(self) -> bool: + # Nova Sonic (the older model) is identified by "amazon.nova-sonic-v1:0" + return self._model == "amazon.nova-sonic-v1:0" + def _is_endpointing_sensitivity_supported(self) -> bool: # endpointing_sensitivity is only supported with Nova 2 Sonic (and, # presumably, future models) - return self._model != "amazon.nova-sonic-v1:0" + return not self._is_first_generation_sonic_model() + + def _is_assistant_response_trigger_needed(self) -> bool: + # Assistant response trigger audio is only needed with the older model + return self._is_first_generation_sonic_model() # # LLM communication: input events (pipecat -> LLM) @@ -1230,7 +1238,8 @@ class AWSNovaSonicLLMService(LLMService): ) # - # assistant response trigger (HACK) + # assistant response trigger + # HACK: only needed for the older Nova Sonic (as opposed to Nova 2 Sonic) model # # Class variable @@ -1244,12 +1253,17 @@ class AWSNovaSonicLLMService(LLMService): Sends a pre-recorded "ready" audio trigger to prompt the assistant to start speaking. This is useful for controlling conversation flow. - - Returns: - False if already triggering a response, True otherwise. """ + if not self._is_assistant_response_trigger_needed(): + logger.warning( + f"Assistant response trigger not needed for model '{self._model}'; skipping. " + "An LLMRunFrame() should be sufficient to prompt the assistant to respond, " + "assuming the context ends in a user message." + ) + return + if self._triggering_assistant_response: - return False + return self._triggering_assistant_response = True