Files
pipecat/examples/phone-chatbot/daily-pstn-call-transfer/server.py
Dominic Stewart 70951b1198 Add simplified pstn examples (#1822)
* Add simplified pstn examples
* Add daily_twilio_sip_dial_out example
2025-06-02 14:50:21 +09:00

117 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#
# Copyright (c) 20242025, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
"""server.py.
Webhook server to handle webhook coming from Daily, create a Daily room and start the bot.
"""
import json
import os
import shlex
import subprocess
from contextlib import asynccontextmanager
import aiohttp
import uvicorn
from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse
from utils.daily_helpers import create_daily_room
load_dotenv()
# ----------------- API ----------------- #
@asynccontextmanager
async def lifespan(app: FastAPI):
# Create aiohttp session to be used for Daily API calls
app.state.session = aiohttp.ClientSession()
yield
# Close session when shutting down
await app.state.session.close()
app = FastAPI(lifespan=lifespan)
@app.post("/start")
async def handle_incoming_daily_webhook(request: Request) -> JSONResponse:
"""Handle incoming Daily call webhook."""
print("Received webhook from Daily")
# Get the dial-in properties from the request
try:
data = await request.json()
if "test" in data:
# Pass through any webhook checks
return JSONResponse({"test": True})
if not all(key in data for key in ["From", "To", "callId", "callDomain"]):
raise HTTPException(
status_code=400, detail="Missing properties 'From', 'To', 'callId', 'callDomain'"
)
# Extract the caller's phone number
caller_phone = str(data.get("From"))
print(f"Processing call from {caller_phone}")
# Create a Daily room with dial-in capabilities
try:
room_details = await create_daily_room(request.app.state.session, caller_phone)
except Exception as e:
print(f"Error creating Daily room: {e}")
raise HTTPException(status_code=500, detail=f"Failed to create Daily room: {str(e)}")
room_url = room_details["room_url"]
token = room_details["token"]
print(f"Created Daily room: {room_url} with token: {token}")
body_json = json.dumps(data)
bot_cmd = f"python3 -m bot -u {room_url} -t {token} -b {shlex.quote(body_json)}"
try:
# CHANGE: Keep stdout/stderr for debugging
# Start the bot in the background but capture output
subprocess.Popen(
bot_cmd,
shell=True,
# Don't redirect output so we can see logs
# stdout=subprocess.DEVNULL,
# stderr=subprocess.DEVNULL
)
print(f"Started bot process with command: {bot_cmd}")
except Exception as e:
print(f"Error starting bot: {e}")
raise HTTPException(status_code=500, detail=f"Failed to start bot: {str(e)}")
except HTTPException:
raise
except Exception as e:
print(f"Unexpected error: {str(e)}")
raise HTTPException(status_code=500, detail=f"Server error: {str(e)}")
# Grab a token for the user to join with
return JSONResponse({"room_url": room_url, "token": token})
@app.get("/health")
async def health_check():
"""Simple health check endpoint."""
return {"status": "healthy"}
# ----------------- Main ----------------- #
if __name__ == "__main__":
# Run the server
port = int(os.getenv("PORT", "7860"))
print(f"Starting server on port {port}")
uvicorn.run("server:app", host="0.0.0.0", port=port, reload=True)