Updating foundation examples to use SmallWebRTCTransport and pipecat-ai-small-webrtc-prebuilt (#1534)

Co-authored-by: Filipi Fuchter <filipi@daily.co>
This commit is contained in:
Mark Backman
2025-04-11 19:44:16 -04:00
committed by GitHub
parent 8186219879
commit f6accbd510
120 changed files with 7989 additions and 7179 deletions

View File

@@ -4,54 +4,54 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import EndFrame, TTSSpeakFrame from pipecat.frames.frames import EndFrame, TTSSpeakFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineTask
from pipecat.services.piper.tts import PiperTTSService from pipecat.services.piper.tts import PiperTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): # Create a transport using the WebRTC connection
transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_out_enabled=True,
),
)
# Create an HTTP session
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
(room_url, _) = await configure(session)
transport = DailyTransport(
room_url, None, "Say One Thing", DailyParams(audio_out_enabled=True)
)
tts = PiperTTSService( tts = PiperTTSService(
base_url=os.getenv("PIPER_BASE_URL"), aiohttp_session=session, sample_rate=24000 base_url=os.getenv("PIPER_BASE_URL"), aiohttp_session=session, sample_rate=24000
) )
runner = PipelineRunner()
task = PipelineTask(Pipeline([tts, transport.output()])) task = PipelineTask(Pipeline([tts, transport.output()]))
# Register an event handler so we can play the audio when the # Register an event handler so we can play the audio when the client joins
# participant joins. @transport.event_handler("on_client_connected")
@transport.event_handler("on_first_participant_joined") async def on_client_connected(transport, client):
async def on_first_participant_joined(transport, participant): await task.queue_frames([TTSSpeakFrame(f"Hello there!"), EndFrame()])
await task.queue_frames(
[TTSSpeakFrame(f"Hello there, how are you today ?"), EndFrame()] runner = PipelineRunner(handle_sigint=False)
)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -0,0 +1,59 @@
#
# Copyright (c) 20242025, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
import os
import aiohttp
from dotenv import load_dotenv
from loguru import logger
from pipecat.frames.frames import EndFrame, TTSSpeakFrame
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask
from pipecat.services.rime.tts import RimeHttpTTSService
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True)
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
# Create a transport using the WebRTC connection
transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_out_enabled=True,
),
)
# Create an HTTP session
async with aiohttp.ClientSession() as session:
tts = RimeHttpTTSService(
api_key=os.getenv("RIME_API_KEY", ""),
voice_id="rex",
aiohttp_session=session,
)
task = PipelineTask(Pipeline([tts, transport.output()]))
# Register an event handler so we can play the audio when the client joins
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
await task.queue_frames([TTSSpeakFrame(f"Hello there!"), EndFrame()])
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__":
from run import main
main()

View File

