diff --git a/CHANGELOG.md b/CHANGELOG.md index 658218361..4da3cf32d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- The development runner how handles custom `body` data for `DailyTransport`. + The `body` data is passed to the Pipecat client. You can POST to the `/start` + endpoint with a request body of: + + ``` + { + "createDailyRoom": true, + "dailyRoomProperties": { "start_video_off": true }, + "body": { "custom_data": "value" } + } + ``` + + The `body` information is parsed and used in the application. The + `dailyRoomProperties` are currently not handled. + - Added detailed latency logging to `UserBotLatencyLogObserver`, capturing average response time between user stop and bot start, as well as minimum and maximum response latency. ### Changed +- The development runners `/connect` and `/start` endpoint now both return + `dailyRoom` and `dailyToken` in place of the previous `room_url` and `token`. + - Updated the `pipecat.runner.daily` utility to only a take `DAILY_API_URL` and `DAILY_SAMPLE_ROOM_URL` environment variables instead of argparsing `-u` and `-k`, respectively. @@ -50,6 +68,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - In the `pipecat.runner.daily`, the `configure_with_args()` function is deprecated. Use the `configure()` function instead. +- The development runner's `/connect` endpoint is deprecated and will be + removed in a future version. Use the `/start` endpoint in its place. In the + meantime, both endpoints work and deliver equivalent functionality. + ## [0.0.77] - 2025-07-31 ### Added diff --git a/src/pipecat/runner/run.py b/src/pipecat/runner/run.py index 79750d3e9..77902adfd 100644 --- a/src/pipecat/runner/run.py +++ b/src/pipecat/runner/run.py @@ -82,7 +82,7 @@ from pipecat.runner.types import ( try: import uvicorn from dotenv import load_dotenv - from fastapi import BackgroundTasks, FastAPI, WebSocket + from fastapi import BackgroundTasks, FastAPI, Request, WebSocket from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import HTMLResponse, RedirectResponse except ImportError as e: @@ -261,17 +261,43 @@ def _setup_daily_routes(app: FastAPI): async with aiohttp.ClientSession() as session: room_url, token = await configure(session) - # Start the bot in the background + # Start the bot in the background with empty body for GET requests bot_module = _get_bot_module() runner_args = DailyRunnerArguments(room_url=room_url, token=token, body={}) asyncio.create_task(bot_module.bot(runner_args)) return RedirectResponse(room_url) - @app.post("/connect") - async def rtvi_connect(): - """Launch a Daily bot and return connection info for RTVI clients.""" + async def _handle_rtvi_request(request: Request): + """Common handler for both /start and /connect endpoints. + + Expects POST body like:: + + { + "createDailyRoom": true, + "dailyRoomProperties": { "start_video_off": true }, + "body": { "custom_data": "value" } + } + """ print("Starting bot with Daily transport") + # Parse the request body + try: + request_data = await request.json() + logger.debug(f"Received request: {request_data}") + except Exception as e: + logger.error(f"Failed to parse request body: {e}") + request_data = {} + + # Extract the body data that should be passed to the bot + # This mimics Pipecat Cloud's behavior + bot_body = request_data.get("body", {}) + + # Log the extracted body data for debugging + if bot_body: + logger.info(f"Extracted body data for bot: {bot_body}") + else: + logger.debug("No body data provided in request") + import aiohttp from pipecat.runner.daily import configure @@ -279,11 +305,30 @@ def _setup_daily_routes(app: FastAPI): async with aiohttp.ClientSession() as session: room_url, token = await configure(session) - # Start the bot in the background + # Start the bot in the background with extracted body data bot_module = _get_bot_module() - runner_args = DailyRunnerArguments(room_url=room_url, token=token, body={}) + runner_args = DailyRunnerArguments(room_url=room_url, token=token, body=bot_body) asyncio.create_task(bot_module.bot(runner_args)) - return {"room_url": room_url, "token": token} + # Match PCC /start endpoint response format: + return {"dailyRoom": room_url, "dailyToken": token} + + @app.post("/start") + async def rtvi_start(request: Request): + """Launch a Daily bot and return connection info for RTVI clients.""" + return await _handle_rtvi_request(request) + + @app.post("/connect") + async def rtvi_connect(request: Request): + """Launch a Daily bot and return connection info for RTVI clients. + + .. deprecated:: 0.0.78 + Use /start instead. This endpoint will be removed in a future version. + """ + logger.warning( + "DEPRECATED: /connect endpoint is deprecated. Please use /start instead. " + "This endpoint will be removed in a future version." + ) + return await _handle_rtvi_request(request) def _setup_telephony_routes(app: FastAPI, transport_type: str, proxy: str): @@ -345,6 +390,7 @@ async def _run_daily_direct(): async with aiohttp.ClientSession() as session: room_url, token = await configure(session) + # Direct connections have no request body, so use empty dict runner_args = DailyRunnerArguments(room_url=room_url, token=token, body={}) # Get the bot module and run it directly