From ee0a0db60934b1c57453db0c368d24eb42d5bd58 Mon Sep 17 00:00:00 2001 From: Afzal Ansari Date: Sun, 20 Oct 2024 16:36:27 +0000 Subject: [PATCH 1/3] Add a podcastai bot --- examples/podcast-chatbot/README.md | 24 ++++++ examples/podcast-chatbot/bot.py | 98 +++++++++++++++++++++++ examples/podcast-chatbot/env.example | 5 ++ examples/podcast-chatbot/requirements.txt | 4 + examples/podcast-chatbot/runner.py | 62 ++++++++++++++ 5 files changed, 193 insertions(+) create mode 100644 examples/podcast-chatbot/README.md create mode 100644 examples/podcast-chatbot/bot.py create mode 100644 examples/podcast-chatbot/env.example create mode 100644 examples/podcast-chatbot/requirements.txt create mode 100644 examples/podcast-chatbot/runner.py diff --git a/examples/podcast-chatbot/README.md b/examples/podcast-chatbot/README.md new file mode 100644 index 000000000..6b38381f2 --- /dev/null +++ b/examples/podcast-chatbot/README.md @@ -0,0 +1,24 @@ +# podcastai + +### Have a conversation about any article on the web + +podcastai is a fast conversational AI built using [Daily](https://www.daily.co/) for real-time media transport and [Cartesia](https://cartesia.ai) for text-to-speech. Everything is orchestrated together (VAD -> STT -> LLM -> TTS) using [Pipecat](https://www.pipecat.ai/). + +## Get started + +```python +python3 -m venv venv +source venv/bin/activate +pip install -r requirements.txt + +cp env.example .env # and add your credentials + +``` + +## Run the bot + +```bash +python bot.py +``` + +While the app is running, go to the `https://.daily.co/` set in `DAILY_SAMPLE_ROOM_URL` and talk to studypal! diff --git a/examples/podcast-chatbot/bot.py b/examples/podcast-chatbot/bot.py new file mode 100644 index 000000000..668ef1753 --- /dev/null +++ b/examples/podcast-chatbot/bot.py @@ -0,0 +1,98 @@ +import aiohttp +import asyncio +import os +import sys +from loguru import logger +from dotenv import load_dotenv + +from pipecat.vad.silero import SileroVADAnalyzer +from pipecat.frames.frames import LLMMessagesFrame +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 + +load_dotenv(override=True) + +# Run this script directly from your command line. +# This project was adapted from +# https://github.com/pipecat-ai/pipecat/blob/main/examples/foundational/07d-interruptible-cartesia.py + +logger.remove(0) +logger.add(sys.stderr, level="DEBUG") + + +# This is the main function that handles STT -> LLM -> TTS + + +async def main(): + async with aiohttp.ClientSession() as session: + (room_url, token) = await configure(session) + + transport = DailyTransport( + room_url, + token, + "Tech Podcast", + DailyParams( + audio_out_sample_rate=44100, + audio_out_enabled=True, + transcription_enabled=True, + vad_enabled=True, + vad_analyzer=SileroVADAnalyzer(), + ), + ) + + tts = CartesiaTTSService( + api_key=os.getenv("CARTESIA_API_KEY"), + voice_id=os.getenv("CARTESIA_VOICE_ID", "4d2fd738-3b3d-4368-957a-bb4805275bd9"), # British Narration Lady + sample_rate=44100, + ) + + llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4") + + messages = [ + { + "role": "system", + "content": "You are Keith, the podcast host. You will engage with the participants by asking about tech topics, keeping responses short, clear, and conversational." + } + ] + + context = OpenAILLMContext(messages) + context_aggregator = llm.create_context_aggregator(context) + + pipeline = Pipeline( + [ + transport.input(), + context_aggregator.user(), + llm, + tts, + transport.output(), + context_aggregator.assistant(), + ] + ) + + task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True, enable_metrics=True)) + + @transport.event_handler("on_first_participant_joined") + async def on_first_participant_joined(transport, participant): + transport.capture_participant_transcription(participant["id"]) + messages.append( + { + "role": "system", + "content": "Hey, You are Keith. Start introducing yourself and welcoming participants to the tech podcast! Ask them `What topic are you interested in today?`", + } + ) + await task.queue_frames([LLMMessagesFrame(messages)]) + + runner = PipelineRunner() + + await runner.run(task) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/examples/podcast-chatbot/env.example b/examples/podcast-chatbot/env.example new file mode 100644 index 000000000..69245a3d6 --- /dev/null +++ b/examples/podcast-chatbot/env.example @@ -0,0 +1,5 @@ +DAILY_SAMPLE_ROOM_URL= # Follow instructions here and put your https://YOURDOMAIN.daily.co/YOURROOM (Instructions: https://docs.pipecat.ai/quickstart#preparing-your-environment) +DAILY_API_KEY= # Create here: https://dashboard.daily.co/developers +OPENAI_API_KEY= # Create here: https://platform.openai.com/docs/overview +CARTESIA_API_KEY= # Create here: https://play.cartesia.ai/console +CARTESIA_VOICE_ID= # Find here: https://play.cartesia.ai/ \ No newline at end of file diff --git a/examples/podcast-chatbot/requirements.txt b/examples/podcast-chatbot/requirements.txt new file mode 100644 index 000000000..056caad29 --- /dev/null +++ b/examples/podcast-chatbot/requirements.txt @@ -0,0 +1,4 @@ +pypdf==4.3.1 +loguru +pipecat-ai[daily,cartesia,openai,silero]==0.0.40 +python-dotenv==1.0.1 diff --git a/examples/podcast-chatbot/runner.py b/examples/podcast-chatbot/runner.py new file mode 100644 index 000000000..13c4ff076 --- /dev/null +++ b/examples/podcast-chatbot/runner.py @@ -0,0 +1,62 @@ +# +# Copyright (c) 2024, Daily +# +# SPDX-License-Identifier: BSD 2-Clause License +# + +import aiohttp +import argparse +import os + +from pipecat.transports.services.helpers.daily_rest import DailyRESTHelper + + +async def configure(aiohttp_session: aiohttp.ClientSession): + (url, token, _) = await configure_with_args(aiohttp_session) + return (url, token) + + +async def configure_with_args( + aiohttp_session: aiohttp.ClientSession, parser: argparse.ArgumentParser | None = None +): + if not parser: + parser = argparse.ArgumentParser(description="Daily AI SDK Bot Sample") + parser.add_argument( + "-u", "--url", type=str, required=False, help="URL of the Daily room to join" + ) + parser.add_argument( + "-k", + "--apikey", + type=str, + required=False, + help="Daily API Key (needed to create an owner token for the room)", + ) + + args, unknown = parser.parse_known_args() + + url = args.url or os.getenv("DAILY_SAMPLE_ROOM_URL") + key = args.apikey or os.getenv("DAILY_API_KEY") + + if not url: + raise Exception( + "No Daily room specified. use the -u/--url option from the command line, or set DAILY_SAMPLE_ROOM_URL in your environment to specify a Daily room URL." + ) + + if not key: + raise Exception( + "No Daily API key specified. use the -k/--apikey option from the command line, or set DAILY_API_KEY in your environment to specify a Daily API key, available from https://dashboard.daily.co/developers." + ) + + daily_rest_helper = DailyRESTHelper( + daily_api_key=key, + daily_api_url=os.getenv("DAILY_API_URL", "https://api.daily.co/v1"), + aiohttp_session=aiohttp_session, + ) + + # Create a meeting token for the given room with an expiration 1 hour in + # the future. + expiry_time: float = 60 * 60 + + token = await daily_rest_helper.get_token(url, expiry_time) + + return (url, token, args) From 34207dabedae2e933e1f3bde0c8bcd32c1865b98 Mon Sep 17 00:00:00 2001 From: Afzal Ansari Date: Sun, 20 Oct 2024 19:51:28 +0000 Subject: [PATCH 2/3] upgraded the version --- examples/podcast-chatbot/bot.py | 6 ++++-- examples/podcast-chatbot/requirements.txt | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/podcast-chatbot/bot.py b/examples/podcast-chatbot/bot.py index 668ef1753..ee63b961d 100644 --- a/examples/podcast-chatbot/bot.py +++ b/examples/podcast-chatbot/bot.py @@ -5,7 +5,7 @@ from loguru import logger from dotenv import load_dotenv -from pipecat.vad.silero import SileroVADAnalyzer +from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.frames.frames import LLMMessagesFrame from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner @@ -50,7 +50,9 @@ async def main(): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), voice_id=os.getenv("CARTESIA_VOICE_ID", "4d2fd738-3b3d-4368-957a-bb4805275bd9"), # British Narration Lady - sample_rate=44100, + params=CartesiaTTSService.InputParams( + sample_rate=44100, + ), ) llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4") diff --git a/examples/podcast-chatbot/requirements.txt b/examples/podcast-chatbot/requirements.txt index 056caad29..13569f65c 100644 --- a/examples/podcast-chatbot/requirements.txt +++ b/examples/podcast-chatbot/requirements.txt @@ -1,4 +1,4 @@ pypdf==4.3.1 loguru -pipecat-ai[daily,cartesia,openai,silero]==0.0.40 +pipecat-ai[daily,cartesia,openai,silero]==0.0.46 python-dotenv==1.0.1 From 2ffc34ce3f6c94c7ef89d78042ccc20bcb415675 Mon Sep 17 00:00:00 2001 From: Afzal Ansari Date: Sun, 20 Oct 2024 19:57:34 +0000 Subject: [PATCH 3/3] updated the docs --- examples/podcast-chatbot/README.md | 4 ++-- examples/podcast-chatbot/bot.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/podcast-chatbot/README.md b/examples/podcast-chatbot/README.md index 6b38381f2..cac0764a7 100644 --- a/examples/podcast-chatbot/README.md +++ b/examples/podcast-chatbot/README.md @@ -1,6 +1,6 @@ # podcastai -### Have a conversation about any article on the web +### Have a conversation about any technology topics podcastai is a fast conversational AI built using [Daily](https://www.daily.co/) for real-time media transport and [Cartesia](https://cartesia.ai) for text-to-speech. Everything is orchestrated together (VAD -> STT -> LLM -> TTS) using [Pipecat](https://www.pipecat.ai/). @@ -21,4 +21,4 @@ cp env.example .env # and add your credentials python bot.py ``` -While the app is running, go to the `https://.daily.co/` set in `DAILY_SAMPLE_ROOM_URL` and talk to studypal! +While the app is running, go to the `https://.daily.co/` set in `DAILY_SAMPLE_ROOM_URL` and talk to podcaster! diff --git a/examples/podcast-chatbot/bot.py b/examples/podcast-chatbot/bot.py index ee63b961d..228730572 100644 --- a/examples/podcast-chatbot/bot.py +++ b/examples/podcast-chatbot/bot.py @@ -60,7 +60,7 @@ async def main(): messages = [ { "role": "system", - "content": "You are Keith, the podcast host. You will engage with the participants by asking about tech topics, keeping responses short, clear, and conversational." + "content": "You are an AI assistant, the podcast host. You will engage with the participants by asking about tech topics, keeping responses short, clear, and conversational." } ]