@@ -4,56 +4,52 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import EndFrame, TTSSpeakFrame from pipecat.frames.frames import EndFrame, TTSSpeakFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineTask
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): # Create a transport using the WebRTC connection
async with aiohttp.ClientSession() as session: transport = SmallWebRTCTransport(
(room_url, _) = await configure(session) webrtc_connection=webrtc_connection,
params=TransportParams(
audio_out_enabled=True,
),
)
transport = DailyTransport( tts = CartesiaTTSService(
room_url, None, "Say One Thing", DailyParams(audio_out_enabled=True) api_key=os.getenv("CARTESIA_API_KEY"),
) voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
tts = CartesiaTTSService( task = PipelineTask(Pipeline([tts, transport.output()]))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
runner = PipelineRunner() # Register an event handler so we can play the audio when the client joins
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
await task.queue_frames([TTSSpeakFrame(f"Hello there!"), EndFrame()])
task = PipelineTask(Pipeline([tts, transport.output()])) runner = PipelineRunner(handle_sigint=False)
# Register an event handler so we can play the audio when the await runner.run(task)
# participant joins.
@transport.event_handler("on_first_participant_joined")
async def on_first_participant_joined(transport, participant):
participant_name = participant.get("info", {}).get("userName", "")
await task.queue_frames(
[TTSSpeakFrame(f"Hello there, {participant_name}!"), EndFrame()]
)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,51 +4,49 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import EndFrame, TTSSpeakFrame from pipecat.frames.frames import EndFrame, TTSSpeakFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineTask
from pipecat.services.riva.tts import FastPitchTTSService from pipecat.services.riva.tts import FastPitchTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): # Create a transport using the WebRTC connection
async with aiohttp.ClientSession() as session: transport = SmallWebRTCTransport(
(room_url, _) = await configure(session) webrtc_connection=webrtc_connection,
params=TransportParams(
audio_out_enabled=True,
),
)
transport = DailyTransport( tts = FastPitchTTSService(api_key=os.getenv("NVIDIA_API_KEY"))
room_url, None, "Say One Thing", DailyParams(audio_out_enabled=True)
)
tts = FastPitchTTSService(api_key=os.getenv("NVIDIA_API_KEY")) task = PipelineTask(Pipeline([tts, transport.output()]))
runner = PipelineRunner() # Register an event handler so we can play the audio when the client joins
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
await task.queue_frames([TTSSpeakFrame(f"Hello there!"), EndFrame()])
task = PipelineTask(Pipeline([tts, transport.output()])) runner = PipelineRunner(handle_sigint=False)
# Register an event handler so we can play the audio when the await runner.run(task)
# participant joins.
@transport.event_handler("on_first_participant_joined")
async def on_first_participant_joined(transport, participant):
participant_name = participant.get("info", {}).get("userName", "")
await task.queue_frames([TTSSpeakFrame(f"Aloha, {participant_name}!"), EndFrame()])
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import EndFrame, LLMMessagesFrame from pipecat.frames.frames import EndFrame, LLMMessagesFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -19,46 +15,51 @@ from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineTask
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): # Create a transport using the WebRTC connection
async with aiohttp.ClientSession() as session: transport = SmallWebRTCTransport(
(room_url, _) = await configure(session) webrtc_connection=webrtc_connection,
params=TransportParams(
audio_out_enabled=True,
),
)
transport = DailyTransport( tts = CartesiaTTSService(
room_url, None, "Say One Thing From an LLM", DailyParams(audio_out_enabled=True) api_key=os.getenv("CARTESIA_API_KEY"),
) voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
tts = CartesiaTTSService( llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") messages = [
{
"role": "system",
"content": "You are an LLM in a WebRTC session, and this is a 'hello world' demo. Say hello to the world.",
}
]
messages = [ task = PipelineTask(Pipeline([llm, tts, transport.output()]))
{
"role": "system",
"content": "You are an LLM in a WebRTC session, and this is a 'hello world' demo. Say hello to the world.",
}
]
runner = PipelineRunner() # Register an event handler so we can play the audio when the client joins
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
await task.queue_frames([LLMMessagesFrame(messages), EndFrame()])
task = PipelineTask(Pipeline([llm, tts, transport.output()])) runner = PipelineRunner(handle_sigint=False)
@transport.event_handler("on_first_participant_joined") await runner.run(task)
async def on_first_participant_joined(transport, participant):
await task.queue_frames([LLMMessagesFrame(messages), EndFrame()])
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,59 +4,67 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import TextFrame from pipecat.frames.frames import TextFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineTask
from pipecat.services.fal.image import FalImageGenService from pipecat.services.fal.image import FalImageGenService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): # Create a transport using the WebRTC connection
transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
camera_out_enabled=True,
camera_out_width=1024,
camera_out_height=1024,
),
)
# Create an HTTP session
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
(room_url, _) = await configure(session)
transport = DailyTransport(
room_url,
None,
"Show a still frame image",
DailyParams(camera_out_enabled=True, camera_out_width=1024, camera_out_height=1024),
)
imagegen = FalImageGenService( imagegen = FalImageGenService(
params=FalImageGenService.InputParams(image_size="square_hd"), params=FalImageGenService.InputParams(image_size="square_hd"),
aiohttp_session=session, aiohttp_session=session,
key=os.getenv("FAL_KEY"), key=os.getenv("FAL_KEY"),
) )
runner = PipelineRunner()
task = PipelineTask(Pipeline([imagegen, transport.output()])) task = PipelineTask(Pipeline([imagegen, transport.output()]))
@transport.event_handler("on_first_participant_joined") # Register an event handler so we can play the audio when the client joins
async def on_first_participant_joined(transport, participant): @transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
await task.queue_frame(TextFrame("a cat in the style of picasso")) await task.queue_frame(TextFrame("a cat in the style of picasso"))
@transport.event_handler("on_participant_left") @transport.event_handler("on_client_disconnected")
async def on_participant_left(transport, participant, reason): async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel() await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,62 +4,67 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import EndFrame, TextFrame from pipecat.frames.frames import TextFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.services.google.image import GoogleImageGenService from pipecat.services.google.image import GoogleImageGenService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): # Create a transport using the WebRTC connection
async with aiohttp.ClientSession() as session: transport = SmallWebRTCTransport(
(room_url, _) = await configure(session) webrtc_connection=webrtc_connection,
params=TransportParams(
camera_out_enabled=True,
camera_out_width=1024,
camera_out_height=1024,
),
)
transport = DailyTransport( imagegen = GoogleImageGenService(
room_url, api_key=os.getenv("GOOGLE_API_KEY"),
None, )
"Show a still frame image",
DailyParams(camera_out_enabled=True, camera_out_width=1024, camera_out_height=1024),
)
imagegen = GoogleImageGenService( task = PipelineTask(
api_key=os.getenv("GOOGLE_API_KEY"), Pipeline([imagegen, transport.output()]),
) params=PipelineParams(enable_metrics=True),
)
runner = PipelineRunner() # Register an event handler so we can play the audio when the client joins
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
await task.queue_frame(TextFrame("a cat in the style of picasso"))
await task.queue_frame(TextFrame("a dog in the style of picasso"))
await task.queue_frame(TextFrame("a fish in the style of picasso"))
task = PipelineTask( @transport.event_handler("on_client_disconnected")
Pipeline([imagegen, transport.output()]), async def on_client_disconnected(transport, client):
params=PipelineParams(enable_metrics=True), logger.info(f"Client disconnected")
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await task.queue_frame(TextFrame("a cat in the style of picasso")) logger.info(f"Client closed connection")
await task.queue_frame(TextFrame("a dog in the style of picasso")) await task.cancel()
await task.queue_frame(TextFrame("a fish in the style of picasso"))
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.queue_frame(EndFrame())
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -13,9 +13,9 @@ import os
import sys import sys
import aiohttp import aiohttp
from daily_runner import configure
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import EndPipeFrame, LLMMessagesFrame, TextFrame from pipecat.frames.frames import EndPipeFrame, LLMMessagesFrame, TextFrame
from pipecat.pipeline.merge_pipeline import SequentialMergePipeline from pipecat.pipeline.merge_pipeline import SequentialMergePipeline

View File

@@ -4,15 +4,12 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
from dataclasses import dataclass from dataclasses import dataclass
import aiohttp import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import ( from pipecat.frames.frames import (
DataFrame, DataFrame,
@@ -30,13 +27,12 @@ from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.services.cartesia.tts import CartesiaHttpTTSService from pipecat.services.cartesia.tts import CartesiaHttpTTSService
from pipecat.services.fal.image import FalImageGenService from pipecat.services.fal.image import FalImageGenService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
@dataclass @dataclass
class MonthFrame(DataFrame): class MonthFrame(DataFrame):
@@ -67,22 +63,28 @@ class MonthPrepender(FrameProcessor):
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
"""Run the Calendar Month Narration bot using WebRTC transport.
Args:
webrtc_connection: The WebRTC connection to use
room_name: Optional room name for display purposes
"""
logger.info(f"Starting bot")
# Create a transport using the WebRTC connection
transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_out_enabled=True,
camera_out_enabled=True,
camera_out_width=1024,
camera_out_height=1024,
),
)
# Create an HTTP session for API calls
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
(room_url, _) = await configure(session)
transport = DailyTransport(
room_url,
None,
"Month Narration Bot",
DailyParams(
audio_out_enabled=True,
camera_out_enabled=True,
camera_out_width=1024,
camera_out_height=1024,
),
)
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
tts = CartesiaHttpTTSService( tts = CartesiaHttpTTSService(
@@ -144,14 +146,30 @@ async def main():
frames.append(MonthFrame(month=month)) frames.append(MonthFrame(month=month))
frames.append(LLMMessagesFrame(messages)) frames.append(LLMMessagesFrame(messages))
runner = PipelineRunner()
task = PipelineTask(pipeline) task = PipelineTask(pipeline)
await task.queue_frames(frames) # Set up transport event handlers
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Start the month narration once connected
await task.queue_frames(frames)
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
# Run the pipeline
runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import Frame, MetricsFrame from pipecat.frames.frames import Frame, MetricsFrame
@@ -27,14 +23,14 @@ 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.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
class MetricsLogger(FrameProcessor): class MetricsLogger(FrameProcessor):
async def process_frame(self, frame: Frame, direction: FrameDirection): async def process_frame(self, frame: Frame, direction: FrameDirection):
@@ -56,76 +52,83 @@ class MetricsLogger(FrameProcessor):
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
ml = MetricsLogger() llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
messages = [ ml = MetricsLogger()
{
"role": "system", messages = [
"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.", {
}, "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(),
stt,
context_aggregator.user(),
llm,
tts,
ml,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
enable_metrics=True,
enable_usage_metrics=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, messages.append({"role": "system", "content": "Please introduce yourself to the user."})
tts, await task.queue_frames([context_aggregator.user().get_context_frame()])
ml,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason): await runner.run(task)
await task.cancel()
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,15 +4,11 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from PIL import Image from PIL import Image
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import ( from pipecat.frames.frames import (
@@ -20,7 +16,6 @@ from pipecat.frames.frames import (
BotStoppedSpeakingFrame, BotStoppedSpeakingFrame,
Frame, Frame,
OutputImageRawFrame, OutputImageRawFrame,
TextFrame,
) )
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
@@ -28,14 +23,14 @@ 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.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
class ImageSyncAggregator(FrameProcessor): class ImageSyncAggregator(FrameProcessor):
def __init__(self, speaking_path: str, waiting_path: str): def __init__(self, speaking_path: str, waiting_path: str):
@@ -72,83 +67,90 @@ class ImageSyncAggregator(FrameProcessor):
await self.push_frame(frame) await self.push_frame(frame)
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, camera_out_enabled=True,
camera_out_enabled=True, camera_out_width=1024,
camera_out_width=1024, camera_out_height=1024,
camera_out_height=1024, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
messages = [ llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
{
"role": "system", messages = [
"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.", {
}, "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)
image_sync_aggregator = ImageSyncAggregator(
os.path.join(os.path.dirname(__file__), "assets", "speaking.png"),
os.path.join(os.path.dirname(__file__), "assets", "waiting.png"),
)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
image_sync_aggregator,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
image_sync_aggregator = ImageSyncAggregator( @transport.event_handler("on_client_connected")
os.path.join(os.path.dirname(__file__), "assets", "speaking.png"), async def on_client_connected(transport, client):
os.path.join(os.path.dirname(__file__), "assets", "waiting.png"), logger.info(f"Client connected")
) # Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()])
pipeline = Pipeline( @transport.event_handler("on_client_disconnected")
[ async def on_client_disconnected(transport, client):
transport.input(), logger.info(f"Client disconnected")
context_aggregator.user(),
llm,
tts,
image_sync_aggregator,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_closed")
pipeline, async def on_client_closed(transport, client):
params=PipelineParams( logger.info(f"Client closed connection")
allow_interruptions=True, await task.cancel()
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") runner = PipelineRunner(handle_sigint=False)
async def on_first_participant_joined(transport, participant): await runner.run(task)
participant_name = participant.get("info", {}).get("userName", "")
await transport.capture_participant_transcription(participant["id"])
await task.queue_frames([TextFrame(f"Hi there {participant_name}!")])
@transport.event_handler("on_participant_left")
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -1,104 +0,0 @@
#
# Copyright (c) 20242025, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
import asyncio
import os
import sys
import aiohttp
from dotenv import load_dotenv
from loguru import logger
from runner import configure
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.processors.audio.vad.silero import SileroVAD
from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport
load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def main():
async with aiohttp.ClientSession() as session:
(room_url, token) = await configure(session)
transport = DailyTransport(
room_url,
token,
"Respond bot",
DailyParams(
audio_in_enabled=True,
audio_out_enabled=True,
transcription_enabled=True,
),
)
vad = SileroVAD()
tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading 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(),
vad,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask(
pipeline,
params=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"])
# Kick off the conversation.
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left")
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -19,84 +15,92 @@ 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.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = CartesiaTTSService( tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
) )
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
messages = [ messages = [
{ {
"role": "system", "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.", "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
stt,
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
context_aggregator.user(), # User responses # Kick off the conversation.
llm, # LLM messages.append({"role": "system", "content": "Please introduce yourself to the user."})
tts, # TTS await task.queue_frames([context_aggregator.user().get_context_frame()])
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -1,106 +0,0 @@
#
# Copyright (c) 20242025, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
import asyncio
import os
import sys
import aiohttp
from dotenv import load_dotenv
from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer
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.anthropic.llm import AnthropicLLMService
from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport
load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def main():
async with aiohttp.ClientSession() as session:
(room_url, token) = await configure(session)
transport = DailyTransport(
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = AnthropicLLMService(
api_key=os.getenv("ANTHROPIC_API_KEY"), model="claude-3-opus-20240229"
)
# todo: think more about how to handle system prompts in a more general way. OpenAI,
# Google, and Anthropic all have slightly different approaches to providing a system
# prompt.
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, helpful, and brief way. Say hello.",
},
]
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,
params=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"])
# Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left")
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -0,0 +1,106 @@
#
# Copyright (c) 20242025, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
import os
from dotenv import load_dotenv
from loguru import logger
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.processors.audio.vad.silero import SileroVAD
from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True)
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
),
)
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
vad = SileroVAD()
tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading 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(),
stt,
vad,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask(
pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Kick off the conversation.
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__":
from run import main
main()

View File

@@ -4,11 +4,8 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_community.chat_message_histories import ChatMessageHistory from langchain_community.chat_message_histories import ChatMessageHistory
@@ -16,7 +13,6 @@ from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI from langchain_openai import ChatOpenAI
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import LLMMessagesFrame from pipecat.frames.frames import LLMMessagesFrame
@@ -29,14 +25,14 @@ from pipecat.processors.aggregators.llm_response import (
) )
from pipecat.processors.frameworks.langchain import LangchainProcessor from pipecat.processors.frameworks.langchain import LangchainProcessor
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
message_store = {} message_store = {}
@@ -46,90 +42,97 @@ def get_session_history(session_id: str) -> BaseChatMessageHistory:
return message_store[session_id] return message_store[session_id]
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
)
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"Be nice and helpful. Answer very briefly and without special characters like `#` or `*`. "
"Your response will be synthesized to voice and those characters will create unnatural sounds.",
), ),
) MessagesPlaceholder("chat_history"),
("human", "{input}"),
]
)
chain = prompt | ChatOpenAI(model="gpt-4o", temperature=0.7)
history_chain = RunnableWithMessageHistory(
chain,
get_session_history,
history_messages_key="chat_history",
input_messages_key="input",
)
lc = LangchainProcessor(history_chain)
tts = CartesiaTTSService( tma_in = LLMUserResponseAggregator()
api_key=os.getenv("CARTESIA_API_KEY"), tma_out = LLMAssistantResponseAggregator()
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
prompt = ChatPromptTemplate.from_messages( pipeline = Pipeline(
[ [
( transport.input(), # Transport user input
"system", stt,
"Be nice and helpful. Answer very briefly and without special characters like `#` or `*`. " tma_in, # User responses
"Your response will be synthesized to voice and those characters will create unnatural sounds.", lc, # Langchain
), tts, # TTS
MessagesPlaceholder("chat_history"), transport.output(), # Transport bot output
("human", "{input}"), tma_out, # Assistant spoken responses
] ]
) )
chain = prompt | ChatOpenAI(model="gpt-4o", temperature=0.7)
history_chain = RunnableWithMessageHistory(
chain,
get_session_history,
history_messages_key="chat_history",
input_messages_key="input",
)
lc = LangchainProcessor(history_chain)
tma_in = LLMUserResponseAggregator() task = PipelineTask(
tma_out = LLMAssistantResponseAggregator() pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
tma_in, # User responses # Kick off the conversation.
lc, # Langchain # the `LLMMessagesFrame` will be picked up by the LangchainProcessor using
tts, # TTS # only the content of the last message to inject it in the prompt defined
transport.output(), # Transport bot output # above. So no role is required here.
tma_out, # Assistant spoken responses messages = [({"content": "Please briefly introduce yourself to the user."})]
] await task.queue_frames([LLMMessagesFrame(messages)])
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
lc.set_participant_id(participant["id"]) await task.cancel()
# Kick off the conversation.
# the `LLMMessagesFrame` will be picked up by the LangchainProcessor using
# only the content of the last message to inject it in the prompt defined
# above. So no role is required here.
messages = [({"content": "Please briefly introduce yourself to the user."})]
await task.queue_frames([LLMMessagesFrame(messages)])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,15 +4,11 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from deepgram import LiveOptions from deepgram import LiveOptions
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import ( from pipecat.frames.frames import (
BotInterruptionFrame, BotInterruptionFrame,
@@ -27,91 +23,95 @@ from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.deepgram.tts import DeepgramTTSService from pipecat.services.deepgram.tts import DeepgramTTSService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, _) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(
room_url, api_key=os.getenv("DEEPGRAM_API_KEY"),
None, live_options=LiveOptions(vad_events=True, utterance_end_ms="1000"),
"Respond bot", )
DailyParams(
audio_in_enabled=True,
audio_out_enabled=True,
),
)
stt = DeepgramSTTService( tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en")
api_key=os.getenv("DEEPGRAM_API_KEY"),
live_options=LiveOptions(vad_events=True, utterance_end_ms="1000"),
)
tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
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.",
},
]
messages = [ context = OpenAILLMContext(messages)
{ context_aggregator = llm.create_context_aggregator(context)
"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.", pipeline = Pipeline(
}, [
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @stt.event_handler("on_speech_started")
[ async def on_speech_started(stt, *args, **kwargs):
transport.input(), # Transport user input await task.queue_frames([BotInterruptionFrame(), UserStartedSpeakingFrame()])
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @stt.event_handler("on_utterance_end")
pipeline, async def on_utterance_end(stt, *args, **kwargs):
params=PipelineParams( await task.queue_frames([StopInterruptionFrame(), UserStoppedSpeakingFrame()])
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@stt.event_handler("on_speech_started") @transport.event_handler("on_client_connected")
async def on_speech_started(stt, *args, **kwargs): async def on_client_connected(transport, client):
await task.queue_frames([BotInterruptionFrame(), UserStartedSpeakingFrame()]) logger.info(f"Client connected")
# Kick off the conversation.
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@stt.event_handler("on_utterance_end") @transport.event_handler("on_client_disconnected")
async def on_utterance_end(stt, *args, **kwargs): async def on_client_disconnected(transport, client):
await task.queue_frames([StopInterruptionFrame(), UserStoppedSpeakingFrame()]) logger.info(f"Client disconnected")
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
# Kick off the conversation. logger.info(f"Client closed connection")
messages.append({"role": "system", "content": "Please introduce yourself to the user."}) await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -21,82 +17,87 @@ from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.deepgram.tts import DeepgramTTSService from pipecat.services.deepgram.tts import DeepgramTTSService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, _) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
None,
"Respond bot",
DailyParams(
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en")
tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
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.",
},
]
messages = [ context = OpenAILLMContext(messages)
{ context_aggregator = llm.create_context_aggregator(context)
"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.", pipeline = Pipeline(
}, [
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
stt, # STT # Kick off the conversation.
context_aggregator.user(), # User responses messages.append({"role": "system", "content": "Please introduce yourself to the user."})
llm, # LLM await task.queue_frames([context_aggregator.user().get_context_frame()])
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
# Kick off the conversation. logger.info(f"Client closed connection")
messages.append({"role": "system", "content": "Please introduce yourself to the user."}) await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,45 +4,44 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.elevenlabs.tts import ElevenLabsHttpTTSService from pipecat.services.elevenlabs.tts import ElevenLabsHttpTTSService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
# Create an HTTP session
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
(room_url, token) = await configure(session) stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
transport = DailyTransport(
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = ElevenLabsHttpTTSService( tts = ElevenLabsHttpTTSService(
api_key=os.getenv("ELEVENLABS_API_KEY", ""), api_key=os.getenv("ELEVENLABS_API_KEY", ""),
@@ -65,6 +64,7 @@ async def main():
pipeline = Pipeline( pipeline = Pipeline(
[ [
transport.input(), # Transport user input transport.input(), # Transport user input
stt,
context_aggregator.user(), # User responses context_aggregator.user(), # User responses
llm, # LLM llm, # LLM
tts, # TTS tts, # TTS
@@ -83,21 +83,28 @@ async def main():
), ),
) )
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_connected")
async def on_first_participant_joined(transport, participant): async def on_client_connected(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client connected")
# Kick off the conversation. # Kick off the conversation.
messages.append({"role": "system", "content": "Please introduce yourself to the user."}) messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()]) await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") @transport.event_handler("on_client_disconnected")
async def on_participant_left(transport, participant, reason): async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel() await task.cancel()
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,99 +4,103 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.elevenlabs.tts import ElevenLabsTTSService from pipecat.services.elevenlabs.tts import ElevenLabsTTSService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = ElevenLabsTTSService( tts = ElevenLabsTTSService(
api_key=os.getenv("ELEVENLABS_API_KEY", ""), api_key=os.getenv("ELEVENLABS_API_KEY", ""),
voice_id=os.getenv("ELEVENLABS_VOICE_ID", ""), voice_id=os.getenv("ELEVENLABS_VOICE_ID", ""),
) )
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
messages = [ messages = [
{ {
"role": "system", "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.", "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
stt,
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
context_aggregator.user(), # User responses # Kick off the conversation.
llm, # LLM messages.append({"role": "system", "content": "Please introduce yourself to the user."})
tts, # TTS await task.queue_frames([context_aggregator.user().get_context_frame()])
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,100 +4,104 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.services.playht.tts import PlayHTHttpTTSService from pipecat.services.playht.tts import PlayHTHttpTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = PlayHTHttpTTSService( tts = PlayHTHttpTTSService(
user_id=os.getenv("PLAYHT_USER_ID"), user_id=os.getenv("PLAYHT_USER_ID"),
api_key=os.getenv("PLAYHT_API_KEY"), api_key=os.getenv("PLAYHT_API_KEY"),
voice_url="s3://voice-cloning-zero-shot/d9ff78ba-d016-47f6-b0ef-dd630f59414e/female-cs/manifest.json", voice_url="s3://voice-cloning-zero-shot/d9ff78ba-d016-47f6-b0ef-dd630f59414e/female-cs/manifest.json",
) )
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
messages = [ messages = [
{ {
"role": "system", "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.", "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
stt,
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
context_aggregator.user(), # User responses # Kick off the conversation.
llm, # LLM messages.append({"role": "system", "content": "Please introduce yourself to the user."})
tts, # TTS await task.queue_frames([context_aggregator.user().get_context_frame()])
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,102 +4,106 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.services.playht.tts import PlayHTTTSService from pipecat.services.playht.tts import PlayHTTTSService
from pipecat.transcriptions.language import Language from pipecat.transcriptions.language import Language
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = PlayHTTTSService( tts = PlayHTTTSService(
user_id=os.getenv("PLAYHT_USER_ID"), user_id=os.getenv("PLAYHT_USER_ID"),
api_key=os.getenv("PLAYHT_API_KEY"), api_key=os.getenv("PLAYHT_API_KEY"),
voice_url="s3://voice-cloning-zero-shot/e46b4027-b38d-4d24-b292-38fbca2be0ef/original/manifest.json", voice_url="s3://voice-cloning-zero-shot/e46b4027-b38d-4d24-b292-38fbca2be0ef/original/manifest.json",
params=PlayHTTTSService.InputParams(language=Language.EN), params=PlayHTTTSService.InputParams(language=Language.EN),
) )
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
messages = [ messages = [
{ {
"role": "system", "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.", "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
stt,
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
context_aggregator.user(), # User responses # Kick off the conversation.
llm, # LLM messages.append({"role": "system", "content": "Please introduce yourself to the user."})
tts, # TTS await task.queue_frames([context_aggregator.user().get_context_frame()])
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -21,93 +17,97 @@ from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.azure.llm import AzureLLMService from pipecat.services.azure.llm import AzureLLMService
from pipecat.services.azure.stt import AzureSTTService from pipecat.services.azure.stt import AzureSTTService
from pipecat.services.azure.tts import AzureTTSService from pipecat.services.azure.tts import AzureTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = AzureSTTService(
room_url, api_key=os.getenv("AZURE_SPEECH_API_KEY"),
token, region=os.getenv("AZURE_SPEECH_REGION"),
"Respond bot", )
DailyParams(
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
stt = AzureSTTService( tts = AzureTTSService(
api_key=os.getenv("AZURE_SPEECH_API_KEY"), api_key=os.getenv("AZURE_SPEECH_API_KEY"),
region=os.getenv("AZURE_SPEECH_REGION"), region=os.getenv("AZURE_SPEECH_REGION"),
) )
tts = AzureTTSService( llm = AzureLLMService(
api_key=os.getenv("AZURE_SPEECH_API_KEY"), api_key=os.getenv("AZURE_CHATGPT_API_KEY"),
region=os.getenv("AZURE_SPEECH_REGION"), endpoint=os.getenv("AZURE_CHATGPT_ENDPOINT"),
) model=os.getenv("AZURE_CHATGPT_MODEL"),
)
llm = AzureLLMService( messages = [
api_key=os.getenv("AZURE_CHATGPT_API_KEY"), {
endpoint=os.getenv("AZURE_CHATGPT_ENDPOINT"), "role": "system",
model=os.getenv("AZURE_CHATGPT_MODEL"), "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.",
) },
]
messages = [ context = OpenAILLMContext(messages)
{ context_aggregator = llm.create_context_aggregator(context)
"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.", pipeline = Pipeline(
}, [
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
stt, # STT # Kick off the conversation.
context_aggregator.user(), # User responses messages.append({"role": "system", "content": "Please introduce yourself to the user."})
llm, # LLM await task.queue_frames([context_aggregator.user().get_context_frame()])
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -21,95 +17,92 @@ from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.services.openai.stt import OpenAISTTService from pipecat.services.openai.stt import OpenAISTTService
from pipecat.services.openai.tts import OpenAITTSService from pipecat.services.openai.tts import OpenAITTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = OpenAISTTService(
room_url, api_key=os.getenv("OPENAI_API_KEY"),
token, model="gpt-4o-transcribe-latest",
"Respond bot", prompt="Expect words related to dogs, such as breed names.",
DailyParams( )
audio_out_enabled=True,
audio_out_sample_rate=24000,
transcription_enabled=False,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
# You can use the OpenAI compatible API like Groq. tts = OpenAITTSService(api_key=os.getenv("OPENAI_API_KEY"), voice="ballad")
# stt = OpenAISTTService(
# base_url="https://api.groq.com/openai/v1",
# api_key="gsk_***",
# model="whisper-large-v3",
# )
stt = OpenAISTTService(
api_key=os.getenv("OPENAI_API_KEY"),
model="gpt-4o-transcribe-latest",
prompt="Expect words related to dogs, such as breed names.",
)
tts = OpenAITTSService(api_key=os.getenv("OPENAI_API_KEY"), voice="ballad") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") messages = [
{
"role": "system",
"content": "You are very knowledgable about dogs. 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.",
},
]
messages = [ context = OpenAILLMContext(messages)
{ context_aggregator = llm.create_context_aggregator(context)
"role": "system",
"content": "You are very knowledgable about dogs. 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.", pipeline = Pipeline(
}, [
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
audio_out_sample_rate=24000,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
stt, # STT # Kick off the conversation.
context_aggregator.user(), # User responses messages.append({"role": "system", "content": "Please introduce yourself to the user."})
llm, # LLM await task.queue_frames([context_aggregator.user().get_context_frame()])
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,15 +4,11 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import time import time
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -20,90 +16,98 @@ 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.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openpipe.llm import OpenPipeLLMService from pipecat.services.openpipe.llm import OpenPipeLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = CartesiaTTSService( tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
) )
timestamp = int(time.time()) timestamp = int(time.time())
llm = OpenPipeLLMService( llm = OpenPipeLLMService(
api_key=os.getenv("OPENAI_API_KEY"), api_key=os.getenv("OPENAI_API_KEY"),
openpipe_api_key=os.getenv("OPENPIPE_API_KEY"), openpipe_api_key=os.getenv("OPENPIPE_API_KEY"),
model="gpt-4o", model="gpt-4o",
tags={"conversation_id": f"pipecat-{timestamp}"}, tags={"conversation_id": f"pipecat-{timestamp}"},
) )
messages = [ messages = [
{ {
"role": "system", "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.", "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
stt,
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
context_aggregator.user(), # User responses # Kick off the conversation.
llm, # LLM messages.append({"role": "system", "content": "Please introduce yourself to the user."})
tts, # TTS await task.queue_frames([context_aggregator.user().get_context_frame()])
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,45 +4,44 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.services.xtts.tts import XTTSService from pipecat.services.xtts.tts import XTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
# Create an HTTP session
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
(room_url, token) = await configure(session) stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
transport = DailyTransport(
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = XTTSService( tts = XTTSService(
aiohttp_session=session, aiohttp_session=session,
@@ -65,6 +64,7 @@ async def main():
pipeline = Pipeline( pipeline = Pipeline(
[ [
transport.input(), # Transport user input transport.input(), # Transport user input
stt,
context_aggregator.user(), # User responses context_aggregator.user(), # User responses
llm, # LLM llm, # LLM
tts, # TTS tts, # TTS
@@ -83,21 +83,28 @@ async def main():
), ),
) )
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_connected")
async def on_first_participant_joined(transport, participant): async def on_client_connected(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client connected")
# Kick off the conversation. # Kick off the conversation.
messages.append({"role": "system", "content": "Please introduce yourself to the user."}) messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()]) await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") @transport.event_handler("on_client_disconnected")
async def on_participant_left(transport, participant, reason): async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel() await task.cancel()
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -23,94 +19,96 @@ from pipecat.services.gladia.config import GladiaInputParams, LanguageConfig
from pipecat.services.gladia.stt import GladiaSTTService from pipecat.services.gladia.stt import GladiaSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transcriptions.language import Language from pipecat.transcriptions.language import Language
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = GladiaSTTService(
room_url, api_key=os.getenv("GLADIA_API_KEY", ""),
token, params=GladiaInputParams(
"Respond bot", language_config=LanguageConfig(
DailyParams( languages=[Language.EN],
audio_out_enabled=True, )
vad_enabled=True, ),
vad_analyzer=SileroVADAnalyzer(), )
vad_audio_passthrough=True,
),
)
stt = GladiaSTTService( tts = CartesiaTTSService(
api_key=os.getenv("GLADIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY", ""),
params=GladiaInputParams( voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
language_config=LanguageConfig( )
languages=[Language.EN],
)
),
)
tts = CartesiaTTSService( llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY", ""), model="gpt-4o")
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") messages = [
{
"role": "system",
"content": f"You are a helpful LLM. 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.",
},
]
messages = [ context = OpenAILLMContext(messages)
{ context_aggregator = llm.create_context_aggregator(context)
"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.", pipeline = Pipeline(
}, [
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
stt, # STT # Kick off the conversation.
context_aggregator.user(), # User responses messages.append({"role": "system", "content": "Please introduce yourself to the user."})
llm, # LLM await task.queue_frames([context_aggregator.user().get_context_frame()])
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
# Register an event handler to exit the application when the user leaves. runner = PipelineRunner(handle_sigint=False)
@transport.event_handler("on_participant_left") await runner.run(task)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,96 +4,100 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.lmnt.tts import LmntTTSService from pipecat.services.lmnt.tts import LmntTTSService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = LmntTTSService(api_key=os.getenv("LMNT_API_KEY"), voice_id="morgan") tts = LmntTTSService(api_key=os.getenv("LMNT_API_KEY"), voice_id="morgan")
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
messages = [ messages = [
{ {
"role": "system", "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.", "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
stt,
context_aggregator.user(), # User respones
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
context_aggregator.user(), # User respones # Kick off the conversation.
llm, # LLM messages.append({"role": "system", "content": "Please introduce yourself to the user."})
tts, # TTS await task.queue_frames([context_aggregator.user().get_context_frame()])
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -0,0 +1,102 @@
#
# Copyright (c) 20242025, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
import os
from dotenv import load_dotenv
from loguru import logger
from pipecat.audio.vad.silero import SileroVADAnalyzer
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.groq.llm import GroqLLMService
from pipecat.services.groq.stt import GroqSTTService
from pipecat.services.groq.tts import GroqTTSService
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True)
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
stt = GroqSTTService(api_key=os.getenv("GROQ_API_KEY"))
llm = GroqLLMService(api_key=os.getenv("GROQ_API_KEY"), model="llama-3.3-70b-versatile")
tts = GroqTTSService(api_key=os.getenv("GROQ_API_KEY"))
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
stt,
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask(
pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Kick off the conversation.
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__":
from run import main
main()

View File

@@ -1,115 +0,0 @@
#
# Copyright (c) 20242025, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
import asyncio
import os
import sys
import aiohttp
from dotenv import load_dotenv
from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer
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.tts import CartesiaTTSService
from pipecat.services.together.llm import TogetherLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport
load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def main():
async with aiohttp.ClientSession() as session:
(room_url, token) = await configure(session)
transport = DailyTransport(
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = TogetherLLMService(
api_key=os.getenv("TOGETHER_API_KEY"),
model="meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo",
params=TogetherLLMService.InputParams(
temperature=1.0,
top_p=0.9,
top_k=40,
extra={
"frequency_penalty": 2.0,
"presence_penalty": 0.0,
},
),
)
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 in plain language. Respond to what the user said in a creative and helpful way.",
},
]
context = OpenAILLMContext(messages)
context_aggregator = llm.create_context_aggregator(context)
user_aggregator = context_aggregator.user()
assistant_aggregator = context_aggregator.assistant()
pipeline = Pipeline(
[
transport.input(), # Transport user input
user_aggregator, # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
assistant_aggregator, # Assistant spoken responses
]
)
task = PipelineTask(
pipeline,
params=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"])
# Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left")
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -21,89 +17,93 @@ from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.aws.tts import PollyTTSService from pipecat.services.aws.tts import PollyTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, _) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
None,
"Respond bot",
DailyParams(
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) tts = PollyTTSService(
api_key=os.getenv("AWS_SECRET_ACCESS_KEY"),
aws_access_key_id=os.getenv("AWS_ACCESS_KEY_ID"),
region=os.getenv("AWS_REGION"),
voice_id="Amy",
params=PollyTTSService.InputParams(engine="neural", language="en-GB", rate="1.05"),
)
tts = PollyTTSService( llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
api_key=os.getenv("AWS_SECRET_ACCESS_KEY"),
aws_access_key_id=os.getenv("AWS_ACCESS_KEY_ID"),
region=os.getenv("AWS_REGION"),
voice_id="Amy",
params=PollyTTSService.InputParams(engine="neural", language="en-GB", rate="1.05"),
)
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.",
},
]
messages = [ context = OpenAILLMContext(messages)
{ context_aggregator = llm.create_context_aggregator(context)
"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.", pipeline = Pipeline(
}, [
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
stt, # STT # Kick off the conversation.
context_aggregator.user(), # User responses messages.append({"role": "system", "content": "Please introduce yourself to the user."})
llm, # LLM await task.queue_frames([context_aggregator.user().get_context_frame()])
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -22,88 +18,94 @@ from pipecat.services.google.llm import GoogleLLMService
from pipecat.services.google.stt import GoogleSTTService from pipecat.services.google.stt import GoogleSTTService
from pipecat.services.google.tts import GoogleTTSService from pipecat.services.google.tts import GoogleTTSService
from pipecat.transcriptions.language import Language from pipecat.transcriptions.language import Language
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, _) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = GoogleSTTService(
room_url, params=GoogleSTTService.InputParams(languages=Language.EN_US),
None, credentials=os.getenv("GOOGLE_TEST_CREDENTIALS"),
"Respond bot", )
DailyParams(
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
stt = GoogleSTTService( tts = GoogleTTSService(
params=GoogleSTTService.InputParams(languages=Language.EN_US), voice_id="en-US-Chirp3-HD-Charon",
) params=GoogleTTSService.InputParams(language=Language.EN_US),
credentials=os.getenv("GOOGLE_TEST_CREDENTIALS"),
)
tts = GoogleTTSService( llm = GoogleLLMService(api_key=os.getenv("GOOGLE_API_KEY"))
voice_id="en-US-Journey-F",
params=GoogleTTSService.InputParams(language=Language.EN_US),
)
llm = GoogleLLMService(api_key=os.getenv("GOOGLE_API_KEY")) 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.",
},
]
messages = [ context = OpenAILLMContext(messages)
{ context_aggregator = llm.create_context_aggregator(context)
"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.", pipeline = Pipeline(
}, [
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User respones
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
stt, # STT # Kick off the conversation.
context_aggregator.user(), # User respones messages.append({"role": "system", "content": "Please introduce yourself to the user."})
llm, # LLM await task.queue_frames([context_aggregator.user().get_context_frame()])
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -21,88 +17,92 @@ from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.assemblyai.stt import AssemblyAISTTService from pipecat.services.assemblyai.stt import AssemblyAISTTService
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = AssemblyAISTTService(
room_url, api_key=os.getenv("ASSEMBLYAI_API_KEY"),
token, )
"Respond bot",
DailyParams(
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
stt = AssemblyAISTTService( tts = CartesiaTTSService(
api_key=os.getenv("ASSEMBLYAI_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
) voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
tts = CartesiaTTSService( llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading 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.",
},
]
messages = [ context = OpenAILLMContext(messages)
{ context_aggregator = llm.create_context_aggregator(context)
"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.", pipeline = Pipeline(
}, [
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
stt, # STT # Kick off the conversation.
context_aggregator.user(), # User responses messages.append({"role": "system", "content": "Please introduce yourself to the user."})
llm, # LLM await task.queue_frames([context_aggregator.user().get_context_frame()])
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.filters.krisp_filter import KrispFilter from pipecat.audio.filters.krisp_filter import KrispFilter
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
@@ -22,83 +18,88 @@ from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.deepgram.tts import DeepgramTTSService from pipecat.services.deepgram.tts import DeepgramTTSService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
audio_in_filter=KrispFilter(),
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
audio_in_filter=KrispFilter(),
),
)
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en")
tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
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.",
},
]
messages = [ context = OpenAILLMContext(messages)
{ context_aggregator = llm.create_context_aggregator(context)
"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.", pipeline = Pipeline(
}, [
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
stt, # STT # Kick off the conversation.
context_aggregator.user(), # User responses messages.append({"role": "system", "content": "Please introduce yourself to the user."})
llm, # LLM await task.queue_frames([context_aggregator.user().get_context_frame()])
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
# Kick off the conversation. logger.info(f"Client closed connection")
messages.append({"role": "system", "content": "Please introduce yourself to the user."}) await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,45 +4,44 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.services.rime.tts import RimeHttpTTSService from pipecat.services.rime.tts import RimeHttpTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
# Create an HTTP session
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
(room_url, token) = await configure(session) stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
transport = DailyTransport(
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = RimeHttpTTSService( tts = RimeHttpTTSService(
api_key=os.getenv("RIME_API_KEY", ""), api_key=os.getenv("RIME_API_KEY", ""),
@@ -65,6 +64,7 @@ async def main():
pipeline = Pipeline( pipeline = Pipeline(
[ [
transport.input(), # Transport user input transport.input(), # Transport user input
stt,
context_aggregator.user(), # User responses context_aggregator.user(), # User responses
llm, # LLM llm, # LLM
tts, # TTS tts, # TTS
@@ -83,21 +83,28 @@ async def main():
), ),
) )
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_connected")
async def on_first_participant_joined(transport, participant): async def on_client_connected(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client connected")
# Kick off the conversation. # Kick off the conversation.
messages.append({"role": "system", "content": "Please introduce yourself to the user."}) messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()]) await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") @transport.event_handler("on_client_disconnected")
async def on_participant_left(transport, participant, reason): async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel() await task.cancel()
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,99 +4,103 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.services.rime.tts import RimeTTSService from pipecat.services.rime.tts import RimeTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = RimeTTSService( tts = RimeTTSService(
api_key=os.getenv("RIME_API_KEY", ""), api_key=os.getenv("RIME_API_KEY", ""),
voice_id="rex", voice_id="rex",
) )
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
messages = [ messages = [
{ {
"role": "system", "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.", "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
stt,
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
context_aggregator.user(), # User responses # Kick off the conversation.
llm, # LLM messages.append({"role": "system", "content": "Please introduce yourself to the user."})
tts, # TTS await task.queue_frames([context_aggregator.user().get_context_frame()])
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -21,76 +17,87 @@ from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.nim.llm import NimLLMService from pipecat.services.nim.llm import NimLLMService
from pipecat.services.riva.stt import ParakeetSTTService from pipecat.services.riva.stt import ParakeetSTTService
from pipecat.services.riva.tts import FastPitchTTSService from pipecat.services.riva.tts import FastPitchTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, _) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = ParakeetSTTService(api_key=os.getenv("NVIDIA_API_KEY"))
room_url,
None,
"Respond bot",
DailyParams(
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
stt = ParakeetSTTService(api_key=os.getenv("NVIDIA_API_KEY")) llm = NimLLMService(api_key=os.getenv("NVIDIA_API_KEY"), model="meta/llama-3.1-405b-instruct")
llm = NimLLMService( tts = FastPitchTTSService(api_key=os.getenv("NVIDIA_API_KEY"))
api_key=os.getenv("NVIDIA_API_KEY"), model="meta/llama-3.1-405b-instruct"
)
tts = FastPitchTTSService(api_key=os.getenv("NVIDIA_API_KEY")) 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.",
},
]
messages = [ context = OpenAILLMContext(messages)
{ context_aggregator = llm.create_context_aggregator(context)
"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.", pipeline = Pipeline(
}, [
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
stt, # STT # Kick off the conversation.
context_aggregator.user(), # User responses messages.append({"role": "system", "content": "Please introduce yourself to the user."})
llm, # LLM await task.queue_frames([context_aggregator.user().get_context_frame()])
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask(pipeline, params=PipelineParams(allow_interruptions=True)) @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
# Kick off the conversation. logger.info(f"Client closed connection")
messages.append({"role": "system", "content": "Please introduce yourself to the user."}) await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,16 +4,12 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
from dataclasses import dataclass from dataclasses import dataclass
import aiohttp
import google.ai.generativelanguage as glm import google.ai.generativelanguage as glm
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import ( from pipecat.frames.frames import (
@@ -32,14 +28,15 @@ 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.processors.frame_processor import FrameProcessor from pipecat.processors.frame_processor import FrameProcessor
from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.google.llm import GoogleLLMService from pipecat.services.google.llm import GoogleLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.services.google.tts import GoogleTTSService
from pipecat.transcriptions.language import Language
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
marker = "|----|" marker = "|----|"
system_message = f""" system_message = f"""
@@ -193,85 +190,92 @@ class TanscriptionContextFixup(FrameProcessor):
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, # No transcription at all. just audio input to Gemini!
# No transcription at all. just audio input to Gemini! # transcription_enabled=True,
# transcription_enabled=True, vad_enabled=True,
vad_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_analyzer=SileroVADAnalyzer(), vad_audio_passthrough=True,
vad_audio_passthrough=True, ),
), )
)
tts = CartesiaTTSService( llm = GoogleLLMService(api_key=os.getenv("GOOGLE_API_KEY"), model="gemini-2.0-flash-001")
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = GoogleLLMService(api_key=os.getenv("GOOGLE_API_KEY"), model="gemini-2.0-flash-001") tts = GoogleTTSService(
voice_id="en-US-Chirp3-HD-Charon",
params=GoogleTTSService.InputParams(language=Language.EN_US),
credentials=os.getenv("GOOGLE_TEST_CREDENTIALS"),
)
messages = [ messages = [
{ {
"role": "system", "role": "system",
"content": system_message, "content": system_message,
}, },
{ {
"role": "user", "role": "user",
"content": "Start by saying hello.", "content": "Start by saying hello.",
}, },
]
context = OpenAILLMContext(messages)
context_aggregator = llm.create_context_aggregator(context)
audio_collector = UserAudioCollector(context, context_aggregator.user())
pull_transcript_out_of_llm_output = TranscriptExtractor(context)
fixup_context_messages = TanscriptionContextFixup(context)
pipeline = Pipeline(
[
transport.input(), # Transport user input
audio_collector,
context_aggregator.user(), # User responses
llm, # LLM
pull_transcript_out_of_llm_output,
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
fixup_context_messages,
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
audio_collector = UserAudioCollector(context, context_aggregator.user()) params=PipelineParams(
pull_transcript_out_of_llm_output = TranscriptExtractor(context) allow_interruptions=True,
fixup_context_messages = TanscriptionContextFixup(context) enable_metrics=True,
enable_usage_metrics=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
audio_collector, # Kick off the conversation.
context_aggregator.user(), # User responses messages.append({"role": "system", "content": "Please introduce yourself to the user."})
llm, # LLM await task.queue_frames([context_aggregator.user().get_context_frame()])
pull_transcript_out_of_llm_output,
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
fixup_context_messages,
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,99 +4,103 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.fish.tts import FishAudioTTSService from pipecat.services.fish.tts import FishAudioTTSService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = FishAudioTTSService( tts = FishAudioTTSService(
api_key=os.getenv("FISH_API_KEY"), api_key=os.getenv("FISH_API_KEY"),
model="4ce7e917cedd4bc2bb2e6ff3a46acaa1", # Barack Obama model="4ce7e917cedd4bc2bb2e6ff3a46acaa1", # Barack Obama
) )
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
messages = [ messages = [
{ {
"role": "system", "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.", "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
stt,
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
context_aggregator.user(), # User responses # Kick off the conversation.
llm, # LLM messages.append({"role": "system", "content": "Please introduce yourself to the user."})
tts, # TTS await task.queue_frames([context_aggregator.user().get_context_frame()])
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.audio.vad.vad_analyzer import VADParams
@@ -20,7 +16,9 @@ from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.ultravox.stt import UltravoxSTTService from pipecat.services.ultravox.stt import UltravoxSTTService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
@@ -28,8 +26,6 @@ load_dotenv(override=True)
# The Ultravox model is compute-intensive and performs best with GPU acceleration. # The Ultravox model is compute-intensive and performs best with GPU acceleration.
# This can be deployed on cloud GPU providers like Cerebrium.ai for optimal performance. # This can be deployed on cloud GPU providers like Cerebrium.ai for optimal performance.
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
# Want to initialize the ultravox processor since it takes time to load the model and dont # Want to initialize the ultravox processor since it takes time to load the model and dont
# want to load it every time the pipeline is run # want to load it every time the pipeline is run
@@ -39,53 +35,61 @@ ultravox_processor = UltravoxSTTService(
) )
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=False, vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ),
vad_audio_passthrough=True, )
),
)
tts = CartesiaTTSService( tts = CartesiaTTSService(
api_key=os.environ.get("CARTESIA_API_KEY"), api_key=os.environ.get("CARTESIA_API_KEY"),
voice_id="97f4b8fb-f2fe-444b-bb9a-c109783a857a", voice_id="97f4b8fb-f2fe-444b-bb9a-c109783a857a",
) )
pipeline = Pipeline( pipeline = Pipeline(
[ [
transport.input(), # Transport user input transport.input(), # Transport user input
ultravox_processor, ultravox_processor,
tts, # TTS tts, # TTS
transport.output(), # Transport bot output transport.output(), # Transport bot output
] ]
) )
task = PipelineTask( task = PipelineTask(
pipeline, pipeline,
params=PipelineParams( params=PipelineParams(
allow_interruptions=True, allow_interruptions=True,
enable_metrics=True, enable_metrics=True,
), ),
) )
@transport.event_handler("on_participant_left") @transport.event_handler("on_client_connected")
async def on_participant_left(transport, participant, reason): async def on_client_connected(transport, client):
await task.cancel() logger.info(f"Client connected")
runner = PipelineRunner() @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
await runner.run(task) @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,99 +4,103 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.neuphonic.tts import NeuphonicHttpTTSService from pipecat.services.neuphonic.tts import NeuphonicHttpTTSService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = NeuphonicHttpTTSService( tts = NeuphonicHttpTTSService(
api_key=os.getenv("NEUPHONIC_API_KEY"), api_key=os.getenv("NEUPHONIC_API_KEY"),
voice_id="fc854436-2dac-4d21-aa69-ae17b54e98eb", # Emily voice_id="fc854436-2dac-4d21-aa69-ae17b54e98eb", # Emily
) )
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
messages = [ messages = [
{ {
"role": "system", "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.", "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
stt,
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
context_aggregator.user(), # User responses # Kick off the conversation.
llm, # LLM messages.append({"role": "system", "content": "Please introduce yourself to the user."})
tts, # TTS await task.queue_frames([context_aggregator.user().get_context_frame()])
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,99 +4,103 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.neuphonic.tts import NeuphonicTTSService from pipecat.services.neuphonic.tts import NeuphonicTTSService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = NeuphonicTTSService( tts = NeuphonicTTSService(
api_key=os.getenv("NEUPHONIC_API_KEY"), api_key=os.getenv("NEUPHONIC_API_KEY"),
voice_id="fc854436-2dac-4d21-aa69-ae17b54e98eb", # Emily voice_id="fc854436-2dac-4d21-aa69-ae17b54e98eb", # Emily
) )
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
messages = [ messages = [
{ {
"role": "system", "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.", "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
stt,
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
context_aggregator.user(), # User responses # Kick off the conversation.
llm, # LLM messages.append({"role": "system", "content": "Please introduce yourself to the user."})
tts, # TTS await task.queue_frames([context_aggregator.user().get_context_frame()])
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left") runner = PipelineRunner(handle_sigint=False)
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -21,89 +17,92 @@ from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.fal.stt import FalSTTService from pipecat.services.fal.stt import FalSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = FalSTTService(
room_url, api_key=os.getenv("FAL_KEY"),
token, )
"Respond bot",
DailyParams(
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
stt = FalSTTService( tts = CartesiaTTSService(
api_key=os.getenv("FAL_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
) voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
tts = CartesiaTTSService( llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading 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.",
},
]
messages = [ context = OpenAILLMContext(messages)
{ context_aggregator = llm.create_context_aggregator(context)
"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.", pipeline = Pipeline(
}, [
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected")
stt, # STT # Kick off the conversation.
context_aggregator.user(), # User responses messages.append({"role": "system", "content": "Please introduce yourself to the user."})
llm, # LLM await task.queue_frames([context_aggregator.user().get_context_frame()])
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
# Register an event handler to exit the application when the user leaves. runner = PipelineRunner(handle_sigint=False)
@transport.event_handler("on_participant_left")
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -1,103 +0,0 @@
#
# Copyright (c) 20242025, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
import asyncio
import os
import sys
import aiohttp
from dotenv import load_dotenv
from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer
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.groq.llm import GroqLLMService
from pipecat.services.groq.stt import GroqSTTService
from pipecat.services.groq.tts import GroqTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport
load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def main():
async with aiohttp.ClientSession() as session:
(room_url, token) = await configure(session)
transport = DailyTransport(
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
# transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
stt = GroqSTTService(api_key=os.getenv("GROQ_API_KEY"))
llm = GroqLLMService(api_key=os.getenv("GROQ_API_KEY"), model="llama-3.3-70b-versatile")
tts = GroqTTSService(api_key=os.getenv("GROQ_API_KEY"))
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
stt,
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask(
pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined")
async def on_first_participant_joined(transport, participant):
await transport.capture_participant_transcription(participant["id"])
# Kick off the conversation.
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_participant_left")
async def on_participant_left(transport, participant, reason):
await task.cancel()
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -4,8 +4,8 @@ import os
from typing import Tuple from typing import Tuple
import aiohttp import aiohttp
from daily_runner import configure
from dotenv import load_dotenv from dotenv import load_dotenv
from runner import configure
from pipecat.frames.frames import AudioFrame, EndFrame, ImageFrame, LLMMessagesFrame, TextFrame from pipecat.frames.frames import AudioFrame, EndFrame, ImageFrame, LLMMessagesFrame, TextFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -72,7 +72,8 @@ async def main():
async def get_text_and_audio(messages) -> Tuple[str, bytearray]: async def get_text_and_audio(messages) -> Tuple[str, bytearray]:
"""This function streams text from the LLM and uses the TTS service to convert """This function streams text from the LLM and uses the TTS service to convert
that text to speech as it's received.""" that text to speech as it's received.
"""
source_queue = asyncio.Queue() source_queue = asyncio.Queue()
sink_queue = asyncio.Queue() sink_queue = asyncio.Queue()
sentence_aggregator = SentenceAggregator() sentence_aggregator = SentenceAggregator()

View File

@@ -4,13 +4,9 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import ( from pipecat.frames.frames import (
Frame, Frame,
@@ -23,13 +19,12 @@ from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
class MirrorProcessor(FrameProcessor): class MirrorProcessor(FrameProcessor):
async def process_frame(self, frame: Frame, direction: FrameDirection): async def process_frame(self, frame: Frame, direction: FrameDirection):
@@ -44,6 +39,7 @@ class MirrorProcessor(FrameProcessor):
) )
) )
elif isinstance(frame, InputImageRawFrame): elif isinstance(frame, InputImageRawFrame):
print(f"Received image frame: {frame.size} {frame.format}")
await self.push_frame( await self.push_frame(
OutputImageRawFrame(image=frame.image, size=frame.size, format=frame.format) OutputImageRawFrame(image=frame.image, size=frame.size, format=frame.format)
) )
@@ -51,42 +47,48 @@ class MirrorProcessor(FrameProcessor):
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Test", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_in_enabled=True, camera_in_enabled=True,
audio_out_enabled=True, camera_out_enabled=True,
camera_out_enabled=True, camera_out_is_live=True,
camera_out_is_live=True, camera_out_width=1280,
camera_out_width=1280, camera_out_height=720,
camera_out_height=720, ),
), )
)
@transport.event_handler("on_first_participant_joined") pipeline = Pipeline([transport.input(), MirrorProcessor(), transport.output()])
async def on_first_participant_joined(transport, participant):
await transport.capture_participant_video(participant["id"])
pipeline = Pipeline([transport.input(), MirrorProcessor(), transport.output()]) task = PipelineTask(
pipeline,
params=PipelineParams(),
)
runner = PipelineRunner() @transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected")
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
audio_in_sample_rate=24000,
audio_out_sample_rate=24000,
),
)
await runner.run(task) @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -5,13 +5,10 @@
# #
import asyncio import asyncio
import sys
import tkinter as tk import tkinter as tk
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import ( from pipecat.frames.frames import (
Frame, Frame,
@@ -24,14 +21,13 @@ from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.local.tk import TkLocalTransport, TkTransportParams from pipecat.transports.local.tk import TkLocalTransport, TkTransportParams
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
class MirrorProcessor(FrameProcessor): class MirrorProcessor(FrameProcessor):
async def process_frame(self, frame: Frame, direction: FrameDirection): async def process_frame(self, frame: Frame, direction: FrameDirection):
@@ -53,52 +49,59 @@ class MirrorProcessor(FrameProcessor):
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
tk_root = tk.Tk() p2p_transport = SmallWebRTCTransport(
tk_root.title("Local Mirror") webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
camera_in_enabled=True,
camera_out_enabled=True,
camera_out_is_live=True,
camera_out_width=1280,
camera_out_height=720,
),
)
daily_transport = DailyTransport( tk_root = tk.Tk()
room_url, token, "Test", DailyParams(audio_in_enabled=True) tk_root.title("Local Mirror")
)
tk_transport = TkLocalTransport( tk_transport = TkLocalTransport(
tk_root, tk_root,
TkTransportParams( TkTransportParams(
audio_out_enabled=True, audio_out_enabled=True,
camera_out_enabled=True, camera_out_enabled=True,
camera_out_is_live=True, camera_out_is_live=True,
camera_out_width=1280, camera_out_width=1280,
camera_out_height=720, camera_out_height=720,
), ),
) )
@daily_transport.event_handler("on_first_participant_joined") @p2p_transport.event_handler("on_client_connected")
async def on_first_participant_joined(transport, participant): async def on_client_connected(transport, client):
await transport.capture_participant_video(participant["id"]) logger.info(f"Client connected")
pipeline = Pipeline([daily_transport.input(), MirrorProcessor(), tk_transport.output()]) pipeline = Pipeline([p2p_transport.input(), MirrorProcessor(), tk_transport.output()])
task = PipelineTask( task = PipelineTask(
pipeline, pipeline,
params=PipelineParams( params=PipelineParams(),
audio_in_sample_rate=24000, )
audio_out_sample_rate=24000,
),
)
async def run_tk(): async def run_tk():
while not task.has_finished(): while not task.has_finished():
tk_root.update() tk_root.update()
tk_root.update_idletasks() tk_root.update_idletasks()
await asyncio.sleep(0.1) await asyncio.sleep(0.1)
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await asyncio.gather(runner.run(task), run_tk()) await asyncio.gather(runner.run(task), run_tk())
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,89 +4,99 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import TTSSpeakFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.processors.filters.wake_check_filter import WakeCheckFilter from pipecat.processors.filters.wake_check_filter import WakeCheckFilter
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Robot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = CartesiaTTSService( tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
) )
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
messages = [ messages = [
{ {
"role": "system", "role": "system",
"content": "You are a helpful assistant. Respond to what the user said in a creative and helpful way. Keep your responses brief.", "content": "You are a helpful assistant. Respond to what the user said in a creative and helpful way. Keep your responses brief.",
}, },
]
hey_robot_filter = WakeCheckFilter(["hey robot", "hey, robot"])
context = OpenAILLMContext(messages)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(), # Transport user input
stt, # STT
hey_robot_filter, # Filter out speech not directed at the robot
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
hey_robot_filter = WakeCheckFilter(["hey robot", "hey, robot"]) task = PipelineTask(pipeline, params=PipelineParams(allow_interruptions=True))
context = OpenAILLMContext(messages) @transport.event_handler("on_client_connected")
context_aggregator = llm.create_context_aggregator(context) async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Kick off the conversation.
await task.queue_frame(TTSSpeakFrame("Hi! If you want to talk to me, just say 'Hey Robot'"))
pipeline = Pipeline( @transport.event_handler("on_client_disconnected")
[ async def on_client_disconnected(transport, client):
transport.input(), # Transport user input logger.info(f"Client disconnected")
hey_robot_filter, # Filter out speech not directed at the robot
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask(pipeline, params=PipelineParams(allow_interruptions=True)) @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
@transport.event_handler("on_first_participant_joined") runner = PipelineRunner(handle_sigint=False)
async def on_first_participant_joined(transport, participant):
await transport.capture_participant_transcription(participant["id"])
await tts.say("Hi! If you want to talk to me, just say 'Hey Robot'.")
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,21 +4,18 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import wave import wave
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import ( from pipecat.frames.frames import (
Frame, Frame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
OutputAudioRawFrame, OutputAudioRawFrame,
TTSSpeakFrame,
) )
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
@@ -30,14 +27,14 @@ from pipecat.processors.aggregators.openai_llm_context import (
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.processors.logger import FrameLogger from pipecat.processors.logger import FrameLogger
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
sounds = {} sounds = {}
sound_files = ["ding1.wav", "ding2.wav"] sound_files = ["ding1.wav", "ding2.wav"]
@@ -80,70 +77,83 @@ class InboundSoundEffectWrapper(FrameProcessor):
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
tts = CartesiaTTSService( llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
messages = [ tts = CartesiaTTSService(
{ api_key=os.getenv("CARTESIA_API_KEY"),
"role": "system", voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
"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. Respond to what the user said in a creative and helpful way.", )
},
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. Respond to what the user said in a creative and helpful way.",
},
]
context = OpenAILLMContext(messages)
context_aggregator = llm.create_context_aggregator(context)
out_sound = OutboundSoundEffectWrapper()
in_sound = InboundSoundEffectWrapper()
fl = FrameLogger("LLM Out")
fl2 = FrameLogger("Transcription In")
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
in_sound,
fl2,
llm,
fl,
tts,
out_sound,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(pipeline)
context_aggregator = llm.create_context_aggregator(context)
out_sound = OutboundSoundEffectWrapper()
in_sound = InboundSoundEffectWrapper()
fl = FrameLogger("LLM Out")
fl2 = FrameLogger("Transcription In")
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
in_sound, await task.queue_frame(TTSSpeakFrame("Hi, I'm listening!"))
fl2, await transport.send_audio(sounds["ding1.wav"])
llm,
fl,
tts,
out_sound,
transport.output(),
context_aggregator.assistant(),
]
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_disconnected")
async def on_first_participant_joined(transport, participant): async def on_client_disconnected(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client disconnected")
await tts.say("Hi, I'm listening!")
await transport.send_audio(sounds["ding1.wav"])
runner = PipelineRunner() @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
task = PipelineTask(pipeline) runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,15 +4,11 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
from typing import Optional from typing import Optional
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame
@@ -23,14 +19,14 @@ from pipecat.processors.aggregators.user_response import UserResponseAggregator
from pipecat.processors.aggregators.vision_image_frame import VisionImageFrameAggregator from pipecat.processors.aggregators.vision_image_frame import VisionImageFrameAggregator
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.moondream.vision import MoondreamService from pipecat.services.moondream.vision import MoondreamService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
class UserImageRequester(FrameProcessor): class UserImageRequester(FrameProcessor):
def __init__(self, participant_id: Optional[str] = None): def __init__(self, participant_id: Optional[str] = None):
@@ -50,61 +46,81 @@ class UserImageRequester(FrameProcessor):
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: # Get WebRTC peer connection ID
(room_url, token) = await configure(session) webrtc_peer_id = webrtc_connection.pc_id
transport = DailyTransport( logger.info(f"Starting bot with peer_id: {webrtc_peer_id}")
room_url,
token,
"Describe participant video",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
user_response = UserResponseAggregator() transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
camera_in_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
image_requester = UserImageRequester() user_response = UserResponseAggregator()
vision_aggregator = VisionImageFrameAggregator() # Initialize the image requester without setting the participant ID yet
image_requester = UserImageRequester()
# If you run into weird description, try with use_cpu=True vision_aggregator = VisionImageFrameAggregator()
moondream = MoondreamService()
tts = CartesiaTTSService( # If you run into weird description, try with use_cpu=True
api_key=os.getenv("CARTESIA_API_KEY"), moondream = MoondreamService()
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
@transport.event_handler("on_first_participant_joined") stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
async def on_first_participant_joined(transport, participant):
await tts.say("Hi there! Feel free to ask me what I see.")
await transport.capture_participant_video(participant["id"], framerate=0)
await transport.capture_participant_transcription(participant["id"])
image_requester.set_participant_id(participant["id"])
pipeline = Pipeline( tts = CartesiaTTSService(
[ api_key=os.getenv("CARTESIA_API_KEY"),
transport.input(), voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
user_response, )
image_requester,
vision_aggregator,
moondream,
tts,
transport.output(),
]
)
task = PipelineTask(pipeline) pipeline = Pipeline(
[
transport.input(),
stt,
user_response,
image_requester,
vision_aggregator,
moondream,
tts,
transport.output(),
]
)
runner = PipelineRunner() task = PipelineTask(pipeline)
await runner.run(task) @transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected: {client}")
# Welcome message
await tts.say("Hi there! Feel free to ask me what I see.")
# Set the participant ID in the image requester
image_requester.set_participant_id(webrtc_peer_id)
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,33 +4,29 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
from typing import Optional from typing import Optional
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.aggregators.user_response import UserResponseAggregator from pipecat.processors.aggregators.user_response import UserResponseAggregator
from pipecat.processors.aggregators.vision_image_frame import VisionImageFrameAggregator from pipecat.processors.aggregators.vision_image_frame import VisionImageFrameAggregator
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.google.llm import GoogleLLMService from pipecat.services.google.llm import GoogleLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
class UserImageRequester(FrameProcessor): class UserImageRequester(FrameProcessor):
def __init__(self, participant_id: Optional[str] = None): def __init__(self, participant_id: Optional[str] = None):
@@ -50,61 +46,84 @@ class UserImageRequester(FrameProcessor):
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: # Get WebRTC peer connection ID
(room_url, token) = await configure(session) webrtc_peer_id = webrtc_connection.pc_id
transport = DailyTransport( logger.info(f"Starting bot with peer_id: {webrtc_peer_id}")
room_url,
token,
"Describe participant video",
DailyParams(
audio_in_enabled=True, # This is so Silero VAD can get audio data
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
user_response = UserResponseAggregator() transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
camera_in_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
image_requester = UserImageRequester() user_response = UserResponseAggregator()
vision_aggregator = VisionImageFrameAggregator() # Initialize the image requester without setting the participant ID yet
image_requester = UserImageRequester()
google = GoogleLLMService(model="gemini-2.0-flash-001", api_key=os.getenv("GOOGLE_API_KEY")) vision_aggregator = VisionImageFrameAggregator()
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
@transport.event_handler("on_first_participant_joined") # Google Gemini model for vision analysis
async def on_first_participant_joined(transport, participant): google = GoogleLLMService(model="gemini-2.0-flash-001", api_key=os.getenv("GOOGLE_API_KEY"))
await tts.say("Hi there! Feel free to ask me what I see.")
await transport.capture_participant_video(participant["id"], framerate=0)
await transport.capture_participant_transcription(participant["id"])
image_requester.set_participant_id(participant["id"])
pipeline = Pipeline( tts = CartesiaTTSService(
[ api_key=os.getenv("CARTESIA_API_KEY"),
transport.input(), voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
user_response, )
image_requester,
vision_aggregator,
google,
tts,
transport.output(),
]
)
task = PipelineTask(pipeline) pipeline = Pipeline(
[
transport.input(),
stt,
user_response,
image_requester,
vision_aggregator,
google,
tts,
transport.output(),
]
)
runner = PipelineRunner() task = PipelineTask(
pipeline,
params=PipelineParams(allow_interruptions=True),
)
await runner.run(task) @transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected: {client}")
# Welcome message
await tts.say("Hi there! Feel free to ask me what I see.")
# Set the participant ID in the image requester
image_requester.set_participant_id(webrtc_peer_id)
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,33 +4,29 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
from typing import Optional from typing import Optional
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.aggregators.user_response import UserResponseAggregator from pipecat.processors.aggregators.user_response import UserResponseAggregator
from pipecat.processors.aggregators.vision_image_frame import VisionImageFrameAggregator from pipecat.processors.aggregators.vision_image_frame import VisionImageFrameAggregator
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
class UserImageRequester(FrameProcessor): class UserImageRequester(FrameProcessor):
def __init__(self, participant_id: Optional[str] = None): def __init__(self, participant_id: Optional[str] = None):
@@ -50,60 +46,84 @@ class UserImageRequester(FrameProcessor):
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: # Get WebRTC peer connection ID
(room_url, token) = await configure(session) webrtc_peer_id = webrtc_connection.pc_id
transport = DailyTransport( logger.info(f"Starting bot with peer_id: {webrtc_peer_id}")
room_url,
token,
"Describe participant video",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
user_response = UserResponseAggregator() transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
camera_in_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
image_requester = UserImageRequester() user_response = UserResponseAggregator()
vision_aggregator = VisionImageFrameAggregator() # Initialize the image requester without setting the participant ID yet
image_requester = UserImageRequester()
openai = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") vision_aggregator = VisionImageFrameAggregator()
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
@transport.event_handler("on_first_participant_joined") # OpenAI GPT-4o for vision analysis
async def on_first_participant_joined(transport, participant): openai = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
await tts.say("Hi there! Feel free to ask me what I see.")
await transport.capture_participant_video(participant["id"], framerate=0)
await transport.capture_participant_transcription(participant["id"])
image_requester.set_participant_id(participant["id"])
pipeline = Pipeline( tts = CartesiaTTSService(
[ api_key=os.getenv("CARTESIA_API_KEY"),
transport.input(), voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
user_response, )
image_requester,
vision_aggregator,
openai,
tts,
transport.output(),
]
)
task = PipelineTask(pipeline) pipeline = Pipeline(
[
transport.input(),
stt,
user_response,
image_requester,
vision_aggregator,
openai,
tts,
transport.output(),
]
)
runner = PipelineRunner() task = PipelineTask(
pipeline,
params=PipelineParams(allow_interruptions=True),
)
await runner.run(task) @transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected: {client}")
# Welcome message
await tts.say("Hi there! Feel free to ask me what I see.")
# Set the participant ID in the image requester
image_requester.set_participant_id(webrtc_peer_id)
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,33 +4,29 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
from typing import Optional from typing import Optional
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.aggregators.user_response import UserResponseAggregator from pipecat.processors.aggregators.user_response import UserResponseAggregator
from pipecat.processors.aggregators.vision_image_frame import VisionImageFrameAggregator from pipecat.processors.aggregators.vision_image_frame import VisionImageFrameAggregator
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.services.anthropic.llm import AnthropicLLMService from pipecat.services.anthropic.llm import AnthropicLLMService
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
class UserImageRequester(FrameProcessor): class UserImageRequester(FrameProcessor):
def __init__(self, participant_id: Optional[str] = None): def __init__(self, participant_id: Optional[str] = None):
@@ -50,60 +46,84 @@ class UserImageRequester(FrameProcessor):
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: # Get WebRTC peer connection ID
(room_url, token) = await configure(session) webrtc_peer_id = webrtc_connection.pc_id
transport = DailyTransport( logger.info(f"Starting bot with peer_id: {webrtc_peer_id}")
room_url,
token,
"Describe participant video",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
user_response = UserResponseAggregator() transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
camera_in_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
image_requester = UserImageRequester() user_response = UserResponseAggregator()
vision_aggregator = VisionImageFrameAggregator() # Initialize the image requester without setting the participant ID yet
image_requester = UserImageRequester()
anthropic = AnthropicLLMService(api_key=os.getenv("ANTHROPIC_API_KEY")) vision_aggregator = VisionImageFrameAggregator()
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
@transport.event_handler("on_first_participant_joined") # Anthropic for vision analysis
async def on_first_participant_joined(transport, participant): anthropic = AnthropicLLMService(api_key=os.getenv("ANTHROPIC_API_KEY"))
await tts.say("Hi there! Feel free to ask me what I see.")
await transport.capture_participant_video(participant["id"], framerate=0)
await transport.capture_participant_transcription(participant["id"])
image_requester.set_participant_id(participant["id"])
pipeline = Pipeline( tts = CartesiaTTSService(
[ api_key=os.getenv("CARTESIA_API_KEY"),
transport.input(), voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
user_response, )
image_requester,
vision_aggregator,
anthropic,
tts,
transport.output(),
]
)
task = PipelineTask(pipeline) pipeline = Pipeline(
[
transport.input(),
stt,
user_response,
image_requester,
vision_aggregator,
anthropic,
tts,
transport.output(),
]
)
runner = PipelineRunner() task = PipelineTask(
pipeline,
params=PipelineParams(allow_interruptions=True),
)
await runner.run(task) @transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected: {client}")
# Welcome message
await tts.say("Hi there! Feel free to ask me what I see.")
# Set the participant ID in the image requester
image_requester.set_participant_id(webrtc_peer_id)
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,13 +4,9 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import Frame, TranscriptionFrame from pipecat.frames.frames import Frame, TranscriptionFrame
@@ -19,13 +15,12 @@ from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineTask
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.services.whisper.stt import WhisperSTTService from pipecat.services.whisper.stt import WhisperSTTService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
class TranscriptionLogger(FrameProcessor): class TranscriptionLogger(FrameProcessor):
async def process_frame(self, frame: Frame, direction: FrameDirection): async def process_frame(self, frame: Frame, direction: FrameDirection):
@@ -35,34 +30,42 @@ class TranscriptionLogger(FrameProcessor):
print(f"Transcription: {frame.text}") print(f"Transcription: {frame.text}")
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, _) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
None, params=TransportParams(
"Transcription bot", audio_in_enabled=True,
DailyParams( vad_enabled=True,
audio_in_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
vad_audio_passthrough=True, )
),
)
stt = WhisperSTTService() stt = WhisperSTTService()
tl = TranscriptionLogger() tl = TranscriptionLogger()
pipeline = Pipeline([transport.input(), stt, tl]) pipeline = Pipeline([transport.input(), stt, tl])
task = PipelineTask(pipeline) task = PipelineTask(pipeline)
runner = PipelineRunner() @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
await runner.run(task) @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,11 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os
import sys
import aiohttp import os
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import Frame, TranscriptionFrame from pipecat.frames.frames import Frame, TranscriptionFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -19,13 +16,12 @@ from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineTask
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.services.deepgram.stt import DeepgramSTTService, Language, LiveOptions from pipecat.services.deepgram.stt import DeepgramSTTService, Language, LiveOptions
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
class TranscriptionLogger(FrameProcessor): class TranscriptionLogger(FrameProcessor):
async def process_frame(self, frame: Frame, direction: FrameDirection): async def process_frame(self, frame: Frame, direction: FrameDirection):
@@ -35,29 +31,40 @@ class TranscriptionLogger(FrameProcessor):
print(f"Transcription: {frame.text}") print(f"Transcription: {frame.text}")
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, _) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, None, "Transcription bot", DailyParams(audio_in_enabled=True) webrtc_connection=webrtc_connection,
) params=TransportParams(audio_in_enabled=True),
)
stt = DeepgramSTTService( stt = DeepgramSTTService(
api_key=os.getenv("DEEPGRAM_API_KEY"), api_key=os.getenv("DEEPGRAM_API_KEY"),
# live_options=LiveOptions(language=Language.FR), live_options=LiveOptions(language=Language.EN),
) )
tl = TranscriptionLogger() tl = TranscriptionLogger()
pipeline = Pipeline([transport.input(), stt, tl]) pipeline = Pipeline([transport.input(), stt, tl])
task = PipelineTask(pipeline) task = PipelineTask(pipeline)
runner = PipelineRunner() @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
await runner.run(task) @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import Frame, TranscriptionFrame from pipecat.frames.frames import Frame, TranscriptionFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -19,13 +15,12 @@ from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineTask
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.services.gladia import GladiaSTTService from pipecat.services.gladia import GladiaSTTService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
class TranscriptionLogger(FrameProcessor): class TranscriptionLogger(FrameProcessor):
async def process_frame(self, frame: Frame, direction: FrameDirection): async def process_frame(self, frame: Frame, direction: FrameDirection):
@@ -35,29 +30,40 @@ class TranscriptionLogger(FrameProcessor):
print(f"Transcription: {frame.text}") print(f"Transcription: {frame.text}")
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, _) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, None, "Transcription bot", DailyParams(audio_in_enabled=True) webrtc_connection=webrtc_connection,
) params=TransportParams(audio_in_enabled=True),
)
stt = GladiaSTTService( stt = GladiaSTTService(
api_key=os.getenv("GLADIA_API_KEY"), api_key=os.getenv("GLADIA_API_KEY"),
# live_options=LiveOptions(language=Language.FR), # live_options=LiveOptions(language=Language.FR),
) )
tl = TranscriptionLogger() tl = TranscriptionLogger()
pipeline = Pipeline([transport.input(), stt, tl]) pipeline = Pipeline([transport.input(), stt, tl])
task = PipelineTask(pipeline) task = PipelineTask(pipeline)
runner = PipelineRunner() @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
await runner.run(task) @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.frames.frames import Frame, TranscriptionFrame from pipecat.frames.frames import Frame, TranscriptionFrame
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -19,13 +15,12 @@ from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineTask
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.services.assemblyai.stt import AssemblyAISTTService from pipecat.services.assemblyai.stt import AssemblyAISTTService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
class TranscriptionLogger(FrameProcessor): class TranscriptionLogger(FrameProcessor):
async def process_frame(self, frame: Frame, direction: FrameDirection): async def process_frame(self, frame: Frame, direction: FrameDirection):
@@ -35,28 +30,39 @@ class TranscriptionLogger(FrameProcessor):
print(f"Transcription: {frame.text}") print(f"Transcription: {frame.text}")
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, _) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, None, "Transcription bot", DailyParams(audio_in_enabled=True) webrtc_connection=webrtc_connection,
) params=TransportParams(audio_in_enabled=True),
)
stt = AssemblyAISTTService( stt = AssemblyAISTTService(
api_key=os.getenv("ASSEMBLYAI_API_KEY"), api_key=os.getenv("ASSEMBLYAI_API_KEY"),
) )
tl = TranscriptionLogger() tl = TranscriptionLogger()
pipeline = Pipeline([transport.input(), stt, tl]) pipeline = Pipeline([transport.input(), stt, tl])
task = PipelineTask(pipeline) task = PipelineTask(pipeline)
runner = PipelineRunner() @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
await runner.run(task) @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,11 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import sys
import time import time
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.audio.vad.vad_analyzer import VADParams
@@ -21,13 +18,12 @@ from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.services.whisper.stt import MLXModel, WhisperSTTServiceMLX from pipecat.services.whisper.stt import MLXModel, WhisperSTTServiceMLX
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
STOP_SECS = 2.0 STOP_SECS = 2.0
@@ -56,40 +52,48 @@ class TranscriptionLogger(FrameProcessor):
self._last_transcription_time = time.time() self._last_transcription_time = time.time()
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, _) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
None, params=TransportParams(
"Transcription bot", audio_in_enabled=True,
DailyParams( vad_enabled=True,
audio_in_enabled=True, vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=STOP_SECS)),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=STOP_SECS)), ),
vad_audio_passthrough=True, )
),
)
stt = WhisperSTTServiceMLX(model=MLXModel.LARGE_V3_TURBO) stt = WhisperSTTServiceMLX(model=MLXModel.LARGE_V3_TURBO)
tl = TranscriptionLogger() tl = TranscriptionLogger()
pipeline = Pipeline([transport.input(), stt, tl]) pipeline = Pipeline([transport.input(), stt, tl])
task = PipelineTask( task = PipelineTask(
pipeline, pipeline,
params=PipelineParams( params=PipelineParams(
enable_metrics=True, enable_metrics=True,
report_only_initial_ttfb=False, report_only_initial_ttfb=False,
), ),
) )
runner = PipelineRunner() @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
await runner.run(task) @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -22,106 +18,118 @@ 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.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
await llm.push_frame(TTSSpeakFrame("Let me check on that.")) await llm.push_frame(TTSSpeakFrame("Let me check on that."))
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
# You can also register a function_name of None to get all functions llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
# sent to the same callback with an additional function_name parameter.
llm.register_function("get_current_weather", fetch_weather_from_api)
weather_function = FunctionSchema( # You can also register a function_name of None to get all functions
name="get_current_weather", # sent to the same callback with an additional function_name parameter.
description="Get the current weather", llm.register_function("get_current_weather", fetch_weather_from_api)
properties={
"location": { weather_function = FunctionSchema(
"type": "string", name="get_current_weather",
"description": "The city and state, e.g. San Francisco, CA", description="Get the current weather",
}, properties={
"format": { "location": {
"type": "string", "type": "string",
"enum": ["celsius", "fahrenheit"], "description": "The city and state, e.g. San Francisco, CA",
"description": "The temperature unit to use. Infer this from the user's location.",
},
}, },
required=["location", "format"], "format": {
) "type": "string",
tools = ToolsSchema(standard_tools=[weather_function]) "enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the user's location.",
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.",
}, },
},
required=["location", "format"],
)
tools = ToolsSchema(standard_tools=[weather_function])
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, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -22,99 +18,111 @@ 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.anthropic.llm import AnthropicLLMService from pipecat.services.anthropic.llm import AnthropicLLMService
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def get_weather(function_name, tool_call_id, arguments, llm, context, result_callback): async def get_weather(function_name, tool_call_id, arguments, llm, context, result_callback):
location = arguments["location"] location = arguments["location"]
await result_callback(f"The weather in {location} is currently 72 degrees and sunny.") await result_callback(f"The weather in {location} is currently 72 degrees and sunny.")
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = AnthropicLLMService( tts = CartesiaTTSService(
api_key=os.getenv("ANTHROPIC_API_KEY"), model="claude-3-7-sonnet-latest" api_key=os.getenv("CARTESIA_API_KEY"),
) voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
llm.register_function("get_weather", get_weather) )
weather_function = FunctionSchema( llm = AnthropicLLMService(
name="get_weather", api_key=os.getenv("ANTHROPIC_API_KEY"), model="claude-3-7-sonnet-latest"
description="Get the current weather", )
properties={ llm.register_function("get_weather", get_weather)
"location": {
"type": "string", weather_function = FunctionSchema(
"description": "The city and state, e.g. San Francisco, CA", name="get_weather",
}, description="Get the current weather",
properties={
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}, },
required=["location"], },
) required=["location"],
tools = ToolsSchema(standard_tools=[weather_function]) )
tools = ToolsSchema(standard_tools=[weather_function])
# todo: test with very short initial user message # todo: test with very short initial user message
# messages = [{"role": "system", # messages = [{"role": "system",
# "content": "You are a helpful assistant who can report the weather in any location in the universe. Respond concisely. Your response will be turned into speech so use only simple words and punctuation."}, # "content": "You are a helpful assistant who can report the weather in any location in the universe. Respond concisely. Your response will be turned into speech so use only simple words and punctuation."},
# {"role": "user", # {"role": "user",
# "content": " Start the conversation by introducing yourself."}] # "content": " Start the conversation by introducing yourself."}]
messages = [{"role": "user", "content": "Say 'hello' to start the conversation."}] messages = [{"role": "user", "content": "Say 'hello' to start the conversation."}]
context = OpenAILLMContext(messages, tools) context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context) context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline( pipeline = Pipeline(
[ [
transport.input(), # Transport user input transport.input(), # Transport user input
context_aggregator.user(), # User spoken responses stt,
llm, # LLM context_aggregator.user(), # User spoken responses
tts, # TTS llm, # LLM
transport.output(), # Transport bot output tts, # TTS
context_aggregator.assistant(), # Assistant spoken responses and tool context transport.output(), # Transport bot output
] context_aggregator.assistant(), # Assistant spoken responses and tool context
) ]
)
task = PipelineTask( task = PipelineTask(
pipeline, pipeline,
params=PipelineParams( params=PipelineParams(
allow_interruptions=True, allow_interruptions=True,
enable_metrics=True, enable_metrics=True,
), ),
) )
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_connected")
async def on_first_participant_joined(transport, participant): async def on_client_connected(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client connected")
# Kick off the conversation. # Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()]) await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
await runner.run(task) @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -6,12 +6,9 @@
import asyncio import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -22,14 +19,16 @@ 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.anthropic.llm import AnthropicLLMService from pipecat.services.anthropic.llm import AnthropicLLMService
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
video_participant_id = None # Global variable to store the peer connection ID
webrtc_peer_id = None
async def get_weather(function_name, tool_call_id, arguments, llm, context, result_callback): async def get_weather(function_name, tool_call_id, arguments, llm, context, result_callback):
@@ -39,72 +38,83 @@ async def get_weather(function_name, tool_call_id, arguments, llm, context, resu
async def get_image(function_name, tool_call_id, arguments, llm, context, result_callback): async def get_image(function_name, tool_call_id, arguments, llm, context, result_callback):
question = arguments["question"] question = arguments["question"]
logger.debug(f"Requesting image with user_id={webrtc_peer_id}, question={question}")
# Request the image frame
await llm.request_image_frame( await llm.request_image_frame(
user_id=video_participant_id, user_id=webrtc_peer_id,
function_name=function_name, function_name=function_name,
tool_call_id=tool_call_id, tool_call_id=tool_call_id,
text_content=question, text_content=question,
) )
# Wait a short time for the frame to be processed
await asyncio.sleep(0.5)
async def main(): # Return a result to complete the function call
global llm await result_callback(
f"I've captured an image from your camera and I'm analyzing what you asked about: {question}"
)
async with aiohttp.ClientSession() as session:
(room_url, token) = await configure(session)
transport = DailyTransport( async def run_bot(webrtc_connection: SmallWebRTCConnection):
room_url, global webrtc_peer_id
token, webrtc_peer_id = webrtc_connection.pc_id
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = CartesiaTTSService( logger.info(f"Starting bot with peer_id: {webrtc_peer_id}")
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = AnthropicLLMService( transport = SmallWebRTCTransport(
api_key=os.getenv("ANTHROPIC_API_KEY"), webrtc_connection=webrtc_connection,
model="claude-3-7-sonnet-latest", params=TransportParams(
enable_prompt_caching_beta=True, audio_in_enabled=True,
) audio_out_enabled=True,
llm.register_function("get_weather", get_weather) camera_in_enabled=True, # Make sure camera input is enabled
llm.register_function("get_image", get_image) vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
weather_function = FunctionSchema( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
name="get_weather",
description="Get the current weather", tts = CartesiaTTSService(
properties={ api_key=os.getenv("CARTESIA_API_KEY"),
"location": { voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
"type": "string", )
"description": "The city and state, e.g. San Francisco, CA",
}, llm = AnthropicLLMService(
api_key=os.getenv("ANTHROPIC_API_KEY"),
model="claude-3-7-sonnet-latest",
enable_prompt_caching_beta=True,
)
llm.register_function("get_weather", get_weather)
llm.register_function("get_image", get_image)
weather_function = FunctionSchema(
name="get_weather",
description="Get the current weather",
properties={
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}, },
required=["location"], },
) required=["location"],
get_image_function = FunctionSchema( )
name="get_image", get_image_function = FunctionSchema(
description="Get an image from the video stream.", name="get_image",
properties={ description="Get an image from the video stream.",
"question": { properties={
"type": "string", "question": {
"description": "The question that the user is asking about the image.", "type": "string",
} "description": "The question that the user is asking about the image.",
}, }
required=["question"], },
) required=["question"],
tools = ToolsSchema(standard_tools=[weather_function, get_image_function]) )
tools = ToolsSchema(standard_tools=[weather_function, get_image_function])
# todo: test with very short initial user message system_prompt = """\
system_prompt = """\
You are a helpful assistant who converses with a user and answers questions. Respond concisely to general questions. You are a helpful assistant who converses with a user and answers questions. Respond concisely to general questions.
Your response will be turned into speech so use only simple words and punctuation. Your response will be turned into speech so use only simple words and punctuation.
@@ -115,63 +125,73 @@ You can respond to questions about the weather using the get_weather tool.
You can answer questions about the user's video stream using the get_image tool. Some examples of phrases that \ You can answer questions about the user's video stream using the get_image tool. Some examples of phrases that \
indicate you should use the get_image tool are: indicate you should use the get_image tool are:
- What do you see? - What do you see?
- What's in the video? - What's in the video?
- Can you describe the video? - Can you describe the video?
- Tell me about what you see. - Tell me about what you see.
- Tell me something interesting about what you see. - Tell me something interesting about what you see.
- What's happening in the video? - What's happening in the video?
If you need to use a tool, simply use the tool. Do not tell the user the tool you are using. Be brief and concise. If you need to use a tool, simply use the tool. Do not tell the user the tool you are using. Be brief and concise.
""" """
messages = [ messages = [
{ {
"role": "system", "role": "system",
"content": [ "content": [
{ {
"type": "text", "type": "text",
"text": system_prompt, "text": system_prompt,
} }
], ],
}, },
{"role": "user", "content": "Start the conversation by introducing yourself."}, {"role": "user", "content": "Start the conversation by introducing yourself."},
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User speech to text
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses and tool context
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), # Transport user input logger.info(f"Client connected: {client}")
context_aggregator.user(), # User speech to text # Kick off the conversation.
llm, # LLM await task.queue_frames([context_aggregator.user().get_context_frame()])
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses and tool context
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
global video_participant_id logger.info(f"Client closed connection")
video_participant_id = participant["id"] await task.cancel()
await transport.capture_participant_transcription(video_participant_id)
await transport.capture_participant_video(video_participant_id, framerate=0)
# Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -22,99 +18,111 @@ from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineTask
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.together.llm import TogetherLLMService from pipecat.services.together.llm import TogetherLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
await llm.push_frame(TTSSpeakFrame("Let me check on that.")) await llm.push_frame(TTSSpeakFrame("Let me check on that."))
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = TogetherLLMService( tts = CartesiaTTSService(
api_key=os.getenv("TOGETHER_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
model="meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo", voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
) )
# You can also register a function_name of None to get all functions
# sent to the same callback with an additional function_name parameter.
llm.register_function("get_current_weather", fetch_weather_from_api)
weather_function = FunctionSchema( llm = TogetherLLMService(
name="get_current_weather", api_key=os.getenv("TOGETHER_API_KEY"),
description="Get the current weather", model="meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo",
properties={ )
"location": { # You can also register a function_name of None to get all functions
"type": "string", # sent to the same callback with an additional function_name parameter.
"description": "The city and state, e.g. San Francisco, CA", llm.register_function("get_current_weather", fetch_weather_from_api)
},
"format": { weather_function = FunctionSchema(
"type": "string", name="get_current_weather",
"enum": ["celsius", "fahrenheit"], description="Get the current weather",
"description": "The temperature unit to use. Infer this from the user's location.", properties={
}, "location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}, },
required=["location", "format"], "format": {
) "type": "string",
tools = ToolsSchema(standard_tools=[weather_function]) "enum": ["celsius", "fahrenheit"],
messages = [ "description": "The temperature unit to use. Infer this from the user's location.",
{
"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.",
}, },
},
required=["location", "format"],
)
tools = ToolsSchema(standard_tools=[weather_function])
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, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(pipeline)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask(pipeline) @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -6,12 +6,9 @@
import asyncio import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -21,15 +18,17 @@ from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineTask
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
video_participant_id = None # Global variable to store the peer connection ID
webrtc_peer_id = None
async def get_weather(function_name, tool_call_id, arguments, llm, context, result_callback): async def get_weather(function_name, tool_call_id, arguments, llm, context, result_callback):
@@ -38,71 +37,85 @@ async def get_weather(function_name, tool_call_id, arguments, llm, context, resu
async def get_image(function_name, tool_call_id, arguments, llm, context, result_callback): async def get_image(function_name, tool_call_id, arguments, llm, context, result_callback):
logger.debug(f"!!! IN get_image {video_participant_id}, {arguments}")
question = arguments["question"] question = arguments["question"]
logger.debug(f"Requesting image with user_id={webrtc_peer_id}, question={question}")
# Request the image frame
await llm.request_image_frame( await llm.request_image_frame(
user_id=video_participant_id, user_id=webrtc_peer_id,
function_name=function_name, function_name=function_name,
tool_call_id=tool_call_id, tool_call_id=tool_call_id,
text_content=question, text_content=question,
) )
# Wait a short time for the frame to be processed
await asyncio.sleep(0.5)
async def main(): # Return a result to complete the function call
async with aiohttp.ClientSession() as session: await result_callback(
(room_url, token) = await configure(session) f"I've captured an image from your camera and I'm analyzing what you asked about: {question}"
)
transport = DailyTransport(
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = CartesiaTTSService( async def run_bot(webrtc_connection: SmallWebRTCConnection):
api_key=os.getenv("CARTESIA_API_KEY"), global webrtc_peer_id
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady webrtc_peer_id = webrtc_connection.pc_id
)
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") logger.info(f"Starting bot with peer_id: {webrtc_peer_id}")
llm.register_function("get_weather", get_weather)
llm.register_function("get_image", get_image)
weather_function = FunctionSchema( transport = SmallWebRTCTransport(
name="get_weather", webrtc_connection=webrtc_connection,
description="Get the current weather", params=TransportParams(
properties={ audio_in_enabled=True,
"location": { audio_out_enabled=True,
"type": "string", camera_in_enabled=True, # Make sure camera input is enabled
"description": "The city and state, e.g. San Francisco, CA", vad_enabled=True,
}, vad_analyzer=SileroVADAnalyzer(),
"format": { vad_audio_passthrough=True,
"type": "string", ),
"enum": ["celsius", "fahrenheit"], )
"description": "The temperature unit to use. Infer this from the user's location.",
}, stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
llm.register_function("get_weather", get_weather)
llm.register_function("get_image", get_image)
weather_function = FunctionSchema(
name="get_weather",
description="Get the current weather",
properties={
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}, },
required=["location"], "format": {
) "type": "string",
get_image_function = FunctionSchema( "enum": ["celsius", "fahrenheit"],
name="get_image", "description": "The temperature unit to use. Infer this from the user's location.",
description="Get an image from the video stream.",
properties={
"question": {
"type": "string",
"description": "The question that the user is asking about the image.",
}
}, },
required=["question"], },
) required=["location"],
tools = ToolsSchema(standard_tools=[weather_function, get_image_function]) )
get_image_function = FunctionSchema(
name="get_image",
description="Get an image from the video stream.",
properties={
"question": {
"type": "string",
"description": "The question that the user is asking about the image.",
}
},
required=["question"],
)
tools = ToolsSchema(standard_tools=[weather_function, get_image_function])
system_prompt = """\ system_prompt = """\
You are a helpful assistant who converses with a user and answers questions. Respond concisely to general questions. You are a helpful assistant who converses with a user and answers questions. Respond concisely to general questions.
Your response will be turned into speech so use only simple words and punctuation. Your response will be turned into speech so use only simple words and punctuation.
@@ -113,46 +126,55 @@ You can respond to questions about the weather using the get_weather tool.
You can answer questions about the user's video stream using the get_image tool. Some examples of phrases that \ You can answer questions about the user's video stream using the get_image tool. Some examples of phrases that \
indicate you should use the get_image tool are: indicate you should use the get_image tool are:
- What do you see? - What do you see?
- What's in the video? - What's in the video?
- Can you describe the video? - Can you describe the video?
- Tell me about what you see. - Tell me about what you see.
- Tell me something interesting about what you see. - Tell me something interesting about what you see.
- What's happening in the video? - What's happening in the video?
""" """
messages = [ messages = [
{"role": "system", "content": system_prompt}, {"role": "system", "content": system_prompt},
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(pipeline)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask(pipeline) @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
global video_participant_id logger.info(f"Client closed connection")
video_participant_id = participant["id"] await task.cancel()
await transport.capture_participant_transcription(participant["id"])
await transport.capture_participant_video(video_participant_id, framerate=0)
# Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -6,12 +6,9 @@
import asyncio import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -22,15 +19,17 @@ 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.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.google.llm import GoogleLLMService from pipecat.services.google.llm import GoogleLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
video_participant_id = None # Global variable to store the peer connection ID
webrtc_peer_id = None
async def get_weather(function_name, tool_call_id, arguments, llm, context, result_callback): async def get_weather(function_name, tool_call_id, arguments, llm, context, result_callback):
@@ -40,71 +39,85 @@ async def get_weather(function_name, tool_call_id, arguments, llm, context, resu
async def get_image(function_name, tool_call_id, arguments, llm, context, result_callback): async def get_image(function_name, tool_call_id, arguments, llm, context, result_callback):
logger.debug(f"!!! IN get_image {video_participant_id}, {arguments}")
question = arguments["question"] question = arguments["question"]
logger.debug(f"Requesting image with user_id={webrtc_peer_id}, question={question}")
# Request the image frame
await llm.request_image_frame( await llm.request_image_frame(
user_id=video_participant_id, user_id=webrtc_peer_id,
function_name=function_name, function_name=function_name,
tool_call_id=tool_call_id, tool_call_id=tool_call_id,
text_content=question, text_content=question,
) )
# Wait a short time for the frame to be processed
await asyncio.sleep(0.5)
async def main(): # Return a result to complete the function call
async with aiohttp.ClientSession() as session: await result_callback(
(room_url, token) = await configure(session) f"I've captured an image from your camera and I'm analyzing what you asked about: {question}"
)
transport = DailyTransport(
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = CartesiaTTSService( async def run_bot(webrtc_connection: SmallWebRTCConnection):
api_key=os.getenv("CARTESIA_API_KEY"), global webrtc_peer_id
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady webrtc_peer_id = webrtc_connection.pc_id
)
llm = GoogleLLMService(api_key=os.getenv("GOOGLE_API_KEY"), model="gemini-2.0-flash-001") logger.info(f"Starting bot with peer_id: {webrtc_peer_id}")
llm.register_function("get_weather", get_weather)
llm.register_function("get_image", get_image)
weather_function = FunctionSchema( transport = SmallWebRTCTransport(
name="get_weather", webrtc_connection=webrtc_connection,
description="Get the current weather", params=TransportParams(
properties={ audio_in_enabled=True,
"location": { audio_out_enabled=True,
"type": "string", camera_in_enabled=True, # Make sure camera input is enabled
"description": "The city and state, e.g. San Francisco, CA", vad_enabled=True,
}, vad_analyzer=SileroVADAnalyzer(),
"format": { vad_audio_passthrough=True,
"type": "string", ),
"enum": ["celsius", "fahrenheit"], )
"description": "The temperature unit to use. Infer this from the user's location.",
}, stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = GoogleLLMService(api_key=os.getenv("GOOGLE_API_KEY"), model="gemini-2.0-flash-001")
llm.register_function("get_weather", get_weather)
llm.register_function("get_image", get_image)
weather_function = FunctionSchema(
name="get_weather",
description="Get the current weather",
properties={
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}, },
required=["location", "format"], "format": {
) "type": "string",
get_image_function = FunctionSchema( "enum": ["celsius", "fahrenheit"],
name="get_image", "description": "The temperature unit to use. Infer this from the user's location.",
description="Get an image from the video stream.",
properties={
"question": {
"type": "string",
"description": "The question that the user is asking about the image.",
}
}, },
required=["question"], },
) required=["location", "format"],
tools = ToolsSchema(standard_tools=[weather_function, get_image_function]) )
get_image_function = FunctionSchema(
name="get_image",
description="Get an image from the video stream.",
properties={
"question": {
"type": "string",
"description": "The question that the user is asking about the image.",
}
},
required=["question"],
)
tools = ToolsSchema(standard_tools=[weather_function, get_image_function])
system_prompt = """\ system_prompt = """\
You are a helpful assistant who converses with a user and answers questions. Respond concisely to general questions. You are a helpful assistant who converses with a user and answers questions. Respond concisely to general questions.
Your response will be turned into speech so use only simple words and punctuation. Your response will be turned into speech so use only simple words and punctuation.
@@ -115,54 +128,63 @@ You can respond to questions about the weather using the get_weather tool.
You can answer questions about the user's video stream using the get_image tool. Some examples of phrases that \ You can answer questions about the user's video stream using the get_image tool. Some examples of phrases that \
indicate you should use the get_image tool are: indicate you should use the get_image tool are:
- What do you see? - What do you see?
- What's in the video? - What's in the video?
- Can you describe the video? - Can you describe the video?
- Tell me about what you see. - Tell me about what you see.
- Tell me something interesting about what you see. - Tell me something interesting about what you see.
- What's happening in the video? - What's happening in the video?
""" """
messages = [ messages = [
{"role": "system", "content": system_prompt}, {"role": "system", "content": system_prompt},
{"role": "user", "content": "Say hello."}, {"role": "user", "content": "Say hello."},
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected: {client}")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
global video_participant_id logger.info(f"Client closed connection")
video_participant_id = participant["id"] await task.cancel()
await transport.capture_participant_transcription(participant["id"])
await transport.capture_participant_video(video_participant_id, framerate=0)
# Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -24,105 +20,113 @@ from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.groq.llm import GroqLLMService from pipecat.services.groq.llm import GroqLLMService
from pipecat.services.groq.stt import GroqSTTService from pipecat.services.groq.stt import GroqSTTService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
await llm.push_frame(TTSSpeakFrame("Let me check on that.")) await llm.push_frame(TTSSpeakFrame("Let me check on that."))
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
vad_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_analyzer=SileroVADAnalyzer(), vad_audio_passthrough=True,
vad_audio_passthrough=True, ),
), )
)
stt = GroqSTTService(api_key=os.getenv("GROQ_API_KEY"), model="distil-whisper-large-v3-en") stt = GroqSTTService(api_key=os.getenv("GROQ_API_KEY"), model="distil-whisper-large-v3-en")
tts = CartesiaTTSService( tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
) )
llm = GroqLLMService(api_key=os.getenv("GROQ_API_KEY"), model="llama-3.3-70b-versatile") llm = GroqLLMService(api_key=os.getenv("GROQ_API_KEY"), model="llama-3.3-70b-versatile")
# You can also register a function_name of None to get all functions # You can also register a function_name of None to get all functions
# sent to the same callback with an additional function_name parameter. # sent to the same callback with an additional function_name parameter.
llm.register_function("get_current_weather", fetch_weather_from_api) llm.register_function("get_current_weather", fetch_weather_from_api)
weather_function = FunctionSchema( weather_function = FunctionSchema(
name="get_current_weather", name="get_current_weather",
description="Get the current weather", description="Get the current weather",
properties={ properties={
"location": { "location": {
"type": "string", "type": "string",
"description": "The city and state, e.g. San Francisco, CA", "description": "The city and state, e.g. San Francisco, CA",
},
"format": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the user's location.",
},
}, },
required=["location"], "format": {
) "type": "string",
tools = ToolsSchema(standard_tools=[weather_function]) "enum": ["celsius", "fahrenheit"],
messages = [ "description": "The temperature unit to use. Infer this from the user's location.",
{
"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.",
}, },
},
required=["location"],
)
tools = ToolsSchema(standard_tools=[weather_function])
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, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
stt, # Kick off the conversation.
context_aggregator.user(), await task.queue_frames([context_aggregator.user().get_context_frame()])
llm,
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -21,102 +17,114 @@ 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.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.grok.llm import GrokLLMService from pipecat.services.grok.llm import GrokLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = GrokLLMService(api_key=os.getenv("GROK_API_KEY")) tts = CartesiaTTSService(
# You can also register a function_name of None to get all functions api_key=os.getenv("CARTESIA_API_KEY"),
# sent to the same callback with an additional function_name parameter. voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
llm.register_function("get_current_weather", fetch_weather_from_api) )
weather_function = FunctionSchema( llm = GrokLLMService(api_key=os.getenv("GROK_API_KEY"))
name="get_current_weather", # You can also register a function_name of None to get all functions
description="Get the current weather", # sent to the same callback with an additional function_name parameter.
properties={ llm.register_function("get_current_weather", fetch_weather_from_api)
"location": {
"type": "string", weather_function = FunctionSchema(
"description": "The city and state, e.g. San Francisco, CA", name="get_current_weather",
}, description="Get the current weather",
"format": { properties={
"type": "string", "location": {
"enum": ["celsius", "fahrenheit"], "type": "string",
"description": "The temperature unit to use. Infer this from the user's location.", "description": "The city and state, e.g. San Francisco, CA",
},
}, },
required=["location", "format"], "format": {
) "type": "string",
tools = ToolsSchema(standard_tools=[weather_function]) "enum": ["celsius", "fahrenheit"],
messages = [ "description": "The temperature unit to use. Infer this from the user's location.",
{
"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.",
}, },
},
required=["location", "format"],
)
tools = ToolsSchema(standard_tools=[weather_function])
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, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -23,106 +19,118 @@ 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.azure.llm import AzureLLMService from pipecat.services.azure.llm import AzureLLMService
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
await llm.push_frame(TTSSpeakFrame("Let me check on that.")) await llm.push_frame(TTSSpeakFrame("Let me check on that."))
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = AzureLLMService( tts = CartesiaTTSService(
api_key=os.getenv("AZURE_CHATGPT_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
endpoint=os.getenv("AZURE_CHATGPT_ENDPOINT"), voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
model=os.getenv("AZURE_CHATGPT_MODEL"), )
)
# You can also register a function_name of None to get all functions
# sent to the same callback with an additional function_name parameter.
llm.register_function("get_current_weather", fetch_weather_from_api)
weather_function = FunctionSchema( llm = AzureLLMService(
name="get_current_weather", api_key=os.getenv("AZURE_CHATGPT_API_KEY"),
description="Get the current weather", endpoint=os.getenv("AZURE_CHATGPT_ENDPOINT"),
properties={ model=os.getenv("AZURE_CHATGPT_MODEL"),
"location": { )
"type": "string", # You can also register a function_name of None to get all functions
"description": "The city and state, e.g. San Francisco, CA", # sent to the same callback with an additional function_name parameter.
}, llm.register_function("get_current_weather", fetch_weather_from_api)
"format": {
"type": "string", weather_function = FunctionSchema(
"enum": ["celsius", "fahrenheit"], name="get_current_weather",
"description": "The temperature unit to use. Infer this from the user's location.", description="Get the current weather",
}, properties={
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}, },
required=["location", "format"], "format": {
) "type": "string",
tools = ToolsSchema(standard_tools=[weather_function]) "enum": ["celsius", "fahrenheit"],
messages = [ "description": "The temperature unit to use. Infer this from the user's location.",
{
"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.",
}, },
},
required=["location", "format"],
)
tools = ToolsSchema(standard_tools=[weather_function])
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, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -22,106 +18,118 @@ 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.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.fireworks.llm import FireworksLLMService from pipecat.services.fireworks.llm import FireworksLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
await llm.push_frame(TTSSpeakFrame("Let me check on that.")) await llm.push_frame(TTSSpeakFrame("Let me check on that."))
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = FireworksLLMService( tts = CartesiaTTSService(
api_key=os.getenv("FIREWORKS_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
model="accounts/fireworks/models/llama-v3p1-405b-instruct", voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
) )
# You can also register a function_name of None to get all functions
# sent to the same callback with an additional function_name parameter.
llm.register_function("get_current_weather", fetch_weather_from_api)
weather_function = FunctionSchema( llm = FireworksLLMService(
name="get_current_weather", api_key=os.getenv("FIREWORKS_API_KEY"),
description="Get the current weather", model="accounts/fireworks/models/llama-v3p1-405b-instruct",
properties={ )
"location": { # You can also register a function_name of None to get all functions
"type": "string", # sent to the same callback with an additional function_name parameter.
"description": "The city and state, e.g. San Francisco, CA", llm.register_function("get_current_weather", fetch_weather_from_api)
},
"format": { weather_function = FunctionSchema(
"type": "string", name="get_current_weather",
"enum": ["celsius", "fahrenheit"], description="Get the current weather",
"description": "The temperature unit to use. Infer this from the user's location.", properties={
}, "location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}, },
required=["location", "format"], "format": {
) "type": "string",
tools = ToolsSchema(standard_tools=[weather_function]) "enum": ["celsius", "fahrenheit"],
messages = [ "description": "The temperature unit to use. Infer this from the user's location.",
{
"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.",
}, },
},
required=["location", "format"],
)
tools = ToolsSchema(standard_tools=[weather_function])
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, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -22,106 +18,116 @@ 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.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.nim.llm import NimLLMService from pipecat.services.nim.llm import NimLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
await llm.push_frame(TTSSpeakFrame("Let me check on that.")) await llm.push_frame(TTSSpeakFrame("Let me check on that."))
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
# text_filters=[MarkdownTextFilter()],
)
llm = NimLLMService( tts = CartesiaTTSService(
api_key=os.getenv("NVIDIA_API_KEY"), model="meta/llama-3.3-70b-instruct" api_key=os.getenv("CARTESIA_API_KEY"),
) voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
# You can also register a function_name of None to get all functions # text_filters=[MarkdownTextFilter()],
# sent to the same callback with an additional function_name parameter. )
llm.register_function("get_current_weather", fetch_weather_from_api)
weather_function = FunctionSchema( llm = NimLLMService(api_key=os.getenv("NVIDIA_API_KEY"), model="meta/llama-3.3-70b-instruct")
name="get_current_weather", # You can also register a function_name of None to get all functions
description="Get the current weather", # sent to the same callback with an additional function_name parameter.
properties={ llm.register_function("get_current_weather", fetch_weather_from_api)
"location": {
"type": "string", weather_function = FunctionSchema(
"description": "The city and state, e.g. San Francisco, CA", name="get_current_weather",
}, description="Get the current weather",
"format": { properties={
"type": "string", "location": {
"enum": ["celsius", "fahrenheit"], "type": "string",
"description": "The temperature unit to use. Infer this from the user's location.", "description": "The city and state, e.g. San Francisco, CA",
},
}, },
required=["location", "format"], "format": {
) "type": "string",
tools = ToolsSchema(standard_tools=[weather_function]) "enum": ["celsius", "fahrenheit"],
messages = [ "description": "The temperature unit to use. Infer this from the user's location.",
{
"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.",
}, },
},
required=["location", "format"],
)
tools = ToolsSchema(standard_tools=[weather_function])
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, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -23,66 +19,66 @@ 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.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.cerebras.llm import CerebrasLLMService from pipecat.services.cerebras.llm import CerebrasLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
await llm.push_frame(TTSSpeakFrame("Let me check on that.")) await llm.push_frame(TTSSpeakFrame("Let me check on that."))
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = CerebrasLLMService(api_key=os.getenv("CEREBRAS_API_KEY"), model="llama-3.3-70b") tts = CartesiaTTSService(
# You can also register a function_name of None to get all functions api_key=os.getenv("CARTESIA_API_KEY"),
# sent to the same callback with an additional function_name parameter. voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
llm.register_function("get_current_weather", fetch_weather_from_api) )
weather_function = FunctionSchema( llm = CerebrasLLMService(api_key=os.getenv("CEREBRAS_API_KEY"), model="llama-3.3-70b")
name="get_current_weather", # You can also register a function_name of None to get all functions
description="Get the current weather", # sent to the same callback with an additional function_name parameter.
properties={ llm.register_function("get_current_weather", fetch_weather_from_api)
"location": {
"type": "string", weather_function = FunctionSchema(
"description": "The city and state, e.g. San Francisco, CA", name="get_current_weather",
}, description="Get the current weather",
"format": { properties={
"type": "string", "location": {
"enum": ["celsius", "fahrenheit"], "type": "string",
"description": "The temperature unit to use. Infer this from the user's location.", "description": "The city and state, e.g. San Francisco, CA",
},
}, },
required=["location", "format"], "format": {
) "type": "string",
tools = ToolsSchema(standard_tools=[weather_function]) "enum": ["celsius", "fahrenheit"],
messages = [ "description": "The temperature unit to use. Infer this from the user's location.",
{ },
"role": "system", },
"content": """You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. required=["location", "format"],
)
tools = ToolsSchema(standard_tools=[weather_function])
messages = [
{
"role": "system",
"content": """You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way.
You have one functions available: You have one functions available:
@@ -92,44 +88,56 @@ Infer whether to use Fahrenheit or Celsius automatically based on the location,
Start by asking me for my location. Then, use 'get_weather_current' to give me a forecast. Start by asking me for my location. Then, use 'get_weather_current' to give me a forecast.
Respond to what the user said in a creative and helpful way.""", Respond to what the user said in a creative and helpful way.""",
}, },
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -22,67 +18,67 @@ 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.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.deepseek.llm import DeepSeekLLMService from pipecat.services.deepseek.llm import DeepSeekLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
await llm.push_frame(TTSSpeakFrame("Let me check on that.")) await llm.push_frame(TTSSpeakFrame("Let me check on that."))
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = DeepSeekLLMService(api_key=os.getenv("DEEPSEEK_API_KEY"), model="deepseek-chat") tts = CartesiaTTSService(
# You can also register a function_name of None to get all functions api_key=os.getenv("CARTESIA_API_KEY"),
# sent to the same callback with an additional function_name parameter. voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
llm.register_function("get_current_weather", fetch_weather_from_api) )
weather_function = FunctionSchema( llm = DeepSeekLLMService(api_key=os.getenv("DEEPSEEK_API_KEY"), model="deepseek-chat")
name="get_current_weather", # You can also register a function_name of None to get all functions
description="Get the current weather", # sent to the same callback with an additional function_name parameter.
properties={ llm.register_function("get_current_weather", fetch_weather_from_api)
"location": {
"type": "string", weather_function = FunctionSchema(
"description": "The city and state, e.g. San Francisco, CA", name="get_current_weather",
}, description="Get the current weather",
"format": { properties={
"type": "string", "location": {
"enum": ["celsius", "fahrenheit"], "type": "string",
"description": "The temperature unit to use. Infer this from the user's location.", "description": "The city and state, e.g. San Francisco, CA",
},
}, },
required=["location", "format"], "format": {
) "type": "string",
tools = ToolsSchema(standard_tools=[weather_function]) "enum": ["celsius", "fahrenheit"],
messages = [ "description": "The temperature unit to use. Infer this from the user's location.",
{ },
"role": "system", },
"content": """You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. required=["location", "format"],
)
tools = ToolsSchema(standard_tools=[weather_function])
messages = [
{
"role": "system",
"content": """You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way.
You have one functions available: You have one functions available:
@@ -92,44 +88,56 @@ Infer whether to use Fahrenheit or Celsius automatically based on the location,
Start by asking me for my location. Then, use 'get_weather_current' to give me a forecast. Start by asking me for my location. Then, use 'get_weather_current' to give me a forecast.
Respond to what the user said in a creative and helpful way.""", Respond to what the user said in a creative and helpful way.""",
}, },
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -22,108 +18,120 @@ 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.azure.tts import AzureTTSService from pipecat.services.azure.tts import AzureTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openrouter.llm import OpenRouterLLMService from pipecat.services.openrouter.llm import OpenRouterLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
await llm.push_frame(TTSSpeakFrame("Let me check on that.")) await llm.push_frame(TTSSpeakFrame("Let me check on that."))
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = AzureTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("AZURE_API_KEY"),
region="eastus",
voice="en-US-JennyNeural",
params=AzureTTSService.InputParams(language="en-US", rate="1.1", style="cheerful"),
)
llm = OpenRouterLLMService( tts = AzureTTSService(
api_key=os.getenv("OPENROUTER_API_KEY"), model="openai/gpt-4o-2024-11-20" api_key=os.getenv("AZURE_API_KEY"),
) region="eastus",
# You can also register a function_name of None to get all functions voice="en-US-JennyNeural",
# sent to the same callback with an additional function_name parameter. params=AzureTTSService.InputParams(language="en-US", rate="1.1", style="cheerful"),
llm.register_function("get_current_weather", fetch_weather_from_api) )
weather_function = FunctionSchema( llm = OpenRouterLLMService(
name="get_current_weather", api_key=os.getenv("OPENROUTER_API_KEY"), model="openai/gpt-4o-2024-11-20"
description="Get the current weather", )
properties={ # You can also register a function_name of None to get all functions
"location": { # sent to the same callback with an additional function_name parameter.
"type": "string", llm.register_function("get_current_weather", fetch_weather_from_api)
"description": "The city and state, e.g. San Francisco, CA",
}, weather_function = FunctionSchema(
"format": { name="get_current_weather",
"type": "string", description="Get the current weather",
"enum": ["celsius", "fahrenheit"], properties={
"description": "The temperature unit to use. Infer this from the user's location.", "location": {
}, "type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}, },
required=["location", "format"], "format": {
) "type": "string",
tools = ToolsSchema(standard_tools=[weather_function]) "enum": ["celsius", "fahrenheit"],
messages = [ "description": "The temperature unit to use. Infer this from the user's location.",
{
"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.",
}, },
},
required=["location", "format"],
)
tools = ToolsSchema(standard_tools=[weather_function])
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, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -11,14 +11,10 @@ currently support function calling. The example shows basic chat completion func
using Perplexity's API while maintaining compatibility with the OpenAI interface. using Perplexity's API while maintaining compatibility with the OpenAI interface.
""" """
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
@@ -26,79 +22,91 @@ 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.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.perplexity.llm import PerplexityLLMService from pipecat.services.perplexity.llm import PerplexityLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = CartesiaTTSService( tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
) )
llm = PerplexityLLMService(api_key=os.getenv("PERPLEXITY_API_KEY"), model="sonar") llm = PerplexityLLMService(api_key=os.getenv("PERPLEXITY_API_KEY"), model="sonar")
messages = [ messages = [
{ {
"role": "user", "role": "user",
"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.", "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(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -21,104 +17,116 @@ from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.elevenlabs.tts import ElevenLabsTTSService from pipecat.services.elevenlabs.tts import ElevenLabsTTSService
from pipecat.services.google.llm_openai import GoogleLLMOpenAIBetaService from pipecat.services.google.llm_openai import GoogleLLMOpenAIBetaService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
await llm.push_frame(TTSSpeakFrame("Let me check on that.")) await llm.push_frame(TTSSpeakFrame("Let me check on that."))
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = ElevenLabsTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("ELEVENLABS_API_KEY", ""),
voice_id=os.getenv("ELEVENLABS_VOICE_ID", ""),
)
llm = GoogleLLMOpenAIBetaService(api_key=os.getenv("GEMINI_API_KEY")) tts = ElevenLabsTTSService(
# You can aslo register a function_name of None to get all functions api_key=os.getenv("ELEVENLABS_API_KEY", ""),
# sent to the same callback with an additional function_name parameter. voice_id=os.getenv("ELEVENLABS_VOICE_ID", ""),
llm.register_function("get_current_weather", fetch_weather_from_api) )
weather_function = FunctionSchema( llm = GoogleLLMOpenAIBetaService(api_key=os.getenv("GEMINI_API_KEY"))
name="get_current_weather", # You can aslo register a function_name of None to get all functions
description="Get the current weather", # sent to the same callback with an additional function_name parameter.
properties={ llm.register_function("get_current_weather", fetch_weather_from_api)
"location": {
"type": "string", weather_function = FunctionSchema(
"description": "The city and state, e.g. San Francisco, CA", name="get_current_weather",
}, description="Get the current weather",
"format": { properties={
"type": "string", "location": {
"enum": ["celsius", "fahrenheit"], "type": "string",
"description": "The temperature unit to use. Infer this from the user's location.", "description": "The city and state, e.g. San Francisco, CA",
},
}, },
required=["location", "format"], "format": {
) "type": "string",
tools = ToolsSchema(standard_tools=[weather_function]) "enum": ["celsius", "fahrenheit"],
messages = [ "description": "The temperature unit to use. Infer this from the user's location.",
{
"role": "user",
"content": "Start a conversation with 'Hey there' to get the current weather.",
}, },
},
required=["location", "format"],
)
tools = ToolsSchema(standard_tools=[weather_function])
messages = [
{
"role": "user",
"content": "Start a conversation with 'Hey there' to get the current weather.",
},
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -21,110 +17,122 @@ from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.elevenlabs.tts import ElevenLabsTTSService from pipecat.services.elevenlabs.tts import ElevenLabsTTSService
from pipecat.services.google.llm_vertex import GoogleVertexLLMService from pipecat.services.google.llm_vertex import GoogleVertexLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
await llm.push_frame(TTSSpeakFrame("Let me check on that.")) await llm.push_frame(TTSSpeakFrame("Let me check on that."))
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
tts = ElevenLabsTTSService(
api_key=os.getenv("ELEVENLABS_API_KEY", ""),
voice_id=os.getenv("ELEVENLABS_VOICE_ID", ""),
)
llm = GoogleVertexLLMService(
# credentials="<json-credentials>",
params=GoogleVertexLLMService.InputParams(
project_id="<google-project-id>",
) )
)
# You can aslo register a function_name of None to get all functions
# sent to the same callback with an additional function_name parameter.
llm.register_function("get_current_weather", fetch_weather_from_api)
tts = ElevenLabsTTSService( weather_function = FunctionSchema(
api_key=os.getenv("ELEVENLABS_API_KEY", ""), name="get_current_weather",
voice_id=os.getenv("ELEVENLABS_VOICE_ID", ""), description="Get the current weather",
) properties={
"location": {
llm = GoogleVertexLLMService( "type": "string",
# credentials="<json-credentials>", "description": "The city and state, e.g. San Francisco, CA",
params=GoogleVertexLLMService.InputParams(
project_id="<google-project-id>",
)
)
# You can aslo register a function_name of None to get all functions
# sent to the same callback with an additional function_name parameter.
llm.register_function("get_current_weather", fetch_weather_from_api)
weather_function = FunctionSchema(
name="get_current_weather",
description="Get the current weather",
properties={
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"format": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the user's location.",
},
}, },
required=["location", "format"], "format": {
) "type": "string",
tools = ToolsSchema(standard_tools=[weather_function]) "enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the user's location.",
messages = [
{
"role": "user",
"content": "Start a conversation with 'Hey there' to get the current weather.",
}, },
},
required=["location", "format"],
)
tools = ToolsSchema(standard_tools=[weather_function])
messages = [
{
"role": "user",
"content": "Start a conversation with 'Hey there' to get the current weather.",
},
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -22,106 +18,118 @@ 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.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.qwen.llm import QwenLLMService from pipecat.services.qwen.llm import QwenLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
await llm.push_frame(TTSSpeakFrame("Let me check on that.")) await llm.push_frame(TTSSpeakFrame("Let me check on that."))
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = QwenLLMService(api_key=os.getenv("QWEN_API_KEY"), model="qwen2.5-72b-instruct") tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
# You can also register a function_name of None to get all functions llm = QwenLLMService(api_key=os.getenv("QWEN_API_KEY"), model="qwen2.5-72b-instruct")
# sent to the same callback with an additional function_name parameter.
llm.register_function("get_current_weather", fetch_weather_from_api)
weather_function = FunctionSchema( # You can also register a function_name of None to get all functions
name="get_current_weather", # sent to the same callback with an additional function_name parameter.
description="Get the current weather", llm.register_function("get_current_weather", fetch_weather_from_api)
properties={
"location": { weather_function = FunctionSchema(
"type": "string", name="get_current_weather",
"description": "The city and state, e.g. San Francisco, CA", description="Get the current weather",
}, properties={
"format": { "location": {
"type": "string", "type": "string",
"enum": ["celsius", "fahrenheit"], "description": "The city and state, e.g. San Francisco, CA",
"description": "The temperature unit to use. Infer this from the user's location.",
},
}, },
required=["location", "format"], "format": {
) "type": "string",
tools = ToolsSchema(standard_tools=[weather_function]) "enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the user's location.",
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.",
}, },
},
required=["location", "format"],
)
tools = ToolsSchema(standard_tools=[weather_function])
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, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
context_aggregator.user(), # Kick off the conversation.
llm, await task.queue_frames([context_aggregator.user().get_context_frame()])
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,15 +4,11 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from openai.types.chat import ChatCompletionToolParam from openai.types.chat import ChatCompletionToolParam
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.parallel_pipeline import ParallelPipeline from pipecat.pipeline.parallel_pipeline import ParallelPipeline
@@ -22,13 +18,14 @@ 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.processors.filters.function_filter import FunctionFilter from pipecat.processors.filters.function_filter import FunctionFilter
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
current_voice = "News Lady" current_voice = "News Lady"
@@ -55,105 +52,117 @@ async def barbershop_man_filter(frame) -> bool:
return current_voice == "Barbershop Man" return current_voice == "Barbershop Man"
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Pipecat", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(), ),
), )
)
news_lady = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="bf991597-6c13-47e4-8411-91ec2de5c466", # Newslady
)
british_lady = CartesiaTTSService( news_lady = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady voice_id="bf991597-6c13-47e4-8411-91ec2de5c466", # Newslady
) )
barbershop_man = CartesiaTTSService( british_lady = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="a0e99841-438c-4a64-b679-ae501e7d6091", # Barbershop Man voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
) )
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") barbershop_man = CartesiaTTSService(
llm.register_function("switch_voice", switch_voice) api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="a0e99841-438c-4a64-b679-ae501e7d6091", # Barbershop Man
)
tools = [ llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
ChatCompletionToolParam( llm.register_function("switch_voice", switch_voice)
type="function",
function={ tools = [
"name": "switch_voice", ChatCompletionToolParam(
"description": "Switch your voice only when the user asks you to", type="function",
"parameters": { function={
"type": "object", "name": "switch_voice",
"properties": { "description": "Switch your voice only when the user asks you to",
"voice": { "parameters": {
"type": "string", "type": "object",
"description": "The voice the user wants you to use", "properties": {
}, "voice": {
"type": "string",
"description": "The voice the user wants you to use",
}, },
"required": ["voice"],
}, },
"required": ["voice"],
}, },
) },
)
]
messages = [
{
"role": "system",
"content": "You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities. Respond to what the user said in a creative and helpful way. Your output should not include non-alphanumeric characters. You can do the following voices: 'News Lady', 'British Lady' and 'Barbershop Man'.",
},
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(), # Transport user input
stt,
context_aggregator.user(), # User responses
llm, # LLM
ParallelPipeline( # TTS (one of the following vocies)
[FunctionFilter(news_lady_filter), news_lady], # News Lady voice
[
FunctionFilter(british_lady_filter),
british_lady,
], # British Reading Lady voice
[FunctionFilter(barbershop_man_filter), barbershop_man], # Barbershop Man voice
),
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
messages = [ )
task = PipelineTask(pipeline, params=PipelineParams(allow_interruptions=True))
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Kick off the conversation.
messages.append(
{ {
"role": "system", "role": "system",
"content": "You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities. Respond to what the user said in a creative and helpful way. Your output should not include non-alphanumeric characters. You can do the following voices: 'News Lady', 'British Lady' and 'Barbershop Man'.", "content": f"Please introduce yourself to the user and let them know the voices you can do. Your initial responses should be as if you were a {current_voice}.",
}, }
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(), # Transport user input
context_aggregator.user(), # User responses
llm, # LLM
ParallelPipeline( # TTS (one of the following vocies)
[FunctionFilter(news_lady_filter), news_lady], # News Lady voice
[
FunctionFilter(british_lady_filter),
british_lady,
], # British Reading Lady voice
[FunctionFilter(barbershop_man_filter), barbershop_man], # Barbershop Man voice
),
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
) )
await task.queue_frames([context_aggregator.user().get_context_frame()])
task = PipelineTask(pipeline, params=PipelineParams(allow_interruptions=True)) @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append(
{
"role": "system",
"content": f"Please introduce yourself to the user and let them know the voices you can do. Your initial responses should be as if you were a {current_voice}.",
}
)
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,16 +4,12 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from deepgram import LiveOptions from deepgram import LiveOptions
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from openai.types.chat import ChatCompletionToolParam from openai.types.chat import ChatCompletionToolParam
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.parallel_pipeline import ParallelPipeline from pipecat.pipeline.parallel_pipeline import ParallelPipeline
@@ -25,12 +21,12 @@ from pipecat.processors.filters.function_filter import FunctionFilter
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
current_language = "English" current_language = "English"
@@ -49,101 +45,110 @@ async def spanish_filter(frame) -> bool:
return current_language == "Spanish" return current_language == "Spanish"
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Pipecat", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
vad_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_analyzer=SileroVADAnalyzer(), vad_audio_passthrough=True,
vad_audio_passthrough=True, ),
), )
)
stt = DeepgramSTTService( stt = DeepgramSTTService(
api_key=os.getenv("DEEPGRAM_API_KEY"), live_options=LiveOptions(language="multi") api_key=os.getenv("DEEPGRAM_API_KEY"), live_options=LiveOptions(language="multi")
) )
english_tts = CartesiaTTSService( english_tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
) )
spanish_tts = CartesiaTTSService( spanish_tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="846d6cb0-2301-48b6-9683-48f5618ea2f6", # Spanish-speaking Lady voice_id="d4db5fb9-f44b-4bd1-85fa-192e0f0d75f9", # Spanish-speaking Lady
) )
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
llm.register_function("switch_language", switch_language) llm.register_function("switch_language", switch_language)
tools = [ tools = [
ChatCompletionToolParam( ChatCompletionToolParam(
type="function", type="function",
function={ function={
"name": "switch_language", "name": "switch_language",
"description": "Switch to another language when the user asks you to", "description": "Switch to another language when the user asks you to",
"parameters": { "parameters": {
"type": "object", "type": "object",
"properties": { "properties": {
"language": { "language": {
"type": "string", "type": "string",
"description": "The language the user wants you to speak", "description": "The language the user wants you to speak",
},
}, },
"required": ["language"],
}, },
"required": ["language"],
}, },
) },
)
]
messages = [
{
"role": "system",
"content": "You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities. Respond to what the user said in a creative and helpful way. Your output should not include non-alphanumeric characters. You can speak the following languages: 'English' and 'Spanish'.",
},
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
ParallelPipeline( # TTS (bot will speak the chosen language)
[FunctionFilter(english_filter), english_tts], # English
[FunctionFilter(spanish_filter), spanish_tts], # Spanish
),
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
messages = [ )
task = PipelineTask(pipeline, params=PipelineParams(allow_interruptions=True))
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Kick off the conversation.
messages.append(
{ {
"role": "system", "role": "system",
"content": "You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities. Respond to what the user said in a creative and helpful way. Your output should not include non-alphanumeric characters. You can speak the following languages: 'English' and 'Spanish'.", "content": f"Please introduce yourself to the user and let them know the languages you speak. Your initial responses should be in {current_language}.",
}, }
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
ParallelPipeline( # TTS (bot will speak the chosen language)
[FunctionFilter(english_filter), english_tts], # English
[FunctionFilter(spanish_filter), spanish_tts], # Spanish
),
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
) )
await task.queue_frames([context_aggregator.user().get_context_frame()])
task = PipelineTask(pipeline, params=PipelineParams(allow_interruptions=True)) @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append(
{
"role": "system",
"content": f"Please introduce yourself to the user and let them know the languages you speak. Your initial responses should be in {current_language}.",
}
)
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,49 +4,45 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner 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.deepgram.stt import DeepgramSTTService
from pipecat.services.deepgram.tts import DeepgramTTSService from pipecat.services.deepgram.tts import DeepgramTTSService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import ( from pipecat.transports.base_transport import TransportParams
DailyParams, from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
DailyTransport, from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
DailyTransportMessageFrame, from pipecat.transports.services.daily import DailyTransportMessageFrame
)
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
# Create an HTTP session
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
(room_url, token) = await configure(session) stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
transport = DailyTransport(
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = DeepgramTTSService( tts = DeepgramTTSService(
aiohttp_session=session, aiohttp_session=session,
@@ -77,6 +73,7 @@ async def main():
pipeline = Pipeline( pipeline = Pipeline(
[ [
transport.input(), # Transport user input transport.input(), # Transport user input
stt, # STT
context_aggregator.user(), context_aggregator.user(),
llm, # LLM llm, # LLM
tts, # TTS tts, # TTS
@@ -93,15 +90,11 @@ async def main():
), ),
) )
# When a participant joins, start transcription for that participant so the
# bot can "hear" and respond to them.
@transport.event_handler("on_participant_joined")
async def on_participant_joined(transport, participant):
await transport.capture_participant_transcription(participant["id"])
# When the first participant joins, the bot should introduce itself. # When the first participant joins, the bot should introduce itself.
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_connected")
async def on_first_participant_joined(transport, participant): async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Kick off the conversation.
messages.append({"role": "system", "content": "Please introduce yourself to the user."}) messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()]) await task.queue_frames([context_aggregator.user().get_context_frame()])
@@ -134,9 +127,21 @@ async def main():
except Exception as e: except Exception as e:
logger.debug(f"message handling error: {e} - {message}") logger.debug(f"message handling error: {e} - {message}")
runner = PipelineRunner() @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import EndFrame, LLMMessagesFrame, TTSSpeakFrame from pipecat.frames.frames import EndFrame, LLMMessagesFrame, TTSSpeakFrame
@@ -21,111 +17,123 @@ 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.processors.user_idle_processor import UserIdleProcessor from pipecat.processors.user_idle_processor import UserIdleProcessor
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, token) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
tts = CartesiaTTSService( tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
) )
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
messages = [ messages = [
{ {
"role": "system", "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.", "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)
async def handle_user_idle(user_idle: UserIdleProcessor, retry_count: int) -> bool:
if retry_count == 1:
# First attempt: Add a gentle prompt to the conversation
messages.append(
{
"role": "system",
"content": "The user has been quiet. Politely and briefly ask if they're still there.",
}
)
await user_idle.push_frame(LLMMessagesFrame(messages))
return True
elif retry_count == 2:
# Second attempt: More direct prompt
messages.append(
{
"role": "system",
"content": "The user is still inactive. Ask if they'd like to continue our conversation.",
}
)
await user_idle.push_frame(LLMMessagesFrame(messages))
return True
else:
# Third attempt: End the conversation
await user_idle.push_frame(
TTSSpeakFrame("It seems like you're busy right now. Have a nice day!")
)
await task.queue_frame(EndFrame())
return False
user_idle = UserIdleProcessor(callback=handle_user_idle, timeout=5.0)
pipeline = Pipeline(
[
transport.input(), # Transport user input
stt,
user_idle, # Idle user check-in
context_aggregator.user(),
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
report_only_initial_ttfb=True,
),
)
async def handle_user_idle(user_idle: UserIdleProcessor, retry_count: int) -> bool: @transport.event_handler("on_client_connected")
if retry_count == 1: async def on_client_connected(transport, client):
# First attempt: Add a gentle prompt to the conversation logger.info(f"Client connected")
messages.append( # Kick off the conversation.
{ messages.append({"role": "system", "content": "Please introduce yourself to the user."})
"role": "system", await task.queue_frames([context_aggregator.user().get_context_frame()])
"content": "The user has been quiet. Politely and briefly ask if they're still there.",
}
)
await user_idle.push_frame(LLMMessagesFrame(messages))
return True
elif retry_count == 2:
# Second attempt: More direct prompt
messages.append(
{
"role": "system",
"content": "The user is still inactive. Ask if they'd like to continue our conversation.",
}
)
await user_idle.push_frame(LLMMessagesFrame(messages))
return True
else:
# Third attempt: End the conversation
await user_idle.push_frame(
TTSSpeakFrame("It seems like you're busy right now. Have a nice day!")
)
await task.queue_frame(EndFrame())
return False
user_idle = UserIdleProcessor(callback=handle_user_idle, timeout=5.0) @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
pipeline = Pipeline( @transport.event_handler("on_client_closed")
[ async def on_client_closed(transport, client):
transport.input(), # Transport user input logger.info(f"Client closed connection")
user_idle, # Idle user check-in await task.cancel()
context_aggregator.user(),
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(),
]
)
task = PipelineTask( runner = PipelineRunner(handle_sigint=False)
pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") await runner.run(task)
async def on_first_participant_joined(transport, participant):
await transport.capture_participant_transcription(participant["id"])
# Kick off the conversation.
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -5,67 +5,71 @@
# #
import argparse import argparse
import asyncio
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure_with_args
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineTask
from pipecat.processors.gstreamer.pipeline_source import GStreamerPipelineSource from pipecat.processors.gstreamer.pipeline_source import GStreamerPipelineSource
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG") # Parse command line arguments
# This will be used to pass the input video file to the bot
# You can run the bot with a command like:
# python 18-gstreamer-filesrc.py -i path/to/video.mp4
def parse_arguments():
parser = argparse.ArgumentParser(description="Daily AI SDK Bot Sample")
parser.add_argument("-i", "--input", type=str, required=True, help="Input video file")
return parser.parse_args()
async def main(): args = parse_arguments()
async with aiohttp.ClientSession() as session:
parser = argparse.ArgumentParser(description="Daily AI SDK Bot Sample")
parser.add_argument("-i", "--input", type=str, required=True, help="Input video file")
(room_url, _, args) = await configure_with_args(session, parser)
transport = DailyTransport( async def run_bot(webrtc_connection: SmallWebRTCConnection):
room_url, logger.info(f"Starting bot with video input: {args.input}")
None,
"GStreamer",
DailyParams(
audio_out_enabled=True,
camera_out_enabled=True,
camera_out_width=1280,
camera_out_height=720,
camera_out_is_live=True,
),
)
gst = GStreamerPipelineSource( transport = SmallWebRTCTransport(
pipeline=f"filesrc location={args.input}", webrtc_connection=webrtc_connection,
out_params=GStreamerPipelineSource.OutputParams( params=TransportParams(
video_width=1280, audio_in_enabled=True,
video_height=720, camera_out_enabled=True,
), camera_out_is_live=True,
) camera_out_width=1280,
camera_out_height=720,
),
)
pipeline = Pipeline( gst = GStreamerPipelineSource(
[ pipeline=f"filesrc location={args.input}",
gst, # GStreamer file source out_params=GStreamerPipelineSource.OutputParams(
transport.output(), # Transport bot output video_width=1280,
] video_height=720,
) ),
)
task = PipelineTask(pipeline) pipeline = Pipeline(
[
gst, # GStreamer file source
transport.output(), # Transport bot output
]
)
runner = PipelineRunner() task = PipelineTask(pipeline)
await runner.run(task) runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,62 +4,57 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask from pipecat.pipeline.task import PipelineTask
from pipecat.processors.gstreamer.pipeline_source import GStreamerPipelineSource from pipecat.processors.gstreamer.pipeline_source import GStreamerPipelineSource
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot with video test source")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, _) = await configure(session) params=TransportParams(
audio_in_enabled=True,
camera_out_enabled=True,
camera_out_is_live=True,
camera_out_width=1280,
camera_out_height=720,
),
)
transport = DailyTransport( gst = GStreamerPipelineSource(
room_url, pipeline='videotestsrc ! capsfilter caps="video/x-raw,width=1280,height=720,framerate=30/1"',
None, out_params=GStreamerPipelineSource.OutputParams(
"GStreamer", video_width=1280, video_height=720, clock_sync=False
DailyParams( ),
camera_out_enabled=True, )
camera_out_width=1280,
camera_out_height=720,
camera_out_is_live=True,
),
)
gst = GStreamerPipelineSource( pipeline = Pipeline(
pipeline='videotestsrc ! capsfilter caps="video/x-raw,width=1280,height=720,framerate=30/1"', [
out_params=GStreamerPipelineSource.OutputParams( gst, # GStreamer test source
video_width=1280, video_height=720, clock_sync=False transport.output(), # Transport bot output
), ]
) )
pipeline = Pipeline( task = PipelineTask(pipeline)
[
gst, # GStreamer file source
transport.output(), # Transport bot output
]
)
task = PipelineTask(pipeline) runner = PipelineRunner(handle_sigint=False)
runner = PipelineRunner() await runner.run(task)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,15 +4,11 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
from datetime import datetime from datetime import datetime
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -29,13 +25,12 @@ from pipecat.services.openai_realtime_beta import (
SemanticTurnDetection, SemanticTurnDetection,
SessionProperties, SessionProperties,
) )
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
temperature = 75 if args["format"] == "fahrenheit" else 24 temperature = 75 if args["format"] == "fahrenheit" else 24
@@ -70,34 +65,30 @@ weather_function = FunctionSchema(
tools = ToolsSchema(standard_tools=[weather_function]) tools = ToolsSchema(standard_tools=[weather_function])
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_in_enabled=True, vad_enabled=True,
audio_out_enabled=True, vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)),
transcription_enabled=False, vad_audio_passthrough=True,
vad_enabled=True, ),
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)), )
vad_audio_passthrough=True,
),
)
session_properties = SessionProperties( session_properties = SessionProperties(
input_audio_transcription=InputAudioTranscription(), input_audio_transcription=InputAudioTranscription(),
# Set openai TurnDetection parameters. Not setting this at all will turn it # Set openai TurnDetection parameters. Not setting this at all will turn it
# on by default # on by default
turn_detection=SemanticTurnDetection(), turn_detection=SemanticTurnDetection(),
# Or set to False to disable openai turn detection and use transport VAD # Or set to False to disable openai turn detection and use transport VAD
# turn_detection=False, # turn_detection=False,
input_audio_noise_reduction=InputAudioNoiseReduction(type="near_field"), input_audio_noise_reduction=InputAudioNoiseReduction(type="near_field"),
# tools=tools, # tools=tools,
instructions="""Your knowledge cutoff is 2023-10. You are a helpful and friendly AI. instructions="""Your knowledge cutoff is 2023-10. You are a helpful and friendly AI.
Act like a human, but remember that you aren't a human and that you can't do human Act like a human, but remember that you aren't a human and that you can't do human
things in the real world. Your voice and personality should be warm and engaging, with a lively and things in the real world. Your voice and personality should be warm and engaging, with a lively and
@@ -111,68 +102,79 @@ You are participating in a voice conversation. Keep your responses concise, shor
unless specifically asked to elaborate on a topic. unless specifically asked to elaborate on a topic.
Remember, your responses should be short. Just one or two sentences, usually.""", Remember, your responses should be short. Just one or two sentences, usually.""",
) )
llm = OpenAIRealtimeBetaLLMService( llm = OpenAIRealtimeBetaLLMService(
api_key=os.getenv("OPENAI_API_KEY"), api_key=os.getenv("OPENAI_API_KEY"),
session_properties=session_properties, session_properties=session_properties,
start_audio_paused=False, start_audio_paused=False,
) )
# you can either register a single function for all function calls, or specific functions # you can either register a single function for all function calls, or specific functions
# llm.register_function(None, fetch_weather_from_api) # llm.register_function(None, fetch_weather_from_api)
llm.register_function("get_current_weather", fetch_weather_from_api) llm.register_function("get_current_weather", fetch_weather_from_api)
# Create a standard OpenAI LLM context object using the normal messages format. The # Create a standard OpenAI LLM context object using the normal messages format. The
# OpenAIRealtimeBetaLLMService will convert this internally to messages that the # OpenAIRealtimeBetaLLMService will convert this internally to messages that the
# openai WebSocket API can understand. # openai WebSocket API can understand.
context = OpenAILLMContext( context = OpenAILLMContext(
[{"role": "user", "content": "Say hello!"}], [{"role": "user", "content": "Say hello!"}],
# [{"role": "user", "content": [{"type": "text", "text": "Say hello!"}]}], # [{"role": "user", "content": [{"type": "text", "text": "Say hello!"}]}],
# [ # [
# { # {
# "role": "user", # "role": "user",
# "content": [ # "content": [
# {"type": "text", "text": "Say"}, # {"type": "text", "text": "Say"},
# {"type": "text", "text": "yo what's up!"}, # {"type": "text", "text": "yo what's up!"},
# ], # ],
# } # }
# ], # ],
tools, tools,
) )
context_aggregator = llm.create_context_aggregator(context) context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline( pipeline = Pipeline(
[ [
transport.input(), # Transport user input transport.input(), # Transport user input
context_aggregator.user(), context_aggregator.user(),
llm, # LLM llm, # LLM
transport.output(), # Transport bot output transport.output(), # Transport bot output
context_aggregator.assistant(), context_aggregator.assistant(),
] ]
) )
task = PipelineTask( task = PipelineTask(
pipeline, pipeline,
params=PipelineParams( params=PipelineParams(
allow_interruptions=True, allow_interruptions=True,
enable_metrics=True, enable_metrics=True,
enable_usage_metrics=True, enable_usage_metrics=True,
# report_only_initial_ttfb=True, report_only_initial_ttfb=True,
), ),
) )
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_connected")
async def on_first_participant_joined(transport, participant): async def on_client_connected(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client connected")
# Kick off the conversation. # Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()]) await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
await runner.run(task) @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,15 +4,11 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
from datetime import datetime from datetime import datetime
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema
@@ -27,13 +23,12 @@ from pipecat.services.openai_realtime_beta import (
InputAudioTranscription, InputAudioTranscription,
SessionProperties, SessionProperties,
) )
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
temperature = 75 if args["format"] == "fahrenheit" else 24 temperature = 75 if args["format"] == "fahrenheit" else 24
@@ -69,33 +64,29 @@ weather_function = FunctionSchema(
tools = ToolsSchema(standard_tools=[weather_function]) tools = ToolsSchema(standard_tools=[weather_function])
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_in_enabled=True, vad_enabled=True,
audio_out_enabled=True, vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)),
transcription_enabled=False, vad_audio_passthrough=True,
vad_enabled=True, ),
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)), )
vad_audio_passthrough=True,
),
)
session_properties = SessionProperties( session_properties = SessionProperties(
input_audio_transcription=InputAudioTranscription(), input_audio_transcription=InputAudioTranscription(model="whisper-1"),
# Set openai TurnDetection parameters. Not setting this at all will turn it # Set openai TurnDetection parameters. Not setting this at all will turn it
# on by default # on by default
# turn_detection=TurnDetection(silence_duration_ms=1000), # turn_detection=TurnDetection(silence_duration_ms=1000),
# Or set to False to disable openai turn detection and use transport VAD # Or set to False to disable openai turn detection and use transport VAD
# turn_detection=False, # turn_detection=False,
# tools=tools, # tools=tools,
instructions="""Your knowledge cutoff is 2023-10. You are a helpful and friendly AI. instructions="""Your knowledge cutoff is 2023-10. You are a helpful and friendly AI.
Act like a human, but remember that you aren't a human and that you can't do human Act like a human, but remember that you aren't a human and that you can't do human
things in the real world. Your voice and personality should be warm and engaging, with a lively and things in the real world. Your voice and personality should be warm and engaging, with a lively and
@@ -109,69 +100,80 @@ You are participating in a voice conversation. Keep your responses concise, shor
unless specifically asked to elaborate on a topic. unless specifically asked to elaborate on a topic.
Remember, your responses should be short. Just one or two sentences, usually.""", Remember, your responses should be short. Just one or two sentences, usually.""",
) )
llm = AzureRealtimeBetaLLMService( llm = AzureRealtimeBetaLLMService(
api_key=os.getenv("AZURE_REALTIME_API_KEY"), api_key=os.getenv("AZURE_REALTIME_API_KEY"),
base_url=os.getenv("AZURE_REALTIME_BASE_URL"), base_url=os.getenv("AZURE_REALTIME_BASE_URL"),
session_properties=session_properties, session_properties=session_properties,
start_audio_paused=False, start_audio_paused=False,
) )
# you can either register a single function for all function calls, or specific functions # you can either register a single function for all function calls, or specific functions
# llm.register_function(None, fetch_weather_from_api) # llm.register_function(None, fetch_weather_from_api)
llm.register_function("get_current_weather", fetch_weather_from_api) llm.register_function("get_current_weather", fetch_weather_from_api)
# Create a standard OpenAI LLM context object using the normal messages format. The # Create a standard OpenAI LLM context object using the normal messages format. The
# OpenAIRealtimeBetaLLMService will convert this internally to messages that the # OpenAIRealtimeBetaLLMService will convert this internally to messages that the
# openai WebSocket API can understand. # openai WebSocket API can understand.
context = OpenAILLMContext( context = OpenAILLMContext(
[{"role": "user", "content": "Say hello!"}], [{"role": "user", "content": "Say hello!"}],
# [{"role": "user", "content": [{"type": "text", "text": "Say hello!"}]}], # [{"role": "user", "content": [{"type": "text", "text": "Say hello!"}]}],
# [ # [
# { # {
# "role": "user", # "role": "user",
# "content": [ # "content": [
# {"type": "text", "text": "Say"}, # {"type": "text", "text": "Say"},
# {"type": "text", "text": "yo what's up!"}, # {"type": "text", "text": "yo what's up!"},
# ], # ],
# } # }
# ], # ],
tools, tools,
) )
context_aggregator = llm.create_context_aggregator(context) context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline( pipeline = Pipeline(
[ [
transport.input(), # Transport user input transport.input(), # Transport user input
context_aggregator.user(), context_aggregator.user(),
llm, # LLM llm, # LLM
transport.output(), # Transport bot output transport.output(), # Transport bot output
context_aggregator.assistant(), context_aggregator.assistant(),
] ]
) )
task = PipelineTask( task = PipelineTask(
pipeline, pipeline,
params=PipelineParams( params=PipelineParams(
allow_interruptions=True, allow_interruptions=True,
enable_metrics=True, enable_metrics=True,
enable_usage_metrics=True, enable_usage_metrics=True,
# report_only_initial_ttfb=True, report_only_initial_ttfb=True,
), ),
) )
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_connected")
async def on_first_participant_joined(transport, participant): async def on_client_connected(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client connected")
# Kick off the conversation. # Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()]) await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
await runner.run(task) @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,17 +4,13 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import glob import glob
import json import json
import os import os
import sys
from datetime import datetime from datetime import datetime
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.audio.vad.vad_analyzer import VADParams
@@ -25,13 +21,14 @@ from pipecat.processors.aggregators.openai_llm_context import (
OpenAILLMContext, OpenAILLMContext,
) )
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
BASE_FILENAME = "/tmp/pipecat_conversation_" BASE_FILENAME = "/tmp/pipecat_conversation_"
tts = None tts = None
@@ -165,71 +162,84 @@ tools = [
] ]
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
global tts global tts
async with aiohttp.ClientSession() as session:
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
# you can either register a single function for all function calls, or specific functions llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
# llm.register_function(None, fetch_weather_from_api)
llm.register_function("get_current_weather", fetch_weather_from_api)
llm.register_function("save_conversation", save_conversation)
llm.register_function("get_saved_conversation_filenames", get_saved_conversation_filenames)
llm.register_function("load_conversation", load_conversation)
context = OpenAILLMContext(messages, tools) # you can either register a single function for all function calls, or specific functions
context_aggregator = llm.create_context_aggregator(context) # llm.register_function(None, fetch_weather_from_api)
llm.register_function("get_current_weather", fetch_weather_from_api)
llm.register_function("save_conversation", save_conversation)
llm.register_function("get_saved_conversation_filenames", get_saved_conversation_filenames)
llm.register_function("load_conversation", load_conversation)
pipeline = Pipeline( context = OpenAILLMContext(messages, tools)
[ context_aggregator = llm.create_context_aggregator(context)
transport.input(), # Transport user input
context_aggregator.user(),
llm, # LLM
tts,
transport.output(), # Transport bot output
context_aggregator.assistant(),
]
)
task = PipelineTask( pipeline = Pipeline(
pipeline, [
params=PipelineParams( transport.input(), # Transport user input
allow_interruptions=True, stt, # STT
enable_metrics=True, context_aggregator.user(),
enable_usage_metrics=True, llm, # LLM
# report_only_initial_ttfb=True, tts,
), transport.output(), # Transport bot output
) context_aggregator.assistant(),
]
)
@transport.event_handler("on_first_participant_joined") task = PipelineTask(
async def on_first_participant_joined(transport, participant): pipeline,
await transport.capture_participant_transcription(participant["id"]) params=PipelineParams(
# Kick off the conversation. allow_interruptions=True,
await task.queue_frames([context_aggregator.user().get_context_frame()]) enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
runner = PipelineRunner() @transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()])
await runner.run(task) @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -8,13 +8,10 @@ import asyncio
import glob import glob
import json import json
import os import os
import sys
from datetime import datetime from datetime import datetime
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.audio.vad.vad_analyzer import VADParams
@@ -24,19 +21,19 @@ from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.aggregators.openai_llm_context import ( from pipecat.processors.aggregators.openai_llm_context import (
OpenAILLMContext, OpenAILLMContext,
) )
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai_realtime_beta import ( from pipecat.services.openai_realtime_beta import (
InputAudioTranscription, InputAudioTranscription,
OpenAIRealtimeBetaLLMService, OpenAIRealtimeBetaLLMService,
SessionProperties, SessionProperties,
TurnDetection, TurnDetection,
) )
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
BASE_FILENAME = "/tmp/pipecat_conversation_" BASE_FILENAME = "/tmp/pipecat_conversation_"
@@ -167,33 +164,31 @@ tools = [
] ]
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_in_enabled=True, vad_enabled=True,
audio_out_enabled=True, vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)),
transcription_enabled=False, vad_audio_passthrough=True,
vad_enabled=True, ),
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)), )
vad_audio_passthrough=True,
),
)
session_properties = SessionProperties( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
input_audio_transcription=InputAudioTranscription(),
# Set openai TurnDetection parameters. Not setting this at all will turn it session_properties = SessionProperties(
# on by default input_audio_transcription=InputAudioTranscription(),
turn_detection=TurnDetection(silence_duration_ms=1000), # Set openai TurnDetection parameters. Not setting this at all will turn it
# Or set to False to disable openai turn detection and use transport VAD # on by default
# turn_detection=False, turn_detection=TurnDetection(silence_duration_ms=1000),
# tools=tools, # Or set to False to disable openai turn detection and use transport VAD
instructions="""Your knowledge cutoff is 2023-10. You are a helpful and friendly AI. # turn_detection=False,
# tools=tools,
instructions="""Your knowledge cutoff is 2023-10. You are a helpful and friendly AI.
Act like a human, but remember that you aren't a human and that you can't do human Act like a human, but remember that you aren't a human and that you can't do human
things in the real world. Your voice and personality should be warm and engaging, with a lively and things in the real world. Your voice and personality should be warm and engaging, with a lively and
@@ -207,54 +202,66 @@ You are participating in a voice conversation. Keep your responses concise, shor
unless specifically asked to elaborate on a topic. unless specifically asked to elaborate on a topic.
Remember, your responses should be short. Just one or two sentences, usually.""", Remember, your responses should be short. Just one or two sentences, usually.""",
) )
llm = OpenAIRealtimeBetaLLMService( llm = OpenAIRealtimeBetaLLMService(
api_key=os.getenv("OPENAI_API_KEY"), api_key=os.getenv("OPENAI_API_KEY"),
session_properties=session_properties, session_properties=session_properties,
start_audio_paused=False, start_audio_paused=False,
) )
# you can either register a single function for all function calls, or specific functions # you can either register a single function for all function calls, or specific functions
# llm.register_function(None, fetch_weather_from_api) # llm.register_function(None, fetch_weather_from_api)
llm.register_function("get_current_weather", fetch_weather_from_api) llm.register_function("get_current_weather", fetch_weather_from_api)
llm.register_function("save_conversation", save_conversation) llm.register_function("save_conversation", save_conversation)
llm.register_function("get_saved_conversation_filenames", get_saved_conversation_filenames) llm.register_function("get_saved_conversation_filenames", get_saved_conversation_filenames)
llm.register_function("load_conversation", load_conversation) llm.register_function("load_conversation", load_conversation)
context = OpenAILLMContext([], tools) context = OpenAILLMContext([], tools)
context_aggregator = llm.create_context_aggregator(context) context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline( pipeline = Pipeline(
[ [
transport.input(), # Transport user input transport.input(), # Transport user input
context_aggregator.user(), stt, # STT
llm, # LLM context_aggregator.user(),
transport.output(), # Transport bot output llm, # LLM
context_aggregator.assistant(), transport.output(), # Transport bot output
] context_aggregator.assistant(),
) ]
)
task = PipelineTask( task = PipelineTask(
pipeline, pipeline,
params=PipelineParams( params=PipelineParams(
allow_interruptions=True, allow_interruptions=True,
enable_metrics=True, enable_metrics=True,
enable_usage_metrics=True, enable_usage_metrics=True,
# report_only_initial_ttfb=True, report_only_initial_ttfb=True,
), ),
) )
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_connected")
async def on_first_participant_joined(transport, participant): async def on_client_connected(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client connected")
# Kick off the conversation. # Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()]) await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
await runner.run(task) @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,17 +4,13 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import glob import glob
import json import json
import os import os
import sys
from datetime import datetime from datetime import datetime
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.audio.vad.vad_analyzer import VADParams
@@ -26,12 +22,13 @@ from pipecat.processors.aggregators.openai_llm_context import (
) )
from pipecat.services.anthropic.llm import AnthropicLLMService from pipecat.services.anthropic.llm import AnthropicLLMService
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
BASE_FILENAME = "/tmp/pipecat_conversation_" BASE_FILENAME = "/tmp/pipecat_conversation_"
tts = None tts = None
@@ -160,73 +157,86 @@ tools = [
] ]
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
global tts global tts
async with aiohttp.ClientSession() as session:
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)),
vad_enabled=True, vad_audio_passthrough=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)), ),
), )
)
tts = CartesiaTTSService( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
llm = AnthropicLLMService( tts = CartesiaTTSService(
api_key=os.getenv("ANTHROPIC_API_KEY"), model="claude-3-5-sonnet-latest" api_key=os.getenv("CARTESIA_API_KEY"),
) voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
# you can either register a single function for all function calls, or specific functions llm = AnthropicLLMService(
# llm.register_function(None, fetch_weather_from_api) api_key=os.getenv("ANTHROPIC_API_KEY"), model="claude-3-5-sonnet-latest"
llm.register_function("get_current_weather", fetch_weather_from_api) )
llm.register_function("save_conversation", save_conversation)
llm.register_function("get_saved_conversation_filenames", get_saved_conversation_filenames)
llm.register_function("load_conversation", load_conversation)
context = OpenAILLMContext(messages, tools) # you can either register a single function for all function calls, or specific functions
context_aggregator = llm.create_context_aggregator(context) # llm.register_function(None, fetch_weather_from_api)
llm.register_function("get_current_weather", fetch_weather_from_api)
llm.register_function("save_conversation", save_conversation)
llm.register_function("get_saved_conversation_filenames", get_saved_conversation_filenames)
llm.register_function("load_conversation", load_conversation)
pipeline = Pipeline( context = OpenAILLMContext(messages, tools)
[ context_aggregator = llm.create_context_aggregator(context)
transport.input(), # Transport user input
context_aggregator.user(),
llm, # LLM
tts,
transport.output(), # Transport bot output
context_aggregator.assistant(),
]
)
task = PipelineTask( pipeline = Pipeline(
pipeline, [
params=PipelineParams( transport.input(), # Transport user input
allow_interruptions=True, stt, # STT
enable_metrics=True, context_aggregator.user(),
enable_usage_metrics=True, llm, # LLM
# report_only_initial_ttfb=True, tts,
), transport.output(), # Transport bot output
) context_aggregator.assistant(),
]
)
@transport.event_handler("on_first_participant_joined") task = PipelineTask(
async def on_first_participant_joined(transport, participant): pipeline,
await transport.capture_participant_transcription(participant["id"]) params=PipelineParams(
# Kick off the conversation. allow_interruptions=True,
await task.queue_frames([context_aggregator.user().get_context_frame()]) enable_metrics=True,
enable_usage_metrics=True,
# report_only_initial_ttfb=True,
),
)
runner = PipelineRunner() @transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()])
await runner.run(task) @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,17 +4,13 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import glob import glob
import json import json
import os import os
import sys
from datetime import datetime from datetime import datetime
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.audio.vad.vad_analyzer import VADParams
@@ -25,19 +21,21 @@ from pipecat.processors.aggregators.openai_llm_context import (
OpenAILLMContext, OpenAILLMContext,
) )
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.google.llm import GoogleLLMService from pipecat.services.google.llm import GoogleLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
video_participant_id = None video_participant_id = None
BASE_FILENAME = "/tmp/pipecat_conversation_" BASE_FILENAME = "/tmp/pipecat_conversation_"
tts = None tts = None
webrtc_peer_id = None
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
@@ -54,8 +52,11 @@ async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context
async def get_image(function_name, tool_call_id, arguments, llm, context, result_callback): async def get_image(function_name, tool_call_id, arguments, llm, context, result_callback):
question = arguments["question"] question = arguments["question"]
logger.debug(f"Requesting image with user_id={webrtc_peer_id}, question={question}")
# Request the image frame
await llm.request_image_frame( await llm.request_image_frame(
user_id=video_participant_id, user_id=webrtc_peer_id,
function_name=function_name, function_name=function_name,
tool_call_id=tool_call_id, tool_call_id=tool_call_id,
text_content=question, text_content=question,
@@ -220,75 +221,87 @@ tools = [
] ]
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
global tts global tts, webrtc_peer_id
async with aiohttp.ClientSession() as session: webrtc_peer_id = webrtc_connection.pc_id
(room_url, token) = await configure(session)
transport = DailyTransport( logger.info(f"Starting bot with peer_id: {webrtc_peer_id}")
room_url,
token,
"Respond bot",
DailyParams(
audio_out_enabled=True,
transcription_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)),
),
)
tts = CartesiaTTSService( transport = SmallWebRTCTransport(
api_key=os.getenv("CARTESIA_API_KEY"), webrtc_connection=webrtc_connection,
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady params=TransportParams(
) audio_in_enabled=True,
audio_out_enabled=True,
camera_in_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.8)),
vad_audio_passthrough=True,
),
)
llm = GoogleLLMService(model="gemini-2.0-flash-001", api_key=os.getenv("GOOGLE_API_KEY")) stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
# you can either register a single function for all function calls, or specific functions tts = CartesiaTTSService(
# llm.register_function(None, fetch_weather_from_api) api_key=os.getenv("CARTESIA_API_KEY"),
llm.register_function("get_current_weather", fetch_weather_from_api) voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
llm.register_function("save_conversation", save_conversation) )
llm.register_function("get_saved_conversation_filenames", get_saved_conversation_filenames)
llm.register_function("load_conversation", load_conversation)
llm.register_function("get_image", get_image)
context = OpenAILLMContext(messages, tools) llm = GoogleLLMService(model="gemini-2.0-flash-001", api_key=os.getenv("GOOGLE_API_KEY"))
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline( # you can either register a single function for all function calls, or specific functions
[ # llm.register_function(None, fetch_weather_from_api)
transport.input(), # Transport user input llm.register_function("get_current_weather", fetch_weather_from_api)
context_aggregator.user(), llm.register_function("save_conversation", save_conversation)
llm, # LLM llm.register_function("get_saved_conversation_filenames", get_saved_conversation_filenames)
tts, llm.register_function("load_conversation", load_conversation)
transport.output(), # Transport bot output llm.register_function("get_image", get_image)
context_aggregator.assistant(),
]
)
task = PipelineTask( context = OpenAILLMContext(messages, tools)
pipeline, context_aggregator = llm.create_context_aggregator(context)
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
# report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") pipeline = Pipeline(
async def on_first_participant_joined(transport, participant): [
global video_participant_id transport.input(), # Transport user input
video_participant_id = participant["id"] stt, # STT
await transport.capture_participant_transcription(participant["id"]) context_aggregator.user(),
await transport.capture_participant_video(video_participant_id, framerate=0) llm, # LLM
# Kick off the conversation. tts,
await task.queue_frames([context_aggregator.user().get_context_frame()]) transport.output(), # Transport bot output
context_aggregator.assistant(),
]
)
runner = PipelineRunner() task = PipelineTask(
pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
# report_only_initial_ttfb=True,
),
)
await runner.run(task) @transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import TextFrame from pipecat.frames.frames import TextFrame
@@ -28,142 +24,146 @@ from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.sync.event_notifier import EventNotifier from pipecat.sync.event_notifier import EventNotifier
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): transport = SmallWebRTCTransport(
async with aiohttp.ClientSession() as session: webrtc_connection=webrtc_connection,
(room_url, _) = await configure(session) params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
transport = DailyTransport( stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
room_url,
None, tts = CartesiaTTSService(
"Respond bot", api_key=os.getenv("CARTESIA_API_KEY"),
DailyParams( voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
audio_out_enabled=True, )
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(), # This is the LLM that will be used to detect if the user has finished a
vad_audio_passthrough=True, # statement. This doesn't really need to be an LLM, we could use NLP
# libraries for that, but it was easier as an example because we
# leverage the context aggregators.
statement_llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
statement_messages = [
{
"role": "system",
"content": "Determine if the user's statement is a complete sentence or question, ending in a natural pause or punctuation. Return 'YES' if it is complete and 'NO' if it seems to leave a thought unfinished.",
},
]
statement_context = OpenAILLMContext(statement_messages)
statement_context_aggregator = statement_llm.create_context_aggregator(statement_context)
# This is the regular LLM.
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)
# We have instructed the LLM to return 'YES' if it thinks the user
# completed a sentence. So, if it's 'YES' we will return true in this
# predicate which will wake up the notifier.
async def wake_check_filter(frame):
return frame.text == "YES"
# This is a notifier that we use to synchronize the two LLMs.
notifier = EventNotifier()
# This a filter that will wake up the notifier if the given predicate
# (wake_check_filter) returns true.
completness_check = WakeNotifierFilter(notifier, types=(TextFrame,), filter=wake_check_filter)
# This processor keeps the last context and will let it through once the
# notifier is woken up. We start with the gate open because we send an
# initial context frame to start the conversation.
gated_context_aggregator = GatedOpenAILLMContextAggregator(notifier=notifier, start_open=True)
# Notify if the user hasn't said anything.
async def user_idle_notifier(frame):
await notifier.notify()
# Sometimes the LLM will fail detecting if a user has completed a
# sentence, this will wake up the notifier if that happens.
user_idle = UserIdleProcessor(callback=user_idle_notifier, timeout=3.0)
# The ParallePipeline input are the user transcripts. We have two
# contexts. The first one will be used to determine if the user finished
# a statement and if so the notifier will be woken up. The second
# context is simply the regular context but it's gated waiting for the
# notifier to be woken up.
pipeline = Pipeline(
[
transport.input(), # Transport user input
stt,
ParallelPipeline(
[
statement_context_aggregator.user(),
statement_llm,
completness_check,
NullFilter(),
],
[context_aggregator.user(), gated_context_aggregator, llm],
), ),
) user_idle,
tts, # TTS
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
# This is the LLM that will be used to detect if the user has finished a
# statement. This doesn't really need to be an LLM, we could use NLP
# libraries for that, but it was easier as an example because we
# leverage the context aggregators.
statement_llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
statement_messages = [
{
"role": "system",
"content": "Determine if the user's statement is a complete sentence or question, ending in a natural pause or punctuation. Return 'YES' if it is complete and 'NO' if it seems to leave a thought unfinished.",
},
] ]
)
statement_context = OpenAILLMContext(statement_messages) task = PipelineTask(
statement_context_aggregator = statement_llm.create_context_aggregator(statement_context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
# This is the regular LLM. @transport.event_handler("on_client_connected")
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Kick off the conversation.
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
messages = [ @transport.event_handler("on_client_disconnected")
{ async def on_client_disconnected(transport, client):
"role": "system", logger.info(f"Client disconnected")
"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) @transport.event_handler("on_client_closed")
context_aggregator = llm.create_context_aggregator(context) async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
# We have instructed the LLM to return 'YES' if it thinks the user runner = PipelineRunner(handle_sigint=False)
# completed a sentence. So, if it's 'YES' we will return true in this
# predicate which will wake up the notifier.
async def wake_check_filter(frame):
return frame.text == "YES"
# This is a notifier that we use to synchronize the two LLMs. await runner.run(task)
notifier = EventNotifier()
# This a filter that will wake up the notifier if the given predicate
# (wake_check_filter) returns true.
completness_check = WakeNotifierFilter(
notifier, types=(TextFrame,), filter=wake_check_filter
)
# This processor keeps the last context and will let it through once the
# notifier is woken up. We start with the gate open because we send an
# initial context frame to start the conversation.
gated_context_aggregator = GatedOpenAILLMContextAggregator(
notifier=notifier, start_open=True
)
# Notify if the user hasn't said anything.
async def user_idle_notifier(frame):
await notifier.notify()
# Sometimes the LLM will fail detecting if a user has completed a
# sentence, this will wake up the notifier if that happens.
user_idle = UserIdleProcessor(callback=user_idle_notifier, timeout=3.0)
# The ParallePipeline input are the user transcripts. We have two
# contexts. The first one will be used to determine if the user finished
# a statement and if so the notifier will be woken up. The second
# context is simply the regular context but it's gated waiting for the
# notifier to be woken up.
pipeline = Pipeline(
[
transport.input(), # Transport user input
stt,
ParallelPipeline(
[
statement_context_aggregator.user(),
statement_llm,
completness_check,
NullFilter(),
],
[context_aggregator.user(), gated_context_aggregator, llm],
),
user_idle,
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask(
pipeline,
params=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"])
# Kick off the conversation.
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -6,14 +6,11 @@
import asyncio import asyncio
import os import os
import sys
import time import time
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from openai.types.chat import ChatCompletionToolParam from openai.types.chat import ChatCompletionToolParam
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import ( from pipecat.frames.frames import (
@@ -49,13 +46,12 @@ from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.sync.base_notifier import BaseNotifier from pipecat.sync.base_notifier import BaseNotifier
from pipecat.sync.event_notifier import EventNotifier from pipecat.sync.event_notifier import EventNotifier
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
classifier_statement = "Determine if the user's statement ends with a complete thought and you should respond. The user text is transcribed speech. It may contain multiple fragments concatentated together. You are trying to determine only the completeness of the last user statement. The previous assistant statement is provided only for context. Categorize the text as either complete with the user now expecting a response, or incomplete. Return 'YES' if text is likely complete and the user is expecting a response. Return 'NO' if the text seems to be a partial expression or unfinished thought." classifier_statement = "Determine if the user's statement ends with a complete thought and you should respond. The user text is transcribed speech. It may contain multiple fragments concatentated together. You are trying to determine only the completeness of the last user statement. The previous assistant statement is provided only for context. Categorize the text as either complete with the user now expecting a response, or incomplete. Return 'YES' if text is likely complete and the user is expecting a response. Return 'NO' if the text seems to be a partial expression or unfinished thought."
@@ -204,186 +200,194 @@ async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, _) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
None, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
vad_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_analyzer=SileroVADAnalyzer(), vad_audio_passthrough=True,
vad_audio_passthrough=True, ),
), )
)
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
tts = CartesiaTTSService( tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
) )
# This is the LLM that will be used to detect if the user has finished a # This is the LLM that will be used to detect if the user has finished a
# statement. This doesn't really need to be an LLM, we could use NLP # statement. This doesn't really need to be an LLM, we could use NLP
# libraries for that, but we have the machinery to use an LLM, so we might as well! # libraries for that, but we have the machinery to use an LLM, so we might as well!
statement_llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") statement_llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
# This is the regular LLM. # This is the regular LLM.
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
# You can also register a function_name of None to get all functions # You can also register a function_name of None to get all functions
# sent to the same callback with an additional function_name parameter. # sent to the same callback with an additional function_name parameter.
llm.register_function("get_current_weather", fetch_weather_from_api) llm.register_function("get_current_weather", fetch_weather_from_api)
tools = [ tools = [
ChatCompletionToolParam( ChatCompletionToolParam(
type="function", type="function",
function={ function={
"name": "get_current_weather", "name": "get_current_weather",
"description": "Get the current weather", "description": "Get the current weather",
"parameters": { "parameters": {
"type": "object", "type": "object",
"properties": { "properties": {
"location": { "location": {
"type": "string", "type": "string",
"description": "The city and state, e.g. San Francisco, CA", "description": "The city and state, e.g. San Francisco, CA",
}, },
"format": { "format": {
"type": "string", "type": "string",
"enum": ["celsius", "fahrenheit"], "enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the users location.", "description": "The temperature unit to use. Infer this from the users location.",
},
}, },
"required": ["location", "format"],
}, },
"required": ["location", "format"],
}, },
)
]
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.",
}, },
)
]
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, tools)
context_aggregator = llm.create_context_aggregator(context)
# We have instructed the LLM to return 'YES' if it thinks the user
# completed a sentence. So, if it's 'YES' we will return true in this
# predicate which will wake up the notifier.
async def wake_check_filter(frame):
logger.debug(f"Completeness check frame: {frame}")
return frame.text == "YES"
# This is a notifier that we use to synchronize the two LLMs.
notifier = EventNotifier()
# This turns the LLM context into an inference request to classify the user's speech
# as complete or incomplete.
statement_judge_context_filter = StatementJudgeContextFilter(notifier=notifier)
# This sends a UserStoppedSpeakingFrame and triggers the notifier event
completeness_check = CompletenessCheck(notifier=notifier)
# # Notify if the user hasn't said anything.
async def user_idle_notifier(frame):
await notifier.notify()
# Sometimes the LLM will fail detecting if a user has completed a
# sentence, this will wake up the notifier if that happens.
user_idle = UserIdleProcessor(callback=user_idle_notifier, timeout=5.0)
# We start with the gate open because we send an initial context frame
# to start the conversation.
bot_output_gate = OutputGate(notifier=notifier, start_open=True)
async def block_user_stopped_speaking(frame):
return not isinstance(frame, UserStoppedSpeakingFrame)
async def pass_only_llm_trigger_frames(frame):
return (
isinstance(frame, OpenAILLMContextFrame)
or isinstance(frame, LLMMessagesFrame)
or isinstance(frame, StartInterruptionFrame)
or isinstance(frame, StopInterruptionFrame)
or isinstance(frame, FunctionCallInProgressFrame)
or isinstance(frame, FunctionCallResultFrame)
)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
ParallelPipeline(
[
# Pass everything except UserStoppedSpeaking to the elements after
# this ParallelPipeline
FunctionFilter(filter=block_user_stopped_speaking),
],
[
# Ignore everything except an OpenAILLMContextFrame. Pass a specially constructed
# LLMMessagesFrame to the statement classifier LLM. The only frame this
# sub-pipeline will output is a UserStoppedSpeakingFrame.
statement_judge_context_filter,
statement_llm,
completeness_check,
],
[
# Block everything except OpenAILLMContextFrame and LLMMessagesFrame
FunctionFilter(filter=pass_only_llm_trigger_frames),
llm,
bot_output_gate, # Buffer all llm/tts output until notified.
],
),
tts,
user_idle,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
# We have instructed the LLM to return 'YES' if it thinks the user @transport.event_handler("on_client_connected")
# completed a sentence. So, if it's 'YES' we will return true in this async def on_client_connected(transport, client):
# predicate which will wake up the notifier. logger.info(f"Client connected")
async def wake_check_filter(frame): # Kick off the conversation.
logger.debug(f"Completeness check frame: {frame}") messages.append({"role": "system", "content": "Please introduce yourself to the user."})
return frame.text == "YES" await task.queue_frames([context_aggregator.user().get_context_frame()])
# This is a notifier that we use to synchronize the two LLMs. @transport.event_handler("on_app_message")
notifier = EventNotifier() async def on_app_message(transport, message):
logger.debug(f"Received app message: {message}")
if "message" not in message:
return
# This turns the LLM context into an inference request to classify the user's speech await task.queue_frames(
# as complete or incomplete.
statement_judge_context_filter = StatementJudgeContextFilter(notifier=notifier)
# This sends a UserStoppedSpeakingFrame and triggers the notifier event
completeness_check = CompletenessCheck(notifier=notifier)
# # Notify if the user hasn't said anything.
async def user_idle_notifier(frame):
await notifier.notify()
# Sometimes the LLM will fail detecting if a user has completed a
# sentence, this will wake up the notifier if that happens.
user_idle = UserIdleProcessor(callback=user_idle_notifier, timeout=5.0)
# We start with the gate open because we send an initial context frame
# to start the conversation.
bot_output_gate = OutputGate(notifier=notifier, start_open=True)
async def block_user_stopped_speaking(frame):
return not isinstance(frame, UserStoppedSpeakingFrame)
async def pass_only_llm_trigger_frames(frame):
return (
isinstance(frame, OpenAILLMContextFrame)
or isinstance(frame, LLMMessagesFrame)
or isinstance(frame, StartInterruptionFrame)
or isinstance(frame, StopInterruptionFrame)
or isinstance(frame, FunctionCallInProgressFrame)
or isinstance(frame, FunctionCallResultFrame)
)
pipeline = Pipeline(
[ [
transport.input(), UserStartedSpeakingFrame(),
stt, TranscriptionFrame(user_id="", timestamp=time.time(), text=message["message"]),
context_aggregator.user(), UserStoppedSpeakingFrame(),
ParallelPipeline(
[
# Pass everything except UserStoppedSpeaking to the elements after
# this ParallelPipeline
FunctionFilter(filter=block_user_stopped_speaking),
],
[
# Ignore everything except an OpenAILLMContextFrame. Pass a specially constructed
# LLMMessagesFrame to the statement classifier LLM. The only frame this
# sub-pipeline will output is a UserStoppedSpeakingFrame.
statement_judge_context_filter,
statement_llm,
completeness_check,
],
[
# Block everything except OpenAILLMContextFrame and LLMMessagesFrame
FunctionFilter(filter=pass_only_llm_trigger_frames),
llm,
bot_output_gate, # Buffer all llm/tts output until notified.
],
),
tts,
user_idle,
transport.output(),
context_aggregator.assistant(),
] ]
) )
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_app_message") runner = PipelineRunner(handle_sigint=False)
async def on_app_message(transport, message, sender):
logger.debug(f"Received app message: {message} - {sender}")
if "message" not in message:
return
await task.queue_frames( await runner.run(task)
[
UserStartedSpeakingFrame(),
TranscriptionFrame(
user_id=sender, timestamp=time.time(), text=message["message"]
),
UserStoppedSpeakingFrame(),
]
)
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -6,14 +6,11 @@
import asyncio import asyncio
import os import os
import sys
import time import time
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from openai.types.chat import ChatCompletionToolParam from openai.types.chat import ChatCompletionToolParam
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import ( from pipecat.frames.frames import (
@@ -50,13 +47,12 @@ from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.sync.base_notifier import BaseNotifier from pipecat.sync.base_notifier import BaseNotifier
from pipecat.sync.event_notifier import EventNotifier from pipecat.sync.event_notifier import EventNotifier
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
classifier_statement = """CRITICAL INSTRUCTION: classifier_statement = """CRITICAL INSTRUCTION:
You are a BINARY CLASSIFIER that must ONLY output "YES" or "NO". You are a BINARY CLASSIFIER that must ONLY output "YES" or "NO".
@@ -408,195 +404,203 @@ async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, _) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
None, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
vad_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_analyzer=SileroVADAnalyzer(), vad_audio_passthrough=True,
vad_audio_passthrough=True, ),
), )
)
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
tts = CartesiaTTSService( tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
) )
# This is the LLM that will be used to detect if the user has finished a # This is the LLM that will be used to detect if the user has finished a
# statement. This doesn't really need to be an LLM, we could use NLP # statement. This doesn't really need to be an LLM, we could use NLP
# libraries for that, but we have the machinery to use an LLM, so we might as well! # libraries for that, but we have the machinery to use an LLM, so we might as well!
statement_llm = AnthropicLLMService( statement_llm = AnthropicLLMService(
api_key=os.getenv("ANTHROPIC_API_KEY"), api_key=os.getenv("ANTHROPIC_API_KEY"),
model="claude-3-5-sonnet-20241022", model="claude-3-5-sonnet-20241022",
) )
# This is the regular LLM. # This is the regular LLM.
llm = OpenAILLMService( llm = OpenAILLMService(
api_key=os.getenv("OPENAI_API_KEY"), api_key=os.getenv("OPENAI_API_KEY"),
model="gpt-4o", model="gpt-4o",
) )
# Register a function_name of None to get all functions # Register a function_name of None to get all functions
# sent to the same callback with an additional function_name parameter. # sent to the same callback with an additional function_name parameter.
llm.register_function("get_current_weather", fetch_weather_from_api) llm.register_function("get_current_weather", fetch_weather_from_api)
tools = [ tools = [
ChatCompletionToolParam( ChatCompletionToolParam(
type="function", type="function",
function={ function={
"name": "get_current_weather", "name": "get_current_weather",
"description": "Get the current weather", "description": "Get the current weather",
"parameters": { "parameters": {
"type": "object", "type": "object",
"properties": { "properties": {
"location": { "location": {
"type": "string", "type": "string",
"description": "The city and state, e.g. San Francisco, CA", "description": "The city and state, e.g. San Francisco, CA",
}, },
"format": { "format": {
"type": "string", "type": "string",
"enum": ["celsius", "fahrenheit"], "enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the users location.", "description": "The temperature unit to use. Infer this from the users location.",
},
}, },
"required": ["location", "format"],
}, },
"required": ["location", "format"],
}, },
)
]
messages = [
{
"role": "system",
"content": conversational_system_message,
}, },
)
]
messages = [
{
"role": "system",
"content": conversational_system_message,
},
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
# We have instructed the LLM to return 'YES' if it thinks the user
# completed a sentence. So, if it's 'YES' we will return true in this
# predicate which will wake up the notifier.
async def wake_check_filter(frame):
return frame.text == "YES"
# This is a notifier that we use to synchronize the two LLMs.
notifier = EventNotifier()
# This turns the LLM context into an inference request to classify the user's speech
# as complete or incomplete.
statement_judge_context_filter = StatementJudgeContextFilter(notifier=notifier)
# This sends a UserStoppedSpeakingFrame and triggers the notifier event
completeness_check = CompletenessCheck(notifier=notifier)
# # Notify if the user hasn't said anything.
async def user_idle_notifier(frame):
await notifier.notify()
# Sometimes the LLM will fail detecting if a user has completed a
# sentence, this will wake up the notifier if that happens.
user_idle = UserIdleProcessor(callback=user_idle_notifier, timeout=5.0)
# We start with the gate open because we send an initial context frame
# to start the conversation.
bot_output_gate = OutputGate(notifier=notifier, start_open=True)
async def block_user_stopped_speaking(frame):
return not isinstance(frame, UserStoppedSpeakingFrame)
async def pass_only_llm_trigger_frames(frame):
return (
isinstance(frame, OpenAILLMContextFrame)
or isinstance(frame, LLMMessagesFrame)
or isinstance(frame, StartInterruptionFrame)
or isinstance(frame, StopInterruptionFrame)
or isinstance(frame, FunctionCallInProgressFrame)
or isinstance(frame, FunctionCallResultFrame)
)
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
ParallelPipeline(
[
# Pass everything except UserStoppedSpeaking to the elements after
# this ParallelPipeline
FunctionFilter(filter=block_user_stopped_speaking),
],
[
# Ignore everything except an OpenAILLMContextFrame. Pass a specially constructed
# LLMMessagesFrame to the statement classifier LLM. The only frame this
# sub-pipeline will output is a UserStoppedSpeakingFrame.
statement_judge_context_filter,
statement_llm,
completeness_check,
],
[
# Block everything except OpenAILLMContextFrame and LLMMessagesFrame
FunctionFilter(filter=pass_only_llm_trigger_frames),
llm,
bot_output_gate, # Buffer all llm/tts output until notified.
],
),
tts,
user_idle,
transport.output(),
context_aggregator.assistant(),
] ]
)
context = OpenAILLMContext(messages, tools) task = PipelineTask(
context_aggregator = llm.create_context_aggregator(context) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
# We have instructed the LLM to return 'YES' if it thinks the user @transport.event_handler("on_client_connected")
# completed a sentence. So, if it's 'YES' we will return true in this async def on_client_connected(transport, client):
# predicate which will wake up the notifier. logger.info(f"Client connected")
async def wake_check_filter(frame): # Kick off the conversation.
return frame.text == "YES" messages.append(
{
"role": "user",
"content": "Start by just saying \"Hello I'm ready.\" Don't say anything else.",
}
)
await task.queue_frames([context_aggregator.user().get_context_frame()])
# This is a notifier that we use to synchronize the two LLMs. @transport.event_handler("on_app_message")
notifier = EventNotifier() async def on_app_message(transport, message):
logger.debug(f"Received app message: {message}")
if "message" not in message:
return
# This turns the LLM context into an inference request to classify the user's speech await task.queue_frames(
# as complete or incomplete.
statement_judge_context_filter = StatementJudgeContextFilter(notifier=notifier)
# This sends a UserStoppedSpeakingFrame and triggers the notifier event
completeness_check = CompletenessCheck(notifier=notifier)
# # Notify if the user hasn't said anything.
async def user_idle_notifier(frame):
await notifier.notify()
# Sometimes the LLM will fail detecting if a user has completed a
# sentence, this will wake up the notifier if that happens.
user_idle = UserIdleProcessor(callback=user_idle_notifier, timeout=5.0)
# We start with the gate open because we send an initial context frame
# to start the conversation.
bot_output_gate = OutputGate(notifier=notifier, start_open=True)
async def block_user_stopped_speaking(frame):
return not isinstance(frame, UserStoppedSpeakingFrame)
async def pass_only_llm_trigger_frames(frame):
return (
isinstance(frame, OpenAILLMContextFrame)
or isinstance(frame, LLMMessagesFrame)
or isinstance(frame, StartInterruptionFrame)
or isinstance(frame, StopInterruptionFrame)
or isinstance(frame, FunctionCallInProgressFrame)
or isinstance(frame, FunctionCallResultFrame)
)
pipeline = Pipeline(
[ [
transport.input(), UserStartedSpeakingFrame(),
stt, TranscriptionFrame(user_id="", timestamp=time.time(), text=message["message"]),
context_aggregator.user(), UserStoppedSpeakingFrame(),
ParallelPipeline(
[
# Pass everything except UserStoppedSpeaking to the elements after
# this ParallelPipeline
FunctionFilter(filter=block_user_stopped_speaking),
],
[
# Ignore everything except an OpenAILLMContextFrame. Pass a specially constructed
# LLMMessagesFrame to the statement classifier LLM. The only frame this
# sub-pipeline will output is a UserStoppedSpeakingFrame.
statement_judge_context_filter,
statement_llm,
completeness_check,
],
[
# Block everything except OpenAILLMContextFrame and LLMMessagesFrame
FunctionFilter(filter=pass_only_llm_trigger_frames),
llm,
bot_output_gate, # Buffer all llm/tts output until notified.
],
),
tts,
user_idle,
transport.output(),
context_aggregator.assistant(),
] ]
) )
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await transport.capture_participant_transcription(participant["id"]) logger.info(f"Client closed connection")
# Kick off the conversation. await task.cancel()
messages.append(
{
"role": "user",
"content": "Start by just saying \"Hello I'm ready.\" Don't say anything else.",
}
)
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_app_message") runner = PipelineRunner(handle_sigint=False)
async def on_app_message(transport, message, sender):
logger.debug(f"Received app message: {message} - {sender}")
if "message" not in message:
return
await task.queue_frames( await runner.run(task)
[
UserStartedSpeakingFrame(),
TranscriptionFrame(
user_id=sender, timestamp=time.time(), text=message["message"]
),
UserStoppedSpeakingFrame(),
]
)
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -6,14 +6,11 @@
import asyncio import asyncio
import os import os
import sys
import time import time
import aiohttp
import google.ai.generativelanguage as glm import google.ai.generativelanguage as glm
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import ( from pipecat.frames.frames import (
@@ -47,12 +44,12 @@ from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.google.llm import GoogleLLMContext, GoogleLLMService from pipecat.services.google.llm import GoogleLLMContext, GoogleLLMService
from pipecat.sync.base_notifier import BaseNotifier from pipecat.sync.base_notifier import BaseNotifier
from pipecat.sync.event_notifier import EventNotifier from pipecat.sync.event_notifier import EventNotifier
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
TRANSCRIBER_MODEL = "gemini-2.0-flash-001" TRANSCRIBER_MODEL = "gemini-2.0-flash-001"
CLASSIFIER_MODEL = "gemini-2.0-flash-001" CLASSIFIER_MODEL = "gemini-2.0-flash-001"
@@ -626,149 +623,155 @@ class OutputGate(FrameProcessor):
break break
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, _) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
None, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
vad_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_analyzer=SileroVADAnalyzer(), vad_audio_passthrough=True,
vad_audio_passthrough=True, ),
), )
)
tts = CartesiaTTSService( tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"), api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
) )
# This is the LLM that will transcribe user speech. # This is the LLM that will transcribe user speech.
tx_llm = GoogleLLMService( tx_llm = GoogleLLMService(
name="Transcriber", name="Transcriber",
model=TRANSCRIBER_MODEL, model=TRANSCRIBER_MODEL,
api_key=os.getenv("GOOGLE_API_KEY"), api_key=os.getenv("GOOGLE_API_KEY"),
temperature=0.0, temperature=0.0,
system_instruction=transcriber_system_instruction, system_instruction=transcriber_system_instruction,
) )
# This is the LLM that will classify user speech as complete or incomplete. # This is the LLM that will classify user speech as complete or incomplete.
classifier_llm = GoogleLLMService( classifier_llm = GoogleLLMService(
name="Classifier", name="Classifier",
model=CLASSIFIER_MODEL, model=CLASSIFIER_MODEL,
api_key=os.getenv("GOOGLE_API_KEY"), api_key=os.getenv("GOOGLE_API_KEY"),
temperature=0.0, temperature=0.0,
system_instruction=classifier_system_instruction, system_instruction=classifier_system_instruction,
) )
# This is the regular LLM that responds conversationally. # This is the regular LLM that responds conversationally.
conversation_llm = GoogleLLMService( conversation_llm = GoogleLLMService(
name="Conversation", name="Conversation",
model=CONVERSATION_MODEL, model=CONVERSATION_MODEL,
api_key=os.getenv("GOOGLE_API_KEY"), api_key=os.getenv("GOOGLE_API_KEY"),
system_instruction=conversation_system_instruction, system_instruction=conversation_system_instruction,
) )
context = OpenAILLMContext() context = OpenAILLMContext()
context_aggregator = conversation_llm.create_context_aggregator(context) context_aggregator = conversation_llm.create_context_aggregator(context)
# This is a notifier that we use to synchronize the two LLMs. # This is a notifier that we use to synchronize the two LLMs.
notifier = EventNotifier() notifier = EventNotifier()
# This turns the LLM context into an inference request to classify the user's speech # This turns the LLM context into an inference request to classify the user's speech
# as complete or incomplete. # as complete or incomplete.
# statement_judge_context_filter = StatementJudgeAudioContextAccumulator(notifier=notifier) # statement_judge_context_filter = StatementJudgeAudioContextAccumulator(notifier=notifier)
audio_accumulater = AudioAccumulator() audio_accumulater = AudioAccumulator()
# This sends a UserStoppedSpeakingFrame and triggers the notifier event # This sends a UserStoppedSpeakingFrame and triggers the notifier event
completeness_check = CompletenessCheck( completeness_check = CompletenessCheck(notifier=notifier, audio_accumulator=audio_accumulater)
notifier=notifier, audio_accumulator=audio_accumulater
)
async def block_user_stopped_speaking(frame): async def block_user_stopped_speaking(frame):
return not isinstance(frame, UserStoppedSpeakingFrame) return not isinstance(frame, UserStoppedSpeakingFrame)
conversation_audio_context_assembler = ConversationAudioContextAssembler(context=context) conversation_audio_context_assembler = ConversationAudioContextAssembler(context=context)
llm_aggregator_buffer = LLMAggregatorBuffer() llm_aggregator_buffer = LLMAggregatorBuffer()
bot_output_gate = OutputGate( bot_output_gate = OutputGate(
notifier=notifier, context=context, llm_transcription_buffer=llm_aggregator_buffer notifier=notifier, context=context, llm_transcription_buffer=llm_aggregator_buffer
) )
pipeline = Pipeline( pipeline = Pipeline(
[ [
transport.input(), transport.input(),
audio_accumulater, audio_accumulater,
ParallelPipeline( ParallelPipeline(
[
# Pass everything except UserStoppedSpeaking to the elements after
# this ParallelPipeline
FunctionFilter(filter=block_user_stopped_speaking),
],
[
ParallelPipeline(
[
classifier_llm,
completeness_check,
],
[
tx_llm,
llm_aggregator_buffer,
],
)
],
[
conversation_audio_context_assembler,
conversation_llm,
bot_output_gate, # buffer output until notified, then flush frames and update context
# TempPrinter(),
],
),
tts,
transport.output(),
context_aggregator.assistant(),
],
)
task = PipelineTask(
pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined")
async def on_first_participant_joined(transport, participant):
await transport.capture_participant_transcription(participant["id"])
# Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_app_message")
async def on_app_message(transport, message, sender):
logger.debug(f"Received app message: {message} - {sender}")
if "message" not in message:
return
await task.queue_frames(
[ [
UserStartedSpeakingFrame(), # Pass everything except UserStoppedSpeaking to the elements after
TranscriptionFrame( # this ParallelPipeline
user_id=sender, timestamp=time.time(), text=message["message"] FunctionFilter(filter=block_user_stopped_speaking),
), ],
UserStoppedSpeakingFrame(), [
] ParallelPipeline(
) [
classifier_llm,
completeness_check,
],
[
tx_llm,
llm_aggregator_buffer,
],
)
],
[
conversation_audio_context_assembler,
conversation_llm,
bot_output_gate, # buffer output until notified, then flush frames and update context
# TempPrinter(),
],
),
tts,
transport.output(),
context_aggregator.assistant(),
],
)
runner = PipelineRunner() task = PipelineTask(
await runner.run(task) pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_app_message")
async def on_app_message(transport, message):
logger.debug(f"Received app message: {message}")
if "message" not in message:
return
await task.queue_frames(
[
UserStartedSpeakingFrame(),
TranscriptionFrame(user_id="", timestamp=time.time(), text=message["message"]),
UserStoppedSpeakingFrame(),
]
)
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -10,9 +10,9 @@ import os
import sys import sys
import aiohttp import aiohttp
from daily_runner import configure_with_args
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure_with_args
from pipecat.audio.mixers.soundfile_mixer import SoundfileMixer from pipecat.audio.mixers.soundfile_mixer import SoundfileMixer
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer

View File

@@ -0,0 +1,140 @@
#
# Copyright (c) 20242025, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
"""
Usage
-----
Set the path to your background audio file using the `INPUT_AUDIO_PATH` environment variable, then run the bot using:
INPUT_AUDIO_PATH=path/to/your_audio.mp3 python 23-bot-background-sound.py
Example:
INPUT_AUDIO_PATH=my_audio.mp3 python 23-bot-background-sound.py
"""
import asyncio
import os
from dotenv import load_dotenv
from loguru import logger
from pipecat.audio.mixers.soundfile_mixer import SoundfileMixer
from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import MixerEnableFrame, MixerUpdateSettingsFrame
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.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True)
audio_path = os.getenv("INPUT_AUDIO_PATH")
if not audio_path:
raise ValueError("No INPUT_AUDIO_PATH specified in environment variables")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
soundfile_mixer = SoundfileMixer(
sound_files={"office": audio_path},
default_sound="office",
volume=2.0,
)
transport = SmallWebRTCTransport(
webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
audio_out_mixer=soundfile_mixer,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
),
)
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading 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
stt, # STT service
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
)
task = PipelineTask(
pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
report_only_initial_ttfb=True,
),
)
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected: {client}")
# 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([context_aggregator.user().get_context_frame()])
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__":
from run import main
main()

View File

@@ -6,14 +6,12 @@
import asyncio import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from openai.types.chat import ChatCompletionToolParam
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
@@ -23,13 +21,12 @@ from pipecat.processors.filters.stt_mute_filter import STTMuteConfig, STTMuteFil
from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.deepgram.tts import DeepgramTTSService from pipecat.services.deepgram.tts import DeepgramTTSService
from pipecat.services.openai.llm import OpenAILLMService from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
# Add a delay to test interruption during function calls # Add a delay to test interruption during function calls
@@ -39,103 +36,107 @@ async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context
await result_callback({"conditions": "nice", "temperature": "75"}) await result_callback({"conditions": "nice", "temperature": "75"})
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, _) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
None, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
vad_enabled=True, vad_analyzer=SileroVADAnalyzer(),
vad_analyzer=SileroVADAnalyzer(), vad_audio_passthrough=True,
vad_audio_passthrough=True, ),
), )
)
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
# Configure the mute processor with both strategies
stt_mute_processor = STTMuteFilter(
config=STTMuteConfig(
strategies={
STTMuteStrategy.MUTE_UNTIL_FIRST_BOT_COMPLETE,
STTMuteStrategy.FUNCTION_CALL,
}
),
)
tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en") # Configure the mute processor with both strategies
stt_mute_processor = STTMuteFilter(
config=STTMuteConfig(
strategies={
STTMuteStrategy.MUTE_UNTIL_FIRST_BOT_COMPLETE,
STTMuteStrategy.FUNCTION_CALL,
}
),
)
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o") tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en")
llm.register_function("get_current_weather", fetch_weather_from_api)
tools = [ llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
ChatCompletionToolParam( llm.register_function("get_current_weather", fetch_weather_from_api)
type="function",
function={ weather_function = FunctionSchema(
"name": "get_current_weather", name="get_current_weather",
"description": "Get the current weather", description="Get the current weather",
"parameters": { properties={
"type": "object", "location": {
"properties": { "type": "string",
"location": { "description": "The city and state, e.g. San Francisco, CA",
"type": "string", },
"description": "The city and state, e.g. San Francisco, CA", "format": {
}, "type": "string",
"format": { "enum": ["celsius", "fahrenheit"],
"type": "string", "description": "The temperature unit to use. Infer this from the user's location.",
"enum": ["celsius", "fahrenheit"], },
"description": "The temperature unit to use. Infer this from the users location.", },
}, required=["location", "format"],
}, )
"required": ["location", "format"], tools = ToolsSchema(standard_tools=[weather_function])
},
}, messages = [
) {
"role": "system",
"content": "You are a helpful assistant who can check the weather. Always check the weather when a location is mentioned. Respond concisely and naturally. Your output will be converted to audio so use only simple words and punctuation.",
},
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(), # Transport user input
stt_mute_processor, # Add the mute processor before STT
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
] ]
)
messages = [ task = PipelineTask(pipeline, params=PipelineParams(allow_interruptions=True))
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Kick off the conversation with a weather-related prompt
messages.append(
{ {
"role": "system", "role": "system",
"content": "You are a helpful assistant who can check the weather. Always check the weather when a location is mentioned. Respond concisely and naturally. Your output will be converted to audio so use only simple words and punctuation.", "content": "Ask the user what city they'd like to know the weather for.",
}, }
]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline(
[
transport.input(), # Transport user input
stt_mute_processor, # Add the mute processor before STT
stt, # STT
context_aggregator.user(), # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
context_aggregator.assistant(), # Assistant spoken responses
]
) )
await task.queue_frames([context_aggregator.user().get_context_frame()])
task = PipelineTask(pipeline, params=PipelineParams(allow_interruptions=True)) @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
# Kick off the conversation with a weather-related prompt logger.info(f"Client closed connection")
messages.append( await task.cancel()
{
"role": "system",
"content": "Ask the user what city they'd like to know the weather for.",
}
)
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,16 +4,12 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
from dataclasses import dataclass from dataclasses import dataclass
import aiohttp
import google.ai.generativelanguage as glm import google.ai.generativelanguage as glm
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import ( from pipecat.frames.frames import (
@@ -37,13 +33,12 @@ from pipecat.processors.aggregators.openai_llm_context import (
from pipecat.processors.frame_processor import FrameProcessor from pipecat.processors.frame_processor import FrameProcessor
from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.google.llm import GoogleLLMContext, GoogleLLMService from pipecat.services.google.llm import GoogleLLMContext, GoogleLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
# #
# The system prompt for the main conversation. # The system prompt for the main conversation.
# #
@@ -273,102 +268,110 @@ class TranscriptionContextFixup(FrameProcessor):
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( transport = SmallWebRTCTransport(
room_url, webrtc_connection=webrtc_connection,
token, params=TransportParams(
"Respond bot", audio_in_enabled=True,
DailyParams( audio_out_enabled=True,
audio_out_enabled=True, vad_enabled=True,
# No transcription at all. just audio input to Gemini! vad_analyzer=SileroVADAnalyzer(),
# transcription_enabled=True, vad_audio_passthrough=True,
vad_enabled=True, ),
vad_analyzer=SileroVADAnalyzer(), )
vad_audio_passthrough=True,
tts = CartesiaTTSService(
api_key=os.getenv("CARTESIA_API_KEY"),
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
conversation_llm = GoogleLLMService(
name="Conversation",
model="gemini-2.0-flash-001",
# model="gemini-exp-1121",
api_key=os.getenv("GOOGLE_API_KEY"),
# we can give the GoogleLLMService a system instruction to use directly
# in the GenerativeModel constructor. Let's do that rather than put
# our system message in the messages list.
system_instruction=conversation_system_message,
)
input_transcription_llm = GoogleLLMService(
name="Transcription",
model="gemini-2.0-flash-001",
# model="gemini-exp-1121",
api_key=os.getenv("GOOGLE_API_KEY"),
system_instruction=transcriber_system_message,
)
messages = [
{
"role": "user",
"content": "Start by saying hello.",
},
]
context = OpenAILLMContext(messages)
context_aggregator = conversation_llm.create_context_aggregator(context)
audio_collector = UserAudioCollector(context, context_aggregator.user())
input_transcription_context_filter = InputTranscriptionContextFilter()
transcription_frames_emitter = InputTranscriptionFrameEmitter()
fixup_context_messages = TranscriptionContextFixup(context)
pipeline = Pipeline(
[
transport.input(),
audio_collector,
context_aggregator.user(),
ParallelPipeline(
[ # transcribe
input_transcription_context_filter,
input_transcription_llm,
transcription_frames_emitter,
],
[ # conversation inference
conversation_llm,
],
), ),
) tts,
transport.output(),
tts = CartesiaTTSService( context_aggregator.assistant(),
api_key=os.getenv("CARTESIA_API_KEY"), fixup_context_messages,
voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady
)
conversation_llm = GoogleLLMService(
name="Conversation",
model="gemini-2.0-flash-001",
# model="gemini-exp-1121",
api_key=os.getenv("GOOGLE_API_KEY"),
# we can give the GoogleLLMService a system instruction to use directly
# in the GenerativeModel constructor. Let's do that rather than put
# our system message in the messages list.
system_instruction=conversation_system_message,
)
input_transcription_llm = GoogleLLMService(
name="Transcription",
model="gemini-2.0-flash-001",
# model="gemini-exp-1121",
api_key=os.getenv("GOOGLE_API_KEY"),
system_instruction=transcriber_system_message,
)
messages = [
{
"role": "user",
"content": "Start by saying hello.",
},
] ]
)
context = OpenAILLMContext(messages) task = PipelineTask(
context_aggregator = conversation_llm.create_context_aggregator(context) pipeline,
audio_collector = UserAudioCollector(context, context_aggregator.user()) params=PipelineParams(
input_transcription_context_filter = InputTranscriptionContextFilter() allow_interruptions=True,
transcription_frames_emitter = InputTranscriptionFrameEmitter() enable_metrics=True,
fixup_context_messages = TranscriptionContextFixup(context) enable_usage_metrics=True,
),
)
pipeline = Pipeline( @transport.event_handler("on_client_connected")
[ async def on_client_connected(transport, client):
transport.input(), logger.info(f"Client connected")
audio_collector, # Kick off the conversation.
context_aggregator.user(), await task.queue_frames([context_aggregator.user().get_context_frame()])
ParallelPipeline(
[ # transcribe
input_transcription_context_filter,
input_transcription_llm,
transcription_frames_emitter,
],
[ # conversation inference
conversation_llm,
],
),
tts,
transport.output(),
context_aggregator.assistant(),
fixup_context_messages,
]
)
task = PipelineTask( @transport.event_handler("on_client_disconnected")
pipeline, async def on_client_disconnected(transport, client):
params=PipelineParams( logger.info(f"Client disconnected")
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
# Kick off the conversation. logger.info(f"Client closed connection")
await task.queue_frames([context_aggregator.user().get_context_frame()]) await task.cancel()
runner = PipelineRunner() runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.audio.vad.vad_analyzer import VADParams
@@ -20,75 +16,100 @@ from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.services.gemini_multimodal_live.gemini import GeminiMultimodalLiveLLMService from pipecat.services.gemini_multimodal_live.gemini import GeminiMultimodalLiveLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
# Load environment variables
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): # Initialize the SmallWebRTCTransport with the connection
async with aiohttp.ClientSession() as session: transport = SmallWebRTCTransport(
(room_url, token) = await configure(session) webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
camera_in_enabled=False,
vad_enabled=True,
vad_audio_passthrough=True,
# set stop_secs to something roughly similar to the internal setting
# of the Multimodal Live api, just to align events.
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)),
),
)
transport = DailyTransport( # Create the Gemini Multimodal Live LLM service
room_url, system_instruction = f"""
token, You are a helpful AI assistant.
"Respond bot", Your goal is to demonstrate your capabilities in a helpful and engaging way.
DailyParams( Your output will be converted to audio so don't include special characters in your answers.
audio_out_enabled=True, Respond to what the user said in a creative and helpful way.
vad_enabled=True, """
vad_audio_passthrough=True,
# set stop_secs to something roughly similar to the internal setting
# of the Multimodal Live api, just to align events. This doesn't really
# matter because we can only use the Multimodal Live API's phrase
# endpointing, for now.
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)),
),
)
llm = GeminiMultimodalLiveLLMService( llm = GeminiMultimodalLiveLLMService(
api_key=os.getenv("GOOGLE_API_KEY"), api_key=os.getenv("GOOGLE_API_KEY"),
# system_instruction="Talk like a pirate." system_instruction=system_instruction,
) voice_id="Puck", # Aoede, Charon, Fenrir, Kore, Puck
transcribe_user_audio=True,
)
pipeline = Pipeline( # Build the pipeline
pipeline = Pipeline(
[
transport.input(),
llm,
transport.output(),
]
)
# Configure the pipeline task
task = PipelineTask(
pipeline,
params=PipelineParams(
allow_interruptions=True,
enable_metrics=True,
enable_usage_metrics=True,
),
)
# Handle client connection event
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info(f"Client connected")
# Kick off the conversation.
await task.queue_frames(
[ [
transport.input(), LLMMessagesAppendFrame(
llm, messages=[
transport.output(), {
"role": "user",
"content": f"Greet the user and introduce yourself.",
}
]
)
] ]
) )
task = PipelineTask( # Handle client disconnection events
pipeline, @transport.event_handler("on_client_disconnected")
params=PipelineParams( async def on_client_disconnected(transport, client):
allow_interruptions=True, logger.info(f"Client disconnected")
enable_metrics=True,
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_closed")
async def on_first_participant_joined(transport, participant): async def on_client_closed(transport, client):
await task.queue_frames( logger.info(f"Client closed connection")
[ await task.cancel()
LLMMessagesAppendFrame(
messages=[
{
"role": "user",
"content": "Greet the user.",
}
]
)
]
)
runner = PipelineRunner() # Run the pipeline
runner = PipelineRunner(handle_sigint=False)
await runner.run(task) await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,14 +4,10 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.audio.vad.vad_analyzer import VADParams
@@ -20,90 +16,100 @@ 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.gemini_multimodal_live.gemini import GeminiMultimodalLiveLLMService from pipecat.services.gemini_multimodal_live.gemini import GeminiMultimodalLiveLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def run_bot(webrtc_connection: SmallWebRTCConnection):
logger.info(f"Starting bot")
async def main(): # Initialize the SmallWebRTCTransport with the connection
async with aiohttp.ClientSession() as session: transport = SmallWebRTCTransport(
(room_url, token) = await configure(session) webrtc_connection=webrtc_connection,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_enabled=True,
vad_audio_passthrough=True,
# set stop_secs to something roughly similar to the internal setting
# of the Multimodal Live api, just to align events. This doesn't really
# matter because we can only use the Multimodal Live API's phrase
# endpointing, for now.
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)),
),
)
transport = DailyTransport( llm = GeminiMultimodalLiveLLMService(
room_url, api_key=os.getenv("GOOGLE_API_KEY"),
token, voice_id="Aoede", # Puck, Charon, Kore, Fenrir, Aoede
"Respond bot", # system_instruction="Talk like a pirate."
DailyParams( transcribe_user_audio=True,
audio_out_enabled=True, # inference_on_context_initialization=False,
vad_enabled=True, )
vad_audio_passthrough=True,
# set stop_secs to something roughly similar to the internal setting
# of the Multimodal Live api, just to align events. This doesn't really
# matter because we can only use the Multimodal Live API's phrase
# endpointing, for now.
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)),
),
)
llm = GeminiMultimodalLiveLLMService( context = OpenAILLMContext(
api_key=os.getenv("GOOGLE_API_KEY"), [
voice_id="Aoede", # Puck, Charon, Kore, Fenrir, Aoede {
# system_instruction="Talk like a pirate." "role": "user",
transcribe_user_audio=True, "content": "Say hello. Then ask if I want to hear a joke.",
transcribe_model_audio=True, },
# inference_on_context_initialization=False, # {"role": "assistant", "content": "Hello! Why don't scientists trust atoms?"},
) # {
# "role": "user",
# "content": [
# {
# "type": "text",
# "text": "Oh, I know this one: because they make up everything.",
# }
# ],
# },
],
)
context_aggregator = llm.create_context_aggregator(context)
context = OpenAILLMContext( pipeline = Pipeline(
[ [
{ transport.input(),
"role": "user", context_aggregator.user(),
"content": "Say hello. Then ask if I want to hear a joke.", llm,
}, transport.output(),
# {"role": "assistant", "content": "Hello! Why don't scientists trust atoms?"}, context_aggregator.assistant(),
# { ]
# "role": "user", )
# "content": [
# {
# "type": "text",
# "text": "Oh, I know this one: because they make up everything.",
# }
# ],
# },
],
)
context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline( task = PipelineTask(
[ pipeline,
transport.input(), params=PipelineParams(
context_aggregator.user(), allow_interruptions=True,
llm, enable_metrics=True,
transport.output(), enable_usage_metrics=True,
context_aggregator.assistant(), ),
] )
)
task = PipelineTask( @transport.event_handler("on_client_connected")
pipeline, async def on_client_connected(transport, client):
params=PipelineParams( logger.info(f"Client connected")
allow_interruptions=True, # Kick off the conversation.
enable_metrics=True, await task.queue_frames([context_aggregator.user().get_context_frame()])
enable_usage_metrics=True,
),
)
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_disconnected")
async def on_first_participant_joined(transport, participant): async def on_client_disconnected(transport, client):
await task.queue_frames([context_aggregator.user().get_context_frame()]) logger.info(f"Client disconnected")
runner = PipelineRunner() @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
await runner.run(task) runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -4,15 +4,11 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
import asyncio
import os import os
import sys
from datetime import datetime from datetime import datetime
import aiohttp
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import AdapterType, ToolsSchema from pipecat.adapters.schemas.tools_schema import AdapterType, ToolsSchema
@@ -23,13 +19,12 @@ 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.gemini_multimodal_live.gemini import GeminiMultimodalLiveLLMService from pipecat.services.gemini_multimodal_live.gemini import GeminiMultimodalLiveLLMService
from pipecat.transports.services.daily import DailyParams, DailyTransport from pipecat.transports.base_transport import TransportParams
from pipecat.transports.network.small_webrtc import SmallWebRTCTransport
from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection
load_dotenv(override=True) load_dotenv(override=True)
logger.remove(0)
logger.add(sys.stderr, level="DEBUG")
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback): async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
temperature = 75 if args["format"] == "fahrenheit" else 24 temperature = 75 if args["format"] == "fahrenheit" else 24
@@ -51,87 +46,99 @@ for the weather, call this function.
""" """
async def main(): async def run_bot(webrtc_connection: SmallWebRTCConnection):
async with aiohttp.ClientSession() as session: logger.info(f"Starting bot")
(room_url, token) = await configure(session)
transport = DailyTransport( # Initialize the SmallWebRTCTransport with the connection
room_url, transport = SmallWebRTCTransport(
token, webrtc_connection=webrtc_connection,
"Respond bot", params=TransportParams(
DailyParams( audio_in_enabled=True,
audio_out_enabled=True, audio_out_enabled=True,
vad_enabled=True, vad_enabled=True,
vad_audio_passthrough=True, vad_audio_passthrough=True,
# set stop_secs to something roughly similar to the internal setting # set stop_secs to something roughly similar to the internal setting
# of the Multimodal Live api, just to align events. This doesn't really # of the Multimodal Live api, just to align events. This doesn't really
# matter because we can only use the Multimodal Live API's phrase # matter because we can only use the Multimodal Live API's phrase
# endpointing, for now. # endpointing, for now.
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)),
), ),
) )
weather_function = FunctionSchema( weather_function = FunctionSchema(
name="get_current_weather", name="get_current_weather",
description="Get the current weather", description="Get the current weather",
properties={ properties={
"location": { "location": {
"type": "string", "type": "string",
"description": "The city and state, e.g. San Francisco, CA", "description": "The city and state, e.g. San Francisco, CA",
},
"format": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the user's location.",
},
}, },
required=["location", "format"], "format": {
) "type": "string",
search_tool = {"google_search": {}} "enum": ["celsius", "fahrenheit"],
tools = ToolsSchema( "description": "The temperature unit to use. Infer this from the user's location.",
standard_tools=[weather_function], custom_tools={AdapterType.GEMINI: [search_tool]} },
) },
required=["location", "format"],
)
search_tool = {"google_search": {}}
tools = ToolsSchema(
standard_tools=[weather_function], custom_tools={AdapterType.GEMINI: [search_tool]}
)
llm = GeminiMultimodalLiveLLMService( llm = GeminiMultimodalLiveLLMService(
api_key=os.getenv("GOOGLE_API_KEY"), api_key=os.getenv("GOOGLE_API_KEY"),
system_instruction=system_instruction, system_instruction=system_instruction,
tools=tools, tools=tools,
) )
llm.register_function("get_current_weather", fetch_weather_from_api) llm.register_function("get_current_weather", fetch_weather_from_api)
context = OpenAILLMContext( context = OpenAILLMContext(
[{"role": "user", "content": "Say hello."}], [{"role": "user", "content": "Say hello."}],
) )
context_aggregator = llm.create_context_aggregator(context) context_aggregator = llm.create_context_aggregator(context)
pipeline = Pipeline( pipeline = Pipeline(
[ [
transport.input(), transport.input(),
context_aggregator.user(), context_aggregator.user(),
llm, llm,
transport.output(), transport.output(),
context_aggregator.assistant(), context_aggregator.assistant(),
] ]
) )
task = PipelineTask( task = PipelineTask(
pipeline, pipeline,
params=PipelineParams( params=PipelineParams(
allow_interruptions=True, allow_interruptions=True,
enable_metrics=True, enable_metrics=True,
enable_usage_metrics=True, enable_usage_metrics=True,
), ),
) )
@transport.event_handler("on_first_participant_joined") @transport.event_handler("on_client_connected")
async def on_first_participant_joined(transport, participant): async def on_client_connected(transport, client):
await task.queue_frames([context_aggregator.user().get_context_frame()]) logger.info(f"Client connected")
# Kick off the conversation.
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner() @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info(f"Client disconnected")
await runner.run(task) @transport.event_handler("on_client_closed")
async def on_client_closed(transport, client):
logger.info(f"Client closed connection")
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) from run import main
main()

View File

@@ -9,9 +9,9 @@ import os
import sys import sys
import aiohttp import aiohttp
from daily_runner import configure
from dotenv import load_dotenv from dotenv import load_dotenv
from loguru import logger from loguru import logger
from runner import configure
from pipecat.audio.vad.silero import SileroVADAnalyzer from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.audio.vad.vad_analyzer import VADParams
@@ -53,7 +53,6 @@ async def main():
voice_id="Aoede", # Puck, Charon, Kore, Fenrir, Aoede voice_id="Aoede", # Puck, Charon, Kore, Fenrir, Aoede
# system_instruction="Talk like a pirate." # system_instruction="Talk like a pirate."
transcribe_user_audio=True, transcribe_user_audio=True,
transcribe_model_audio=True,
# inference_on_context_initialization=False, # inference_on_context_initialization=False,
) )

Some files were not shown because too many files have changed in this diff Show More