-
Notifications
You must be signed in to change notification settings - Fork 389
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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://<yourdomain>.daily.co/<room_url>` set in `DAILY_SAMPLE_ROOM_URL` and talk to studypal! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
pypdf==4.3.1 | ||
loguru | ||
pipecat-ai[daily,cartesia,openai,silero]==0.0.40 | ||
python-dotenv==1.0.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |