import os
from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import LLMRunFrame
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.worker import PipelineParams, PipelineWorker
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.processors.aggregators.llm_response_universal import (
LLMContextAggregatorPair,
LLMUserAggregatorParams,
)
from pipecat.services.cartesia.tts import CartesiaTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService
from pipecat.services.simli.video import SimliVideoService
from pipecat.workers.runner import WorkerRunner
from relaymessenger_pipecat import RelayParams, RelayTransport
async def answer(call_id: str) -> None:
transport = RelayTransport(
api_key=os.environ["RELAY_AGENT_TOKEN"],
call_id=call_id,
base_url="https://api.relayapp.im",
params=RelayParams(
audio_in_enabled=True,
audio_out_enabled=True,
video_out_enabled=True,
video_out_is_live=True,
video_out_width=512,
video_out_height=512,
),
)
stt = DeepgramSTTService(api_key=os.environ["DEEPGRAM_API_KEY"])
tts = CartesiaTTSService(
api_key=os.environ["CARTESIA_API_KEY"],
settings=CartesiaTTSService.Settings(voice=os.environ["CARTESIA_VOICE_ID"]),
)
avatar = SimliVideoService(
api_key=os.environ["SIMLI_API_KEY"],
face_id=os.environ["SIMLI_FACE_ID"],
)
llm = OpenAILLMService(
api_key=os.environ["OPENAI_API_KEY"],
settings=OpenAILLMService.Settings(
system_instruction="You are on a video call. Keep answers short and speakable.",
),
)
context = LLMContext()
user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
context,
user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()),
)
worker = PipelineWorker(
Pipeline(
[
transport.input(),
stt,
user_aggregator,
llm,
tts,
avatar, # turns the bot's speech into lip-synced video and audio
transport.output(), # sends both into the Relay call
assistant_aggregator,
]
),
params=PipelineParams(enable_metrics=True),
cancel_on_idle_timeout=False, # a quiet call is still a call
)
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
await worker.queue_frames([LLMRunFrame()])
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
await worker.cancel()
runner = WorkerRunner()
await runner.add_workers(worker)
await runner.run()