From a9ef5ca95d1d36e8d6ed09a0ec72ca821ab6d683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Thu, 31 Oct 2024 15:47:32 -0700 Subject: [PATCH] examples: add bot background sound example --- CHANGELOG.md | 4 +- .../foundational/23-bot-background-sound.py | 121 ++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 examples/foundational/23-bot-background-sound.py diff --git a/CHANGELOG.md b/CHANGELOG.md index dd56eb011..eb344aa45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,7 +61,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Other -- Added a new foundational example 22-natural-conversation.py. This examples +- Add `23-bot-background-sound.py` foundational example. + +- Added a new foundational example `22-natural-conversation.py`. This example shows how to achieve a more natural conversation detecting when the user ends statement. diff --git a/examples/foundational/23-bot-background-sound.py b/examples/foundational/23-bot-background-sound.py new file mode 100644 index 000000000..68dd700d5 --- /dev/null +++ b/examples/foundational/23-bot-background-sound.py @@ -0,0 +1,121 @@ +# +# Copyright (c) 2024, Daily +# +# SPDX-License-Identifier: BSD 2-Clause License +# + +import argparse +import asyncio +import aiohttp +import os +import sys + +from pipecat.audio.mixers.soundfile_mixer import SoundfileMixer +from pipecat.audio.vad.silero import SileroVADAnalyzer +from pipecat.frames.frames import LLMMessagesFrame, MixerUpdateSettingsFrame, MixerEnableFrame +from pipecat.pipeline.pipeline import Pipeline +from pipecat.pipeline.runner import PipelineRunner +from pipecat.pipeline.task import PipelineParams, PipelineTask +from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext +from pipecat.services.cartesia import CartesiaTTSService +from pipecat.services.openai import OpenAILLMService +from pipecat.transports.services.daily import DailyParams, DailyTransport + +from runner import configure_with_args + +from loguru import logger + +from dotenv import load_dotenv + +load_dotenv(override=True) + +logger.remove(0) +logger.add(sys.stderr, level="DEBUG") + + +async def main(): + async with aiohttp.ClientSession() as session: + parser = argparse.ArgumentParser(description="Bot Background Sound") + parser.add_argument("-i", "--input", type=str, required=True, help="Input audio file") + + (room_url, token, args) = await configure_with_args(session, parser) + + soundfile_mixer = SoundfileMixer( + sound_files={"office": args.input}, + default_sound="office", + volume=2.0, + ) + + transport = DailyTransport( + room_url, + token, + "Respond bot", + DailyParams( + audio_out_enabled=True, + audio_out_mixer=soundfile_mixer, + transcription_enabled=True, + vad_enabled=True, + vad_analyzer=SileroVADAnalyzer(), + ), + ) + + tts = CartesiaTTSService( + api_key=os.getenv("CARTESIA_API_KEY"), + voice_id="79a125e8-cd45-4c13-8a67-188112f4dd22", # British Lady + ) + + llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") + + messages = [ + { + "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.", + }, + ] + + context = OpenAILLMContext(messages) + context_aggregator = llm.create_context_aggregator(context) + + pipeline = Pipeline( + [ + transport.input(), # Transport user input + context_aggregator.user(), # User responses + llm, # LLM + tts, # TTS + transport.output(), # Transport bot output + context_aggregator.assistant(), # Assistant spoken responses + ] + ) + + task = PipelineTask( + pipeline, + PipelineParams( + allow_interruptions=True, + enable_metrics=True, + enable_usage_metrics=True, + report_only_initial_ttfb=True, + ), + ) + + @transport.event_handler("on_first_participant_joined") + async def on_first_participant_joined(transport, participant): + await transport.capture_participant_transcription(participant["id"]) + # Show how to use mixer control frames. + await asyncio.sleep(10.0) + await task.queue_frame(MixerUpdateSettingsFrame({"volume": 0.5})) + await asyncio.sleep(5.0) + await task.queue_frame(MixerEnableFrame(False)) + await asyncio.sleep(5.0) + await task.queue_frame(MixerEnableFrame(True)) + await asyncio.sleep(5.0) + # Kick off the conversation. + messages.append({"role": "system", "content": "Please introduce yourself to the user."}) + await task.queue_frames([LLMMessagesFrame(messages)]) + + runner = PipelineRunner() + + await runner.run(task) + + +if __name__ == "__main__": + asyncio.run(main())