import argparse import asyncio import logging from contextlib import asynccontextmanager from typing import Dict import uvicorn from bot import run_bot from dotenv import load_dotenv from fastapi import BackgroundTasks, FastAPI from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection # Load environment variables load_dotenv(override=True) logger = logging.getLogger("pc") app = FastAPI() # Store connections by pc_id pcs_map: Dict[str, SmallWebRTCConnection] = {} ice_servers = ["stun:stun.l.google.com:19302"] @app.post("/api/offer") async def offer(request: dict, background_tasks: BackgroundTasks): pc_id = request.get("pc_id") if pc_id and pc_id in pcs_map: pipecat_connection = pcs_map[pc_id] logger.info(f"Reusing existing connection for pc_id: {pc_id}") await pipecat_connection.renegotiate( sdp=request["sdp"], type=request["type"], restart_pc=request.get("restart_pc", False) ) else: pipecat_connection = SmallWebRTCConnection(ice_servers) await pipecat_connection.initialize(sdp=request["sdp"], type=request["type"]) @pipecat_connection.event_handler("closed") async def handle_disconnected(webrtc_connection: SmallWebRTCConnection): logger.info(f"Discarding peer connection for pc_id: {webrtc_connection.pc_id}") pcs_map.pop(webrtc_connection.pc_id, None) background_tasks.add_task(run_bot, pipecat_connection) answer = pipecat_connection.get_answer() # Updating the peer connection inside the map pcs_map[answer["pc_id"]] = pipecat_connection return answer @asynccontextmanager async def lifespan(app: FastAPI): yield # Run app coros = [pc.close() for pc in pcs_map.values()] await asyncio.gather(*coros) pcs_map.clear() if __name__ == "__main__": parser = argparse.ArgumentParser(description="WebRTC demo") parser.add_argument( "--host", default="localhost", help="Host for HTTP server (default: localhost)" ) parser.add_argument( "--port", type=int, default=7860, help="Port for HTTP server (default: 7860)" ) parser.add_argument("--verbose", "-v", action="count") args = parser.parse_args() if args.verbose: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) uvicorn.run(app, host=args.host, port=args.port)